认识vue-konva画图工具

认识vue-konva画图工具一 vue konva 是什么 Vue Konva 是一个 JavaScript 库 用于使用 Vue 绘制复杂的画布图形 它提供了对 Konva 框架的声明性和反应性绑定 所有 vue konva 组件都对应于同名的 KONVA 组件 前缀为 V KONVA 对象可用的所有参数都可以添加为相应的 VUE KONVA 组件的配置中的配置 官网链接 konva

大家好,我是讯享网,很高兴认识大家。

一、vue-konva是什么?

Vue Konva是一个JavaScript库,用于使用Vue绘制复杂的画布图形。
它提供了对Konva框架的声明性和反应性绑定。
所有vue-konva组件都对应于同名的KONVA组件,前缀为“ V-”。 KONVA对象可用的所有参数都可以添加为相应的VUE-KONVA组件的配置中的配置。
官网链接konva
中文链接:konva
中文官网:http://konvajs-doc.bluehymn.com/docs/

二、核心形状有:

【v矩形、v圆形、v椭圆、v线、v图像、v文本、v文本路径、v星形、v标签、v路径、
v规则多边形】。
v-rect, v-circle, v-ellipse, v-line, v-image, v-text, v-text-path, v-star, v-label, v-path, v-regular-polygon.
您也可以创建自定义形状。

三.安装引入

pnpm install vue-konva konva --save

import { 
    createApp } from 'vue'; import App from './App.vue'; import VueKonva from 'vue-konva'; const app = createApp(App); app.use(VueKonva); app.mount('#app'); 
讯享网

四、组件模板中的引用

讯享网<template> <v-stage :config="configKonva"> <v-layer> <v-circle :config="configCircle"></v-circle> </v-layer> </v-stage> </template> 
<script> export default { 
    data() { 
    return { 
    configKonva: { 
    width: 200, height: 200 }, configCircle: { 
    x: 100, y: 100, radius: 70, fill: "red", stroke: "black", strokeWidth: 4 } }; } }; 

五、案例

讯享网<template> <div> <v-stage ref="stage" :config="configKonva" @dragstart="handleDragstart" @dragend="handleDragend" > <v-layer ref="layer"> <v-star v-for="item in list" :key="item.id" :config="{ 
    x: item.x, y: item.y, rotation: item.rotation, id: item.id, numPoints: 5, innerRadius: 30, outerRadius: 50, fill: '#89b717', opacity: 0.8, draggable: true, scaleX: dragItemId === item.id ? item.scale * 1.2 : item.scale, scaleY: dragItemId === item.id ? item.scale * 1.2 : item.scale, shadowColor: 'black', shadowBlur: 10, shadowOffsetX: dragItemId === item.id ? 15 : 5, shadowOffsetY: dragItemId === item.id ? 15 : 5, shadowOpacity: 0.6 }" ></v-star> </v-layer> </v-stage> </div> </template> <script> const width = window.innerWidth; const height = window.innerHeight; export default { 
    data() { 
    return { 
    list: [], dragItemId: null, configKonva: { 
    width: width, height: height } }; }, methods: { 
    handleDragstart(e) { 
    // save drag element: this.dragItemId = e.target.id(); // move current element to the top: const item = this.list.find(i => i.id === this.dragItemId); const index = this.list.indexOf(item); this.list.splice(index, 1); this.list.push(item); }, handleDragend(e) { 
    this.dragItemId = null; } }, mounted() { 
    for (let n = 0; n < 30; n++) { 
    this.list.push({ 
    id: Math.round(Math.random() * 10000).toString(), x: Math.random() * width, y: Math.random() * height, rotation: Math.random() * 180, scale: Math.random() }); } } }; </script> <style> body { 
    margin: 0; padding: 0; } </style> 

六、事件

组件模板中的引用使用vue-konva,您可以轻松监听用户输入事件(click, dblclick, mouseover, tap, dbltap, touchstart, etc…)和拖放事件(dragstart、dragmove、dragend)。

1.鼠标悬停 mouseover
2.触摸启动 etc
3.双击事件 dbclick
4.键盘事件 tab
5.自定义事件 emit(“change”) 也就是子组件给父组件传递一个事件。
有关事件的完整列表,请查看on()方法文档。

<template> <v-stage ref="stage" :config="stageSize"> <v-layer ref="layer"> <v-regular-polygon @mousemove="handleMouseMove" @mouseout="handleMouseOut" :config="{ 
    x: 80, y: 120, sides: 3, radius: 80, fill: '#00D2FF', stroke: 'black', strokeWidth: 4 }" /> <v-text ref="text" :config="{ 
    x: 10, y: 10, fontFamily: 'Calibri', fontSize: 24, text: text, fill: 'black' }" /> </v-layer> </v-stage> </template> <script> const width = window.innerWidth; const height = window.innerHeight; export default { 
    data() { 
    return { 
    stageSize: { 
    width: width, height: height }, text: '' }; }, methods: { 
    writeMessage(message) { 
    this.text = message; }, handleMouseOut(event) { 
    this.writeMessage('Mouseout triangle'); }, handleMouseMove(event) { 
    const mousePos = this.$refs.stage.getNode().getPointerPosition(); const x = mousePos.x - 190; const y = mousePos.y - 40; this.writeMessage('x: ' + x + ', y: ' + y); } } }; </script> 

七、图片

对于图像,您需要手动创建原生window.Image实例或画布元素,并将其用作v-Image组件的图像属性。

<template> <v-stage ref="stage" :config="stageSize"> <v-layer ref="layer"> <v-image :config="{ 
    image: image }"/> </v-layer> </v-stage> </template> <script> const width = window.innerWidth; const height = window.innerHeight; export default { 
    data() { 
    return { 
    stageSize: { 
    width: width, height: height }, image: null }; }, created() { 
    const image = new window.Image(); image.src = "https://konvajs.org/assets/yoda.jpg"; image.onload = () => { 
    // set image only when it is loaded this.image = image; }; } }; </script> 

八、文件

要应用筛选器,您需要手动缓存Konva.Node。您可以通过created()方法来完成。
每次在updated()中更新节点的样式时,可能需要重新缓存节点。
说明:点击矩形查看更改

<template> <v-stage ref="stage" :config="stageSize"> <v-layer ref="layer"> <v-rect ref="rect" @mousemove="handleMouseMove" :config="{ 
    filters: filters, noise: 1, x: 10, y: 10, width: 50, height: 50, fill: color, shadowBlur: 10 }" /> </v-layer> </v-stage> </template> <script> const width = window.innerWidth; const height = window.innerHeight; import Konva from 'konva'; export default { 
    data() { 
    return { 
    stageSize: { 
    width: width, height: height }, color: 'green', filters: [Konva.Filters.Noise] }; }, methods: { 
    handleMouseMove() { 
    this.color = Konva.Util.getRandomColor(); } }, mounted() { 
    const rectNode = this.$refs.rect.getNode(); rectNode.cache(); }, updated() { 
    // recache const rectNode = this.$refs.rect.getNode(); // may need to redraw layer manually rectNode.cache(); } }; </script> 

九、如何使用Vue序列化和反序列化Konva阶段?

Pure Konva具有特殊的mechanizm,可以使用node.toJSON()和node.create(json)函数保存/加载整个画布阶段。
请参阅演示。
但是,如果您正在使用vue-konva,我们不建议使用这些方法。在vue-konva中,你应该在你的vue组件中定义应用程序的状态。该状态映射到具有模板的节点中。要保存/加载整个阶段,您只需要保存/加载应用程序的状态,而不需要保存Konva内部和节点。

<template> <div> Click on canvas to create a cirlce. <a href=".">Reload the page</a>. Circles should stay here. <v-stage ref="stage" :config="stageSize" @click="handleClick" > <v-layer ref="layer"> <v-circle v-for="item in list" :key="item.id" :config="{ 
    x : item.x, y: item.y, radius: 50, fill: 'red', }"></v-circle> </v-layer> <v-layer ref="dragLayer"></v-layer> </v-stage> </div> </template> <script> const width = window.innerWidth; const height = window.innerHeight; export default { 
    data() { 
    return { 
    list: [{ 
    x: 100, y: 100, radius: 50, fill: 'blue' }], stageSize: { 
    width: width, height: height } }; }, methods: { 
    handleClick(evt) { 
    const stage = evt.target.getStage(); const pos = stage.getPointerPosition(); this.list.push(pos); this.save(); }, load() { 
    const data = localStorage.getItem('storage') || '[]'; this.list = JSON.parse(data); }, save() { 
    localStorage.setItem('storage', JSON.stringify(this.list)); } }, mounted() { 
    this.load(); } }; </script> 

十、拖放

<template> <v-stage ref="stage" :config="stageSize"> <v-layer ref="layer"> <v-text @dragstart="handleDragStart" @dragend="handleDragEnd" :config="{ 
    text: 'Draggable Text', x: 50, y: 50, draggable: true, fill: isDragging ? 'green' : 'black' }" /> </v-layer> </v-stage> </template> <script> const width = window.innerWidth; const height = window.innerHeight; export default { 
    data() { 
    return { 
    stageSize: { 
    width: width, height: height }, isDragging: false }; }, methods: { 
    handleDragStart() { 
    this.isDragging = true; }, handleDragEnd() { 
    this.isDragging = false; } } }; </script> 

十一、Transformer工具

目前还没有好的纯声明性“vue方式”来使用Transformer工具。
但是,您仍然可以将它与一些对Konva节点的小型手动请求一起使用。
它会很好地工作。
想法:您需要创建Konva.Transformer节点,并手动将其附加到所需的节点中。
说明:点击形状进行选择。

<template> <v-stage ref="stage" :config="stageSize" @mousedown="handleStageMouseDown" @touchstart="handleStageMouseDown" > <v-layer ref="layer"> <v-rect v-for="item in rectangles" :key="item.id" :config="item" @transformend="handleTransformEnd" /> <v-transformer ref="transformer" /> </v-layer> </v-stage> </template> <script> import Konva from 'konva'; const width = window.innerWidth; const height = window.innerHeight; export default { 
    data() { 
    return { 
    stageSize: { 
    width: width, height: height, }, rectangles: [ { 
    rotation: 0, x: 10, y: 10, width: 100, height: 100, scaleX: 1, scaleY: 1, fill: 'red', name: 'rect1', draggable: true, }, { 
    rotation: 0, x: 150, y: 150, width: 100, height: 100, scaleX: 1, scaleY: 1, fill: 'green', name: 'rect2', draggable: true, }, ], selectedShapeName: '', }; }, methods: { 
    handleTransformEnd(e) { 
    // shape is transformed, let us save new attrs back to the node // find element in our state const rect = this.rectangles.find( (r) => r.name === this.selectedShapeName ); // update the state rect.x = e.target.x(); rect.y = e.target.y(); rect.rotation = e.target.rotation(); rect.scaleX = e.target.scaleX(); rect.scaleY = e.target.scaleY(); // change fill rect.fill = Konva.Util.getRandomColor(); }, handleStageMouseDown(e) { 
    // clicked on stage - clear selection if (e.target === e.target.getStage()) { 
    this.selectedShapeName = ''; this.updateTransformer(); return; } // clicked on transformer - do nothing const clickedOnTransformer = e.target.getParent().className === 'Transformer'; if (clickedOnTransformer) { 
    return; } // find clicked rect by its name const name = e.target.name(); const rect = this.rectangles.find((r) => r.name === name); if (rect) { 
    this.selectedShapeName = name; } else { 
    this.selectedShapeName = ''; } this.updateTransformer(); }, updateTransformer() { 
    // here we need to manually attach or detach Transformer node const transformerNode = this.$refs.transformer.getNode(); const stage = transformerNode.getStage(); const { 
    selectedShapeName } = this; const selectedNode = stage.findOne('.' + selectedShapeName); // do nothing if selected node is already attached if (selectedNode === transformerNode.node()) { 
    return; } if (selectedNode) { 
    // attach to another node transformerNode.nodes([selectedNode]); } else { 
    // remove transformer transformerNode.nodes([]); } }, }, }; </script> 

十二、动画

Konva本身有两种动画方法Tween和Animation。您可以手动将这两种方法应用于节点。
对于简单的用例,我们建议使用node.to()方法。
说明:试着移动一个矩形。

<template> <v-stage ref="stage" :config="stageSize"> <v-layer ref="layer"> <v-rect ref="rect" @dragstart="changeSize" @dragend="changeSize" :config="{ 
    width: 50, height: 50, fill: 'green', draggable: true }" /> <v-regular-polygon ref="hexagon" :config="{ 
    x: 200, y: 200, sides: 6, radius: 20, fill: 'red', stroke: 'black', strokeWidth: 4 }" /> </v-layer> </v-stage> </template> <script> import Konva from "konva"; const width = window.innerWidth; const height = window.innerHeight; export default { 
    data() { 
    return { 
    stageSize: { 
    width: width, height: height } }; }, methods: { 
    changeSize(e) { 
    // to() is a method of `Konva.Node` instances e.target.to({ 
    scaleX: Math.random() + 0.8, scaleY: Math.random() + 0.8, duration: 0.2 }); } }, mounted() { 
    const vm = this; const amplitude = 100; const period = 5000; // in ms const centerX = vm.$refs.stage.getNode().getWidth() / 2; const hexagon = this.$refs.hexagon.getNode(); // example of Konva.Animation const anim = new Konva.Animation(function(frame) { 
    hexagon.setX( amplitude * Math.sin((frame.time * 2 * Math.PI) / period) + centerX ); }, hexagon.getLayer()); anim.start(); } }; </script> 

十三、缓存节点

如果你想在vue应用程序中缓存一个节点,你需要访问Konva节点并使用node.cache()函数。
要访问节点,可以使用references和component.getNode()方法:
说明:试着拖动整个舞台。然后使用缓存的组重试。
你应该看到更好的表现。

<template> <v-stage ref="stage" :config="stageSize"> <v-layer ref="layer"> <v-rect ref="rect" @dragstart="changeSize" @dragend="changeSize" :config="{ 
    width: 50, height: 50, fill: 'green', draggable: true }" /> <v-regular-polygon ref="hexagon" :config="{ 
    x: 200, y: 200, sides: 6, radius: 20, fill: 'red', stroke: 'black', strokeWidth: 4 }" /> </v-layer> </v-stage> </template> <script> import Konva from "konva"; const width = window.innerWidth; const height = window.innerHeight; export default { 
    data() { 
    return { 
    stageSize: { 
    width: width, height: height } }; }, methods: { 
    changeSize(e) { 
    // to() is a method of `Konva.Node` instances e.target.to({ 
    scaleX: Math.random() + 0.8, scaleY: Math.random() + 0.8, duration: 0.2 }); } }, mounted() { 
    const vm = this; const amplitude = 100; const period = 5000; // in ms const centerX = vm.$refs.stage.getNode().getWidth() / 2; const hexagon = this.$refs.hexagon.getNode(); // example of Konva.Animation const anim = new Konva.Animation(function(frame) { 
    hexagon.setX( amplitude * Math.sin((frame.time * 2 * Math.PI) / period) + centerX ); }, hexagon.getLayer()); anim.start(); } }; </script> 

十四、如何更改zIndex并重新排序vue-konva中的组件?

当你直接使用Konva时,你有很多方法可以改变节点的顺序,比如node.zIndex(5)、node.moveToTop()等。教程。
但在使用vue框架时,不建议使用这些方法。
vue-konva正试图按照您在<template>中描述的节点顺序进行操作。因此,您只需要正确更新应用程序的数据,就可以使中的组件保持正确的顺序,而无需手动更改zIndex。
不要将zIndex用于画布组件。
说明:试着拖动一个圆圈。看看它是如何到达顶端的。我们通过操纵应用程序的数据来做到这一点,以便中的圆圈保持正确的顺序。

<template> <div> <v-stage ref="stage" :config="configKonva"> <v-layer ref="layer"> <v-circle v-for="item in items" :key="item.id" :config="item" @dragstart="handleDragstart" @dragend="handleDragend" ></v-circle> </v-layer> </v-stage> </div> </template> <script> import Konva from "konva"; const width = window.innerWidth; const height = window.innerHeight; function generateItems() { 
    const items = []; for (let i = 0; i < 10; i++) { 
    items.push({ 
    x: Math.random() * width, y: Math.random() * height, radius: 50, id: "node-" + i, fill: Konva.Util.getRandomColor(), draggable: true, }); } return items; } export default { 
    data() { 
    return { 
    items: [], dragItemId: null, configKonva: { 
    width: width, height: height, }, }; }, methods: { 
    handleDragstart(e) { 
    // save drag element: this.dragItemId = e.target.id(); // move current element to the top, by rearranging the items array: const item = this.items.find((i) => i.id === this.dragItemId); const index = this.items.indexOf(item); this.items.splice(index, 1); this.items.push(item); }, handleDragend(e) { 
    this.dragItemId = null; }, }, mounted() { 
    this.items = generateItems(); }, }; </script> <style> body { 
    margin: 0; padding: 0; } </style> 
小讯
上一篇 2025-02-18 14:57
下一篇 2025-04-09 09:52

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/19227.html