这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
相关阅读
- 使用konva制作在线photoshop(1)——元素拖拽、变形与导出
- 使用react-konva制作在线photoshop(2)——字体的文本与样式的修改
- 使用react-konva制作在线制图应用(3)——在线字体文件的动态渲染
- 使用react-konva制作在线制图应用(4)——撤销/重做(踩坑篇)
- 使用react-konva制作在线制图应用(5)——撤销/重做(填坑篇)
图层移动
konva 上图层的顺序其实就是 Layer 的渲染顺序,如下,layer3 就是最上层的,layer1 是最下层的。
<Stage>
<Layer1 />
<Layer2 />
<Layer3 />
</Stage>
我们移动上下图层就是改变 info 中每个图层的 index 值.交换当前图层与目标图层的 index
// i正数往上移动,负数往下移动
Shape.moveLayer = (i: number) => {
const current = [...steps]
const currentLayerIndex = current.findIndex((c) => c.id === selectedId)
let isChanged = false
if (currentLayerIndex >= 0) {
const tmp = current[currentLayerIndex]
if (i > 0) {
if (currentLayerIndex < current.length - 1) {
// 界限
current[currentLayerIndex] = current[currentLayerIndex + 1]
current[currentLayerIndex + 1] = tmp
isChanged = true
}
} else if (i < 0) {
if (currentLayerIndex > 0) {
// 界限
current[currentLayerIndex] = current[currentLayerIndex - 1]
current[currentLayerIndex - 1] = tmp
isChanged = true
}
}
}
if (isChanged) {
stepCached.enqueue(current) // 本地数据更改
setSteps(stepCached.getCurrent()) // 绑定state
}
}
我们可以看到图层虽然可以正常移动,但是图层移动之后添加文字元素,图层的选中态有问题,看看咋回事。
打印 selectedId 发现,当移动图层后再生成新元素时,新元素的 id 没有递增,查看下生成新元素的代码
// 添加新元素时
const onAdd = (item: IaddItem) => {
const infos = stepCached.getCurrent()
const newItem = { ...item, id: 0 }
const lastInfo = infos[infos.length - 1] // !!!!
const newId = lastInfo ? lastInfo.id + 1 : 1000
newItem.id = newId
const list = [...infos, newItem]
stepCached.enqueue(list)
setSteps(stepCached.getCurrent())
setSelected(newId)
}
发现新元素的 id:newId 是当前 info 数组最后一个元素+1 生成的,这里显然是不太严谨的,应该是当前数组中 id 最大元素+1,这里修改为
const onAdd = (item: IaddItem) => {
const infos = stepCached.getCurrent()
const newItem = { ...item, id: 0 }
const maxId = infos.reduce((prev, info) => Math.max(info.id, prev), 0) // 注意!
const newId = maxId ? maxId + 1 : 1000
newItem.id = newId
const list = [...infos, newItem]
stepCached.enqueue(list)
setSteps(stepCached.getCurrent())
setSelected(newId)
}
最终效果如下
缩放画布
因为我们产品只要求画布中心点缩放,并没有以鼠标为中心进行缩放的功能,就比较简单,直接改变 css transform 属性就 ok 了。
const [stageScale, setStageScale] = useState(1)
// ...
Shape.canvasScale = (ratio = number) => {
// ratio属于[0.25,2]
// 获取画布中心的位置
if (ratio <= 2 && ratio >= 0.25) {
setStageScale(ratio)
}
}
return (
<Stage
// ....
style={{ backgroundColor: '#fff', transform: `scale(${stageScale})` }}
></Stage>
)
删除元素
删除元素非常好理解,就是删除一个 info 中的所选中的元素。
// 删除选中元素
Shape.deleteItem = () => {
const info = [...steps]
const index = info.findIndex((i) => i.id === selectedId)
if (index >= 0) {
info.splice(index, 1)
stepCached.enqueue(info)
setSteps(stepCached.getCurrent())
}
}
效果如下: