I am trying to increase the performance of my code below. I am looking to render multiple circles every X seconds onto the screen at the position of the mouse cursor. The gif shows it nicely.
This is how it currently looks when I hold down the mouse and drag, but I want to improve the performance so at least I am not using that many layers. See the warnings in google dev tools.
This is my code for the component, it is written in Vue with Typescript. Both Vue with Typescript and Vue Konva are newish to me so if you notice any quick wins with my code please also let me know.
I don't like my approach to solving the problem and I feel there is a far better way of doing it, but I found no real example of this within the docs or through a google search, so this is what I managed to get working.
Thank you.
<template>
<v-stage ref="stage" :config="stageSize" class="konva-stage" @mousemove="throttledMethod" :onMouseDown="onMouseDownHandler" :onMouseUp="onMouseUpHandler">
<v-layer ref="layer" />
</v-stage>
</template>
<script lang="ts">
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'
import { ITool } from '../types/canvas'
import Konva from 'konva'
import _ from 'lodash'
@Component({
name: 'MapCanvas',
data () {
return {
stageSize: {
width: window.innerWidth,
height: window.innerHeight
},
showPing: false
}
},
methods: {
throttledMethod: _.throttle(function (e) {
this.onMouseMoveHandler(e)
}, 100),
onMouseUpHandler (e: any) : void {
this.$data.showPing = false
},
onMouseDownHandler (e: any) : void {
this.$data.showPing = true
},
addPing (e, stage) {
const layer = new Konva.Layer()
const amplitude = 25
const period = 500
let item = new Konva.Circle({
x: e.evt.x,
y: e.evt.y,
radius: 0,
stroke: 'red',
strokeWidth: 5
})
layer.add(item)
stage.add(layer)
const anim = new Konva.Animation((frame: any) => {
item.radius(amplitude * Math.sin((frame.time * Math.PI) / 1000))
}, layer)
anim.start()
setTimeout(() => {
layer.remove()
anim.stop()
}, period)
},
onMouseMoveHandler (e:any) : void {
if (this.$data.showPing) {
const stage = this.$refs.stage.getStage()
this.addPing(e, stage)
}
}
}
}
})
export default class MapButtons extends Vue {
@Prop() private id!: string;
}
</script>
<style scoped lang="scss">
.konva-stage {
background-color: white;
width: 100%;
height: 100%;
position: absolute;
}
</style>
You can just use layer, that you already created in your template:
addPing(e, stage) {
const layer = this.$refs.layer.getNode();
const amplitude = 25;
const period = 500;
let item = new Konva.Circle({
x: e.evt.x,
y: e.evt.y,
radius: 0,
stroke: "red",
strokeWidth: 5
});
layer.add(item);
const anim = new Konva.Animation(frame => {
item.radius(amplitude * Math.sin((frame.time * Math.PI) / 1000));
}, layer);
anim.start();
setTimeout(() => {
item.destroy();
anim.stop();
layer.batchDraw();
}, period);
},