HTML5 Canvas 强制更新教程
Konva.Transformer 会自动跟踪已附加节点的属性。
因此,它会自动调整自身的属性。
从 Konva 10.7.1 开始,Transformer 也会跟踪已附加的 Konva.Group 内部的更改:子节点的尺寸变化,以及子节点的添加或移除。在旧版本中,这些更改需要调用 forceUpdate,下面的演示就是这样做的。
如果要一次修改许多已附加的节点,请参见批量更新,这样只需支付一次 Transformer 更新的代价,而不是每次更改都更新一次。
但是,Konva.Transformer 无法检测未设置任何属性的更改。例如,原地修改 Konva.Line 的 points 数组,或者依赖外部状态的自定义 getSelfRect()。在此类更改之后,请调用 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>