HTML5 Canvas 强制更新教程
Konva.Transformer 会自动跟踪已附加节点的属性。
因此,它会自动调整自身的属性。
但在某些情况下,Konva.Transformer 无法执行此操作。目前,Konva.Transformer 无法跟踪 Konva.Group 节点内部的深层更改。在这种情况下,需要使用 forceUpdate 方法重置变换工具。
操作说明:单击按钮。观察 Transformer 的变化。
- Vanilla
- React
- Vue
import Konva from 'konva';
const width = window.innerWidth;
const height = window.innerHeight;
const stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
const layer = new Konva.Layer();
stage.add(layer);
const group = new Konva.Group({
x: 50,
y: 50,
draggable: true,
});
layer.add(group);
const text = new Konva.Text({
text: 'Some text here',
fontSize: 24,
});
group.add(text);
const rect = new Konva.Rect({
width: text.width(),
height: text.height(),
fill: 'yellow',
});
group.add(rect);
// add the shape to the layer
rect.moveToBottom();
const tr = new Konva.Transformer({
nodes: [group],
padding: 5,
// enable only one anchor
enabledAnchors: ['middle-left', 'middle-right'],
});
layer.add(tr);
const button = document.createElement('button');
button.innerHTML = 'Change text';
document.body.appendChild(button);
button.addEventListener('click', () => {
text.text('Something else is here');
rect.width(text.width());
// we need to update transformer manually
tr.forceUpdate();
});
import { Stage, Layer, Text, Rect, Group, Transformer } from 'react-konva';
import { useState, useRef, useLayoutEffect } from 'react';
const App = () => {
const [text, setText] = useState('Some text here');
const [groupPosition, setGroupPosition] = useState({ x: 50, y: 50 });
const groupRef = useRef();
const textRef = useRef();
const rectRef = useRef();
const trRef = useRef();
const handleClick = () => {
setText('Something else is here');
};
useLayoutEffect(() => {
const transformer = trRef.current;
const label = textRef.current;
const background = rectRef.current;
if (!transformer || !label || !background) return;
background.size({ width: label.width(), height: label.height() });
transformer.nodes([groupRef.current]);
transformer.forceUpdate();
}, [text]);
return (
<>
<button onClick={handleClick}>Change text</button>
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Group
x={groupPosition.x}
y={groupPosition.y}
draggable
ref={groupRef}
onDragEnd={(event) => setGroupPosition(event.target.position())}
onTransformEnd={(event) => setGroupPosition(event.target.position())}
>
<Rect
ref={rectRef}
width={0}
height={0}
fill="yellow"
/>
<Text
ref={textRef}
text={text}
fontSize={24}
/>
</Group>
<Transformer
ref={trRef}
padding={5}
enabledAnchors={['middle-left', 'middle-right']}
/>
</Layer>
</Stage>
</>
);
};
export default App;
<template>
<div>
<button @click="changeText">Change text</button>
<v-stage :config="stageSize">
<v-layer>
<v-group :config="groupConfig" ref="groupRef">
<v-rect :config="rectConfig" ref="rectRef" />
<v-text :config="textConfig" ref="textRef" />
</v-group>
<v-transformer :config="transformerConfig" ref="transformerRef" />
</v-layer>
</v-stage>
</div>
</template>
<script setup>
import { ref, computed, nextTick, onMounted } from 'vue';
const stageSize = {
width: window.innerWidth,
height: window.innerHeight
};
const text = ref('Some text here');
const groupRef = ref(null);
const textRef = ref(null);
const rectRef = ref(null);
const transformerRef = ref(null);
const groupConfig = {
x: 50,
y: 50,
draggable: true
};
const textConfig = computed(() => ({
text: text.value,
fontSize: 24
}));
const rectConfig = {
width: 0,
height: 0,
fill: 'yellow'
};
const transformerConfig = {
padding: 5,
enabledAnchors: ['middle-left', 'middle-right']
};
const updateTransformer = () => {
const label = textRef.value.getNode();
const background = rectRef.value.getNode();
const transformer = transformerRef.value.getNode();
background.size({ width: label.width(), height: label.height() });
transformer.forceUpdate();
};
const changeText = async () => {
text.value = 'Something else is here';
await nextTick();
updateTransformer();
};
onMounted(() => {
if (transformerRef.value && groupRef.value) {
transformerRef.value.getNode().nodes([groupRef.value.getNode()]);
updateTransformer();
}
});
</script>