@netless/forge-whiteboard 0.1.6 → 0.1.9

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.
@@ -27761,7 +27761,7 @@ var ToolbarModel = class extends import_eventemitter33.default {
27761
27761
  this.root = root;
27762
27762
  this.root.observe(this.handleRootUpdate);
27763
27763
  Object.keys(defaultStyle).forEach((key) => {
27764
- if (!this.root.has(key)) {
27764
+ if (!this.root.has(key) || this.root.get(key) === void 0) {
27765
27765
  this.root.set(key, defaultStyle[key]);
27766
27766
  }
27767
27767
  });
@@ -28838,6 +28838,14 @@ var Camera = class extends import_eventemitter38.default {
28838
28838
  hasPermission;
28839
28839
  gesture;
28840
28840
  inherentScale = 1;
28841
+ maxScale;
28842
+ initSize;
28843
+ bound;
28844
+ boundTiemoutId;
28845
+ enableByMouse = true;
28846
+ enableByTouch = true;
28847
+ boundaryColor = "#F44336";
28848
+ enableBoundaryHighlight = true;
28841
28849
  get inherentMatrix() {
28842
28850
  const inherentMatrix = new this.scope.Matrix();
28843
28851
  inherentMatrix.scale(this.inherentScale, [0, 0]);
@@ -28847,8 +28855,12 @@ var Camera = class extends import_eventemitter38.default {
28847
28855
  const view = this.scope.project.view;
28848
28856
  return 1 / view.matrix.scaling.x;
28849
28857
  }
28850
- constructor(dom, userManager, scope, whiteboardAttrsMap, hasPermission, requestUserMap, paperSize, domSize) {
28858
+ constructor(initSize, maxScale, dom, userManager, scope, whiteboardAttrsMap, hasPermission, requestUserMap, paperSize, domSize) {
28851
28859
  super();
28860
+ this.maxScale = maxScale;
28861
+ this.bound = window.document.createElement("div");
28862
+ this.bound.style.cssText = `transition: box-shadow 100ms;pointer-events:none;z-index:99;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);`;
28863
+ this.initSize = initSize;
28852
28864
  this.hasPermission = hasPermission;
28853
28865
  this.paperSize = paperSize;
28854
28866
  this.domSize = domSize;
@@ -28857,6 +28869,7 @@ var Camera = class extends import_eventemitter38.default {
28857
28869
  this.requestUserMap = requestUserMap;
28858
28870
  this.userManager = userManager;
28859
28871
  this.dom = dom;
28872
+ this.dom.appendChild(this.bound);
28860
28873
  this.dom.addEventListener("wheel", this.handleWheel, { passive: false, capture: true });
28861
28874
  this.dom.addEventListener("touchstart", (e) => {
28862
28875
  e.preventDefault();
@@ -28877,17 +28890,32 @@ var Camera = class extends import_eventemitter38.default {
28877
28890
  this.whiteboardAttrsMap.observe(this.handleMainCameraChange);
28878
28891
  this.gesture = new Gesture(this.dom, this.scope);
28879
28892
  this.gesture.on("offset", (x, y) => {
28893
+ if (!this.enableByTouch) {
28894
+ return;
28895
+ }
28880
28896
  const matrix = new this.scope.Matrix();
28881
28897
  matrix.translate({ x: x * this.translateScale, y: y * this.translateScale });
28882
- this.appendViewMatrix(matrix);
28898
+ this.updateViewMatrix(matrix);
28883
28899
  });
28884
28900
  this.gesture.on("scale", (scale, center) => {
28901
+ if (!this.enableByTouch) {
28902
+ return;
28903
+ }
28885
28904
  const matrix = new this.scope.Matrix();
28886
28905
  const paperPoint = this.scope.project.view.viewToProject(center);
28887
28906
  matrix.scale(scale, paperPoint);
28888
- this.appendViewMatrix(matrix);
28907
+ this.updateViewMatrix(matrix);
28889
28908
  });
28890
28909
  }
28910
+ highlightBound() {
28911
+ if (this.enableBoundaryHighlight) {
28912
+ this.bound.style.boxShadow = `inset 0px 0px 6px 2px ${this.boundaryColor}`;
28913
+ window.clearTimeout(this.boundTiemoutId);
28914
+ this.boundTiemoutId = window.setTimeout(() => {
28915
+ this.bound.style.boxShadow = `none`;
28916
+ }, 100);
28917
+ }
28918
+ }
28891
28919
  updateInherentScale(scale) {
28892
28920
  this.inherentScale = scale;
28893
28921
  }
@@ -28904,6 +28932,9 @@ var Camera = class extends import_eventemitter38.default {
28904
28932
  return new this.scope.Matrix(matrixValue);
28905
28933
  }
28906
28934
  triggerZoom() {
28935
+ const [width, height] = this.domSize();
28936
+ this.bound.style.width = `${width}px`;
28937
+ this.bound.style.height = `${height}px`;
28907
28938
  this.emit("zoom", this.inherentMatrix.appended(this.getActiveMatrix()));
28908
28939
  }
28909
28940
  resetViewMatrixToFlow(userId) {
@@ -28982,29 +29013,89 @@ var Camera = class extends import_eventemitter38.default {
28982
29013
  }
28983
29014
  }
28984
29015
  };
28985
- appendViewMatrix(matrix) {
29016
+ validNextMatrix(next) {
29017
+ let shouldHighlightBound = false;
29018
+ const maxTranslate = (this.maxScale - 1) / 2;
29019
+ const maxScale = maxTranslate * 2 + 1;
29020
+ const minScale = 1 / maxScale;
29021
+ if (next.a > maxScale) {
29022
+ const tx = next.tx / next.a;
29023
+ next.a = maxScale;
29024
+ next.tx = tx * maxScale;
29025
+ shouldHighlightBound = true;
29026
+ }
29027
+ if (next.a < minScale) {
29028
+ const tx = next.tx / next.a;
29029
+ next.a = minScale;
29030
+ next.tx = tx * minScale;
29031
+ shouldHighlightBound = true;
29032
+ }
29033
+ if (next.d > maxScale) {
29034
+ const ty = next.ty / next.d;
29035
+ next.d = maxScale;
29036
+ next.ty = ty * maxScale;
29037
+ shouldHighlightBound = true;
29038
+ }
29039
+ if (next.d < minScale) {
29040
+ const ty = next.ty / next.d;
29041
+ next.d = minScale;
29042
+ next.ty = ty * minScale;
29043
+ shouldHighlightBound = true;
29044
+ }
29045
+ const maxTranslateX = this.initSize.width * maxTranslate;
29046
+ if (next.tx / next.a > maxTranslateX) {
29047
+ next.tx = maxTranslateX * next.a;
29048
+ shouldHighlightBound = true;
29049
+ }
29050
+ const minTx = (this.initSize.width * (maxTranslate + 1) - this.scope.project.view.bounds.width) * -next.a;
29051
+ if (next.tx < minTx) {
29052
+ next.tx = minTx;
29053
+ shouldHighlightBound = true;
29054
+ }
29055
+ const maxTranslateY = this.initSize.height * maxTranslate;
29056
+ if (next.ty / next.d > maxTranslateY) {
29057
+ next.ty = maxTranslateY * next.d;
29058
+ shouldHighlightBound = true;
29059
+ }
29060
+ const minTy = (this.initSize.height * (maxTranslate + 1) - this.scope.project.view.bounds.height) * -next.d;
29061
+ if (next.ty < minTy) {
29062
+ next.ty = minTy;
29063
+ shouldHighlightBound = true;
29064
+ }
29065
+ if (shouldHighlightBound) {
29066
+ this.highlightBound();
29067
+ }
29068
+ return next;
29069
+ }
29070
+ updateViewMatrix(matrix, append = true) {
28986
29071
  const userMap = this.requestUserMap(this.userManager.selfId);
28987
29072
  const cameraMode = userMap.get(WhiteboardKeys.cameraMode);
28988
- if (cameraMode === "free" || cameraMode === "main") {
29073
+ let next = matrix;
29074
+ if (append) {
28989
29075
  const currentMatrixValue = userMap.get(WhiteboardKeys.viewMatrix);
28990
29076
  const current = new this.scope.Matrix(currentMatrixValue);
28991
- const next = current.appended(matrix);
28992
- if (next.scaling.x <= 3 && next.scaling.x >= 0.3) {
28993
- userMap.set(WhiteboardKeys.viewMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
29077
+ next = current.appended(matrix);
29078
+ }
29079
+ if (this.maxScale >= 1) {
29080
+ next = this.validNextMatrix(next);
29081
+ } else {
29082
+ if (!(next.scaling.x <= 3 && next.scaling.x >= 0.2) && append) {
29083
+ return;
28994
29084
  }
28995
29085
  }
29086
+ if (cameraMode === "free" || cameraMode === "main") {
29087
+ userMap.set(WhiteboardKeys.viewMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
29088
+ }
28996
29089
  if (cameraMode === "main") {
28997
29090
  if (this.hasPermission(32 /* mainView */)) {
28998
- const currentMatrixValue = this.whiteboardAttrsMap.get(WhiteboardKeys.viewMatrix);
28999
- const current = new this.scope.Matrix(currentMatrixValue);
29000
- const next = current.appended(matrix);
29001
- if (next.scaling.x <= 3 && next.scaling.x >= 0.3) {
29002
- this.whiteboardAttrsMap.set(WhiteboardKeys.viewMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
29003
- }
29091
+ this.whiteboardAttrsMap.set(WhiteboardKeys.viewMatrix, [next.a, next.b, next.c, next.d, next.tx, next.ty]);
29004
29092
  }
29005
29093
  }
29006
29094
  }
29007
29095
  handleWheel = (evt) => {
29096
+ if (!this.enableByMouse) {
29097
+ return;
29098
+ }
29008
29099
  evt.preventDefault();
29009
29100
  evt.stopImmediatePropagation();
29010
29101
  evt.stopPropagation();
@@ -29028,22 +29119,33 @@ var Camera = class extends import_eventemitter38.default {
29028
29119
  } else {
29029
29120
  scale = 1 + Math.abs(deltaY / wheelDelta);
29030
29121
  }
29122
+ scale = Math.max(0.9, scale);
29123
+ scale = Math.min(1.1, scale);
29031
29124
  matrix.scale(scale, paperPoint);
29032
- this.appendViewMatrix(matrix);
29125
+ this.updateViewMatrix(matrix);
29033
29126
  } else {
29034
29127
  const deltaX = this.lastDelta.x + evt.deltaX;
29035
29128
  const deltaY = this.lastDelta.y + evt.deltaY;
29036
29129
  const matrix = new this.scope.Matrix();
29037
29130
  matrix.translate({ x: -deltaX * window.devicePixelRatio, y: -deltaY * window.devicePixelRatio });
29038
- this.appendViewMatrix(matrix);
29131
+ this.updateViewMatrix(matrix);
29039
29132
  }
29040
29133
  this.lastTriggerTime = Date.now();
29041
29134
  this.lastDelta = { x: 0, y: 0 };
29042
29135
  };
29136
+ scale(value) {
29137
+ const matrix = new this.scope.Matrix();
29138
+ matrix.scale(value, this.scope.project.view.bounds.center);
29139
+ this.updateViewMatrix(matrix);
29140
+ }
29043
29141
  translate(offsetX, offsetY) {
29044
29142
  const matrix = new this.scope.Matrix();
29045
29143
  matrix.translate({ x: offsetX, y: offsetY });
29046
- this.appendViewMatrix(matrix);
29144
+ this.updateViewMatrix(matrix);
29145
+ }
29146
+ reset() {
29147
+ this.updateViewMatrix(new this.scope.Matrix(), false);
29148
+ this.lastDelta = { x: 0, y: 0 };
29047
29149
  }
29048
29150
  };
29049
29151
 
@@ -29152,6 +29254,22 @@ var Whiteboard = class extends import_eventemitter39.default {
29152
29254
  * 描边宽度
29153
29255
  */
29154
29256
  strokeWidth;
29257
+ /**
29258
+ * 是否允许用鼠标/触控板进行缩放和拖动画布
29259
+ */
29260
+ enableCameraByMouse;
29261
+ /**
29262
+ * 是否允许触摸屏上触摸事件进行缩放和拖动画布
29263
+ */
29264
+ enableCameraByTouch;
29265
+ /**
29266
+ * 相机超出边界时, 警示阴影的颜色, 默认 "#F44336"
29267
+ */
29268
+ cameraBoundaryColor;
29269
+ /**
29270
+ * 是否允许相机超出边界时, 警示高亮阴影, 默认 true
29271
+ */
29272
+ enableCameraBoundaryHighlight;
29155
29273
  getElementAttribute;
29156
29274
  setElementAttribute;
29157
29275
  getCurrentTool;
@@ -29193,6 +29311,21 @@ var Whiteboard = class extends import_eventemitter39.default {
29193
29311
  * 清空当前页面
29194
29312
  */
29195
29313
  clearPage;
29314
+ /**
29315
+ * 平移画布
29316
+ * @param {number} offsetX - x 轴偏移量
29317
+ * @param {number} offsetY - y 轴偏移量
29318
+ */
29319
+ translateCamera;
29320
+ /**
29321
+ * 以画布中心为固定点缩放画布
29322
+ * @param {number} scale - 缩放比例
29323
+ */
29324
+ scaleCamera;
29325
+ /**
29326
+ * 重置画布, 将画布缩放比例重置为 1, 平移量重置为 [0, 0]
29327
+ */
29328
+ resetCamera;
29196
29329
  /**
29197
29330
  * 为 userId 指定的用户设置页面, 调用需要有 `WhiteboardPermissionFlag.setOthersView` 权限,
29198
29331
  * userId 指定的用户的视角模式应为 `free`, 否则调用无效
@@ -30149,6 +30282,21 @@ var WhiteboardApplication = class extends import_forge_room3.AbstractApplication
30149
30282
  this.inputType = type;
30150
30283
  this.emitter.emit("inputTypeChange", this.inputType);
30151
30284
  };
30285
+ this.emitter.translateCamera = (offsetX, offsetY) => {
30286
+ this.camera.translate(offsetX, offsetY);
30287
+ };
30288
+ this.emitter.scaleCamera = (scale) => {
30289
+ this.camera.scale(scale);
30290
+ };
30291
+ this.emitter.resetCamera = () => {
30292
+ this.camera.reset();
30293
+ };
30294
+ this.emitter.on("error", (errorCode, errorMessage) => {
30295
+ (0, import_forge_room3.log)("WhiteboardApplicationError", {
30296
+ errorCode,
30297
+ errorMessage
30298
+ });
30299
+ });
30152
30300
  const that = this;
30153
30301
  Object.defineProperty(this.emitter, "tool", {
30154
30302
  get() {
@@ -30206,6 +30354,38 @@ var WhiteboardApplication = class extends import_forge_room3.AbstractApplication
30206
30354
  that.toolbarModel.dashArray = v;
30207
30355
  }
30208
30356
  });
30357
+ Object.defineProperty(this.emitter, "enableCameraByMouse", {
30358
+ get() {
30359
+ return that.camera.enableByMouse;
30360
+ },
30361
+ set(value) {
30362
+ that.camera.enableByMouse = value;
30363
+ }
30364
+ });
30365
+ Object.defineProperty(this.emitter, "enableCameraByTouch", {
30366
+ get() {
30367
+ return that.camera.enableByTouch;
30368
+ },
30369
+ set(value) {
30370
+ that.camera.enableByTouch = value;
30371
+ }
30372
+ });
30373
+ Object.defineProperty(this.emitter, "cameraBoundaryColor", {
30374
+ get() {
30375
+ return that.camera.boundaryColor;
30376
+ },
30377
+ set(value) {
30378
+ that.camera.boundaryColor = value;
30379
+ }
30380
+ });
30381
+ Object.defineProperty(this.emitter, "enableCameraBoundaryHighlight", {
30382
+ get() {
30383
+ return that.camera.enableBoundaryHighlight;
30384
+ },
30385
+ set(value) {
30386
+ that.camera.enableBoundaryHighlight = value;
30387
+ }
30388
+ });
30209
30389
  }
30210
30390
  userMap(userId) {
30211
30391
  return this.getMap(`user/${userId}`);
@@ -30233,7 +30413,12 @@ var WhiteboardApplication = class extends import_forge_room3.AbstractApplication
30233
30413
  );
30234
30414
  this.pageModel.on("pagesChange", this.handleLayersChange);
30235
30415
  this.pageModel.on("switchPage", this.handlePageSwitch);
30416
+ if (option.maxScaleRatio && option.maxScaleRatio < 1 && option.maxScaleRatio !== -1) {
30417
+ throw new Error(`[@netless/forge-whiteboard] invalid maxScaleRatio ${option.maxScaleRatio}`);
30418
+ }
30236
30419
  this.camera = new Camera(
30420
+ new this.paperScope.Size(option.width, option.height),
30421
+ option.maxScaleRatio ?? -1,
30237
30422
  this.rootElement,
30238
30423
  this.userManager,
30239
30424
  this.paperScope,
@@ -30294,10 +30479,19 @@ var WhiteboardApplication = class extends import_forge_room3.AbstractApplication
30294
30479
  grab: new GrabTool(this.enableToolEvent, this.getCurrentRenderableModel, this.shadowEmitter, this.paperScope, this.camera)
30295
30480
  };
30296
30481
  this.toolbarModel.on("update", (style) => {
30297
- this.paperScope.tool = this.tools[style.tool].tool;
30482
+ if (this.tools[style.tool]) {
30483
+ this.paperScope.tool = this.tools[style.tool].tool;
30484
+ } else {
30485
+ this.emitter.emit("error", 300001, `${style.tool} not supported`);
30486
+ }
30298
30487
  this.emitter.emit("toolbarStyleChange", style);
30299
30488
  });
30300
- this.paperScope.tool = this.tools[this.toolbarModel.currentTool].tool;
30489
+ if (this.tools[this.toolbarModel.currentTool]) {
30490
+ this.paperScope.tool = this.tools[this.toolbarModel.currentTool].tool;
30491
+ } else {
30492
+ this.paperScope.tool = this.tools["curve"].tool;
30493
+ (0, import_forge_room3.log)(`${this.toolbarModel.currentTool} not supported, backup to curve`);
30494
+ }
30301
30495
  this.selectElementsModel.on("elementsChange", this.handleElementsSelect);
30302
30496
  this.trashedElementsModel.on("elementsChange", this.handleElementsTrash);
30303
30497
  this.trashedElementsModel.on("removeElementForSelf", this.handleRemoveTrashedElementForSelf);
@@ -30516,7 +30710,7 @@ var WhiteboardApplication = class extends import_forge_room3.AbstractApplication
30516
30710
  getCurrentRenderableModel = () => {
30517
30711
  let layerId = this.userMap(this.userId).get(WhiteboardKeys.currentPage);
30518
30712
  if (!this.layers.has(layerId)) {
30519
- this.emitter.emit("error", 20001, `target page: ${layerId} not found`);
30713
+ this.emitter.emit("error", 300002, `target page: ${layerId} not found`);
30520
30714
  }
30521
30715
  return this.layers.get(layerId);
30522
30716
  };