Merge remote-tracking branch 'upstream/master' into change-text-paths

This commit is contained in:
gtktsc 2023-03-24 20:00:26 +01:00
commit c759ec43be
24 changed files with 196 additions and 123 deletions

View File

@ -3,6 +3,11 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
### 8.4.3 (2023-03-23)
- Typescript fixes
- Better validation for `Konva.Transfomer` `nodes` property
### 8.4.2 (2023-01-20) ### 8.4.2 (2023-01-20)
- Fix justify on text with limited height - Fix justify on text with limited height

View File

@ -5,10 +5,10 @@
})(this, (function () { 'use strict'; })(this, (function () { 'use strict';
/* /*
* Konva JavaScript Framework v8.4.2 * Konva JavaScript Framework v8.4.3
* http://konvajs.org/ * http://konvajs.org/
* Licensed under the MIT * Licensed under the MIT
* Date: Fri Jan 20 2023 * Date: Thu Mar 23 2023
* *
* Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS)
* Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva)
@ -35,7 +35,7 @@
: {}; : {};
const Konva$2 = { const Konva$2 = {
_global: glob, _global: glob,
version: '8.4.2', version: '8.4.3',
isBrowser: detectBrowser(), isBrowser: detectBrowser(),
isUnminified: /param/.test(function (param) { }.toString()), isUnminified: /param/.test(function (param) { }.toString()),
dblClickWindow: 400, dblClickWindow: 400,
@ -1652,7 +1652,7 @@
} }
} }
_applyLineCap(shape) { _applyLineCap(shape) {
var lineCap = shape.getLineCap(); const lineCap = shape.attrs.lineCap;
if (lineCap) { if (lineCap) {
this.setAttr('lineCap', lineCap); this.setAttr('lineCap', lineCap);
} }
@ -1664,7 +1664,7 @@
} }
} }
_applyLineJoin(shape) { _applyLineJoin(shape) {
var lineJoin = shape.attrs.lineJoin; const lineJoin = shape.attrs.lineJoin;
if (lineJoin) { if (lineJoin) {
this.setAttr('lineJoin', lineJoin); this.setAttr('lineJoin', lineJoin);
} }
@ -2081,30 +2081,30 @@
} }
} }
_fillRadialGradient(shape) { _fillRadialGradient(shape) {
var grd = shape._getRadialGradient(); const grd = shape._getRadialGradient();
if (grd) { if (grd) {
this.setAttr('fillStyle', grd); this.setAttr('fillStyle', grd);
shape._fillFunc(this); shape._fillFunc(this);
} }
} }
_fill(shape) { _fill(shape) {
var hasColor = shape.fill(), fillPriority = shape.getFillPriority(); const hasColor = shape.fill(), fillPriority = shape.getFillPriority();
// priority fills // priority fills
if (hasColor && fillPriority === 'color') { if (hasColor && fillPriority === 'color') {
this._fillColor(shape); this._fillColor(shape);
return; return;
} }
var hasPattern = shape.getFillPatternImage(); const hasPattern = shape.getFillPatternImage();
if (hasPattern && fillPriority === 'pattern') { if (hasPattern && fillPriority === 'pattern') {
this._fillPattern(shape); this._fillPattern(shape);
return; return;
} }
var hasLinearGradient = shape.getFillLinearGradientColorStops(); const hasLinearGradient = shape.getFillLinearGradientColorStops();
if (hasLinearGradient && fillPriority === 'linear-gradient') { if (hasLinearGradient && fillPriority === 'linear-gradient') {
this._fillLinearGradient(shape); this._fillLinearGradient(shape);
return; return;
} }
var hasRadialGradient = shape.getFillRadialGradientColorStops(); const hasRadialGradient = shape.getFillRadialGradientColorStops();
if (hasRadialGradient && fillPriority === 'radial-gradient') { if (hasRadialGradient && fillPriority === 'radial-gradient') {
this._fillRadialGradient(shape); this._fillRadialGradient(shape);
return; return;
@ -2124,7 +2124,7 @@
} }
} }
_strokeLinearGradient(shape) { _strokeLinearGradient(shape) {
var start = shape.getStrokeLinearGradientStartPoint(), end = shape.getStrokeLinearGradientEndPoint(), colorStops = shape.getStrokeLinearGradientColorStops(), grd = this.createLinearGradient(start.x, start.y, end.x, end.y); const start = shape.getStrokeLinearGradientStartPoint(), end = shape.getStrokeLinearGradientEndPoint(), colorStops = shape.getStrokeLinearGradientColorStops(), grd = this.createLinearGradient(start.x, start.y, end.x, end.y);
if (colorStops) { if (colorStops) {
// build color stops // build color stops
for (var n = 0; n < colorStops.length; n += 2) { for (var n = 0; n < colorStops.length; n += 2) {
@ -2198,7 +2198,7 @@
_stroke(shape) { _stroke(shape) {
if (shape.hasHitStroke()) { if (shape.hasHitStroke()) {
// ignore strokeScaleEnabled for Text // ignore strokeScaleEnabled for Text
var strokeScaleEnabled = shape.getStrokeScaleEnabled(); const strokeScaleEnabled = shape.getStrokeScaleEnabled();
if (!strokeScaleEnabled) { if (!strokeScaleEnabled) {
this.save(); this.save();
var pixelRatio = this.getCanvas().getPixelRatio(); var pixelRatio = this.getCanvas().getPixelRatio();
@ -14893,7 +14893,15 @@
if (this._nodes && this._nodes.length) { if (this._nodes && this._nodes.length) {
this.detach(); this.detach();
} }
this._nodes = nodes; const filteredNodes = nodes.filter((node) => {
// check if ancestor of the transformer
if (node.isAncestorOf(this)) {
Util.error('Konva.Transformer cannot be an a child of the node you are trying to attach');
return false;
}
return true;
});
this._nodes = nodes = filteredNodes;
if (nodes.length === 1 && this.useSingleNodeRotation()) { if (nodes.length === 1 && this.useSingleNodeRotation()) {
this.rotation(nodes[0].getAbsoluteRotation()); this.rotation(nodes[0].getAbsoluteRotation());
} }
@ -14993,6 +15001,19 @@
this._nodes = []; this._nodes = [];
this._resetTransformCache(); this._resetTransformCache();
} }
/**
* bind events to the Transformer. You can use events: `transform`, `transformstart`, `transformend`, `dragstart`, `dragmove`, `dragend`
* @method
* @name Konva.Transformer#on
* @param {String} evtStr e.g. 'transform'
* @param {Function} handler The handler function. The first argument of that function is event object. Event object has `target` as main target of the event, `currentTarget` as current node listener and `evt` as native browser event.
* @returns {Konva.Transformer}
* @example
* // add click listener
* tr.on('transformstart', function() {
* console.log('transform started');
* });
*/
_resetTransformCache() { _resetTransformCache() {
this._clearCache(NODES_RECT); this._clearCache(NODES_RECT);
this._clearCache('transform'); this._clearCache('transform');

6
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "konva", "name": "konva",
"version": "8.4.2", "version": "8.4.3",
"author": "Anton Lavrenov", "author": "Anton Lavrenov",
"files": [ "files": [
"README.md", "README.md",

View File

@ -1,7 +1,7 @@
import FileHound from 'filehound'; import FileHound from 'filehound';
import fs from 'fs'; import fs from 'fs';
const files = FileHound.create().paths('./lib').ext('js').find(); const files = FileHound.create().paths('./lib').ext(['js', 'ts']).find();
files.then((filePaths) => { files.then((filePaths) => {
filePaths.forEach((filepath) => { filePaths.forEach((filepath) => {
@ -22,6 +22,9 @@ files.then((filePaths) => {
"import * as Canvas from 'canvas';" "import * as Canvas from 'canvas';"
); );
// Handle import("./x/y/z") syntax.
text = text.replace(/(import\s*\(\s*['"])(.*)(?=['"])/g, '$1$2.js');
fs.writeFile(filepath, text, function (err) { fs.writeFile(filepath, text, function (err) {
if (err) { if (err) {
throw err; throw err;

View File

@ -3,6 +3,7 @@ import { Konva } from './Global';
import { Canvas } from './Canvas'; import { Canvas } from './Canvas';
import { Shape } from './Shape'; import { Shape } from './Shape';
import { IRect } from './types'; import { IRect } from './types';
import type { Node } from './Node';
function simplifyArray(arr: Array<any>) { function simplifyArray(arr: Array<any>) {
var retArr = [], var retArr = [],
@ -153,7 +154,7 @@ export class Context {
} }
} }
_stroke(shape) { _stroke(shape: Shape) {
// abstract // abstract
} }
@ -173,7 +174,7 @@ export class Context {
} }
} }
getTrace(relaxed?, rounded?) { getTrace(relaxed?: boolean, rounded?: boolean) {
var traceArr = this.traceArr, var traceArr = this.traceArr,
len = traceArr.length, len = traceArr.length,
str = '', str = '',
@ -279,20 +280,20 @@ export class Context {
); );
} }
} }
_applyLineCap(shape) { _applyLineCap(shape: Shape) {
var lineCap = shape.getLineCap(); const lineCap = shape.attrs.lineCap;
if (lineCap) { if (lineCap) {
this.setAttr('lineCap', lineCap); this.setAttr('lineCap', lineCap);
} }
} }
_applyOpacity(shape) { _applyOpacity(shape: Node) {
var absOpacity = shape.getAbsoluteOpacity(); var absOpacity = shape.getAbsoluteOpacity();
if (absOpacity !== 1) { if (absOpacity !== 1) {
this.setAttr('globalAlpha', absOpacity); this.setAttr('globalAlpha', absOpacity);
} }
} }
_applyLineJoin(shape: Shape) { _applyLineJoin(shape: Shape) {
var lineJoin = shape.attrs.lineJoin; const lineJoin = shape.attrs.lineJoin;
if (lineJoin) { if (lineJoin) {
this.setAttr('lineJoin', lineJoin); this.setAttr('lineJoin', lineJoin);
} }
@ -663,7 +664,7 @@ export class Context {
* @method * @method
* @name Konva.Context#strokeText * @name Konva.Context#strokeText
*/ */
strokeText(a0: string, a1: number, a2: number, a3: number) { strokeText(a0: string, a1: number, a2: number, a3?: number) {
this._context.strokeText(a0, a1, a2, a3); this._context.strokeText(a0, a1, a2, a3);
} }
/** /**
@ -775,11 +776,11 @@ export class SceneContext extends Context {
this.setAttr('fillStyle', fill); this.setAttr('fillStyle', fill);
shape._fillFunc(this); shape._fillFunc(this);
} }
_fillPattern(shape) { _fillPattern(shape: Shape) {
this.setAttr('fillStyle', shape._getFillPattern()); this.setAttr('fillStyle', shape._getFillPattern());
shape._fillFunc(this); shape._fillFunc(this);
} }
_fillLinearGradient(shape) { _fillLinearGradient(shape: Shape) {
var grd = shape._getLinearGradient(); var grd = shape._getLinearGradient();
if (grd) { if (grd) {
@ -787,15 +788,15 @@ export class SceneContext extends Context {
shape._fillFunc(this); shape._fillFunc(this);
} }
} }
_fillRadialGradient(shape) { _fillRadialGradient(shape: Shape) {
var grd = shape._getRadialGradient(); const grd = shape._getRadialGradient();
if (grd) { if (grd) {
this.setAttr('fillStyle', grd); this.setAttr('fillStyle', grd);
shape._fillFunc(this); shape._fillFunc(this);
} }
} }
_fill(shape) { _fill(shape) {
var hasColor = shape.fill(), const hasColor = shape.fill(),
fillPriority = shape.getFillPriority(); fillPriority = shape.getFillPriority();
// priority fills // priority fills
@ -804,19 +805,19 @@ export class SceneContext extends Context {
return; return;
} }
var hasPattern = shape.getFillPatternImage(); const hasPattern = shape.getFillPatternImage();
if (hasPattern && fillPriority === 'pattern') { if (hasPattern && fillPriority === 'pattern') {
this._fillPattern(shape); this._fillPattern(shape);
return; return;
} }
var hasLinearGradient = shape.getFillLinearGradientColorStops(); const hasLinearGradient = shape.getFillLinearGradientColorStops();
if (hasLinearGradient && fillPriority === 'linear-gradient') { if (hasLinearGradient && fillPriority === 'linear-gradient') {
this._fillLinearGradient(shape); this._fillLinearGradient(shape);
return; return;
} }
var hasRadialGradient = shape.getFillRadialGradientColorStops(); const hasRadialGradient = shape.getFillRadialGradientColorStops();
if (hasRadialGradient && fillPriority === 'radial-gradient') { if (hasRadialGradient && fillPriority === 'radial-gradient') {
this._fillRadialGradient(shape); this._fillRadialGradient(shape);
return; return;
@ -834,7 +835,7 @@ export class SceneContext extends Context {
} }
} }
_strokeLinearGradient(shape) { _strokeLinearGradient(shape) {
var start = shape.getStrokeLinearGradientStartPoint(), const start = shape.getStrokeLinearGradientStartPoint(),
end = shape.getStrokeLinearGradientEndPoint(), end = shape.getStrokeLinearGradientEndPoint(),
colorStops = shape.getStrokeLinearGradientColorStops(), colorStops = shape.getStrokeLinearGradientColorStops(),
grd = this.createLinearGradient(start.x, start.y, end.x, end.y); grd = this.createLinearGradient(start.x, start.y, end.x, end.y);
@ -842,7 +843,7 @@ export class SceneContext extends Context {
if (colorStops) { if (colorStops) {
// build color stops // build color stops
for (var n = 0; n < colorStops.length; n += 2) { for (var n = 0; n < colorStops.length; n += 2) {
grd.addColorStop(colorStops[n], colorStops[n + 1]); grd.addColorStop(colorStops[n] as number, colorStops[n + 1] as string);
} }
this.setAttr('strokeStyle', grd); this.setAttr('strokeStyle', grd);
} }
@ -914,7 +915,7 @@ export class HitContext extends Context {
willReadFrequently: true, willReadFrequently: true,
}) as CanvasRenderingContext2D; }) as CanvasRenderingContext2D;
} }
_fill(shape) { _fill(shape: Shape) {
this.save(); this.save();
this.setAttr('fillStyle', shape.colorKey); this.setAttr('fillStyle', shape.colorKey);
shape._fillFuncHit(this); shape._fillFuncHit(this);
@ -928,7 +929,7 @@ export class HitContext extends Context {
_stroke(shape) { _stroke(shape) {
if (shape.hasHitStroke()) { if (shape.hasHitStroke()) {
// ignore strokeScaleEnabled for Text // ignore strokeScaleEnabled for Text
var strokeScaleEnabled = shape.getStrokeScaleEnabled(); const strokeScaleEnabled = shape.getStrokeScaleEnabled();
if (!strokeScaleEnabled) { if (!strokeScaleEnabled) {
this.save(); this.save();
var pixelRatio = this.getCanvas().getPixelRatio(); var pixelRatio = this.getCanvas().getPixelRatio();

View File

@ -820,6 +820,8 @@ export class Shape<
strokeHitEnabled: GetSet<boolean, this>; strokeHitEnabled: GetSet<boolean, this>;
strokeWidth: GetSet<number, this>; strokeWidth: GetSet<number, this>;
hitStrokeWidth: GetSet<number | 'auto', this>; hitStrokeWidth: GetSet<number | 'auto', this>;
strokeLinearGradientStartPoint: GetSet<Vector2d, this>;
strokeLinearGradientEndPoint: GetSet<Vector2d, this>;
strokeLinearGradientColorStops: GetSet<Array<number | string>, this>; strokeLinearGradientColorStops: GetSet<Array<number | string>, this>;
} }

View File

@ -4,7 +4,7 @@ import { Konva } from '../Global';
import { GetSet } from '../types'; import { GetSet } from '../types';
import { getNumberValidator, getBooleanValidator } from '../Validators'; import { getNumberValidator, getBooleanValidator } from '../Validators';
import { _registerNode } from '../Global'; import { _registerNode } from '../Global';
import { Transform, Util } from '../Util'; import { Context } from '../Context';
export interface ArcConfig extends ShapeConfig { export interface ArcConfig extends ShapeConfig {
angle: number; angle: number;
@ -38,7 +38,7 @@ export interface ArcConfig extends ShapeConfig {
* }); * });
*/ */
export class Arc extends Shape<ArcConfig> { export class Arc extends Shape<ArcConfig> {
_sceneFunc(context) { _sceneFunc(context: Context) {
var angle = Konva.getAngle(this.angle()), var angle = Konva.getAngle(this.angle()),
clockwise = this.clockwise(); clockwise = this.clockwise();
@ -54,10 +54,10 @@ export class Arc extends Shape<ArcConfig> {
getHeight() { getHeight() {
return this.outerRadius() * 2; return this.outerRadius() * 2;
} }
setWidth(width) { setWidth(width: number) {
this.outerRadius(width / 2); this.outerRadius(width / 2);
} }
setHeight(height) { setHeight(height: number) {
this.outerRadius(height / 2); this.outerRadius(height / 2);
} }

View File

@ -4,6 +4,7 @@ import { GetSet } from '../types';
import { getNumberValidator } from '../Validators'; import { getNumberValidator } from '../Validators';
import { _registerNode } from '../Global'; import { _registerNode } from '../Global';
import { Path } from './Path'; import { Path } from './Path';
import { Context } from '../Context';
export interface ArrowConfig extends LineConfig { export interface ArrowConfig extends LineConfig {
points: number[]; points: number[];
@ -40,7 +41,7 @@ export interface ArrowConfig extends LineConfig {
* }); * });
*/ */
export class Arrow extends Line<ArrowConfig> { export class Arrow extends Line<ArrowConfig> {
_sceneFunc(ctx) { _sceneFunc(ctx: Context) {
super._sceneFunc(ctx); super._sceneFunc(ctx);
var PI2 = Math.PI * 2; var PI2 = Math.PI * 2;
var points = this.points(); var points = this.points();
@ -126,7 +127,7 @@ export class Arrow extends Line<ArrowConfig> {
} }
} }
__fillStroke(ctx) { __fillStroke(ctx: Context) {
// here is a tricky part // here is a tricky part
// we need to disable dash for arrow pointers // we need to disable dash for arrow pointers
var isDashEnabled = this.dashEnabled(); var isDashEnabled = this.dashEnabled();

View File

@ -3,6 +3,7 @@ import { Shape, ShapeConfig } from '../Shape';
import { GetSet } from '../types'; import { GetSet } from '../types';
import { getNumberValidator } from '../Validators'; import { getNumberValidator } from '../Validators';
import { _registerNode } from '../Global'; import { _registerNode } from '../Global';
import { Context } from '../Context';
export interface CircleConfig extends ShapeConfig { export interface CircleConfig extends ShapeConfig {
radius?: number; radius?: number;
@ -27,7 +28,7 @@ export interface CircleConfig extends ShapeConfig {
* }); * });
*/ */
export class Circle extends Shape<CircleConfig> { export class Circle extends Shape<CircleConfig> {
_sceneFunc(context) { _sceneFunc(context: Context) {
context.beginPath(); context.beginPath();
context.arc(0, 0, this.attrs.radius || 0, 0, Math.PI * 2, false); context.arc(0, 0, this.attrs.radius || 0, 0, Math.PI * 2, false);
context.closePath(); context.closePath();
@ -39,12 +40,12 @@ export class Circle extends Shape<CircleConfig> {
getHeight() { getHeight() {
return this.radius() * 2; return this.radius() * 2;
} }
setWidth(width) { setWidth(width: number) {
if (this.radius() !== width / 2) { if (this.radius() !== width / 2) {
this.radius(width / 2); this.radius(width / 2);
} }
} }
setHeight(height) { setHeight(height: number) {
if (this.radius() !== height / 2) { if (this.radius() !== height / 2) {
this.radius(height / 2); this.radius(height / 2);
} }

View File

@ -2,6 +2,7 @@ import { Factory } from '../Factory';
import { Shape, ShapeConfig } from '../Shape'; import { Shape, ShapeConfig } from '../Shape';
import { getNumberValidator } from '../Validators'; import { getNumberValidator } from '../Validators';
import { _registerNode } from '../Global'; import { _registerNode } from '../Global';
import { Context } from '../Context';
import { GetSet, Vector2d } from '../types'; import { GetSet, Vector2d } from '../types';
@ -29,7 +30,7 @@ export interface EllipseConfig extends ShapeConfig {
* }); * });
*/ */
export class Ellipse extends Shape<EllipseConfig> { export class Ellipse extends Shape<EllipseConfig> {
_sceneFunc(context) { _sceneFunc(context: Context) {
var rx = this.radiusX(), var rx = this.radiusX(),
ry = this.radiusY(); ry = this.radiusY();
@ -49,10 +50,10 @@ export class Ellipse extends Shape<EllipseConfig> {
getHeight() { getHeight() {
return this.radiusY() * 2; return this.radiusY() * 2;
} }
setWidth(width) { setWidth(width: number) {
this.radiusX(width / 2); this.radiusX(width / 2);
} }
setHeight(height) { setHeight(height: number) {
this.radiusY(height / 2); this.radiusY(height / 2);
} }

View File

@ -111,7 +111,7 @@ export class Image extends Shape<ImageConfig> {
} }
// If you need to draw later, you need to execute save/restore // If you need to draw later, you need to execute save/restore
} }
_hitFunc(context) { _hitFunc(context: Context) {
var width = this.width(), var width = this.width(),
height = this.height(), height = this.height(),
cornerRadius = this.cornerRadius(); cornerRadius = this.cornerRadius();
@ -146,7 +146,7 @@ export class Image extends Shape<ImageConfig> {
* layer.draw(); * layer.draw();
* }); * });
*/ */
static fromURL(url, callback, onError = null) { static fromURL(url: string, callback: (img: Image) => void, onError: OnErrorEventHandler = null) {
var img = Util.createImageElement(); var img = Util.createImageElement();
img.onload = function () { img.onload = function () {
var image = new Image({ var image = new Image({

View File

@ -1,6 +1,7 @@
import { Factory } from '../Factory'; import { Factory } from '../Factory';
import { Shape, ShapeConfig } from '../Shape'; import { Shape, ShapeConfig } from '../Shape';
import { Group } from '../Group'; import { Group } from '../Group';
import { Context } from '../Context';
import { ContainerConfig } from '../Container'; import { ContainerConfig } from '../Container';
import { import {
getNumberOrArrayOfNumbersValidator, getNumberOrArrayOfNumbersValidator,
@ -75,7 +76,7 @@ var ATTR_CHANGE_LIST = [
* })); * }));
*/ */
export class Label extends Group { export class Label extends Group {
constructor(config?) { constructor(config?: LabelConfig) {
super(config); super(config);
this.on('add.konva', function (evt) { this.on('add.konva', function (evt) {
this._addListeners(evt.child); this._addListeners(evt.child);
@ -198,7 +199,7 @@ export interface TagConfig extends ShapeConfig {
* @param {Number} [config.cornerRadius] * @param {Number} [config.cornerRadius]
*/ */
export class Tag extends Shape<TagConfig> { export class Tag extends Shape<TagConfig> {
_sceneFunc(context) { _sceneFunc(context: Context) {
var width = this.width(), var width = this.width(),
height = this.height(), height = this.height(),
pointerDirection = this.pointerDirection(), pointerDirection = this.pointerDirection(),

View File

@ -3,6 +3,7 @@ import { Shape, ShapeConfig } from '../Shape';
import { GetSet } from '../types'; import { GetSet } from '../types';
import { getNumberValidator } from '../Validators'; import { getNumberValidator } from '../Validators';
import { _registerNode } from '../Global'; import { _registerNode } from '../Global';
import { Context } from '../Context';
export interface RegularPolygonConfig extends ShapeConfig { export interface RegularPolygonConfig extends ShapeConfig {
sides: number; sides: number;
@ -30,7 +31,7 @@ export interface RegularPolygonConfig extends ShapeConfig {
* }); * });
*/ */
export class RegularPolygon extends Shape<RegularPolygonConfig> { export class RegularPolygon extends Shape<RegularPolygonConfig> {
_sceneFunc(context) { _sceneFunc(context: Context) {
const points = this._getPoints(); const points = this._getPoints();
context.beginPath(); context.beginPath();
@ -81,10 +82,10 @@ export class RegularPolygon extends Shape<RegularPolygonConfig> {
getHeight() { getHeight() {
return this.radius() * 2; return this.radius() * 2;
} }
setWidth(width) { setWidth(width: number) {
this.radius(width / 2); this.radius(width / 2);
} }
setHeight(height) { setHeight(height: number) {
this.radius(height / 2); this.radius(height / 2);
} }

View File

@ -3,6 +3,7 @@ import { Shape, ShapeConfig } from '../Shape';
import { GetSet } from '../types'; import { GetSet } from '../types';
import { getNumberValidator } from '../Validators'; import { getNumberValidator } from '../Validators';
import { _registerNode } from '../Global'; import { _registerNode } from '../Global';
import { Context } from '../Context';
export interface RingConfig extends ShapeConfig { export interface RingConfig extends ShapeConfig {
innerRadius: number; innerRadius: number;
@ -30,7 +31,7 @@ var PIx2 = Math.PI * 2;
* }); * });
*/ */
export class Ring extends Shape<RingConfig> { export class Ring extends Shape<RingConfig> {
_sceneFunc(context) { _sceneFunc(context: Context) {
context.beginPath(); context.beginPath();
context.arc(0, 0, this.innerRadius(), 0, PIx2, false); context.arc(0, 0, this.innerRadius(), 0, PIx2, false);
context.moveTo(this.outerRadius(), 0); context.moveTo(this.outerRadius(), 0);
@ -44,10 +45,10 @@ export class Ring extends Shape<RingConfig> {
getHeight() { getHeight() {
return this.outerRadius() * 2; return this.outerRadius() * 2;
} }
setWidth(width) { setWidth(width: number) {
this.outerRadius(width / 2); this.outerRadius(width / 2);
} }
setHeight(height) { setHeight(height: number) {
this.outerRadius(height / 2); this.outerRadius(height / 2);
} }

View File

@ -1,4 +1,5 @@
import { Factory } from '../Factory'; import { Factory } from '../Factory';
import { Context } from '../Context';
import { Shape, ShapeConfig } from '../Shape'; import { Shape, ShapeConfig } from '../Shape';
import { Animation } from '../Animation'; import { Animation } from '../Animation';
import { getNumberValidator } from '../Validators'; import { getNumberValidator } from '../Validators';
@ -65,7 +66,7 @@ export class Sprite extends Shape<SpriteConfig> {
_updated = true; _updated = true;
anim: Animation; anim: Animation;
interval: any; interval: any;
constructor(config) { constructor(config: SpriteConfig) {
super(config); super(config);
this.anim = new Animation(() => { this.anim = new Animation(() => {
// if we don't need to redraw layer we should return false // if we don't need to redraw layer we should return false
@ -90,7 +91,7 @@ export class Sprite extends Shape<SpriteConfig> {
}); });
} }
_sceneFunc(context) { _sceneFunc(context: Context) {
var anim = this.animation(), var anim = this.animation(),
index = this.frameIndex(), index = this.frameIndex(),
ix4 = index * 4, ix4 = index * 4,
@ -129,7 +130,7 @@ export class Sprite extends Shape<SpriteConfig> {
} }
} }
} }
_hitFunc(context) { _hitFunc(context: Context) {
var anim = this.animation(), var anim = this.animation(),
index = this.frameIndex(), index = this.frameIndex(),
ix4 = index * 4, ix4 = index * 4,

View File

@ -1,4 +1,5 @@
import { Factory } from '../Factory'; import { Factory } from '../Factory';
import { Context } from '../Context';
import { Shape, ShapeConfig } from '../Shape'; import { Shape, ShapeConfig } from '../Shape';
import { getNumberValidator } from '../Validators'; import { getNumberValidator } from '../Validators';
import { _registerNode } from '../Global'; import { _registerNode } from '../Global';
@ -35,7 +36,7 @@ export interface StarConfig extends ShapeConfig {
* }); * });
*/ */
export class Star extends Shape<StarConfig> { export class Star extends Shape<StarConfig> {
_sceneFunc(context) { _sceneFunc(context: Context) {
var innerRadius = this.innerRadius(), var innerRadius = this.innerRadius(),
outerRadius = this.outerRadius(), outerRadius = this.outerRadius(),
numPoints = this.numPoints(); numPoints = this.numPoints();
@ -59,10 +60,10 @@ export class Star extends Shape<StarConfig> {
getHeight() { getHeight() {
return this.outerRadius() * 2; return this.outerRadius() * 2;
} }
setWidth(width) { setWidth(width: number) {
this.outerRadius(width / 2); this.outerRadius(width / 2);
} }
setHeight(height) { setHeight(height: number) {
this.outerRadius(height / 2); this.outerRadius(height / 2);
} }

View File

@ -1,4 +1,5 @@
import { Util } from '../Util'; import { Util } from '../Util';
import { Context } from '../Context';
import { Factory } from '../Factory'; import { Factory } from '../Factory';
import { Shape, ShapeConfig } from '../Shape'; import { Shape, ShapeConfig } from '../Shape';
import { Konva } from '../Global'; import { Konva } from '../Global';
@ -92,23 +93,23 @@ function normalizeFontFamily(fontFamily: string) {
.join(', '); .join(', ');
} }
var dummyContext; var dummyContext: CanvasRenderingContext2D;
function getDummyContext() { function getDummyContext() {
if (dummyContext) { if (dummyContext) {
return dummyContext; return dummyContext;
} }
dummyContext = Util.createCanvasElement().getContext(CONTEXT_2D); dummyContext = Util.createCanvasElement().getContext(CONTEXT_2D) as CanvasRenderingContext2D;
return dummyContext; return dummyContext;
} }
function _fillFunc(context) { function _fillFunc(context: Context) {
context.fillText(this._partialText, this._partialTextX, this._partialTextY); context.fillText(this._partialText, this._partialTextX, this._partialTextY);
} }
function _strokeFunc(context) { function _strokeFunc(context: Context) {
context.strokeText(this._partialText, this._partialTextX, this._partialTextY); context.strokeText(this._partialText, this._partialTextX, this._partialTextY);
} }
function checkDefaultFill(config) { function checkDefaultFill(config: TextConfig) {
config = config || {}; config = config || {};
// set default color to black // set default color to black
@ -169,7 +170,7 @@ export class Text extends Shape<TextConfig> {
this._setTextData(); this._setTextData();
} }
_sceneFunc(context) { _sceneFunc(context: Context) {
var textArr = this.textArr, var textArr = this.textArr,
textArrLen = textArr.length; textArrLen = textArr.length;
@ -311,7 +312,7 @@ export class Text extends Shape<TextConfig> {
} }
} }
} }
_hitFunc(context) { _hitFunc(context: Context) {
var width = this.getWidth(), var width = this.getWidth(),
height = this.getHeight(); height = this.getHeight();
@ -320,7 +321,7 @@ export class Text extends Shape<TextConfig> {
context.closePath(); context.closePath();
context.fillStrokeShape(this); context.fillStrokeShape(this);
} }
setText(text) { setText(text: string) {
var str = Util._isString(text) var str = Util._isString(text)
? text ? text
: text === null || text === undefined : text === null || text === undefined
@ -390,7 +391,7 @@ export class Text extends Shape<TextConfig> {
normalizeFontFamily(this.fontFamily()) normalizeFontFamily(this.fontFamily())
); );
} }
_addTextLine(line) { _addTextLine(line: string) {
const align = this.align(); const align = this.align();
if (align === JUSTIFY) { if (align === JUSTIFY) {
line = line.trim(); line = line.trim();
@ -402,7 +403,7 @@ export class Text extends Shape<TextConfig> {
lastInParagraph: false, lastInParagraph: false,
}); });
} }
_getTextWidth(text) { _getTextWidth(text: string) {
var letterSpacing = this.letterSpacing(); var letterSpacing = this.letterSpacing();
var length = text.length; var length = text.length;
return ( return (

View File

@ -1,5 +1,6 @@
import { Util } from '../Util'; import { Util } from '../Util';
import { Factory } from '../Factory'; import { Factory } from '../Factory';
import { Context } from '../Context';
import { Shape, ShapeConfig } from '../Shape'; import { Shape, ShapeConfig } from '../Shape';
import { Path } from './Path'; import { Path } from './Path';
import { Text, stringToArray } from './Text'; import { Text, stringToArray } from './Text';
@ -155,7 +156,7 @@ export class TextPath extends Shape<TextPathConfig> {
this.pathLength = this._getTextPathLength(); this.pathLength = this._getTextPathLength();
} }
_sceneFunc(context) { _sceneFunc(context: Context) {
context.setAttr('font', this._getContextFont()); context.setAttr('font', this._getContextFont());
context.setAttr('textBaseline', this.textBaseline()); context.setAttr('textBaseline', this.textBaseline());
context.setAttr('textAlign', 'left'); context.setAttr('textAlign', 'left');
@ -205,7 +206,7 @@ export class TextPath extends Shape<TextPathConfig> {
context.restore(); context.restore();
} }
_hitFunc(context) { _hitFunc(context: Context) {
context.beginPath(); context.beginPath();
var glyphInfo = this.glyphInfo; var glyphInfo = this.glyphInfo;
@ -235,7 +236,7 @@ export class TextPath extends Shape<TextPathConfig> {
); );
return this.textHeight; return this.textHeight;
} }
setText(text) { setText(text: string) {
return Text.prototype.setText.call(this, text); return Text.prototype.setText.call(this, text);
} }
@ -243,7 +244,7 @@ export class TextPath extends Shape<TextPathConfig> {
return Text.prototype._getContextFont.call(this); return Text.prototype._getContextFont.call(this);
} }
_getTextSize(text) { _getTextSize(text: string) {
var dummyCanvas = this.dummyCanvas; var dummyCanvas = this.dummyCanvas;
var _context = dummyCanvas.getContext('2d'); var _context = dummyCanvas.getContext('2d');

View File

@ -266,11 +266,11 @@ export class Transformer extends Group {
* @example * @example
* transformer.attachTo(shape); * transformer.attachTo(shape);
*/ */
attachTo(node) { attachTo(node: Node) {
this.setNode(node); this.setNode(node);
return this; return this;
} }
setNode(node) { setNode(node: Node) {
Util.warn( Util.warn(
'tr.setNode(shape), tr.node(shape) and tr.attachTo(shape) methods are deprecated. Please use tr.nodes(nodesArray) instead.' 'tr.setNode(shape), tr.node(shape) and tr.attachTo(shape) methods are deprecated. Please use tr.nodes(nodesArray) instead.'
); );
@ -288,7 +288,20 @@ export class Transformer extends Group {
if (this._nodes && this._nodes.length) { if (this._nodes && this._nodes.length) {
this.detach(); this.detach();
} }
this._nodes = nodes;
const filteredNodes = nodes.filter((node) => {
// check if ancestor of the transformer
if (node.isAncestorOf(this)) {
Util.error(
'Konva.Transformer cannot be an a child of the node you are trying to attach'
);
return false;
}
return true;
});
this._nodes = nodes = filteredNodes;
if (nodes.length === 1 && this.useSingleNodeRotation()) { if (nodes.length === 1 && this.useSingleNodeRotation()) {
this.rotation(nodes[0].getAbsoluteRotation()); this.rotation(nodes[0].getAbsoluteRotation());
} else { } else {
@ -395,6 +408,19 @@ export class Transformer extends Group {
this._nodes = []; this._nodes = [];
this._resetTransformCache(); this._resetTransformCache();
} }
/**
* bind events to the Transformer. You can use events: `transform`, `transformstart`, `transformend`, `dragstart`, `dragmove`, `dragend`
* @method
* @name Konva.Transformer#on
* @param {String} evtStr e.g. 'transform'
* @param {Function} handler The handler function. The first argument of that function is event object. Event object has `target` as main target of the event, `currentTarget` as current node listener and `evt` as native browser event.
* @returns {Konva.Transformer}
* @example
* // add click listener
* tr.on('transformstart', function() {
* console.log('transform started');
* });
*/
_resetTransformCache() { _resetTransformCache() {
this._clearCache(NODES_RECT); this._clearCache(NODES_RECT);
this._clearCache('transform'); this._clearCache('transform');

View File

@ -1,4 +1,5 @@
import { Factory } from '../Factory'; import { Factory } from '../Factory';
import { Context } from '../Context';
import { Shape, ShapeConfig } from '../Shape'; import { Shape, ShapeConfig } from '../Shape';
import { Konva } from '../Global'; import { Konva } from '../Global';
import { getNumberValidator } from '../Validators'; import { getNumberValidator } from '../Validators';
@ -35,7 +36,7 @@ export interface WedgeConfig extends ShapeConfig {
* }); * });
*/ */
export class Wedge extends Shape<WedgeConfig> { export class Wedge extends Shape<WedgeConfig> {
_sceneFunc(context) { _sceneFunc(context: Context) {
context.beginPath(); context.beginPath();
context.arc( context.arc(
0, 0,
@ -55,10 +56,10 @@ export class Wedge extends Shape<WedgeConfig> {
getHeight() { getHeight() {
return this.radius() * 2; return this.radius() * 2;
} }
setWidth(width) { setWidth(width: number) {
this.radius(width / 2); this.radius(width / 2);
} }
setHeight(height) { setHeight(height: number) {
this.radius(height / 2); this.radius(height / 2);
} }

View File

@ -1750,7 +1750,7 @@ describe('MouseEvents', function () {
assert.equal(shape, circle); assert.equal(shape, circle);
}); });
it('double click after click should trigger event', function (done) { it('double click after click should trigger event', function () {
var stage = addStage(); var stage = addStage();
var layer = new Konva.Layer(); var layer = new Konva.Layer();
stage.add(layer); stage.add(layer);
@ -1802,37 +1802,31 @@ describe('MouseEvents', function () {
assert.equal(smallClicks, 0, 'no click on small rect'); assert.equal(smallClicks, 0, 'no click on small rect');
assert.equal(smallDblClicks, 0, 'no dblclick on small rect'); assert.equal(smallDblClicks, 0, 'no dblclick on small rect');
setTimeout(function () { simulateMouseDown(stage, {
simulateMouseDown(stage, { x: 100,
x: 100, y: 100,
y: 100,
});
simulateMouseUp(stage, {
x: 100,
y: 100,
});
assert.equal(bigClicks, 1, 'single click on big rect');
assert.equal(smallClicks, 1, 'single click on small rect');
assert.equal(smallDblClicks, 0, 'no dblclick on small rect');
setTimeout(function () {
simulateMouseDown(stage, {
x: 100,
y: 100,
});
simulateMouseUp(stage, {
x: 100,
y: 100,
});
assert.equal(bigClicks, 1, 'single click on big rect');
assert.equal(smallClicks, 2, 'second click on small rect');
assert.equal(smallDblClicks, 1, 'single dblclick on small rect');
done();
});
}); });
simulateMouseUp(stage, {
x: 100,
y: 100,
});
assert.equal(bigClicks, 1, 'single click on big rect');
assert.equal(smallClicks, 1, 'single click on small rect');
assert.equal(smallDblClicks, 0, 'no dblclick on small rect');
simulateMouseDown(stage, {
x: 100,
y: 100,
});
simulateMouseUp(stage, {
x: 100,
y: 100,
});
assert.equal(bigClicks, 1, 'single click on big rect');
assert.equal(smallClicks, 2, 'second click on small rect');
assert.equal(smallDblClicks, 1, 'single dblclick on small rect');
}); });
it('click on stage and second click on shape should not trigger double click (check after dblclick)', function (done) { it('click on stage and second click on shape should not trigger double click (check after dblclick)', function (done) {

View File

@ -667,15 +667,12 @@ describe('Text', function () {
stage.add(layer); stage.add(layer);
let trace = if (Konva.isBrowser) {
'clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);font=normal normal 30px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=black;fillText(Y,0,15);fillStyle=black;fillText(O,20,15);fillStyle=black;fillText(U,43,15);fillStyle=black;fillText( ,65,15);fillStyle=black;fillText(A,73,15);fillStyle=black;fillText(R,93,15);fillStyle=black;fillText(E,115,15);fillStyle=black;fillText( ,135,15);fillStyle=black;fillText(I,143,15);fillStyle=black;fillText(N,151,15);fillStyle=black;fillText(V,173,15);fillStyle=black;fillText(I,193,15);fillStyle=black;fillText(T,201,15);fillStyle=black;fillText(E,220,15);fillStyle=black;fillText(D,240,15);fillStyle=black;fillText(!,261,15);restore();restore();'; var trace =
'clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);font=normal normal 30px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=black;fillText(Y,0,15);fillStyle=black;fillText(O,20,15);fillStyle=black;fillText(U,43,15);fillStyle=black;fillText( ,65,15);fillStyle=black;fillText(A,73,15);fillStyle=black;fillText(R,93,15);fillStyle=black;fillText(E,115,15);fillStyle=black;fillText( ,135,15);fillStyle=black;fillText(I,143,15);fillStyle=black;fillText(N,151,15);fillStyle=black;fillText(V,173,15);fillStyle=black;fillText(I,193,15);fillStyle=black;fillText(T,201,15);fillStyle=black;fillText(E,220,15);fillStyle=black;fillText(D,240,15);fillStyle=black;fillText(!,261,15);restore();restore();';
if (!isBrowser) { assert.equal(layer.getContext().getTrace(false, true), trace);
trace =
'clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);font=normal normal 30px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=black;fillText(Y,0,15);fillStyle=black;fillText(O,20,15);fillStyle=black;fillText(U,43,15);fillStyle=black;fillText( ,65,15);fillStyle=black;fillText(A,73,15);fillStyle=black;fillText(R,93,15);fillStyle=black;fillText(E,115,15);fillStyle=black;fillText( ,135,15);fillStyle=black;fillText(I,143,15);fillStyle=black;fillText(N,151,15);fillStyle=black;fillText(V,173,15);fillStyle=black;fillText(I,193,15);fillStyle=black;fillText(T,201,15);fillStyle=black;fillText(E,219,15);fillStyle=black;fillText(D,239,15);fillStyle=black;fillText(!,261,15);restore();restore();';
} }
assert.equal(layer.getContext().getTrace(false, true), trace);
}); });
it('text multi line with justify align and several paragraphs', function () { it('text multi line with justify align and several paragraphs', function () {

View File

@ -4769,4 +4769,17 @@ describe('Transformer', function () {
assert.equal(clone.getChildren().length, tr.getChildren().length); assert.equal(clone.getChildren().length, tr.getChildren().length);
assert.equal(clone.nodes().length, 0); assert.equal(clone.nodes().length, 0);
}); });
it('should filter parent of the transformer', function () {
const stage = addStage();
const layer = new Konva.Layer();
stage.add(layer);
const tr = new Konva.Transformer();
layer.add(tr);
tr.nodes([layer]);
assert.equal(tr.nodes().length, 0);
});
}); });