sequential-workflow-designer 0.24.7 → 0.25.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/lib/cjs/index.cjs CHANGED
@@ -670,16 +670,92 @@ class ToolboxDataProvider {
670
670
  }
671
671
  }
672
672
 
673
+ function animate(interval, handler) {
674
+ const iv = setInterval(tick, 15);
675
+ const startTime = Date.now();
676
+ const anim = {
677
+ isAlive: true,
678
+ stop: () => {
679
+ anim.isAlive = false;
680
+ clearInterval(iv);
681
+ }
682
+ };
683
+ function tick() {
684
+ const progress = Math.min((Date.now() - startTime) / interval, 1);
685
+ handler(progress);
686
+ if (progress === 1) {
687
+ anim.stop();
688
+ }
689
+ }
690
+ return anim;
691
+ }
692
+
693
+ class ViewportAnimator {
694
+ constructor(api) {
695
+ this.api = api;
696
+ }
697
+ execute(target) {
698
+ if (this.animation && this.animation.isAlive) {
699
+ this.animation.stop();
700
+ }
701
+ const viewport = this.api.getViewport();
702
+ const startPosition = viewport.position;
703
+ const startScale = viewport.scale;
704
+ const deltaPosition = startPosition.subtract(target.position);
705
+ const deltaScale = startScale - target.scale;
706
+ this.animation = animate(150, progress => {
707
+ const newScale = startScale - deltaScale * progress;
708
+ this.api.setViewport({
709
+ position: startPosition.subtract(deltaPosition.multiplyByScalar(progress)),
710
+ scale: newScale
711
+ });
712
+ });
713
+ }
714
+ }
715
+
716
+ class ZoomByWheelCalculator {
717
+ static calculate(controller, current, canvasPosition, e) {
718
+ if (e.deltaY === 0) {
719
+ return null;
720
+ }
721
+ const nextScale = controller.getNextScale(current.scale, e.deltaY < 0);
722
+ let scale;
723
+ const absDeltaY = Math.abs(e.deltaY);
724
+ if (absDeltaY < controller.smoothDeltaYLimit) {
725
+ const fraction = absDeltaY / controller.smoothDeltaYLimit;
726
+ const step = nextScale.next - nextScale.current;
727
+ scale = current.scale + step * fraction;
728
+ }
729
+ else {
730
+ scale = nextScale.next;
731
+ }
732
+ const mousePoint = new Vector(e.pageX, e.pageY).subtract(canvasPosition);
733
+ // The real point is point on canvas with no scale.
734
+ const mouseRealPoint = mousePoint.divideByScalar(current.scale).subtract(current.position.divideByScalar(current.scale));
735
+ const position = mouseRealPoint.multiplyByScalar(-scale).add(mousePoint);
736
+ return { position, scale };
737
+ }
738
+ }
739
+
673
740
  class ViewportApi {
674
- constructor(workspaceController, viewportController) {
741
+ constructor(workspaceController, viewportController, api) {
675
742
  this.workspaceController = workspaceController;
676
743
  this.viewportController = viewportController;
744
+ this.api = api;
745
+ this.animator = new ViewportAnimator(this.api);
746
+ }
747
+ limitScale(scale) {
748
+ return this.viewportController.limitScale(scale);
677
749
  }
678
750
  resetViewport() {
679
- this.viewportController.setDefault();
751
+ const defaultViewport = this.viewportController.getDefault();
752
+ this.api.setViewport(defaultViewport);
680
753
  }
681
754
  zoom(direction) {
682
- this.viewportController.zoom(direction);
755
+ const viewport = this.viewportController.getZoomed(direction);
756
+ if (viewport) {
757
+ this.api.setViewport(viewport);
758
+ }
683
759
  }
684
760
  moveViewportToStep(stepId) {
685
761
  const component = this.workspaceController.getComponentByStepId(stepId);
@@ -687,7 +763,16 @@ class ViewportApi {
687
763
  const clientPosition = component.view.getClientPosition();
688
764
  const componentPosition = clientPosition.subtract(canvasPosition);
689
765
  const componentSize = new Vector(component.view.width, component.view.height);
690
- this.viewportController.focusOnComponent(componentPosition, componentSize);
766
+ const viewport = this.viewportController.getFocusedOnComponent(componentPosition, componentSize);
767
+ this.animator.execute(viewport);
768
+ }
769
+ handleWheelEvent(e) {
770
+ const viewport = this.api.getViewport();
771
+ const canvasPosition = this.api.getCanvasPosition();
772
+ const newViewport = ZoomByWheelCalculator.calculate(this.viewportController, viewport, canvasPosition, e);
773
+ if (newViewport) {
774
+ this.api.setViewport(newViewport);
775
+ }
691
776
  }
692
777
  }
693
778
 
@@ -726,7 +811,7 @@ class DesignerApi {
726
811
  static create(context) {
727
812
  const workspace = new WorkspaceApi(context.state, context.workspaceController);
728
813
  const viewportController = context.services.viewportController.create(workspace);
729
- const viewport = new ViewportApi(context.workspaceController, viewportController);
814
+ const viewport = new ViewportApi(context.workspaceController, viewportController, workspace);
730
815
  const toolboxDataProvider = new ToolboxDataProvider(context.componentContext.iconProvider, context.i18n, context.configuration.toolbox);
731
816
  return new DesignerApi(context.configuration.shadowRoot, ControlBarApi.create(context.state, context.historyController, context.stateModifier, viewport), new ToolboxApi(context.state, context, context.behaviorController, toolboxDataProvider, context.configuration.uidGenerator), new EditorApi(context.state, context.definitionWalker, context.stateModifier), workspace, viewport, new PathBarApi(context.state, context.definitionWalker), context.definitionWalker, context.i18n);
732
817
  }
@@ -1171,7 +1256,7 @@ class ValidationErrorBadge {
1171
1256
  }
1172
1257
  }
1173
1258
 
1174
- const defaultConfiguration$6 = {
1259
+ const defaultConfiguration$7 = {
1175
1260
  view: {
1176
1261
  size: 22,
1177
1262
  iconSize: 12
@@ -1179,7 +1264,7 @@ const defaultConfiguration$6 = {
1179
1264
  };
1180
1265
  class ValidationErrorBadgeExtension {
1181
1266
  static create(configuration) {
1182
- return new ValidationErrorBadgeExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$6);
1267
+ return new ValidationErrorBadgeExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$7);
1183
1268
  }
1184
1269
  constructor(configuration) {
1185
1270
  this.configuration = configuration;
@@ -1496,13 +1581,13 @@ class StartStopRootComponentView {
1496
1581
  const x = view.joinX - cfg.size / 2;
1497
1582
  const endY = cfg.size + view.height;
1498
1583
  const iconSize = parentPlaceIndicator ? cfg.folderIconSize : cfg.defaultIconSize;
1499
- const startCircle = createCircle(parentPlaceIndicator ? cfg.folderIconD : cfg.startIconD, cfg.size, iconSize);
1584
+ const startCircle = createCircle('start', parentPlaceIndicator ? cfg.folderIconD : cfg.startIconD, cfg.size, iconSize);
1500
1585
  Dom.translate(startCircle, x, 0);
1501
1586
  g.appendChild(startCircle);
1502
1587
  Dom.translate(view.g, 0, cfg.size);
1503
- const endCircle = createCircle(parentPlaceIndicator ? cfg.folderIconD : cfg.stopIconD, cfg.size, iconSize);
1504
- Dom.translate(endCircle, x, endY);
1505
- g.appendChild(endCircle);
1588
+ const stopCircle = createCircle('stop', parentPlaceIndicator ? cfg.folderIconD : cfg.stopIconD, cfg.size, iconSize);
1589
+ Dom.translate(stopCircle, x, endY);
1590
+ g.appendChild(stopCircle);
1506
1591
  let startPlaceholder = null;
1507
1592
  let endPlaceholder = null;
1508
1593
  if (parentPlaceIndicator) {
@@ -1530,7 +1615,10 @@ class StartStopRootComponentView {
1530
1615
  (_a = this.g.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.g);
1531
1616
  }
1532
1617
  }
1533
- function createCircle(d, size, iconSize) {
1618
+ function createCircle(classSuffix, d, size, iconSize) {
1619
+ const g = Dom.svg('g', {
1620
+ class: 'sqd-root-start-stop-' + classSuffix
1621
+ });
1534
1622
  const r = size / 2;
1535
1623
  const circle = Dom.svg('circle', {
1536
1624
  class: 'sqd-root-start-stop-circle',
@@ -1538,7 +1626,6 @@ function createCircle(d, size, iconSize) {
1538
1626
  cy: r,
1539
1627
  r: r
1540
1628
  });
1541
- const g = Dom.svg('g');
1542
1629
  g.appendChild(circle);
1543
1630
  const offset = (size - iconSize) / 2;
1544
1631
  const icon = Icons.appendPath(g, 'sqd-root-start-stop-icon', d, iconSize);
@@ -1573,7 +1660,7 @@ class StartStopRootComponent {
1573
1660
  }
1574
1661
  }
1575
1662
 
1576
- const defaultConfiguration$5 = {
1663
+ const defaultConfiguration$6 = {
1577
1664
  view: {
1578
1665
  size: 30,
1579
1666
  defaultIconSize: 22,
@@ -1585,7 +1672,7 @@ const defaultConfiguration$5 = {
1585
1672
  };
1586
1673
  class StartStopRootComponentExtension {
1587
1674
  static create(configuration) {
1588
- return new StartStopRootComponentExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$5);
1675
+ return new StartStopRootComponentExtension(configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$6);
1589
1676
  }
1590
1677
  constructor(configuration) {
1591
1678
  this.configuration = configuration;
@@ -1819,15 +1906,15 @@ const createTaskStepComponentViewFactory = (isInterrupted, cfg) => (parentElemen
1819
1906
  };
1820
1907
 
1821
1908
  class CenteredViewportCalculator {
1822
- static center(margin, canvasSize, rootComponentSize) {
1909
+ static center(padding, canvasSize, rootComponentSize) {
1823
1910
  if (canvasSize.x === 0 || canvasSize.y === 0) {
1824
1911
  return {
1825
1912
  position: new Vector(0, 0),
1826
1913
  scale: 1
1827
1914
  };
1828
1915
  }
1829
- const canvasSafeWidth = Math.max(canvasSize.x - margin * 2, 0);
1830
- const canvasSafeHeight = Math.max(canvasSize.y - margin * 2, 0);
1916
+ const canvasSafeWidth = Math.max(canvasSize.x - padding * 2, 0);
1917
+ const canvasSafeHeight = Math.max(canvasSize.y - padding * 2, 0);
1831
1918
  const scale = Math.min(Math.min(canvasSafeWidth / rootComponentSize.x, canvasSafeHeight / rootComponentSize.y), 1);
1832
1919
  const width = rootComponentSize.x * scale;
1833
1920
  const height = rootComponentSize.y * scale;
@@ -1838,7 +1925,7 @@ class CenteredViewportCalculator {
1838
1925
  scale
1839
1926
  };
1840
1927
  }
1841
- static focusOnComponent(canvasSize, viewport, componentPosition, componentSize) {
1928
+ static getFocusedOnComponent(canvasSize, viewport, componentPosition, componentSize) {
1842
1929
  const realPosition = viewport.position.divideByScalar(viewport.scale).subtract(componentPosition.divideByScalar(viewport.scale));
1843
1930
  const componentOffset = componentSize.divideByScalar(2);
1844
1931
  const position = realPosition.add(canvasSize.divideByScalar(2)).subtract(componentOffset);
@@ -1846,6 +1933,24 @@ class CenteredViewportCalculator {
1846
1933
  }
1847
1934
  }
1848
1935
 
1936
+ class ClassicWheelController {
1937
+ static create(api) {
1938
+ return new ClassicWheelController(api);
1939
+ }
1940
+ constructor(api) {
1941
+ this.api = api;
1942
+ }
1943
+ onWheel(e) {
1944
+ this.api.handleWheelEvent(e);
1945
+ }
1946
+ }
1947
+
1948
+ class ClassicWheelControllerExtension {
1949
+ constructor() {
1950
+ this.create = ClassicWheelController.create;
1951
+ }
1952
+ }
1953
+
1849
1954
  class NextQuantifiedNumber {
1850
1955
  constructor(values) {
1851
1956
  this.values = values;
@@ -1872,142 +1977,68 @@ class NextQuantifiedNumber {
1872
1977
  next: this.values[index]
1873
1978
  };
1874
1979
  }
1875
- }
1876
-
1877
- const SCALES = [0.06, 0.08, 0.1, 0.12, 0.16, 0.2, 0.26, 0.32, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
1878
- const MAX_DELTA_Y$1 = 16;
1879
- const quantifiedScale = new NextQuantifiedNumber(SCALES);
1880
- class QuantifiedScaleViewportCalculator {
1881
- static zoom(current, direction) {
1882
- const nextScale = quantifiedScale.next(current.scale, direction);
1883
- return {
1884
- position: current.position,
1885
- scale: nextScale.next
1886
- };
1887
- }
1888
- static zoomByWheel(current, e, canvasPosition) {
1889
- if (e.deltaY === 0) {
1890
- return null;
1891
- }
1892
- const nextScale = quantifiedScale.next(current.scale, e.deltaY < 0);
1893
- let scale;
1894
- const absDeltaY = Math.abs(e.deltaY);
1895
- if (absDeltaY < MAX_DELTA_Y$1) {
1896
- const fraction = absDeltaY / MAX_DELTA_Y$1;
1897
- const step = nextScale.next - nextScale.current;
1898
- scale = current.scale + step * fraction;
1899
- }
1900
- else {
1901
- scale = nextScale.next;
1902
- }
1903
- const mousePoint = new Vector(e.pageX, e.pageY).subtract(canvasPosition);
1904
- // The real point is point on canvas with no scale.
1905
- const mouseRealPoint = mousePoint.divideByScalar(current.scale).subtract(current.position.divideByScalar(current.scale));
1906
- const position = mouseRealPoint.multiplyByScalar(-scale).add(mousePoint);
1907
- return { position, scale };
1980
+ limit(scale) {
1981
+ const min = this.values[0];
1982
+ const max = this.values[this.values.length - 1];
1983
+ return Math.min(Math.max(scale, min), max);
1908
1984
  }
1909
1985
  }
1910
1986
 
1911
- class ClassicWheelController {
1912
- static create(api) {
1913
- return new ClassicWheelController(api);
1914
- }
1915
- constructor(api) {
1916
- this.api = api;
1917
- }
1918
- onWheel(e) {
1919
- const viewport = this.api.getViewport();
1920
- const canvasPosition = this.api.getCanvasPosition();
1921
- const newViewport = QuantifiedScaleViewportCalculator.zoomByWheel(viewport, e, canvasPosition);
1922
- if (newViewport) {
1923
- this.api.setViewport(newViewport);
1924
- }
1925
- }
1926
- }
1927
-
1928
- class ClassicWheelControllerExtension {
1929
- constructor() {
1930
- this.create = ClassicWheelController.create;
1931
- }
1932
- }
1933
-
1934
- function animate(interval, handler) {
1935
- const iv = setInterval(tick, 15);
1936
- const startTime = Date.now();
1937
- const anim = {
1938
- isAlive: true,
1939
- stop: () => {
1940
- anim.isAlive = false;
1941
- clearInterval(iv);
1942
- }
1943
- };
1944
- function tick() {
1945
- const progress = Math.min((Date.now() - startTime) / interval, 1);
1946
- handler(progress);
1947
- if (progress === 1) {
1948
- anim.stop();
1949
- }
1950
- }
1951
- return anim;
1952
- }
1953
-
1954
- class ViewportAnimator {
1955
- constructor(api) {
1956
- this.api = api;
1957
- }
1958
- execute(target) {
1959
- if (this.animation && this.animation.isAlive) {
1960
- this.animation.stop();
1961
- }
1962
- const viewport = this.api.getViewport();
1963
- const startPosition = viewport.position;
1964
- const startScale = viewport.scale;
1965
- const deltaPosition = startPosition.subtract(target.position);
1966
- const deltaScale = startScale - target.scale;
1967
- this.animation = animate(150, progress => {
1968
- const newScale = startScale - deltaScale * progress;
1969
- this.api.setViewport({
1970
- position: startPosition.subtract(deltaPosition.multiplyByScalar(progress)),
1971
- scale: newScale
1972
- });
1973
- });
1974
- }
1975
- }
1976
-
1977
- const CENTER_MARGIN = 10;
1987
+ const defaultConfiguration$5 = {
1988
+ scales: [0.06, 0.08, 0.1, 0.12, 0.16, 0.2, 0.26, 0.32, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
1989
+ smoothDeltaYLimit: 16,
1990
+ padding: 10
1991
+ };
1978
1992
  class DefaultViewportController {
1979
- static create(api) {
1980
- return new DefaultViewportController(api);
1993
+ static create(api, configuration) {
1994
+ const config = configuration !== null && configuration !== void 0 ? configuration : defaultConfiguration$5;
1995
+ const nqn = new NextQuantifiedNumber(config.scales);
1996
+ return new DefaultViewportController(config.smoothDeltaYLimit, nqn, api, config.padding);
1981
1997
  }
1982
- constructor(api) {
1998
+ constructor(smoothDeltaYLimit, nqn, api, padding) {
1999
+ this.smoothDeltaYLimit = smoothDeltaYLimit;
2000
+ this.nqn = nqn;
1983
2001
  this.api = api;
1984
- this.animator = new ViewportAnimator(this.api);
2002
+ this.padding = padding;
1985
2003
  }
1986
- setDefault() {
2004
+ getDefault() {
1987
2005
  const rootComponentSize = this.api.getRootComponentSize();
1988
2006
  const canvasSize = this.api.getCanvasSize();
1989
- const target = CenteredViewportCalculator.center(CENTER_MARGIN, canvasSize, rootComponentSize);
1990
- this.api.setViewport(target);
2007
+ return CenteredViewportCalculator.center(this.padding, canvasSize, rootComponentSize);
1991
2008
  }
1992
- zoom(direction) {
1993
- const viewport = this.api.getViewport();
1994
- const target = QuantifiedScaleViewportCalculator.zoom(viewport, direction);
1995
- this.api.setViewport(target);
2009
+ getZoomed(direction) {
2010
+ const current = this.api.getViewport();
2011
+ const nextScale = this.nqn.next(current.scale, direction);
2012
+ if (nextScale) {
2013
+ return {
2014
+ position: current.position,
2015
+ scale: nextScale.next
2016
+ };
2017
+ }
2018
+ return null;
1996
2019
  }
1997
- focusOnComponent(componentPosition, componentSize) {
2020
+ getFocusedOnComponent(componentPosition, componentSize) {
1998
2021
  const viewport = this.api.getViewport();
1999
2022
  const canvasSize = this.api.getCanvasSize();
2000
- const target = CenteredViewportCalculator.focusOnComponent(canvasSize, viewport, componentPosition, componentSize);
2001
- this.animateTo(target);
2023
+ return CenteredViewportCalculator.getFocusedOnComponent(canvasSize, viewport, componentPosition, componentSize);
2002
2024
  }
2003
- animateTo(viewport) {
2004
- this.animator.execute(viewport);
2025
+ getNextScale(scale, direction) {
2026
+ return this.nqn.next(scale, direction);
2027
+ }
2028
+ limitScale(scale) {
2029
+ return this.nqn.limit(scale);
2005
2030
  }
2006
2031
  }
2007
2032
 
2008
2033
  class DefaultViewportControllerExtension {
2009
- constructor() {
2010
- this.create = DefaultViewportController.create;
2034
+ static create(configuration) {
2035
+ return new DefaultViewportControllerExtension(configuration);
2036
+ }
2037
+ constructor(configuration) {
2038
+ this.configuration = configuration;
2039
+ }
2040
+ create(api) {
2041
+ return DefaultViewportController.create(api, this.configuration);
2011
2042
  }
2012
2043
  }
2013
2044
 
@@ -2167,10 +2198,26 @@ function readTouchPosition(e) {
2167
2198
  return new Vector(touch.pageX, touch.pageY);
2168
2199
  }
2169
2200
  throw new Error('Unknown touch position');
2201
+ }
2202
+ function calculateFingerDistance(e) {
2203
+ if (e.touches.length === 2) {
2204
+ const t0 = e.touches[0];
2205
+ const t1 = e.touches[1];
2206
+ return Math.hypot(t0.clientX - t1.clientX, t0.clientY - t1.clientY);
2207
+ }
2208
+ throw new Error('Cannot calculate finger distance');
2209
+ }
2210
+ function readFingerCenterPoint(e) {
2211
+ if (e.touches.length === 2) {
2212
+ const t0 = e.touches[0];
2213
+ const t1 = e.touches[1];
2214
+ return new Vector((t0.pageX + t1.pageX) / 2, (t0.pageY + t1.pageY) / 2);
2215
+ }
2216
+ throw new Error('Cannot calculate finger center point');
2170
2217
  }
2171
2218
 
2172
- const notInitializedError = 'State is not initialized';
2173
- const nonPassiveOptions = {
2219
+ const notInitializedError$1 = 'State is not initialized';
2220
+ const nonPassiveOptions$1 = {
2174
2221
  passive: false
2175
2222
  };
2176
2223
  class BehaviorController {
@@ -2200,7 +2247,7 @@ class BehaviorController {
2200
2247
  e.preventDefault();
2201
2248
  e.stopPropagation();
2202
2249
  if (!this.state) {
2203
- throw new Error(notInitializedError);
2250
+ throw new Error(notInitializedError$1);
2204
2251
  }
2205
2252
  const position = (_a = this.state.lastPosition) !== null && _a !== void 0 ? _a : this.state.startPosition;
2206
2253
  const element = this.dom.elementFromPoint(position.x, position.y);
@@ -2231,21 +2278,21 @@ class BehaviorController {
2231
2278
  }
2232
2279
  bind(target) {
2233
2280
  target.addEventListener('mousemove', this.onMouseMove, false);
2234
- target.addEventListener('touchmove', this.onTouchMove, nonPassiveOptions);
2281
+ target.addEventListener('touchmove', this.onTouchMove, nonPassiveOptions$1);
2235
2282
  target.addEventListener('mouseup', this.onMouseUp, false);
2236
- target.addEventListener('touchend', this.onTouchEnd, nonPassiveOptions);
2237
- target.addEventListener('touchstart', this.onTouchStart, nonPassiveOptions);
2283
+ target.addEventListener('touchend', this.onTouchEnd, nonPassiveOptions$1);
2284
+ target.addEventListener('touchstart', this.onTouchStart, nonPassiveOptions$1);
2238
2285
  }
2239
2286
  unbind(target) {
2240
2287
  target.removeEventListener('mousemove', this.onMouseMove, false);
2241
- target.removeEventListener('touchmove', this.onTouchMove, nonPassiveOptions);
2288
+ target.removeEventListener('touchmove', this.onTouchMove, nonPassiveOptions$1);
2242
2289
  target.removeEventListener('mouseup', this.onMouseUp, false);
2243
- target.removeEventListener('touchend', this.onTouchEnd, nonPassiveOptions);
2244
- target.removeEventListener('touchstart', this.onTouchStart, nonPassiveOptions);
2290
+ target.removeEventListener('touchend', this.onTouchEnd, nonPassiveOptions$1);
2291
+ target.removeEventListener('touchstart', this.onTouchStart, nonPassiveOptions$1);
2245
2292
  }
2246
2293
  move(position) {
2247
2294
  if (!this.state) {
2248
- throw new Error(notInitializedError);
2295
+ throw new Error(notInitializedError$1);
2249
2296
  }
2250
2297
  this.state.lastPosition = position;
2251
2298
  const delta = this.state.startPosition.subtract(position);
@@ -2259,7 +2306,7 @@ class BehaviorController {
2259
2306
  }
2260
2307
  stop(interrupt, element) {
2261
2308
  if (!this.state) {
2262
- throw new Error(notInitializedError);
2309
+ throw new Error(notInitializedError$1);
2263
2310
  }
2264
2311
  if (this.shadowRoot) {
2265
2312
  this.unbind(this.shadowRoot);
@@ -2834,20 +2881,26 @@ class WorkspaceView {
2834
2881
  getCanvasSize() {
2835
2882
  return new Vector(this.canvas.clientWidth, this.canvas.clientHeight);
2836
2883
  }
2837
- bindClick(handler) {
2884
+ bindMouseDown(handler) {
2838
2885
  this.canvas.addEventListener('mousedown', e => {
2839
2886
  e.preventDefault();
2840
2887
  handler(readMousePosition(e), e.target, e.button, e.altKey);
2841
2888
  }, false);
2889
+ }
2890
+ bindTouchStart(clickHandler, pinchToZoomHandler) {
2842
2891
  this.canvas.addEventListener('touchstart', e => {
2843
2892
  var _a;
2844
2893
  e.preventDefault();
2894
+ if (e.touches.length === 2) {
2895
+ pinchToZoomHandler(calculateFingerDistance(e), readFingerCenterPoint(e));
2896
+ return;
2897
+ }
2845
2898
  const clientPosition = readTouchClientPosition(e);
2846
2899
  const dom = (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : document;
2847
2900
  const element = dom.elementFromPoint(clientPosition.x, clientPosition.y);
2848
2901
  if (element) {
2849
2902
  const position = readTouchPosition(e);
2850
- handler(position, element, 0, false);
2903
+ clickHandler(position, element, 0, false);
2851
2904
  }
2852
2905
  }, listenerOptions$1);
2853
2906
  }
@@ -3224,17 +3277,96 @@ class ContextMenuItemsBuilder {
3224
3277
  }
3225
3278
  }
3226
3279
 
3280
+ const nonPassiveOptions = {
3281
+ passive: false
3282
+ };
3283
+ const notInitializedError = 'State is not initialized';
3284
+ class PinchToZoomController {
3285
+ static create(workspaceApi, viewportApi, shadowRoot) {
3286
+ return new PinchToZoomController(workspaceApi, viewportApi, shadowRoot);
3287
+ }
3288
+ constructor(workspaceApi, viewportApi, shadowRoot) {
3289
+ this.workspaceApi = workspaceApi;
3290
+ this.viewportApi = viewportApi;
3291
+ this.shadowRoot = shadowRoot;
3292
+ this.state = null;
3293
+ this.onTouchMove = (e) => {
3294
+ e.preventDefault();
3295
+ if (!this.state) {
3296
+ throw new Error(notInitializedError);
3297
+ }
3298
+ const touchEvent = e;
3299
+ const distance = calculateFingerDistance(touchEvent);
3300
+ const centerPoint = readFingerCenterPoint(touchEvent);
3301
+ const deltaCenterPoint = centerPoint.subtract(this.state.lastCenterPoint);
3302
+ const scale = this.viewportApi.limitScale(this.state.startScale * (distance / this.state.startDistance));
3303
+ const zoomPoint = centerPoint.subtract(this.state.canvasPosition);
3304
+ const zoomRealPoint = zoomPoint
3305
+ .divideByScalar(this.state.lastViewport.scale)
3306
+ .subtract(this.state.lastViewport.position.divideByScalar(this.state.lastViewport.scale));
3307
+ const position = zoomRealPoint
3308
+ .multiplyByScalar(-scale)
3309
+ .add(zoomPoint)
3310
+ .add(deltaCenterPoint.divideByScalar(this.state.lastViewport.scale));
3311
+ const newViewport = {
3312
+ position,
3313
+ scale
3314
+ };
3315
+ this.workspaceApi.setViewport(newViewport);
3316
+ this.state.lastCenterPoint = centerPoint;
3317
+ this.state.lastViewport = newViewport;
3318
+ };
3319
+ this.onTouchEnd = (e) => {
3320
+ e.preventDefault();
3321
+ if (!this.state) {
3322
+ throw new Error(notInitializedError);
3323
+ }
3324
+ if (this.shadowRoot) {
3325
+ this.unbind(this.shadowRoot);
3326
+ }
3327
+ this.unbind(window);
3328
+ this.state = null;
3329
+ };
3330
+ }
3331
+ start(startDistance, centerPoint) {
3332
+ if (this.state) {
3333
+ throw new Error(`State is already initialized`);
3334
+ }
3335
+ if (this.shadowRoot) {
3336
+ this.bind(this.shadowRoot);
3337
+ }
3338
+ this.bind(window);
3339
+ const viewport = this.workspaceApi.getViewport();
3340
+ this.state = {
3341
+ canvasPosition: this.workspaceApi.getCanvasPosition(),
3342
+ startScale: viewport.scale,
3343
+ startDistance,
3344
+ lastViewport: viewport,
3345
+ lastCenterPoint: centerPoint
3346
+ };
3347
+ }
3348
+ bind(target) {
3349
+ target.addEventListener('touchmove', this.onTouchMove, nonPassiveOptions);
3350
+ target.addEventListener('touchend', this.onTouchEnd, nonPassiveOptions);
3351
+ }
3352
+ unbind(target) {
3353
+ target.removeEventListener('touchmove', this.onTouchMove, nonPassiveOptions);
3354
+ target.removeEventListener('touchend', this.onTouchEnd, nonPassiveOptions);
3355
+ }
3356
+ }
3357
+
3227
3358
  class Workspace {
3228
3359
  static create(parent, designerContext, api) {
3229
3360
  var _a;
3230
3361
  const view = WorkspaceView.create(parent, designerContext.componentContext);
3231
3362
  const clickBehaviorResolver = new ClickBehaviorResolver(designerContext);
3232
- const wheelController = designerContext.services.wheelController.create(api.workspace);
3363
+ const wheelController = designerContext.services.wheelController.create(api.viewport, api.workspace);
3364
+ const pinchToZoomController = PinchToZoomController.create(api.workspace, api.viewport, api.shadowRoot);
3233
3365
  const contextMenuItemsBuilder = new ContextMenuItemsBuilder(api.viewport, api.i18n, designerContext.stateModifier, designerContext.state, ((_a = designerContext.services.contextMenu) === null || _a === void 0 ? void 0 : _a.createItemsProvider)
3234
3366
  ? designerContext.services.contextMenu.createItemsProvider(designerContext.customActionController)
3235
3367
  : undefined);
3236
3368
  const contextMenuController = new ContextMenuController(designerContext.theme, designerContext.configuration, contextMenuItemsBuilder);
3237
- const workspace = new Workspace(view, designerContext.definitionWalker, designerContext.state, designerContext.behaviorController, wheelController, contextMenuController, clickBehaviorResolver, api.viewport, designerContext.services);
3369
+ const workspace = new Workspace(view, designerContext.definitionWalker, designerContext.state, designerContext.behaviorController, wheelController, pinchToZoomController, contextMenuController, clickBehaviorResolver, api.viewport, designerContext.services);
3238
3370
  setTimeout(() => {
3239
3371
  workspace.updateRootComponent();
3240
3372
  api.viewport.resetViewport();
@@ -3244,17 +3376,19 @@ class Workspace {
3244
3376
  race(0, designerContext.state.onDefinitionChanged, designerContext.state.onSelectedStepIdChanged, designerContext.state.onFolderPathChanged).subscribe(r => {
3245
3377
  workspace.onStateChanged(r[0], r[1], r[2]);
3246
3378
  });
3247
- view.bindClick(workspace.onClick);
3379
+ view.bindMouseDown(workspace.onClick);
3380
+ view.bindTouchStart(workspace.onClick, workspace.onPinchToZoom);
3248
3381
  view.bindWheel(workspace.onWheel);
3249
3382
  view.bindContextMenu(workspace.onContextMenu);
3250
3383
  return workspace;
3251
3384
  }
3252
- constructor(view, definitionWalker, state, behaviorController, wheelController, contextMenuController, clickBehaviorResolver, viewportApi, services) {
3385
+ constructor(view, definitionWalker, state, behaviorController, wheelController, pinchToZoomController, contextMenuController, clickBehaviorResolver, viewportApi, services) {
3253
3386
  this.view = view;
3254
3387
  this.definitionWalker = definitionWalker;
3255
3388
  this.state = state;
3256
3389
  this.behaviorController = behaviorController;
3257
3390
  this.wheelController = wheelController;
3391
+ this.pinchToZoomController = pinchToZoomController;
3258
3392
  this.contextMenuController = contextMenuController;
3259
3393
  this.clickBehaviorResolver = clickBehaviorResolver;
3260
3394
  this.viewportApi = viewportApi;
@@ -3273,6 +3407,9 @@ class Workspace {
3273
3407
  this.behaviorController.start(position, behavior);
3274
3408
  }
3275
3409
  };
3410
+ this.onPinchToZoom = (distance, centerPoint) => {
3411
+ this.pinchToZoomController.start(distance, centerPoint);
3412
+ };
3276
3413
  this.onWheel = (e) => {
3277
3414
  e.preventDefault();
3278
3415
  e.stopPropagation();
@@ -4396,7 +4533,7 @@ function setDefaults(services, configuration) {
4396
4533
  services.regionComponentView = new DefaultRegionComponentViewExtension();
4397
4534
  }
4398
4535
  if (!services.viewportController) {
4399
- services.viewportController = new DefaultViewportControllerExtension();
4536
+ services.viewportController = DefaultViewportControllerExtension.create();
4400
4537
  }
4401
4538
  if (!services.grid) {
4402
4539
  services.grid = LineGridExtension.create();
@@ -4715,7 +4852,6 @@ exports.LineGridDesignerExtension = LineGridDesignerExtension;
4715
4852
  exports.ObjectCloner = ObjectCloner;
4716
4853
  exports.OutputView = OutputView;
4717
4854
  exports.PathBarApi = PathBarApi;
4718
- exports.QuantifiedScaleViewportCalculator = QuantifiedScaleViewportCalculator;
4719
4855
  exports.RectPlaceholder = RectPlaceholder;
4720
4856
  exports.RectPlaceholderView = RectPlaceholderView;
4721
4857
  exports.ServicesResolver = ServicesResolver;
@@ -4728,6 +4864,7 @@ exports.ToolboxApi = ToolboxApi;
4728
4864
  exports.Uid = Uid;
4729
4865
  exports.ValidationErrorBadgeExtension = ValidationErrorBadgeExtension;
4730
4866
  exports.Vector = Vector;
4867
+ exports.ViewportApi = ViewportApi;
4731
4868
  exports.WorkspaceApi = WorkspaceApi;
4732
4869
  exports.createContainerStepComponentViewFactory = createContainerStepComponentViewFactory;
4733
4870
  exports.createSwitchStepComponentViewFactory = createSwitchStepComponentViewFactory;