@inditextech/weave-sdk 0.27.4 → 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
  }
@@ -15810,6 +15833,54 @@ function moveNodeToContainer(instance, node) {
15810
15833
  }
15811
15834
  return void 0;
15812
15835
  }
15836
+ function getContrastTextColor(hex) {
15837
+ const cleaned = hex.replace(/^#/, "");
15838
+ const r = parseInt(cleaned.slice(0, 2), 16);
15839
+ const g = parseInt(cleaned.slice(2, 4), 16);
15840
+ const b = parseInt(cleaned.slice(4, 6), 16);
15841
+ const luminance = (.299 * r + .587 * g + .114 * b) / 255;
15842
+ return luminance > .5 ? "black" : "white";
15843
+ }
15844
+ function stringToColor(str) {
15845
+ let hash = 0;
15846
+ str.split("").forEach((char) => {
15847
+ hash = char.charCodeAt(0) + ((hash << 5) - hash);
15848
+ });
15849
+ let color = "#";
15850
+ for (let i = 0; i < 3; i++) {
15851
+ const value = hash >> i * 8 & 255;
15852
+ color += value.toString(16).padStart(2, "0");
15853
+ }
15854
+ return color;
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
+ }
15813
15884
 
15814
15885
  //#endregion
15815
15886
  //#region src/plugins/users-selection/constants.ts
@@ -15907,6 +15978,9 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
15907
15978
  const copyPastePlugin = this.instance.getPlugin("copyPasteNodes");
15908
15979
  return copyPastePlugin.isPasting();
15909
15980
  }
15981
+ isAreaSelecting() {
15982
+ return this.selecting;
15983
+ }
15910
15984
  isSelecting() {
15911
15985
  return this.instance.getActiveAction() === "selectionTool";
15912
15986
  }
@@ -16024,8 +16098,6 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16024
16098
  stage.container().style.cursor = actualCursor;
16025
16099
  });
16026
16100
  }
16027
- const usersSelectionPlugin = this.instance.getPlugin(WEAVE_USERS_SELECTION_KEY);
16028
- if (usersSelectionPlugin) usersSelectionPlugin.sendSelectionAwarenessInfo(this.tr);
16029
16101
  tr.forceUpdate();
16030
16102
  });
16031
16103
  this.tr = tr;
@@ -16102,6 +16174,7 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16102
16174
  if (!this.initialized) return;
16103
16175
  if (!this.active) return;
16104
16176
  if (e.evt.button && e.evt.button !== 0) return;
16177
+ if (e.evt.touches && e.evt.touches.length > 1) return;
16105
16178
  const selectedGroup = this.instance.getInstanceRecursive(e.target);
16106
16179
  if (!(e.target instanceof konva.default.Stage) && !(selectedGroup && selectedGroup.getAttrs().nodeType === "frame")) return;
16107
16180
  e.evt.preventDefault();
@@ -16121,6 +16194,7 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16121
16194
  const handleMouseMove = (e) => {
16122
16195
  if (!this.initialized) return;
16123
16196
  if (!this.active) return;
16197
+ if (e.evt instanceof TouchEvent && e.evt.touches && e.evt.touches.length > 1) return;
16124
16198
  if (!this.selecting) {
16125
16199
  this.cameFromSelectingMultiple = false;
16126
16200
  return;
@@ -16141,6 +16215,9 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16141
16215
  stage.on("mouseup touchend", (e) => {
16142
16216
  if (!this.initialized) return;
16143
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;
16144
16221
  this.selecting = false;
16145
16222
  this.instance.emitEvent("onSelectionState", false);
16146
16223
  if (!this.selectionRectangle.visible()) {
@@ -16186,6 +16263,7 @@ var WeaveNodesSelectionPlugin = class extends WeavePlugin {
16186
16263
  stage.on("click tap", (e) => {
16187
16264
  if (!this.enabled) return;
16188
16265
  const contextMenuPlugin = this.instance.getPlugin("contextMenu");
16266
+ if (contextMenuPlugin && contextMenuPlugin.isContextMenuVisible()) return;
16189
16267
  if (this.cameFromSelectingMultiple) {
16190
16268
  this.cameFromSelectingMultiple = false;
16191
16269
  return;
@@ -16516,9 +16594,6 @@ var WeaveCopyPasteNodesPlugin = class extends WeavePlugin {
16516
16594
  //#endregion
16517
16595
  //#region src/nodes/node.ts
16518
16596
  const augmentKonvaStageClass = () => {
16519
- konva.default.Stage.prototype.isFocused = function() {
16520
- return false;
16521
- };
16522
16597
  konva.default.Stage.prototype.isMouseWheelPressed = function() {
16523
16598
  return false;
16524
16599
  };
@@ -16531,6 +16606,9 @@ const augmentKonvaNodeClass = (config) => {
16531
16606
  ...transform
16532
16607
  };
16533
16608
  };
16609
+ konva.default.Node.prototype.getRealClientRect = function(config$1) {
16610
+ return this.getClientRect(config$1);
16611
+ };
16534
16612
  konva.default.Node.prototype.movedToContainer = function() {};
16535
16613
  konva.default.Node.prototype.updatePosition = function() {};
16536
16614
  konva.default.Node.prototype.triggerCrop = function() {};
@@ -16604,10 +16682,9 @@ var WeaveNode = class {
16604
16682
  this.scaleReset(node$1);
16605
16683
  const nodeHandler = this.instance.getNodeHandler(node$1.getAttrs().nodeType);
16606
16684
  this.instance.updateNode(nodeHandler.serialize(node$1));
16607
- e.cancelBubble = true;
16608
16685
  }
16609
16686
  };
16610
- node.on("transform", (0, import_lodash.throttle)(handleTransform, 50));
16687
+ node.on("transform", (0, import_lodash.throttle)(handleTransform, 100));
16611
16688
  node.on("transformend", (e) => {
16612
16689
  const node$1 = e.target;
16613
16690
  transforming = false;
@@ -16637,9 +16714,11 @@ var WeaveNode = class {
16637
16714
  clearContainerTargets(this.instance);
16638
16715
  const layerToMove = checkIfOverContainer(this.instance, e.target);
16639
16716
  if (layerToMove) layerToMove.fire(__inditextech_weave_types.WEAVE_NODE_CUSTOM_EVENTS.onTargetEnter, { bubbles: true });
16717
+ const nodeHandler = this.instance.getNodeHandler(node.getAttrs().nodeType);
16718
+ this.instance.updateNode(nodeHandler.serialize(node));
16640
16719
  }
16641
16720
  };
16642
- node.on("dragmove", (0, import_lodash.throttle)(handleDragMove, 50));
16721
+ node.on("dragmove", (0, import_lodash.throttle)(handleDragMove, 100));
16643
16722
  node.on("dragend", (e) => {
16644
16723
  if (this.isSelecting() && this.isNodeSelected(node)) {
16645
16724
  clearContainerTargets(this.instance);
@@ -18139,7 +18218,7 @@ var WeaveRegisterManager = class {
18139
18218
 
18140
18219
  //#endregion
18141
18220
  //#region package.json
18142
- var version = "0.27.4";
18221
+ var version = "0.29.0";
18143
18222
 
18144
18223
  //#endregion
18145
18224
  //#region src/managers/setup.ts
@@ -18348,103 +18427,55 @@ var WeaveExportManager = class {
18348
18427
  this.logger = this.instance.getChildLogger("export-manager");
18349
18428
  this.logger.debug("Export manager created");
18350
18429
  }
18351
- exportStage(options) {
18430
+ exportNodes(nodes, options) {
18352
18431
  return new Promise((resolve) => {
18353
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;
18354
18433
  const stage = this.instance.getStage();
18355
18434
  const mainLayer = this.instance.getMainLayer();
18356
- const previousScale = stage.scaleX();
18357
- const previousX = stage.x();
18358
- const previousY = stage.y();
18359
- let background = void 0;
18360
- if (mainLayer) {
18361
- const box = mainLayer.getClientRect({ relativeTo: stage });
18362
- const scale = Math.min(stage.width() / (box.width + padding * 2), stage.height() / (box.height + padding * 2));
18363
- stage.setAttrs({
18364
- x: -box.x * scale + (stage.width() - box.width * scale) / 2,
18365
- y: -box.y * scale + (stage.height() - box.height * scale) / 2
18366
- });
18367
- const actScale = stage.scale();
18368
- actScale.x = scale;
18369
- actScale.y = scale;
18370
- stage.scale(actScale);
18371
- const plugins = this.instance.getPlugins();
18372
- for (const pluginId of Object.keys(plugins)) {
18373
- const pluginInstance = plugins[pluginId];
18374
- pluginInstance.onRender?.();
18375
- }
18376
- const stageClientRect = stage.getClientRect({ relativeTo: stage });
18377
- background = new konva.default.Rect({
18378
- x: stageClientRect.x,
18379
- y: stageClientRect.y,
18380
- width: stageClientRect.width,
18381
- height: stageClientRect.height,
18382
- fill: backgroundColor
18383
- });
18384
- mainLayer.add(background);
18385
- background.moveToBottom();
18386
- stage.toImage({
18387
- mimeType: format$2,
18388
- x: (mainLayer?.x() ?? 0) - padding,
18389
- y: (mainLayer?.y() ?? 0) - padding,
18390
- width: (mainLayer?.width() ?? 0) + padding * 2,
18391
- height: (mainLayer?.height() ?? 0) + padding * 2,
18392
- pixelRatio,
18393
- quality: options.quality ?? 1,
18394
- callback: (img) => {
18395
- stage.setAttrs({
18396
- x: previousX,
18397
- y: previousY,
18398
- scaleX: previousScale,
18399
- scaleY: previousScale
18400
- });
18401
- const plugins$1 = this.instance.getPlugins();
18402
- for (const pluginId of Object.keys(plugins$1)) {
18403
- const pluginInstance = plugins$1[pluginId];
18404
- pluginInstance.onRender?.();
18405
- }
18406
- background?.destroy();
18407
- resolve(img);
18408
- }
18409
- });
18410
- }
18411
- });
18412
- }
18413
- exportNode(node, options) {
18414
- return new Promise((resolve) => {
18415
- const { format: format$2 = __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG, padding = 0, pixelRatio = 1, backgroundColor = __inditextech_weave_types.WEAVE_EXPORT_BACKGROUND_COLOR } = options;
18416
- const mainLayer = this.instance.getMainLayer();
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");
18417
18439
  if (mainLayer) {
18418
- const clonedNode = node.clone({ id: v4_default() });
18419
- const group = new konva.default.Group({
18420
- x: clonedNode.getAbsolutePosition().x,
18421
- y: clonedNode.getAbsolutePosition().y,
18422
- visible: false
18423
- });
18424
- mainLayer.add(group);
18425
- 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();
18426
18450
  const background = new konva.default.Rect({
18427
- x: 0,
18428
- y: 0,
18429
- width: nodeClientRect.width + 2 * padding,
18430
- 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,
18431
18455
  fill: backgroundColor
18432
18456
  });
18433
- group.add(background);
18434
- background.zIndex(0);
18435
- clonedNode.moveTo(group);
18436
- clonedNode.setPosition({
18437
- x: padding,
18438
- y: padding
18439
- });
18440
- clonedNode.zIndex(1);
18441
- group.visible(true);
18442
- 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,
18443
18474
  mimeType: format$2,
18444
18475
  pixelRatio,
18445
18476
  quality: options.quality ?? 1,
18446
18477
  callback: (img) => {
18447
- group?.destroy();
18478
+ exportGroup.destroy();
18448
18479
  resolve(img);
18449
18480
  }
18450
18481
  });
@@ -18813,11 +18844,8 @@ var Weave = class extends Emittery {
18813
18844
  getFonts() {
18814
18845
  return this.fontsManager.getFonts();
18815
18846
  }
18816
- async exportStage(options) {
18817
- return await this.exportManager.exportStage(options);
18818
- }
18819
- async exportNode(node, options) {
18820
- return await this.exportManager.exportNode(node, options);
18847
+ async exportNodes(nodes, options) {
18848
+ return await this.exportManager.exportNodes(nodes, options);
18821
18849
  }
18822
18850
  };
18823
18851
 
@@ -20697,6 +20725,21 @@ var WeaveFrameNode = class extends WeaveNode {
20697
20725
  draggable: false,
20698
20726
  clip: void 0
20699
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
+ };
20700
20743
  this.setupDefaultNodeAugmentation(frame);
20701
20744
  const frameInternalGroup = new konva.default.Group({
20702
20745
  id: `${id}-selector`,
@@ -20988,6 +21031,1672 @@ const WEAVE_STAGE_ZOOM_DEFAULT_CONFIG = {
20988
21031
  fitToSelection: { padding: 40 }
20989
21032
  };
20990
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
+
20991
22700
  //#endregion
20992
22701
  //#region src/plugins/stage-zoom/stage-zoom.ts
20993
22702
  var WeaveStageZoomPlugin = class extends WeavePlugin {
@@ -21149,32 +22858,29 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21149
22858
  return;
21150
22859
  }
21151
22860
  const stage = this.instance.getStage();
21152
- const box = mainLayer.getClientRect({
21153
- relativeTo: stage,
21154
- skipStroke: true
22861
+ stage.scale({
22862
+ x: 1,
22863
+ y: 1
21155
22864
  });
21156
- const stageBox = {
21157
- width: stage.width(),
21158
- height: stage.height()
21159
- };
21160
- const availableScreenWidth = stageBox.width - 2 * this.config.fitToScreen.padding;
21161
- const availableScreenHeight = stageBox.height - 2 * this.config.fitToScreen.padding;
21162
- const scaleX = availableScreenWidth / box.width;
21163
- 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;
21164
22874
  const scale = Math.min(scaleX, scaleY);
22875
+ const offsetX = bounds.x + bounds.width / 2;
22876
+ const offsetY = bounds.y + bounds.height / 2;
21165
22877
  stage.scale({
21166
22878
  x: scale,
21167
22879
  y: scale
21168
22880
  });
21169
- const selectionCenterX = box.x + box.width / 2;
21170
- const selectionCenterY = box.y + box.height / 2;
21171
- const canvasCenterX = stage.width() / (2 * scale);
21172
- const canvasCenterY = stage.height() / (2 * scale);
21173
- const stageX = (canvasCenterX - selectionCenterX) * scale;
21174
- const stageY = (canvasCenterY - selectionCenterY) * scale;
21175
22881
  stage.position({
21176
- x: stageX,
21177
- y: stageY
22882
+ x: stageWidth / 2 - offsetX * scale,
22883
+ y: stageHeight / 2 - offsetY * scale
21178
22884
  });
21179
22885
  this.setZoom(scale, false);
21180
22886
  }
@@ -21247,14 +22953,42 @@ var WeaveStageZoomPlugin = class extends WeavePlugin {
21247
22953
  window.addEventListener("keyup", (e) => {
21248
22954
  if (!(e.ctrlKey || e.metaKey)) this.isCtrlOrMetaPressed = false;
21249
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
+ });
21250
22980
  window.addEventListener("wheel", (e) => {
22981
+ e.preventDefault();
21251
22982
  if (!this.enabled || !this.isCtrlOrMetaPressed) return;
21252
- const stage = this.instance.getStage();
21253
- const pointer = stage.getPointerPosition();
22983
+ const stage$1 = this.instance.getStage();
22984
+ const oldScale = stage$1.scaleX();
22985
+ const pointer = stage$1.getPointerPosition();
21254
22986
  if (!pointer) return;
21255
- if (e.deltaY > 0) this.zoomOut(pointer);
21256
- if (e.deltaY < 0) this.zoomIn(pointer);
21257
- });
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 });
21258
22992
  }
21259
22993
  };
21260
22994
 
@@ -21532,7 +23266,7 @@ var WeaveEraserToolAction = class extends WeaveAction {
21532
23266
  }
21533
23267
  setupEvents() {
21534
23268
  const stage = this.instance.getStage();
21535
- stage.on("click touch", (e) => {
23269
+ stage.on("click tap", (e) => {
21536
23270
  e.evt.preventDefault();
21537
23271
  if (!this.erasing) return;
21538
23272
  const nodeIntersected = this.instance.pointIntersectsElement();
@@ -21570,6 +23304,8 @@ var WeaveEraserToolAction = class extends WeaveAction {
21570
23304
  stage.container().tabIndex = 1;
21571
23305
  stage.container().focus();
21572
23306
  this.cancelAction = cancelAction;
23307
+ const selectionPlugin = this.instance.getPlugin("nodesSelection");
23308
+ if (selectionPlugin) selectionPlugin.disable();
21573
23309
  this.setEraser();
21574
23310
  }
21575
23311
  cleanup() {
@@ -21577,7 +23313,10 @@ var WeaveEraserToolAction = class extends WeaveAction {
21577
23313
  stage.container().style.cursor = "default";
21578
23314
  this.erasing = false;
21579
23315
  const selectionPlugin = this.instance.getPlugin("nodesSelection");
21580
- if (selectionPlugin) this.instance.triggerAction(SELECTION_TOOL_ACTION_NAME);
23316
+ if (selectionPlugin) {
23317
+ selectionPlugin.enable();
23318
+ this.instance.triggerAction(SELECTION_TOOL_ACTION_NAME);
23319
+ }
21581
23320
  this.setState(ERASER_TOOL_STATE.IDLE);
21582
23321
  }
21583
23322
  };
@@ -21615,7 +23354,7 @@ var WeaveRectangleToolAction = class extends WeaveAction {
21615
23354
  initProps() {
21616
23355
  return {
21617
23356
  opacity: 1,
21618
- fill: "#71717aff",
23357
+ fill: "#ffffffff",
21619
23358
  stroke: "#000000ff",
21620
23359
  strokeWidth: 1,
21621
23360
  width: 100,
@@ -21790,7 +23529,7 @@ var WeaveEllipseToolAction = class extends WeaveAction {
21790
23529
  initProps() {
21791
23530
  return {
21792
23531
  opacity: 1,
21793
- fill: "#71717aff",
23532
+ fill: "#ffffffff",
21794
23533
  stroke: "#000000ff",
21795
23534
  strokeWidth: 1,
21796
23535
  radiusX: 50,
@@ -22475,7 +24214,7 @@ var WeaveStarToolAction = class extends WeaveAction {
22475
24214
  initProps() {
22476
24215
  return {
22477
24216
  opacity: 1,
22478
- fill: "#71717aff",
24217
+ fill: "#ffffffff",
22479
24218
  stroke: "#000000ff",
22480
24219
  strokeWidth: 1,
22481
24220
  numPoints: 5,
@@ -22913,7 +24652,7 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
22913
24652
  initProps() {
22914
24653
  return {
22915
24654
  opacity: 1,
22916
- fill: "#71717aff",
24655
+ fill: "#ffffffff",
22917
24656
  stroke: "#000000ff",
22918
24657
  strokeWidth: 1,
22919
24658
  sides: 5,
@@ -23187,10 +24926,11 @@ var WeaveExportStageToolAction = class extends WeaveAction {
23187
24926
  return EXPORT_STAGE_TOOL_ACTION_NAME;
23188
24927
  }
23189
24928
  async exportStage() {
23190
- 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);
23191
24931
  const link = document.createElement("a");
23192
24932
  link.href = img.src;
23193
- 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]}`;
23194
24934
  link.click();
23195
24935
  this.cancelAction?.();
23196
24936
  }
@@ -23216,12 +24956,12 @@ var WeaveExportStageToolAction = class extends WeaveAction {
23216
24956
  };
23217
24957
 
23218
24958
  //#endregion
23219
- //#region src/actions/export-node-tool/constants.ts
23220
- const EXPORT_NODE_TOOL_ACTION_NAME = "exportNodeTool";
24959
+ //#region src/actions/export-nodes-tool/constants.ts
24960
+ const EXPORT_NODES_TOOL_ACTION_NAME = "exportNodesTool";
23221
24961
 
23222
24962
  //#endregion
23223
- //#region src/actions/export-node-tool/export-node-tool.ts
23224
- var WeaveExportNodeToolAction = class extends WeaveAction {
24963
+ //#region src/actions/export-nodes-tool/export-nodes-tool.ts
24964
+ var WeaveExportNodesToolAction = class extends WeaveAction {
23225
24965
  defaultFormatOptions = {
23226
24966
  format: __inditextech_weave_types.WEAVE_EXPORT_FORMATS.PNG,
23227
24967
  padding: 0,
@@ -23232,17 +24972,17 @@ var WeaveExportNodeToolAction = class extends WeaveAction {
23232
24972
  onPropsChange = void 0;
23233
24973
  onInit = void 0;
23234
24974
  getName() {
23235
- return EXPORT_NODE_TOOL_ACTION_NAME;
24975
+ return EXPORT_NODES_TOOL_ACTION_NAME;
23236
24976
  }
23237
- async exportNode(node) {
23238
- const img = await this.instance.exportNode(node, this.options);
24977
+ async exportNodes(nodes) {
24978
+ const img = await this.instance.exportNodes(nodes, this.options);
23239
24979
  const link = document.createElement("a");
23240
24980
  link.href = img.src;
23241
- 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]}`;
23242
24982
  link.click();
23243
24983
  this.cancelAction?.();
23244
24984
  }
23245
- async trigger(cancelAction, { node, options }) {
24985
+ async trigger(cancelAction, { nodes, options }) {
23246
24986
  if (!this.instance) throw new Error("Instance not defined");
23247
24987
  const stage = this.instance.getStage();
23248
24988
  stage.container().tabIndex = 1;
@@ -23252,7 +24992,7 @@ var WeaveExportNodeToolAction = class extends WeaveAction {
23252
24992
  ...this.defaultFormatOptions,
23253
24993
  ...options
23254
24994
  };
23255
- await this.exportNode(node);
24995
+ await this.exportNodes(nodes);
23256
24996
  }
23257
24997
  cleanup() {
23258
24998
  const stage = this.instance.getStage();
@@ -23777,6 +25517,7 @@ var WeaveUsersSelectionPlugin = class extends WeavePlugin {
23777
25517
  return stage.findOne(`#${this.getLayerName()}`);
23778
25518
  }
23779
25519
  onInit() {
25520
+ const stage = this.instance.getStage();
23780
25521
  this.instance.addEventListener("onAwarenessChange", (changes) => {
23781
25522
  const selfUser = this.config.getUser();
23782
25523
  const allActiveUsers = [];
@@ -23785,15 +25526,18 @@ var WeaveUsersSelectionPlugin = class extends WeavePlugin {
23785
25526
  if (change[WEAVE_USER_SELECTION_KEY] && selfUser.name !== change[WEAVE_USER_SELECTION_KEY].user) {
23786
25527
  const userSelection = change[WEAVE_USER_SELECTION_KEY];
23787
25528
  allActiveUsers.push(userSelection.user);
23788
- this.usersSelection[userSelection.user] = {
23789
- oldNodes: this.usersSelection[userSelection.user]?.actualNodes ?? {
23790
- user: userSelection.user,
23791
- nodes: []
23792
- },
23793
- actualNodes: userSelection
23794
- };
25529
+ this.usersSelection[userSelection.user] = userSelection;
23795
25530
  }
23796
25531
  }
25532
+ const allNodesSelections = Object.keys(this.usersSelection);
25533
+ const inactiveUsers = allNodesSelections.filter((user) => !allNodesSelections.includes(user));
25534
+ for (let i = 0; i < inactiveUsers.length; i++) delete this.usersSelection[inactiveUsers[i]];
25535
+ this.renderSelectors();
25536
+ });
25537
+ stage.on("dragstart dragmove dragend", () => {
25538
+ this.renderSelectors();
25539
+ });
25540
+ stage.on("transformstart transform transformend", () => {
23797
25541
  this.renderSelectors();
23798
25542
  });
23799
25543
  this.renderSelectors();
@@ -23810,18 +25554,6 @@ var WeaveUsersSelectionPlugin = class extends WeavePlugin {
23810
25554
  const store = this.instance.getStore();
23811
25555
  store.setAwarenessInfo(WEAVE_USER_SELECTION_KEY, void 0);
23812
25556
  }
23813
- stringToColor(str) {
23814
- let hash = 0;
23815
- str.split("").forEach((char) => {
23816
- hash = char.charCodeAt(0) + ((hash << 5) - hash);
23817
- });
23818
- let color = "#";
23819
- for (let i = 0; i < 3; i++) {
23820
- const value = hash >> i * 8 & 255;
23821
- color += value.toString(16).padStart(2, "0");
23822
- }
23823
- return color;
23824
- }
23825
25557
  getSelectedNodesRect(nodes) {
23826
25558
  const stage = this.instance.getStage();
23827
25559
  const maxPoint = {
@@ -23860,10 +25592,10 @@ var WeaveUsersSelectionPlugin = class extends WeavePlugin {
23860
25592
  for (const selector of selectors) selector.destroy();
23861
25593
  for (const userPointerKey of Object.keys(this.usersSelection)) {
23862
25594
  const userSelector = this.usersSelection[userPointerKey];
23863
- const selectionRect = this.getSelectedNodesRect(userSelector.actualNodes.nodes);
25595
+ const selectionRect = this.getSelectedNodesRect(userSelector.nodes);
23864
25596
  const userSelectorNode = new konva.default.Group({
23865
25597
  name: "selector",
23866
- id: `selector_${userSelector.actualNodes.user}`,
25598
+ id: `selector_${userSelector.user}`,
23867
25599
  x: selectionRect.x,
23868
25600
  y: selectionRect.y,
23869
25601
  listening: false
@@ -23872,12 +25604,12 @@ var WeaveUsersSelectionPlugin = class extends WeavePlugin {
23872
25604
  const userSelectorRect = new konva.default.Rect({
23873
25605
  x: -this.padding / stage.scaleX(),
23874
25606
  y: -this.padding / stage.scaleY(),
23875
- id: `selector_${userSelector.actualNodes.user}_rect`,
25607
+ id: `selector_${userSelector.user}_rect`,
23876
25608
  width: (selectionRect.width + 2 * this.padding) / stage.scaleX(),
23877
25609
  height: (selectionRect.height + 2 * this.padding) / stage.scaleY(),
23878
25610
  fill: "transparent",
23879
25611
  listening: false,
23880
- stroke: this.stringToColor(userSelector.actualNodes.user),
25612
+ stroke: stringToColor(userSelector.user),
23881
25613
  strokeWidth: 3,
23882
25614
  strokeScaleEnabled: false
23883
25615
  });
@@ -23968,14 +25700,7 @@ var WeaveUsersPointersPlugin = class extends WeavePlugin {
23968
25700
  if (change[WEAVE_USER_POINTER_KEY] && selfUser.name !== change[WEAVE_USER_POINTER_KEY].user) {
23969
25701
  const userPointer = change[WEAVE_USER_POINTER_KEY];
23970
25702
  allActiveUsers.push(userPointer.user);
23971
- this.usersPointers[userPointer.user] = {
23972
- oldPos: this.usersPointers[userPointer.user]?.actualPos ?? {
23973
- user: userPointer.user,
23974
- x: 0,
23975
- y: 0
23976
- },
23977
- actualPos: userPointer
23978
- };
25703
+ this.usersPointers[userPointer.user] = userPointer;
23979
25704
  }
23980
25705
  }
23981
25706
  const allPointers = Object.keys(this.usersPointers);
@@ -24005,26 +25730,6 @@ var WeaveUsersPointersPlugin = class extends WeavePlugin {
24005
25730
  });
24006
25731
  this.renderPointers();
24007
25732
  }
24008
- getContrastTextColor(hex) {
24009
- const cleaned = hex.replace(/^#/, "");
24010
- const r = parseInt(cleaned.slice(0, 2), 16);
24011
- const g = parseInt(cleaned.slice(2, 4), 16);
24012
- const b = parseInt(cleaned.slice(4, 6), 16);
24013
- const luminance = (.299 * r + .587 * g + .114 * b) / 255;
24014
- return luminance > .5 ? "black" : "white";
24015
- }
24016
- stringToColor(str) {
24017
- let hash = 0;
24018
- str.split("").forEach((char) => {
24019
- hash = char.charCodeAt(0) + ((hash << 5) - hash);
24020
- });
24021
- let color = "#";
24022
- for (let i = 0; i < 3; i++) {
24023
- const value = hash >> i * 8 & 255;
24024
- color += value.toString(16).padStart(2, "0");
24025
- }
24026
- return color;
24027
- }
24028
25733
  renderPointers() {
24029
25734
  const stage = this.instance.getStage();
24030
25735
  const pointersLayer = this.getLayer();
@@ -24035,9 +25740,9 @@ var WeaveUsersPointersPlugin = class extends WeavePlugin {
24035
25740
  const userPointer = this.usersPointers[userPointerKey];
24036
25741
  const userPointerNode = new konva.default.Group({
24037
25742
  name: "pointer",
24038
- id: `pointer_${userPointer.actualPos.user}`,
24039
- x: userPointer.actualPos.x,
24040
- y: userPointer.actualPos.y,
25743
+ id: `pointer_${userPointer.user}`,
25744
+ x: userPointer.x,
25745
+ y: userPointer.y,
24041
25746
  opacity: 1,
24042
25747
  listening: false,
24043
25748
  scaleX: 1 / stage.scaleX(),
@@ -24045,10 +25750,10 @@ var WeaveUsersPointersPlugin = class extends WeavePlugin {
24045
25750
  });
24046
25751
  userPointerNode.moveToTop();
24047
25752
  const { separation, pointer: { circleRadius, circleStrokeWidth }, name: { fontFamily, fontSize, backgroundCornerRadius, backgroundPaddingX, backgroundPaddingY } } = this.uiConfig;
24048
- const userColor = this.stringToColor(userPointer.actualPos.user);
24049
- const userContrastColor = this.getContrastTextColor(userColor);
25753
+ const userColor = stringToColor(userPointer.user);
25754
+ const userContrastColor = getContrastTextColor(userColor);
24050
25755
  const userPointNode = new konva.default.Circle({
24051
- id: `pointer_${userPointer.actualPos.user}_userPoint`,
25756
+ id: `pointer_${userPointer.user}_userPoint`,
24052
25757
  x: 0,
24053
25758
  y: 0,
24054
25759
  radius: circleRadius,
@@ -24059,10 +25764,10 @@ var WeaveUsersPointersPlugin = class extends WeavePlugin {
24059
25764
  listening: false
24060
25765
  });
24061
25766
  const userNameNode = new konva.default.Text({
24062
- id: `pointer_${userPointer.actualPos.user}_userPointName`,
25767
+ id: `pointer_${userPointer.user}_userPointName`,
24063
25768
  x: separation,
24064
25769
  y: -circleRadius * 2 + backgroundPaddingY,
24065
- text: userPointer.actualPos.user.trim(),
25770
+ text: userPointer.user.trim(),
24066
25771
  fontSize,
24067
25772
  fontFamily,
24068
25773
  lineHeight: .9,
@@ -24078,7 +25783,7 @@ var WeaveUsersPointersPlugin = class extends WeavePlugin {
24078
25783
  userNameNode.width(textWidth + backgroundPaddingX * 2);
24079
25784
  userNameNode.height(textHeight + backgroundPaddingY * 2);
24080
25785
  const userNameBackground = new konva.default.Rect({
24081
- id: `pointer_${userPointer.actualPos.user}_userPointRect`,
25786
+ id: `pointer_${userPointer.user}_userPointRect`,
24082
25787
  x: separation,
24083
25788
  y: -backgroundPaddingY,
24084
25789
  width: textWidth + backgroundPaddingX * 2,
@@ -24232,7 +25937,10 @@ var WeaveNodesSnappingPlugin = class extends WeavePlugin {
24232
25937
  node = nodesSelectionPlugin.getTransformer();
24233
25938
  skipNodes = [...nodes];
24234
25939
  }
24235
- if (e.type === "transform") node = e.target;
25940
+ if (e.type === "transform") {
25941
+ node = e.target;
25942
+ skipNodes.push(node.getAttrs().id ?? "");
25943
+ }
24236
25944
  if (typeof node === "undefined") return;
24237
25945
  const lineGuideStops = this.getLineGuideStops(skipNodes);
24238
25946
  const itemBounds = this.getObjectSnappingEdges(node);
@@ -24584,7 +26292,7 @@ exports.WeaveCopyPasteNodesPlugin = WeaveCopyPasteNodesPlugin
24584
26292
  exports.WeaveEllipseNode = WeaveEllipseNode
24585
26293
  exports.WeaveEllipseToolAction = WeaveEllipseToolAction
24586
26294
  exports.WeaveEraserToolAction = WeaveEraserToolAction
24587
- exports.WeaveExportNodeToolAction = WeaveExportNodeToolAction
26295
+ exports.WeaveExportNodesToolAction = WeaveExportNodesToolAction
24588
26296
  exports.WeaveExportStageToolAction = WeaveExportStageToolAction
24589
26297
  exports.WeaveFitToScreenToolAction = WeaveFitToScreenToolAction
24590
26298
  exports.WeaveFitToSelectionToolAction = WeaveFitToSelectionToolAction
@@ -24623,5 +26331,8 @@ exports.WeaveZoomInToolAction = WeaveZoomInToolAction
24623
26331
  exports.WeaveZoomOutToolAction = WeaveZoomOutToolAction
24624
26332
  exports.checkIfOverContainer = checkIfOverContainer
24625
26333
  exports.clearContainerTargets = clearContainerTargets
26334
+ exports.getBoundingBox = getBoundingBox
26335
+ exports.getContrastTextColor = getContrastTextColor
24626
26336
  exports.moveNodeToContainer = moveNodeToContainer
24627
- exports.resetScale = resetScale
26337
+ exports.resetScale = resetScale
26338
+ exports.stringToColor = stringToColor