konva
Version:
<p align="center"> <img src="https://konvajs.org/android-chrome-192x192.png" alt="Konva logo" height="180" /> </p>
1,005 lines (1,004 loc) • 38.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Transformer = void 0;
const Util_1 = require("../Util");
const Factory_1 = require("../Factory");
const Node_1 = require("../Node");
const Shape_1 = require("../Shape");
const Rect_1 = require("./Rect");
const Group_1 = require("../Group");
const Global_1 = require("../Global");
const Validators_1 = require("../Validators");
const Global_2 = require("../Global");
var EVENTS_NAME = 'tr-konva';
var ATTR_CHANGE_LIST = [
'resizeEnabledChange',
'rotateAnchorOffsetChange',
'rotateEnabledChange',
'enabledAnchorsChange',
'anchorSizeChange',
'borderEnabledChange',
'borderStrokeChange',
'borderStrokeWidthChange',
'borderDashChange',
'anchorStrokeChange',
'anchorStrokeWidthChange',
'anchorFillChange',
'anchorCornerRadiusChange',
'ignoreStrokeChange',
'anchorStyleFuncChange',
]
.map((e) => e + `.${EVENTS_NAME}`)
.join(' ');
var NODES_RECT = 'nodesRect';
var TRANSFORM_CHANGE_STR = [
'widthChange',
'heightChange',
'scaleXChange',
'scaleYChange',
'skewXChange',
'skewYChange',
'rotationChange',
'offsetXChange',
'offsetYChange',
'transformsEnabledChange',
'strokeWidthChange',
];
var ANGLES = {
'top-left': -45,
'top-center': 0,
'top-right': 45,
'middle-right': -90,
'middle-left': 90,
'bottom-left': -135,
'bottom-center': 180,
'bottom-right': 135,
};
const TOUCH_DEVICE = 'ontouchstart' in Global_1.Konva._global;
function getCursor(anchorName, rad, rotateCursor) {
if (anchorName === 'rotater') {
return rotateCursor;
}
rad += Util_1.Util.degToRad(ANGLES[anchorName] || 0);
var angle = ((Util_1.Util.radToDeg(rad) % 360) + 360) % 360;
if (Util_1.Util._inRange(angle, 315 + 22.5, 360) || Util_1.Util._inRange(angle, 0, 22.5)) {
return 'ns-resize';
}
else if (Util_1.Util._inRange(angle, 45 - 22.5, 45 + 22.5)) {
return 'nesw-resize';
}
else if (Util_1.Util._inRange(angle, 90 - 22.5, 90 + 22.5)) {
return 'ew-resize';
}
else if (Util_1.Util._inRange(angle, 135 - 22.5, 135 + 22.5)) {
return 'nwse-resize';
}
else if (Util_1.Util._inRange(angle, 180 - 22.5, 180 + 22.5)) {
return 'ns-resize';
}
else if (Util_1.Util._inRange(angle, 225 - 22.5, 225 + 22.5)) {
return 'nesw-resize';
}
else if (Util_1.Util._inRange(angle, 270 - 22.5, 270 + 22.5)) {
return 'ew-resize';
}
else if (Util_1.Util._inRange(angle, 315 - 22.5, 315 + 22.5)) {
return 'nwse-resize';
}
else {
Util_1.Util.error('Transformer has unknown angle for cursor detection: ' + angle);
return 'pointer';
}
}
var ANCHORS_NAMES = [
'top-left',
'top-center',
'top-right',
'middle-right',
'middle-left',
'bottom-left',
'bottom-center',
'bottom-right',
];
var MAX_SAFE_INTEGER = 100000000;
function getCenter(shape) {
return {
x: shape.x +
(shape.width / 2) * Math.cos(shape.rotation) +
(shape.height / 2) * Math.sin(-shape.rotation),
y: shape.y +
(shape.height / 2) * Math.cos(shape.rotation) +
(shape.width / 2) * Math.sin(shape.rotation),
};
}
function rotateAroundPoint(shape, angleRad, point) {
const x = point.x +
(shape.x - point.x) * Math.cos(angleRad) -
(shape.y - point.y) * Math.sin(angleRad);
const y = point.y +
(shape.x - point.x) * Math.sin(angleRad) +
(shape.y - point.y) * Math.cos(angleRad);
return {
...shape,
rotation: shape.rotation + angleRad,
x,
y,
};
}
function rotateAroundCenter(shape, deltaRad) {
const center = getCenter(shape);
return rotateAroundPoint(shape, deltaRad, center);
}
function getSnap(snaps, newRotationRad, tol) {
let snapped = newRotationRad;
for (let i = 0; i < snaps.length; i++) {
const angle = Global_1.Konva.getAngle(snaps[i]);
const absDiff = Math.abs(angle - newRotationRad) % (Math.PI * 2);
const dif = Math.min(absDiff, Math.PI * 2 - absDiff);
if (dif < tol) {
snapped = angle;
}
}
return snapped;
}
let activeTransformersCount = 0;
class Transformer extends Group_1.Group {
constructor(config) {
super(config);
this._movingAnchorName = null;
this._transforming = false;
this._createElements();
this._handleMouseMove = this._handleMouseMove.bind(this);
this._handleMouseUp = this._handleMouseUp.bind(this);
this.update = this.update.bind(this);
this.on(ATTR_CHANGE_LIST, this.update);
if (this.getNode()) {
this.update();
}
}
attachTo(node) {
this.setNode(node);
return this;
}
setNode(node) {
Util_1.Util.warn('tr.setNode(shape), tr.node(shape) and tr.attachTo(shape) methods are deprecated. Please use tr.nodes(nodesArray) instead.');
return this.setNodes([node]);
}
getNode() {
return this._nodes && this._nodes[0];
}
_getEventNamespace() {
return EVENTS_NAME + this._id;
}
setNodes(nodes = []) {
if (this._nodes && this._nodes.length) {
this.detach();
}
const filteredNodes = nodes.filter((node) => {
if (node.isAncestorOf(this)) {
Util_1.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()) {
this.rotation(nodes[0].getAbsoluteRotation());
}
else {
this.rotation(0);
}
this._nodes.forEach((node) => {
const onChange = () => {
if (this.nodes().length === 1 && this.useSingleNodeRotation()) {
this.rotation(this.nodes()[0].getAbsoluteRotation());
}
this._resetTransformCache();
if (!this._transforming && !this.isDragging()) {
this.update();
}
};
const additionalEvents = node._attrsAffectingSize
.map((prop) => prop + 'Change.' + this._getEventNamespace())
.join(' ');
node.on(additionalEvents, onChange);
node.on(TRANSFORM_CHANGE_STR.map((e) => e + `.${this._getEventNamespace()}`).join(' '), onChange);
node.on(`absoluteTransformChange.${this._getEventNamespace()}`, onChange);
this._proxyDrag(node);
});
this._resetTransformCache();
var elementsCreated = !!this.findOne('.top-left');
if (elementsCreated) {
this.update();
}
return this;
}
_proxyDrag(node) {
let lastPos;
node.on(`dragstart.${this._getEventNamespace()}`, (e) => {
lastPos = node.getAbsolutePosition();
if (!this.isDragging() && node !== this.findOne('.back')) {
this.startDrag(e, false);
}
});
node.on(`dragmove.${this._getEventNamespace()}`, (e) => {
if (!lastPos) {
return;
}
const abs = node.getAbsolutePosition();
const dx = abs.x - lastPos.x;
const dy = abs.y - lastPos.y;
this.nodes().forEach((otherNode) => {
if (otherNode === node) {
return;
}
if (otherNode.isDragging()) {
return;
}
const otherAbs = otherNode.getAbsolutePosition();
otherNode.setAbsolutePosition({
x: otherAbs.x + dx,
y: otherAbs.y + dy,
});
otherNode.startDrag(e);
});
lastPos = null;
});
}
getNodes() {
return this._nodes || [];
}
getActiveAnchor() {
return this._movingAnchorName;
}
detach() {
if (this._nodes) {
this._nodes.forEach((node) => {
node.off('.' + this._getEventNamespace());
});
}
this._nodes = [];
this._resetTransformCache();
}
_resetTransformCache() {
this._clearCache(NODES_RECT);
this._clearCache('transform');
this._clearSelfAndDescendantCache('absoluteTransform');
}
_getNodeRect() {
return this._getCache(NODES_RECT, this.__getNodeRect);
}
__getNodeShape(node, rot = this.rotation(), relative) {
var rect = node.getClientRect({
skipTransform: true,
skipShadow: true,
skipStroke: this.ignoreStroke(),
});
var absScale = node.getAbsoluteScale(relative);
var absPos = node.getAbsolutePosition(relative);
var dx = rect.x * absScale.x - node.offsetX() * absScale.x;
var dy = rect.y * absScale.y - node.offsetY() * absScale.y;
const rotation = (Global_1.Konva.getAngle(node.getAbsoluteRotation()) + Math.PI * 2) %
(Math.PI * 2);
const box = {
x: absPos.x + dx * Math.cos(rotation) + dy * Math.sin(-rotation),
y: absPos.y + dy * Math.cos(rotation) + dx * Math.sin(rotation),
width: rect.width * absScale.x,
height: rect.height * absScale.y,
rotation: rotation,
};
return rotateAroundPoint(box, -Global_1.Konva.getAngle(rot), {
x: 0,
y: 0,
});
}
__getNodeRect() {
var node = this.getNode();
if (!node) {
return {
x: -MAX_SAFE_INTEGER,
y: -MAX_SAFE_INTEGER,
width: 0,
height: 0,
rotation: 0,
};
}
const totalPoints = [];
this.nodes().map((node) => {
const box = node.getClientRect({
skipTransform: true,
skipShadow: true,
skipStroke: this.ignoreStroke(),
});
var points = [
{ x: box.x, y: box.y },
{ x: box.x + box.width, y: box.y },
{ x: box.x + box.width, y: box.y + box.height },
{ x: box.x, y: box.y + box.height },
];
var trans = node.getAbsoluteTransform();
points.forEach(function (point) {
var transformed = trans.point(point);
totalPoints.push(transformed);
});
});
const tr = new Util_1.Transform();
tr.rotate(-Global_1.Konva.getAngle(this.rotation()));
var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
totalPoints.forEach(function (point) {
var transformed = tr.point(point);
if (minX === undefined) {
minX = maxX = transformed.x;
minY = maxY = transformed.y;
}
minX = Math.min(minX, transformed.x);
minY = Math.min(minY, transformed.y);
maxX = Math.max(maxX, transformed.x);
maxY = Math.max(maxY, transformed.y);
});
tr.invert();
const p = tr.point({ x: minX, y: minY });
return {
x: p.x,
y: p.y,
width: maxX - minX,
height: maxY - minY,
rotation: Global_1.Konva.getAngle(this.rotation()),
};
}
getX() {
return this._getNodeRect().x;
}
getY() {
return this._getNodeRect().y;
}
getWidth() {
return this._getNodeRect().width;
}
getHeight() {
return this._getNodeRect().height;
}
_createElements() {
this._createBack();
ANCHORS_NAMES.forEach((name) => {
this._createAnchor(name);
});
this._createAnchor('rotater');
}
_createAnchor(name) {
var anchor = new Rect_1.Rect({
stroke: 'rgb(0, 161, 255)',
fill: 'white',
strokeWidth: 1,
name: name + ' _anchor',
dragDistance: 0,
draggable: true,
hitStrokeWidth: TOUCH_DEVICE ? 10 : 'auto',
});
var self = this;
anchor.on('mousedown touchstart', function (e) {
self._handleMouseDown(e);
});
anchor.on('dragstart', (e) => {
anchor.stopDrag();
e.cancelBubble = true;
});
anchor.on('dragend', (e) => {
e.cancelBubble = true;
});
anchor.on('mouseenter', () => {
var rad = Global_1.Konva.getAngle(this.rotation());
var rotateCursor = this.rotateAnchorCursor();
var cursor = getCursor(name, rad, rotateCursor);
anchor.getStage().content &&
(anchor.getStage().content.style.cursor = cursor);
this._cursorChange = true;
});
anchor.on('mouseout', () => {
anchor.getStage().content &&
(anchor.getStage().content.style.cursor = '');
this._cursorChange = false;
});
this.add(anchor);
}
_createBack() {
var back = new Shape_1.Shape({
name: 'back',
width: 0,
height: 0,
draggable: true,
sceneFunc(ctx, shape) {
var tr = shape.getParent();
var padding = tr.padding();
ctx.beginPath();
ctx.rect(-padding, -padding, shape.width() + padding * 2, shape.height() + padding * 2);
ctx.moveTo(shape.width() / 2, -padding);
if (tr.rotateEnabled() && tr.rotateLineVisible()) {
ctx.lineTo(shape.width() / 2, -tr.rotateAnchorOffset() * Util_1.Util._sign(shape.height()) - padding);
}
ctx.fillStrokeShape(shape);
},
hitFunc: (ctx, shape) => {
if (!this.shouldOverdrawWholeArea()) {
return;
}
var padding = this.padding();
ctx.beginPath();
ctx.rect(-padding, -padding, shape.width() + padding * 2, shape.height() + padding * 2);
ctx.fillStrokeShape(shape);
},
});
this.add(back);
this._proxyDrag(back);
back.on('dragstart', (e) => {
e.cancelBubble = true;
});
back.on('dragmove', (e) => {
e.cancelBubble = true;
});
back.on('dragend', (e) => {
e.cancelBubble = true;
});
this.on('dragmove', (e) => {
this.update();
});
}
_handleMouseDown(e) {
this._movingAnchorName = e.target.name().split(' ')[0];
var attrs = this._getNodeRect();
var width = attrs.width;
var height = attrs.height;
var hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
this.sin = Math.abs(height / hypotenuse);
this.cos = Math.abs(width / hypotenuse);
if (typeof window !== 'undefined') {
window.addEventListener('mousemove', this._handleMouseMove);
window.addEventListener('touchmove', this._handleMouseMove);
window.addEventListener('mouseup', this._handleMouseUp, true);
window.addEventListener('touchend', this._handleMouseUp, true);
}
this._transforming = true;
var ap = e.target.getAbsolutePosition();
var pos = e.target.getStage().getPointerPosition();
this._anchorDragOffset = {
x: pos.x - ap.x,
y: pos.y - ap.y,
};
activeTransformersCount++;
this._fire('transformstart', { evt: e.evt, target: this.getNode() });
this._nodes.forEach((target) => {
target._fire('transformstart', { evt: e.evt, target });
});
}
_handleMouseMove(e) {
var x, y, newHypotenuse;
var anchorNode = this.findOne('.' + this._movingAnchorName);
var stage = anchorNode.getStage();
stage.setPointersPositions(e);
const pp = stage.getPointerPosition();
let newNodePos = {
x: pp.x - this._anchorDragOffset.x,
y: pp.y - this._anchorDragOffset.y,
};
const oldAbs = anchorNode.getAbsolutePosition();
if (this.anchorDragBoundFunc()) {
newNodePos = this.anchorDragBoundFunc()(oldAbs, newNodePos, e);
}
anchorNode.setAbsolutePosition(newNodePos);
const newAbs = anchorNode.getAbsolutePosition();
if (oldAbs.x === newAbs.x && oldAbs.y === newAbs.y) {
return;
}
if (this._movingAnchorName === 'rotater') {
var attrs = this._getNodeRect();
x = anchorNode.x() - attrs.width / 2;
y = -anchorNode.y() + attrs.height / 2;
let delta = Math.atan2(-y, x) + Math.PI / 2;
if (attrs.height < 0) {
delta -= Math.PI;
}
var oldRotation = Global_1.Konva.getAngle(this.rotation());
const newRotation = oldRotation + delta;
const tol = Global_1.Konva.getAngle(this.rotationSnapTolerance());
const snappedRot = getSnap(this.rotationSnaps(), newRotation, tol);
const diff = snappedRot - attrs.rotation;
const shape = rotateAroundCenter(attrs, diff);
this._fitNodesInto(shape, e);
return;
}
var shiftBehavior = this.shiftBehavior();
var keepProportion;
if (shiftBehavior === 'inverted') {
keepProportion = this.keepRatio() && !e.shiftKey;
}
else if (shiftBehavior === 'none') {
keepProportion = this.keepRatio();
}
else {
keepProportion = this.keepRatio() || e.shiftKey;
}
var centeredScaling = this.centeredScaling() || e.altKey;
if (this._movingAnchorName === 'top-left') {
if (keepProportion) {
var comparePoint = centeredScaling
? {
x: this.width() / 2,
y: this.height() / 2,
}
: {
x: this.findOne('.bottom-right').x(),
y: this.findOne('.bottom-right').y(),
};
newHypotenuse = Math.sqrt(Math.pow(comparePoint.x - anchorNode.x(), 2) +
Math.pow(comparePoint.y - anchorNode.y(), 2));
var reverseX = this.findOne('.top-left').x() > comparePoint.x ? -1 : 1;
var reverseY = this.findOne('.top-left').y() > comparePoint.y ? -1 : 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.top-left').x(comparePoint.x - x);
this.findOne('.top-left').y(comparePoint.y - y);
}
}
else if (this._movingAnchorName === 'top-center') {
this.findOne('.top-left').y(anchorNode.y());
}
else if (this._movingAnchorName === 'top-right') {
if (keepProportion) {
var comparePoint = centeredScaling
? {
x: this.width() / 2,
y: this.height() / 2,
}
: {
x: this.findOne('.bottom-left').x(),
y: this.findOne('.bottom-left').y(),
};
newHypotenuse = Math.sqrt(Math.pow(anchorNode.x() - comparePoint.x, 2) +
Math.pow(comparePoint.y - anchorNode.y(), 2));
var reverseX = this.findOne('.top-right').x() < comparePoint.x ? -1 : 1;
var reverseY = this.findOne('.top-right').y() > comparePoint.y ? -1 : 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.top-right').x(comparePoint.x + x);
this.findOne('.top-right').y(comparePoint.y - y);
}
var pos = anchorNode.position();
this.findOne('.top-left').y(pos.y);
this.findOne('.bottom-right').x(pos.x);
}
else if (this._movingAnchorName === 'middle-left') {
this.findOne('.top-left').x(anchorNode.x());
}
else if (this._movingAnchorName === 'middle-right') {
this.findOne('.bottom-right').x(anchorNode.x());
}
else if (this._movingAnchorName === 'bottom-left') {
if (keepProportion) {
var comparePoint = centeredScaling
? {
x: this.width() / 2,
y: this.height() / 2,
}
: {
x: this.findOne('.top-right').x(),
y: this.findOne('.top-right').y(),
};
newHypotenuse = Math.sqrt(Math.pow(comparePoint.x - anchorNode.x(), 2) +
Math.pow(anchorNode.y() - comparePoint.y, 2));
var reverseX = comparePoint.x < anchorNode.x() ? -1 : 1;
var reverseY = anchorNode.y() < comparePoint.y ? -1 : 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
anchorNode.x(comparePoint.x - x);
anchorNode.y(comparePoint.y + y);
}
pos = anchorNode.position();
this.findOne('.top-left').x(pos.x);
this.findOne('.bottom-right').y(pos.y);
}
else if (this._movingAnchorName === 'bottom-center') {
this.findOne('.bottom-right').y(anchorNode.y());
}
else if (this._movingAnchorName === 'bottom-right') {
if (keepProportion) {
var comparePoint = centeredScaling
? {
x: this.width() / 2,
y: this.height() / 2,
}
: {
x: this.findOne('.top-left').x(),
y: this.findOne('.top-left').y(),
};
newHypotenuse = Math.sqrt(Math.pow(anchorNode.x() - comparePoint.x, 2) +
Math.pow(anchorNode.y() - comparePoint.y, 2));
var reverseX = this.findOne('.bottom-right').x() < comparePoint.x ? -1 : 1;
var reverseY = this.findOne('.bottom-right').y() < comparePoint.y ? -1 : 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.bottom-right').x(comparePoint.x + x);
this.findOne('.bottom-right').y(comparePoint.y + y);
}
}
else {
console.error(new Error('Wrong position argument of selection resizer: ' +
this._movingAnchorName));
}
var centeredScaling = this.centeredScaling() || e.altKey;
if (centeredScaling) {
var topLeft = this.findOne('.top-left');
var bottomRight = this.findOne('.bottom-right');
var topOffsetX = topLeft.x();
var topOffsetY = topLeft.y();
var bottomOffsetX = this.getWidth() - bottomRight.x();
var bottomOffsetY = this.getHeight() - bottomRight.y();
bottomRight.move({
x: -topOffsetX,
y: -topOffsetY,
});
topLeft.move({
x: bottomOffsetX,
y: bottomOffsetY,
});
}
var absPos = this.findOne('.top-left').getAbsolutePosition();
x = absPos.x;
y = absPos.y;
var width = this.findOne('.bottom-right').x() - this.findOne('.top-left').x();
var height = this.findOne('.bottom-right').y() - this.findOne('.top-left').y();
this._fitNodesInto({
x: x,
y: y,
width: width,
height: height,
rotation: Global_1.Konva.getAngle(this.rotation()),
}, e);
}
_handleMouseUp(e) {
this._removeEvents(e);
}
getAbsoluteTransform() {
return this.getTransform();
}
_removeEvents(e) {
var _a;
if (this._transforming) {
this._transforming = false;
if (typeof window !== 'undefined') {
window.removeEventListener('mousemove', this._handleMouseMove);
window.removeEventListener('touchmove', this._handleMouseMove);
window.removeEventListener('mouseup', this._handleMouseUp, true);
window.removeEventListener('touchend', this._handleMouseUp, true);
}
var node = this.getNode();
activeTransformersCount--;
this._fire('transformend', { evt: e, target: node });
(_a = this.getLayer()) === null || _a === void 0 ? void 0 : _a.batchDraw();
if (node) {
this._nodes.forEach((target) => {
var _a;
target._fire('transformend', { evt: e, target });
(_a = target.getLayer()) === null || _a === void 0 ? void 0 : _a.batchDraw();
});
}
this._movingAnchorName = null;
}
}
_fitNodesInto(newAttrs, evt) {
var oldAttrs = this._getNodeRect();
const minSize = 1;
if (Util_1.Util._inRange(newAttrs.width, -this.padding() * 2 - minSize, minSize)) {
this.update();
return;
}
if (Util_1.Util._inRange(newAttrs.height, -this.padding() * 2 - minSize, minSize)) {
this.update();
return;
}
var t = new Util_1.Transform();
t.rotate(Global_1.Konva.getAngle(this.rotation()));
if (this._movingAnchorName &&
newAttrs.width < 0 &&
this._movingAnchorName.indexOf('left') >= 0) {
const offset = t.point({
x: -this.padding() * 2,
y: 0,
});
newAttrs.x += offset.x;
newAttrs.y += offset.y;
newAttrs.width += this.padding() * 2;
this._movingAnchorName = this._movingAnchorName.replace('left', 'right');
this._anchorDragOffset.x -= offset.x;
this._anchorDragOffset.y -= offset.y;
}
else if (this._movingAnchorName &&
newAttrs.width < 0 &&
this._movingAnchorName.indexOf('right') >= 0) {
const offset = t.point({
x: this.padding() * 2,
y: 0,
});
this._movingAnchorName = this._movingAnchorName.replace('right', 'left');
this._anchorDragOffset.x -= offset.x;
this._anchorDragOffset.y -= offset.y;
newAttrs.width += this.padding() * 2;
}
if (this._movingAnchorName &&
newAttrs.height < 0 &&
this._movingAnchorName.indexOf('top') >= 0) {
const offset = t.point({
x: 0,
y: -this.padding() * 2,
});
newAttrs.x += offset.x;
newAttrs.y += offset.y;
this._movingAnchorName = this._movingAnchorName.replace('top', 'bottom');
this._anchorDragOffset.x -= offset.x;
this._anchorDragOffset.y -= offset.y;
newAttrs.height += this.padding() * 2;
}
else if (this._movingAnchorName &&
newAttrs.height < 0 &&
this._movingAnchorName.indexOf('bottom') >= 0) {
const offset = t.point({
x: 0,
y: this.padding() * 2,
});
this._movingAnchorName = this._movingAnchorName.replace('bottom', 'top');
this._anchorDragOffset.x -= offset.x;
this._anchorDragOffset.y -= offset.y;
newAttrs.height += this.padding() * 2;
}
if (this.boundBoxFunc()) {
const bounded = this.boundBoxFunc()(oldAttrs, newAttrs);
if (bounded) {
newAttrs = bounded;
}
else {
Util_1.Util.warn('boundBoxFunc returned falsy. You should return new bound rect from it!');
}
}
const baseSize = 10000000;
const oldTr = new Util_1.Transform();
oldTr.translate(oldAttrs.x, oldAttrs.y);
oldTr.rotate(oldAttrs.rotation);
oldTr.scale(oldAttrs.width / baseSize, oldAttrs.height / baseSize);
const newTr = new Util_1.Transform();
const newScaleX = newAttrs.width / baseSize;
const newScaleY = newAttrs.height / baseSize;
if (this.flipEnabled() === false) {
newTr.translate(newAttrs.x, newAttrs.y);
newTr.rotate(newAttrs.rotation);
newTr.translate(newAttrs.width < 0 ? newAttrs.width : 0, newAttrs.height < 0 ? newAttrs.height : 0);
newTr.scale(Math.abs(newScaleX), Math.abs(newScaleY));
}
else {
newTr.translate(newAttrs.x, newAttrs.y);
newTr.rotate(newAttrs.rotation);
newTr.scale(newScaleX, newScaleY);
}
const delta = newTr.multiply(oldTr.invert());
this._nodes.forEach((node) => {
var _a;
const parentTransform = node.getParent().getAbsoluteTransform();
const localTransform = node.getTransform().copy();
localTransform.translate(node.offsetX(), node.offsetY());
const newLocalTransform = new Util_1.Transform();
newLocalTransform
.multiply(parentTransform.copy().invert())
.multiply(delta)
.multiply(parentTransform)
.multiply(localTransform);
const attrs = newLocalTransform.decompose();
node.setAttrs(attrs);
(_a = node.getLayer()) === null || _a === void 0 ? void 0 : _a.batchDraw();
});
this.rotation(Util_1.Util._getRotation(newAttrs.rotation));
this._nodes.forEach((node) => {
this._fire('transform', { evt: evt, target: node });
node._fire('transform', { evt: evt, target: node });
});
this._resetTransformCache();
this.update();
this.getLayer().batchDraw();
}
forceUpdate() {
this._resetTransformCache();
this.update();
}
_batchChangeChild(selector, attrs) {
const anchor = this.findOne(selector);
anchor.setAttrs(attrs);
}
update() {
var _a;
var attrs = this._getNodeRect();
this.rotation(Util_1.Util._getRotation(attrs.rotation));
var width = attrs.width;
var height = attrs.height;
var enabledAnchors = this.enabledAnchors();
var resizeEnabled = this.resizeEnabled();
var padding = this.padding();
var anchorSize = this.anchorSize();
const anchors = this.find('._anchor');
anchors.forEach((node) => {
node.setAttrs({
width: anchorSize,
height: anchorSize,
offsetX: anchorSize / 2,
offsetY: anchorSize / 2,
stroke: this.anchorStroke(),
strokeWidth: this.anchorStrokeWidth(),
fill: this.anchorFill(),
cornerRadius: this.anchorCornerRadius(),
});
});
this._batchChangeChild('.top-left', {
x: 0,
y: 0,
offsetX: anchorSize / 2 + padding,
offsetY: anchorSize / 2 + padding,
visible: resizeEnabled && enabledAnchors.indexOf('top-left') >= 0,
});
this._batchChangeChild('.top-center', {
x: width / 2,
y: 0,
offsetY: anchorSize / 2 + padding,
visible: resizeEnabled && enabledAnchors.indexOf('top-center') >= 0,
});
this._batchChangeChild('.top-right', {
x: width,
y: 0,
offsetX: anchorSize / 2 - padding,
offsetY: anchorSize / 2 + padding,
visible: resizeEnabled && enabledAnchors.indexOf('top-right') >= 0,
});
this._batchChangeChild('.middle-left', {
x: 0,
y: height / 2,
offsetX: anchorSize / 2 + padding,
visible: resizeEnabled && enabledAnchors.indexOf('middle-left') >= 0,
});
this._batchChangeChild('.middle-right', {
x: width,
y: height / 2,
offsetX: anchorSize / 2 - padding,
visible: resizeEnabled && enabledAnchors.indexOf('middle-right') >= 0,
});
this._batchChangeChild('.bottom-left', {
x: 0,
y: height,
offsetX: anchorSize / 2 + padding,
offsetY: anchorSize / 2 - padding,
visible: resizeEnabled && enabledAnchors.indexOf('bottom-left') >= 0,
});
this._batchChangeChild('.bottom-center', {
x: width / 2,
y: height,
offsetY: anchorSize / 2 - padding,
visible: resizeEnabled && enabledAnchors.indexOf('bottom-center') >= 0,
});
this._batchChangeChild('.bottom-right', {
x: width,
y: height,
offsetX: anchorSize / 2 - padding,
offsetY: anchorSize / 2 - padding,
visible: resizeEnabled && enabledAnchors.indexOf('bottom-right') >= 0,
});
this._batchChangeChild('.rotater', {
x: width / 2,
y: -this.rotateAnchorOffset() * Util_1.Util._sign(height) - padding,
visible: this.rotateEnabled(),
});
this._batchChangeChild('.back', {
width: width,
height: height,
visible: this.borderEnabled(),
stroke: this.borderStroke(),
strokeWidth: this.borderStrokeWidth(),
dash: this.borderDash(),
x: 0,
y: 0,
});
const styleFunc = this.anchorStyleFunc();
if (styleFunc) {
anchors.forEach((node) => {
styleFunc(node);
});
}
(_a = this.getLayer()) === null || _a === void 0 ? void 0 : _a.batchDraw();
}
isTransforming() {
return this._transforming;
}
stopTransform() {
if (this._transforming) {
this._removeEvents();
var anchorNode = this.findOne('.' + this._movingAnchorName);
if (anchorNode) {
anchorNode.stopDrag();
}
}
}
destroy() {
if (this.getStage() && this._cursorChange) {
this.getStage().content && (this.getStage().content.style.cursor = '');
}
Group_1.Group.prototype.destroy.call(this);
this.detach();
this._removeEvents();
return this;
}
toObject() {
return Node_1.Node.prototype.toObject.call(this);
}
clone(obj) {
var node = Node_1.Node.prototype.clone.call(this, obj);
return node;
}
getClientRect() {
if (this.nodes().length > 0) {
return super.getClientRect();
}
else {
return { x: 0, y: 0, width: 0, height: 0 };
}
}
}
exports.Transformer = Transformer;
Transformer.isTransforming = () => {
return activeTransformersCount > 0;
};
function validateAnchors(val) {
if (!(val instanceof Array)) {
Util_1.Util.warn('enabledAnchors value should be an array');
}
if (val instanceof Array) {
val.forEach(function (name) {
if (ANCHORS_NAMES.indexOf(name) === -1) {
Util_1.Util.warn('Unknown anchor name: ' +
name +
'. Available names are: ' +
ANCHORS_NAMES.join(', '));
}
});
}
return val || [];
}
Transformer.prototype.className = 'Transformer';
(0, Global_2._registerNode)(Transformer);
Factory_1.Factory.addGetterSetter(Transformer, 'enabledAnchors', ANCHORS_NAMES, validateAnchors);
Factory_1.Factory.addGetterSetter(Transformer, 'flipEnabled', true, (0, Validators_1.getBooleanValidator)());
Factory_1.Factory.addGetterSetter(Transformer, 'resizeEnabled', true);
Factory_1.Factory.addGetterSetter(Transformer, 'anchorSize', 10, (0, Validators_1.getNumberValidator)());
Factory_1.Factory.addGetterSetter(Transformer, 'rotateEnabled', true);
Factory_1.Factory.addGetterSetter(Transformer, 'rotateLineVisible', true);
Factory_1.Factory.addGetterSetter(Transformer, 'rotationSnaps', []);
Factory_1.Factory.addGetterSetter(Transformer, 'rotateAnchorOffset', 50, (0, Validators_1.getNumberValidator)());
Factory_1.Factory.addGetterSetter(Transformer, 'rotateAnchorCursor', 'crosshair');
Factory_1.Factory.addGetterSetter(Transformer, 'rotationSnapTolerance', 5, (0, Validators_1.getNumberValidator)());
Factory_1.Factory.addGetterSetter(Transformer, 'borderEnabled', true);
Factory_1.Factory.addGetterSetter(Transformer, 'anchorStroke', 'rgb(0, 161, 255)');
Factory_1.Factory.addGetterSetter(Transformer, 'anchorStrokeWidth', 1, (0, Validators_1.getNumberValidator)());
Factory_1.Factory.addGetterSetter(Transformer, 'anchorFill', 'white');
Factory_1.Factory.addGetterSetter(Transformer, 'anchorCornerRadius', 0, (0, Validators_1.getNumberValidator)());
Factory_1.Factory.addGetterSetter(Transformer, 'borderStroke', 'rgb(0, 161, 255)');
Factory_1.Factory.addGetterSetter(Transformer, 'borderStrokeWidth', 1, (0, Validators_1.getNumberValidator)());
Factory_1.Factory.addGetterSetter(Transformer, 'borderDash');
Factory_1.Factory.addGetterSetter(Transformer, 'keepRatio', true);
Factory_1.Factory.addGetterSetter(Transformer, 'shiftBehavior', 'default');
Factory_1.Factory.addGetterSetter(Transformer, 'centeredScaling', false);
Factory_1.Factory.addGetterSetter(Transformer, 'ignoreStroke', false);
Factory_1.Factory.addGetterSetter(Transformer, 'padding', 0, (0, Validators_1.getNumberValidator)());
Factory_1.Factory.addGetterSetter(Transformer, 'node');
Factory_1.Factory.addGetterSetter(Transformer, 'nodes');
Factory_1.Factory.addGetterSetter(Transformer, 'boundBoxFunc');
Factory_1.Factory.addGetterSetter(Transformer, 'anchorDragBoundFunc');
Factory_1.Factory.addGetterSetter(Transformer, 'anchorStyleFunc');
Factory_1.Factory.addGetterSetter(Transformer, 'shouldOverdrawWholeArea', false);
Factory_1.Factory.addGetterSetter(Transformer, 'useSingleNodeRotation', true);
Factory_1.Factory.backCompat(Transformer, {
lineEnabled: 'borderEnabled',
rotateHandlerOffset: 'rotateAnchorOffset',
enabledHandlers: 'enabledAnchors',
});