成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

用Canvas畫(huà)一棵二叉樹(shù)

lordharrd / 2248人閱讀

摘要:如何得到樹(shù)的深度這樣父節(jié)點(diǎn)與子結(jié)點(diǎn)在軸上最長(zhǎng)的距離即為父節(jié)點(diǎn)與子結(jié)點(diǎn)在軸上最長(zhǎng)的距離為正方形的長(zhǎng)度,如何確定,假設(shè)的寬度為,由深度可知,樹(shù)的最大寬度為,最底層的正方形占據(jù)個(gè)。

筆墨伺候
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 然后便可以揮毫潑墨了
樹(shù)的樣子

const root = {
      value: "A",
      label: "100",
      left: {
        value: "B",
        label: "70",
        left: {
          value: "D",
          label: "40",
          left: {
            value: "H",
            label: "20",
            left: null,
            right: null
          },
          right: {
            value: "I",
            label: "20",
            left: null,
            right: null
          }
        },
        right: {
          value: "E",
          label: "30",
          left: null,
          right: null
        }
      },
      right: {
        value: "C",
        label: "30",
        left: {
          value: "F",
          label: "15",
          left: null,
          right: null
        },
        right: {
          value: "G",
          label: "15",
          left: null,
          right: null
        }
      }
    }
構(gòu)思構(gòu)思

這樣一幅大作,無(wú)非就是由黑色的正方形+線(xiàn)段構(gòu)成
這正方形怎么畫(huà)

function drawRect(text, x, y, unit) {
  ctx.fillRect(x, y, unit, unit)
  // fillRect(x, y, width, height) 
  // x與y指定了在canvas畫(huà)布上所繪制的矩形的左上角(相對(duì)于原點(diǎn))的坐標(biāo)
  // width和height設(shè)置矩形的尺寸。
  ctx.font = "14px serif"
  ctx.fillText(text, x + unit, y + unit) // 再給每個(gè)正方形加個(gè)名字
}

這直線(xiàn)怎么畫(huà)

function drawLine(x1, y1, x2, y2) {
  ctx.moveTo(x1, y1)
  ctx.lineTo(x2, y2)
  ctx.stroke()
}

這關(guān)系怎么畫(huà)

// 前序遍歷二叉樹(shù)
function preOrderTraverse(root, x, y){
  drawRect(root.value, x, y)
  if(root.left){
    drawLine(x, y, ...)
    preOrderTraverse(root.left, ...)
  }
  if(root.right){
    drawLine(x, y, ...)
    preOrderTraverse(root.right, ...)
  }
}

現(xiàn)在遇到個(gè)小問(wèn)題,如何確定節(jié)點(diǎn)的子節(jié)的位置?

父節(jié)點(diǎn)與子結(jié)點(diǎn)在y軸上的距離固定,為正方形長(zhǎng)度unit的兩倍;父節(jié)點(diǎn)與子結(jié)點(diǎn)在x軸上的距離滿(mǎn)足n2=(n1+2)*2-2,其中設(shè)父節(jié)點(diǎn)與子結(jié)點(diǎn)在x軸上最短的距離n0=1,即unit,而父節(jié)點(diǎn)與子結(jié)點(diǎn)在x軸上最長(zhǎng)的距離取決于該樹(shù)的層數(shù)。
如何得到樹(shù)的深度?

function getDeepOfTree(root) {
  if (!root) {
    return 0
  }
  let left = getDeepOfTree(root.left)
  let right = getDeepOfTree(root.right)
  return (left > right) ? left + 1 : right + 1
}

這樣父節(jié)點(diǎn)與子結(jié)點(diǎn)在x軸上最長(zhǎng)的距離

let distance = 1
const deep = getDeepOfTree(root)
for (let i = 2; i < deep; i++) {
  distance = (distance + 2) * 2 - 2
}
// distance*unit 即為父節(jié)點(diǎn)與子結(jié)點(diǎn)在x軸上最長(zhǎng)的距離

unit為正方形的長(zhǎng)度,如何確定,假設(shè)canvas的寬度為1000,由深度deep可知,樹(shù)的最大寬度為Math.pow(2, deep - 1),最底層的正方形占據(jù)4個(gè)unit。

所以unit是如此計(jì)算,const unit = 1000 / (Math.pow(2, deep - 1) * 4 + 8),+8是個(gè)備用空間。

代碼



  
  


來(lái)點(diǎn)互動(dòng)

實(shí)現(xiàn)移動(dòng)至節(jié)點(diǎn)出現(xiàn)tooltip

首先要有tooltip

... const tooltip = document.getElementById("tooltip")

由于canvas是一個(gè)整體元素,所以只能給canvas綁定事件,根據(jù)鼠標(biāo)的坐標(biāo),判斷是否落在某個(gè)正方形區(qū)域內(nèi)
這里有個(gè)關(guān)健個(gè)函數(shù)

ctx.rect(0, 0, 100, 100)
ctx.isPointInPath(x, y)
// 判斷x,y是否落在剛剛由path繪制出的區(qū)域內(nèi)

所以在繪制正方形時(shí)還要將其path記下來(lái)

let pathArr = []
function preOrderTraverse(root, x, y, distance) {
  pathArr.push({
    x,
    y,
    value: root.value,
    label: root.label
  })
  // 記錄正方形左上角的位置,就可以重繪路徑
  drawRect(root.value, x, y) // 繪制節(jié)點(diǎn)
  if (root.left) {
    drawLeftLine(x, y + unit, distance)
    preOrderTraverse(root.left, x - (distance + 1) * unit, y + 3 * unit, distance / 2 - 1)
  }
  if (root.right) {
    drawRightLine(x + unit, y + unit, distance)
    preOrderTraverse(root.right, x + (distance + 1) * unit, y + 3 * unit, distance / 2 - 1)
  }
}

綁定事件

// 模擬鼠標(biāo)hover效果
canvas.addEventListener("mousemove", (e) => {
  let i = 0
  while (i < pathArr.length) {
    ctx.beginPath()
    ctx.rect(pathArr[i].x, pathArr[i].y, unit, unit)
    if (ctx.isPointInPath(e.offsetX, e.offsetY)) {
      canvas.style.cursor = "pointer"
      tooltip.innerHTML = `${pathArr[i].label}`
      tooltip.style.top = `${pathArr[i].y + unit + 4}px`
      tooltip.style.left = `${pathArr[i].x + unit}px`
      break
    } else {
      i++
    }
  }
  if (i === pathArr.length) {
    canvas.style.cursor = "default"
    tooltip.innerHTML = ``
  }
})
線(xiàn)上demo

JSBin地址

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92087.html

相關(guān)文章

  • 數(shù)據(jù)結(jié)構(gòu):二叉樹(shù)

    摘要:鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)由于二叉樹(shù)的每個(gè)結(jié)點(diǎn)最多有兩個(gè)孩子,所以為每個(gè)結(jié)點(diǎn)設(shè)計(jì)一個(gè)數(shù)據(jù)域和兩個(gè)指針域。最終能得到二叉樹(shù)的完整結(jié)構(gòu)。這篇文章主要介紹樹(shù)結(jié)構(gòu)中的一種特殊存在——二叉樹(shù)。主要內(nèi)容有: 二叉樹(shù)的概念 二叉樹(shù)的基本結(jié)構(gòu) 二叉樹(shù)的操作 概念 二叉樹(shù): 每個(gè)結(jié)點(diǎn)最多有兩個(gè)子結(jié)點(diǎn),兩個(gè)子結(jié)點(diǎn)是有次序的,且子結(jié)點(diǎn)次序不能顛倒。兩個(gè)子結(jié)點(diǎn)一般稱(chēng)之為左結(jié)點(diǎn)及右結(jié)點(diǎn)。 層次: 在樹(shù)中,節(jié)點(diǎn)的層次從...

    Ashin 評(píng)論0 收藏0
  • 使JavaScript完成二叉樹(shù)的一些基本操作

    摘要:另外,由于篇幅有限,本篇的重點(diǎn)在于二叉樹(shù)的常見(jiàn)算法以及實(shí)現(xiàn)。常見(jiàn)的二叉樹(shù)實(shí)現(xiàn)代碼之前寫(xiě)過(guò)相關(guān)的文章,是關(guān)于如何創(chuàng)建及遍歷二叉樹(shù)的,這里不再贅述。同時(shí)我們注意到,在二叉樹(shù)深度比較大的時(shí)候,我們光是比較左右是不夠的。 本篇為復(fù)習(xí)過(guò)程中遇到過(guò)的總結(jié),同時(shí)也給準(zhǔn)備面試的同學(xué)一份參考。另外,由于篇幅有限,本篇的重點(diǎn)在于二叉樹(shù)的常見(jiàn)算法以及實(shí)現(xiàn)。 常見(jiàn)的二叉樹(shù)實(shí)現(xiàn)代碼 之前寫(xiě)過(guò)相關(guān)的文章,是關(guān)于如...

    YPHP 評(píng)論0 收藏0
  • js數(shù)據(jù)結(jié)構(gòu)-二叉樹(shù)二叉堆)

    摘要:二叉樹(shù)二叉樹(shù)是一種樹(shù)形結(jié)構(gòu),它的特點(diǎn)是每個(gè)節(jié)點(diǎn)最多只有兩個(gè)分支節(jié)點(diǎn),一棵二叉樹(shù)通常由根節(jié)點(diǎn),分支節(jié)點(diǎn),葉子節(jié)點(diǎn)組成。 二叉樹(shù) 二叉樹(shù)(Binary Tree)是一種樹(shù)形結(jié)構(gòu),它的特點(diǎn)是每個(gè)節(jié)點(diǎn)最多只有兩個(gè)分支節(jié)點(diǎn),一棵二叉樹(shù)通常由根節(jié)點(diǎn),分支節(jié)點(diǎn),葉子節(jié)點(diǎn)組成。而每個(gè)分支節(jié)點(diǎn)也常常被稱(chēng)作為一棵子樹(shù)。 showImg(https://segmentfault.com/img/bVbmEd...

    ningwang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<