mirror of
https://github.com/konvajs/konva.git
synced 2025-06-28 09:17:25 +08:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
27fc1b1ba5 | ||
![]() |
cdd61d7179 | ||
![]() |
f00fd70756 | ||
![]() |
faa2203da7 | ||
![]() |
3442071bdd | ||
![]() |
9c59566a9b | ||
![]() |
ca9be838a8 | ||
![]() |
09f2838d43 | ||
![]() |
a4980fccdc | ||
![]() |
35873586db | ||
![]() |
88e3d2a088 | ||
![]() |
791a786c81 | ||
![]() |
a29157a528 | ||
![]() |
dc8b9df1f5 | ||
![]() |
1ff1885de9 | ||
![]() |
3d5a216f23 | ||
![]() |
2e08f7319f | ||
![]() |
e12365f14f | ||
![]() |
fe80a44407 | ||
![]() |
8211db3233 | ||
![]() |
f32a416e03 | ||
![]() |
fd77f305d1 | ||
![]() |
53a4b494ee | ||
![]() |
9f5a7f0e2d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,6 +19,7 @@ src_old
|
||||
types
|
||||
out.png
|
||||
cmj
|
||||
.test-temp
|
||||
|
||||
# Numerous always-ignore extensions
|
||||
*.diff
|
||||
|
@ -3,6 +3,13 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 9.3.21 (not released)
|
||||
|
||||
- Fixed memory leaks on Tween destroy
|
||||
- Fixed incorrect export of stage/layer when internal nodes used buffer canvas for rendering
|
||||
- Fixed incorrect render of cached node when buffer canvas is used
|
||||
- Fixed incorrect path lenth calculations
|
||||
|
||||
## 9.3.20 (2025-03-20)
|
||||
|
||||
- Fix text rendering when ellipses are used
|
||||
|
@ -16,7 +16,7 @@ You can draw things onto the stage, add event listeners to them, move them, scal
|
||||
This repository began as a GitHub fork of [ericdrowell/KineticJS](https://github.com/ericdrowell/KineticJS).
|
||||
|
||||
- **Visit:** The [Home Page](http://konvajs.org/) and follow on [Twitter](https://twitter.com/lavrton)
|
||||
- **Discover:** [Tutorials](http://konvajs.org/docs), [API Documentation](http://konvajs.org/api)
|
||||
- **Discover:** [Tutorials](http://konvajs.org/docs/index.html), [API Documentation](http://konvajs.org/api/Konva.html)
|
||||
- **Help:** [StackOverflow](http://stackoverflow.com/questions/tagged/konvajs), [Discord Chat](https://discord.gg/8FqZwVT)
|
||||
|
||||
# Quick Look
|
||||
|
@ -22,7 +22,8 @@
|
||||
"test:build": "PARCEL_WORKER_BACKEND=process parcel build ./test/unit-tests.html --dist-dir ./test-build --target none --public-url ./ --no-source-maps",
|
||||
"test:browser": "npm run test:build && mocha-headless-chrome -f ./test-build/unit-tests.html -a disable-web-security -a no-sandbox -a disable-setuid-sandbox",
|
||||
"test:watch": "rm -rf ./.parcel-cache && PARCEL_WORKERS=0 parcel serve ./test/unit-tests.html ./test/manual-tests.html ./test/sandbox.html ./test/text-paths.html ./test/bunnies.html",
|
||||
"test:node": "ts-mocha -r ./test/node-global-setup.mjs -p ./test/tsconfig.json test/unit/**/*.ts --exit && npm run test:import",
|
||||
"test:node:compiled": "rm -rf ./.test-temp && mkdir ./.test-temp && (tsc -p ./test/tsconfig.json --outDir ./.test-temp || true) && mocha './.test-temp/test/unit/**/*.js' -r ./test/node-global-setup.mjs --exit && rm -rf ./.test-temp && npm run test:import",
|
||||
"test:node": "npm run test:node:compiled",
|
||||
"tsc": "tsc --removeComments",
|
||||
"rollup": "rollup -c --bundleConfigAsCjs",
|
||||
"clean": "rm -rf ./lib && rm -rf ./types && rm -rf ./cmj && rm -rf ./test-build",
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { Util } from './Util';
|
||||
import { SceneContext, HitContext, Context } from './Context';
|
||||
import { Konva } from './Global';
|
||||
import { Factory } from './Factory';
|
||||
import { getNumberValidator } from './Validators';
|
||||
|
||||
// calculate pixel ratio
|
||||
let _pixelRatio;
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Factory } from './Factory';
|
||||
import { Node, NodeConfig } from './Node';
|
||||
import { getNumberValidator } from './Validators';
|
||||
|
||||
import { GetSet, IRect } from './types';
|
||||
import { Shape } from './Shape';
|
||||
import { HitCanvas, SceneCanvas } from './Canvas';
|
||||
import { SceneContext } from './Context';
|
||||
import { Factory } from './Factory';
|
||||
import { Node, NodeConfig } from './Node';
|
||||
import { Shape } from './Shape';
|
||||
import { GetSet, IRect } from './types';
|
||||
import { getNumberValidator } from './Validators';
|
||||
|
||||
export type ClipFuncOutput =
|
||||
| void
|
||||
@ -51,18 +50,11 @@ export abstract class Container<
|
||||
* });
|
||||
*/
|
||||
getChildren(filterFunc?: (item: Node) => boolean) {
|
||||
if (!filterFunc) {
|
||||
return this.children || [];
|
||||
}
|
||||
|
||||
const children = this.children || [];
|
||||
const results: Array<ChildType> = [];
|
||||
children.forEach(function (child) {
|
||||
if (filterFunc(child)) {
|
||||
results.push(child);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
if (filterFunc) {
|
||||
return children.filter(filterFunc);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
/**
|
||||
* determine if node has children
|
||||
@ -120,8 +112,6 @@ export abstract class Container<
|
||||
* layer.add(shape1, shape2, shape3);
|
||||
* // empty arrays are accepted, though each individual child must be defined
|
||||
* layer.add(...shapes);
|
||||
* // remember to redraw layer if you changed something
|
||||
* layer.draw();
|
||||
*/
|
||||
add(...children: ChildType[]) {
|
||||
if (children.length === 0) {
|
||||
@ -235,7 +225,7 @@ export abstract class Container<
|
||||
this._descendants((node) => {
|
||||
const valid = node._isMatch(selector);
|
||||
if (valid) {
|
||||
retArr.push(node as unknown as ChildNode);
|
||||
retArr.push(node as ChildNode);
|
||||
}
|
||||
if (valid && findOne) {
|
||||
return true;
|
||||
|
@ -70,7 +70,7 @@ export const Factory = {
|
||||
attr: U,
|
||||
def?: Value<T, U>
|
||||
) {
|
||||
var method = GET + Util._capitalize(attr);
|
||||
const method = GET + Util._capitalize(attr);
|
||||
|
||||
constructor.prototype[method] =
|
||||
constructor.prototype[method] ||
|
||||
@ -86,7 +86,7 @@ export const Factory = {
|
||||
validator?: ValidatorFunc<Value<T, U>>,
|
||||
after?: AfterFunc<T>
|
||||
) {
|
||||
var method = SET + Util._capitalize(attr);
|
||||
const method = SET + Util._capitalize(attr);
|
||||
|
||||
if (!constructor.prototype[method]) {
|
||||
Factory.overWriteSetter(constructor, attr, validator, after);
|
||||
@ -99,7 +99,7 @@ export const Factory = {
|
||||
validator?: ValidatorFunc<Value<T, U>>,
|
||||
after?: AfterFunc<T>
|
||||
) {
|
||||
var method = SET + Util._capitalize(attr);
|
||||
const method = SET + Util._capitalize(attr);
|
||||
constructor.prototype[method] = function (val) {
|
||||
if (validator && val !== undefined && val !== null) {
|
||||
val = validator.call(this, val, attr);
|
||||
@ -180,7 +180,7 @@ export const Factory = {
|
||||
constructor: T,
|
||||
attr: U
|
||||
) {
|
||||
var capitalizedAttr = Util._capitalize(attr),
|
||||
const capitalizedAttr = Util._capitalize(attr),
|
||||
setter = SET + capitalizedAttr,
|
||||
getter = GET + capitalizedAttr;
|
||||
|
||||
|
@ -114,7 +114,7 @@ export class Layer extends Container<Group | Shape> {
|
||||
return this;
|
||||
}
|
||||
// extend Node.prototype.setZIndex
|
||||
setZIndex(index) {
|
||||
setZIndex(index: number) {
|
||||
super.setZIndex(index);
|
||||
const stage = this.getStage();
|
||||
if (stage && stage.content) {
|
||||
@ -385,7 +385,7 @@ export class Layer extends Container<Group | Shape> {
|
||||
// empty pixel
|
||||
return {};
|
||||
}
|
||||
drawScene(can?: SceneCanvas, top?: Node) {
|
||||
drawScene(can?: SceneCanvas, top?: Node, bufferCanvas?: SceneCanvas) {
|
||||
const layer = this.getLayer(),
|
||||
canvas = can || (layer && layer.getCanvas());
|
||||
|
||||
@ -397,7 +397,7 @@ export class Layer extends Container<Group | Shape> {
|
||||
canvas.getContext().clear();
|
||||
}
|
||||
|
||||
Container.prototype.drawScene.call(this, canvas, top);
|
||||
Container.prototype.drawScene.call(this, canvas, top, bufferCanvas);
|
||||
|
||||
this._fire(DRAW, {
|
||||
node: this,
|
||||
|
104
src/Node.ts
104
src/Node.ts
@ -1,19 +1,19 @@
|
||||
import { Util, Transform } from './Util';
|
||||
import { Factory } from './Factory';
|
||||
import { SceneCanvas, HitCanvas, Canvas } from './Canvas';
|
||||
import { Konva } from './Global';
|
||||
import { Canvas, HitCanvas, SceneCanvas } from './Canvas';
|
||||
import { Container } from './Container';
|
||||
import { GetSet, Vector2d, IRect } from './types';
|
||||
import { Context } from './Context';
|
||||
import { DD } from './DragAndDrop';
|
||||
import { Factory } from './Factory';
|
||||
import { Konva } from './Global';
|
||||
import { Layer } from './Layer';
|
||||
import { Shape } from './Shape';
|
||||
import { Stage } from './Stage';
|
||||
import { GetSet, IRect, Vector2d } from './types';
|
||||
import { Transform, Util } from './Util';
|
||||
import {
|
||||
getBooleanValidator,
|
||||
getNumberValidator,
|
||||
getStringValidator,
|
||||
getBooleanValidator,
|
||||
} from './Validators';
|
||||
import { Stage } from './Stage';
|
||||
import { Context } from './Context';
|
||||
import { Shape } from './Shape';
|
||||
import { Layer } from './Layer';
|
||||
|
||||
export type Filter = (this: Node, imageData: ImageData) => void;
|
||||
|
||||
@ -88,6 +88,10 @@ const ABSOLUTE_OPACITY = 'absoluteOpacity',
|
||||
LISTENING = 'listening',
|
||||
MOUSEENTER = 'mouseenter',
|
||||
MOUSELEAVE = 'mouseleave',
|
||||
POINTERENTER = 'pointerenter',
|
||||
POINTERLEAVE = 'pointerleave',
|
||||
TOUCHENTER = 'touchenter',
|
||||
TOUCHLEAVE = 'touchleave',
|
||||
NAME = 'name',
|
||||
SET = 'set',
|
||||
SHAPE = 'Shape',
|
||||
@ -248,8 +252,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
*/
|
||||
clearCache() {
|
||||
if (this._cache.has(CANVAS)) {
|
||||
const { scene, filter, hit } = this._cache.get(CANVAS);
|
||||
Util.releaseCanvas(scene, filter, hit);
|
||||
const { scene, filter, hit, buffer } = this._cache.get(CANVAS);
|
||||
Util.releaseCanvas(scene, filter, hit, buffer);
|
||||
this._cache.delete(CANVAS);
|
||||
}
|
||||
|
||||
@ -385,6 +389,18 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
sceneContext = cachedSceneCanvas.getContext(),
|
||||
hitContext = cachedHitCanvas.getContext();
|
||||
|
||||
const bufferCanvas = new SceneCanvas({
|
||||
// width and height already multiplied by pixelRatio
|
||||
// so we need to revert that
|
||||
// also increase size by x nd y offset to make sure content fits canvas
|
||||
width:
|
||||
cachedSceneCanvas.width / cachedSceneCanvas.pixelRatio + Math.abs(x),
|
||||
height:
|
||||
cachedSceneCanvas.height / cachedSceneCanvas.pixelRatio + Math.abs(y),
|
||||
pixelRatio: cachedSceneCanvas.pixelRatio,
|
||||
}),
|
||||
bufferContext = bufferCanvas.getContext();
|
||||
|
||||
cachedHitCanvas.isCache = true;
|
||||
cachedSceneCanvas.isCache = true;
|
||||
|
||||
@ -398,16 +414,23 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
|
||||
sceneContext.save();
|
||||
hitContext.save();
|
||||
bufferContext.save();
|
||||
|
||||
sceneContext.translate(-x, -y);
|
||||
hitContext.translate(-x, -y);
|
||||
bufferContext.translate(-x, -y);
|
||||
// hard-code offset to make sure content fits canvas
|
||||
// @ts-ignore
|
||||
bufferCanvas.x = x;
|
||||
// @ts-ignore
|
||||
bufferCanvas.y = y;
|
||||
|
||||
// extra flag to skip on getAbsolute opacity calc
|
||||
this._isUnderCache = true;
|
||||
this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY);
|
||||
this._clearSelfAndDescendantCache(ABSOLUTE_SCALE);
|
||||
|
||||
this.drawScene(cachedSceneCanvas, this);
|
||||
this.drawScene(cachedSceneCanvas, this, bufferCanvas);
|
||||
this.drawHit(cachedHitCanvas, this);
|
||||
this._isUnderCache = false;
|
||||
|
||||
@ -431,6 +454,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
scene: cachedSceneCanvas,
|
||||
filter: cachedFilterCanvas,
|
||||
hit: cachedHitCanvas,
|
||||
buffer: bufferCanvas,
|
||||
x: x,
|
||||
y: y,
|
||||
});
|
||||
@ -693,39 +717,32 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
evtStr: K,
|
||||
handler: KonvaEventListener<this, NodeEventMap[K]>
|
||||
) {
|
||||
this._cache && this._cache.delete(ALL_LISTENERS);
|
||||
if (this._cache) {
|
||||
this._cache.delete(ALL_LISTENERS);
|
||||
}
|
||||
|
||||
if (arguments.length === 3) {
|
||||
return this._delegate.apply(this, arguments as any);
|
||||
}
|
||||
let events = (evtStr as string).split(SPACE),
|
||||
len = events.length,
|
||||
n,
|
||||
event,
|
||||
parts,
|
||||
baseEvent,
|
||||
name;
|
||||
const events = (evtStr as string).split(SPACE);
|
||||
|
||||
/*
|
||||
* loop through types and attach event listeners to
|
||||
* each one. eg. 'click mouseover.namespace mouseout'
|
||||
* will create three event bindings
|
||||
*/
|
||||
for (n = 0; n < len; n++) {
|
||||
event = events[n];
|
||||
parts = event.split('.');
|
||||
baseEvent = parts[0];
|
||||
name = parts[1] || '';
|
||||
for (let n = 0; n < events.length; n++) {
|
||||
const event = events[n];
|
||||
const parts = event.split('.');
|
||||
const baseEvent = parts[0];
|
||||
const name = parts[1] || '';
|
||||
|
||||
// create events array if it doesn't exist
|
||||
if (!this.eventListeners[baseEvent]) {
|
||||
this.eventListeners[baseEvent] = [];
|
||||
}
|
||||
|
||||
this.eventListeners[baseEvent].push({
|
||||
name: name,
|
||||
handler: handler,
|
||||
});
|
||||
this.eventListeners[baseEvent].push({ name, handler });
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -881,13 +898,13 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
* @example
|
||||
* var x = node.getAttr('x');
|
||||
*/
|
||||
getAttr(attr: string) {
|
||||
getAttr<T>(attr: string) {
|
||||
const method = 'get' + Util._capitalize(attr);
|
||||
if (Util._isFunction((this as any)[method])) {
|
||||
return (this as any)[method]();
|
||||
}
|
||||
// otherwise get directly
|
||||
return this.attrs[attr];
|
||||
return this.attrs[attr] as T | undefined;
|
||||
}
|
||||
/**
|
||||
* get ancestors
|
||||
@ -2208,7 +2225,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
* node.addName('selected');
|
||||
* node.name(); // return 'red selected'
|
||||
*/
|
||||
addName(name) {
|
||||
addName(name: string) {
|
||||
if (!this.hasName(name)) {
|
||||
const oldName = this.name();
|
||||
const newName = oldName ? oldName + ' ' + name : name;
|
||||
@ -2271,7 +2288,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
* @example
|
||||
* node.setAttr('x', 5);
|
||||
*/
|
||||
setAttr(attr, val) {
|
||||
setAttr(attr: string, val) {
|
||||
const func = this[SET + Util._capitalize(attr)];
|
||||
|
||||
if (Util._isFunction(func)) {
|
||||
@ -2288,7 +2305,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
drawNode?.batchDraw();
|
||||
}
|
||||
}
|
||||
_setAttr(key, val) {
|
||||
_setAttr(key: string, val) {
|
||||
const oldVal = this.attrs[key];
|
||||
if (oldVal === val && !Util.isObject(val)) {
|
||||
return;
|
||||
@ -2322,8 +2339,17 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
evt.target = this;
|
||||
}
|
||||
|
||||
const nonBubbling = [
|
||||
MOUSEENTER,
|
||||
MOUSELEAVE,
|
||||
POINTERENTER,
|
||||
POINTERLEAVE,
|
||||
TOUCHENTER,
|
||||
TOUCHLEAVE,
|
||||
];
|
||||
|
||||
const shouldStop =
|
||||
(eventType === MOUSEENTER || eventType === MOUSELEAVE) &&
|
||||
nonBubbling.indexOf(eventType) !== -1 &&
|
||||
((compareShape &&
|
||||
(this === compareShape ||
|
||||
(this.isAncestorOf && this.isAncestorOf(compareShape)))) ||
|
||||
@ -2334,7 +2360,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
|
||||
// simulate event bubbling
|
||||
const stopBubble =
|
||||
(eventType === MOUSEENTER || eventType === MOUSELEAVE) &&
|
||||
nonBubbling.indexOf(eventType) !== -1 &&
|
||||
compareShape &&
|
||||
compareShape.isAncestorOf &&
|
||||
compareShape.isAncestorOf(this) &&
|
||||
@ -2380,7 +2406,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
|
||||
const topListeners = this._getProtoListeners(eventType);
|
||||
if (topListeners) {
|
||||
for (var i = 0; i < topListeners.length; i++) {
|
||||
for (let i = 0; i < topListeners.length; i++) {
|
||||
topListeners[i].handler.call(this, evt);
|
||||
}
|
||||
}
|
||||
@ -2389,7 +2415,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
// because events can be added/removed while firing
|
||||
const selfListeners = this.eventListeners[eventType];
|
||||
if (selfListeners) {
|
||||
for (var i = 0; i < selfListeners.length; i++) {
|
||||
for (let i = 0; i < selfListeners.length; i++) {
|
||||
selfListeners[i].handler.call(this, evt);
|
||||
}
|
||||
}
|
||||
|
31
src/Shape.ts
31
src/Shape.ts
@ -213,10 +213,16 @@ export class Shape<
|
||||
shapes[key] = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getContext() {
|
||||
Util.warn('shape.getContext() method is deprecated. Please do not use it.');
|
||||
return this.getLayer()!.getContext();
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getCanvas() {
|
||||
Util.warn('shape.getCanvas() method is deprecated. Please do not use it.');
|
||||
return this.getLayer()!.getCanvas();
|
||||
@ -442,7 +448,7 @@ export class Shape<
|
||||
* @param {Number} point.y
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
intersects(point) {
|
||||
intersects(point: Vector2d) {
|
||||
const stage = this.getStage();
|
||||
if (!stage) {
|
||||
return false;
|
||||
@ -594,15 +600,14 @@ export class Shape<
|
||||
// 3 - when node is cached and we need to draw it into layer
|
||||
|
||||
const layer = this.getLayer();
|
||||
let canvas = can || layer!.getCanvas(),
|
||||
const canvas = can || layer!.getCanvas(),
|
||||
context = canvas.getContext() as SceneContext,
|
||||
cachedCanvas = this._getCanvasCache(),
|
||||
drawFunc = this.getSceneFunc(),
|
||||
hasShadow = this.hasShadow(),
|
||||
stage,
|
||||
bufferContext;
|
||||
hasShadow = this.hasShadow();
|
||||
let stage;
|
||||
|
||||
const skipBuffer = canvas.isCache;
|
||||
const skipBuffer = false;
|
||||
const cachingSelf = top === this;
|
||||
|
||||
if (!this.isVisible() && !cachingSelf) {
|
||||
@ -628,12 +633,12 @@ export class Shape<
|
||||
if (this._useBufferCanvas() && !skipBuffer) {
|
||||
stage = this.getStage();
|
||||
const bc = bufferCanvas || stage.bufferCanvas;
|
||||
bufferContext = bc.getContext();
|
||||
const bufferContext = bc.getContext();
|
||||
bufferContext.clear();
|
||||
bufferContext.save();
|
||||
bufferContext._applyLineJoin(this);
|
||||
// layer might be undefined if we are using cache before adding to layer
|
||||
var o = this.getAbsoluteTransform(top).getMatrix();
|
||||
const o = this.getAbsoluteTransform(top).getMatrix();
|
||||
bufferContext.transform(o[0], o[1], o[2], o[3], o[4], o[5]);
|
||||
|
||||
drawFunc.call(this, bufferContext, this);
|
||||
@ -646,12 +651,18 @@ export class Shape<
|
||||
}
|
||||
context._applyOpacity(this);
|
||||
context._applyGlobalCompositeOperation(this);
|
||||
context.drawImage(bc._canvas, 0, 0, bc.width / ratio, bc.height / ratio);
|
||||
context.drawImage(
|
||||
bc._canvas,
|
||||
bc.x || 0,
|
||||
bc.y || 0,
|
||||
bc.width / ratio,
|
||||
bc.height / ratio
|
||||
);
|
||||
} else {
|
||||
context._applyLineJoin(this);
|
||||
|
||||
if (!cachingSelf) {
|
||||
var o = this.getAbsoluteTransform(top).getMatrix();
|
||||
const o = this.getAbsoluteTransform(top).getMatrix();
|
||||
context.transform(o[0], o[1], o[2], o[3], o[4], o[5]);
|
||||
context._applyOpacity(this);
|
||||
context._applyGlobalCompositeOperation(this);
|
||||
|
@ -214,11 +214,11 @@ export class Stage extends Container<Layer> {
|
||||
*/
|
||||
setContainer(container) {
|
||||
if (typeof container === STRING) {
|
||||
let id;
|
||||
if (container.charAt(0) === '.') {
|
||||
const className = container.slice(1);
|
||||
container = document.getElementsByClassName(className)[0];
|
||||
} else {
|
||||
var id;
|
||||
if (container.charAt(0) !== '#') {
|
||||
id = container;
|
||||
} else {
|
||||
|
33
src/Tween.ts
33
src/Tween.ts
@ -200,8 +200,7 @@ export class Tween {
|
||||
nodeId = node._id,
|
||||
easing = config.easing || Easings.Linear,
|
||||
yoyo = !!config.yoyo;
|
||||
let duration,
|
||||
key;
|
||||
let duration, key;
|
||||
|
||||
if (typeof config.duration === 'undefined') {
|
||||
duration = 0.3;
|
||||
@ -268,11 +267,7 @@ export class Tween {
|
||||
_addAttr(key, end) {
|
||||
const node = this.node,
|
||||
nodeId = node._id;
|
||||
let diff,
|
||||
len,
|
||||
trueEnd,
|
||||
trueStart,
|
||||
endRGBA;
|
||||
let diff, len, trueEnd, trueStart, endRGBA;
|
||||
|
||||
// remove conflict from tween map if it exists
|
||||
const tweenId = Tween.tweens[nodeId][key];
|
||||
@ -352,14 +347,7 @@ export class Tween {
|
||||
_tweenFunc(i) {
|
||||
const node = this.node,
|
||||
attrs = Tween.attrs[node._id][this._id];
|
||||
let key,
|
||||
attr,
|
||||
start,
|
||||
diff,
|
||||
newVal,
|
||||
n,
|
||||
len,
|
||||
end;
|
||||
let key, attr, start, diff, newVal, n, len, end;
|
||||
|
||||
for (key in attrs) {
|
||||
attr = attrs[key];
|
||||
@ -528,11 +516,26 @@ export class Tween {
|
||||
|
||||
this.pause();
|
||||
|
||||
// Clean up animation
|
||||
if (this.anim) {
|
||||
this.anim.stop();
|
||||
}
|
||||
|
||||
// Clean up tween entries
|
||||
for (const key in attrs) {
|
||||
delete Tween.tweens[nodeId][key];
|
||||
}
|
||||
|
||||
// Clean up attrs entry
|
||||
delete Tween.attrs[nodeId][thisId];
|
||||
|
||||
// Clean up parent objects if empty
|
||||
if (Object.keys(Tween.tweens[nodeId]).length === 0) {
|
||||
delete Tween.tweens[nodeId];
|
||||
}
|
||||
if (Object.keys(Tween.attrs[nodeId]).length === 0) {
|
||||
delete Tween.attrs[nodeId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,8 +72,8 @@ export function getNumberOrArrayOfNumbersValidator<T>(noOfElements: number) {
|
||||
export function getNumberOrAutoValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function (val: T, attr: string): T {
|
||||
var isNumber = Util._isNumber(val);
|
||||
var isAuto = val === 'auto';
|
||||
const isNumber = Util._isNumber(val);
|
||||
const isAuto = val === 'auto';
|
||||
|
||||
if (!(isNumber || isAuto)) {
|
||||
Util.warn(
|
||||
@ -175,7 +175,7 @@ export function getNumberArrayValidator<T>() {
|
||||
export function getBooleanValidator<T>() {
|
||||
if (Konva.isUnminified) {
|
||||
return function (val: T, attr: string): T {
|
||||
var isBool = val === true || val === false;
|
||||
const isBool = val === true || val === false;
|
||||
if (!isBool) {
|
||||
Util.warn(
|
||||
_formatValue(val) +
|
||||
|
@ -96,11 +96,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
width = imageData.width,
|
||||
height = imageData.height;
|
||||
|
||||
let x,
|
||||
y,
|
||||
i,
|
||||
p,
|
||||
yp,
|
||||
let p,
|
||||
yi,
|
||||
yw,
|
||||
r_sum,
|
||||
@ -135,7 +131,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
stackIn: any = null,
|
||||
stackOut: any = null;
|
||||
|
||||
for (i = 1; i < div; i++) {
|
||||
for (let i = 1; i < div; i++) {
|
||||
stack = stack.next = new BlurStack();
|
||||
if (i === radiusPlus1) {
|
||||
stackEnd = stack;
|
||||
@ -146,7 +142,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
|
||||
yw = yi = 0;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (let y = 0; y < height; y++) {
|
||||
r_in_sum =
|
||||
g_in_sum =
|
||||
b_in_sum =
|
||||
@ -169,7 +165,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
|
||||
stack = stackStart;
|
||||
|
||||
for (i = 0; i < radiusPlus1; i++) {
|
||||
for (let i = 0; i < radiusPlus1; i++) {
|
||||
stack.r = pr;
|
||||
stack.g = pg;
|
||||
stack.b = pb;
|
||||
@ -177,7 +173,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
stack = stack.next;
|
||||
}
|
||||
|
||||
for (i = 1; i < radiusPlus1; i++) {
|
||||
for (let i = 1; i < radiusPlus1; i++) {
|
||||
p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);
|
||||
r_sum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i);
|
||||
g_sum += (stack.g = pg = pixels[p + 1]) * rbs;
|
||||
@ -194,7 +190,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
|
||||
stackIn = stackStart;
|
||||
stackOut = stackEnd;
|
||||
for (x = 0; x < width; x++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
pixels[yi + 3] = pa = (a_sum * mul_sum) >> shg_sum;
|
||||
if (pa !== 0) {
|
||||
pa = 255 / pa;
|
||||
@ -246,7 +242,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
yw += width;
|
||||
}
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
g_in_sum =
|
||||
b_in_sum =
|
||||
a_in_sum =
|
||||
@ -270,7 +266,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
|
||||
stack = stackStart;
|
||||
|
||||
for (i = 0; i < radiusPlus1; i++) {
|
||||
for (let i = 0; i < radiusPlus1; i++) {
|
||||
stack.r = pr;
|
||||
stack.g = pg;
|
||||
stack.b = pb;
|
||||
@ -278,9 +274,9 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
stack = stack.next;
|
||||
}
|
||||
|
||||
yp = width;
|
||||
let yp = width;
|
||||
|
||||
for (i = 1; i <= radius; i++) {
|
||||
for (let i = 1; i <= radius; i++) {
|
||||
yi = (yp + x) << 2;
|
||||
|
||||
r_sum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i);
|
||||
@ -303,7 +299,7 @@ function filterGaussBlurRGBA(imageData, radius) {
|
||||
yi = x;
|
||||
stackIn = stackStart;
|
||||
stackOut = stackEnd;
|
||||
for (y = 0; y < height; y++) {
|
||||
for (let y = 0; y < height; y++) {
|
||||
p = yi << 2;
|
||||
pixels[p + 3] = pa = (a_sum * mul_sum) >> shg_sum;
|
||||
if (pa > 0) {
|
||||
|
@ -94,15 +94,12 @@ export const Enhance: Filter = function (imageData) {
|
||||
bMin = 0;
|
||||
}
|
||||
|
||||
let rMid,
|
||||
rGoalMax,
|
||||
rGoalMin,
|
||||
gMid,
|
||||
gGoalMax,
|
||||
gGoalMin,
|
||||
bMid,
|
||||
bGoalMax,
|
||||
bGoalMin;
|
||||
let rGoalMax: number,
|
||||
rGoalMin: number,
|
||||
gGoalMax: number,
|
||||
gGoalMin: number,
|
||||
bGoalMax: number,
|
||||
bGoalMin: number;
|
||||
|
||||
// If the enhancement is positive - stretch the histogram
|
||||
if (enhanceAmount > 0) {
|
||||
@ -114,13 +111,13 @@ export const Enhance: Filter = function (imageData) {
|
||||
bGoalMin = bMin - enhanceAmount * (bMin - 0);
|
||||
// If the enhancement is negative - compress the histogram
|
||||
} else {
|
||||
rMid = (rMax + rMin) * 0.5;
|
||||
const rMid = (rMax + rMin) * 0.5;
|
||||
rGoalMax = rMax + enhanceAmount * (rMax - rMid);
|
||||
rGoalMin = rMin + enhanceAmount * (rMin - rMid);
|
||||
gMid = (gMax + gMin) * 0.5;
|
||||
const gMid = (gMax + gMin) * 0.5;
|
||||
gGoalMax = gMax + enhanceAmount * (gMax - gMid);
|
||||
gGoalMin = gMin + enhanceAmount * (gMin - gMid);
|
||||
bMid = (bMax + bMin) * 0.5;
|
||||
const bMid = (bMax + bMin) * 0.5;
|
||||
bGoalMax = bMax + enhanceAmount * (bMax - bMid);
|
||||
bGoalMin = bMin + enhanceAmount * (bMin - bMid);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Factory } from '../Factory';
|
||||
import { Node, Filter } from '../Node';
|
||||
import { Filter, Node } from '../Node';
|
||||
import { getNumberValidator } from '../Validators';
|
||||
|
||||
/**
|
||||
@ -46,13 +46,11 @@ export const HSV: Filter = function (imageData) {
|
||||
bg = 0.587 * v - 0.586 * vsu - 1.05 * vsw,
|
||||
bb = 0.114 * v + 0.886 * vsu - 0.2 * vsw;
|
||||
|
||||
let r, g, b, a;
|
||||
|
||||
for (let i = 0; i < nPixels; i += 4) {
|
||||
r = data[i + 0];
|
||||
g = data[i + 1];
|
||||
b = data[i + 2];
|
||||
a = data[i + 3];
|
||||
const r = data[i + 0];
|
||||
const g = data[i + 1];
|
||||
const b = data[i + 2];
|
||||
const a = data[i + 3];
|
||||
|
||||
data[i + 0] = rr * r + rg * g + rb * b;
|
||||
data[i + 1] = gr * r + gg * g + gb * b;
|
||||
|
@ -2,7 +2,7 @@ import { Factory } from '../Factory';
|
||||
import { Filter, Node } from '../Node';
|
||||
import { getNumberValidator } from '../Validators';
|
||||
|
||||
function pixelAt(idata, x, y) {
|
||||
function pixelAt(idata, x: number, y: number) {
|
||||
let idx = (y * idata.width + x) * 4;
|
||||
const d: Array<number> = [];
|
||||
d.push(
|
||||
@ -137,7 +137,7 @@ function dilateMask(mask, sw, sh) {
|
||||
return maskResult;
|
||||
}
|
||||
|
||||
function smoothEdgeMask(mask, sw, sh) {
|
||||
function smoothEdgeMask(mask, sw: number, sh: number) {
|
||||
const weights = [1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9];
|
||||
const side = Math.round(Math.sqrt(weights.length));
|
||||
const halfSide = Math.floor(side / 2);
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import { Factory } from '../Factory';
|
||||
import { Util } from '../Util';
|
||||
import { Node, Filter } from '../Node';
|
||||
@ -22,23 +21,9 @@ export const Pixelate: Filter = function (imageData) {
|
||||
let pixelSize = Math.ceil(this.pixelSize()),
|
||||
width = imageData.width,
|
||||
height = imageData.height,
|
||||
x,
|
||||
y,
|
||||
i,
|
||||
//pixelsPerBin = pixelSize * pixelSize,
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
alpha,
|
||||
nBinsX = Math.ceil(width / pixelSize),
|
||||
nBinsY = Math.ceil(height / pixelSize),
|
||||
xBinStart,
|
||||
xBinEnd,
|
||||
yBinStart,
|
||||
yBinEnd,
|
||||
xBin,
|
||||
yBin,
|
||||
pixelsInBin,
|
||||
data = imageData.data;
|
||||
|
||||
if (pixelSize <= 0) {
|
||||
@ -46,31 +31,31 @@ export const Pixelate: Filter = function (imageData) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (xBin = 0; xBin < nBinsX; xBin += 1) {
|
||||
for (yBin = 0; yBin < nBinsY; yBin += 1) {
|
||||
for (let xBin = 0; xBin < nBinsX; xBin += 1) {
|
||||
for (let yBin = 0; yBin < nBinsY; yBin += 1) {
|
||||
// Initialize the color accumlators to 0
|
||||
red = 0;
|
||||
green = 0;
|
||||
blue = 0;
|
||||
alpha = 0;
|
||||
let red = 0;
|
||||
let green = 0;
|
||||
let blue = 0;
|
||||
let alpha = 0;
|
||||
|
||||
// Determine which pixels are included in this bin
|
||||
xBinStart = xBin * pixelSize;
|
||||
xBinEnd = xBinStart + pixelSize;
|
||||
yBinStart = yBin * pixelSize;
|
||||
yBinEnd = yBinStart + pixelSize;
|
||||
const xBinStart = xBin * pixelSize;
|
||||
const xBinEnd = xBinStart + pixelSize;
|
||||
const yBinStart = yBin * pixelSize;
|
||||
const yBinEnd = yBinStart + pixelSize;
|
||||
|
||||
// Add all of the pixels to this bin!
|
||||
pixelsInBin = 0;
|
||||
for (x = xBinStart; x < xBinEnd; x += 1) {
|
||||
let pixelsInBin = 0;
|
||||
for (let x = xBinStart; x < xBinEnd; x += 1) {
|
||||
if (x >= width) {
|
||||
continue;
|
||||
}
|
||||
for (y = yBinStart; y < yBinEnd; y += 1) {
|
||||
for (let y = yBinStart; y < yBinEnd; y += 1) {
|
||||
if (y >= height) {
|
||||
continue;
|
||||
}
|
||||
i = (width * y + x) * 4;
|
||||
const i = (width * y + x) * 4;
|
||||
red += data[i + 0];
|
||||
green += data[i + 1];
|
||||
blue += data[i + 2];
|
||||
@ -86,15 +71,15 @@ export const Pixelate: Filter = function (imageData) {
|
||||
alpha = alpha / pixelsInBin;
|
||||
|
||||
// Draw this bin
|
||||
for (x = xBinStart; x < xBinEnd; x += 1) {
|
||||
for (let x = xBinStart; x < xBinEnd; x += 1) {
|
||||
if (x >= width) {
|
||||
continue;
|
||||
}
|
||||
for (y = yBinStart; y < yBinEnd; y += 1) {
|
||||
for (let y = yBinStart; y < yBinEnd; y += 1) {
|
||||
if (y >= height) {
|
||||
continue;
|
||||
}
|
||||
i = (width * y + x) * 4;
|
||||
const i = (width * y + x) * 4;
|
||||
data[i + 0] = red;
|
||||
data[i + 1] = green;
|
||||
data[i + 2] = blue;
|
||||
|
@ -163,7 +163,6 @@ export class Image extends Shape<ImageConfig> {
|
||||
* Konva.Image.fromURL(imageURL, function(image){
|
||||
* // image is Konva.Image instance
|
||||
* layer.add(image);
|
||||
* layer.draw();
|
||||
* });
|
||||
*/
|
||||
static fromURL(
|
||||
|
@ -6,7 +6,15 @@ import { getNumberArrayValidator, getNumberValidator } from '../Validators';
|
||||
import { Context } from '../Context';
|
||||
import { GetSet } from '../types';
|
||||
|
||||
function getControlPoints(x0, y0, x1, y1, x2, y2, t) {
|
||||
function getControlPoints(
|
||||
x0: number,
|
||||
y0: number,
|
||||
x1: number,
|
||||
y1: number,
|
||||
x2: number,
|
||||
y2: number,
|
||||
t: number
|
||||
) {
|
||||
const d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)),
|
||||
d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)),
|
||||
fa = (t * d01) / (d01 + d12),
|
||||
@ -102,26 +110,24 @@ export class Line<
|
||||
}
|
||||
|
||||
_sceneFunc(context: Context) {
|
||||
let points = this.points(),
|
||||
const points = this.points(),
|
||||
length = points.length,
|
||||
tension = this.tension(),
|
||||
closed = this.closed(),
|
||||
bezier = this.bezier(),
|
||||
tp,
|
||||
len,
|
||||
n;
|
||||
bezier = this.bezier();
|
||||
|
||||
if (!length) {
|
||||
return;
|
||||
}
|
||||
let n = 0;
|
||||
|
||||
context.beginPath();
|
||||
context.moveTo(points[0], points[1]);
|
||||
|
||||
// tension
|
||||
if (tension !== 0 && length > 4) {
|
||||
tp = this.getTensionPoints();
|
||||
len = tp.length;
|
||||
const tp = this.getTensionPoints();
|
||||
const len = tp.length;
|
||||
n = closed ? 0 : 4;
|
||||
|
||||
if (!closed) {
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Factory } from '../Factory';
|
||||
import { Shape, ShapeConfig } from '../Shape';
|
||||
import { _registerNode } from '../Global';
|
||||
import { Shape, ShapeConfig } from '../Shape';
|
||||
|
||||
import { GetSet, PathSegment } from '../types';
|
||||
import {
|
||||
getCubicArcLength,
|
||||
getQuadraticArcLength,
|
||||
t2length,
|
||||
} from '../BezierFunctions';
|
||||
import { GetSet, PathSegment } from '../types';
|
||||
|
||||
export interface PathConfig extends ShapeConfig {
|
||||
data?: string;
|
||||
@ -73,7 +73,7 @@ export class Path extends Shape<PathConfig> {
|
||||
context.quadraticCurveTo(p[0], p[1], p[2], p[3]);
|
||||
break;
|
||||
case 'A':
|
||||
var cx = p[0],
|
||||
const cx = p[0],
|
||||
cy = p[1],
|
||||
rx = p[2],
|
||||
ry = p[3],
|
||||
@ -82,9 +82,9 @@ export class Path extends Shape<PathConfig> {
|
||||
psi = p[6],
|
||||
fs = p[7];
|
||||
|
||||
var r = rx > ry ? rx : ry;
|
||||
var scaleX = rx > ry ? 1 : rx / ry;
|
||||
var scaleY = rx > ry ? ry / rx : 1;
|
||||
const r = rx > ry ? rx : ry;
|
||||
const scaleX = rx > ry ? 1 : rx / ry;
|
||||
const scaleY = rx > ry ? ry / rx : 1;
|
||||
|
||||
context.translate(cx, cy);
|
||||
context.rotate(psi);
|
||||
@ -217,7 +217,7 @@ export class Path extends Shape<PathConfig> {
|
||||
* @example
|
||||
* var point = path.getPointAtLength(10);
|
||||
*/
|
||||
getPointAtLength(length) {
|
||||
getPointAtLength(length: number) {
|
||||
return Path.getPointAtLengthOfDataArray(length, this.dataArray);
|
||||
}
|
||||
|
||||
@ -258,11 +258,19 @@ export class Path extends Shape<PathConfig> {
|
||||
}
|
||||
|
||||
if (length < 0.01) {
|
||||
points = dataArray[i].points.slice(0, 2);
|
||||
return {
|
||||
x: points[0],
|
||||
y: points[1],
|
||||
};
|
||||
const cmd = dataArray[i].command;
|
||||
if (cmd === 'M') {
|
||||
points = dataArray[i].points.slice(0, 2);
|
||||
return {
|
||||
x: points[0],
|
||||
y: points[1],
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
x: dataArray[i].start.x,
|
||||
y: dataArray[i].start.y,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const cp = dataArray[i];
|
||||
@ -305,13 +313,13 @@ export class Path extends Shape<PathConfig> {
|
||||
p[3]
|
||||
);
|
||||
case 'A':
|
||||
var cx = p[0],
|
||||
const cx = p[0],
|
||||
cy = p[1],
|
||||
rx = p[2],
|
||||
ry = p[3],
|
||||
theta = p[4],
|
||||
dTheta = p[5],
|
||||
psi = p[6];
|
||||
let theta = p[4];
|
||||
theta += (dTheta * length) / cp.pathLength;
|
||||
return Path.getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi);
|
||||
}
|
||||
@ -362,26 +370,33 @@ export class Path extends Shape<PathConfig> {
|
||||
return { x: ix + adjustedRun, y: iy + adjustedRise };
|
||||
}
|
||||
|
||||
static getPointOnCubicBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y, P4x, P4y) {
|
||||
function CB1(t) {
|
||||
static getPointOnCubicBezier(
|
||||
pct: number,
|
||||
P1x: number,
|
||||
P1y: number,
|
||||
P2x: number,
|
||||
P2y: number,
|
||||
P3x: number,
|
||||
P3y: number,
|
||||
P4x: number,
|
||||
P4y: number
|
||||
) {
|
||||
function CB1(t: number) {
|
||||
return t * t * t;
|
||||
}
|
||||
function CB2(t) {
|
||||
function CB2(t: number) {
|
||||
return 3 * t * t * (1 - t);
|
||||
}
|
||||
function CB3(t) {
|
||||
function CB3(t: number) {
|
||||
return 3 * t * (1 - t) * (1 - t);
|
||||
}
|
||||
function CB4(t) {
|
||||
function CB4(t: number) {
|
||||
return (1 - t) * (1 - t) * (1 - t);
|
||||
}
|
||||
const x = P4x * CB1(pct) + P3x * CB2(pct) + P2x * CB3(pct) + P1x * CB4(pct);
|
||||
const y = P4y * CB1(pct) + P3y * CB2(pct) + P2y * CB3(pct) + P1y * CB4(pct);
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
};
|
||||
return { x, y };
|
||||
}
|
||||
static getPointOnQuadraticBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y) {
|
||||
function QB1(t) {
|
||||
@ -396,10 +411,7 @@ export class Path extends Shape<PathConfig> {
|
||||
const x = P3x * QB1(pct) + P2x * QB2(pct) + P1x * QB3(pct);
|
||||
const y = P3y * QB1(pct) + P2y * QB2(pct) + P1y * QB3(pct);
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
};
|
||||
return { x, y };
|
||||
}
|
||||
static getPointOnEllipticalArc(
|
||||
cx: number,
|
||||
@ -483,7 +495,7 @@ export class Path extends Shape<PathConfig> {
|
||||
// convert white spaces to commas
|
||||
cs = cs.replace(new RegExp(' ', 'g'), ',');
|
||||
// create pipes so that we can split the data
|
||||
for (var n = 0; n < cc.length; n++) {
|
||||
for (let n = 0; n < cc.length; n++) {
|
||||
cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);
|
||||
}
|
||||
// create array
|
||||
@ -496,7 +508,7 @@ export class Path extends Shape<PathConfig> {
|
||||
|
||||
const re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi;
|
||||
let match;
|
||||
for (n = 1; n < arr.length; n++) {
|
||||
for (let n = 1; n < arr.length; n++) {
|
||||
let str = arr[n];
|
||||
let c = str.charAt(0);
|
||||
str = str.slice(1);
|
||||
@ -536,8 +548,8 @@ export class Path extends Shape<PathConfig> {
|
||||
const startX = cpx,
|
||||
startY = cpy;
|
||||
// Move var from within the switch to up here (jshint)
|
||||
var prevCmd, ctlPtx, ctlPty; // Ss, Tt
|
||||
var rx, ry, psi, fa, fs, x1, y1; // Aa
|
||||
let prevCmd, ctlPtx, ctlPty; // Ss, Tt
|
||||
let rx, ry, psi, fa, fs, x1, y1; // Aa
|
||||
|
||||
// convert l, H, h, V, and v to L
|
||||
switch (c) {
|
||||
@ -555,8 +567,8 @@ export class Path extends Shape<PathConfig> {
|
||||
break;
|
||||
// Note: lineTo handlers need to be above this point
|
||||
case 'm':
|
||||
var dx = p.shift()!;
|
||||
var dy = p.shift()!;
|
||||
const dx = p.shift()!;
|
||||
const dy = p.shift()!;
|
||||
cpx += dx;
|
||||
cpy += dy;
|
||||
cmd = 'M';
|
||||
@ -782,12 +794,12 @@ export class Path extends Shape<PathConfig> {
|
||||
case 'A':
|
||||
// Approximates by breaking curve into line segments
|
||||
len = 0.0;
|
||||
var start = points[4];
|
||||
const start = points[4];
|
||||
// 4 = theta
|
||||
var dTheta = points[5];
|
||||
const dTheta = points[5];
|
||||
// 5 = dTheta
|
||||
var end = points[4] + dTheta;
|
||||
var inc = Math.PI / 180.0;
|
||||
const end = points[4] + dTheta;
|
||||
let inc = Math.PI / 180.0;
|
||||
// 1 degree resolution
|
||||
if (Math.abs(start - end) < inc) {
|
||||
inc = Math.abs(start - end);
|
||||
@ -846,15 +858,15 @@ export class Path extends Shape<PathConfig> {
|
||||
return 0;
|
||||
}
|
||||
static convertEndpointToCenterParameterization(
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
fa,
|
||||
fs,
|
||||
rx,
|
||||
ry,
|
||||
psiDeg
|
||||
x1: number,
|
||||
y1: number,
|
||||
x2: number,
|
||||
y2: number,
|
||||
fa: number,
|
||||
fs: number,
|
||||
rx: number,
|
||||
ry: number,
|
||||
psiDeg: number
|
||||
) {
|
||||
// Derived from: http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||
const psi = psiDeg * (Math.PI / 180.0);
|
||||
|
@ -171,7 +171,7 @@ function checkDefaultFill(config?: TextConfig) {
|
||||
* @param {String} [config.fontVariant] can be normal or small-caps. Default is normal
|
||||
* @param {String} [config.textDecoration] can be line-through, underline or empty string. Default is empty string.
|
||||
* @param {String} config.text
|
||||
* @param {String} [config.align] can be left, center, or right
|
||||
* @param {String} [config.align] can be left, center, right or justify
|
||||
* @param {String} [config.verticalAlign] can be top, middle or bottom
|
||||
* @param {Number} [config.padding]
|
||||
* @param {Number} [config.lineHeight] default is 1
|
||||
@ -242,9 +242,6 @@ export class Text extends Shape<TextConfig> {
|
||||
lineHeightPx / 2;
|
||||
}
|
||||
|
||||
var lineTranslateX = 0;
|
||||
var lineTranslateY = 0;
|
||||
|
||||
if (direction === RTL) {
|
||||
context.setAttr('direction', direction);
|
||||
}
|
||||
@ -266,15 +263,12 @@ export class Text extends Shape<TextConfig> {
|
||||
|
||||
// draw text lines
|
||||
for (n = 0; n < textArrLen; n++) {
|
||||
var lineTranslateX = 0;
|
||||
var lineTranslateY = 0;
|
||||
var obj = textArr[n],
|
||||
let lineTranslateX = 0;
|
||||
let lineTranslateY = 0;
|
||||
const obj = textArr[n],
|
||||
text = obj.text,
|
||||
width = obj.width,
|
||||
lastLine = obj.lastInParagraph,
|
||||
spacesNumber,
|
||||
oneWord,
|
||||
lineWidth;
|
||||
lastLine = obj.lastInParagraph;
|
||||
|
||||
// horizontal alignment
|
||||
context.save();
|
||||
@ -294,9 +288,7 @@ export class Text extends Shape<TextConfig> {
|
||||
const x = lineTranslateX;
|
||||
const y = translateY + lineTranslateY + yOffset;
|
||||
context.moveTo(x, y);
|
||||
spacesNumber = text.split(' ').length - 1;
|
||||
oneWord = spacesNumber === 0;
|
||||
lineWidth =
|
||||
const lineWidth =
|
||||
align === JUSTIFY && !lastLine ? totalWidth - padding * 2 : width;
|
||||
context.lineTo(x + Math.round(lineWidth), y);
|
||||
|
||||
@ -314,9 +306,7 @@ export class Text extends Shape<TextConfig> {
|
||||
context.beginPath();
|
||||
const yOffset = Konva._fixTextRendering ? -Math.round(fontSize / 4) : 0;
|
||||
context.moveTo(lineTranslateX, translateY + lineTranslateY + yOffset);
|
||||
spacesNumber = text.split(' ').length - 1;
|
||||
oneWord = spacesNumber === 0;
|
||||
lineWidth =
|
||||
const lineWidth =
|
||||
align === JUSTIFY && !lastLine ? totalWidth - padding * 2 : width;
|
||||
context.lineTo(
|
||||
lineTranslateX + Math.round(lineWidth),
|
||||
@ -333,7 +323,7 @@ export class Text extends Shape<TextConfig> {
|
||||
// be supported otherwise.
|
||||
if (direction !== RTL && (letterSpacing !== 0 || align === JUSTIFY)) {
|
||||
// var words = text.split(' ');
|
||||
spacesNumber = text.split(' ').length - 1;
|
||||
const spacesNumber = text.split(' ').length - 1;
|
||||
const array = stringToArray(text);
|
||||
for (let li = 0; li < array.length; li++) {
|
||||
const letter = array[li];
|
||||
@ -885,6 +875,8 @@ Factory.addGetterSetter(Text, 'padding', 0, getNumberValidator());
|
||||
*
|
||||
* // align text to right
|
||||
* text.align('right');
|
||||
*
|
||||
* // justify text
|
||||
*/
|
||||
|
||||
Factory.addGetterSetter(Text, 'align', LEFT);
|
||||
|
@ -770,11 +770,11 @@ export class Transformer extends Group {
|
||||
keepProportion = this.keepRatio() || e.shiftKey;
|
||||
}
|
||||
|
||||
var centeredScaling = this.centeredScaling() || e.altKey;
|
||||
let centeredScaling = this.centeredScaling() || e.altKey;
|
||||
|
||||
if (this._movingAnchorName === 'top-left') {
|
||||
if (keepProportion) {
|
||||
var comparePoint = centeredScaling
|
||||
const comparePoint = centeredScaling
|
||||
? {
|
||||
x: this.width() / 2,
|
||||
y: this.height() / 2,
|
||||
@ -788,9 +788,9 @@ export class Transformer extends Group {
|
||||
Math.pow(comparePoint.y - anchorNode.y(), 2)
|
||||
);
|
||||
|
||||
var reverseX = this.findOne('.top-left')!.x() > comparePoint.x ? -1 : 1;
|
||||
const reverseX = this.findOne('.top-left')!.x() > comparePoint.x ? -1 : 1;
|
||||
|
||||
var reverseY = this.findOne('.top-left')!.y() > comparePoint.y ? -1 : 1;
|
||||
const reverseY = this.findOne('.top-left')!.y() > comparePoint.y ? -1 : 1;
|
||||
|
||||
x = newHypotenuse * this.cos * reverseX;
|
||||
y = newHypotenuse * this.sin * reverseY;
|
||||
@ -802,7 +802,7 @@ export class Transformer extends Group {
|
||||
this.findOne('.top-left')!.y(anchorNode.y());
|
||||
} else if (this._movingAnchorName === 'top-right') {
|
||||
if (keepProportion) {
|
||||
var comparePoint = centeredScaling
|
||||
const comparePoint = centeredScaling
|
||||
? {
|
||||
x: this.width() / 2,
|
||||
y: this.height() / 2,
|
||||
@ -817,10 +817,10 @@ export class Transformer extends Group {
|
||||
Math.pow(comparePoint.y - anchorNode.y(), 2)
|
||||
);
|
||||
|
||||
var reverseX =
|
||||
const reverseX =
|
||||
this.findOne('.top-right')!.x() < comparePoint.x ? -1 : 1;
|
||||
|
||||
var reverseY =
|
||||
const reverseY =
|
||||
this.findOne('.top-right')!.y() > comparePoint.y ? -1 : 1;
|
||||
|
||||
x = newHypotenuse * this.cos * reverseX;
|
||||
@ -838,7 +838,7 @@ export class Transformer extends Group {
|
||||
this.findOne('.bottom-right')!.x(anchorNode.x());
|
||||
} else if (this._movingAnchorName === 'bottom-left') {
|
||||
if (keepProportion) {
|
||||
var comparePoint = centeredScaling
|
||||
const comparePoint = centeredScaling
|
||||
? {
|
||||
x: this.width() / 2,
|
||||
y: this.height() / 2,
|
||||
@ -853,9 +853,9 @@ export class Transformer extends Group {
|
||||
Math.pow(anchorNode.y() - comparePoint.y, 2)
|
||||
);
|
||||
|
||||
var reverseX = comparePoint.x < anchorNode.x() ? -1 : 1;
|
||||
const reverseX = comparePoint.x < anchorNode.x() ? -1 : 1;
|
||||
|
||||
var reverseY = anchorNode.y() < comparePoint.y ? -1 : 1;
|
||||
const reverseY = anchorNode.y() < comparePoint.y ? -1 : 1;
|
||||
|
||||
x = newHypotenuse * this.cos * reverseX;
|
||||
y = newHypotenuse * this.sin * reverseY;
|
||||
@ -872,7 +872,7 @@ export class Transformer extends Group {
|
||||
this.findOne('.bottom-right')!.y(anchorNode.y());
|
||||
} else if (this._movingAnchorName === 'bottom-right') {
|
||||
if (keepProportion) {
|
||||
var comparePoint = centeredScaling
|
||||
const comparePoint = centeredScaling
|
||||
? {
|
||||
x: this.width() / 2,
|
||||
y: this.height() / 2,
|
||||
@ -887,10 +887,10 @@ export class Transformer extends Group {
|
||||
Math.pow(anchorNode.y() - comparePoint.y, 2)
|
||||
);
|
||||
|
||||
var reverseX =
|
||||
const reverseX =
|
||||
this.findOne('.bottom-right')!.x() < comparePoint.x ? -1 : 1;
|
||||
|
||||
var reverseY =
|
||||
const reverseY =
|
||||
this.findOne('.bottom-right')!.y() < comparePoint.y ? -1 : 1;
|
||||
|
||||
x = newHypotenuse * this.cos * reverseX;
|
||||
@ -908,7 +908,7 @@ export class Transformer extends Group {
|
||||
);
|
||||
}
|
||||
|
||||
var centeredScaling = this.centeredScaling() || e.altKey;
|
||||
centeredScaling = this.centeredScaling() || e.altKey;
|
||||
if (centeredScaling) {
|
||||
const topLeft = this.findOne('.top-left')!;
|
||||
const bottomRight = this.findOne('.bottom-right')!;
|
||||
|
@ -1,10 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2015",
|
||||
"noEmitOnError": true,
|
||||
"noEmitOnError": false,
|
||||
"moduleResolution": "node",
|
||||
"lib": ["ES2015", "dom"],
|
||||
"module": "CommonJS"
|
||||
"module": "CommonJS",
|
||||
"skipLibCheck": true,
|
||||
"noImplicitAny": false,
|
||||
"allowJs": true,
|
||||
"noEmit": false,
|
||||
"checkJs": false,
|
||||
"allowUnreachableCode": true,
|
||||
"allowUnusedLabels": true,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"noImplicitReturns": false,
|
||||
"noImplicitThis": false,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"strict": false
|
||||
},
|
||||
"include": ["../src/**/*.ts"]
|
||||
"include": ["../src/**/*.ts", "./**/*.ts"],
|
||||
"exclude": ["../node_modules/**/*"]
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
<script type="module">
|
||||
// CORE
|
||||
import './unit/Animation-test.ts';
|
||||
import './unit/Tween-test.ts';
|
||||
import './unit/Canvas-test.ts';
|
||||
import './unit/Container-test.ts';
|
||||
import './unit/Context-test.ts';
|
||||
|
@ -1083,6 +1083,7 @@ describe('Path', function () {
|
||||
it('get point at path', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
const data =
|
||||
'M 300,10 L 250,100 A 100 40 30 1 0 150 150 C 160,100, 290,100, 300,150';
|
||||
var path = new Konva.Path({
|
||||
@ -1102,7 +1103,7 @@ describe('Path', function () {
|
||||
var circle = new Konva.Circle({
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
radius: 2,
|
||||
radius: 0.1,
|
||||
fill: 'black',
|
||||
stroke: 'black',
|
||||
});
|
||||
@ -1164,13 +1165,49 @@ describe('Path', function () {
|
||||
{ x: 299.87435436448743, y: 149.4028482225714 },
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it('get point at vertical path', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
const data = 'M 614.96002,7.5147864 611.20262,429.59529';
|
||||
var path = new Konva.Path({
|
||||
stroke: 'red',
|
||||
strokeWidth: 3,
|
||||
data,
|
||||
x: -600,
|
||||
});
|
||||
layer.add(path);
|
||||
if (isBrowser) {
|
||||
const SVGPath = document.createElementNS(
|
||||
'http://www.w3.org/2000/svg',
|
||||
'path'
|
||||
) as SVGPathElement;
|
||||
SVGPath.setAttribute('d', data);
|
||||
for (var i = 0.001; i < path.getLength(); i += 1) {
|
||||
var p = path.getPointAtLength(i);
|
||||
console.log(p);
|
||||
var circle = new Konva.Circle({
|
||||
x: p.x + path.x(),
|
||||
y: p.y + path.y(),
|
||||
radius: 2,
|
||||
fill: 'black',
|
||||
stroke: 'black',
|
||||
});
|
||||
layer.add(circle);
|
||||
const position = SVGPath.getPointAtLength(i);
|
||||
console.log(position);
|
||||
assert(Math.abs(p.x - position.x) <= 1);
|
||||
assert(Math.abs(p.y - position.y) <= 1);
|
||||
}
|
||||
}
|
||||
stage.add(layer);
|
||||
});
|
||||
|
||||
it('get point at path with float attrs', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const data =
|
||||
'M419.0000314094981 342.88624187900973 L419.00003140949804 577.0038889378335 L465.014001082264 577.0038889378336 Z';
|
||||
|
@ -1550,6 +1550,83 @@ describe('Shape', function () {
|
||||
compareCanvases(canvas2, canvas1, 240, 110);
|
||||
});
|
||||
|
||||
it('export stage when buffer canvas is for line', async function () {
|
||||
var stage = addStage();
|
||||
|
||||
var layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const group = new Konva.Group({
|
||||
id: 'group01',
|
||||
draggable: false,
|
||||
opacity: 0.99,
|
||||
});
|
||||
layer.add(group);
|
||||
|
||||
const arrow = new Konva.Arrow({
|
||||
x: 0,
|
||||
y: 0,
|
||||
points: [50, 25, 200, 25, 200, 225, 400, 225],
|
||||
stroke: 'purple',
|
||||
fill: 'purple',
|
||||
strokeWidth: 4,
|
||||
pointerAtEnding: true,
|
||||
bezier: true,
|
||||
});
|
||||
group.add(arrow);
|
||||
|
||||
const bounds = layer.getClientRect({ relativeTo: stage });
|
||||
const pos = stage.getPosition();
|
||||
|
||||
const canvas1 = layer.toCanvas({
|
||||
pixelRatio: 1,
|
||||
x: bounds.x + pos.x,
|
||||
y: bounds.y + pos.y,
|
||||
width: bounds.width,
|
||||
height: bounds.height,
|
||||
});
|
||||
group.opacity(1);
|
||||
const canvas2 = layer.toCanvas({
|
||||
pixelRatio: 1,
|
||||
x: bounds.x + pos.x,
|
||||
y: bounds.y + pos.y,
|
||||
width: bounds.width,
|
||||
height: bounds.height,
|
||||
});
|
||||
|
||||
compareCanvases(canvas1, canvas2, 240, 110);
|
||||
});
|
||||
|
||||
it('check stroke rendering on buffer canvas', async function () {
|
||||
var stage = addStage();
|
||||
|
||||
var layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
const rect = new Konva.Rect({
|
||||
x: 150,
|
||||
y: 50,
|
||||
width: 50,
|
||||
height: 50,
|
||||
fill: '#039BE5',
|
||||
stroke: 'yellow',
|
||||
strokeWidth: 5,
|
||||
shadowColor: 'black',
|
||||
shadowOffset: { x: 10, y: 10 },
|
||||
shadowOpacity: 0.5,
|
||||
});
|
||||
|
||||
layer.add(rect);
|
||||
|
||||
const canvas1 = layer.toCanvas();
|
||||
rect.cache();
|
||||
const canvas2 = layer.toCanvas();
|
||||
|
||||
// throw new Error('stop');
|
||||
|
||||
compareCanvases(canvas1, canvas2);
|
||||
});
|
||||
|
||||
// ======================================================
|
||||
it('optional disable shadow for stroke', function () {
|
||||
var stage = addStage();
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
simulateTouchStart,
|
||||
simulateTouchMove,
|
||||
simulateTouchEnd,
|
||||
simulatePointerMove,
|
||||
compareCanvases,
|
||||
createCanvas,
|
||||
showHit,
|
||||
@ -1222,6 +1223,36 @@ describe('Stage', function () {
|
||||
assert.equal(count, 2);
|
||||
});
|
||||
|
||||
it('stage pointerleave should not fire when leaving a child', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
var circle = new Konva.Circle({
|
||||
fill: 'red',
|
||||
radius: 30,
|
||||
x: 50,
|
||||
y: 50,
|
||||
});
|
||||
layer.add(circle);
|
||||
layer.draw();
|
||||
|
||||
var stageLeave = 0;
|
||||
var circleLeave = 0;
|
||||
stage.on('pointerleave', function () {
|
||||
stageLeave += 1;
|
||||
});
|
||||
circle.on('pointerleave', function () {
|
||||
circleLeave += 1;
|
||||
});
|
||||
|
||||
simulatePointerMove(stage, { x: 50, y: 50 });
|
||||
simulatePointerMove(stage, { x: 90, y: 50 });
|
||||
|
||||
assert.equal(circleLeave, 1, 'circle pointerleave should fire');
|
||||
assert.equal(stageLeave, 0, 'stage pointerleave should not fire');
|
||||
});
|
||||
|
||||
it('toDataURL with hidden layer', function () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
|
@ -161,7 +161,9 @@ describe('Text', function () {
|
||||
context.fillStyle = 'darkgrey';
|
||||
context.fillText('😬👧🏿', 10, 10 + 25);
|
||||
|
||||
compareLayerAndCanvas(layer, canvas, 254, 100);
|
||||
if (isBrowser) {
|
||||
compareLayerAndCanvas(layer, canvas, 254, 100);
|
||||
}
|
||||
});
|
||||
|
||||
it('check emoji rendering', function () {
|
||||
@ -190,7 +192,9 @@ describe('Text', function () {
|
||||
context.fillText('😁😁', 10, 10 + 10);
|
||||
context.fillText('😁', 10, 10 + 30);
|
||||
|
||||
compareLayerAndCanvas(layer, canvas, 254);
|
||||
if (isBrowser) {
|
||||
compareLayerAndCanvas(layer, canvas, 254, 100);
|
||||
}
|
||||
});
|
||||
|
||||
it('check hindi with letterSpacing', function () {
|
||||
|
@ -98,8 +98,8 @@ describe('Tween', function () {
|
||||
|
||||
tween.destroy();
|
||||
|
||||
assert.equal(Konva.Tween.tweens[circle._id].x, undefined);
|
||||
assert.equal(Konva.Tween.attrs[circle._id][tween._id], undefined);
|
||||
assert.equal(Konva.Tween.tweens[circle._id], undefined);
|
||||
assert.equal(Konva.Tween.attrs[circle._id], undefined);
|
||||
});
|
||||
|
||||
// ======================================================
|
||||
@ -238,7 +238,7 @@ describe('Tween', function () {
|
||||
duration: 0.1,
|
||||
onFinish: function () {
|
||||
assert.equal(circle.x(), stage.width() / 2);
|
||||
assert.equal(Object.keys(Konva.Tween.attrs[circle._id]).length, 0);
|
||||
assert.equal(Konva.Tween.attrs[circle._id], undefined);
|
||||
done();
|
||||
},
|
||||
});
|
||||
@ -305,16 +305,10 @@ describe('Tween', function () {
|
||||
points: [100, 100, 200, 100, 200, 200, 100, 200],
|
||||
duration: 0.1,
|
||||
onFinish: function () {
|
||||
assert.deepEqual(line.points(), [
|
||||
100,
|
||||
100,
|
||||
200,
|
||||
100,
|
||||
200,
|
||||
200,
|
||||
100,
|
||||
200,
|
||||
]);
|
||||
assert.deepEqual(
|
||||
line.points(),
|
||||
[100, 100, 200, 100, 200, 200, 100, 200]
|
||||
);
|
||||
done();
|
||||
},
|
||||
});
|
||||
@ -364,16 +358,10 @@ describe('Tween', function () {
|
||||
tween.reverse();
|
||||
},
|
||||
onReset: function () {
|
||||
assert.deepEqual(line.points(), [
|
||||
100,
|
||||
100,
|
||||
200,
|
||||
100,
|
||||
200,
|
||||
200,
|
||||
100,
|
||||
200,
|
||||
]);
|
||||
assert.deepEqual(
|
||||
line.points(),
|
||||
[100, 100, 200, 100, 200, 200, 100, 200]
|
||||
);
|
||||
done();
|
||||
},
|
||||
});
|
||||
|
@ -57,19 +57,16 @@ function isType(object, type) {
|
||||
|
||||
// Type Conversion
|
||||
function copyImageData(imageData) {
|
||||
var height = imageData.height,
|
||||
const height = imageData.height,
|
||||
width = imageData.width,
|
||||
data = imageData.data,
|
||||
newImageData,
|
||||
newData,
|
||||
i;
|
||||
data = imageData.data;
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
newImageData = context.getImageData(0, 0, width, height);
|
||||
newData = newImageData.data;
|
||||
const newImageData = context.getImageData(0, 0, width, height);
|
||||
const newData = newImageData.data;
|
||||
|
||||
for (i = imageData.data.length; i--; ) {
|
||||
for (let i = imageData.data.length; i--; ) {
|
||||
newData[i] = data[i];
|
||||
}
|
||||
|
||||
@ -90,7 +87,7 @@ function toImageData(object) {
|
||||
}
|
||||
}
|
||||
function toImageDataFromImage(image) {
|
||||
var height = image.height,
|
||||
const height = image.height,
|
||||
width = image.width;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
@ -99,7 +96,7 @@ function toImageDataFromImage(image) {
|
||||
return context.getImageData(0, 0, width, height);
|
||||
}
|
||||
function toImageDataFromCanvas(canvas) {
|
||||
var height = canvas.height,
|
||||
const height = canvas.height,
|
||||
width = canvas.width,
|
||||
context = canvas.getContext('2d');
|
||||
if (!width || !height) {
|
||||
@ -109,13 +106,13 @@ function toImageDataFromCanvas(canvas) {
|
||||
return context.getImageData(0, 0, width, height);
|
||||
}
|
||||
function toImageDataFromContext(context) {
|
||||
var canvas = context.canvas,
|
||||
const canvas = context.canvas,
|
||||
height = canvas.height,
|
||||
width = canvas.width;
|
||||
return context.getImageData(0, 0, width, height);
|
||||
}
|
||||
function toCanvas(object) {
|
||||
var data = toImageData(object),
|
||||
const data = toImageData(object),
|
||||
canvas = getCanvas(data.width, data.height),
|
||||
context = canvas.getContext('2d');
|
||||
|
||||
@ -135,16 +132,15 @@ function equalDimensions(a, b) {
|
||||
}
|
||||
|
||||
export function equal(a, b, tolerance, secondTol) {
|
||||
var aData = a.data,
|
||||
const aData = a.data,
|
||||
bData = b.data,
|
||||
length = aData.length,
|
||||
i;
|
||||
length = aData.length;
|
||||
|
||||
tolerance = tolerance || 0;
|
||||
|
||||
var count = 0;
|
||||
let count = 0;
|
||||
if (!equalDimensions(a, b)) return false;
|
||||
for (i = length; i--; ) {
|
||||
for (let i = length; i--; ) {
|
||||
const d = Math.abs(aData[i] - bData[i]);
|
||||
if (aData[i] !== bData[i] && d > tolerance) {
|
||||
if (!secondTol) {
|
||||
@ -168,21 +164,15 @@ function diff(a, b, options) {
|
||||
return (equalDimensions(a, b) ? diffEqual : diffUnequal)(a, b, options);
|
||||
}
|
||||
function diffEqual(a, b, options) {
|
||||
var height = a.height,
|
||||
const height = a.height,
|
||||
width = a.width,
|
||||
c = getImageData(width, height), // c = a - b
|
||||
aData = a.data,
|
||||
bData = b.data,
|
||||
cData = c.data,
|
||||
length = cData.length,
|
||||
row,
|
||||
column,
|
||||
i,
|
||||
j,
|
||||
k,
|
||||
v;
|
||||
length = cData.length;
|
||||
|
||||
for (i = 0; i < length; i += 4) {
|
||||
for (let i = 0; i < length; i += 4) {
|
||||
cData[i] = Math.abs(aData[i] - bData[i]);
|
||||
cData[i + 1] = Math.abs(aData[i + 1] - bData[i + 1]);
|
||||
cData[i + 2] = Math.abs(aData[i + 2] - bData[i + 2]);
|
||||
@ -192,32 +182,26 @@ function diffEqual(a, b, options) {
|
||||
return c;
|
||||
}
|
||||
function diffUnequal(a, b, options) {
|
||||
var height = Math.max(a.height, b.height),
|
||||
const height = Math.max(a.height, b.height),
|
||||
width = Math.max(a.width, b.width),
|
||||
c = getImageData(width, height), // c = a - b
|
||||
aData = a.data,
|
||||
bData = b.data,
|
||||
cData = c.data,
|
||||
align = options && options.align,
|
||||
rowOffset,
|
||||
columnOffset,
|
||||
row,
|
||||
column,
|
||||
i,
|
||||
j,
|
||||
k,
|
||||
v;
|
||||
align = options && options.align;
|
||||
var rowOffset,
|
||||
columnOffset;
|
||||
|
||||
for (i = cData.length - 1; i > 0; i = i - 4) {
|
||||
for (let i = cData.length - 1; i > 0; i = i - 4) {
|
||||
cData[i] = 255;
|
||||
}
|
||||
|
||||
// Add First Image
|
||||
offsets(a);
|
||||
for (row = a.height; row--; ) {
|
||||
for (column = a.width; column--; ) {
|
||||
i = 4 * ((row + rowOffset) * width + (column + columnOffset));
|
||||
j = 4 * (row * a.width + column);
|
||||
for (let row = a.height; row--; ) {
|
||||
for (let column = a.width; column--; ) {
|
||||
const i = 4 * ((row + rowOffset) * width + (column + columnOffset));
|
||||
const j = 4 * (row * a.width + column);
|
||||
cData[i + 0] = aData[j + 0]; // r
|
||||
cData[i + 1] = aData[j + 1]; // g
|
||||
cData[i + 2] = aData[j + 2]; // b
|
||||
@ -227,10 +211,10 @@ function diffUnequal(a, b, options) {
|
||||
|
||||
// Subtract Second Image
|
||||
offsets(b);
|
||||
for (row = b.height; row--; ) {
|
||||
for (column = b.width; column--; ) {
|
||||
i = 4 * ((row + rowOffset) * width + (column + columnOffset));
|
||||
j = 4 * (row * b.width + column);
|
||||
for (let row = b.height; row--; ) {
|
||||
for (let column = b.width; column--; ) {
|
||||
const i = 4 * ((row + rowOffset) * width + (column + columnOffset));
|
||||
const j = 4 * (row * b.width + column);
|
||||
cData[i + 0] = Math.abs(cData[i + 0] - bData[j + 0]); // r
|
||||
cData[i + 1] = Math.abs(cData[i + 1] - bData[j + 1]); // g
|
||||
cData[i + 2] = Math.abs(cData[i + 2] - bData[j + 2]); // b
|
||||
@ -253,8 +237,7 @@ function diffUnequal(a, b, options) {
|
||||
|
||||
// Validation
|
||||
function checkType(...args) {
|
||||
var i;
|
||||
for (i = 0; i < args.length; i++) {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (!isImageType(args[i])) {
|
||||
throw {
|
||||
name: 'ImageTypeError',
|
||||
|
@ -131,6 +131,14 @@ export function compareCanvases(canvas1, canvas2, tol?, secondTol?) {
|
||||
b.appendChild(canvas2);
|
||||
c.appendChild(diffCanvas);
|
||||
div.appendChild(b);
|
||||
if (!canvas1.parentNode) {
|
||||
const d = get('div', '<div>Original:</div>');
|
||||
canvas1.style.position = '';
|
||||
canvas1.style.display = '';
|
||||
d.style.float = 'left';
|
||||
d.appendChild(canvas1);
|
||||
div.appendChild(d);
|
||||
}
|
||||
div.appendChild(c);
|
||||
getContainer().appendChild(div);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user