@inditextech/weave-sdk 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sdk.cjs CHANGED
@@ -15658,6 +15658,8 @@ var WeaveContextMenuPlugin = class extends WeavePlugin {
15658
15658
  super();
15659
15659
  this.touchTimer = void 0;
15660
15660
  this.tapHold = false;
15661
+ this.contextMenuVisible = false;
15662
+ this.tapHoldTimeout = 500;
15661
15663
  const { config } = params ?? {};
15662
15664
  this.config = {
15663
15665
  xOffset: WEAVE_CONTEXT_MENU_X_OFFSET_DEFAULT,
@@ -15700,6 +15702,7 @@ var WeaveContextMenuPlugin = class extends WeavePlugin {
15700
15702
  x: containerRect.left + pointerPos.x + (this.config.xOffset ?? 4),
15701
15703
  y: containerRect.top + pointerPos.y + (this.config.yOffset ?? 4)
15702
15704
  };
15705
+ this.contextMenuVisible = true;
15703
15706
  this.instance.emitEvent("onNodeContextMenu", {
15704
15707
  selection: nodes,
15705
15708
  point,
@@ -15707,22 +15710,39 @@ var WeaveContextMenuPlugin = class extends WeavePlugin {
15707
15710
  });
15708
15711
  }
15709
15712
  }
15713
+ closeContextMenu() {
15714
+ this.contextMenuVisible = false;
15715
+ this.instance.emitEvent("onNodeContextMenu", {
15716
+ selection: [],
15717
+ point: {
15718
+ x: 0,
15719
+ y: 0
15720
+ },
15721
+ visible: false
15722
+ });
15723
+ }
15710
15724
  initEvents() {
15711
15725
  const stage = this.instance.getStage();
15712
15726
  stage.on("touchstart", (e) => {
15713
15727
  e.evt.preventDefault();
15728
+ if (e.evt instanceof TouchEvent && e.evt.touches && e.evt.touches.length > 1) {
15729
+ if (this.touchTimer) clearTimeout(this.touchTimer);
15730
+ return;
15731
+ }
15714
15732
  this.touchTimer = setTimeout(() => {
15715
15733
  this.tapHold = true;
15716
15734
  this.triggerContextMenu(e.target);
15717
- }, 500);
15735
+ }, this.tapHoldTimeout);
15718
15736
  });
15719
- stage.on("touchmove", (e) => {
15720
- e.evt.preventDefault();
15721
- this.tapHold = false;
15737
+ stage.on("touchmove", () => {
15722
15738
  if (this.touchTimer) clearTimeout(this.touchTimer);
15723
15739
  });
15724
15740
  stage.on("touchend", (e) => {
15725
15741
  e.evt.preventDefault();
15742
+ if (e.evt instanceof TouchEvent && e.evt.touches && e.evt.touches.length > 1) {
15743
+ if (this.touchTimer) clearTimeout(this.touchTimer);
15744
+ return;
15745
+ }
15726
15746
  if (this.touchTimer) clearTimeout(this.touchTimer);
15727
15747
  if (this.tapHold) this.tapHold = false;
15728
15748
  });
@@ -15748,6 +15768,9 @@ var WeaveContextMenuPlugin = class extends WeavePlugin {
15748
15768
  }
15749
15769
  });
15750
15770
  }
15771
+ isContextMenuVisible() {
15772
+ return this.contextMenuVisible;
15773
+ }
15751
15774
  isTapHold() {
15752
15775
  return this.tapHold;
15753
15776
  }
@@ -15830,6 +15853,34 @@ function stringToColor(str) {
15830
15853
  }
15831
15854
  return color;
15832
15855
  }
15856
+ function getBoundingBox(stage, nodes) {
15857
+ if (nodes.length === 0) return {
15858
+ x: 0,
15859
+ y: 0,
15860
+ width: 0,
15861
+ height: 0
15862
+ };
15863
+ let minX = Infinity;
15864
+ let minY = Infinity;
15865
+ let maxX = -Infinity;
15866
+ let maxY = -Infinity;
15867
+ for (const node of nodes) {
15868
+ let realNode = node;
15869
+ if (realNode.getAttrs().containerId) realNode = stage.findOne(`#${realNode.getAttrs().containerId}`);
15870
+ if (!realNode) continue;
15871
+ const box = node.getRealClientRect({ skipTransform: false });
15872
+ minX = Math.min(minX, box.x);
15873
+ minY = Math.min(minY, box.y);
15874
+ maxX = Math.max(maxX, box.x + box.width);
15875
+ maxY = Math.max(maxY, box.y + box.height);
15876
+ }
15877
+ return {
15878
+ x: minX,
15879
+ y: minY,
15880
+ width: maxX - minX,
15881
+ height: maxY - minY
15882
+ };
15883
+ }
15833
15884
 
15834
15885
  //#endregion
15835
15886
  //#region src/plugins/users-selection/constants.ts
@@ -15927,6 +15978,9 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
15927
15978
  const copyPastePlugin = this.instance.getPlugin("copyPasteNodes");
15928
15979
  return copyPastePlugin.isPasting();
15929
15980
  }
15981
+ isAreaSelecting() {
15982
+ return this.selecting;
15983
+ }
15930
15984
  isSelecting() {
15931
15985
  return this.instance.getActiveAction() === "selectionTool";
15932
15986
  }
@@ -16120,6 +16174,7 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16120
16174
  if (!this.initialized) return;
16121
16175
  if (!this.active) return;
16122
16176
  if (e.evt.button && e.evt.button !== 0) return;
16177
+ if (e.evt.touches && e.evt.touches.length > 1) return;
16123
16178
  const selectedGroup = this.instance.getInstanceRecursive(e.target);
16124
16179
  if (!(e.target instanceof konva.default.Stage) && !(selectedGroup && selectedGroup.getAttrs().nodeType === "frame")) return;
16125
16180
  e.evt.preventDefault();
@@ -16139,6 +16194,7 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16139
16194
  const handleMouseMove = (e) => {
16140
16195
  if (!this.initialized) return;
16141
16196
  if (!this.active) return;
16197
+ if (e.evt instanceof TouchEvent && e.evt.touches && e.evt.touches.length > 1) return;
16142
16198
  if (!this.selecting) {
16143
16199
  this.cameFromSelectingMultiple = false;
16144
16200
  return;
@@ -16159,6 +16215,9 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16159
16215
  stage.on("mouseup touchend", (e) => {
16160
16216
  if (!this.initialized) return;
16161
16217
  if (!this.active) return;
16218
+ if (e.evt instanceof TouchEvent && e.evt.touches && e.evt.touches.length > 1) return;
16219
+ const contextMenuPlugin = this.instance.getPlugin("contextMenu");
16220
+ if (contextMenuPlugin && contextMenuPlugin.isContextMenuVisible()) return;
16162
16221
  this.selecting = false;
16163
16222
  this.instance.emitEvent("onSelectionState", false);
16164
16223
  if (!this.selectionRectangle.visible()) {
@@ -16204,6 +16263,7 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16204
16263
  stage.on("click tap", (e) => {
16205
16264
  if (!this.enabled) return;
16206
16265
  const contextMenuPlugin = this.instance.getPlugin("contextMenu");
16266
+ if (contextMenuPlugin && contextMenuPlugin.isContextMenuVisible()) return;
16207
16267
  if (this.cameFromSelectingMultiple) {
16208
16268
  this.cameFromSelectingMultiple = false;
16209
16269
  return;
@@ -16546,6 +16606,9 @@ const augmentKonvaNodeClass = (config) => {
16546
16606
  ...transform
16547
16607
  };
16548
16608
  };
16609
+ konva.default.Node.prototype.getRealClientRect = function(config$1) {
16610
+ return this.getClientRect(config$1);
16611
+ };
16549
16612
  konva.default.Node.prototype.movedToContainer = function() {};
16550
16613
  konva.default.Node.prototype.updatePosition = function() {};
16551
16614
  konva.default.Node.prototype.triggerCrop = function() {};
@@ -18155,7 +18218,7 @@ var WeaveRegisterManager = class {
18155
18218
 
18156
18219
  //#endregion
18157
18220
  //#region package.json
18158
- var version = "0.28.0";
18221
+ var version = "0.29.0";
18159
18222
 
18160
18223
  //#endregion
18161
18224
  //#region src/managers/setup.ts
@@ -18364,103 +18427,55 @@ var WeaveExportManager = class {
18364
18427
  this.logger = this.instance.getChildLogger("export-manager");
18365
18428
  this.logger.debug("Export manager created");
18366
18429
  }
18367
- exportStage(options) {
18430
+ exportNodes(nodes, options) {
18368
18431
  return new Promise((resolve) => {
18369
18432
  const { format: format$2 = __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG, padding = 0, pixelRatio = 1, backgroundColor = __inditextech_weave_types.WEAVE_EXPORT_BACKGROUND_COLOR } = options;
18370
18433
  const stage = this.instance.getStage();
18371
18434
  const mainLayer = this.instance.getMainLayer();
18372
- const previousScale = stage.scaleX();
18373
- const previousX = stage.x();
18374
- const previousY = stage.y();
18375
- let background = void 0;
18435
+ const realNodes = nodes.map((node) => {
18436
+ if (node.getAttrs().nodeId) return stage.findOne(`#${node.getAttrs().nodeId}`);
18437
+ return node;
18438
+ }).filter((node) => typeof node !== "undefined");
18376
18439
  if (mainLayer) {
18377
- const box = mainLayer.getClientRect({ relativeTo: stage });
18378
- const scale = Math.min(stage.width() / (box.width + padding * 2), stage.height() / (box.height + padding * 2));
18379
- stage.setAttrs({
18380
- x: -box.x * scale + (stage.width() - box.width * scale) / 2,
18381
- y: -box.y * scale + (stage.height() - box.height * scale) / 2
18382
- });
18383
- const actScale = stage.scale();
18384
- actScale.x = scale;
18385
- actScale.y = scale;
18386
- stage.scale(actScale);
18387
- const plugins = this.instance.getPlugins();
18388
- for (const pluginId of Object.keys(plugins)) {
18389
- const pluginInstance = plugins[pluginId];
18390
- pluginInstance.onRender?.();
18391
- }
18392
- const stageClientRect = stage.getClientRect({ relativeTo: stage });
18393
- background = new konva.default.Rect({
18394
- x: stageClientRect.x,
18395
- y: stageClientRect.y,
18396
- width: stageClientRect.width,
18397
- height: stageClientRect.height,
18398
- fill: backgroundColor
18399
- });
18400
- mainLayer.add(background);
18401
- background.moveToBottom();
18402
- stage.toImage({
18403
- mimeType: format$2,
18404
- x: (mainLayer?.x() ?? 0) - padding,
18405
- y: (mainLayer?.y() ?? 0) - padding,
18406
- width: (mainLayer?.width() ?? 0) + padding * 2,
18407
- height: (mainLayer?.height() ?? 0) + padding * 2,
18408
- pixelRatio,
18409
- quality: options.quality ?? 1,
18410
- callback: (img) => {
18411
- stage.setAttrs({
18412
- x: previousX,
18413
- y: previousY,
18414
- scaleX: previousScale,
18415
- scaleY: previousScale
18416
- });
18417
- const plugins$1 = this.instance.getPlugins();
18418
- for (const pluginId of Object.keys(plugins$1)) {
18419
- const pluginInstance = plugins$1[pluginId];
18420
- pluginInstance.onRender?.();
18421
- }
18422
- background?.destroy();
18423
- resolve(img);
18424
- }
18425
- });
18426
- }
18427
- });
18428
- }
18429
- exportNode(node, options) {
18430
- return new Promise((resolve) => {
18431
- const { format: format$2 = __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG, padding = 0, pixelRatio = 1, backgroundColor = __inditextech_weave_types.WEAVE_EXPORT_BACKGROUND_COLOR } = options;
18432
- const mainLayer = this.instance.getMainLayer();
18433
- if (mainLayer) {
18434
- const clonedNode = node.clone({ id: v4_default() });
18435
- const group = new konva.default.Group({
18436
- x: clonedNode.getAbsolutePosition().x,
18437
- y: clonedNode.getAbsolutePosition().y,
18438
- visible: false
18439
- });
18440
- mainLayer.add(group);
18441
- const nodeClientRect = clonedNode.getClientRect();
18440
+ const bounds = getBoundingBox(stage, realNodes);
18441
+ const scaleX = stage.scaleX();
18442
+ const scaleY = stage.scaleY();
18443
+ const unscaledBounds = {
18444
+ x: bounds.x / scaleX,
18445
+ y: bounds.y / scaleY,
18446
+ width: bounds.width / scaleX,
18447
+ height: bounds.height / scaleY
18448
+ };
18449
+ const exportGroup = new konva.default.Group();
18442
18450
  const background = new konva.default.Rect({
18443
- x: 0,
18444
- y: 0,
18445
- width: nodeClientRect.width + 2 * padding,
18446
- height: nodeClientRect.height + 2 * padding,
18451
+ x: unscaledBounds.x - padding,
18452
+ y: unscaledBounds.y - padding,
18453
+ width: unscaledBounds.width + 2 * padding,
18454
+ height: unscaledBounds.height + 2 * padding,
18447
18455
  fill: backgroundColor
18448
18456
  });
18449
- group.add(background);
18450
- background.zIndex(0);
18451
- clonedNode.moveTo(group);
18452
- clonedNode.setPosition({
18453
- x: padding,
18454
- y: padding
18455
- });
18456
- clonedNode.zIndex(1);
18457
- group.visible(true);
18458
- group.toImage({
18457
+ exportGroup.add(background);
18458
+ for (const node of realNodes) {
18459
+ const clonedNode = node.clone({ id: v4_default() });
18460
+ const absPos = node.getAbsolutePosition();
18461
+ clonedNode.absolutePosition({
18462
+ x: absPos.x / scaleX,
18463
+ y: absPos.y / scaleY
18464
+ });
18465
+ exportGroup.add(clonedNode);
18466
+ }
18467
+ mainLayer.add(exportGroup);
18468
+ const backgroundRect = background.getClientRect();
18469
+ exportGroup.toImage({
18470
+ x: backgroundRect.x,
18471
+ y: backgroundRect.y,
18472
+ width: backgroundRect.width,
18473
+ height: backgroundRect.height,
18459
18474
  mimeType: format$2,
18460
18475
  pixelRatio,
18461
18476
  quality: options.quality ?? 1,
18462
18477
  callback: (img) => {
18463
- group?.destroy();
18478
+ exportGroup.destroy();
18464
18479
  resolve(img);
18465
18480
  }
18466
18481
  });
@@ -18829,11 +18844,8 @@ var Weave = class extends Emittery {
18829
18844
  getFonts() {
18830
18845
  return this.fontsManager.getFonts();
18831
18846
  }
18832
- async exportStage(options) {
18833
- return await this.exportManager.exportStage(options);
18834
- }
18835
- async exportNode(node, options) {
18836
- return await this.exportManager.exportNode(node, options);
18847
+ async exportNodes(nodes, options) {
18848
+ return await this.exportManager.exportNodes(nodes, options);
18837
18849
  }
18838
18850
  };
18839
18851
 
@@ -20713,6 +20725,21 @@ var WeaveFrameNode = class extends WeaveNode {
20713
20725
  draggable: false,
20714
20726
  clip: void 0
20715
20727
  });
20728
+ frame.getRealClientRect = function(config) {
20729
+ const node = frame.getStage()?.findOne(`#${`${id}-selector-area`}`);
20730
+ const nodeTitle = frame.getStage()?.findOne(`#${`${id}-title`}`);
20731
+ if (!node || !nodeTitle) return {
20732
+ x: 0,
20733
+ y: 0,
20734
+ width: 0,
20735
+ height: 0
20736
+ };
20737
+ const rectContainer = node.getClientRect(config);
20738
+ const rectTitle = nodeTitle.getClientRect(config);
20739
+ rectContainer.y = rectContainer.y - rectTitle.height - titleMargin;
20740
+ rectContainer.height = rectContainer.height + rectTitle.height + titleMargin;
20741
+ return rectContainer;
20742
+ };
20716
20743
  this.setupDefaultNodeAugmentation(frame);
20717
20744
  const frameInternalGroup = new konva.default.Group({
20718
20745
  id: `${id}-selector`,
@@ -21004,6 +21031,1672 @@ const WEAVE_STAGE_ZOOM_DEFAULT_CONFIG = {
21004
21031
  fitToSelection: { padding: 40 }
21005
21032
  };
21006
21033
 
21034
+ //#endregion
21035
+ //#region ../../node_modules/hammerjs/hammer.js
21036
+ var require_hammer = __commonJS({ "../../node_modules/hammerjs/hammer.js"(exports, module) {
21037
+ /*! Hammer.JS - v2.0.7 - 2016-04-22
21038
+ * http://hammerjs.github.io/
21039
+ *
21040
+ * Copyright (c) 2016 Jorik Tangelder;
21041
+ * Licensed under the MIT license */
21042
+ (function(window$1, document$1, exportName, undefined$1) {
21043
+ "use strict";
21044
+ var VENDOR_PREFIXES = [
21045
+ "",
21046
+ "webkit",
21047
+ "Moz",
21048
+ "MS",
21049
+ "ms",
21050
+ "o"
21051
+ ];
21052
+ var TEST_ELEMENT = document$1.createElement("div");
21053
+ var TYPE_FUNCTION = "function";
21054
+ var round = Math.round;
21055
+ var abs = Math.abs;
21056
+ var now = Date.now;
21057
+ /**
21058
+ * set a timeout with a given scope
21059
+ * @param {Function} fn
21060
+ * @param {Number} timeout
21061
+ * @param {Object} context
21062
+ * @returns {number}
21063
+ */
21064
+ function setTimeoutContext(fn, timeout, context) {
21065
+ return setTimeout(bindFn(fn, context), timeout);
21066
+ }
21067
+ /**
21068
+ * if the argument is an array, we want to execute the fn on each entry
21069
+ * if it aint an array we don't want to do a thing.
21070
+ * this is used by all the methods that accept a single and array argument.
21071
+ * @param {*|Array} arg
21072
+ * @param {String} fn
21073
+ * @param {Object} [context]
21074
+ * @returns {Boolean}
21075
+ */
21076
+ function invokeArrayArg(arg, fn, context) {
21077
+ if (Array.isArray(arg)) {
21078
+ each(arg, context[fn], context);
21079
+ return true;
21080
+ }
21081
+ return false;
21082
+ }
21083
+ /**
21084
+ * walk objects and arrays
21085
+ * @param {Object} obj
21086
+ * @param {Function} iterator
21087
+ * @param {Object} context
21088
+ */
21089
+ function each(obj, iterator$1, context) {
21090
+ var i;
21091
+ if (!obj) return;
21092
+ if (obj.forEach) obj.forEach(iterator$1, context);
21093
+ else if (obj.length !== undefined$1) {
21094
+ i = 0;
21095
+ while (i < obj.length) {
21096
+ iterator$1.call(context, obj[i], i, obj);
21097
+ i++;
21098
+ }
21099
+ } else for (i in obj) obj.hasOwnProperty(i) && iterator$1.call(context, obj[i], i, obj);
21100
+ }
21101
+ /**
21102
+ * wrap a method with a deprecation warning and stack trace
21103
+ * @param {Function} method
21104
+ * @param {String} name
21105
+ * @param {String} message
21106
+ * @returns {Function} A new function wrapping the supplied method.
21107
+ */
21108
+ function deprecate(method, name, message) {
21109
+ var deprecationMessage = "DEPRECATED METHOD: " + name + "\n" + message + " AT \n";
21110
+ return function() {
21111
+ var e = new Error("get-stack-trace");
21112
+ var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, "").replace(/^\s+at\s+/gm, "").replace(/^Object.<anonymous>\s*\(/gm, "{anonymous}()@") : "Unknown Stack Trace";
21113
+ var log = window$1.console && (window$1.console.warn || window$1.console.log);
21114
+ if (log) log.call(window$1.console, deprecationMessage, stack);
21115
+ return method.apply(this, arguments);
21116
+ };
21117
+ }
21118
+ /**
21119
+ * extend object.
21120
+ * means that properties in dest will be overwritten by the ones in src.
21121
+ * @param {Object} target
21122
+ * @param {...Object} objects_to_assign
21123
+ * @returns {Object} target
21124
+ */
21125
+ var assign;
21126
+ if (typeof Object.assign !== "function") assign = function assign$1(target) {
21127
+ if (target === undefined$1 || target === null) throw new TypeError("Cannot convert undefined or null to object");
21128
+ var output = Object(target);
21129
+ for (var index = 1; index < arguments.length; index++) {
21130
+ var source = arguments[index];
21131
+ if (source !== undefined$1 && source !== null) {
21132
+ for (var nextKey in source) if (source.hasOwnProperty(nextKey)) output[nextKey] = source[nextKey];
21133
+ }
21134
+ }
21135
+ return output;
21136
+ };
21137
+ else assign = Object.assign;
21138
+ /**
21139
+ * extend object.
21140
+ * means that properties in dest will be overwritten by the ones in src.
21141
+ * @param {Object} dest
21142
+ * @param {Object} src
21143
+ * @param {Boolean} [merge=false]
21144
+ * @returns {Object} dest
21145
+ */
21146
+ var extend = deprecate(function extend$1(dest, src, merge$1) {
21147
+ var keys = Object.keys(src);
21148
+ var i = 0;
21149
+ while (i < keys.length) {
21150
+ if (!merge$1 || merge$1 && dest[keys[i]] === undefined$1) dest[keys[i]] = src[keys[i]];
21151
+ i++;
21152
+ }
21153
+ return dest;
21154
+ }, "extend", "Use `assign`.");
21155
+ /**
21156
+ * merge the values from src in the dest.
21157
+ * means that properties that exist in dest will not be overwritten by src
21158
+ * @param {Object} dest
21159
+ * @param {Object} src
21160
+ * @returns {Object} dest
21161
+ */
21162
+ var merge = deprecate(function merge$1(dest, src) {
21163
+ return extend(dest, src, true);
21164
+ }, "merge", "Use `assign`.");
21165
+ /**
21166
+ * simple class inheritance
21167
+ * @param {Function} child
21168
+ * @param {Function} base
21169
+ * @param {Object} [properties]
21170
+ */
21171
+ function inherit(child, base, properties) {
21172
+ var baseP = base.prototype, childP;
21173
+ childP = child.prototype = Object.create(baseP);
21174
+ childP.constructor = child;
21175
+ childP._super = baseP;
21176
+ if (properties) assign(childP, properties);
21177
+ }
21178
+ /**
21179
+ * simple function bind
21180
+ * @param {Function} fn
21181
+ * @param {Object} context
21182
+ * @returns {Function}
21183
+ */
21184
+ function bindFn(fn, context) {
21185
+ return function boundFn() {
21186
+ return fn.apply(context, arguments);
21187
+ };
21188
+ }
21189
+ /**
21190
+ * let a boolean value also be a function that must return a boolean
21191
+ * this first item in args will be used as the context
21192
+ * @param {Boolean|Function} val
21193
+ * @param {Array} [args]
21194
+ * @returns {Boolean}
21195
+ */
21196
+ function boolOrFn(val, args) {
21197
+ if (typeof val == TYPE_FUNCTION) return val.apply(args ? args[0] || undefined$1 : undefined$1, args);
21198
+ return val;
21199
+ }
21200
+ /**
21201
+ * use the val2 when val1 is undefined
21202
+ * @param {*} val1
21203
+ * @param {*} val2
21204
+ * @returns {*}
21205
+ */
21206
+ function ifUndefined(val1, val2) {
21207
+ return val1 === undefined$1 ? val2 : val1;
21208
+ }
21209
+ /**
21210
+ * addEventListener with multiple events at once
21211
+ * @param {EventTarget} target
21212
+ * @param {String} types
21213
+ * @param {Function} handler
21214
+ */
21215
+ function addEventListeners(target, types, handler) {
21216
+ each(splitStr(types), function(type) {
21217
+ target.addEventListener(type, handler, false);
21218
+ });
21219
+ }
21220
+ /**
21221
+ * removeEventListener with multiple events at once
21222
+ * @param {EventTarget} target
21223
+ * @param {String} types
21224
+ * @param {Function} handler
21225
+ */
21226
+ function removeEventListeners(target, types, handler) {
21227
+ each(splitStr(types), function(type) {
21228
+ target.removeEventListener(type, handler, false);
21229
+ });
21230
+ }
21231
+ /**
21232
+ * find if a node is in the given parent
21233
+ * @method hasParent
21234
+ * @param {HTMLElement} node
21235
+ * @param {HTMLElement} parent
21236
+ * @return {Boolean} found
21237
+ */
21238
+ function hasParent(node, parent) {
21239
+ while (node) {
21240
+ if (node == parent) return true;
21241
+ node = node.parentNode;
21242
+ }
21243
+ return false;
21244
+ }
21245
+ /**
21246
+ * small indexOf wrapper
21247
+ * @param {String} str
21248
+ * @param {String} find
21249
+ * @returns {Boolean} found
21250
+ */
21251
+ function inStr(str, find) {
21252
+ return str.indexOf(find) > -1;
21253
+ }
21254
+ /**
21255
+ * split string on whitespace
21256
+ * @param {String} str
21257
+ * @returns {Array} words
21258
+ */
21259
+ function splitStr(str) {
21260
+ return str.trim().split(/\s+/g);
21261
+ }
21262
+ /**
21263
+ * find if a array contains the object using indexOf or a simple polyFill
21264
+ * @param {Array} src
21265
+ * @param {String} find
21266
+ * @param {String} [findByKey]
21267
+ * @return {Boolean|Number} false when not found, or the index
21268
+ */
21269
+ function inArray(src, find, findByKey) {
21270
+ if (src.indexOf && !findByKey) return src.indexOf(find);
21271
+ else {
21272
+ var i = 0;
21273
+ while (i < src.length) {
21274
+ if (findByKey && src[i][findByKey] == find || !findByKey && src[i] === find) return i;
21275
+ i++;
21276
+ }
21277
+ return -1;
21278
+ }
21279
+ }
21280
+ /**
21281
+ * convert array-like objects to real arrays
21282
+ * @param {Object} obj
21283
+ * @returns {Array}
21284
+ */
21285
+ function toArray(obj) {
21286
+ return Array.prototype.slice.call(obj, 0);
21287
+ }
21288
+ /**
21289
+ * unique array with objects based on a key (like 'id') or just by the array's value
21290
+ * @param {Array} src [{id:1},{id:2},{id:1}]
21291
+ * @param {String} [key]
21292
+ * @param {Boolean} [sort=False]
21293
+ * @returns {Array} [{id:1},{id:2}]
21294
+ */
21295
+ function uniqueArray(src, key, sort) {
21296
+ var results = [];
21297
+ var values = [];
21298
+ var i = 0;
21299
+ while (i < src.length) {
21300
+ var val = key ? src[i][key] : src[i];
21301
+ if (inArray(values, val) < 0) results.push(src[i]);
21302
+ values[i] = val;
21303
+ i++;
21304
+ }
21305
+ if (sort) if (!key) results = results.sort();
21306
+ else results = results.sort(function sortUniqueArray(a, b) {
21307
+ return a[key] > b[key];
21308
+ });
21309
+ return results;
21310
+ }
21311
+ /**
21312
+ * get the prefixed property
21313
+ * @param {Object} obj
21314
+ * @param {String} property
21315
+ * @returns {String|Undefined} prefixed
21316
+ */
21317
+ function prefixed(obj, property) {
21318
+ var prefix, prop;
21319
+ var camelProp = property[0].toUpperCase() + property.slice(1);
21320
+ var i = 0;
21321
+ while (i < VENDOR_PREFIXES.length) {
21322
+ prefix = VENDOR_PREFIXES[i];
21323
+ prop = prefix ? prefix + camelProp : property;
21324
+ if (prop in obj) return prop;
21325
+ i++;
21326
+ }
21327
+ return undefined$1;
21328
+ }
21329
+ /**
21330
+ * get a unique id
21331
+ * @returns {number} uniqueId
21332
+ */
21333
+ var _uniqueId = 1;
21334
+ function uniqueId() {
21335
+ return _uniqueId++;
21336
+ }
21337
+ /**
21338
+ * get the window object of an element
21339
+ * @param {HTMLElement} element
21340
+ * @returns {DocumentView|Window}
21341
+ */
21342
+ function getWindowForElement(element) {
21343
+ var doc = element.ownerDocument || element;
21344
+ return doc.defaultView || doc.parentWindow || window$1;
21345
+ }
21346
+ var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
21347
+ var SUPPORT_TOUCH = "ontouchstart" in window$1;
21348
+ var SUPPORT_POINTER_EVENTS = prefixed(window$1, "PointerEvent") !== undefined$1;
21349
+ var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
21350
+ var INPUT_TYPE_TOUCH = "touch";
21351
+ var INPUT_TYPE_PEN = "pen";
21352
+ var INPUT_TYPE_MOUSE = "mouse";
21353
+ var INPUT_TYPE_KINECT = "kinect";
21354
+ var COMPUTE_INTERVAL = 25;
21355
+ var INPUT_START = 1;
21356
+ var INPUT_MOVE = 2;
21357
+ var INPUT_END = 4;
21358
+ var INPUT_CANCEL = 8;
21359
+ var DIRECTION_NONE = 1;
21360
+ var DIRECTION_LEFT = 2;
21361
+ var DIRECTION_RIGHT = 4;
21362
+ var DIRECTION_UP = 8;
21363
+ var DIRECTION_DOWN = 16;
21364
+ var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
21365
+ var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
21366
+ var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
21367
+ var PROPS_XY = ["x", "y"];
21368
+ var PROPS_CLIENT_XY = ["clientX", "clientY"];
21369
+ /**
21370
+ * create new input type manager
21371
+ * @param {Manager} manager
21372
+ * @param {Function} callback
21373
+ * @returns {Input}
21374
+ * @constructor
21375
+ */
21376
+ function Input(manager, callback) {
21377
+ var self$1 = this;
21378
+ this.manager = manager;
21379
+ this.callback = callback;
21380
+ this.element = manager.element;
21381
+ this.target = manager.options.inputTarget;
21382
+ this.domHandler = function(ev) {
21383
+ if (boolOrFn(manager.options.enable, [manager])) self$1.handler(ev);
21384
+ };
21385
+ this.init();
21386
+ }
21387
+ Input.prototype = {
21388
+ handler: function() {},
21389
+ init: function() {
21390
+ this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
21391
+ this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
21392
+ this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
21393
+ },
21394
+ destroy: function() {
21395
+ this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
21396
+ this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
21397
+ this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
21398
+ }
21399
+ };
21400
+ /**
21401
+ * create new input type manager
21402
+ * called by the Manager constructor
21403
+ * @param {Hammer} manager
21404
+ * @returns {Input}
21405
+ */
21406
+ function createInputInstance(manager) {
21407
+ var Type;
21408
+ var inputClass = manager.options.inputClass;
21409
+ if (inputClass) Type = inputClass;
21410
+ else if (SUPPORT_POINTER_EVENTS) Type = PointerEventInput;
21411
+ else if (SUPPORT_ONLY_TOUCH) Type = TouchInput;
21412
+ else if (!SUPPORT_TOUCH) Type = MouseInput;
21413
+ else Type = TouchMouseInput;
21414
+ return new Type(manager, inputHandler);
21415
+ }
21416
+ /**
21417
+ * handle input events
21418
+ * @param {Manager} manager
21419
+ * @param {String} eventType
21420
+ * @param {Object} input
21421
+ */
21422
+ function inputHandler(manager, eventType, input) {
21423
+ var pointersLen = input.pointers.length;
21424
+ var changedPointersLen = input.changedPointers.length;
21425
+ var isFirst = eventType & INPUT_START && pointersLen - changedPointersLen === 0;
21426
+ var isFinal = eventType & (INPUT_END | INPUT_CANCEL) && pointersLen - changedPointersLen === 0;
21427
+ input.isFirst = !!isFirst;
21428
+ input.isFinal = !!isFinal;
21429
+ if (isFirst) manager.session = {};
21430
+ input.eventType = eventType;
21431
+ computeInputData(manager, input);
21432
+ manager.emit("hammer.input", input);
21433
+ manager.recognize(input);
21434
+ manager.session.prevInput = input;
21435
+ }
21436
+ /**
21437
+ * extend the data with some usable properties like scale, rotate, velocity etc
21438
+ * @param {Object} manager
21439
+ * @param {Object} input
21440
+ */
21441
+ function computeInputData(manager, input) {
21442
+ var session = manager.session;
21443
+ var pointers = input.pointers;
21444
+ var pointersLength = pointers.length;
21445
+ if (!session.firstInput) session.firstInput = simpleCloneInputData(input);
21446
+ if (pointersLength > 1 && !session.firstMultiple) session.firstMultiple = simpleCloneInputData(input);
21447
+ else if (pointersLength === 1) session.firstMultiple = false;
21448
+ var firstInput = session.firstInput;
21449
+ var firstMultiple = session.firstMultiple;
21450
+ var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
21451
+ var center = input.center = getCenter(pointers);
21452
+ input.timeStamp = now();
21453
+ input.deltaTime = input.timeStamp - firstInput.timeStamp;
21454
+ input.angle = getAngle(offsetCenter, center);
21455
+ input.distance = getDistance(offsetCenter, center);
21456
+ computeDeltaXY(session, input);
21457
+ input.offsetDirection = getDirection(input.deltaX, input.deltaY);
21458
+ var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
21459
+ input.overallVelocityX = overallVelocity.x;
21460
+ input.overallVelocityY = overallVelocity.y;
21461
+ input.overallVelocity = abs(overallVelocity.x) > abs(overallVelocity.y) ? overallVelocity.x : overallVelocity.y;
21462
+ input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
21463
+ input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
21464
+ input.maxPointers = !session.prevInput ? input.pointers.length : input.pointers.length > session.prevInput.maxPointers ? input.pointers.length : session.prevInput.maxPointers;
21465
+ computeIntervalInputData(session, input);
21466
+ var target = manager.element;
21467
+ if (hasParent(input.srcEvent.target, target)) target = input.srcEvent.target;
21468
+ input.target = target;
21469
+ }
21470
+ function computeDeltaXY(session, input) {
21471
+ var center = input.center;
21472
+ var offset = session.offsetDelta || {};
21473
+ var prevDelta = session.prevDelta || {};
21474
+ var prevInput = session.prevInput || {};
21475
+ if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
21476
+ prevDelta = session.prevDelta = {
21477
+ x: prevInput.deltaX || 0,
21478
+ y: prevInput.deltaY || 0
21479
+ };
21480
+ offset = session.offsetDelta = {
21481
+ x: center.x,
21482
+ y: center.y
21483
+ };
21484
+ }
21485
+ input.deltaX = prevDelta.x + (center.x - offset.x);
21486
+ input.deltaY = prevDelta.y + (center.y - offset.y);
21487
+ }
21488
+ /**
21489
+ * velocity is calculated every x ms
21490
+ * @param {Object} session
21491
+ * @param {Object} input
21492
+ */
21493
+ function computeIntervalInputData(session, input) {
21494
+ var last = session.lastInterval || input, deltaTime = input.timeStamp - last.timeStamp, velocity, velocityX, velocityY, direction;
21495
+ if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined$1)) {
21496
+ var deltaX = input.deltaX - last.deltaX;
21497
+ var deltaY = input.deltaY - last.deltaY;
21498
+ var v = getVelocity(deltaTime, deltaX, deltaY);
21499
+ velocityX = v.x;
21500
+ velocityY = v.y;
21501
+ velocity = abs(v.x) > abs(v.y) ? v.x : v.y;
21502
+ direction = getDirection(deltaX, deltaY);
21503
+ session.lastInterval = input;
21504
+ } else {
21505
+ velocity = last.velocity;
21506
+ velocityX = last.velocityX;
21507
+ velocityY = last.velocityY;
21508
+ direction = last.direction;
21509
+ }
21510
+ input.velocity = velocity;
21511
+ input.velocityX = velocityX;
21512
+ input.velocityY = velocityY;
21513
+ input.direction = direction;
21514
+ }
21515
+ /**
21516
+ * create a simple clone from the input used for storage of firstInput and firstMultiple
21517
+ * @param {Object} input
21518
+ * @returns {Object} clonedInputData
21519
+ */
21520
+ function simpleCloneInputData(input) {
21521
+ var pointers = [];
21522
+ var i = 0;
21523
+ while (i < input.pointers.length) {
21524
+ pointers[i] = {
21525
+ clientX: round(input.pointers[i].clientX),
21526
+ clientY: round(input.pointers[i].clientY)
21527
+ };
21528
+ i++;
21529
+ }
21530
+ return {
21531
+ timeStamp: now(),
21532
+ pointers,
21533
+ center: getCenter(pointers),
21534
+ deltaX: input.deltaX,
21535
+ deltaY: input.deltaY
21536
+ };
21537
+ }
21538
+ /**
21539
+ * get the center of all the pointers
21540
+ * @param {Array} pointers
21541
+ * @return {Object} center contains `x` and `y` properties
21542
+ */
21543
+ function getCenter(pointers) {
21544
+ var pointersLength = pointers.length;
21545
+ if (pointersLength === 1) return {
21546
+ x: round(pointers[0].clientX),
21547
+ y: round(pointers[0].clientY)
21548
+ };
21549
+ var x = 0, y = 0, i = 0;
21550
+ while (i < pointersLength) {
21551
+ x += pointers[i].clientX;
21552
+ y += pointers[i].clientY;
21553
+ i++;
21554
+ }
21555
+ return {
21556
+ x: round(x / pointersLength),
21557
+ y: round(y / pointersLength)
21558
+ };
21559
+ }
21560
+ /**
21561
+ * calculate the velocity between two points. unit is in px per ms.
21562
+ * @param {Number} deltaTime
21563
+ * @param {Number} x
21564
+ * @param {Number} y
21565
+ * @return {Object} velocity `x` and `y`
21566
+ */
21567
+ function getVelocity(deltaTime, x, y) {
21568
+ return {
21569
+ x: x / deltaTime || 0,
21570
+ y: y / deltaTime || 0
21571
+ };
21572
+ }
21573
+ /**
21574
+ * get the direction between two points
21575
+ * @param {Number} x
21576
+ * @param {Number} y
21577
+ * @return {Number} direction
21578
+ */
21579
+ function getDirection(x, y) {
21580
+ if (x === y) return DIRECTION_NONE;
21581
+ if (abs(x) >= abs(y)) return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
21582
+ return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
21583
+ }
21584
+ /**
21585
+ * calculate the absolute distance between two points
21586
+ * @param {Object} p1 {x, y}
21587
+ * @param {Object} p2 {x, y}
21588
+ * @param {Array} [props] containing x and y keys
21589
+ * @return {Number} distance
21590
+ */
21591
+ function getDistance(p1, p2, props) {
21592
+ if (!props) props = PROPS_XY;
21593
+ var x = p2[props[0]] - p1[props[0]], y = p2[props[1]] - p1[props[1]];
21594
+ return Math.sqrt(x * x + y * y);
21595
+ }
21596
+ /**
21597
+ * calculate the angle between two coordinates
21598
+ * @param {Object} p1
21599
+ * @param {Object} p2
21600
+ * @param {Array} [props] containing x and y keys
21601
+ * @return {Number} angle
21602
+ */
21603
+ function getAngle(p1, p2, props) {
21604
+ if (!props) props = PROPS_XY;
21605
+ var x = p2[props[0]] - p1[props[0]], y = p2[props[1]] - p1[props[1]];
21606
+ return Math.atan2(y, x) * 180 / Math.PI;
21607
+ }
21608
+ /**
21609
+ * calculate the rotation degrees between two pointersets
21610
+ * @param {Array} start array of pointers
21611
+ * @param {Array} end array of pointers
21612
+ * @return {Number} rotation
21613
+ */
21614
+ function getRotation(start, end) {
21615
+ return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
21616
+ }
21617
+ /**
21618
+ * calculate the scale factor between two pointersets
21619
+ * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
21620
+ * @param {Array} start array of pointers
21621
+ * @param {Array} end array of pointers
21622
+ * @return {Number} scale
21623
+ */
21624
+ function getScale(start, end) {
21625
+ return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
21626
+ }
21627
+ var MOUSE_INPUT_MAP = {
21628
+ mousedown: INPUT_START,
21629
+ mousemove: INPUT_MOVE,
21630
+ mouseup: INPUT_END
21631
+ };
21632
+ var MOUSE_ELEMENT_EVENTS = "mousedown";
21633
+ var MOUSE_WINDOW_EVENTS = "mousemove mouseup";
21634
+ /**
21635
+ * Mouse events input
21636
+ * @constructor
21637
+ * @extends Input
21638
+ */
21639
+ function MouseInput() {
21640
+ this.evEl = MOUSE_ELEMENT_EVENTS;
21641
+ this.evWin = MOUSE_WINDOW_EVENTS;
21642
+ this.pressed = false;
21643
+ Input.apply(this, arguments);
21644
+ }
21645
+ inherit(MouseInput, Input, { handler: function MEhandler(ev) {
21646
+ var eventType = MOUSE_INPUT_MAP[ev.type];
21647
+ if (eventType & INPUT_START && ev.button === 0) this.pressed = true;
21648
+ if (eventType & INPUT_MOVE && ev.which !== 1) eventType = INPUT_END;
21649
+ if (!this.pressed) return;
21650
+ if (eventType & INPUT_END) this.pressed = false;
21651
+ this.callback(this.manager, eventType, {
21652
+ pointers: [ev],
21653
+ changedPointers: [ev],
21654
+ pointerType: INPUT_TYPE_MOUSE,
21655
+ srcEvent: ev
21656
+ });
21657
+ } });
21658
+ var POINTER_INPUT_MAP = {
21659
+ pointerdown: INPUT_START,
21660
+ pointermove: INPUT_MOVE,
21661
+ pointerup: INPUT_END,
21662
+ pointercancel: INPUT_CANCEL,
21663
+ pointerout: INPUT_CANCEL
21664
+ };
21665
+ var IE10_POINTER_TYPE_ENUM = {
21666
+ 2: INPUT_TYPE_TOUCH,
21667
+ 3: INPUT_TYPE_PEN,
21668
+ 4: INPUT_TYPE_MOUSE,
21669
+ 5: INPUT_TYPE_KINECT
21670
+ };
21671
+ var POINTER_ELEMENT_EVENTS = "pointerdown";
21672
+ var POINTER_WINDOW_EVENTS = "pointermove pointerup pointercancel";
21673
+ if (window$1.MSPointerEvent && !window$1.PointerEvent) {
21674
+ POINTER_ELEMENT_EVENTS = "MSPointerDown";
21675
+ POINTER_WINDOW_EVENTS = "MSPointerMove MSPointerUp MSPointerCancel";
21676
+ }
21677
+ /**
21678
+ * Pointer events input
21679
+ * @constructor
21680
+ * @extends Input
21681
+ */
21682
+ function PointerEventInput() {
21683
+ this.evEl = POINTER_ELEMENT_EVENTS;
21684
+ this.evWin = POINTER_WINDOW_EVENTS;
21685
+ Input.apply(this, arguments);
21686
+ this.store = this.manager.session.pointerEvents = [];
21687
+ }
21688
+ inherit(PointerEventInput, Input, { handler: function PEhandler(ev) {
21689
+ var store = this.store;
21690
+ var removePointer = false;
21691
+ var eventTypeNormalized = ev.type.toLowerCase().replace("ms", "");
21692
+ var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
21693
+ var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
21694
+ var isTouch = pointerType == INPUT_TYPE_TOUCH;
21695
+ var storeIndex = inArray(store, ev.pointerId, "pointerId");
21696
+ if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
21697
+ if (storeIndex < 0) {
21698
+ store.push(ev);
21699
+ storeIndex = store.length - 1;
21700
+ }
21701
+ } else if (eventType & (INPUT_END | INPUT_CANCEL)) removePointer = true;
21702
+ if (storeIndex < 0) return;
21703
+ store[storeIndex] = ev;
21704
+ this.callback(this.manager, eventType, {
21705
+ pointers: store,
21706
+ changedPointers: [ev],
21707
+ pointerType,
21708
+ srcEvent: ev
21709
+ });
21710
+ if (removePointer) store.splice(storeIndex, 1);
21711
+ } });
21712
+ var SINGLE_TOUCH_INPUT_MAP = {
21713
+ touchstart: INPUT_START,
21714
+ touchmove: INPUT_MOVE,
21715
+ touchend: INPUT_END,
21716
+ touchcancel: INPUT_CANCEL
21717
+ };
21718
+ var SINGLE_TOUCH_TARGET_EVENTS = "touchstart";
21719
+ var SINGLE_TOUCH_WINDOW_EVENTS = "touchstart touchmove touchend touchcancel";
21720
+ /**
21721
+ * Touch events input
21722
+ * @constructor
21723
+ * @extends Input
21724
+ */
21725
+ function SingleTouchInput() {
21726
+ this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
21727
+ this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
21728
+ this.started = false;
21729
+ Input.apply(this, arguments);
21730
+ }
21731
+ inherit(SingleTouchInput, Input, { handler: function TEhandler(ev) {
21732
+ var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
21733
+ if (type === INPUT_START) this.started = true;
21734
+ if (!this.started) return;
21735
+ var touches = normalizeSingleTouches.call(this, ev, type);
21736
+ if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) this.started = false;
21737
+ this.callback(this.manager, type, {
21738
+ pointers: touches[0],
21739
+ changedPointers: touches[1],
21740
+ pointerType: INPUT_TYPE_TOUCH,
21741
+ srcEvent: ev
21742
+ });
21743
+ } });
21744
+ /**
21745
+ * @this {TouchInput}
21746
+ * @param {Object} ev
21747
+ * @param {Number} type flag
21748
+ * @returns {undefined|Array} [all, changed]
21749
+ */
21750
+ function normalizeSingleTouches(ev, type) {
21751
+ var all = toArray(ev.touches);
21752
+ var changed = toArray(ev.changedTouches);
21753
+ if (type & (INPUT_END | INPUT_CANCEL)) all = uniqueArray(all.concat(changed), "identifier", true);
21754
+ return [all, changed];
21755
+ }
21756
+ var TOUCH_INPUT_MAP = {
21757
+ touchstart: INPUT_START,
21758
+ touchmove: INPUT_MOVE,
21759
+ touchend: INPUT_END,
21760
+ touchcancel: INPUT_CANCEL
21761
+ };
21762
+ var TOUCH_TARGET_EVENTS = "touchstart touchmove touchend touchcancel";
21763
+ /**
21764
+ * Multi-user touch events input
21765
+ * @constructor
21766
+ * @extends Input
21767
+ */
21768
+ function TouchInput() {
21769
+ this.evTarget = TOUCH_TARGET_EVENTS;
21770
+ this.targetIds = {};
21771
+ Input.apply(this, arguments);
21772
+ }
21773
+ inherit(TouchInput, Input, { handler: function MTEhandler(ev) {
21774
+ var type = TOUCH_INPUT_MAP[ev.type];
21775
+ var touches = getTouches.call(this, ev, type);
21776
+ if (!touches) return;
21777
+ this.callback(this.manager, type, {
21778
+ pointers: touches[0],
21779
+ changedPointers: touches[1],
21780
+ pointerType: INPUT_TYPE_TOUCH,
21781
+ srcEvent: ev
21782
+ });
21783
+ } });
21784
+ /**
21785
+ * @this {TouchInput}
21786
+ * @param {Object} ev
21787
+ * @param {Number} type flag
21788
+ * @returns {undefined|Array} [all, changed]
21789
+ */
21790
+ function getTouches(ev, type) {
21791
+ var allTouches = toArray(ev.touches);
21792
+ var targetIds = this.targetIds;
21793
+ if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
21794
+ targetIds[allTouches[0].identifier] = true;
21795
+ return [allTouches, allTouches];
21796
+ }
21797
+ var i, targetTouches, changedTouches = toArray(ev.changedTouches), changedTargetTouches = [], target = this.target;
21798
+ targetTouches = allTouches.filter(function(touch) {
21799
+ return hasParent(touch.target, target);
21800
+ });
21801
+ if (type === INPUT_START) {
21802
+ i = 0;
21803
+ while (i < targetTouches.length) {
21804
+ targetIds[targetTouches[i].identifier] = true;
21805
+ i++;
21806
+ }
21807
+ }
21808
+ i = 0;
21809
+ while (i < changedTouches.length) {
21810
+ if (targetIds[changedTouches[i].identifier]) changedTargetTouches.push(changedTouches[i]);
21811
+ if (type & (INPUT_END | INPUT_CANCEL)) delete targetIds[changedTouches[i].identifier];
21812
+ i++;
21813
+ }
21814
+ if (!changedTargetTouches.length) return;
21815
+ return [uniqueArray(targetTouches.concat(changedTargetTouches), "identifier", true), changedTargetTouches];
21816
+ }
21817
+ /**
21818
+ * Combined touch and mouse input
21819
+ *
21820
+ * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
21821
+ * This because touch devices also emit mouse events while doing a touch.
21822
+ *
21823
+ * @constructor
21824
+ * @extends Input
21825
+ */
21826
+ var DEDUP_TIMEOUT = 2500;
21827
+ var DEDUP_DISTANCE = 25;
21828
+ function TouchMouseInput() {
21829
+ Input.apply(this, arguments);
21830
+ var handler = bindFn(this.handler, this);
21831
+ this.touch = new TouchInput(this.manager, handler);
21832
+ this.mouse = new MouseInput(this.manager, handler);
21833
+ this.primaryTouch = null;
21834
+ this.lastTouches = [];
21835
+ }
21836
+ inherit(TouchMouseInput, Input, {
21837
+ handler: function TMEhandler(manager, inputEvent, inputData) {
21838
+ var isTouch = inputData.pointerType == INPUT_TYPE_TOUCH, isMouse = inputData.pointerType == INPUT_TYPE_MOUSE;
21839
+ if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) return;
21840
+ if (isTouch) recordTouches.call(this, inputEvent, inputData);
21841
+ else if (isMouse && isSyntheticEvent.call(this, inputData)) return;
21842
+ this.callback(manager, inputEvent, inputData);
21843
+ },
21844
+ destroy: function destroy() {
21845
+ this.touch.destroy();
21846
+ this.mouse.destroy();
21847
+ }
21848
+ });
21849
+ function recordTouches(eventType, eventData) {
21850
+ if (eventType & INPUT_START) {
21851
+ this.primaryTouch = eventData.changedPointers[0].identifier;
21852
+ setLastTouch.call(this, eventData);
21853
+ } else if (eventType & (INPUT_END | INPUT_CANCEL)) setLastTouch.call(this, eventData);
21854
+ }
21855
+ function setLastTouch(eventData) {
21856
+ var touch = eventData.changedPointers[0];
21857
+ if (touch.identifier === this.primaryTouch) {
21858
+ var lastTouch = {
21859
+ x: touch.clientX,
21860
+ y: touch.clientY
21861
+ };
21862
+ this.lastTouches.push(lastTouch);
21863
+ var lts = this.lastTouches;
21864
+ var removeLastTouch = function() {
21865
+ var i = lts.indexOf(lastTouch);
21866
+ if (i > -1) lts.splice(i, 1);
21867
+ };
21868
+ setTimeout(removeLastTouch, DEDUP_TIMEOUT);
21869
+ }
21870
+ }
21871
+ function isSyntheticEvent(eventData) {
21872
+ var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY;
21873
+ for (var i = 0; i < this.lastTouches.length; i++) {
21874
+ var t = this.lastTouches[i];
21875
+ var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
21876
+ if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) return true;
21877
+ }
21878
+ return false;
21879
+ }
21880
+ var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, "touchAction");
21881
+ var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined$1;
21882
+ var TOUCH_ACTION_COMPUTE = "compute";
21883
+ var TOUCH_ACTION_AUTO = "auto";
21884
+ var TOUCH_ACTION_MANIPULATION = "manipulation";
21885
+ var TOUCH_ACTION_NONE = "none";
21886
+ var TOUCH_ACTION_PAN_X = "pan-x";
21887
+ var TOUCH_ACTION_PAN_Y = "pan-y";
21888
+ var TOUCH_ACTION_MAP = getTouchActionProps();
21889
+ /**
21890
+ * Touch Action
21891
+ * sets the touchAction property or uses the js alternative
21892
+ * @param {Manager} manager
21893
+ * @param {String} value
21894
+ * @constructor
21895
+ */
21896
+ function TouchAction(manager, value) {
21897
+ this.manager = manager;
21898
+ this.set(value);
21899
+ }
21900
+ TouchAction.prototype = {
21901
+ set: function(value) {
21902
+ if (value == TOUCH_ACTION_COMPUTE) value = this.compute();
21903
+ if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
21904
+ this.actions = value.toLowerCase().trim();
21905
+ },
21906
+ update: function() {
21907
+ this.set(this.manager.options.touchAction);
21908
+ },
21909
+ compute: function() {
21910
+ var actions = [];
21911
+ each(this.manager.recognizers, function(recognizer) {
21912
+ if (boolOrFn(recognizer.options.enable, [recognizer])) actions = actions.concat(recognizer.getTouchAction());
21913
+ });
21914
+ return cleanTouchActions(actions.join(" "));
21915
+ },
21916
+ preventDefaults: function(input) {
21917
+ var srcEvent = input.srcEvent;
21918
+ var direction = input.offsetDirection;
21919
+ if (this.manager.session.prevented) {
21920
+ srcEvent.preventDefault();
21921
+ return;
21922
+ }
21923
+ var actions = this.actions;
21924
+ var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
21925
+ var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
21926
+ var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
21927
+ if (hasNone) {
21928
+ var isTapPointer = input.pointers.length === 1;
21929
+ var isTapMovement = input.distance < 2;
21930
+ var isTapTouchTime = input.deltaTime < 250;
21931
+ if (isTapPointer && isTapMovement && isTapTouchTime) return;
21932
+ }
21933
+ if (hasPanX && hasPanY) return;
21934
+ if (hasNone || hasPanY && direction & DIRECTION_HORIZONTAL || hasPanX && direction & DIRECTION_VERTICAL) return this.preventSrc(srcEvent);
21935
+ },
21936
+ preventSrc: function(srcEvent) {
21937
+ this.manager.session.prevented = true;
21938
+ srcEvent.preventDefault();
21939
+ }
21940
+ };
21941
+ /**
21942
+ * when the touchActions are collected they are not a valid value, so we need to clean things up. *
21943
+ * @param {String} actions
21944
+ * @returns {*}
21945
+ */
21946
+ function cleanTouchActions(actions) {
21947
+ if (inStr(actions, TOUCH_ACTION_NONE)) return TOUCH_ACTION_NONE;
21948
+ var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
21949
+ var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
21950
+ if (hasPanX && hasPanY) return TOUCH_ACTION_NONE;
21951
+ if (hasPanX || hasPanY) return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
21952
+ if (inStr(actions, TOUCH_ACTION_MANIPULATION)) return TOUCH_ACTION_MANIPULATION;
21953
+ return TOUCH_ACTION_AUTO;
21954
+ }
21955
+ function getTouchActionProps() {
21956
+ if (!NATIVE_TOUCH_ACTION) return false;
21957
+ var touchMap = {};
21958
+ var cssSupports = window$1.CSS && window$1.CSS.supports;
21959
+ [
21960
+ "auto",
21961
+ "manipulation",
21962
+ "pan-y",
21963
+ "pan-x",
21964
+ "pan-x pan-y",
21965
+ "none"
21966
+ ].forEach(function(val) {
21967
+ touchMap[val] = cssSupports ? window$1.CSS.supports("touch-action", val) : true;
21968
+ });
21969
+ return touchMap;
21970
+ }
21971
+ /**
21972
+ * Recognizer flow explained; *
21973
+ * All recognizers have the initial state of POSSIBLE when a input session starts.
21974
+ * The definition of a input session is from the first input until the last input, with all it's movement in it. *
21975
+ * Example session for mouse-input: mousedown -> mousemove -> mouseup
21976
+ *
21977
+ * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
21978
+ * which determines with state it should be.
21979
+ *
21980
+ * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
21981
+ * POSSIBLE to give it another change on the next cycle.
21982
+ *
21983
+ * Possible
21984
+ * |
21985
+ * +-----+---------------+
21986
+ * | |
21987
+ * +-----+-----+ |
21988
+ * | | |
21989
+ * Failed Cancelled |
21990
+ * +-------+------+
21991
+ * | |
21992
+ * Recognized Began
21993
+ * |
21994
+ * Changed
21995
+ * |
21996
+ * Ended/Recognized
21997
+ */
21998
+ var STATE_POSSIBLE = 1;
21999
+ var STATE_BEGAN = 2;
22000
+ var STATE_CHANGED = 4;
22001
+ var STATE_ENDED = 8;
22002
+ var STATE_RECOGNIZED = STATE_ENDED;
22003
+ var STATE_CANCELLED = 16;
22004
+ var STATE_FAILED = 32;
22005
+ /**
22006
+ * Recognizer
22007
+ * Every recognizer needs to extend from this class.
22008
+ * @constructor
22009
+ * @param {Object} options
22010
+ */
22011
+ function Recognizer(options) {
22012
+ this.options = assign({}, this.defaults, options || {});
22013
+ this.id = uniqueId();
22014
+ this.manager = null;
22015
+ this.options.enable = ifUndefined(this.options.enable, true);
22016
+ this.state = STATE_POSSIBLE;
22017
+ this.simultaneous = {};
22018
+ this.requireFail = [];
22019
+ }
22020
+ Recognizer.prototype = {
22021
+ defaults: {},
22022
+ set: function(options) {
22023
+ assign(this.options, options);
22024
+ this.manager && this.manager.touchAction.update();
22025
+ return this;
22026
+ },
22027
+ recognizeWith: function(otherRecognizer) {
22028
+ if (invokeArrayArg(otherRecognizer, "recognizeWith", this)) return this;
22029
+ var simultaneous = this.simultaneous;
22030
+ otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
22031
+ if (!simultaneous[otherRecognizer.id]) {
22032
+ simultaneous[otherRecognizer.id] = otherRecognizer;
22033
+ otherRecognizer.recognizeWith(this);
22034
+ }
22035
+ return this;
22036
+ },
22037
+ dropRecognizeWith: function(otherRecognizer) {
22038
+ if (invokeArrayArg(otherRecognizer, "dropRecognizeWith", this)) return this;
22039
+ otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
22040
+ delete this.simultaneous[otherRecognizer.id];
22041
+ return this;
22042
+ },
22043
+ requireFailure: function(otherRecognizer) {
22044
+ if (invokeArrayArg(otherRecognizer, "requireFailure", this)) return this;
22045
+ var requireFail = this.requireFail;
22046
+ otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
22047
+ if (inArray(requireFail, otherRecognizer) === -1) {
22048
+ requireFail.push(otherRecognizer);
22049
+ otherRecognizer.requireFailure(this);
22050
+ }
22051
+ return this;
22052
+ },
22053
+ dropRequireFailure: function(otherRecognizer) {
22054
+ if (invokeArrayArg(otherRecognizer, "dropRequireFailure", this)) return this;
22055
+ otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
22056
+ var index = inArray(this.requireFail, otherRecognizer);
22057
+ if (index > -1) this.requireFail.splice(index, 1);
22058
+ return this;
22059
+ },
22060
+ hasRequireFailures: function() {
22061
+ return this.requireFail.length > 0;
22062
+ },
22063
+ canRecognizeWith: function(otherRecognizer) {
22064
+ return !!this.simultaneous[otherRecognizer.id];
22065
+ },
22066
+ emit: function(input) {
22067
+ var self$1 = this;
22068
+ var state = this.state;
22069
+ function emit(event) {
22070
+ self$1.manager.emit(event, input);
22071
+ }
22072
+ if (state < STATE_ENDED) emit(self$1.options.event + stateStr(state));
22073
+ emit(self$1.options.event);
22074
+ if (input.additionalEvent) emit(input.additionalEvent);
22075
+ if (state >= STATE_ENDED) emit(self$1.options.event + stateStr(state));
22076
+ },
22077
+ tryEmit: function(input) {
22078
+ if (this.canEmit()) return this.emit(input);
22079
+ this.state = STATE_FAILED;
22080
+ },
22081
+ canEmit: function() {
22082
+ var i = 0;
22083
+ while (i < this.requireFail.length) {
22084
+ if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) return false;
22085
+ i++;
22086
+ }
22087
+ return true;
22088
+ },
22089
+ recognize: function(inputData) {
22090
+ var inputDataClone = assign({}, inputData);
22091
+ if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
22092
+ this.reset();
22093
+ this.state = STATE_FAILED;
22094
+ return;
22095
+ }
22096
+ if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) this.state = STATE_POSSIBLE;
22097
+ this.state = this.process(inputDataClone);
22098
+ if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) this.tryEmit(inputDataClone);
22099
+ },
22100
+ process: function(inputData) {},
22101
+ getTouchAction: function() {},
22102
+ reset: function() {}
22103
+ };
22104
+ /**
22105
+ * get a usable string, used as event postfix
22106
+ * @param {Const} state
22107
+ * @returns {String} state
22108
+ */
22109
+ function stateStr(state) {
22110
+ if (state & STATE_CANCELLED) return "cancel";
22111
+ else if (state & STATE_ENDED) return "end";
22112
+ else if (state & STATE_CHANGED) return "move";
22113
+ else if (state & STATE_BEGAN) return "start";
22114
+ return "";
22115
+ }
22116
+ /**
22117
+ * direction cons to string
22118
+ * @param {Const} direction
22119
+ * @returns {String}
22120
+ */
22121
+ function directionStr(direction) {
22122
+ if (direction == DIRECTION_DOWN) return "down";
22123
+ else if (direction == DIRECTION_UP) return "up";
22124
+ else if (direction == DIRECTION_LEFT) return "left";
22125
+ else if (direction == DIRECTION_RIGHT) return "right";
22126
+ return "";
22127
+ }
22128
+ /**
22129
+ * get a recognizer by name if it is bound to a manager
22130
+ * @param {Recognizer|String} otherRecognizer
22131
+ * @param {Recognizer} recognizer
22132
+ * @returns {Recognizer}
22133
+ */
22134
+ function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
22135
+ var manager = recognizer.manager;
22136
+ if (manager) return manager.get(otherRecognizer);
22137
+ return otherRecognizer;
22138
+ }
22139
+ /**
22140
+ * This recognizer is just used as a base for the simple attribute recognizers.
22141
+ * @constructor
22142
+ * @extends Recognizer
22143
+ */
22144
+ function AttrRecognizer() {
22145
+ Recognizer.apply(this, arguments);
22146
+ }
22147
+ inherit(AttrRecognizer, Recognizer, {
22148
+ defaults: { pointers: 1 },
22149
+ attrTest: function(input) {
22150
+ var optionPointers = this.options.pointers;
22151
+ return optionPointers === 0 || input.pointers.length === optionPointers;
22152
+ },
22153
+ process: function(input) {
22154
+ var state = this.state;
22155
+ var eventType = input.eventType;
22156
+ var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
22157
+ var isValid = this.attrTest(input);
22158
+ if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) return state | STATE_CANCELLED;
22159
+ else if (isRecognized || isValid) {
22160
+ if (eventType & INPUT_END) return state | STATE_ENDED;
22161
+ else if (!(state & STATE_BEGAN)) return STATE_BEGAN;
22162
+ return state | STATE_CHANGED;
22163
+ }
22164
+ return STATE_FAILED;
22165
+ }
22166
+ });
22167
+ /**
22168
+ * Pan
22169
+ * Recognized when the pointer is down and moved in the allowed direction.
22170
+ * @constructor
22171
+ * @extends AttrRecognizer
22172
+ */
22173
+ function PanRecognizer() {
22174
+ AttrRecognizer.apply(this, arguments);
22175
+ this.pX = null;
22176
+ this.pY = null;
22177
+ }
22178
+ inherit(PanRecognizer, AttrRecognizer, {
22179
+ defaults: {
22180
+ event: "pan",
22181
+ threshold: 10,
22182
+ pointers: 1,
22183
+ direction: DIRECTION_ALL
22184
+ },
22185
+ getTouchAction: function() {
22186
+ var direction = this.options.direction;
22187
+ var actions = [];
22188
+ if (direction & DIRECTION_HORIZONTAL) actions.push(TOUCH_ACTION_PAN_Y);
22189
+ if (direction & DIRECTION_VERTICAL) actions.push(TOUCH_ACTION_PAN_X);
22190
+ return actions;
22191
+ },
22192
+ directionTest: function(input) {
22193
+ var options = this.options;
22194
+ var hasMoved = true;
22195
+ var distance = input.distance;
22196
+ var direction = input.direction;
22197
+ var x = input.deltaX;
22198
+ var y = input.deltaY;
22199
+ if (!(direction & options.direction)) if (options.direction & DIRECTION_HORIZONTAL) {
22200
+ direction = x === 0 ? DIRECTION_NONE : x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
22201
+ hasMoved = x != this.pX;
22202
+ distance = Math.abs(input.deltaX);
22203
+ } else {
22204
+ direction = y === 0 ? DIRECTION_NONE : y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
22205
+ hasMoved = y != this.pY;
22206
+ distance = Math.abs(input.deltaY);
22207
+ }
22208
+ input.direction = direction;
22209
+ return hasMoved && distance > options.threshold && direction & options.direction;
22210
+ },
22211
+ attrTest: function(input) {
22212
+ return AttrRecognizer.prototype.attrTest.call(this, input) && (this.state & STATE_BEGAN || !(this.state & STATE_BEGAN) && this.directionTest(input));
22213
+ },
22214
+ emit: function(input) {
22215
+ this.pX = input.deltaX;
22216
+ this.pY = input.deltaY;
22217
+ var direction = directionStr(input.direction);
22218
+ if (direction) input.additionalEvent = this.options.event + direction;
22219
+ this._super.emit.call(this, input);
22220
+ }
22221
+ });
22222
+ /**
22223
+ * Pinch
22224
+ * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
22225
+ * @constructor
22226
+ * @extends AttrRecognizer
22227
+ */
22228
+ function PinchRecognizer() {
22229
+ AttrRecognizer.apply(this, arguments);
22230
+ }
22231
+ inherit(PinchRecognizer, AttrRecognizer, {
22232
+ defaults: {
22233
+ event: "pinch",
22234
+ threshold: 0,
22235
+ pointers: 2
22236
+ },
22237
+ getTouchAction: function() {
22238
+ return [TOUCH_ACTION_NONE];
22239
+ },
22240
+ attrTest: function(input) {
22241
+ return this._super.attrTest.call(this, input) && (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
22242
+ },
22243
+ emit: function(input) {
22244
+ if (input.scale !== 1) {
22245
+ var inOut = input.scale < 1 ? "in" : "out";
22246
+ input.additionalEvent = this.options.event + inOut;
22247
+ }
22248
+ this._super.emit.call(this, input);
22249
+ }
22250
+ });
22251
+ /**
22252
+ * Press
22253
+ * Recognized when the pointer is down for x ms without any movement.
22254
+ * @constructor
22255
+ * @extends Recognizer
22256
+ */
22257
+ function PressRecognizer() {
22258
+ Recognizer.apply(this, arguments);
22259
+ this._timer = null;
22260
+ this._input = null;
22261
+ }
22262
+ inherit(PressRecognizer, Recognizer, {
22263
+ defaults: {
22264
+ event: "press",
22265
+ pointers: 1,
22266
+ time: 251,
22267
+ threshold: 9
22268
+ },
22269
+ getTouchAction: function() {
22270
+ return [TOUCH_ACTION_AUTO];
22271
+ },
22272
+ process: function(input) {
22273
+ var options = this.options;
22274
+ var validPointers = input.pointers.length === options.pointers;
22275
+ var validMovement = input.distance < options.threshold;
22276
+ var validTime = input.deltaTime > options.time;
22277
+ this._input = input;
22278
+ if (!validMovement || !validPointers || input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime) this.reset();
22279
+ else if (input.eventType & INPUT_START) {
22280
+ this.reset();
22281
+ this._timer = setTimeoutContext(function() {
22282
+ this.state = STATE_RECOGNIZED;
22283
+ this.tryEmit();
22284
+ }, options.time, this);
22285
+ } else if (input.eventType & INPUT_END) return STATE_RECOGNIZED;
22286
+ return STATE_FAILED;
22287
+ },
22288
+ reset: function() {
22289
+ clearTimeout(this._timer);
22290
+ },
22291
+ emit: function(input) {
22292
+ if (this.state !== STATE_RECOGNIZED) return;
22293
+ if (input && input.eventType & INPUT_END) this.manager.emit(this.options.event + "up", input);
22294
+ else {
22295
+ this._input.timeStamp = now();
22296
+ this.manager.emit(this.options.event, this._input);
22297
+ }
22298
+ }
22299
+ });
22300
+ /**
22301
+ * Rotate
22302
+ * Recognized when two or more pointer are moving in a circular motion.
22303
+ * @constructor
22304
+ * @extends AttrRecognizer
22305
+ */
22306
+ function RotateRecognizer() {
22307
+ AttrRecognizer.apply(this, arguments);
22308
+ }
22309
+ inherit(RotateRecognizer, AttrRecognizer, {
22310
+ defaults: {
22311
+ event: "rotate",
22312
+ threshold: 0,
22313
+ pointers: 2
22314
+ },
22315
+ getTouchAction: function() {
22316
+ return [TOUCH_ACTION_NONE];
22317
+ },
22318
+ attrTest: function(input) {
22319
+ return this._super.attrTest.call(this, input) && (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
22320
+ }
22321
+ });
22322
+ /**
22323
+ * Swipe
22324
+ * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
22325
+ * @constructor
22326
+ * @extends AttrRecognizer
22327
+ */
22328
+ function SwipeRecognizer() {
22329
+ AttrRecognizer.apply(this, arguments);
22330
+ }
22331
+ inherit(SwipeRecognizer, AttrRecognizer, {
22332
+ defaults: {
22333
+ event: "swipe",
22334
+ threshold: 10,
22335
+ velocity: .3,
22336
+ direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
22337
+ pointers: 1
22338
+ },
22339
+ getTouchAction: function() {
22340
+ return PanRecognizer.prototype.getTouchAction.call(this);
22341
+ },
22342
+ attrTest: function(input) {
22343
+ var direction = this.options.direction;
22344
+ var velocity;
22345
+ if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) velocity = input.overallVelocity;
22346
+ else if (direction & DIRECTION_HORIZONTAL) velocity = input.overallVelocityX;
22347
+ else if (direction & DIRECTION_VERTICAL) velocity = input.overallVelocityY;
22348
+ return this._super.attrTest.call(this, input) && direction & input.offsetDirection && input.distance > this.options.threshold && input.maxPointers == this.options.pointers && abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
22349
+ },
22350
+ emit: function(input) {
22351
+ var direction = directionStr(input.offsetDirection);
22352
+ if (direction) this.manager.emit(this.options.event + direction, input);
22353
+ this.manager.emit(this.options.event, input);
22354
+ }
22355
+ });
22356
+ /**
22357
+ * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
22358
+ * between the given interval and position. The delay option can be used to recognize multi-taps without firing
22359
+ * a single tap.
22360
+ *
22361
+ * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
22362
+ * multi-taps being recognized.
22363
+ * @constructor
22364
+ * @extends Recognizer
22365
+ */
22366
+ function TapRecognizer() {
22367
+ Recognizer.apply(this, arguments);
22368
+ this.pTime = false;
22369
+ this.pCenter = false;
22370
+ this._timer = null;
22371
+ this._input = null;
22372
+ this.count = 0;
22373
+ }
22374
+ inherit(TapRecognizer, Recognizer, {
22375
+ defaults: {
22376
+ event: "tap",
22377
+ pointers: 1,
22378
+ taps: 1,
22379
+ interval: 300,
22380
+ time: 250,
22381
+ threshold: 9,
22382
+ posThreshold: 10
22383
+ },
22384
+ getTouchAction: function() {
22385
+ return [TOUCH_ACTION_MANIPULATION];
22386
+ },
22387
+ process: function(input) {
22388
+ var options = this.options;
22389
+ var validPointers = input.pointers.length === options.pointers;
22390
+ var validMovement = input.distance < options.threshold;
22391
+ var validTouchTime = input.deltaTime < options.time;
22392
+ this.reset();
22393
+ if (input.eventType & INPUT_START && this.count === 0) return this.failTimeout();
22394
+ if (validMovement && validTouchTime && validPointers) {
22395
+ if (input.eventType != INPUT_END) return this.failTimeout();
22396
+ var validInterval = this.pTime ? input.timeStamp - this.pTime < options.interval : true;
22397
+ var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
22398
+ this.pTime = input.timeStamp;
22399
+ this.pCenter = input.center;
22400
+ if (!validMultiTap || !validInterval) this.count = 1;
22401
+ else this.count += 1;
22402
+ this._input = input;
22403
+ var tapCount = this.count % options.taps;
22404
+ if (tapCount === 0) if (!this.hasRequireFailures()) return STATE_RECOGNIZED;
22405
+ else {
22406
+ this._timer = setTimeoutContext(function() {
22407
+ this.state = STATE_RECOGNIZED;
22408
+ this.tryEmit();
22409
+ }, options.interval, this);
22410
+ return STATE_BEGAN;
22411
+ }
22412
+ }
22413
+ return STATE_FAILED;
22414
+ },
22415
+ failTimeout: function() {
22416
+ this._timer = setTimeoutContext(function() {
22417
+ this.state = STATE_FAILED;
22418
+ }, this.options.interval, this);
22419
+ return STATE_FAILED;
22420
+ },
22421
+ reset: function() {
22422
+ clearTimeout(this._timer);
22423
+ },
22424
+ emit: function() {
22425
+ if (this.state == STATE_RECOGNIZED) {
22426
+ this._input.tapCount = this.count;
22427
+ this.manager.emit(this.options.event, this._input);
22428
+ }
22429
+ }
22430
+ });
22431
+ /**
22432
+ * Simple way to create a manager with a default set of recognizers.
22433
+ * @param {HTMLElement} element
22434
+ * @param {Object} [options]
22435
+ * @constructor
22436
+ */
22437
+ function Hammer(element, options) {
22438
+ options = options || {};
22439
+ options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
22440
+ return new Manager(element, options);
22441
+ }
22442
+ /**
22443
+ * @const {string}
22444
+ */
22445
+ Hammer.VERSION = "2.0.7";
22446
+ /**
22447
+ * default settings
22448
+ * @namespace
22449
+ */
22450
+ Hammer.defaults = {
22451
+ domEvents: false,
22452
+ touchAction: TOUCH_ACTION_COMPUTE,
22453
+ enable: true,
22454
+ inputTarget: null,
22455
+ inputClass: null,
22456
+ preset: [
22457
+ [RotateRecognizer, { enable: false }],
22458
+ [
22459
+ PinchRecognizer,
22460
+ { enable: false },
22461
+ ["rotate"]
22462
+ ],
22463
+ [SwipeRecognizer, { direction: DIRECTION_HORIZONTAL }],
22464
+ [
22465
+ PanRecognizer,
22466
+ { direction: DIRECTION_HORIZONTAL },
22467
+ ["swipe"]
22468
+ ],
22469
+ [TapRecognizer],
22470
+ [
22471
+ TapRecognizer,
22472
+ {
22473
+ event: "doubletap",
22474
+ taps: 2
22475
+ },
22476
+ ["tap"]
22477
+ ],
22478
+ [PressRecognizer]
22479
+ ],
22480
+ cssProps: {
22481
+ userSelect: "none",
22482
+ touchSelect: "none",
22483
+ touchCallout: "none",
22484
+ contentZooming: "none",
22485
+ userDrag: "none",
22486
+ tapHighlightColor: "rgba(0,0,0,0)"
22487
+ }
22488
+ };
22489
+ var STOP = 1;
22490
+ var FORCED_STOP = 2;
22491
+ /**
22492
+ * Manager
22493
+ * @param {HTMLElement} element
22494
+ * @param {Object} [options]
22495
+ * @constructor
22496
+ */
22497
+ function Manager(element, options) {
22498
+ this.options = assign({}, Hammer.defaults, options || {});
22499
+ this.options.inputTarget = this.options.inputTarget || element;
22500
+ this.handlers = {};
22501
+ this.session = {};
22502
+ this.recognizers = [];
22503
+ this.oldCssProps = {};
22504
+ this.element = element;
22505
+ this.input = createInputInstance(this);
22506
+ this.touchAction = new TouchAction(this, this.options.touchAction);
22507
+ toggleCssProps(this, true);
22508
+ each(this.options.recognizers, function(item) {
22509
+ var recognizer = this.add(new item[0](item[1]));
22510
+ item[2] && recognizer.recognizeWith(item[2]);
22511
+ item[3] && recognizer.requireFailure(item[3]);
22512
+ }, this);
22513
+ }
22514
+ Manager.prototype = {
22515
+ set: function(options) {
22516
+ assign(this.options, options);
22517
+ if (options.touchAction) this.touchAction.update();
22518
+ if (options.inputTarget) {
22519
+ this.input.destroy();
22520
+ this.input.target = options.inputTarget;
22521
+ this.input.init();
22522
+ }
22523
+ return this;
22524
+ },
22525
+ stop: function(force) {
22526
+ this.session.stopped = force ? FORCED_STOP : STOP;
22527
+ },
22528
+ recognize: function(inputData) {
22529
+ var session = this.session;
22530
+ if (session.stopped) return;
22531
+ this.touchAction.preventDefaults(inputData);
22532
+ var recognizer;
22533
+ var recognizers = this.recognizers;
22534
+ var curRecognizer = session.curRecognizer;
22535
+ if (!curRecognizer || curRecognizer && curRecognizer.state & STATE_RECOGNIZED) curRecognizer = session.curRecognizer = null;
22536
+ var i = 0;
22537
+ while (i < recognizers.length) {
22538
+ recognizer = recognizers[i];
22539
+ if (session.stopped !== FORCED_STOP && (!curRecognizer || recognizer == curRecognizer || recognizer.canRecognizeWith(curRecognizer))) recognizer.recognize(inputData);
22540
+ else recognizer.reset();
22541
+ if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) curRecognizer = session.curRecognizer = recognizer;
22542
+ i++;
22543
+ }
22544
+ },
22545
+ get: function(recognizer) {
22546
+ if (recognizer instanceof Recognizer) return recognizer;
22547
+ var recognizers = this.recognizers;
22548
+ for (var i = 0; i < recognizers.length; i++) if (recognizers[i].options.event == recognizer) return recognizers[i];
22549
+ return null;
22550
+ },
22551
+ add: function(recognizer) {
22552
+ if (invokeArrayArg(recognizer, "add", this)) return this;
22553
+ var existing = this.get(recognizer.options.event);
22554
+ if (existing) this.remove(existing);
22555
+ this.recognizers.push(recognizer);
22556
+ recognizer.manager = this;
22557
+ this.touchAction.update();
22558
+ return recognizer;
22559
+ },
22560
+ remove: function(recognizer) {
22561
+ if (invokeArrayArg(recognizer, "remove", this)) return this;
22562
+ recognizer = this.get(recognizer);
22563
+ if (recognizer) {
22564
+ var recognizers = this.recognizers;
22565
+ var index = inArray(recognizers, recognizer);
22566
+ if (index !== -1) {
22567
+ recognizers.splice(index, 1);
22568
+ this.touchAction.update();
22569
+ }
22570
+ }
22571
+ return this;
22572
+ },
22573
+ on: function(events, handler) {
22574
+ if (events === undefined$1) return;
22575
+ if (handler === undefined$1) return;
22576
+ var handlers = this.handlers;
22577
+ each(splitStr(events), function(event) {
22578
+ handlers[event] = handlers[event] || [];
22579
+ handlers[event].push(handler);
22580
+ });
22581
+ return this;
22582
+ },
22583
+ off: function(events, handler) {
22584
+ if (events === undefined$1) return;
22585
+ var handlers = this.handlers;
22586
+ each(splitStr(events), function(event) {
22587
+ if (!handler) delete handlers[event];
22588
+ else handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
22589
+ });
22590
+ return this;
22591
+ },
22592
+ emit: function(event, data) {
22593
+ if (this.options.domEvents) triggerDomEvent(event, data);
22594
+ var handlers = this.handlers[event] && this.handlers[event].slice();
22595
+ if (!handlers || !handlers.length) return;
22596
+ data.type = event;
22597
+ data.preventDefault = function() {
22598
+ data.srcEvent.preventDefault();
22599
+ };
22600
+ var i = 0;
22601
+ while (i < handlers.length) {
22602
+ handlers[i](data);
22603
+ i++;
22604
+ }
22605
+ },
22606
+ destroy: function() {
22607
+ this.element && toggleCssProps(this, false);
22608
+ this.handlers = {};
22609
+ this.session = {};
22610
+ this.input.destroy();
22611
+ this.element = null;
22612
+ }
22613
+ };
22614
+ /**
22615
+ * add/remove the css properties as defined in manager.options.cssProps
22616
+ * @param {Manager} manager
22617
+ * @param {Boolean} add
22618
+ */
22619
+ function toggleCssProps(manager, add) {
22620
+ var element = manager.element;
22621
+ if (!element.style) return;
22622
+ var prop;
22623
+ each(manager.options.cssProps, function(value, name) {
22624
+ prop = prefixed(element.style, name);
22625
+ if (add) {
22626
+ manager.oldCssProps[prop] = element.style[prop];
22627
+ element.style[prop] = value;
22628
+ } else element.style[prop] = manager.oldCssProps[prop] || "";
22629
+ });
22630
+ if (!add) manager.oldCssProps = {};
22631
+ }
22632
+ /**
22633
+ * trigger dom event
22634
+ * @param {String} event
22635
+ * @param {Object} data
22636
+ */
22637
+ function triggerDomEvent(event, data) {
22638
+ var gestureEvent = document$1.createEvent("Event");
22639
+ gestureEvent.initEvent(event, true, true);
22640
+ gestureEvent.gesture = data;
22641
+ data.target.dispatchEvent(gestureEvent);
22642
+ }
22643
+ assign(Hammer, {
22644
+ INPUT_START,
22645
+ INPUT_MOVE,
22646
+ INPUT_END,
22647
+ INPUT_CANCEL,
22648
+ STATE_POSSIBLE,
22649
+ STATE_BEGAN,
22650
+ STATE_CHANGED,
22651
+ STATE_ENDED,
22652
+ STATE_RECOGNIZED,
22653
+ STATE_CANCELLED,
22654
+ STATE_FAILED,
22655
+ DIRECTION_NONE,
22656
+ DIRECTION_LEFT,
22657
+ DIRECTION_RIGHT,
22658
+ DIRECTION_UP,
22659
+ DIRECTION_DOWN,
22660
+ DIRECTION_HORIZONTAL,
22661
+ DIRECTION_VERTICAL,
22662
+ DIRECTION_ALL,
22663
+ Manager,
22664
+ Input,
22665
+ TouchAction,
22666
+ TouchInput,
22667
+ MouseInput,
22668
+ PointerEventInput,
22669
+ TouchMouseInput,
22670
+ SingleTouchInput,
22671
+ Recognizer,
22672
+ AttrRecognizer,
22673
+ Tap: TapRecognizer,
22674
+ Pan: PanRecognizer,
22675
+ Swipe: SwipeRecognizer,
22676
+ Pinch: PinchRecognizer,
22677
+ Rotate: RotateRecognizer,
22678
+ Press: PressRecognizer,
22679
+ on: addEventListeners,
22680
+ off: removeEventListeners,
22681
+ each,
22682
+ merge,
22683
+ extend,
22684
+ assign,
22685
+ inherit,
22686
+ bindFn,
22687
+ prefixed
22688
+ });
22689
+ var freeGlobal = typeof window$1 !== "undefined" ? window$1 : typeof self !== "undefined" ? self : {};
22690
+ freeGlobal.Hammer = Hammer;
22691
+ if (typeof define === "function" && define.amd) define(function() {
22692
+ return Hammer;
22693
+ });
22694
+ else if (typeof module != "undefined" && module.exports) module.exports = Hammer;
22695
+ else window$1[exportName] = Hammer;
22696
+ })(window, document, "Hammer");
22697
+ } });
22698
+ var import_hammer = __toESM(require_hammer(), 1);
22699
+
21007
22700
  //#endregion
21008
22701
  //#region src/plugins/stage-zoom/stage-zoom.ts
21009
22702
  var WeaveStageZoomPlugin = class extends WeavePlugin {
@@ -21165,32 +22858,29 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21165
22858
  return;
21166
22859
  }
21167
22860
  const stage = this.instance.getStage();
21168
- const box = mainLayer.getClientRect({
21169
- relativeTo: stage,
21170
- skipStroke: true
22861
+ stage.scale({
22862
+ x: 1,
22863
+ y: 1
21171
22864
  });
21172
- const stageBox = {
21173
- width: stage.width(),
21174
- height: stage.height()
21175
- };
21176
- const availableScreenWidth = stageBox.width - 2 * this.config.fitToScreen.padding;
21177
- const availableScreenHeight = stageBox.height - 2 * this.config.fitToScreen.padding;
21178
- const scaleX = availableScreenWidth / box.width;
21179
- const scaleY = availableScreenHeight / box.height;
22865
+ stage.position({
22866
+ x: 0,
22867
+ y: 0
22868
+ });
22869
+ const bounds = getBoundingBox(stage, mainLayer.getChildren());
22870
+ const stageWidth = stage.width();
22871
+ const stageHeight = stage.height();
22872
+ const scaleX = (stageWidth - this.config.fitToScreen.padding * 2) / bounds.width;
22873
+ const scaleY = (stageHeight - this.config.fitToScreen.padding * 2) / bounds.height;
21180
22874
  const scale = Math.min(scaleX, scaleY);
22875
+ const offsetX = bounds.x + bounds.width / 2;
22876
+ const offsetY = bounds.y + bounds.height / 2;
21181
22877
  stage.scale({
21182
22878
  x: scale,
21183
22879
  y: scale
21184
22880
  });
21185
- const selectionCenterX = box.x + box.width / 2;
21186
- const selectionCenterY = box.y + box.height / 2;
21187
- const canvasCenterX = stage.width() / (2 * scale);
21188
- const canvasCenterY = stage.height() / (2 * scale);
21189
- const stageX = (canvasCenterX - selectionCenterX) * scale;
21190
- const stageY = (canvasCenterY - selectionCenterY) * scale;
21191
22881
  stage.position({
21192
- x: stageX,
21193
- y: stageY
22882
+ x: stageWidth / 2 - offsetX * scale,
22883
+ y: stageHeight / 2 - offsetY * scale
21194
22884
  });
21195
22885
  this.setZoom(scale, false);
21196
22886
  }
@@ -21263,14 +22953,42 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21263
22953
  window.addEventListener("keyup", (e) => {
21264
22954
  if (!(e.ctrlKey || e.metaKey)) this.isCtrlOrMetaPressed = false;
21265
22955
  });
22956
+ const stage = this.instance.getStage();
22957
+ const stageContainer = this.instance.getStage().container();
22958
+ const sc = new import_hammer.default.Manager(stageContainer);
22959
+ sc.add(new import_hammer.default.Pinch({
22960
+ threshold: 0,
22961
+ pointers: 2
22962
+ }));
22963
+ let initialScale = null;
22964
+ let center = {
22965
+ x: 0,
22966
+ y: 0
22967
+ };
22968
+ sc.on("pinchstart", (ev) => {
22969
+ initialScale = stage.scaleX();
22970
+ center = {
22971
+ x: ev.center.x,
22972
+ y: ev.center.y
22973
+ };
22974
+ });
22975
+ sc.on("pinchmove", (ev) => {
22976
+ if (!initialScale) return;
22977
+ const newScale = initialScale * ev.scale;
22978
+ this.setZoom(newScale, false, center);
22979
+ });
21266
22980
  window.addEventListener("wheel", (e) => {
22981
+ e.preventDefault();
21267
22982
  if (!this.enabled || !this.isCtrlOrMetaPressed) return;
21268
- const stage = this.instance.getStage();
21269
- const pointer = stage.getPointerPosition();
22983
+ const stage$1 = this.instance.getStage();
22984
+ const oldScale = stage$1.scaleX();
22985
+ const pointer = stage$1.getPointerPosition();
21270
22986
  if (!pointer) return;
21271
- if (e.deltaY > 0) this.zoomOut(pointer);
21272
- if (e.deltaY < 0) this.zoomIn(pointer);
21273
- });
22987
+ const scaleBy = 1.05;
22988
+ const direction = e.deltaY > 0 ? 1 : -1;
22989
+ const newScale = direction > 0 ? oldScale / scaleBy : oldScale * scaleBy;
22990
+ this.setZoom(newScale, false, pointer);
22991
+ }, { passive: false });
21274
22992
  }
21275
22993
  };
21276
22994
 
@@ -21548,7 +23266,7 @@ var WeaveEraserToolAction = class extends WeaveAction {
21548
23266
  }
21549
23267
  setupEvents() {
21550
23268
  const stage = this.instance.getStage();
21551
- stage.on("click touch", (e) => {
23269
+ stage.on("click tap", (e) => {
21552
23270
  e.evt.preventDefault();
21553
23271
  if (!this.erasing) return;
21554
23272
  const nodeIntersected = this.instance.pointIntersectsElement();
@@ -21586,6 +23304,8 @@ var WeaveEraserToolAction = class extends WeaveAction {
21586
23304
  stage.container().tabIndex = 1;
21587
23305
  stage.container().focus();
21588
23306
  this.cancelAction = cancelAction;
23307
+ const selectionPlugin = this.instance.getPlugin("nodesSelection");
23308
+ if (selectionPlugin) selectionPlugin.disable();
21589
23309
  this.setEraser();
21590
23310
  }
21591
23311
  cleanup() {
@@ -21593,7 +23313,10 @@ var WeaveEraserToolAction = class extends WeaveAction {
21593
23313
  stage.container().style.cursor = "default";
21594
23314
  this.erasing = false;
21595
23315
  const selectionPlugin = this.instance.getPlugin("nodesSelection");
21596
- if (selectionPlugin) this.instance.triggerAction(SELECTION_TOOL_ACTION_NAME);
23316
+ if (selectionPlugin) {
23317
+ selectionPlugin.enable();
23318
+ this.instance.triggerAction(SELECTION_TOOL_ACTION_NAME);
23319
+ }
21597
23320
  this.setState(ERASER_TOOL_STATE.IDLE);
21598
23321
  }
21599
23322
  };
@@ -21631,7 +23354,7 @@ var WeaveRectangleToolAction = class extends WeaveAction {
21631
23354
  initProps() {
21632
23355
  return {
21633
23356
  opacity: 1,
21634
- fill: "#71717aff",
23357
+ fill: "#ffffffff",
21635
23358
  stroke: "#000000ff",
21636
23359
  strokeWidth: 1,
21637
23360
  width: 100,
@@ -21806,7 +23529,7 @@ var WeaveEllipseToolAction = class extends WeaveAction {
21806
23529
  initProps() {
21807
23530
  return {
21808
23531
  opacity: 1,
21809
- fill: "#71717aff",
23532
+ fill: "#ffffffff",
21810
23533
  stroke: "#000000ff",
21811
23534
  strokeWidth: 1,
21812
23535
  radiusX: 50,
@@ -22491,7 +24214,7 @@ var WeaveStarToolAction = class extends WeaveAction {
22491
24214
  initProps() {
22492
24215
  return {
22493
24216
  opacity: 1,
22494
- fill: "#71717aff",
24217
+ fill: "#ffffffff",
22495
24218
  stroke: "#000000ff",
22496
24219
  strokeWidth: 1,
22497
24220
  numPoints: 5,
@@ -22929,7 +24652,7 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
22929
24652
  initProps() {
22930
24653
  return {
22931
24654
  opacity: 1,
22932
- fill: "#71717aff",
24655
+ fill: "#ffffffff",
22933
24656
  stroke: "#000000ff",
22934
24657
  strokeWidth: 1,
22935
24658
  sides: 5,
@@ -23203,10 +24926,11 @@ var WeaveExportStageToolAction = class extends WeaveAction {
23203
24926
  return EXPORT_STAGE_TOOL_ACTION_NAME;
23204
24927
  }
23205
24928
  async exportStage() {
23206
- const img = await this.instance.exportStage(this.options);
24929
+ const mainLayer = this.instance.getMainLayer();
24930
+ const img = await this.instance.exportNodes(mainLayer?.getChildren() ?? [], this.options);
23207
24931
  const link = document.createElement("a");
23208
24932
  link.href = img.src;
23209
- link.download = `stage${__inditextech_weave_types.WEAVE_EXPORT_FILE_FORMAT[this.options.format ?? __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG]}`;
24933
+ link.download = `${v4_default()}${__inditextech_weave_types.WEAVE_EXPORT_FILE_FORMAT[this.options.format ?? __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG]}`;
23210
24934
  link.click();
23211
24935
  this.cancelAction?.();
23212
24936
  }
@@ -23232,12 +24956,12 @@ var WeaveExportStageToolAction = class extends WeaveAction {
23232
24956
  };
23233
24957
 
23234
24958
  //#endregion
23235
- //#region src/actions/export-node-tool/constants.ts
23236
- const EXPORT_NODE_TOOL_ACTION_NAME = "exportNodeTool";
24959
+ //#region src/actions/export-nodes-tool/constants.ts
24960
+ const EXPORT_NODES_TOOL_ACTION_NAME = "exportNodesTool";
23237
24961
 
23238
24962
  //#endregion
23239
- //#region src/actions/export-node-tool/export-node-tool.ts
23240
- var WeaveExportNodeToolAction = class extends WeaveAction {
24963
+ //#region src/actions/export-nodes-tool/export-nodes-tool.ts
24964
+ var WeaveExportNodesToolAction = class extends WeaveAction {
23241
24965
  defaultFormatOptions = {
23242
24966
  format: __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG,
23243
24967
  padding: 0,
@@ -23248,17 +24972,17 @@ var WeaveExportNodeToolAction = class extends WeaveAction {
23248
24972
  onPropsChange = void 0;
23249
24973
  onInit = void 0;
23250
24974
  getName() {
23251
- return EXPORT_NODE_TOOL_ACTION_NAME;
24975
+ return EXPORT_NODES_TOOL_ACTION_NAME;
23252
24976
  }
23253
- async exportNode(node) {
23254
- const img = await this.instance.exportNode(node, this.options);
24977
+ async exportNodes(nodes) {
24978
+ const img = await this.instance.exportNodes(nodes, this.options);
23255
24979
  const link = document.createElement("a");
23256
24980
  link.href = img.src;
23257
- link.download = `node-${node.getAttrs().id}${__inditextech_weave_types.WEAVE_EXPORT_FILE_FORMAT[this.options.format ?? __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG]}`;
24981
+ link.download = `${v4_default()}${__inditextech_weave_types.WEAVE_EXPORT_FILE_FORMAT[this.options.format ?? __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG]}`;
23258
24982
  link.click();
23259
24983
  this.cancelAction?.();
23260
24984
  }
23261
- async trigger(cancelAction, { node, options }) {
24985
+ async trigger(cancelAction, { nodes, options }) {
23262
24986
  if (!this.instance) throw new Error("Instance not defined");
23263
24987
  const stage = this.instance.getStage();
23264
24988
  stage.container().tabIndex = 1;
@@ -23268,7 +24992,7 @@ var WeaveExportNodeToolAction = class extends WeaveAction {
23268
24992
  ...this.defaultFormatOptions,
23269
24993
  ...options
23270
24994
  };
23271
- await this.exportNode(node);
24995
+ await this.exportNodes(nodes);
23272
24996
  }
23273
24997
  cleanup() {
23274
24998
  const stage = this.instance.getStage();
@@ -24568,7 +26292,7 @@ exports.WeaveCopyPasteNodesPlugin = WeaveCopyPasteNodesPlugin
24568
26292
  exports.WeaveEllipseNode = WeaveEllipseNode
24569
26293
  exports.WeaveEllipseToolAction = WeaveEllipseToolAction
24570
26294
  exports.WeaveEraserToolAction = WeaveEraserToolAction
24571
- exports.WeaveExportNodeToolAction = WeaveExportNodeToolAction
26295
+ exports.WeaveExportNodesToolAction = WeaveExportNodesToolAction
24572
26296
  exports.WeaveExportStageToolAction = WeaveExportStageToolAction
24573
26297
  exports.WeaveFitToScreenToolAction = WeaveFitToScreenToolAction
24574
26298
  exports.WeaveFitToSelectionToolAction = WeaveFitToSelectionToolAction
@@ -24607,6 +26331,7 @@ exports.WeaveZoomInToolAction = WeaveZoomInToolAction
24607
26331
  exports.WeaveZoomOutToolAction = WeaveZoomOutToolAction
24608
26332
  exports.checkIfOverContainer = checkIfOverContainer
24609
26333
  exports.clearContainerTargets = clearContainerTargets
26334
+ exports.getBoundingBox = getBoundingBox
24610
26335
  exports.getContrastTextColor = getContrastTextColor
24611
26336
  exports.moveNodeToContainer = moveNodeToContainer
24612
26337
  exports.resetScale = resetScale