摘要:如何得到樹的深度這樣父節點與子結點在軸上最長的距離即為父節點與子結點在軸上最長的距離為正方形的長度,如何確定,假設的寬度為,由深度可知,樹的最大寬度為,最底層的正方形占據個。
筆墨伺候
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); // 然后便可以揮毫潑墨了樹的樣子
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 } } }構思構思
這樣一幅大作,無非就是由黑色的正方形+線段構成
這正方形怎么畫
function drawRect(text, x, y, unit) { ctx.fillRect(x, y, unit, unit) // fillRect(x, y, width, height) // x與y指定了在canvas畫布上所繪制的矩形的左上角(相對于原點)的坐標 // width和height設置矩形的尺寸。 ctx.font = "14px serif" ctx.fillText(text, x + unit, y + unit) // 再給每個正方形加個名字 }
這直線怎么畫
function drawLine(x1, y1, x2, y2) { ctx.moveTo(x1, y1) ctx.lineTo(x2, y2) ctx.stroke() }
這關系怎么畫
// 前序遍歷二叉樹 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, ...) } }
現在遇到個小問題,如何確定節點的子節的位置?
父節點與子結點在y軸上的距離固定,為正方形長度unit的兩倍;父節點與子結點在x軸上的距離滿足n2=(n1+2)*2-2,其中設父節點與子結點在x軸上最短的距離n0=1,即unit,而父節點與子結點在x軸上最長的距離取決于該樹的層數。
如何得到樹的深度?
function getDeepOfTree(root) { if (!root) { return 0 } let left = getDeepOfTree(root.left) let right = getDeepOfTree(root.right) return (left > right) ? left + 1 : right + 1 }
這樣父節點與子結點在x軸上最長的距離
let distance = 1 const deep = getDeepOfTree(root) for (let i = 2; i < deep; i++) { distance = (distance + 2) * 2 - 2 } // distance*unit 即為父節點與子結點在x軸上最長的距離
unit為正方形的長度,如何確定,假設canvas的寬度為1000,由深度deep可知,樹的最大寬度為Math.pow(2, deep - 1),最底層的正方形占據4個unit。
所以unit是如此計算,const unit = 1000 / (Math.pow(2, deep - 1) * 4 + 8),+8是個備用空間。
代碼來點互動
實現移動至節點出現tooltip
首先要有tooltip
... const tooltip = document.getElementById("tooltip")
由于canvas是一個整體元素,所以只能給canvas綁定事件,根據鼠標的坐標,判斷是否落在某個正方形區域內
這里有個關健個函數
ctx.rect(0, 0, 100, 100) ctx.isPointInPath(x, y) // 判斷x,y是否落在剛剛由path繪制出的區域內
所以在繪制正方形時還要將其path記下來
let pathArr = [] function preOrderTraverse(root, x, y, distance) { pathArr.push({ x, y, value: root.value, label: root.label }) // 記錄正方形左上角的位置,就可以重繪路徑 drawRect(root.value, x, y) // 繪制節點 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) } }
綁定事件
// 模擬鼠標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 = ``
}
})
線上demo
JSBin地址
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/92087.html
摘要:另外,由于篇幅有限,本篇的重點在于二叉樹的常見算法以及實現。常見的二叉樹實現代碼之前寫過相關的文章,是關于如何創建及遍歷二叉樹的,這里不再贅述。同時我們注意到,在二叉樹深度比較大的時候,我們光是比較左右是不夠的。 本篇為復習過程中遇到過的總結,同時也給準備面試的同學一份參考。另外,由于篇幅有限,本篇的重點在于二叉樹的常見算法以及實現。 常見的二叉樹實現代碼 之前寫過相關的文章,是關于如...
摘要:二叉樹二叉樹是一種樹形結構,它的特點是每個節點最多只有兩個分支節點,一棵二叉樹通常由根節點,分支節點,葉子節點組成。 二叉樹 二叉樹(Binary Tree)是一種樹形結構,它的特點是每個節點最多只有兩個分支節點,一棵二叉樹通常由根節點,分支節點,葉子節點組成。而每個分支節點也常常被稱作為一棵子樹。 showImg(https://segmentfault.com/img/bVbmEd...
閱讀 3359·2021-09-30 09:47
閱讀 2742·2021-08-18 10:22
閱讀 2527·2021-08-16 10:49
閱讀 2893·2019-08-30 15:53
閱讀 2738·2019-08-29 16:14
閱讀 3191·2019-08-28 18:18
閱讀 3237·2019-08-26 13:21
閱讀 794·2019-08-26 12:02