@plait/core 0.0.41 → 0.0.43

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
  },
@@ -705,22 +708,69 @@ function transformPoints(board, points) {
705
708
  return newPoints;
706
709
  }
707
710
  function transformPoint(board, point) {
708
- const { width, height } = board.host.getBoundingClientRect();
709
711
  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];
712
+ const x = (point[0] / viewBox.viewportWidth) * viewBox.width + viewBox.minX;
713
+ const y = (point[1] / viewBox.viewportHeight) * viewBox.height + viewBox.minY;
714
+ const newPoint = [x, y];
713
715
  return newPoint;
714
716
  }
715
717
  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 };
718
+ const viewportBox = getViewportClientBox(board);
719
+ const rootGroupBBox = calculateBBox(board);
720
+ const padding = [viewportBox.height / 2, viewportBox.width / 2];
721
+ const zoom = board.viewport.zoom;
722
+ const minX = rootGroupBBox.left - padding[1] / zoom;
723
+ const minY = rootGroupBBox.top - padding[0] / zoom;
724
+ const viewportWidth = (rootGroupBBox.right - rootGroupBBox.left) * zoom + 2 * padding[1];
725
+ const viewportHeight = (rootGroupBBox.bottom - rootGroupBBox.top) * zoom + 2 * padding[0];
726
+ const width = viewportWidth / zoom;
727
+ const height = viewportHeight / zoom;
728
+ return { minX, minY, width, height, viewportWidth, viewportHeight };
729
+ }
730
+ function getViewportClientBox(board) {
731
+ var _a;
732
+ const container = (_a = board.host) === null || _a === void 0 ? void 0 : _a.parentElement;
733
+ const containerRect = container === null || container === void 0 ? void 0 : container.getBoundingClientRect();
734
+ const width = containerRect.width - SCROLL_BAR_WIDTH;
735
+ const height = containerRect.height - SCROLL_BAR_WIDTH;
736
+ return {
737
+ width,
738
+ height
739
+ };
740
+ }
741
+ function calculateBBox(board) {
742
+ const viewportBox = getViewportClientBox(board);
743
+ const rootGroup = board.host.firstChild;
744
+ const zoom = board.viewport.zoom;
745
+ const rootGroupBox = rootGroup.getBBox();
746
+ let box = {};
747
+ const containerWidth = viewportBox.width / zoom;
748
+ const containerHeight = viewportBox.height / zoom;
749
+ if (rootGroupBox.width < containerWidth) {
750
+ const offsetX = rootGroupBox.x + rootGroupBox.width / 2;
751
+ const containerX = containerWidth / 2;
752
+ box.left = offsetX - containerX;
753
+ box.right = offsetX + containerX;
754
+ }
755
+ else {
756
+ box.left = rootGroupBox.x;
757
+ box.right = rootGroupBox.x + rootGroupBox.width;
758
+ }
759
+ if (rootGroupBox.height < containerHeight) {
760
+ const offsetY = rootGroupBox.y + rootGroupBox.height / 2;
761
+ const containerY = containerHeight / 2;
762
+ box.top = offsetY - containerY;
763
+ box.bottom = offsetY + containerY;
764
+ }
765
+ else {
766
+ box.top = rootGroupBox.y;
767
+ box.bottom = rootGroupBox.y + rootGroupBox.height;
768
+ }
769
+ // 在新的缩放比容器宽高下的内容盒子位置
770
+ return box;
771
+ }
772
+ function calculateZoom(zoom, minZoom = 0.2, maxZoom = 4) {
773
+ return zoom < minZoom ? minZoom : zoom > maxZoom ? maxZoom : zoom;
724
774
  }
725
775
  function isNoSelectionElement(e) {
726
776
  var _a;
@@ -731,7 +781,7 @@ function isNoSelectionElement(e) {
731
781
  * @param viewZoom 视图上显示的 zoom 缩放级别 %
732
782
  * @returns zoom 真实的 zoom
733
783
  */
734
- const transformViewZoom = (viewZoom) => (2 * viewZoom - 100) / viewZoom;
784
+ const transformViewZoom = (viewZoom) => 2 - 100 / viewZoom;
735
785
  /**
736
786
  * zoom 转 viewZoom
737
787
  * @param zoom this.board.viewport.zoom
@@ -908,15 +958,13 @@ function withMove(board) {
908
958
  boardComponent.movingChange(true);
909
959
  plaitBoardMove.x = event.x;
910
960
  plaitBoardMove.y = event.y;
911
- boardComponent.cdr.detectChanges();
961
+ boardComponent.cdr.markForCheck();
912
962
  }
913
963
  mousedown(event);
914
964
  };
915
965
  board.mousemove = (event) => {
916
966
  const boardComponent = PLAIT_BOARD_TO_COMPONENT.get(board);
917
967
  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
968
  plaitBoardMove.x = event.x;
921
969
  plaitBoardMove.y = event.y;
922
970
  }
@@ -933,17 +981,21 @@ function withMove(board) {
933
981
  };
934
982
  board.keydown = (event) => {
935
983
  if (board.selection && event.code === 'Space') {
936
- updateCursorStatus(board, BaseCursorStatus.move);
937
- const boardComponent = PLAIT_BOARD_TO_COMPONENT.get(board);
938
- boardComponent.cdr.detectChanges();
984
+ if (board.cursor !== BaseCursorStatus.move) {
985
+ updateCursorStatus(board, BaseCursorStatus.move);
986
+ const boardComponent = PLAIT_BOARD_TO_COMPONENT.get(board);
987
+ boardComponent.cdr.markForCheck();
988
+ }
939
989
  event.preventDefault();
940
990
  }
941
991
  keydown(event);
942
992
  };
943
993
  board.keyup = (event) => {
944
- board.selection && !board.readonly && event.code === 'Space' && updateCursorStatus(board, BaseCursorStatus.select);
945
- const boardComponent = PLAIT_BOARD_TO_COMPONENT.get(board);
946
- boardComponent.cdr.detectChanges();
994
+ if (board.selection && !board.readonly && event.code === 'Space') {
995
+ updateCursorStatus(board, BaseCursorStatus.select);
996
+ const boardComponent = PLAIT_BOARD_TO_COMPONENT.get(board);
997
+ boardComponent.cdr.markForCheck();
998
+ }
947
999
  keyup(event);
948
1000
  };
949
1001
  return board;
@@ -990,8 +1042,65 @@ function withSelection(board) {
990
1042
  return board;
991
1043
  }
992
1044
 
1045
+ class PlaitElementComponent {
1046
+ constructor(renderer2, viewContainerRef) {
1047
+ this.renderer2 = renderer2;
1048
+ this.viewContainerRef = viewContainerRef;
1049
+ this.initialized = false;
1050
+ this.selection = null;
1051
+ }
1052
+ ngOnInit() {
1053
+ this.initialize();
1054
+ this.drawElement();
1055
+ }
1056
+ initialize() {
1057
+ this.initialized = true;
1058
+ this.groupG = createG();
1059
+ this.renderer2.setAttribute(this.groupG, 'plait-element-group', this.index.toString());
1060
+ this.host.append(this.groupG);
1061
+ }
1062
+ drawElement() {
1063
+ const gArray = this.board.drawElement({ elementInstance: this });
1064
+ gArray.forEach(g => {
1065
+ this.groupG.appendChild(g);
1066
+ });
1067
+ }
1068
+ ngOnChanges(changes) {
1069
+ if (this.initialized) {
1070
+ this.board.redrawElement({ elementInstance: this }, changes);
1071
+ }
1072
+ }
1073
+ ngOnDestroy() {
1074
+ this.board.destroyElement();
1075
+ this.groupG.remove();
1076
+ }
1077
+ }
1078
+ 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 });
1079
+ 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 });
1080
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitElementComponent, decorators: [{
1081
+ type: Component,
1082
+ args: [{
1083
+ selector: 'plait-element',
1084
+ template: '',
1085
+ changeDetection: ChangeDetectionStrategy.OnPush
1086
+ }]
1087
+ }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
1088
+ type: Input
1089
+ }], element: [{
1090
+ type: Input
1091
+ }], board: [{
1092
+ type: Input
1093
+ }], viewport: [{
1094
+ type: Input
1095
+ }], selection: [{
1096
+ type: Input
1097
+ }], host: [{
1098
+ type: Input
1099
+ }] } });
1100
+
993
1101
  class PlaitToolbarComponent {
994
1102
  constructor() {
1103
+ this._viewZoom = 100;
995
1104
  this.hostClass = `plait-board-toolbar`;
996
1105
  this.moveHandle = new EventEmitter();
997
1106
  this.adaptHandle = new EventEmitter();
@@ -999,6 +1108,12 @@ class PlaitToolbarComponent {
999
1108
  this.zoomOutHandle = new EventEmitter();
1000
1109
  this.resetZoomHandel = new EventEmitter();
1001
1110
  }
1111
+ set viewZoom(zoom) {
1112
+ this._viewZoom = Math.floor(zoom * 100);
1113
+ }
1114
+ get viewZoom() {
1115
+ return this._viewZoom;
1116
+ }
1002
1117
  dragMove() {
1003
1118
  if (this.cursorStatus !== BaseCursorStatus.move) {
1004
1119
  this.moveHandle.emit(BaseCursorStatus.move);
@@ -1047,82 +1162,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1047
1162
  type: Output
1048
1163
  }] } });
1049
1164
 
1050
- class PlaitElementComponent {
1051
- constructor(renderer2, viewContainerRef) {
1052
- this.renderer2 = renderer2;
1053
- this.viewContainerRef = viewContainerRef;
1054
- this.initialized = false;
1055
- this.selection = null;
1056
- }
1057
- ngOnInit() {
1058
- this.initialize();
1059
- this.transform(true);
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
- transform(first = false) {
1069
- if (first && this.viewport.offsetX === 0 && this.viewport.offsetY === 0) {
1070
- return;
1071
- }
1072
- this.renderer2.setAttribute(this.groupG, 'transform', `translate(${this.viewport.offsetX} ${this.viewport.offsetY})`);
1073
- }
1074
- drawElement() {
1075
- const gArray = this.board.drawElement({ elementInstance: this });
1076
- gArray.forEach(g => {
1077
- this.groupG.appendChild(g);
1078
- });
1079
- }
1080
- ngOnChanges(changes) {
1081
- const viewport = changes['viewport'];
1082
- if (this.initialized && viewport) {
1083
- this.transform();
1084
- }
1085
- if (this.initialized) {
1086
- this.board.redrawElement({ elementInstance: this }, changes);
1087
- }
1088
- }
1089
- ngOnDestroy() {
1090
- this.board.destroyElement();
1091
- this.groupG.remove();
1092
- }
1093
- }
1094
- 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 });
1095
- 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 });
1096
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitElementComponent, decorators: [{
1097
- type: Component,
1098
- args: [{
1099
- selector: 'plait-element',
1100
- template: '',
1101
- changeDetection: ChangeDetectionStrategy.OnPush
1102
- }]
1103
- }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
1104
- type: Input
1105
- }], element: [{
1106
- type: Input
1107
- }], board: [{
1108
- type: Input
1109
- }], viewport: [{
1110
- type: Input
1111
- }], selection: [{
1112
- type: Input
1113
- }], host: [{
1114
- type: Input
1115
- }] } });
1116
-
1117
1165
  class PlaitBoardComponent {
1118
- constructor(cdr, elementRef, renderer2) {
1166
+ constructor(cdr, renderer2, elementRef) {
1119
1167
  this.cdr = cdr;
1120
- this.elementRef = elementRef;
1121
1168
  this.renderer2 = renderer2;
1169
+ this.elementRef = elementRef;
1122
1170
  this.hasInitialized = false;
1123
1171
  this.destroy$ = new Subject();
1124
- this._viewZoom = 100;
1125
1172
  this.isMoving = false;
1173
+ this.autoFitPadding = 8;
1126
1174
  this.plaitValue = [];
1127
1175
  this.plaitPlugins = [];
1128
1176
  this.plaitReadonly = false;
@@ -1133,16 +1181,6 @@ class PlaitBoardComponent {
1133
1181
  return index;
1134
1182
  };
1135
1183
  }
1136
- get hostClass() {
1137
- return `plait-board-container ${this.board.cursor}`;
1138
- }
1139
- get viewZoom() {
1140
- const vZoom = transformZoom(this.board.viewport.zoom);
1141
- if (this._viewZoom !== vZoom) {
1142
- this._viewZoom = vZoom;
1143
- }
1144
- return vZoom;
1145
- }
1146
1184
  get isMoveMode() {
1147
1185
  return this.board.cursor === BaseCursorStatus.move;
1148
1186
  }
@@ -1153,11 +1191,14 @@ class PlaitBoardComponent {
1153
1191
  var _a;
1154
1192
  return (_a = this.board) === null || _a === void 0 ? void 0 : _a.selection;
1155
1193
  }
1194
+ get hostClass() {
1195
+ return `plait-board-container ${this.board.cursor}`;
1196
+ }
1156
1197
  get readonly() {
1157
1198
  return this.plaitReadonly;
1158
1199
  }
1159
1200
  get moving() {
1160
- return this.isMoving;
1201
+ return this.board.cursor === BaseCursorStatus.move && this.isMoving;
1161
1202
  }
1162
1203
  get focused() {
1163
1204
  return this.isFocused;
@@ -1167,7 +1208,6 @@ class PlaitBoardComponent {
1167
1208
  HOST_TO_ROUGH_SVG.set(this.host, roughSVG);
1168
1209
  this.initializePlugins();
1169
1210
  this.initializeEvents();
1170
- this.updateViewport();
1171
1211
  PLAIT_BOARD_TO_COMPONENT.set(this.board, this);
1172
1212
  BOARD_TO_ON_CHANGE.set(this.board, () => {
1173
1213
  this.cdr.detectChanges();
@@ -1177,10 +1217,7 @@ class PlaitBoardComponent {
1177
1217
  viewport: this.board.viewport,
1178
1218
  selection: this.board.selection
1179
1219
  };
1180
- // update viewBox
1181
- if (this.board.operations.some(op => PlaitOperation.isSetViewportOperation(op))) {
1182
- this.updateViewport();
1183
- }
1220
+ this.updateViewport();
1184
1221
  this.plaitChange.emit(changeEvent);
1185
1222
  });
1186
1223
  this.hasInitialized = true;
@@ -1194,6 +1231,8 @@ class PlaitBoardComponent {
1194
1231
  }
1195
1232
  ngAfterViewInit() {
1196
1233
  this.plaitBoardInitialized.emit(this.board);
1234
+ this.initContainerSize();
1235
+ this.updateViewport();
1197
1236
  }
1198
1237
  initializePlugins() {
1199
1238
  const options = { readonly: this.plaitReadonly, allowClearBoard: this.plaitAllowClearBoard };
@@ -1227,15 +1266,6 @@ class PlaitBoardComponent {
1227
1266
  .subscribe((event) => {
1228
1267
  this.board.dblclick(event);
1229
1268
  });
1230
- fromEvent(this.host, 'wheel')
1231
- .pipe(takeUntil(this.destroy$))
1232
- .subscribe((event) => {
1233
- if (this.isFocused) {
1234
- event.preventDefault();
1235
- const viewport = this.board.viewport;
1236
- 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 }));
1237
- }
1238
- });
1239
1269
  fromEvent(document, 'keydown')
1240
1270
  .pipe(takeUntil(this.destroy$), filter(() => {
1241
1271
  return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
@@ -1279,19 +1309,71 @@ class PlaitBoardComponent {
1279
1309
  (_a = this.board) === null || _a === void 0 ? void 0 : _a.setFragment(event.clipboardData);
1280
1310
  (_b = this.board) === null || _b === void 0 ? void 0 : _b.deleteFragment(event.clipboardData);
1281
1311
  });
1312
+ fromEvent(this.contentContainer.nativeElement, 'scroll')
1313
+ .pipe(takeUntil(this.destroy$), filter(() => {
1314
+ return !!this.isFocused;
1315
+ }))
1316
+ .subscribe((event) => {
1317
+ const scrollLeft = event.target.scrollLeft;
1318
+ const scrollTop = event.target.scrollTop;
1319
+ this.getScrollOffset(scrollLeft, scrollTop);
1320
+ this.setScroll(scrollLeft, scrollTop);
1321
+ });
1282
1322
  window.onresize = () => {
1283
- this.refreshViewport();
1323
+ this.updateViewport();
1284
1324
  };
1285
1325
  }
1286
- refreshViewport() {
1326
+ initContainerSize() {
1327
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'overflow', 'auto');
1328
+ this.resizeViewport();
1329
+ }
1330
+ resizeViewport() {
1287
1331
  var _a;
1288
- const viewBoxModel = getViewBox(this.board);
1289
- const viewBoxValues = (_a = this.host.getAttribute('viewBox')) === null || _a === void 0 ? void 0 : _a.split(',');
1290
- this.renderer2.setAttribute(this.host, 'viewBox', `${viewBoxValues[0].trim()}, ${viewBoxValues[1].trim()}, ${viewBoxModel.width}, ${viewBoxModel.height}`);
1332
+ const container = (_a = this.elementRef.nativeElement) === null || _a === void 0 ? void 0 : _a.parentElement;
1333
+ const containerRect = container === null || container === void 0 ? void 0 : container.getBoundingClientRect();
1334
+ const width = `${containerRect.width + SCROLL_BAR_WIDTH}px`;
1335
+ const height = `${containerRect.height + SCROLL_BAR_WIDTH}px`;
1336
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'width', width);
1337
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'height', height);
1338
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'maxWidth', width);
1339
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'maxHeight', height);
1340
+ }
1341
+ setScroll(left, top) {
1342
+ const container = this.contentContainer.nativeElement;
1343
+ container.scrollTo({
1344
+ top,
1345
+ left
1346
+ });
1347
+ }
1348
+ getScrollOffset(left, top) {
1349
+ const viewportBox = getViewportClientBox(this.board);
1350
+ const viewBox = getViewBox(this.board);
1351
+ const scrollLeftRatio = left / (viewBox.viewportWidth - viewportBox.width);
1352
+ const scrollTopRatio = top / (viewBox.viewportHeight - viewportBox.height);
1353
+ this.setViewport({
1354
+ offsetXRatio: scrollLeftRatio,
1355
+ offsetYRatio: scrollTopRatio
1356
+ });
1357
+ }
1358
+ viewportChange(viewBox) {
1359
+ const offsetXRatio = this.board.viewport.offsetXRatio;
1360
+ const offsetYRatio = this.board.viewport.offsetYRatio;
1361
+ const viewportBox = getViewportClientBox(this.board);
1362
+ const { minX, minY, width, height, viewportWidth, viewportHeight } = viewBox;
1363
+ const box = [minX, minY, width, height];
1364
+ const scrollLeft = (viewportWidth - viewportBox.width) * offsetXRatio;
1365
+ const scrollTop = (viewportHeight - viewportBox.height) * offsetYRatio;
1366
+ this.resizeViewport();
1367
+ this.renderer2.setStyle(this.host, 'display', 'block');
1368
+ this.renderer2.setStyle(this.host, 'width', `${viewportWidth}px`);
1369
+ this.renderer2.setStyle(this.host, 'height', `${viewportHeight}px`);
1370
+ this.renderer2.setStyle(this.host, 'cursor', this.plaitReadonly ? 'grab' : 'default');
1371
+ this.renderer2.setAttribute(this.host, 'viewBox', box.join());
1372
+ this.setScroll(scrollLeft, scrollTop);
1291
1373
  }
1292
1374
  updateViewport() {
1293
1375
  const viewBox = getViewBox(this.board);
1294
- this.renderer2.setAttribute(this.host, 'viewBox', `${viewBox.minX}, ${viewBox.minY}, ${viewBox.width}, ${viewBox.height}`);
1376
+ this.viewportChange(viewBox);
1295
1377
  }
1296
1378
  // 拖拽模式
1297
1379
  changeMoveMode(cursorStatus) {
@@ -1300,35 +1382,44 @@ class PlaitBoardComponent {
1300
1382
  }
1301
1383
  // 适应画布
1302
1384
  adaptHandle() {
1303
- var _a;
1304
- const viewport = (_a = this.board) === null || _a === void 0 ? void 0 : _a.viewport;
1305
- Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), { offsetX: 0, offsetY: 0 }));
1306
- this.resetZoomHandel();
1385
+ const viewportBox = getViewportClientBox(this.board);
1386
+ const rootGroup = this.host.firstChild;
1387
+ const rootGroupBox = rootGroup.getBBox();
1388
+ const viewportWidth = viewportBox.width - 2 * this.autoFitPadding;
1389
+ const viewportHeight = viewportBox.height - 2 * this.autoFitPadding;
1390
+ let zoom = this.board.viewport.zoom;
1391
+ if (viewportWidth < rootGroupBox.width || viewportHeight < rootGroupBox.height) {
1392
+ zoom = Math.min(viewportWidth / rootGroupBox.width, viewportHeight / rootGroupBox.height);
1393
+ }
1394
+ this.setViewport({
1395
+ zoom: calculateZoom(zoom),
1396
+ offsetXRatio: 0.5,
1397
+ offsetYRatio: 0.5
1398
+ });
1307
1399
  }
1308
1400
  // 放大
1309
1401
  zoomInHandle() {
1310
- if (this._viewZoom >= 400) {
1311
- return;
1312
- }
1313
- this._viewZoom += 10;
1314
- this.zoomChange();
1402
+ const zoom = this.board.viewport.zoom;
1403
+ this.setViewport({
1404
+ zoom: calculateZoom(zoom + 0.1)
1405
+ });
1315
1406
  }
1316
1407
  // 缩小
1317
1408
  zoomOutHandle() {
1318
- if (this._viewZoom <= 20) {
1319
- return;
1320
- }
1321
- this._viewZoom -= 10;
1322
- this.zoomChange();
1409
+ const zoom = this.board.viewport.zoom;
1410
+ this.setViewport({
1411
+ zoom: calculateZoom(zoom - 0.1)
1412
+ });
1323
1413
  }
1324
1414
  resetZoomHandel() {
1325
- this._viewZoom = 100;
1326
- this.zoomChange();
1415
+ this.setViewport({
1416
+ zoom: 1
1417
+ });
1327
1418
  }
1328
- zoomChange() {
1419
+ setViewport(options) {
1329
1420
  var _a;
1330
1421
  const viewport = (_a = this.board) === null || _a === void 0 ? void 0 : _a.viewport;
1331
- Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), { zoom: transformViewZoom(this._viewZoom) }));
1422
+ Transforms.setViewport(this.board, Object.assign(Object.assign({}, viewport), options));
1332
1423
  }
1333
1424
  ngOnDestroy() {
1334
1425
  this.destroy$.next();
@@ -1339,69 +1430,64 @@ class PlaitBoardComponent {
1339
1430
  this.isMoving = isMoving;
1340
1431
  }
1341
1432
  }
1342
- PlaitBoardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
1343
- 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: `
1344
- <svg #svg width="100%" height="100%" style="position: relative"></svg>
1433
+ 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 });
1434
+ 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 }, { propertyName: "contentContainer", first: true, predicate: ["container"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: `
1435
+ <div class="container" #container>
1436
+ <svg #svg width="100%" height="100%" style="position: relative"></svg>
1437
+ <plait-element
1438
+ *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1439
+ [index]="index"
1440
+ [element]="item"
1441
+ [board]="board"
1442
+ [viewport]="board.viewport"
1443
+ [selection]="board.selection"
1444
+ [host]="host"
1445
+ ></plait-element>
1446
+ </div>
1345
1447
  <plait-toolbar
1346
1448
  *ngIf="isFocused && !toolbarTemplateRef"
1347
1449
  [cursorStatus]="board.cursor"
1348
- [viewZoom]="viewZoom"
1450
+ [viewZoom]="board.viewport!.zoom"
1349
1451
  (moveHandle)="changeMoveMode($event)"
1350
1452
  (adaptHandle)="adaptHandle()"
1351
1453
  (zoomInHandle)="zoomInHandle()"
1352
1454
  (zoomOutHandle)="zoomOutHandle()"
1353
1455
  (resetZoomHandel)="resetZoomHandel()"
1354
1456
  ></plait-toolbar>
1355
- <plait-element
1356
- *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1357
- [index]="index"
1358
- [element]="item"
1359
- [board]="board"
1360
- [viewport]="board.viewport"
1361
- [selection]="board.selection"
1362
- [host]="host"
1363
- ></plait-element>
1364
1457
  <ng-content></ng-content>
1365
- `, 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 });
1458
+ `, 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 });
1366
1459
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitBoardComponent, decorators: [{
1367
1460
  type: Component,
1368
1461
  args: [{
1369
1462
  selector: 'plait-board',
1370
1463
  template: `
1371
- <svg #svg width="100%" height="100%" style="position: relative"></svg>
1464
+ <div class="container" #container>
1465
+ <svg #svg width="100%" height="100%" style="position: relative"></svg>
1466
+ <plait-element
1467
+ *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1468
+ [index]="index"
1469
+ [element]="item"
1470
+ [board]="board"
1471
+ [viewport]="board.viewport"
1472
+ [selection]="board.selection"
1473
+ [host]="host"
1474
+ ></plait-element>
1475
+ </div>
1372
1476
  <plait-toolbar
1373
1477
  *ngIf="isFocused && !toolbarTemplateRef"
1374
1478
  [cursorStatus]="board.cursor"
1375
- [viewZoom]="viewZoom"
1479
+ [viewZoom]="board.viewport!.zoom"
1376
1480
  (moveHandle)="changeMoveMode($event)"
1377
1481
  (adaptHandle)="adaptHandle()"
1378
1482
  (zoomInHandle)="zoomInHandle()"
1379
1483
  (zoomOutHandle)="zoomOutHandle()"
1380
1484
  (resetZoomHandel)="resetZoomHandel()"
1381
1485
  ></plait-toolbar>
1382
- <plait-element
1383
- *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1384
- [index]="index"
1385
- [element]="item"
1386
- [board]="board"
1387
- [viewport]="board.viewport"
1388
- [selection]="board.selection"
1389
- [host]="host"
1390
- ></plait-element>
1391
1486
  <ng-content></ng-content>
1392
1487
  `,
1393
1488
  changeDetection: ChangeDetectionStrategy.OnPush
1394
1489
  }]
1395
- }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { hostClass: [{
1396
- type: HostBinding,
1397
- args: ['class']
1398
- }], svg: [{
1399
- type: ViewChild,
1400
- args: ['svg', { static: true }]
1401
- }], toolbarTemplateRef: [{
1402
- type: ContentChild,
1403
- args: ['plaitToolbar']
1404
- }], plaitValue: [{
1490
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { plaitValue: [{
1405
1491
  type: Input
1406
1492
  }], plaitViewport: [{
1407
1493
  type: Input
@@ -1415,6 +1501,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1415
1501
  type: Output
1416
1502
  }], plaitBoardInitialized: [{
1417
1503
  type: Output
1504
+ }], hostClass: [{
1505
+ type: HostBinding,
1506
+ args: ['class']
1418
1507
  }], readonly: [{
1419
1508
  type: HostBinding,
1420
1509
  args: ['class.readonly']
@@ -1424,6 +1513,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1424
1513
  }], focused: [{
1425
1514
  type: HostBinding,
1426
1515
  args: ['class.focused']
1516
+ }], svg: [{
1517
+ type: ViewChild,
1518
+ args: ['svg', { static: true }]
1519
+ }], toolbarTemplateRef: [{
1520
+ type: ContentChild,
1521
+ args: ['plaitToolbar']
1522
+ }], contentContainer: [{
1523
+ type: ViewChild,
1524
+ args: ['container', { read: ElementRef, static: true }]
1427
1525
  }] } });
1428
1526
 
1429
1527
  const COMPONENTS = [PlaitBoardComponent, PlaitElementComponent, PlaitToolbarComponent];
@@ -1441,8 +1539,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1441
1539
  }]
1442
1540
  }] });
1443
1541
 
1444
- const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
1445
-
1446
1542
  /*
1447
1543
  * Public API Surface of plait
1448
1544
  */
@@ -1451,5 +1547,5 @@ const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
1451
1547
  * Generated bundle index. Do not edit.
1452
1548
  */
1453
1549
 
1454
- 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 };
1550
+ 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 };
1455
1551
  //# sourceMappingURL=plait-core.mjs.map