Compare commits
10 Commits
010d9d8ea4
...
67c49a26a4
Author | SHA1 | Date |
---|---|---|
|
67c49a26a4 | |
|
e9e0dab2f8 | |
|
fbf929cc81 | |
|
1fd9d75928 | |
|
5ff3d64e23 | |
|
f86dfe348a | |
|
4a19611284 | |
|
07762aec41 | |
|
106f52f71e | |
|
a42bc7d82d |
90
README.md
90
README.md
|
@ -1,55 +1,37 @@
|
|||
```sh
|
||||
force update
|
||||
text resizing
|
||||
ignore stroke
|
||||
clipping
|
||||
simple clip
|
||||
complex clip
|
||||
groups, layers and ordering
|
||||
groups
|
||||
layering
|
||||
change containers
|
||||
zindex
|
||||
filters
|
||||
blur
|
||||
brighten
|
||||
contrast
|
||||
emboss
|
||||
enhance
|
||||
grayscale
|
||||
hsl
|
||||
hsv
|
||||
rgb
|
||||
invert
|
||||
kaleidoscope
|
||||
mask
|
||||
noise
|
||||
pixelate
|
||||
custom filter
|
||||
multiple filters
|
||||
tweens
|
||||
linear easing
|
||||
common easings
|
||||
all easings
|
||||
finish event
|
||||
all controls
|
||||
tween filter
|
||||
complex tweening
|
||||
animations
|
||||
create an animation
|
||||
moving
|
||||
rotation
|
||||
scaling
|
||||
stop animation
|
||||
selectors
|
||||
select by id
|
||||
select by type
|
||||
select by name
|
||||
data & serialization & export
|
||||
serialize a stage
|
||||
simple load
|
||||
complex load
|
||||
json best practices
|
||||
stage data url
|
||||
export to hd image
|
||||
```
|
||||
https://konvajs.org/docs/animations/Create_an_Animation.html
|
||||
https://konvajs.org/docs/animations/Moving.html
|
||||
https://konvajs.org/docs/animations/Rotation.html
|
||||
https://konvajs.org/docs/animations/Scaling.html
|
||||
https://konvajs.org/docs/animations/Stop_Animation.html
|
||||
|
||||
https://konvajs.org/docs/filters/Blur.html
|
||||
https://konvajs.org/docs/filters/Brighten.html
|
||||
https://konvajs.org/docs/filters/Contrast.html
|
||||
https://konvajs.org/docs/filters/Emboss.html
|
||||
https://konvajs.org/docs/filters/Enhance.html
|
||||
https://konvajs.org/docs/filters/Grayscale.html
|
||||
https://konvajs.org/docs/filters/HSL.html
|
||||
https://konvajs.org/docs/filters/HSV.html
|
||||
https://konvajs.org/docs/filters/RGB.html
|
||||
https://konvajs.org/docs/filters/Invert.html
|
||||
https://konvajs.org/docs/filters/Kaleidoscope.html
|
||||
https://konvajs.org/docs/filters/Mask.html
|
||||
https://konvajs.org/docs/filters/Noise.html
|
||||
https://konvajs.org/docs/filters/Pixelate.html
|
||||
https://konvajs.org/docs/filters/Custom_Filter.html
|
||||
https://konvajs.org/docs/filters/Multiple_Filters.html
|
||||
|
||||
https://konvajs.org/docs/data_and_serialization/Serialize_a_Stage.html
|
||||
https://konvajs.org/docs/data_and_serialization/Simple_Load.html
|
||||
https://konvajs.org/docs/data_and_serialization/Complex_Load.html
|
||||
https://konvajs.org/docs/data_and_serialization/Best_Practices.html
|
||||
https://konvajs.org/docs/data_and_serialization/Stage_Data_URL.html
|
||||
https://konvajs.org/docs/data_and_serialization/High-Quality-Export.html
|
||||
|
||||
https://konvajs.org/docs/performance/Shape_Redraw.html
|
||||
https://konvajs.org/docs/performance/Optimize_Strokes.html
|
||||
https://konvajs.org/docs/performance/Optimize_Animation.html
|
||||
https://konvajs.org/docs/performance/Batch_Draw.html
|
||||
https://konvajs.org/docs/performance/Layer_Management.html
|
||||
```
|
||||
|
|
|
@ -27,7 +27,7 @@ const include = [
|
|||
// 'sortablejs',
|
||||
// 'swiper/vue',
|
||||
// 'mint-filter',
|
||||
// '@vueuse/core',
|
||||
'@vueuse/core',
|
||||
// 'vue3-danmaku',
|
||||
// 'v-contextmenu',
|
||||
// 'vue-pdf-embed',
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"version":1721089915004}
|
||||
{"version":1721355798048}
|
|
@ -0,0 +1,90 @@
|
|||
<script setup lang="ts">
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import Konva from 'konva/lib';
|
||||
import { Group } from 'konva/lib/Group';
|
||||
import { Rect } from 'konva/lib/shapes/Rect';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
const yellowGroup = ref<Group>();
|
||||
const blueGroup = ref<Group>();
|
||||
const box = ref<Rect>();
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
yellowGroup.value = new Konva.Group({
|
||||
x: 100,
|
||||
y: 100,
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
blueGroup.value = new Konva.Group({
|
||||
x: 300,
|
||||
y: 80,
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
box.value = new Konva.Rect({
|
||||
x: 10,
|
||||
y: 10,
|
||||
width: 100,
|
||||
height: 50,
|
||||
fill: 'red',
|
||||
stroke: 'black',
|
||||
});
|
||||
|
||||
const yellowCircle = new Konva.Circle({
|
||||
x: 0,
|
||||
y: 0,
|
||||
radius: 50,
|
||||
fill: 'yellow',
|
||||
stroke: 'black',
|
||||
});
|
||||
|
||||
const blueCircle = new Konva.Circle({
|
||||
x: 0,
|
||||
y: 0,
|
||||
radius: 50,
|
||||
fill: 'blue',
|
||||
stroke: 'black',
|
||||
});
|
||||
|
||||
yellowGroup.value.add(yellowCircle);
|
||||
yellowGroup.value.add(box.value);
|
||||
blueGroup.value.add(blueCircle);
|
||||
layer.add(yellowGroup.value);
|
||||
layer.add(blueGroup.value);
|
||||
stage.add(layer);
|
||||
};
|
||||
|
||||
/**
|
||||
* * 移动到蓝色组
|
||||
*/
|
||||
const toBlue = () => {
|
||||
box.value?.moveTo(blueGroup.value);
|
||||
};
|
||||
|
||||
/**
|
||||
* * 移动到黄色
|
||||
*/
|
||||
const toYellow = () => {
|
||||
box.value?.moveTo(yellowGroup.value);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container-fluid">
|
||||
<button id="toBlue" class="btn btn-primary" @click="toBlue">Move red box to blue group</button>
|
||||
<button id="toYellow" class="btn btn-warning" @click="toYellow">Move red box to yellow group</button>
|
||||
<div id="container"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -0,0 +1,41 @@
|
|||
<script setup lang="ts">
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
import { onMounted } from 'vue';
|
||||
import Konva from 'konva/lib';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const group = new Konva.Group({ x: 120, y: 40, rotation: 20, draggable: true });
|
||||
const colors = ['red', 'orange', 'yellow'];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const rect = new Konva.Rect({
|
||||
x: i * 30,
|
||||
y: i * 30,
|
||||
width: 100,
|
||||
height: 20,
|
||||
name: `color${colors[i]}`,
|
||||
fill: colors[i],
|
||||
stroke: 'black',
|
||||
strokeWidth: 4,
|
||||
});
|
||||
group.add(rect);
|
||||
}
|
||||
|
||||
layer.add(group);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="container"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -0,0 +1,66 @@
|
|||
<script setup lang="ts">
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import Konva from 'konva/lib';
|
||||
import { Rect } from 'konva/lib/shapes/Rect';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
const yellowBox = ref<Rect>();
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'];
|
||||
|
||||
for (let n = 0; n < 6; n++) {
|
||||
(function () {
|
||||
const i = n;
|
||||
const box = new Konva.Rect({
|
||||
x: i * 30 + 210,
|
||||
y: i * 18 + 40,
|
||||
width: 100,
|
||||
height: 50,
|
||||
fill: colors[i],
|
||||
stroke: 'black',
|
||||
strokeWidth: 4,
|
||||
draggable: true,
|
||||
name: colors[i],
|
||||
});
|
||||
|
||||
box.on('mouseover', function () {
|
||||
document.body.style.cursor = 'pointer';
|
||||
});
|
||||
box.on('mouseout', function () {
|
||||
document.body.style.cursor = 'default';
|
||||
});
|
||||
if (colors[i] === 'yellow') {
|
||||
yellowBox.value = box;
|
||||
}
|
||||
layer.add(box);
|
||||
})();
|
||||
}
|
||||
|
||||
stage.add(layer);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container-fluid">
|
||||
<div id="buttons">
|
||||
<button id="toTop" class="btn btn-warning" @click="yellowBox?.moveToTop()">Move yellow box to top</button>
|
||||
<button id="toBottom" class="btn btn-outline-info" @click="yellowBox?.moveToBottom()">Move yellow box to bottom</button>
|
||||
<button id="up" class="btn btn-outline-warning" @click="yellowBox?.moveUp()">Move yellow box up</button>
|
||||
<button id="down " class="btn btn-info" @click="yellowBox?.moveDown()">Move yellow box down</button>
|
||||
<button id="zIndex" class="btn btn-primary" @click="yellowBox?.setZIndex(3)">Set yellow box zIndex to 3</button>
|
||||
</div>
|
||||
<div id="container"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -0,0 +1,55 @@
|
|||
<script setup lang="ts">
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
import Konva from 'konva/lib';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { Circle } from 'konva/lib/shapes/Circle';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
const circle = ref<Circle>();
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const group = new Konva.Group();
|
||||
layer.add(group);
|
||||
|
||||
circle.value = new Konva.Circle({
|
||||
x: 70,
|
||||
y: 70,
|
||||
fill: 'red',
|
||||
radius: 30,
|
||||
});
|
||||
group.add(circle.value);
|
||||
|
||||
const blackRect = new Konva.Rect({
|
||||
x: 20,
|
||||
y: 20,
|
||||
fill: 'black',
|
||||
width: 100,
|
||||
height: 100,
|
||||
});
|
||||
group.add(blackRect);
|
||||
};
|
||||
|
||||
/**
|
||||
* * 将圆形zIndex设置为1
|
||||
*/
|
||||
const updateCircle = () => {
|
||||
circle.value!.zIndex(1);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container-fluid">
|
||||
<button class="btn btn-primary" @click="updateCircle">将圆形zIndex设置为1</button>
|
||||
<div id="container"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -1,153 +1,48 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue';
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useEventListener, useWindowSize } from '@vueuse/core';
|
||||
import Konva from 'konva/lib';
|
||||
import { rect1, rect2, selectionRectangle } from '@/views/select/basic/rect.ts';
|
||||
import { stageEvent } from '@/views/select/basic/stageEvent.ts';
|
||||
import { drawLine } from '@/views/select/basic/line.ts';
|
||||
import { Stage } from 'konva/lib/Stage';
|
||||
import { Layer } from 'konva/lib/Layer';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
// let stage, layer;
|
||||
|
||||
const stage = ref<Stage>();
|
||||
const layer = ref<Layer>();
|
||||
const tr = ref();
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
const layer = new Konva.Layer();
|
||||
stage.value = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
layer.value = new Konva.Layer();
|
||||
stage.value.add(layer.value);
|
||||
|
||||
const rect1 = new Konva.Rect({
|
||||
x: 60,
|
||||
y: 60,
|
||||
width: 100,
|
||||
height: 90,
|
||||
fill: 'red',
|
||||
name: 'rect',
|
||||
draggable: true,
|
||||
});
|
||||
layer.add(rect1);
|
||||
drawLine(stage.value, layer.value);
|
||||
|
||||
const rect2 = new Konva.Rect({
|
||||
x: 180,
|
||||
y: 200,
|
||||
width: 100,
|
||||
height: 200,
|
||||
fill: 'green',
|
||||
name: 'rect',
|
||||
draggable: true,
|
||||
});
|
||||
layer.add(rect2);
|
||||
rect1(layer.value);
|
||||
rect2(layer.value);
|
||||
|
||||
// 添加缩放
|
||||
const tr = new Konva.Transformer();
|
||||
layer.add(tr);
|
||||
tr.nodes([rect1, rect2]);
|
||||
tr.value = new Konva.Transformer();
|
||||
layer.value.add(tr.value);
|
||||
|
||||
const selectionRectangle = new Konva.Rect({
|
||||
fill: 'rgba(0,0,255,0.5)',
|
||||
visible: false,
|
||||
// disable events to not interrupt with events
|
||||
listening: false,
|
||||
});
|
||||
layer.add(selectionRectangle);
|
||||
|
||||
let x1 = 0,
|
||||
y1 = 0,
|
||||
x2 = 0,
|
||||
y2 = 0;
|
||||
let selecting = false;
|
||||
stage.on('mousedown touchstart', e => {
|
||||
// do nothing if we mousedown on any shape
|
||||
if (e.target !== stage) {
|
||||
return;
|
||||
}
|
||||
e.evt.preventDefault();
|
||||
x1 = stage.getPointerPosition()!.x;
|
||||
y1 = stage.getPointerPosition()!.y;
|
||||
x2 = stage.getPointerPosition()!.x;
|
||||
y2 = stage.getPointerPosition()!.y;
|
||||
|
||||
selectionRectangle.width(0);
|
||||
selectionRectangle.height(0);
|
||||
selecting = true;
|
||||
});
|
||||
|
||||
stage.on('mousemove touchmove', e => {
|
||||
// do nothing if we didn't start selection
|
||||
if (!selecting) {
|
||||
return;
|
||||
}
|
||||
e.evt.preventDefault();
|
||||
x2 = stage.getPointerPosition()!.x;
|
||||
y2 = stage.getPointerPosition()!.y;
|
||||
|
||||
selectionRectangle.setAttrs({
|
||||
visible: true,
|
||||
x: Math.min(x1, x2),
|
||||
y: Math.min(y1, y2),
|
||||
width: Math.abs(x2 - x1),
|
||||
height: Math.abs(y2 - y1),
|
||||
});
|
||||
});
|
||||
|
||||
stage.on('mouseup touchend', e => {
|
||||
// do nothing if we didn't start selection
|
||||
selecting = false;
|
||||
if (!selectionRectangle.visible()) {
|
||||
return;
|
||||
}
|
||||
e.evt.preventDefault();
|
||||
// update visibility in timeout, so we can check it in click event
|
||||
selectionRectangle.visible(false);
|
||||
let shapes = stage.find('.rect');
|
||||
let box = selectionRectangle.getClientRect();
|
||||
let selected = shapes.filter(shape => Konva.Util.haveIntersection(box, shape.getClientRect()));
|
||||
tr.nodes(selected);
|
||||
});
|
||||
|
||||
// clicks should select/deselect shapes
|
||||
stage.on('click tap', function (e) {
|
||||
// if we are selecting with rect, do nothing
|
||||
if (selectionRectangle.visible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if click on empty area - remove all selections
|
||||
if (e.target === stage) {
|
||||
tr.nodes([]);
|
||||
return;
|
||||
}
|
||||
|
||||
// do nothing if clicked NOT on our rectangles
|
||||
if (!e.target.hasName('rect')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do we pressed shift or ctrl?
|
||||
const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
|
||||
const isSelected = tr.nodes().indexOf(e.target) >= 0;
|
||||
|
||||
if (!metaPressed && !isSelected) {
|
||||
// if no key pressed and the node is not selected
|
||||
// select just one
|
||||
tr.nodes([e.target]);
|
||||
} else if (metaPressed && isSelected) {
|
||||
// if we pressed keys and node was selected
|
||||
// we need to remove it from selection:
|
||||
const nodes = tr.nodes().slice(); // use slice to have new copy of array
|
||||
// remove node from array
|
||||
nodes.splice(nodes.indexOf(e.target), 1);
|
||||
tr.nodes(nodes);
|
||||
} else if (metaPressed && !isSelected) {
|
||||
// add the node into selection
|
||||
const nodes = tr.nodes().concat([e.target]);
|
||||
tr.nodes(nodes);
|
||||
}
|
||||
});
|
||||
|
||||
stage.add(layer);
|
||||
stageEvent(stage.value, selectionRectangle(layer.value), tr.value);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
useEventListener(window, 'resize', function () {
|
||||
stage.value?.width(width.value);
|
||||
stage.value?.height(height.value);
|
||||
|
||||
// tr.value.forceUpdate();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="container"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import { Stage } from 'konva/lib/Stage';
|
||||
import { Layer } from 'konva/lib/Layer';
|
||||
import Konva from 'konva/lib';
|
||||
|
||||
export const drawLine = (stage: Stage, layer: Layer) => {
|
||||
const xSnaps = Math.round(stage.width() / 50);
|
||||
const ySnaps = Math.round(stage.height() / 50);
|
||||
const cellWidth = stage.width() / xSnaps;
|
||||
const cellHeight = stage.height() / ySnaps;
|
||||
|
||||
for (let i = 0; i < xSnaps; i++) {
|
||||
const xLine = new Konva.Line({
|
||||
x: i * cellWidth,
|
||||
points: [0, 0, 0, stage.height()],
|
||||
stroke: '#96e04d',
|
||||
strokeWidth: 1,
|
||||
id: 'line',
|
||||
});
|
||||
layer.add(xLine);
|
||||
}
|
||||
|
||||
for (let i = 0; i < ySnaps; i++) {
|
||||
layer.add(
|
||||
new Konva.Line({
|
||||
y: i * cellHeight,
|
||||
points: [0, 0, stage.width(), 0],
|
||||
stroke: '#96e04d',
|
||||
strokeWidth: 1,
|
||||
id: 'line',
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
import { Layer } from 'konva/lib/Layer';
|
||||
import Konva from 'konva/lib';
|
||||
|
||||
export const rect1 = (parent: Layer) => {
|
||||
const rect = new Konva.Rect({
|
||||
x: 60,
|
||||
y: 60,
|
||||
width: 100,
|
||||
height: 90,
|
||||
fill: 'red',
|
||||
name: 'rect',
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
parent.add(rect);
|
||||
return rect;
|
||||
};
|
||||
export const rect2 = (parent: Layer) => {
|
||||
const rect = new Konva.Rect({
|
||||
x: 180,
|
||||
y: 200,
|
||||
width: 100,
|
||||
height: 200,
|
||||
fill: 'green',
|
||||
name: 'rect',
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
parent.add(rect);
|
||||
return rect;
|
||||
};
|
||||
|
||||
export const selectionRectangle = (layer: Layer) => {
|
||||
const selectionRectangle = new Konva.Rect({
|
||||
fill: 'rgba(0,0,255,0.5)',
|
||||
visible: false,
|
||||
listening: false,
|
||||
});
|
||||
layer.add(selectionRectangle);
|
||||
return selectionRectangle;
|
||||
};
|
|
@ -0,0 +1,93 @@
|
|||
import Konva from 'konva/lib';
|
||||
import { Stage } from 'konva/lib/Stage';
|
||||
import { Rect } from 'konva/lib/shapes/Rect';
|
||||
import { Transformer } from 'konva/lib/shapes/Transformer';
|
||||
|
||||
export const stageEvent = (stage: Stage, selectionRectangle: Rect, tr: Transformer) => {
|
||||
let x1 = 0,
|
||||
y1 = 0,
|
||||
x2 = 0,
|
||||
y2 = 0;
|
||||
let selecting = false;
|
||||
stage.on('mousedown touchstart', e => {
|
||||
e.evt.preventDefault();
|
||||
|
||||
x1 = stage.getPointerPosition()!.x;
|
||||
y1 = stage.getPointerPosition()!.y;
|
||||
x2 = stage.getPointerPosition()!.x;
|
||||
y2 = stage.getPointerPosition()!.y;
|
||||
|
||||
selectionRectangle.width(0);
|
||||
selectionRectangle.height(0);
|
||||
selecting = true;
|
||||
});
|
||||
|
||||
stage.on('mousemove touchmove', e => {
|
||||
if (!selecting) return;
|
||||
e.evt.preventDefault();
|
||||
|
||||
x2 = stage.getPointerPosition()!.x;
|
||||
y2 = stage.getPointerPosition()!.y;
|
||||
|
||||
selectionRectangle.setAttrs({
|
||||
visible: true,
|
||||
x: Math.min(x1, x2),
|
||||
y: Math.min(y1, y2),
|
||||
width: Math.abs(x2 - x1),
|
||||
height: Math.abs(y2 - y1),
|
||||
});
|
||||
});
|
||||
|
||||
stage.on('mouseup touchend', e => {
|
||||
selecting = false;
|
||||
if (!selectionRectangle.visible()) return;
|
||||
e.evt.preventDefault();
|
||||
|
||||
// update visibility in timeout, so we can check it in click event
|
||||
selectionRectangle.visible(false);
|
||||
let shapes = stage.find('.rect');
|
||||
let box = selectionRectangle.getClientRect();
|
||||
let selected = shapes.filter(shape => Konva.Util.haveIntersection(box, shape.getClientRect()));
|
||||
tr.nodes(selected);
|
||||
});
|
||||
|
||||
// clicks should select/deselect shapes
|
||||
stage.on('click tap', function (e) {
|
||||
// if we are selecting with rect, do nothing
|
||||
if (selectionRectangle.visible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if click on empty area - remove all selections
|
||||
if (e.target === stage) {
|
||||
tr.nodes([]);
|
||||
return;
|
||||
}
|
||||
|
||||
// do nothing if clicked NOT on our rectangles
|
||||
if (!e.target.hasName('rect')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do we pressed shift or ctrl?
|
||||
const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
|
||||
const isSelected = tr.nodes().indexOf(e.target) >= 0;
|
||||
|
||||
if (!metaPressed && !isSelected) {
|
||||
// if no key pressed and the node is not selected
|
||||
// select just one
|
||||
tr.nodes([e.target]);
|
||||
} else if (metaPressed && isSelected) {
|
||||
// if we pressed keys and node was selected
|
||||
// we need to remove it from selection:
|
||||
const nodes = tr.nodes().slice(); // use slice to have new copy of array
|
||||
// remove node from array
|
||||
nodes.splice(nodes.indexOf(e.target), 1);
|
||||
tr.nodes(nodes);
|
||||
} else if (metaPressed && !isSelected) {
|
||||
// add the node into selection
|
||||
const nodes = tr.nodes().concat([e.target]);
|
||||
tr.nodes(nodes);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue';
|
||||
import Konva from 'konva/lib';
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
const MIN_WIDTH = 100;
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const text = new Konva.Text({
|
||||
x: 50,
|
||||
y: 60,
|
||||
fontSize: 20,
|
||||
text: 'Hello from the Konva framework. Try to resize me.',
|
||||
draggable: true,
|
||||
});
|
||||
layer.add(text);
|
||||
|
||||
const tr = new Konva.Transformer({
|
||||
nodes: [text],
|
||||
padding: 5,
|
||||
flipEnabled: false,
|
||||
enabledAnchors: ['middle-left', 'middle-right'],
|
||||
boundBoxFunc(oldBox, newBox) {
|
||||
if (Math.abs(newBox.width) < MIN_WIDTH) {
|
||||
return oldBox;
|
||||
}
|
||||
return newBox;
|
||||
},
|
||||
});
|
||||
|
||||
layer.add(tr);
|
||||
|
||||
text.on('transform', () => {
|
||||
text.setAttrs({
|
||||
width: Math.max(text.width() * text.scaleX(), MIN_WIDTH),
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="container"></div>
|
||||
</template>
|
|
@ -0,0 +1,103 @@
|
|||
<script setup lang="ts">
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
import { onMounted } from 'vue';
|
||||
import Konva from 'konva/lib';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
stage.draggable(true);
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const greenBox = new Konva.Rect({
|
||||
x: 70,
|
||||
y: stage.height() / 2,
|
||||
width: 100,
|
||||
height: 50,
|
||||
fill: 'green',
|
||||
stroke: 'black',
|
||||
strokeWidth: 4,
|
||||
offset: {
|
||||
x: 50,
|
||||
y: 25,
|
||||
},
|
||||
});
|
||||
|
||||
const blueBox = new Konva.Rect({
|
||||
x: 190,
|
||||
y: stage.height() / 2,
|
||||
width: 100,
|
||||
height: 50,
|
||||
fill: 'blue',
|
||||
stroke: 'black',
|
||||
strokeWidth: 4,
|
||||
offset: {
|
||||
x: 50,
|
||||
y: 25,
|
||||
},
|
||||
});
|
||||
|
||||
const redBox = new Konva.Rect({
|
||||
x: 310,
|
||||
y: stage.height() / 2,
|
||||
width: 100,
|
||||
height: 50,
|
||||
fill: 'red',
|
||||
stroke: 'black',
|
||||
strokeWidth: 4,
|
||||
offset: {
|
||||
x: 50,
|
||||
y: 25,
|
||||
},
|
||||
});
|
||||
layer.add(greenBox);
|
||||
layer.add(blueBox);
|
||||
layer.add(redBox);
|
||||
|
||||
// the tween has to be created after the node has been added to the layer
|
||||
greenBox.tween = new Konva.Tween({
|
||||
node: greenBox,
|
||||
scaleX: 2,
|
||||
scaleY: 1.5,
|
||||
easing: Konva.Easings.EaseIn,
|
||||
duration: 1,
|
||||
});
|
||||
|
||||
blueBox.tween = new Konva.Tween({
|
||||
node: blueBox,
|
||||
scaleX: 2,
|
||||
scaleY: 1.5,
|
||||
easing: Konva.Easings.EaseInOut,
|
||||
duration: 1,
|
||||
});
|
||||
|
||||
redBox.tween = new Konva.Tween({
|
||||
node: redBox,
|
||||
scaleX: 2,
|
||||
scaleY: 1.5,
|
||||
easing: Konva.Easings.EaseOut,
|
||||
duration: 1,
|
||||
});
|
||||
|
||||
// use event delegation
|
||||
layer.on('mouseover touchstart', function (evt) {
|
||||
evt.target.tween.play();
|
||||
});
|
||||
|
||||
layer.on('mouseout touchend', function (evt) {
|
||||
evt.target.tween.reverse();
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="container"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -0,0 +1,51 @@
|
|||
<script setup lang="ts">
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
import { onMounted } from 'vue';
|
||||
import Konva from 'konva/lib';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const rect = new Konva.Rect({
|
||||
x: 50,
|
||||
y: 20,
|
||||
width: 120,
|
||||
height: 50,
|
||||
fill: 'green',
|
||||
stroke: 'black',
|
||||
strokeWidth: 2,
|
||||
opacity: 0.2,
|
||||
});
|
||||
layer.add(rect);
|
||||
|
||||
const tween = new Konva.Tween({
|
||||
node: rect,
|
||||
duration: 1,
|
||||
x: 140,
|
||||
y: 90,
|
||||
fill: 'red',
|
||||
rotation: Math.PI * 2,
|
||||
opacity: 1,
|
||||
strokeWidth: 6,
|
||||
scaleX: 1.5,
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
tween.play();
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="container"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -0,0 +1,59 @@
|
|||
<script setup lang="ts">
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
import { onMounted } from 'vue';
|
||||
import Konva from 'konva/lib';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
|
||||
const initial = () => {
|
||||
const stage = new Konva.Stage({ container: 'container', width: width.value, height: height.value });
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const image = new Image();
|
||||
const lion = new Konva.Image({
|
||||
x: 80,
|
||||
y: 30,
|
||||
width: 50,
|
||||
height: 50,
|
||||
draggable: true,
|
||||
image,
|
||||
});
|
||||
layer.add(lion);
|
||||
|
||||
image.crossOrigin = 'Anonymous';
|
||||
image.src = 'https://konvajs.org/assets/darth-vader.jpg';
|
||||
|
||||
image.onload = function () {
|
||||
lion.image(image);
|
||||
lion.cache();
|
||||
lion.filters([Konva.Filters.Blur]);
|
||||
lion.blurRadius(100);
|
||||
|
||||
const tween = new Konva.Tween({
|
||||
node: lion,
|
||||
duration: 0.6,
|
||||
blurRadius: 0,
|
||||
easing: Konva.Easings.EaseInOut,
|
||||
});
|
||||
|
||||
lion.on('mouseover', function () {
|
||||
tween.play();
|
||||
});
|
||||
|
||||
lion.on('mouseout', function () {
|
||||
tween.reverse();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initial();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="container"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
Loading…
Reference in New Issue