HTML5 Canvas 图形调整尺寸和变换限制
要限制或更改调整尺寸和变换的行为,可以使用 boundBoxFunc 属性。
它的工作方式与 dragBoundFunc 类似。
操作说明:尝试调整图形尺寸 。你会看到其宽度限制为 200。
示例将新的包围盒收敛(clamp)到限制值,而不是直接拒绝它。如果在超出限制时简单地 return oldBox,快速移动鼠标会在一次事件中越过边界,图形就会卡在限制值之下。在 oldBox 和 newBox 之间插值可以精确地停在限制值上,并且对每个锚点都能保持图形另一侧固定不动。
你还可以单独控制每个锚点的移动。请参阅 调整尺寸吸附示例。
- 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 rect = new Konva.Rect({
x: 50,
y: 50,
width: 100,
height: 100,
fill: 'yellow',
stroke: 'black',
draggable: true,
});
layer.add(rect);
const tr = new Konva.Transformer({
nodes: [rect],
boundBoxFunc: (oldBox, newBox) => {
// limit resize to a maximum width of 200.
// clamp the box between oldBox and newBox instead of
// rejecting it, so a fast drag still lands exactly on the limit
if (newBox.width > 200) {
const t = (200 - oldBox.width) / (newBox.width - oldBox.width);
return {
x: oldBox.x + t * (newBox.x - oldBox.x),
y: oldBox.y + t * (newBox.y - oldBox.y),
width: 200,
height: oldBox.height + t * (newBox.height - oldBox.height),
rotation: newBox.rotation,
};
}
return newBox;
},
});
layer.add(tr);
import { Stage, Layer, Rect, Transformer } from 'react-konva';
import { useRef, useEffect, useState } from 'react';
const App = () => {
const [rectPosition, setRectPosition] = useState({ x: 50, y: 50 });
const rectRef = useRef();
const trRef = useRef();
useEffect(() => {
trRef.current.nodes([rectRef.current]);
}, []);
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Rect
x={rectPosition.x}
y={rectPosition.y}
width={100}
height={100}
fill="yellow"
stroke="black"
draggable
ref={rectRef}
onDragEnd={(e) => setRectPosition(e.target.position())}
onTransformEnd={(e) => setRectPosition(e.target.position())}
/>
<Transformer
ref={trRef}
boundBoxFunc={(oldBox, newBox) => {
// limit resize to a maximum width of 200.
// clamp the box between oldBox and newBox instead of
// rejecting it, so a fast drag still lands exactly on the limit
if (newBox.width > 200) {
const t = (200 - oldBox.width) / (newBox.width - oldBox.width);
return {
x: oldBox.x + t * (newBox.x - oldBox.x),
y: oldBox.y + t * (newBox.y - oldBox.y),
width: 200,
height: oldBox.height + t * (newBox.height - oldBox.height),
rotation: newBox.rotation,
};
}
return newBox;
}}
/>
</Layer>
</Stage>
);
};
export default App;
<template>
<v-stage :config="stageSize">
<v-layer>
<v-rect
:config="rectConfig"
ref="rectRef"
/>
<v-transformer
:config="transformerConfig"
ref="transformerRef"
/>
</v-layer>
</v-stage>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const stageSize = {
width: window.innerWidth,
height: window.innerHeight
};
const rectConfig = {
x: 50,
y: 50,
width: 100,
height: 100,
fill: 'yellow',
stroke: 'black',
draggable: true
};
const transformerConfig = {
boundBoxFunc: (oldBox, newBox) => {
// limit resize to a maximum width of 200.
// clamp the box between oldBox and newBox instead of
// rejecting it, so a fast drag still lands exactly on the limit
if (newBox.width > 200) {
const t = (200 - oldBox.width) / (newBox.width - oldBox.width);
return {
x: oldBox.x + t * (newBox.x - oldBox.x),
y: oldBox.y + t * (newBox.y - oldBox.y),
width: 200,
height: oldBox.height + t * (newBox.height - oldBox.height),
rotation: newBox.rotation,
};
}
return newBox;
}
};
const rectRef = ref(null);
const transformerRef = ref(null);
onMounted(() => {
transformerRef.value.getNode().nodes([rectRef.value.getNode()]);
});
</script>