@plait/core 0.0.42 → 0.0.44

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Component, ChangeDetectionStrategy, HostBinding, Input, Output, ViewChild, ContentChild, NgModule } from '@angular/core';
2
+ import { Component, ChangeDetectionStrategy, Input, EventEmitter, HostBinding, Output, ElementRef, ViewChild, ContentChild, NgModule } from '@angular/core';
3
3
  import rough from 'roughjs/bin/rough';
4
4
  import { Subject, fromEvent } from 'rxjs';
5
5
  import { takeUntil, filter } from 'rxjs/operators';
@@ -8,6 +8,9 @@ import { isKeyHotkey, isHotkey } from 'is-hotkey';
8
8
  import * as i1 from '@angular/common';
9
9
  import { BrowserModule } from '@angular/platform-browser';
10
10
 
11
+ const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
12
+ const SCROLL_BAR_WIDTH = 20;
13
+
11
14
  var BaseCursorStatus;
12
15
  (function (BaseCursorStatus) {
13
16
  BaseCursorStatus["move"] = "move";
@@ -235,8 +238,8 @@ function isNullOrUndefined(value) {
235
238
 
236
239
  const Viewport = {
237
240
  isViewport: (value) => {
238
- return (!isNullOrUndefined(value.offsetX) &&
239
- !isNullOrUndefined(value.offsetY) &&
241
+ return (!isNullOrUndefined(value.offsetXRatio) &&
242
+ !isNullOrUndefined(value.offsetYRatio) &&
240
243
  !isNullOrUndefined(value.zoom) &&
241
244
  !isNullOrUndefined(value.viewBackgroundColor));
242
245
  }
@@ -245,13 +248,6 @@ const Viewport = {
245
248
  const SAVING = new WeakMap();
246
249
  const MERGING = new WeakMap();
247
250
 
248
- // record richtext type status
249
- const FLUSHING = new WeakMap();
250
- const IS_TEXT_EDITABLE = new WeakMap();
251
- const BOARD_TO_ON_CHANGE = new WeakMap();
252
- const HOST_TO_ROUGH_SVG = new WeakMap();
253
- const PLAIT_BOARD_TO_COMPONENT = new WeakMap();
254
-
255
251
  const applyToDraft = (board, selection, viewport, op) => {
256
252
  var _a, _b;
257
253
  switch (op.type) {
@@ -442,12 +438,19 @@ const ViewportTransforms = {
442
438
 
443
439
  const Transforms = Object.assign(Object.assign(Object.assign(Object.assign({}, GeneralTransforms), ViewportTransforms), SelectionTransforms), NodeTransforms);
444
440
 
441
+ // record richtext type status
442
+ const FLUSHING = new WeakMap();
443
+ const IS_TEXT_EDITABLE = new WeakMap();
444
+ const BOARD_TO_ON_CHANGE = new WeakMap();
445
+ const HOST_TO_ROUGH_SVG = new WeakMap();
446
+ const PLAIT_BOARD_TO_COMPONENT = new WeakMap();
447
+
445
448
  function createBoard(host, children, options) {
446
449
  const board = {
447
450
  host,
448
451
  viewport: {
449
- offsetX: 0,
450
- offsetY: 0,
452
+ offsetXRatio: 0.5,
453
+ offsetYRatio: 0.5,
451
454
  zoom: 1,
452
455
  viewBackgroundColor: '#000'
453
456
  },
@@ -459,8 +462,11 @@ function createBoard(host, children, options) {
459
462
  },
460
463
  selection: null,
461
464
  cursor: BaseCursorStatus.select,
462
- readonly: options.readonly,
463
- allowClearBoard: options.allowClearBoard,
465
+ options: options || {
466
+ readonly: false,
467
+ allowClearBoard: false,
468
+ hideScrollbar: false
469
+ },
464
470
  undo: () => { },
465
471
  redo: () => { },
466
472
  apply: (operation) => {
@@ -706,21 +712,71 @@ function transformPoints(board, points) {
706
712
  }
707
713
  function transformPoint(board, point) {
708
714
  const { width, height } = board.host.getBoundingClientRect();
709
- const viewBox = getViewBox(board);
710
- let x = (point[0] / width) * viewBox.width + viewBox.minX;
711
- let y = (point[1] / height) * viewBox.height + viewBox.minY;
712
- const newPoint = [x - board.viewport.offsetX, y - board.viewport.offsetY];
715
+ const viewBox = board.host.viewBox.baseVal;
716
+ const x = (point[0] / width) * viewBox.width + viewBox.x;
717
+ const y = (point[1] / height) * viewBox.height + viewBox.y;
718
+ const newPoint = [x, y];
713
719
  return newPoint;
714
720
  }
715
721
  function getViewBox(board) {
716
- const { width, height } = board.host.getBoundingClientRect();
717
- const scaleWidth = (board.viewport.zoom - 1) * width;
718
- const scaleHeight = (board.viewport.zoom - 1) * height;
719
- const viewBoxWidth = width - scaleWidth;
720
- const viewBoxHeight = height - scaleHeight;
721
- const minX = scaleWidth / 2;
722
- const minY = scaleHeight / 2;
723
- return { minX, minY: minY, width: viewBoxWidth, height: viewBoxHeight };
722
+ const viewportBox = getViewportClientBox(board);
723
+ const rootGroupBBox = calculateBBox(board);
724
+ const padding = [viewportBox.height / 2, viewportBox.width / 2];
725
+ const zoom = board.viewport.zoom;
726
+ const minX = rootGroupBBox.left - padding[1] / zoom;
727
+ const minY = rootGroupBBox.top - padding[0] / zoom;
728
+ const viewportWidth = (rootGroupBBox.right - rootGroupBBox.left) * zoom + 2 * padding[1];
729
+ const viewportHeight = (rootGroupBBox.bottom - rootGroupBBox.top) * zoom + 2 * padding[0];
730
+ const width = viewportWidth / zoom;
731
+ const height = viewportHeight / zoom;
732
+ return { minX, minY, width, height, viewportWidth, viewportHeight };
733
+ }
734
+ function getViewportClientBox(board) {
735
+ var _a;
736
+ const hideScrollbar = board.options.hideScrollbar;
737
+ const scrollBarWidth = hideScrollbar ? 0 : SCROLL_BAR_WIDTH;
738
+ const container = (_a = board.host) === null || _a === void 0 ? void 0 : _a.parentElement;
739
+ const containerRect = container === null || container === void 0 ? void 0 : container.getBoundingClientRect();
740
+ const width = containerRect.width - scrollBarWidth;
741
+ const height = containerRect.height - scrollBarWidth;
742
+ return {
743
+ width,
744
+ height
745
+ };
746
+ }
747
+ function calculateBBox(board) {
748
+ const viewportBox = getViewportClientBox(board);
749
+ const rootGroup = board.host.firstChild;
750
+ const zoom = board.viewport.zoom;
751
+ const rootGroupBox = rootGroup.getBBox();
752
+ let box = {};
753
+ const containerWidth = viewportBox.width / zoom;
754
+ const containerHeight = viewportBox.height / zoom;
755
+ if (rootGroupBox.width < containerWidth) {
756
+ const offsetX = rootGroupBox.x + rootGroupBox.width / 2;
757
+ const containerX = containerWidth / 2;
758
+ box.left = offsetX - containerX;
759
+ box.right = offsetX + containerX;
760
+ }
761
+ else {
762
+ box.left = rootGroupBox.x;
763
+ box.right = rootGroupBox.x + rootGroupBox.width;
764
+ }
765
+ if (rootGroupBox.height < containerHeight) {
766
+ const offsetY = rootGroupBox.y + rootGroupBox.height / 2;
767
+ const containerY = containerHeight / 2;
768
+ box.top = offsetY - containerY;
769
+ box.bottom = offsetY + containerY;
770
+ }
771
+ else {
772
+ box.top = rootGroupBox.y;
773
+ box.bottom = rootGroupBox.y + rootGroupBox.height;
774
+ }
775
+ // 在新的缩放比容器宽高下的内容盒子位置
776
+ return box;
777
+ }
778
+ function calculateZoom(zoom, minZoom = 0.2, maxZoom = 4) {
779
+ return zoom < minZoom ? minZoom : zoom > maxZoom ? maxZoom : zoom;
724
780
  }
725
781
  function isNoSelectionElement(e) {
726
782
  var _a;
@@ -897,7 +953,7 @@ function withMove(board) {
897
953
  y: 0
898
954
  };
899
955
  board.mousedown = (event) => {
900
- if (board.readonly) {
956
+ if (board.options.readonly) {
901
957
  updateCursorStatus(board, BaseCursorStatus.move);
902
958
  }
903
959
  else if (!board.selection) {
@@ -915,8 +971,6 @@ function withMove(board) {
915
971
  board.mousemove = (event) => {
916
972
  const boardComponent = PLAIT_BOARD_TO_COMPONENT.get(board);
917
973
  if (board.cursor === BaseCursorStatus.move && board.selection && boardComponent.isMoving) {
918
- const viewport = board === null || board === void 0 ? void 0 : board.viewport;
919
- Transforms.setViewport(board, Object.assign(Object.assign({}, viewport), { offsetX: viewport.offsetX + ((event.x - plaitBoardMove.x) * 100) / transformZoom(board.viewport.zoom), offsetY: viewport.offsetY + ((event.y - plaitBoardMove.y) * 100) / transformZoom(board.viewport.zoom) }));
920
974
  plaitBoardMove.x = event.x;
921
975
  plaitBoardMove.y = event.y;
922
976
  }
@@ -943,7 +997,7 @@ function withMove(board) {
943
997
  keydown(event);
944
998
  };
945
999
  board.keyup = (event) => {
946
- if (board.selection && !board.readonly && event.code === 'Space') {
1000
+ if (board.selection && !board.options.readonly && event.code === 'Space') {
947
1001
  updateCursorStatus(board, BaseCursorStatus.select);
948
1002
  const boardComponent = PLAIT_BOARD_TO_COMPONENT.get(board);
949
1003
  boardComponent.cdr.markForCheck();
@@ -994,8 +1048,65 @@ function withSelection(board) {
994
1048
  return board;
995
1049
  }
996
1050
 
1051
+ class PlaitElementComponent {
1052
+ constructor(renderer2, viewContainerRef) {
1053
+ this.renderer2 = renderer2;
1054
+ this.viewContainerRef = viewContainerRef;
1055
+ this.initialized = false;
1056
+ this.selection = null;
1057
+ }
1058
+ ngOnInit() {
1059
+ this.initialize();
1060
+ this.drawElement();
1061
+ }
1062
+ initialize() {
1063
+ this.initialized = true;
1064
+ this.groupG = createG();
1065
+ this.renderer2.setAttribute(this.groupG, 'plait-element-group', this.index.toString());
1066
+ this.host.append(this.groupG);
1067
+ }
1068
+ drawElement() {
1069
+ const gArray = this.board.drawElement({ elementInstance: this });
1070
+ gArray.forEach(g => {
1071
+ this.groupG.appendChild(g);
1072
+ });
1073
+ }
1074
+ ngOnChanges(changes) {
1075
+ if (this.initialized) {
1076
+ this.board.redrawElement({ elementInstance: this }, changes);
1077
+ }
1078
+ }
1079
+ ngOnDestroy() {
1080
+ this.board.destroyElement();
1081
+ this.groupG.remove();
1082
+ }
1083
+ }
1084
+ PlaitElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitElementComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
1085
+ PlaitElementComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: PlaitElementComponent, selector: "plait-element", inputs: { index: "index", element: "element", board: "board", viewport: "viewport", selection: "selection", host: "host" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1086
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitElementComponent, decorators: [{
1087
+ type: Component,
1088
+ args: [{
1089
+ selector: 'plait-element',
1090
+ template: '',
1091
+ changeDetection: ChangeDetectionStrategy.OnPush
1092
+ }]
1093
+ }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
1094
+ type: Input
1095
+ }], element: [{
1096
+ type: Input
1097
+ }], board: [{
1098
+ type: Input
1099
+ }], viewport: [{
1100
+ type: Input
1101
+ }], selection: [{
1102
+ type: Input
1103
+ }], host: [{
1104
+ type: Input
1105
+ }] } });
1106
+
997
1107
  class PlaitToolbarComponent {
998
1108
  constructor() {
1109
+ this._viewZoom = 100;
999
1110
  this.hostClass = `plait-board-toolbar`;
1000
1111
  this.moveHandle = new EventEmitter();
1001
1112
  this.adaptHandle = new EventEmitter();
@@ -1003,6 +1114,12 @@ class PlaitToolbarComponent {
1003
1114
  this.zoomOutHandle = new EventEmitter();
1004
1115
  this.resetZoomHandel = new EventEmitter();
1005
1116
  }
1117
+ set viewZoom(zoom) {
1118
+ this._viewZoom = Math.floor(zoom * 100);
1119
+ }
1120
+ get viewZoom() {
1121
+ return this._viewZoom;
1122
+ }
1006
1123
  dragMove() {
1007
1124
  if (this.cursorStatus !== BaseCursorStatus.move) {
1008
1125
  this.moveHandle.emit(BaseCursorStatus.move);
@@ -1051,101 +1168,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1051
1168
  type: Output
1052
1169
  }] } });
1053
1170
 
1054
- class PlaitElementComponent {
1055
- constructor(renderer2, viewContainerRef) {
1056
- this.renderer2 = renderer2;
1057
- this.viewContainerRef = viewContainerRef;
1058
- this.initialized = false;
1059
- this.selection = null;
1060
- }
1061
- ngOnInit() {
1062
- this.initialize();
1063
- this.transform(true);
1064
- this.drawElement();
1065
- }
1066
- initialize() {
1067
- this.initialized = true;
1068
- this.groupG = createG();
1069
- this.renderer2.setAttribute(this.groupG, 'plait-element-group', this.index.toString());
1070
- this.host.append(this.groupG);
1071
- }
1072
- transform(first = false) {
1073
- if (first && this.viewport.offsetX === 0 && this.viewport.offsetY === 0) {
1074
- return;
1075
- }
1076
- this.renderer2.setAttribute(this.groupG, 'transform', `translate(${this.viewport.offsetX} ${this.viewport.offsetY})`);
1077
- }
1078
- drawElement() {
1079
- const gArray = this.board.drawElement({ elementInstance: this });
1080
- gArray.forEach(g => {
1081
- this.groupG.appendChild(g);
1082
- });
1083
- }
1084
- ngOnChanges(changes) {
1085
- const viewport = changes['viewport'];
1086
- if (this.initialized && viewport) {
1087
- this.transform();
1088
- }
1089
- if (this.initialized) {
1090
- this.board.redrawElement({ elementInstance: this }, changes);
1091
- }
1092
- }
1093
- ngOnDestroy() {
1094
- this.board.destroyElement();
1095
- this.groupG.remove();
1096
- }
1097
- }
1098
- PlaitElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitElementComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
1099
- PlaitElementComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: PlaitElementComponent, selector: "plait-element", inputs: { index: "index", element: "element", board: "board", viewport: "viewport", selection: "selection", host: "host" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1100
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitElementComponent, decorators: [{
1101
- type: Component,
1102
- args: [{
1103
- selector: 'plait-element',
1104
- template: '',
1105
- changeDetection: ChangeDetectionStrategy.OnPush
1106
- }]
1107
- }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
1108
- type: Input
1109
- }], element: [{
1110
- type: Input
1111
- }], board: [{
1112
- type: Input
1113
- }], viewport: [{
1114
- type: Input
1115
- }], selection: [{
1116
- type: Input
1117
- }], host: [{
1118
- type: Input
1119
- }] } });
1120
-
1121
1171
  class PlaitBoardComponent {
1122
- constructor(cdr, renderer2) {
1172
+ constructor(cdr, renderer2, elementRef) {
1123
1173
  this.cdr = cdr;
1124
1174
  this.renderer2 = renderer2;
1175
+ this.elementRef = elementRef;
1125
1176
  this.hasInitialized = false;
1126
1177
  this.destroy$ = new Subject();
1127
- this._viewZoom = 100;
1178
+ this.autoFitPadding = 8;
1128
1179
  this.isMoving = false;
1129
1180
  this.plaitValue = [];
1130
1181
  this.plaitPlugins = [];
1131
- this.plaitReadonly = false;
1132
- this.plaitAllowClearBoard = false;
1133
1182
  this.plaitChange = new EventEmitter();
1134
1183
  this.plaitBoardInitialized = new EventEmitter();
1135
1184
  this.trackBy = (index, element) => {
1136
1185
  return index;
1137
1186
  };
1138
1187
  }
1139
- get hostClass() {
1140
- return `plait-board-container ${this.board.cursor}`;
1141
- }
1142
- get viewZoom() {
1143
- const vZoom = transformZoom(this.board.viewport.zoom);
1144
- if (this._viewZoom !== vZoom) {
1145
- this._viewZoom = vZoom;
1146
- }
1147
- return vZoom;
1148
- }
1149
1188
  get isMoveMode() {
1150
1189
  return this.board.cursor === BaseCursorStatus.move;
1151
1190
  }
@@ -1156,8 +1195,11 @@ class PlaitBoardComponent {
1156
1195
  var _a;
1157
1196
  return (_a = this.board) === null || _a === void 0 ? void 0 : _a.selection;
1158
1197
  }
1198
+ get hostClass() {
1199
+ return `plait-board-container ${this.board.cursor}`;
1200
+ }
1159
1201
  get readonly() {
1160
- return this.plaitReadonly;
1202
+ return this.board.options.readonly;
1161
1203
  }
1162
1204
  get moving() {
1163
1205
  return this.board.cursor === BaseCursorStatus.move && this.isMoving;
@@ -1170,7 +1212,6 @@ class PlaitBoardComponent {
1170
1212
  HOST_TO_ROUGH_SVG.set(this.host, roughSVG);
1171
1213
  this.initializePlugins();
1172
1214
  this.initializeEvents();
1173
- this.updateViewport();
1174
1215
  PLAIT_BOARD_TO_COMPONENT.set(this.board, this);
1175
1216
  BOARD_TO_ON_CHANGE.set(this.board, () => {
1176
1217
  this.cdr.detectChanges();
@@ -1180,7 +1221,6 @@ class PlaitBoardComponent {
1180
1221
  viewport: this.board.viewport,
1181
1222
  selection: this.board.selection
1182
1223
  };
1183
- // update viewBox
1184
1224
  if (this.board.operations.some(op => PlaitOperation.isSetViewportOperation(op))) {
1185
1225
  this.updateViewport();
1186
1226
  }
@@ -1197,10 +1237,11 @@ class PlaitBoardComponent {
1197
1237
  }
1198
1238
  ngAfterViewInit() {
1199
1239
  this.plaitBoardInitialized.emit(this.board);
1240
+ this.initContainerSize();
1241
+ this.updateViewport();
1200
1242
  }
1201
1243
  initializePlugins() {
1202
- const options = { readonly: this.plaitReadonly, allowClearBoard: this.plaitAllowClearBoard };
1203
- let board = withMove(withHistory(withSelection(withBoard(createBoard(this.host, this.plaitValue, options)))));
1244
+ let board = withMove(withHistory(withSelection(withBoard(createBoard(this.host, this.plaitValue, this.plaitOptions)))));
1204
1245
  this.plaitPlugins.forEach(plugin => {
1205
1246
  board = plugin(board);
1206
1247
  });
@@ -1230,15 +1271,6 @@ class PlaitBoardComponent {
1230
1271
  .subscribe((event) => {
1231
1272
  this.board.dblclick(event);
1232
1273
  });
1233
- fromEvent(this.host, 'wheel')
1234
- .pipe(takeUntil(this.destroy$))
1235
- .subscribe((event) => {
1236
- if (this.isFocused) {
1237
- event.preventDefault();
1238
- const viewport = this.board.viewport;
1239
- Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), { offsetX: (viewport === null || viewport === void 0 ? void 0 : viewport.offsetX) - event.deltaX, offsetY: (viewport === null || viewport === void 0 ? void 0 : viewport.offsetY) - event.deltaY }));
1240
- }
1241
- });
1242
1274
  fromEvent(document, 'keydown')
1243
1275
  .pipe(takeUntil(this.destroy$), filter(() => {
1244
1276
  return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
@@ -1282,19 +1314,85 @@ class PlaitBoardComponent {
1282
1314
  (_a = this.board) === null || _a === void 0 ? void 0 : _a.setFragment(event.clipboardData);
1283
1315
  (_b = this.board) === null || _b === void 0 ? void 0 : _b.deleteFragment(event.clipboardData);
1284
1316
  });
1317
+ fromEvent(this.contentContainer.nativeElement, 'wheel')
1318
+ .pipe(takeUntil(this.destroy$), filter((e) => {
1319
+ if (!this.isFocused) {
1320
+ e.preventDefault();
1321
+ e.stopPropagation();
1322
+ }
1323
+ return !!this.isFocused;
1324
+ }))
1325
+ .subscribe();
1326
+ fromEvent(this.contentContainer.nativeElement, 'scroll')
1327
+ .pipe(takeUntil(this.destroy$), filter((e) => {
1328
+ if (!this.isFocused) {
1329
+ e.preventDefault();
1330
+ e.stopPropagation();
1331
+ }
1332
+ return !!this.isFocused;
1333
+ }))
1334
+ .subscribe((event) => {
1335
+ const scrollLeft = event.target.scrollLeft;
1336
+ const scrollTop = event.target.scrollTop;
1337
+ this.getScrollOffset(scrollLeft, scrollTop);
1338
+ });
1285
1339
  window.onresize = () => {
1286
- this.refreshViewport();
1340
+ this.updateViewport();
1287
1341
  };
1288
1342
  }
1289
- refreshViewport() {
1343
+ initContainerSize() {
1344
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'overflow', 'auto');
1345
+ this.resizeViewport();
1346
+ }
1347
+ resizeViewport() {
1290
1348
  var _a;
1291
- const viewBoxModel = getViewBox(this.board);
1292
- const viewBoxValues = (_a = this.host.getAttribute('viewBox')) === null || _a === void 0 ? void 0 : _a.split(',');
1293
- this.renderer2.setAttribute(this.host, 'viewBox', `${viewBoxValues[0].trim()}, ${viewBoxValues[1].trim()}, ${viewBoxModel.width}, ${viewBoxModel.height}`);
1349
+ const container = (_a = this.elementRef.nativeElement) === null || _a === void 0 ? void 0 : _a.parentElement;
1350
+ const containerRect = container === null || container === void 0 ? void 0 : container.getBoundingClientRect();
1351
+ const hideScrollbar = this.board.options.hideScrollbar;
1352
+ const scrollBarWidth = hideScrollbar ? 0 : SCROLL_BAR_WIDTH;
1353
+ const width = `${containerRect.width + scrollBarWidth}px`;
1354
+ const height = `${containerRect.height + scrollBarWidth}px`;
1355
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'width', width);
1356
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'height', height);
1357
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'maxWidth', width);
1358
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'maxHeight', height);
1294
1359
  }
1295
- updateViewport() {
1360
+ setScroll(left, top) {
1361
+ const container = this.contentContainer.nativeElement;
1362
+ container.scrollTo({
1363
+ top,
1364
+ left
1365
+ });
1366
+ }
1367
+ getScrollOffset(left, top) {
1368
+ const viewportBox = getViewportClientBox(this.board);
1296
1369
  const viewBox = getViewBox(this.board);
1297
- this.renderer2.setAttribute(this.host, 'viewBox', `${viewBox.minX}, ${viewBox.minY}, ${viewBox.width}, ${viewBox.height}`);
1370
+ const scrollLeftRatio = left / (viewBox.viewportWidth - viewportBox.width);
1371
+ const scrollTopRatio = top / (viewBox.viewportHeight - viewportBox.height);
1372
+ this.setViewport({
1373
+ offsetXRatio: scrollLeftRatio,
1374
+ offsetYRatio: scrollTopRatio
1375
+ });
1376
+ }
1377
+ viewportChange() {
1378
+ const viewBox = getViewBox(this.board);
1379
+ const offsetXRatio = this.board.viewport.offsetXRatio;
1380
+ const offsetYRatio = this.board.viewport.offsetYRatio;
1381
+ const viewportBox = getViewportClientBox(this.board);
1382
+ const { minX, minY, width, height, viewportWidth, viewportHeight } = viewBox;
1383
+ const box = [minX, minY, width, height];
1384
+ const scrollLeft = (viewportWidth - viewportBox.width) * offsetXRatio;
1385
+ const scrollTop = (viewportHeight - viewportBox.height) * offsetYRatio;
1386
+ this.resizeViewport();
1387
+ this.renderer2.setStyle(this.host, 'display', 'block');
1388
+ this.renderer2.setStyle(this.host, 'width', `${viewportWidth}px`);
1389
+ this.renderer2.setStyle(this.host, 'height', `${viewportHeight}px`);
1390
+ this.renderer2.setStyle(this.host, 'cursor', this.isMoveMode ? 'grab' : 'default');
1391
+ this.renderer2.setAttribute(this.host, 'viewBox', box.join());
1392
+ this.setScroll(scrollLeft, scrollTop);
1393
+ }
1394
+ updateViewport() {
1395
+ this.viewportChange();
1298
1396
  }
1299
1397
  // 拖拽模式
1300
1398
  changeMoveMode(cursorStatus) {
@@ -1303,35 +1401,44 @@ class PlaitBoardComponent {
1303
1401
  }
1304
1402
  // 适应画布
1305
1403
  adaptHandle() {
1306
- var _a;
1307
- const viewport = (_a = this.board) === null || _a === void 0 ? void 0 : _a.viewport;
1308
- Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), { offsetX: 0, offsetY: 0 }));
1309
- this.resetZoomHandel();
1404
+ const viewportBox = getViewportClientBox(this.board);
1405
+ const rootGroup = this.host.firstChild;
1406
+ const rootGroupBox = rootGroup.getBBox();
1407
+ const viewportWidth = viewportBox.width - 2 * this.autoFitPadding;
1408
+ const viewportHeight = viewportBox.height - 2 * this.autoFitPadding;
1409
+ let zoom = this.board.viewport.zoom;
1410
+ if (viewportWidth < rootGroupBox.width || viewportHeight < rootGroupBox.height) {
1411
+ zoom = Math.min(viewportWidth / rootGroupBox.width, viewportHeight / rootGroupBox.height);
1412
+ }
1413
+ this.setViewport({
1414
+ zoom: calculateZoom(zoom),
1415
+ offsetXRatio: 0.5,
1416
+ offsetYRatio: 0.5
1417
+ });
1310
1418
  }
1311
1419
  // 放大
1312
1420
  zoomInHandle() {
1313
- if (this._viewZoom >= 400) {
1314
- return;
1315
- }
1316
- this._viewZoom += 10;
1317
- this.zoomChange();
1421
+ const zoom = this.board.viewport.zoom;
1422
+ this.setViewport({
1423
+ zoom: calculateZoom(zoom + 0.1)
1424
+ });
1318
1425
  }
1319
1426
  // 缩小
1320
1427
  zoomOutHandle() {
1321
- if (this._viewZoom <= 20) {
1322
- return;
1323
- }
1324
- this._viewZoom -= 10;
1325
- this.zoomChange();
1428
+ const zoom = this.board.viewport.zoom;
1429
+ this.setViewport({
1430
+ zoom: calculateZoom(zoom - 0.1)
1431
+ });
1326
1432
  }
1327
1433
  resetZoomHandel() {
1328
- this._viewZoom = 100;
1329
- this.zoomChange();
1434
+ this.setViewport({
1435
+ zoom: 1
1436
+ });
1330
1437
  }
1331
- zoomChange() {
1438
+ setViewport(options) {
1332
1439
  var _a;
1333
1440
  const viewport = (_a = this.board) === null || _a === void 0 ? void 0 : _a.viewport;
1334
- Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), { zoom: transformViewZoom(this._viewZoom) }));
1441
+ Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), options));
1335
1442
  }
1336
1443
  ngOnDestroy() {
1337
1444
  this.destroy$.next();
@@ -1342,82 +1449,78 @@ class PlaitBoardComponent {
1342
1449
  this.isMoving = isMoving;
1343
1450
  }
1344
1451
  }
1345
- PlaitBoardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
1346
- PlaitBoardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: PlaitBoardComponent, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitReadonly: "plaitReadonly", plaitAllowClearBoard: "plaitAllowClearBoard" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.moving": "this.moving", "class.focused": "this.focused" } }, queries: [{ propertyName: "toolbarTemplateRef", first: true, predicate: ["plaitToolbar"], descendants: true }], viewQueries: [{ propertyName: "svg", first: true, predicate: ["svg"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
1347
- <svg #svg width="100%" height="100%" style="position: relative"></svg>
1452
+ PlaitBoardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1453
+ PlaitBoardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: PlaitBoardComponent, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitOptions: "plaitOptions" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.moving": "this.moving", "class.focused": "this.focused" } }, queries: [{ propertyName: "toolbarTemplateRef", first: true, predicate: ["plaitToolbar"], descendants: true }], viewQueries: [{ propertyName: "svg", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "contentContainer", first: true, predicate: ["container"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: `
1454
+ <div class="container" #container>
1455
+ <svg #svg width="100%" height="100%" style="position: relative"></svg>
1456
+ <plait-element
1457
+ *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1458
+ [index]="index"
1459
+ [element]="item"
1460
+ [board]="board"
1461
+ [viewport]="board.viewport"
1462
+ [selection]="board.selection"
1463
+ [host]="host"
1464
+ ></plait-element>
1465
+ </div>
1348
1466
  <plait-toolbar
1349
1467
  *ngIf="isFocused && !toolbarTemplateRef"
1350
1468
  [cursorStatus]="board.cursor"
1351
- [viewZoom]="viewZoom"
1469
+ [viewZoom]="board.viewport!.zoom"
1352
1470
  (moveHandle)="changeMoveMode($event)"
1353
1471
  (adaptHandle)="adaptHandle()"
1354
1472
  (zoomInHandle)="zoomInHandle()"
1355
1473
  (zoomOutHandle)="zoomOutHandle()"
1356
1474
  (resetZoomHandel)="resetZoomHandel()"
1357
1475
  ></plait-toolbar>
1358
- <plait-element
1359
- *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1360
- [index]="index"
1361
- [element]="item"
1362
- [board]="board"
1363
- [viewport]="board.viewport"
1364
- [selection]="board.selection"
1365
- [host]="host"
1366
- ></plait-element>
1367
1476
  <ng-content></ng-content>
1368
- `, isInline: true, components: [{ type: PlaitToolbarComponent, selector: "plait-toolbar", inputs: ["cursorStatus", "viewZoom"], outputs: ["moveHandle", "adaptHandle", "zoomInHandle", "zoomOutHandle", "resetZoomHandel"] }, { type: PlaitElementComponent, selector: "plait-element", inputs: ["index", "element", "board", "viewport", "selection", "host"] }], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1477
+ `, isInline: true, components: [{ type: PlaitElementComponent, selector: "plait-element", inputs: ["index", "element", "board", "viewport", "selection", "host"] }, { type: PlaitToolbarComponent, selector: "plait-toolbar", inputs: ["cursorStatus", "viewZoom"], outputs: ["moveHandle", "adaptHandle", "zoomInHandle", "zoomOutHandle", "resetZoomHandel"] }], directives: [{ type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1369
1478
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitBoardComponent, decorators: [{
1370
1479
  type: Component,
1371
1480
  args: [{
1372
1481
  selector: 'plait-board',
1373
1482
  template: `
1374
- <svg #svg width="100%" height="100%" style="position: relative"></svg>
1483
+ <div class="container" #container>
1484
+ <svg #svg width="100%" height="100%" style="position: relative"></svg>
1485
+ <plait-element
1486
+ *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1487
+ [index]="index"
1488
+ [element]="item"
1489
+ [board]="board"
1490
+ [viewport]="board.viewport"
1491
+ [selection]="board.selection"
1492
+ [host]="host"
1493
+ ></plait-element>
1494
+ </div>
1375
1495
  <plait-toolbar
1376
1496
  *ngIf="isFocused && !toolbarTemplateRef"
1377
1497
  [cursorStatus]="board.cursor"
1378
- [viewZoom]="viewZoom"
1498
+ [viewZoom]="board.viewport!.zoom"
1379
1499
  (moveHandle)="changeMoveMode($event)"
1380
1500
  (adaptHandle)="adaptHandle()"
1381
1501
  (zoomInHandle)="zoomInHandle()"
1382
1502
  (zoomOutHandle)="zoomOutHandle()"
1383
1503
  (resetZoomHandel)="resetZoomHandel()"
1384
1504
  ></plait-toolbar>
1385
- <plait-element
1386
- *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1387
- [index]="index"
1388
- [element]="item"
1389
- [board]="board"
1390
- [viewport]="board.viewport"
1391
- [selection]="board.selection"
1392
- [host]="host"
1393
- ></plait-element>
1394
1505
  <ng-content></ng-content>
1395
1506
  `,
1396
1507
  changeDetection: ChangeDetectionStrategy.OnPush
1397
1508
  }]
1398
- }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }]; }, propDecorators: { hostClass: [{
1399
- type: HostBinding,
1400
- args: ['class']
1401
- }], svg: [{
1402
- type: ViewChild,
1403
- args: ['svg', { static: true }]
1404
- }], toolbarTemplateRef: [{
1405
- type: ContentChild,
1406
- args: ['plaitToolbar']
1407
- }], plaitValue: [{
1509
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { plaitValue: [{
1408
1510
  type: Input
1409
1511
  }], plaitViewport: [{
1410
1512
  type: Input
1411
1513
  }], plaitPlugins: [{
1412
1514
  type: Input
1413
- }], plaitReadonly: [{
1414
- type: Input
1415
- }], plaitAllowClearBoard: [{
1515
+ }], plaitOptions: [{
1416
1516
  type: Input
1417
1517
  }], plaitChange: [{
1418
1518
  type: Output
1419
1519
  }], plaitBoardInitialized: [{
1420
1520
  type: Output
1521
+ }], hostClass: [{
1522
+ type: HostBinding,
1523
+ args: ['class']
1421
1524
  }], readonly: [{
1422
1525
  type: HostBinding,
1423
1526
  args: ['class.readonly']
@@ -1427,6 +1530,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1427
1530
  }], focused: [{
1428
1531
  type: HostBinding,
1429
1532
  args: ['class.focused']
1533
+ }], svg: [{
1534
+ type: ViewChild,
1535
+ args: ['svg', { static: true }]
1536
+ }], toolbarTemplateRef: [{
1537
+ type: ContentChild,
1538
+ args: ['plaitToolbar']
1539
+ }], contentContainer: [{
1540
+ type: ViewChild,
1541
+ args: ['container', { read: ElementRef, static: true }]
1430
1542
  }] } });
1431
1543
 
1432
1544
  const COMPONENTS = [PlaitBoardComponent, PlaitElementComponent, PlaitToolbarComponent];
@@ -1444,8 +1556,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1444
1556
  }]
1445
1557
  }] });
1446
1558
 
1447
- const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
1448
-
1449
1559
  /*
1450
1560
  * Public API Surface of plait
1451
1561
  */
@@ -1454,5 +1564,5 @@ const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
1454
1564
  * Generated bundle index. Do not edit.
1455
1565
  */
1456
1566
 
1457
- export { BOARD_TO_ON_CHANGE, BaseCursorStatus, CLIP_BOARD_FORMAT_KEY, FLUSHING, HOST_TO_ROUGH_SVG, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_SAFARI, IS_TEXT_EDITABLE, MERGING, NS, PLAIT_BOARD_TO_COMPONENT, Path, PlaitBoardComponent, PlaitElementComponent, PlaitHistoryBoard, PlaitModule, PlaitNode, PlaitOperation, PlaitToolbarComponent, SAVING, Transforms, Viewport, createG, createSVG, createText, distanceBetweenPointAndPoint, distanceBetweenPointAndSegment, getViewBox, hotkeys, idCreator, inverse, isNoSelectionElement, isNullOrUndefined, isSetViewportOperation, rotate, shouldClear, shouldMerge, shouldSave, toPoint, toRectangleClient, transformPoint, transformPoints, transformViewZoom, transformZoom, updateCursorStatus };
1567
+ export { BOARD_TO_ON_CHANGE, BaseCursorStatus, CLIP_BOARD_FORMAT_KEY, FLUSHING, HOST_TO_ROUGH_SVG, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_SAFARI, IS_TEXT_EDITABLE, MERGING, NS, PLAIT_BOARD_TO_COMPONENT, Path, PlaitBoardComponent, PlaitElementComponent, PlaitHistoryBoard, PlaitModule, PlaitNode, PlaitOperation, PlaitToolbarComponent, SAVING, SCROLL_BAR_WIDTH, Transforms, Viewport, calculateBBox, calculateZoom, createG, createSVG, createText, distanceBetweenPointAndPoint, distanceBetweenPointAndSegment, getViewBox, getViewportClientBox, hotkeys, idCreator, inverse, isNoSelectionElement, isNullOrUndefined, isSetViewportOperation, rotate, shouldClear, shouldMerge, shouldSave, toPoint, toRectangleClient, transformPoint, transformPoints, transformViewZoom, transformZoom, updateCursorStatus };
1458
1568
  //# sourceMappingURL=plait-core.mjs.map