mirror of
https://github.com/konvajs/konva.git
synced 2025-06-28 02:03:47 +08:00
update test
This commit is contained in:
parent
578191d5d4
commit
d5eceafcae
@ -137,5 +137,8 @@
|
||||
"type": "git",
|
||||
"url": "git://github.com/konvajs/konva.git"
|
||||
},
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
30
test/TransformerX.js
Normal file
30
test/TransformerX.js
Normal file
@ -0,0 +1,30 @@
|
||||
import { Transformer } from '../src/shapes/Transformer';
|
||||
|
||||
const ANCHORS_NAMES = [
|
||||
'top-center',
|
||||
// 'top-right',
|
||||
'middle-right',
|
||||
'middle-left',
|
||||
// 'bottom-left',
|
||||
'bottom-center'
|
||||
// 'bottom-right',
|
||||
];
|
||||
|
||||
export class TransformerX extends Transformer {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
// _createElements() {
|
||||
// console.log('_createElements');
|
||||
// this._createBack();
|
||||
//
|
||||
// ANCHORS_NAMES.forEach(
|
||||
// function (name) {
|
||||
// this._createAnchor(name);
|
||||
// }.bind(this)
|
||||
// );
|
||||
//
|
||||
// this._createAnchor('rotater');
|
||||
// }
|
||||
}
|
BIN
test/assets/sticker.jpg
Normal file
BIN
test/assets/sticker.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
93
test/circularQueue.js
Normal file
93
test/circularQueue.js
Normal file
@ -0,0 +1,93 @@
|
||||
export class circularQueue {
|
||||
constructor(size) {
|
||||
this.length = size
|
||||
this.front = 0
|
||||
this.tail = 0
|
||||
this.current = 0
|
||||
this.list = new Array(size)
|
||||
}
|
||||
|
||||
get canMoveForward() {
|
||||
// 能否后移
|
||||
return (this.current + 1) % this.length !== this.tail
|
||||
}
|
||||
get canMoveBack() {
|
||||
// current能否回退
|
||||
return this.current !== this.front
|
||||
}
|
||||
|
||||
clearAfterCurrent() {
|
||||
let i = this.current
|
||||
const length = this.length
|
||||
|
||||
while ((i + 1) % length !== this.tail) {
|
||||
const clearIndex = (i + 1) % length
|
||||
this.list[clearIndex] = undefined
|
||||
i = clearIndex
|
||||
}
|
||||
this.tail = (this.current + 1) % this.length
|
||||
}
|
||||
|
||||
// 入队
|
||||
enqueue(item) {
|
||||
// 当入队时current不是处于队尾指针的前驱时,需要清空current到队尾之间的所有元素,并重置尾指针
|
||||
if (this.isFull() && (this.current + 1) % this.length !== this.tail) {
|
||||
this.clearAfterCurrent()
|
||||
}
|
||||
|
||||
if (this.isFull()) {
|
||||
this.tail = (this.current + 1) % this.length
|
||||
// 满了移动头指针
|
||||
this.front = (this.front + 1) % this.length
|
||||
}
|
||||
this.list[this.tail] = item
|
||||
this.current = this.tail
|
||||
this.tail = (this.tail + 1) % this.length
|
||||
}
|
||||
|
||||
// 不涉及
|
||||
dequeue() {}
|
||||
|
||||
isEmpty = () => {
|
||||
return typeof this.list[this.front] === 'undefined'
|
||||
}
|
||||
|
||||
isFull = () => {
|
||||
return (
|
||||
this.front === this.tail &&
|
||||
typeof this.list[this.front] !== 'undefined'
|
||||
)
|
||||
} // 队列满了
|
||||
|
||||
getCurrent() {
|
||||
console.log('getCurrent', this.list[this.current])
|
||||
return this.list[this.current]
|
||||
}
|
||||
|
||||
// 往右移一步 (尾指针方向)
|
||||
moveForward() {
|
||||
if (this.canMoveForward) {
|
||||
this.current = this.isFull()
|
||||
? (this.current - 1 + this.length) % this.length
|
||||
: this.current + 1
|
||||
}
|
||||
}
|
||||
// 往左移一步 (头指针方向)
|
||||
moveBack() {
|
||||
if (this.canMoveBack) {
|
||||
this.current = this.isFull()
|
||||
? (this.current - 1 + this.length) % this.length
|
||||
: this.current - 1
|
||||
}
|
||||
}
|
||||
|
||||
print() {
|
||||
let i = 0
|
||||
let p = this.front
|
||||
while (i < this.length) {
|
||||
console.log(this.list[p])
|
||||
p = (p + 1) % this.length
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
40
test/debounce.js
Normal file
40
test/debounce.js
Normal file
@ -0,0 +1,40 @@
|
||||
import restArguments from './restArguments.js';
|
||||
import now from './now.js';
|
||||
|
||||
// When a sequence of calls of the returned function ends, the argument
|
||||
// function is triggered. The end of a sequence is defined by the `wait`
|
||||
// parameter. If `immediate` is passed, the argument function will be
|
||||
// triggered at the beginning of the sequence instead of at the end.
|
||||
export default function debounce(func, wait, immediate) {
|
||||
var timeout, previous, args, result, context;
|
||||
|
||||
var later = function() {
|
||||
var passed = now() - previous;
|
||||
if (wait > passed) {
|
||||
timeout = setTimeout(later, wait - passed);
|
||||
} else {
|
||||
timeout = null;
|
||||
if (!immediate) result = func.apply(context, args);
|
||||
// This check is needed because `func` can recursively invoke `debounced`.
|
||||
if (!timeout) args = context = null;
|
||||
}
|
||||
};
|
||||
|
||||
var debounced = restArguments(function(_args) {
|
||||
context = this;
|
||||
args = _args;
|
||||
previous = now();
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(later, wait);
|
||||
if (immediate) result = func.apply(context, args);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
debounced.cancel = function() {
|
||||
clearTimeout(timeout);
|
||||
timeout = args = context = null;
|
||||
};
|
||||
|
||||
return debounced;
|
||||
}
|
66
test/image.js
Normal file
66
test/image.js
Normal file
@ -0,0 +1,66 @@
|
||||
// noinspection JSCheckFunctionSignatures
|
||||
import Konva from '../src/index.ts';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
export class imageSprite {
|
||||
constructor(options) {
|
||||
// this._stage = options.stage;
|
||||
this._stageWidthMedian = options.stage.getWidth() / 2;
|
||||
this._stageHeightMedian = options.stage.getHeight() / 2;
|
||||
console.log(options.stage);
|
||||
}
|
||||
|
||||
createTexture(source) {
|
||||
if (Object.prototype.toString.call(source) === '[object Object]') {
|
||||
return ( async () => {
|
||||
const imageObj = await this.addImageProcess(source.url);
|
||||
delete source.url;
|
||||
return this.generateImageObject(imageObj, source);
|
||||
} )();
|
||||
} else if (Array.isArray(source)) {
|
||||
const loadSource = [];
|
||||
source.forEach((option) => {
|
||||
const preloading = ( async () => {
|
||||
const imageObj = await this.addImageProcess(option.url);
|
||||
delete option.url;
|
||||
return this.generateImageObject(imageObj, option);
|
||||
}
|
||||
)();
|
||||
loadSource.push(preloading);
|
||||
});
|
||||
|
||||
// 图片全部加载完
|
||||
return Promise.all(loadSource).then((data) => {
|
||||
// console.log(data)
|
||||
return data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
generateImageObject(imageObj, options) {
|
||||
let optionsConfig = options || {};
|
||||
delete optionsConfig.url;
|
||||
const config = {
|
||||
x: this._stageWidthMedian,
|
||||
y: this._stageHeightMedian,
|
||||
image: imageObj,
|
||||
...optionsConfig
|
||||
};
|
||||
const texture = new Konva.Image(config);
|
||||
texture.offsetX(texture.width() / 2);
|
||||
texture.offsetY(texture.height() / 2);
|
||||
!optionsConfig.id ? texture.id(nanoid()) : '';
|
||||
return texture;
|
||||
}
|
||||
|
||||
addImageProcess(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
// img.crossOrigin = 'anonymous'; // to avoid CORS if used with Canvas
|
||||
img.onload = () => resolve(img);
|
||||
img.onerror = e => reject(e);
|
||||
img.src = src;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
4
test/now.js
Normal file
4
test/now.js
Normal file
@ -0,0 +1,4 @@
|
||||
// A (possibly faster) way to get the current timestamp as an integer.
|
||||
export default Date.now || function() {
|
||||
return new Date().getTime();
|
||||
};
|
11
test/rect.js
Normal file
11
test/rect.js
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
import Konva from '../src/index.ts';
|
||||
export function createRect() {
|
||||
return new Konva.Rect({
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fill: '#F78AE0'
|
||||
});
|
||||
}
|
27
test/restArguments.js
Normal file
27
test/restArguments.js
Normal file
@ -0,0 +1,27 @@
|
||||
// Some functions take a variable number of arguments, or a few expected
|
||||
// arguments at the beginning and then a variable number of values to operate
|
||||
// on. This helper accumulates all remaining arguments past the function’s
|
||||
// argument length (or an explicit `startIndex`), into an array that becomes
|
||||
// the last argument. Similar to ES6’s "rest parameter".
|
||||
export default function restArguments(func, startIndex) {
|
||||
startIndex = startIndex == null ? func.length - 1 : +startIndex;
|
||||
return function() {
|
||||
var length = Math.max(arguments.length - startIndex, 0),
|
||||
rest = Array(length),
|
||||
index = 0;
|
||||
for (; index < length; index++) {
|
||||
rest[index] = arguments[index + startIndex];
|
||||
}
|
||||
switch (startIndex) {
|
||||
case 0: return func.call(this, rest);
|
||||
case 1: return func.call(this, arguments[0], rest);
|
||||
case 2: return func.call(this, arguments[0], arguments[1], rest);
|
||||
}
|
||||
var args = Array(startIndex + 1);
|
||||
for (index = 0; index < startIndex; index++) {
|
||||
args[index] = arguments[index];
|
||||
}
|
||||
args[startIndex] = rest;
|
||||
return func.apply(this, args);
|
||||
};
|
||||
}
|
@ -1,57 +1,278 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>KonvaJS Sandbox</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, user-scalable=1.0, minimum-scale=1.0, maximum-scale=1.0"
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, user-scalable=1.0, minimum-scale=1.0, maximum-scale=1.0"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.playgroundContainer {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.toolBar {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
|
||||
position: relative;
|
||||
top: 0;
|
||||
border-bottom: 1px solid slateblue;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 68px;
|
||||
height: 36px;
|
||||
outline: none;
|
||||
border: none;
|
||||
|
||||
border-radius: 6px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
/*background-color: transparent;*/
|
||||
background-color: #316DAC;
|
||||
color: #FFFFFF;
|
||||
display: block;
|
||||
user-select: none; /* Non-prefixed version, currently*/
|
||||
|
||||
font-size: 13px;
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.button:focus,
|
||||
.button:hover {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<!-- <script src="https://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js"></script> -->
|
||||
<script>
|
||||
// TouchEmulator();
|
||||
// TouchEmulator();
|
||||
</script>
|
||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.7/hammer.js"></script> -->
|
||||
<!-- <script src="https://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js"></script> -->
|
||||
<!-- <script src="./hammer.js"></script> -->
|
||||
<!-- <script src="https://unpkg.com/fabric@5.2.1/dist/fabric.js"></script> -->
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container" style="background-color: bisque"></div>
|
||||
<body>
|
||||
<div class="playgroundContainer">
|
||||
<div class="toolBar">
|
||||
<button class="button" id="toAddShape">Add Shape</button>
|
||||
<button class="button" id="toAddText">Add Text</button>
|
||||
<button class="button">导出</button>
|
||||
<button class="button" id="toMoveBack">撤销</button>
|
||||
<button class="button" id="toMoveForward">重做</button>
|
||||
</div>
|
||||
<div id="container"></div>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import Konva from '../src/index.ts';
|
||||
<script type="module">
|
||||
import { circularQueue } from './circularQueue.js';
|
||||
import { sandboxDemo } from './sandbox.js';
|
||||
import { TransformerX } from './TransformerX.js';
|
||||
import { createRect } from './rect.js';
|
||||
import { createText } from './text.js';
|
||||
import { imageSprite } from './image';
|
||||
import debounce from './debounce';
|
||||
|
||||
const stage = new Konva.Stage({
|
||||
container: 'container',
|
||||
width: window.innerWidth / 2,
|
||||
height: window.innerHeight / 2,
|
||||
});
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
const rect = new Konva.Rect({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fill: 'red',
|
||||
});
|
||||
layer.add(rect);
|
||||
stage.on('wheel', (e) => {
|
||||
e.evt.preventDefault();
|
||||
console.log('wheel');
|
||||
});
|
||||
stage.on('contextmenu', (e) => {
|
||||
console.log('click');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
// let textTransformer;
|
||||
const TEXT_MIN_WIDTH = 100;
|
||||
const TEXT_MIN_HEIGHT = 100;
|
||||
const transformer = new TransformerX();
|
||||
const textTransformer = new TransformerX({
|
||||
padding: 5,
|
||||
// enable only side anchors
|
||||
enabledAnchors: ['middle-left', 'middle-right'],
|
||||
// limit transformer size
|
||||
boundBoxFunc: (oldBox, newBox) => {
|
||||
if (newBox.width < TEXT_MIN_WIDTH) {
|
||||
return oldBox;
|
||||
}
|
||||
return newBox;
|
||||
}
|
||||
});
|
||||
|
||||
const textConfig = {
|
||||
'text': '你爱输入什么都行没dfgdffg拭找34554imiadf测拭3453534sfgsf哈哈哈!', 'fontSize': 32, 'fill': '#315DAC'
|
||||
};
|
||||
const currentTargetAttrs = {
|
||||
'target': null,
|
||||
'attrs': {
|
||||
draggable: 0, fill: 0, height: 0, rotation: 0, scaleX: 0, scaleY: 0, skewX: 0, skewY: 0, width: 0,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
function Main() {
|
||||
|
||||
const queue = new circularQueue(3);
|
||||
|
||||
const { stage, container } = sandboxDemo();
|
||||
const IMAGE = new imageSprite({ stage });
|
||||
|
||||
container.add(transformer);
|
||||
container.add(textTransformer);
|
||||
|
||||
const addTextButton = document.querySelector('#toAddText');
|
||||
const addShapeButton = document.querySelector('#toAddShape');
|
||||
const moveBackButton = document.querySelector('#toMoveBack');
|
||||
const moveForwardButton = document.querySelector('#toMoveForward');
|
||||
|
||||
const imageList = [];
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
imageList.push({ url: '/assets/sticker.jpg' });
|
||||
}
|
||||
|
||||
addShapeButton.addEventListener('click', function () {
|
||||
const rect = createRect();
|
||||
IMAGE.createTexture(imageList).then(response => {
|
||||
container.add(...response);
|
||||
|
||||
});
|
||||
|
||||
rect.draggable(true);
|
||||
transformer.nodes([]);
|
||||
transformer.nodes([rect]);
|
||||
currentTargetAttrs['target'] = rect;
|
||||
for (const key in currentTargetAttrs['attrs']) {
|
||||
// console.log(key)
|
||||
if (rect.getAttr(key)) currentTargetAttrs['attrs'][key] = rect.getAttr(key);
|
||||
}
|
||||
|
||||
queue.enqueue(currentTargetAttrs);
|
||||
console.log(currentTargetAttrs);
|
||||
});
|
||||
|
||||
addTextButton.addEventListener('click', function () {
|
||||
createText(textConfig).then(response => {
|
||||
const text = response;
|
||||
container.add(text);
|
||||
!!textTransformer && textTransformer.nodes([]);
|
||||
// noinspection JSCheckFunctionSignatures
|
||||
textTransformer.nodes([text]);
|
||||
text.draggable(true);
|
||||
text.on('transform', (node) => {
|
||||
console.log(node);
|
||||
// with enabled anchors we can only change scaleX
|
||||
// so we don't need to reset height
|
||||
// just width
|
||||
text.setAttrs({
|
||||
width: Math.max(text.width() * text.scaleX(), TEXT_MIN_WIDTH),
|
||||
scaleX: 1,
|
||||
scaleY: 1
|
||||
});
|
||||
});
|
||||
console.log(text.toJSON());
|
||||
});
|
||||
});
|
||||
|
||||
moveBackButton.addEventListener('click', function () {
|
||||
queue.moveBack();
|
||||
applyNodeAttr(queue);
|
||||
});
|
||||
|
||||
moveForwardButton.addEventListener('click', function () {
|
||||
queue.moveForward();
|
||||
applyNodeAttr(queue);
|
||||
});
|
||||
|
||||
function applyNodeAttr(queue) {
|
||||
const { target, attrs } = queue.getCurrent();
|
||||
const currentChildren = container.getChildren(function (node) {
|
||||
return node.getClassName() === 'Rect';
|
||||
});
|
||||
|
||||
console.log(target.getClassName());
|
||||
currentChildren[0].setAttrs(attrs);
|
||||
}
|
||||
|
||||
console.log(queue);
|
||||
// const chineseReg = /[\u4e00-\u9fa5]/g;
|
||||
// const englishReg = /[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]/g;
|
||||
// let matchChinese = textConfig.text.match(chineseReg);
|
||||
// let extractChinese = chineseReg.exec(textConfig.text);
|
||||
// let extractEnglish = englishReg.exec(textConfig.text);
|
||||
const chineseReg = /[\u4e00-\u9fa5]/g;
|
||||
const englishReg = /[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]/g;
|
||||
let extractEnglish = textConfig.text.split(englishReg);
|
||||
let extractChinese = textConfig.text.split(chineseReg);
|
||||
let isFirstStrTypeChinese = chineseReg.test(textConfig.text[0]);
|
||||
console.log('testFirstString ==> chinese', isFirstStrTypeChinese);
|
||||
console.log('extractChinese', extractChinese);
|
||||
console.log('extractEnglish', extractEnglish);
|
||||
|
||||
if (isFirstStrTypeChinese) {
|
||||
let cacheEnglishChar = extractChinese.filter(character => { return character !== ''; });
|
||||
let cacheChineseChar = extractEnglish.filter(character => { return character !== ''; });
|
||||
let textArray = [];
|
||||
|
||||
for (i = 0; i < cacheChineseChar.length; i++) {
|
||||
textArray.push(cacheChineseChar[i]);
|
||||
textArray.push(cacheEnglishChar[i])
|
||||
}
|
||||
|
||||
console.log(textArray);
|
||||
}
|
||||
|
||||
|
||||
const debounceHandleInfo = debounce((newBox) => {
|
||||
console.log(newBox);
|
||||
}, 500);
|
||||
|
||||
transformer.boundBoxFunc(function (oldBox, newBox) {
|
||||
// width and height of the boxes are corresponding to total absolute width and height of all nodes combined
|
||||
// so it includes scale of the node.
|
||||
if (newBox.width < 5 || newBox.height < 5) {
|
||||
return oldBox;
|
||||
}
|
||||
debounceHandleInfo(newBox);
|
||||
return newBox;
|
||||
});
|
||||
|
||||
transformer.on('transformend', function (event) {
|
||||
console.log(event.target, event.target.attrs);
|
||||
let attrs = Object.assign({ 'attrs': event.target.attrs });
|
||||
let currentTargetAttrs = {
|
||||
'target': event.target,
|
||||
'attrs': JSON.parse(JSON.stringify(attrs))
|
||||
};
|
||||
queue.enqueue(currentTargetAttrs);
|
||||
});
|
||||
|
||||
console.log('stage', stage.toJSON());
|
||||
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', Main);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
31
test/sandbox.js
Normal file
31
test/sandbox.js
Normal file
@ -0,0 +1,31 @@
|
||||
import Konva from '../src/index.ts';
|
||||
|
||||
export function sandboxDemo() {
|
||||
|
||||
const stage = new Konva.Stage({
|
||||
container: '#container',
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight - 60
|
||||
});
|
||||
|
||||
const layer = new Konva.Layer();
|
||||
|
||||
stage.add(layer);
|
||||
|
||||
return {
|
||||
stage,
|
||||
container: layer
|
||||
}
|
||||
|
||||
//
|
||||
// transformer.nodes([rect]);
|
||||
//
|
||||
// layer.add(rect);
|
||||
// stage.on('wheel', (e) => {
|
||||
// e.evt.preventDefault();
|
||||
// console.log('wheel');
|
||||
// });
|
||||
// stage.on('contextmenu', (e) => {
|
||||
// console.log('click');
|
||||
// });
|
||||
}
|
29
test/text.js
Normal file
29
test/text.js
Normal file
@ -0,0 +1,29 @@
|
||||
// noinspection JSCheckFunctionSignatures
|
||||
|
||||
import Konva from '../src/index.ts';
|
||||
const container = document.querySelector('#container');
|
||||
|
||||
function inTextProcess(options) {
|
||||
// !options.id ? text.id(nanoid()) : '';
|
||||
|
||||
return new Konva.Text({
|
||||
x: container.clientWidth / 2,
|
||||
y: container.clientHeight / 2,
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
export function createText(source) {
|
||||
if (Object.prototype.toString.call(source) === '[object Object]') {
|
||||
return new Promise((resolve, reject) => {
|
||||
const textObject = inTextProcess(source);
|
||||
resolve(textObject);
|
||||
});
|
||||
} else if (Array.isArray(source)) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let textList = source.map(item => inTextProcess(item));
|
||||
resolve(textList);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
291
test/transformerHelper.js
Normal file
291
test/transformerHelper.js
Normal file
@ -0,0 +1,291 @@
|
||||
// noinspection DuplicatedCode,JSCheckFunctionSignatures
|
||||
|
||||
import Konva from '../src/index.ts';
|
||||
|
||||
import { textTransformer, shapeTransformer, multipleTransformer } from '../controller/transformer.js';
|
||||
|
||||
const latestXY = {};
|
||||
const latestXYPriority = [];
|
||||
const allNodeType = ['Group', 'Image', 'Text', 'Star'];
|
||||
const selectionRectangle = new Konva.Rect({ fill: 'rgb(218,147,243)', visible: false });
|
||||
let transformerTypeSingle = '';
|
||||
let transformerTypeFunc = {
|
||||
'Group': multipleTransformer,
|
||||
'Image': shapeTransformer,
|
||||
'Text': textTransformer,
|
||||
'Star': shapeTransformer
|
||||
};
|
||||
|
||||
let schedulerFunction = null;
|
||||
|
||||
|
||||
export class TransformerHelper {
|
||||
constructor(options) {
|
||||
this._stage = options.stage;
|
||||
this._container = options.container;
|
||||
this.isMultipleSelection = undefined;
|
||||
this.initAddContainer(options.container);
|
||||
this.initStageOfTransformerEvent(options.stage);
|
||||
console.log('UITransformer', this._stage, this._container);
|
||||
}
|
||||
|
||||
|
||||
set isMultipleSelector(isMultiple) {
|
||||
this.isMultipleSelection = !!isMultiple;
|
||||
}
|
||||
|
||||
initAddContainer(container) {
|
||||
console.log(this._container);
|
||||
container.add(selectionRectangle);
|
||||
}
|
||||
|
||||
initStageOfTransformerEvent(stage) {
|
||||
const _this = this;
|
||||
stage.on('tap click', function (event) {
|
||||
clearTimeout(schedulerFunction);
|
||||
schedulerFunction = setTimeout(() => {
|
||||
_this.mouseHandlerGlobalTap.bind(_this, event)();
|
||||
}, 200);
|
||||
});
|
||||
stage.on('dbltap dblclick', function (event) {
|
||||
clearTimeout(schedulerFunction);
|
||||
_this.touchHandlerGlobalDoubleTap.bind(_this, event)();
|
||||
});
|
||||
}
|
||||
|
||||
touchHandlerGlobalDoubleTap(event) {
|
||||
event.evt.preventDefault();
|
||||
event.evt.stopPropagation();
|
||||
|
||||
if (event.target === this._stage) return;
|
||||
|
||||
let currentNode = event.target;
|
||||
let nodeParent = currentNode.getParent();
|
||||
let nodeType = nodeParent.getType() === 'Group' ? nodeParent.getType() : currentNode.getClassName();
|
||||
|
||||
if (nodeType === 'Text') {
|
||||
// this._stage.toDispatchEvent('doubleTapText', { target: currentNode });
|
||||
} else if (nodeType === 'Image') {
|
||||
// this._stage.toDispatchEvent('doubleTapImage', { target: currentNode });
|
||||
}
|
||||
}
|
||||
|
||||
mouseHandlerGlobalTap(event) {
|
||||
|
||||
// if click on empty area - remove all selections
|
||||
if (event.target === this._stage) {
|
||||
this.clearTransformer();
|
||||
return;
|
||||
}
|
||||
|
||||
// do nothing if clicked NOT on our rectangles
|
||||
if (!allNodeType.includes(event.target.getClassName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isSelected = [textTransformer, shapeTransformer, multipleTransformer].some(item => {
|
||||
return item.nodes().length >= 1;
|
||||
});
|
||||
|
||||
// console.log('isSelected', isSelected);
|
||||
let currentNode = event.target;
|
||||
let nodeParent = currentNode.getParent();
|
||||
let nodeType = nodeParent.getType() === 'Group' ? 'Group' : currentNode.getClassName();
|
||||
|
||||
if (nodeType === 'Group') {
|
||||
nodeParent.draggable(true);
|
||||
this._container.children.filter(item => item.id() !== nodeParent.id()).forEach(node => {
|
||||
node.draggable(false);
|
||||
});
|
||||
} else {
|
||||
currentNode.draggable(true);
|
||||
this._container.children.filter(item => item.id() !== currentNode.id()).forEach(node => {
|
||||
node.draggable(false);
|
||||
});
|
||||
}
|
||||
|
||||
if (!isSelected) {
|
||||
if (this.isMultipleSelection) return this.multipleSelector(currentNode, { 'touch': true });
|
||||
this.regenerationTransformer(currentNode);
|
||||
} else if (isSelected) {
|
||||
if (this.isMultipleSelection) {
|
||||
this.clearTransformer();
|
||||
return this.multipleSelector(currentNode, { 'touch': true });
|
||||
}
|
||||
|
||||
this.switchTransformer(currentNode);
|
||||
}
|
||||
}
|
||||
|
||||
multipleSelector(node, event) {
|
||||
let checkbox;
|
||||
let nodeElement = typeof node !== 'string' ? node : this._container.find('#' + node).filter(item => item.getAttr('name') !== 'checkbox')[0];
|
||||
let nodeParent = nodeElement.getParent();
|
||||
let nodeTarget = nodeParent.getType() === 'Group' ? nodeElement.getParent() : nodeElement;
|
||||
let { x, y, width, height } = nodeTarget.getClientRect();
|
||||
|
||||
nodeTarget.draggable(false);
|
||||
if (!nodeTarget.getAttr('selected')) {
|
||||
checkbox = new Konva.Rect({
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
stroke: '#EB0C0C',
|
||||
strokeWidth: 2,
|
||||
name: 'checkbox'
|
||||
});
|
||||
|
||||
checkbox.id(nodeTarget.id());
|
||||
checkbox.on('tap click', function () {
|
||||
nodeTarget.setAttr('selected', false);
|
||||
this.destroy();
|
||||
});
|
||||
|
||||
nodeTarget.setAttr('selected', true);
|
||||
this._container.add(checkbox);
|
||||
|
||||
// if (event) this._stage.toDispatchEvent('selectedNode', { nodes: [nodeTarget] });
|
||||
if (event) this._stage.toDispatchEvent('selectedNode', { target: nodeTarget });
|
||||
}
|
||||
|
||||
if (!event && nodeTarget.getAttr('selected')) {
|
||||
const checkbox = this._container.find('#' + nodeTarget.id()).filter(item => item.getAttr('name') === 'checkbox');
|
||||
nodeTarget.setAttr('selected', false);
|
||||
checkbox.length && checkbox[0].destroy();
|
||||
// this._stage.toDispatchEvent('cancelSelectedNode', { nodes: [nodeTarget] });
|
||||
this._stage.toDispatchEvent('cancelSelectedNode', { target: nodeTarget });
|
||||
console.log(checkbox);
|
||||
}
|
||||
}
|
||||
|
||||
regenerationTransformer(node) {
|
||||
let nodeParent = node.getParent();
|
||||
let nodeType = nodeParent.getType() === 'Group' ? 'Group' : node.getClassName();
|
||||
|
||||
// console.log(nodeParent, nodeType);
|
||||
if (nodeType === 'Group') {
|
||||
if (!nodeParent.draggable()) nodeParent.draggable(true);
|
||||
transformerTypeFunc['Group'].nodes(nodeParent.children);
|
||||
this._stage.toDispatchEvent('selectedNode', { target: nodeParent });
|
||||
} else {
|
||||
if (!node.draggable()) node.draggable(true);
|
||||
transformerTypeSingle = nodeType;
|
||||
transformerTypeFunc[nodeType].nodes([node]);
|
||||
this._stage.toDispatchEvent('selectedNode', { target: node });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switchTransformer(node) {
|
||||
let nodeParent = node.getParent();
|
||||
let nodeType = nodeParent.getType() === 'Group' ? 'Group' : node.getClassName();
|
||||
|
||||
// console.log(nodeParent, nodeType);
|
||||
if (nodeType === 'Group') {
|
||||
let nodeGroupLength = transformerTypeFunc['Group'].nodes().length;
|
||||
|
||||
if (['Image', 'Text', 'Star'].some(item => item === node.getClassName()) && nodeGroupLength > 1) {
|
||||
console.log(node);
|
||||
transformerTypeSingle = nodeType;
|
||||
transformerTypeFunc['Group'].nodes([]);
|
||||
transformerTypeFunc['Group'].nodes([node]);
|
||||
this._stage.toDispatchEvent('selectedNode', { target: node });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nodeParent.draggable()) nodeParent.draggable(true);
|
||||
transformerTypeSingle && transformerTypeFunc[transformerTypeSingle].nodes([]);
|
||||
transformerTypeFunc['Group'].nodes(nodeParent.children);
|
||||
this._stage.toDispatchEvent('selectedNode', { target: nodeParent });
|
||||
} else {
|
||||
if (!node.draggable()) node.draggable(true);
|
||||
transformerTypeSingle && transformerTypeFunc[transformerTypeSingle].nodes([]);
|
||||
transformerTypeSingle = nodeType;
|
||||
transformerTypeFunc['Group'].nodes([]);
|
||||
transformerTypeFunc[nodeType].nodes([node]);
|
||||
this._stage.toDispatchEvent('selectedNode', { target: node });
|
||||
}
|
||||
}
|
||||
|
||||
clearTransformer() {
|
||||
transformerTypeSingle && transformerTypeFunc[transformerTypeSingle].nodes([]);
|
||||
transformerTypeSingle || [textTransformer, shapeTransformer, multipleTransformer].forEach(item => item.nodes([]));
|
||||
transformerTypeFunc['Group'].nodes([]);
|
||||
}
|
||||
|
||||
// currentTransformer(target) {
|
||||
// let group = [textTransformer, shapeTransformer, multipleTransformer];
|
||||
// return group.filter(item => item.nodes()['indexOf'](target) <= 0)[0];
|
||||
// }
|
||||
//
|
||||
// mouseHandlerGlobalDown(event) {
|
||||
// // console.log('mouseHandlerGlobalDown', event, this);
|
||||
// // do nothing if we mousedown on any shape
|
||||
// if (event.target !== this._stage) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// event.evt.preventDefault();
|
||||
// // eslint-disable-next-line no-prototype-builtins
|
||||
// if (!latestXY.hasOwnProperty(event.pointerId)) {
|
||||
// const o = {
|
||||
// x1: this._stage.getPointerPosition().x,
|
||||
// y1: this._stage.getPointerPosition().y,
|
||||
// x2: this._stage.getPointerPosition().x,
|
||||
// y2: this._stage.getPointerPosition().y
|
||||
// };
|
||||
// latestXY[event.pointerId] = o;
|
||||
// latestXYPriority.unshift(o);
|
||||
// }
|
||||
//
|
||||
// selectionRectangle.visible(true);
|
||||
// selectionRectangle.width(0);
|
||||
// selectionRectangle.height(0);
|
||||
// };
|
||||
//
|
||||
// mouseHandlerGlobalMove(event) {
|
||||
// // console.log('mouseHandlerGlobalMove', event);
|
||||
// // do nothing if we didn't start selection
|
||||
// if (!selectionRectangle.visible()) {
|
||||
// return;
|
||||
// }
|
||||
// event.evt.preventDefault();
|
||||
//
|
||||
// const tmpX = this._stage.getPointerPosition().x;
|
||||
// const tmpY = this._stage.getPointerPosition().y;
|
||||
// const o = latestXY[event.pointerId];
|
||||
//
|
||||
// selectionRectangle.setAttrs({
|
||||
// x: Math.min(o.x1, tmpX),
|
||||
// y: Math.min(o.y1, tmpY),
|
||||
// width: Math.abs(tmpX - o.x1),
|
||||
// height: Math.abs(tmpY - o.y1)
|
||||
// });
|
||||
// };
|
||||
//
|
||||
// mouseHandlerGlobalUp(event) {
|
||||
// // console.log('mouseHandlerGlobalUp', event);
|
||||
//
|
||||
// // do nothing if we didn't start selection
|
||||
// if (!selectionRectangle.visible()) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// event.evt.preventDefault();
|
||||
// // update visibility in timeout, so we can check it in click event
|
||||
// setTimeout(() => {
|
||||
// selectionRectangle.visible(false);
|
||||
// });
|
||||
//
|
||||
//
|
||||
// const Nodes = this._container.find(node => {
|
||||
// return allNodeType.some(name => node.getClassName() === name);
|
||||
// });
|
||||
//
|
||||
// const box = selectionRectangle.getClientRect();
|
||||
// const selected = Nodes.filter((shape) => Konva.Util.haveIntersection(box, shape.getClientRect()));
|
||||
//
|
||||
// };
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user