作为继续创作的动力,继续求 github Star 能超过 50 个(目前惨淡的 0 个),望多多支持。
源码
示例地址
在上一章,实现了“无限画布”、“画布移动”、“网格背景”、“比例尺”、“定位缩放”,并简单叙述了它们实现的基本思路。
关于位置和距离
从源码里可以发现,多处依赖了 Konva.Stage 的 width、height、x、y、scale。尤其是 scale,在绘制“网格背景”、“比例尺”中都必须利用它计算。
在这里需要清楚,在设计交互的时候要考虑一种是“逻辑上”的位置和距离,另一种是“真实的”位置和距离。
假设 stage 宽 800 高 600,可以说“逻辑上” stage 的尺寸就是 800 x 600,可是一旦进行了“缩放”,放大到 x2.0,“真实的” stage 的可视尺寸就变成了 1600 x 1200了。
然而,stage 包含的 layer、group 是相对于 stage 进行定义的,例如,存在一个 rect(x:0,y:0,width:100,height:200),当 stage 放大到 x2.0 的时候,“真实的”可视尺寸就变成了 200 x 400 了,但此时 rect 的(width,height)并没有改变。
因此,“逻辑上”和“真实的”的位置和距离之间就需要通过 scale 转换,简单地可以定义成:
// 获取 stage 状态(这里获取的就是“真实的”位置和距离)
getStageState() {
return {
width: this.stage.width(),
height: this.stage.height(),
scale: this.stage.scaleX(),
x: this.stage.x(),
y: this.stage.y()
}
}
// 对于 stage 来说是保持 1:1 比例的,所以 scaleX 和 scaleY 是一样的
// 相对大小(基于 stage,且无视 scale)
toStageValue(boardPos: number) {
return boardPos / this.stage.scaleX()
}
// 绝对大小(基于可视区域像素)
toBoardValue(stagePos: number) {
return stagePos * this.stage.scaleX()
}
再举些代码里的例子:
// src\Render\draws\BgDraw.ts
// stage 状态(这里获取的就是“真实的”位置和距离)
const stageState = this.render.getStageState()
// 格子大小
const cellSize = this.option.size
// 列数
const lenX = Math.ceil(this.render.toStageValue(stageState.width) / cellSize)
// 行数
const lenY = Math.ceil(this.render.toStageValue(stageState.height) / cellSize)
绘制网格的时候,基本就是针对可视区域绘制,所以通过“真实的” stageState.width 和 stageState.height,就需要根据 stage 的 scale 恢复成“逻辑上”的位置和距离,除以“逻辑上”网格大小,就可以得出应该要绘制多少行和列的线了。
又如:
// src\Render\draws\RulerDraw.ts
// stage 状态
const stageState = this.render.getStageState()
// 比例尺 - 上
const groupTop = new Konva.Group({
x: this.render.toStageValue(-stageState.x + this.option.size),
y: this.render.toStageValue(-stageState.y),
width: this.render.toStageValue(stageState.width - this.option.size),
height: this.render.toStageValue(this.option.size)
})
// 比例尺 - 左
const groupLeft = new Konva.