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