@plait/core 0.0.42 → 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";
@@ -255,8 +258,8 @@ function isNullOrUndefined(value) {
255
258
 
256
259
  const Viewport = {
257
260
  isViewport: (value) => {
258
- return (!isNullOrUndefined(value.offsetX) &&
259
- !isNullOrUndefined(value.offsetY) &&
261
+ return (!isNullOrUndefined(value.offsetXRatio) &&
262
+ !isNullOrUndefined(value.offsetYRatio) &&
260
263
  !isNullOrUndefined(value.zoom) &&
261
264
  !isNullOrUndefined(value.viewBackgroundColor));
262
265
  }
@@ -265,13 +268,6 @@ const Viewport = {
265
268
  const SAVING = new WeakMap();
266
269
  const MERGING = new WeakMap();
267
270
 
268
- // record richtext type status
269
- const FLUSHING = new WeakMap();
270
- const IS_TEXT_EDITABLE = new WeakMap();
271
- const BOARD_TO_ON_CHANGE = new WeakMap();
272
- const HOST_TO_ROUGH_SVG = new WeakMap();
273
- const PLAIT_BOARD_TO_COMPONENT = new WeakMap();
274
-
275
271
  const applyToDraft = (board, selection, viewport, op) => {
276
272
  switch (op.type) {
277
273
  case 'insert_node': {
@@ -466,12 +462,19 @@ const Transforms = {
466
462
  ...NodeTransforms
467
463
  };
468
464
 
465
+ // record richtext type status
466
+ const FLUSHING = new WeakMap();
467
+ const IS_TEXT_EDITABLE = new WeakMap();
468
+ const BOARD_TO_ON_CHANGE = new WeakMap();
469
+ const HOST_TO_ROUGH_SVG = new WeakMap();
470
+ const PLAIT_BOARD_TO_COMPONENT = new WeakMap();
471
+
469
472
  function createBoard(host, children, options) {
470
473
  const board = {
471
474
  host,
472
475
  viewport: {
473
- offsetX: 0,
474
- offsetY: 0,
476
+ offsetXRatio: 0.5,
477
+ offsetYRatio: 0.5,
475
478
  zoom: 1,
476
479
  viewBackgroundColor: '#000'
477
480
  },
@@ -729,22 +732,68 @@ function transformPoints(board, points) {
729
732
  return newPoints;
730
733
  }
731
734
  function transformPoint(board, point) {
732
- const { width, height } = board.host.getBoundingClientRect();
733
735
  const viewBox = getViewBox(board);
734
- let x = (point[0] / width) * viewBox.width + viewBox.minX;
735
- let y = (point[1] / height) * viewBox.height + viewBox.minY;
736
- const newPoint = [x - board.viewport.offsetX, y - board.viewport.offsetY];
736
+ const x = (point[0] / viewBox.viewportWidth) * viewBox.width + viewBox.minX;
737
+ const y = (point[1] / viewBox.viewportHeight) * viewBox.height + viewBox.minY;
738
+ const newPoint = [x, y];
737
739
  return newPoint;
738
740
  }
739
741
  function getViewBox(board) {
740
- const { width, height } = board.host.getBoundingClientRect();
741
- const scaleWidth = (board.viewport.zoom - 1) * width;
742
- const scaleHeight = (board.viewport.zoom - 1) * height;
743
- const viewBoxWidth = width - scaleWidth;
744
- const viewBoxHeight = height - scaleHeight;
745
- const minX = scaleWidth / 2;
746
- const minY = scaleHeight / 2;
747
- return { minX, minY: minY, width: viewBoxWidth, height: viewBoxHeight };
742
+ const viewportBox = getViewportClientBox(board);
743
+ const rootGroupBBox = calculateBBox(board);
744
+ const padding = [viewportBox.height / 2, viewportBox.width / 2];
745
+ const zoom = board.viewport.zoom;
746
+ const minX = rootGroupBBox.left - padding[1] / zoom;
747
+ const minY = rootGroupBBox.top - padding[0] / zoom;
748
+ const viewportWidth = (rootGroupBBox.right - rootGroupBBox.left) * zoom + 2 * padding[1];
749
+ const viewportHeight = (rootGroupBBox.bottom - rootGroupBBox.top) * zoom + 2 * padding[0];
750
+ const width = viewportWidth / zoom;
751
+ const height = viewportHeight / zoom;
752
+ return { minX, minY, width, height, viewportWidth, viewportHeight };
753
+ }
754
+ function getViewportClientBox(board) {
755
+ const container = board.host?.parentElement;
756
+ const containerRect = container?.getBoundingClientRect();
757
+ const width = containerRect.width - SCROLL_BAR_WIDTH;
758
+ const height = containerRect.height - SCROLL_BAR_WIDTH;
759
+ return {
760
+ width,
761
+ height
762
+ };
763
+ }
764
+ function calculateBBox(board) {
765
+ const viewportBox = getViewportClientBox(board);
766
+ const rootGroup = board.host.firstChild;
767
+ const zoom = board.viewport.zoom;
768
+ const rootGroupBox = rootGroup.getBBox();
769
+ let box = {};
770
+ const containerWidth = viewportBox.width / zoom;
771
+ const containerHeight = viewportBox.height / zoom;
772
+ if (rootGroupBox.width < containerWidth) {
773
+ const offsetX = rootGroupBox.x + rootGroupBox.width / 2;
774
+ const containerX = containerWidth / 2;
775
+ box.left = offsetX - containerX;
776
+ box.right = offsetX + containerX;
777
+ }
778
+ else {
779
+ box.left = rootGroupBox.x;
780
+ box.right = rootGroupBox.x + rootGroupBox.width;
781
+ }
782
+ if (rootGroupBox.height < containerHeight) {
783
+ const offsetY = rootGroupBox.y + rootGroupBox.height / 2;
784
+ const containerY = containerHeight / 2;
785
+ box.top = offsetY - containerY;
786
+ box.bottom = offsetY + containerY;
787
+ }
788
+ else {
789
+ box.top = rootGroupBox.y;
790
+ box.bottom = rootGroupBox.y + rootGroupBox.height;
791
+ }
792
+ // 在新的缩放比容器宽高下的内容盒子位置
793
+ return box;
794
+ }
795
+ function calculateZoom(zoom, minZoom = 0.2, maxZoom = 4) {
796
+ return zoom < minZoom ? minZoom : zoom > maxZoom ? maxZoom : zoom;
748
797
  }
749
798
  function isNoSelectionElement(e) {
750
799
  return e.target?.closest('.plait-board-attached');
@@ -938,12 +987,6 @@ function withMove(board) {
938
987
  board.mousemove = (event) => {
939
988
  const boardComponent = PLAIT_BOARD_TO_COMPONENT.get(board);
940
989
  if (board.cursor === BaseCursorStatus.move && board.selection && boardComponent.isMoving) {
941
- const viewport = board?.viewport;
942
- Transforms.setViewport(board, {
943
- ...viewport,
944
- offsetX: viewport.offsetX + ((event.x - plaitBoardMove.x) * 100) / transformZoom(board.viewport.zoom),
945
- offsetY: viewport.offsetY + ((event.y - plaitBoardMove.y) * 100) / transformZoom(board.viewport.zoom)
946
- });
947
990
  plaitBoardMove.x = event.x;
948
991
  plaitBoardMove.y = event.y;
949
992
  }
@@ -1021,8 +1064,65 @@ function withSelection(board) {
1021
1064
  return board;
1022
1065
  }
1023
1066
 
1067
+ class PlaitElementComponent {
1068
+ constructor(renderer2, viewContainerRef) {
1069
+ this.renderer2 = renderer2;
1070
+ this.viewContainerRef = viewContainerRef;
1071
+ this.initialized = false;
1072
+ this.selection = null;
1073
+ }
1074
+ ngOnInit() {
1075
+ this.initialize();
1076
+ this.drawElement();
1077
+ }
1078
+ initialize() {
1079
+ this.initialized = true;
1080
+ this.groupG = createG();
1081
+ this.renderer2.setAttribute(this.groupG, 'plait-element-group', this.index.toString());
1082
+ this.host.append(this.groupG);
1083
+ }
1084
+ drawElement() {
1085
+ const gArray = this.board.drawElement({ elementInstance: this });
1086
+ gArray.forEach(g => {
1087
+ this.groupG.appendChild(g);
1088
+ });
1089
+ }
1090
+ ngOnChanges(changes) {
1091
+ if (this.initialized) {
1092
+ this.board.redrawElement({ elementInstance: this }, changes);
1093
+ }
1094
+ }
1095
+ ngOnDestroy() {
1096
+ this.board.destroyElement();
1097
+ this.groupG.remove();
1098
+ }
1099
+ }
1100
+ 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 });
1101
+ 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 });
1102
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitElementComponent, decorators: [{
1103
+ type: Component,
1104
+ args: [{
1105
+ selector: 'plait-element',
1106
+ template: '',
1107
+ changeDetection: ChangeDetectionStrategy.OnPush
1108
+ }]
1109
+ }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
1110
+ type: Input
1111
+ }], element: [{
1112
+ type: Input
1113
+ }], board: [{
1114
+ type: Input
1115
+ }], viewport: [{
1116
+ type: Input
1117
+ }], selection: [{
1118
+ type: Input
1119
+ }], host: [{
1120
+ type: Input
1121
+ }] } });
1122
+
1024
1123
  class PlaitToolbarComponent {
1025
1124
  constructor() {
1125
+ this._viewZoom = 100;
1026
1126
  this.hostClass = `plait-board-toolbar`;
1027
1127
  this.moveHandle = new EventEmitter();
1028
1128
  this.adaptHandle = new EventEmitter();
@@ -1030,6 +1130,12 @@ class PlaitToolbarComponent {
1030
1130
  this.zoomOutHandle = new EventEmitter();
1031
1131
  this.resetZoomHandel = new EventEmitter();
1032
1132
  }
1133
+ set viewZoom(zoom) {
1134
+ this._viewZoom = Math.floor(zoom * 100);
1135
+ }
1136
+ get viewZoom() {
1137
+ return this._viewZoom;
1138
+ }
1033
1139
  dragMove() {
1034
1140
  if (this.cursorStatus !== BaseCursorStatus.move) {
1035
1141
  this.moveHandle.emit(BaseCursorStatus.move);
@@ -1078,81 +1184,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1078
1184
  type: Output
1079
1185
  }] } });
1080
1186
 
1081
- class PlaitElementComponent {
1082
- constructor(renderer2, viewContainerRef) {
1083
- this.renderer2 = renderer2;
1084
- this.viewContainerRef = viewContainerRef;
1085
- this.initialized = false;
1086
- this.selection = null;
1087
- }
1088
- ngOnInit() {
1089
- this.initialize();
1090
- this.transform(true);
1091
- this.drawElement();
1092
- }
1093
- initialize() {
1094
- this.initialized = true;
1095
- this.groupG = createG();
1096
- this.renderer2.setAttribute(this.groupG, 'plait-element-group', this.index.toString());
1097
- this.host.append(this.groupG);
1098
- }
1099
- transform(first = false) {
1100
- if (first && this.viewport.offsetX === 0 && this.viewport.offsetY === 0) {
1101
- return;
1102
- }
1103
- this.renderer2.setAttribute(this.groupG, 'transform', `translate(${this.viewport.offsetX} ${this.viewport.offsetY})`);
1104
- }
1105
- drawElement() {
1106
- const gArray = this.board.drawElement({ elementInstance: this });
1107
- gArray.forEach(g => {
1108
- this.groupG.appendChild(g);
1109
- });
1110
- }
1111
- ngOnChanges(changes) {
1112
- const viewport = changes['viewport'];
1113
- if (this.initialized && viewport) {
1114
- this.transform();
1115
- }
1116
- if (this.initialized) {
1117
- this.board.redrawElement({ elementInstance: this }, changes);
1118
- }
1119
- }
1120
- ngOnDestroy() {
1121
- this.board.destroyElement();
1122
- this.groupG.remove();
1123
- }
1124
- }
1125
- 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 });
1126
- 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 });
1127
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitElementComponent, decorators: [{
1128
- type: Component,
1129
- args: [{
1130
- selector: 'plait-element',
1131
- template: '',
1132
- changeDetection: ChangeDetectionStrategy.OnPush
1133
- }]
1134
- }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
1135
- type: Input
1136
- }], element: [{
1137
- type: Input
1138
- }], board: [{
1139
- type: Input
1140
- }], viewport: [{
1141
- type: Input
1142
- }], selection: [{
1143
- type: Input
1144
- }], host: [{
1145
- type: Input
1146
- }] } });
1147
-
1148
1187
  class PlaitBoardComponent {
1149
- constructor(cdr, renderer2) {
1188
+ constructor(cdr, renderer2, elementRef) {
1150
1189
  this.cdr = cdr;
1151
1190
  this.renderer2 = renderer2;
1191
+ this.elementRef = elementRef;
1152
1192
  this.hasInitialized = false;
1153
1193
  this.destroy$ = new Subject();
1154
- this._viewZoom = 100;
1155
1194
  this.isMoving = false;
1195
+ this.autoFitPadding = 8;
1156
1196
  this.plaitValue = [];
1157
1197
  this.plaitPlugins = [];
1158
1198
  this.plaitReadonly = false;
@@ -1163,16 +1203,6 @@ class PlaitBoardComponent {
1163
1203
  return index;
1164
1204
  };
1165
1205
  }
1166
- get hostClass() {
1167
- return `plait-board-container ${this.board.cursor}`;
1168
- }
1169
- get viewZoom() {
1170
- const vZoom = transformZoom(this.board.viewport.zoom);
1171
- if (this._viewZoom !== vZoom) {
1172
- this._viewZoom = vZoom;
1173
- }
1174
- return vZoom;
1175
- }
1176
1206
  get isMoveMode() {
1177
1207
  return this.board.cursor === BaseCursorStatus.move;
1178
1208
  }
@@ -1182,6 +1212,9 @@ class PlaitBoardComponent {
1182
1212
  get isFocused() {
1183
1213
  return this.board?.selection;
1184
1214
  }
1215
+ get hostClass() {
1216
+ return `plait-board-container ${this.board.cursor}`;
1217
+ }
1185
1218
  get readonly() {
1186
1219
  return this.plaitReadonly;
1187
1220
  }
@@ -1196,7 +1229,6 @@ class PlaitBoardComponent {
1196
1229
  HOST_TO_ROUGH_SVG.set(this.host, roughSVG);
1197
1230
  this.initializePlugins();
1198
1231
  this.initializeEvents();
1199
- this.updateViewport();
1200
1232
  PLAIT_BOARD_TO_COMPONENT.set(this.board, this);
1201
1233
  BOARD_TO_ON_CHANGE.set(this.board, () => {
1202
1234
  this.cdr.detectChanges();
@@ -1206,10 +1238,7 @@ class PlaitBoardComponent {
1206
1238
  viewport: this.board.viewport,
1207
1239
  selection: this.board.selection
1208
1240
  };
1209
- // update viewBox
1210
- if (this.board.operations.some(op => PlaitOperation.isSetViewportOperation(op))) {
1211
- this.updateViewport();
1212
- }
1241
+ this.updateViewport();
1213
1242
  this.plaitChange.emit(changeEvent);
1214
1243
  });
1215
1244
  this.hasInitialized = true;
@@ -1223,6 +1252,8 @@ class PlaitBoardComponent {
1223
1252
  }
1224
1253
  ngAfterViewInit() {
1225
1254
  this.plaitBoardInitialized.emit(this.board);
1255
+ this.initContainerSize();
1256
+ this.updateViewport();
1226
1257
  }
1227
1258
  initializePlugins() {
1228
1259
  const options = { readonly: this.plaitReadonly, allowClearBoard: this.plaitAllowClearBoard };
@@ -1256,19 +1287,6 @@ class PlaitBoardComponent {
1256
1287
  .subscribe((event) => {
1257
1288
  this.board.dblclick(event);
1258
1289
  });
1259
- fromEvent(this.host, 'wheel')
1260
- .pipe(takeUntil(this.destroy$))
1261
- .subscribe((event) => {
1262
- if (this.isFocused) {
1263
- event.preventDefault();
1264
- const viewport = this.board.viewport;
1265
- Transforms.setViewport(this.board, {
1266
- ...viewport,
1267
- offsetX: viewport?.offsetX - event.deltaX,
1268
- offsetY: viewport?.offsetY - event.deltaY
1269
- });
1270
- }
1271
- });
1272
1290
  fromEvent(document, 'keydown')
1273
1291
  .pipe(takeUntil(this.destroy$), filter(() => {
1274
1292
  return !IS_TEXT_EDITABLE.get(this.board) && !!this.board.selection;
@@ -1307,18 +1325,70 @@ class PlaitBoardComponent {
1307
1325
  this.board?.setFragment(event.clipboardData);
1308
1326
  this.board?.deleteFragment(event.clipboardData);
1309
1327
  });
1328
+ fromEvent(this.contentContainer.nativeElement, 'scroll')
1329
+ .pipe(takeUntil(this.destroy$), filter(() => {
1330
+ return !!this.isFocused;
1331
+ }))
1332
+ .subscribe((event) => {
1333
+ const scrollLeft = event.target.scrollLeft;
1334
+ const scrollTop = event.target.scrollTop;
1335
+ this.getScrollOffset(scrollLeft, scrollTop);
1336
+ this.setScroll(scrollLeft, scrollTop);
1337
+ });
1310
1338
  window.onresize = () => {
1311
- this.refreshViewport();
1339
+ this.updateViewport();
1312
1340
  };
1313
1341
  }
1314
- refreshViewport() {
1315
- const viewBoxModel = getViewBox(this.board);
1316
- const viewBoxValues = this.host.getAttribute('viewBox')?.split(',');
1317
- this.renderer2.setAttribute(this.host, 'viewBox', `${viewBoxValues[0].trim()}, ${viewBoxValues[1].trim()}, ${viewBoxModel.width}, ${viewBoxModel.height}`);
1342
+ initContainerSize() {
1343
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'overflow', 'auto');
1344
+ this.resizeViewport();
1345
+ }
1346
+ resizeViewport() {
1347
+ const container = this.elementRef.nativeElement?.parentElement;
1348
+ const containerRect = container?.getBoundingClientRect();
1349
+ const width = `${containerRect.width + SCROLL_BAR_WIDTH}px`;
1350
+ const height = `${containerRect.height + SCROLL_BAR_WIDTH}px`;
1351
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'width', width);
1352
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'height', height);
1353
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'maxWidth', width);
1354
+ this.renderer2.setStyle(this.contentContainer.nativeElement, 'maxHeight', height);
1355
+ }
1356
+ setScroll(left, top) {
1357
+ const container = this.contentContainer.nativeElement;
1358
+ container.scrollTo({
1359
+ top,
1360
+ left
1361
+ });
1362
+ }
1363
+ getScrollOffset(left, top) {
1364
+ const viewportBox = getViewportClientBox(this.board);
1365
+ const viewBox = getViewBox(this.board);
1366
+ const scrollLeftRatio = left / (viewBox.viewportWidth - viewportBox.width);
1367
+ const scrollTopRatio = top / (viewBox.viewportHeight - viewportBox.height);
1368
+ this.setViewport({
1369
+ offsetXRatio: scrollLeftRatio,
1370
+ offsetYRatio: scrollTopRatio
1371
+ });
1372
+ }
1373
+ viewportChange(viewBox) {
1374
+ const offsetXRatio = this.board.viewport.offsetXRatio;
1375
+ const offsetYRatio = this.board.viewport.offsetYRatio;
1376
+ const viewportBox = getViewportClientBox(this.board);
1377
+ const { minX, minY, width, height, viewportWidth, viewportHeight } = viewBox;
1378
+ const box = [minX, minY, width, height];
1379
+ const scrollLeft = (viewportWidth - viewportBox.width) * offsetXRatio;
1380
+ const scrollTop = (viewportHeight - viewportBox.height) * offsetYRatio;
1381
+ this.resizeViewport();
1382
+ this.renderer2.setStyle(this.host, 'display', 'block');
1383
+ this.renderer2.setStyle(this.host, 'width', `${viewportWidth}px`);
1384
+ this.renderer2.setStyle(this.host, 'height', `${viewportHeight}px`);
1385
+ this.renderer2.setStyle(this.host, 'cursor', this.plaitReadonly ? 'grab' : 'default');
1386
+ this.renderer2.setAttribute(this.host, 'viewBox', box.join());
1387
+ this.setScroll(scrollLeft, scrollTop);
1318
1388
  }
1319
1389
  updateViewport() {
1320
1390
  const viewBox = getViewBox(this.board);
1321
- this.renderer2.setAttribute(this.host, 'viewBox', `${viewBox.minX}, ${viewBox.minY}, ${viewBox.width}, ${viewBox.height}`);
1391
+ this.viewportChange(viewBox);
1322
1392
  }
1323
1393
  // 拖拽模式
1324
1394
  changeMoveMode(cursorStatus) {
@@ -1327,39 +1397,45 @@ class PlaitBoardComponent {
1327
1397
  }
1328
1398
  // 适应画布
1329
1399
  adaptHandle() {
1330
- const viewport = this.board?.viewport;
1331
- Transforms.setViewport(this.board, {
1332
- ...viewport,
1333
- offsetX: 0,
1334
- offsetY: 0
1400
+ const viewportBox = getViewportClientBox(this.board);
1401
+ const rootGroup = this.host.firstChild;
1402
+ const rootGroupBox = rootGroup.getBBox();
1403
+ const viewportWidth = viewportBox.width - 2 * this.autoFitPadding;
1404
+ const viewportHeight = viewportBox.height - 2 * this.autoFitPadding;
1405
+ let zoom = this.board.viewport.zoom;
1406
+ if (viewportWidth < rootGroupBox.width || viewportHeight < rootGroupBox.height) {
1407
+ zoom = Math.min(viewportWidth / rootGroupBox.width, viewportHeight / rootGroupBox.height);
1408
+ }
1409
+ this.setViewport({
1410
+ zoom: calculateZoom(zoom),
1411
+ offsetXRatio: 0.5,
1412
+ offsetYRatio: 0.5
1335
1413
  });
1336
- this.resetZoomHandel();
1337
1414
  }
1338
1415
  // 放大
1339
1416
  zoomInHandle() {
1340
- if (this._viewZoom >= 400) {
1341
- return;
1342
- }
1343
- this._viewZoom += 10;
1344
- this.zoomChange();
1417
+ const zoom = this.board.viewport.zoom;
1418
+ this.setViewport({
1419
+ zoom: calculateZoom(zoom + 0.1)
1420
+ });
1345
1421
  }
1346
1422
  // 缩小
1347
1423
  zoomOutHandle() {
1348
- if (this._viewZoom <= 20) {
1349
- return;
1350
- }
1351
- this._viewZoom -= 10;
1352
- this.zoomChange();
1424
+ const zoom = this.board.viewport.zoom;
1425
+ this.setViewport({
1426
+ zoom: calculateZoom(zoom - 0.1)
1427
+ });
1353
1428
  }
1354
1429
  resetZoomHandel() {
1355
- this._viewZoom = 100;
1356
- this.zoomChange();
1430
+ this.setViewport({
1431
+ zoom: 1
1432
+ });
1357
1433
  }
1358
- zoomChange() {
1434
+ setViewport(options) {
1359
1435
  const viewport = this.board?.viewport;
1360
1436
  Transforms.setViewport(this.board, {
1361
1437
  ...viewport,
1362
- zoom: transformViewZoom(this._viewZoom)
1438
+ ...options
1363
1439
  });
1364
1440
  }
1365
1441
  ngOnDestroy() {
@@ -1371,69 +1447,64 @@ class PlaitBoardComponent {
1371
1447
  this.isMoving = isMoving;
1372
1448
  }
1373
1449
  }
1374
- 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 });
1375
- 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: `
1376
- <svg #svg width="100%" height="100%" style="position: relative"></svg>
1450
+ 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 });
1451
+ 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: `
1452
+ <div class="container" #container>
1453
+ <svg #svg width="100%" height="100%" style="position: relative"></svg>
1454
+ <plait-element
1455
+ *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1456
+ [index]="index"
1457
+ [element]="item"
1458
+ [board]="board"
1459
+ [viewport]="board.viewport"
1460
+ [selection]="board.selection"
1461
+ [host]="host"
1462
+ ></plait-element>
1463
+ </div>
1377
1464
  <plait-toolbar
1378
1465
  *ngIf="isFocused && !toolbarTemplateRef"
1379
1466
  [cursorStatus]="board.cursor"
1380
- [viewZoom]="viewZoom"
1467
+ [viewZoom]="board.viewport!.zoom"
1381
1468
  (moveHandle)="changeMoveMode($event)"
1382
1469
  (adaptHandle)="adaptHandle()"
1383
1470
  (zoomInHandle)="zoomInHandle()"
1384
1471
  (zoomOutHandle)="zoomOutHandle()"
1385
1472
  (resetZoomHandel)="resetZoomHandel()"
1386
1473
  ></plait-toolbar>
1387
- <plait-element
1388
- *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1389
- [index]="index"
1390
- [element]="item"
1391
- [board]="board"
1392
- [viewport]="board.viewport"
1393
- [selection]="board.selection"
1394
- [host]="host"
1395
- ></plait-element>
1396
1474
  <ng-content></ng-content>
1397
- `, 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 });
1475
+ `, 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 });
1398
1476
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PlaitBoardComponent, decorators: [{
1399
1477
  type: Component,
1400
1478
  args: [{
1401
1479
  selector: 'plait-board',
1402
1480
  template: `
1403
- <svg #svg width="100%" height="100%" style="position: relative"></svg>
1481
+ <div class="container" #container>
1482
+ <svg #svg width="100%" height="100%" style="position: relative"></svg>
1483
+ <plait-element
1484
+ *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1485
+ [index]="index"
1486
+ [element]="item"
1487
+ [board]="board"
1488
+ [viewport]="board.viewport"
1489
+ [selection]="board.selection"
1490
+ [host]="host"
1491
+ ></plait-element>
1492
+ </div>
1404
1493
  <plait-toolbar
1405
1494
  *ngIf="isFocused && !toolbarTemplateRef"
1406
1495
  [cursorStatus]="board.cursor"
1407
- [viewZoom]="viewZoom"
1496
+ [viewZoom]="board.viewport!.zoom"
1408
1497
  (moveHandle)="changeMoveMode($event)"
1409
1498
  (adaptHandle)="adaptHandle()"
1410
1499
  (zoomInHandle)="zoomInHandle()"
1411
1500
  (zoomOutHandle)="zoomOutHandle()"
1412
1501
  (resetZoomHandel)="resetZoomHandel()"
1413
1502
  ></plait-toolbar>
1414
- <plait-element
1415
- *ngFor="let item of board.children; let index = index; trackBy: trackBy"
1416
- [index]="index"
1417
- [element]="item"
1418
- [board]="board"
1419
- [viewport]="board.viewport"
1420
- [selection]="board.selection"
1421
- [host]="host"
1422
- ></plait-element>
1423
1503
  <ng-content></ng-content>
1424
1504
  `,
1425
1505
  changeDetection: ChangeDetectionStrategy.OnPush
1426
1506
  }]
1427
- }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }]; }, propDecorators: { hostClass: [{
1428
- type: HostBinding,
1429
- args: ['class']
1430
- }], svg: [{
1431
- type: ViewChild,
1432
- args: ['svg', { static: true }]
1433
- }], toolbarTemplateRef: [{
1434
- type: ContentChild,
1435
- args: ['plaitToolbar']
1436
- }], plaitValue: [{
1507
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { plaitValue: [{
1437
1508
  type: Input
1438
1509
  }], plaitViewport: [{
1439
1510
  type: Input
@@ -1447,6 +1518,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1447
1518
  type: Output
1448
1519
  }], plaitBoardInitialized: [{
1449
1520
  type: Output
1521
+ }], hostClass: [{
1522
+ type: HostBinding,
1523
+ args: ['class']
1450
1524
  }], readonly: [{
1451
1525
  type: HostBinding,
1452
1526
  args: ['class.readonly']
@@ -1456,6 +1530,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1456
1530
  }], focused: [{
1457
1531
  type: HostBinding,
1458
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 }]
1459
1542
  }] } });
1460
1543
 
1461
1544
  const COMPONENTS = [PlaitBoardComponent, PlaitElementComponent, PlaitToolbarComponent];
@@ -1473,8 +1556,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1473
1556
  }]
1474
1557
  }] });
1475
1558
 
1476
- const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
1477
-
1478
1559
  /*
1479
1560
  * Public API Surface of plait
1480
1561
  */
@@ -1483,5 +1564,5 @@ const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
1483
1564
  * Generated bundle index. Do not edit.
1484
1565
  */
1485
1566
 
1486
- 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 };
1487
1568
  //# sourceMappingURL=plait-core.mjs.map