microboard-temp 0.11.8 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18214,6 +18214,16 @@ class Transformation {
18214
18214
  shearY: 0
18215
18215
  }, timeStamp);
18216
18216
  }
18217
+ applyMatrixSilent(matrixData) {
18218
+ this.previous = this.matrix.copy();
18219
+ this.matrix.scale(matrixData.scaleX, matrixData.scaleY);
18220
+ this.matrix.translate(matrixData.translateX, matrixData.translateY);
18221
+ this.subject.publish(this, {
18222
+ class: "Transformation",
18223
+ method: "applyMatrix",
18224
+ items: [{ id: this.id, matrix: matrixData }]
18225
+ });
18226
+ }
18217
18227
  setIsLocked(isLocked, timestamp) {
18218
18228
  if (isLocked) {
18219
18229
  this.emit({
@@ -22380,7 +22390,7 @@ class RichText extends BaseItem {
22380
22390
  }
22381
22391
  getMaxWidth() {
22382
22392
  if (this.autoSize) {
22383
- return this.editor.maxWidth;
22393
+ return this.editor.maxWidth || this.getTransformedContainer().getWidth();
22384
22394
  }
22385
22395
  if (this.isContainerSet) {
22386
22396
  return this.getTransformedContainer().getWidth();
@@ -22415,6 +22425,13 @@ class RichText extends BaseItem {
22415
22425
  const point3 = new Point(left, top);
22416
22426
  if (this.worldMatrixGetter) {
22417
22427
  this.worldMatrixGetter().apply(point3);
22428
+ } else if (this.isInShape) {
22429
+ const item = this.board.items.getById(this.id);
22430
+ if (item) {
22431
+ item.getParentWorldMatrix().apply(point3);
22432
+ } else {
22433
+ this.getParentWorldMatrix().apply(point3);
22434
+ }
22418
22435
  } else {
22419
22436
  this.getParentWorldMatrix().apply(point3);
22420
22437
  }
@@ -22424,7 +22441,7 @@ class RichText extends BaseItem {
22424
22441
  height,
22425
22442
  maxWidth: maxWidth ? maxWidth + 1 : undefined,
22426
22443
  maxHeight,
22427
- textScale: this.isInShape ? 1 : this.getScale()
22444
+ textScale: this.getScale()
22428
22445
  };
22429
22446
  }
22430
22447
  transformCanvas() {
@@ -40483,7 +40500,6 @@ class Sticker extends BaseItem {
40483
40500
  this.linkTo = new LinkTo(this.id, this.board.events);
40484
40501
  this.transformation = new Transformation(this.id, this.board.events);
40485
40502
  this.text = new RichText(board, this.textContainer, this.id, this.transformation, this.linkTo, " ", false, true, this.itemType);
40486
- this.text.worldMatrixGetter = () => this.getParentWorldMatrix();
40487
40503
  this.transformation.subject.subscribe((_subject, op) => {
40488
40504
  this.transformPath();
40489
40505
  if (op.method === "applyMatrix") {
@@ -54280,6 +54296,123 @@ class BoardSelection {
54280
54296
  });
54281
54297
  }
54282
54298
  }
54299
+ // src/Gravity/GravityEngine.ts
54300
+ class GravityEngine {
54301
+ board;
54302
+ velocities = new Map;
54303
+ tickTimer = null;
54304
+ syncTimer = null;
54305
+ lastSyncedPositions = new Map;
54306
+ G = 500;
54307
+ DAMPING = 0.98;
54308
+ TICK_MS = 33;
54309
+ SYNC_MS = 300;
54310
+ MAX_DISTANCE = 3000;
54311
+ SOFTENING_SQ = 50 * 50;
54312
+ MIN_MOVE_PX = 0.1;
54313
+ constructor(board) {
54314
+ this.board = board;
54315
+ }
54316
+ start() {
54317
+ if (this.tickTimer !== null)
54318
+ return;
54319
+ for (const item of this.board.items.listAll()) {
54320
+ this.velocities.set(item.getId(), { vx: 0, vy: 0 });
54321
+ }
54322
+ this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
54323
+ this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
54324
+ }
54325
+ stop() {
54326
+ if (this.tickTimer !== null) {
54327
+ clearInterval(this.tickTimer);
54328
+ this.tickTimer = null;
54329
+ }
54330
+ if (this.syncTimer !== null) {
54331
+ clearInterval(this.syncTimer);
54332
+ this.syncTimer = null;
54333
+ }
54334
+ this.velocities.clear();
54335
+ this.lastSyncedPositions.clear();
54336
+ }
54337
+ tick() {
54338
+ const dt = this.TICK_MS / 1000;
54339
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
54340
+ if (items.length < 2)
54341
+ return;
54342
+ for (const item of items) {
54343
+ const id = item.getId();
54344
+ if (!this.velocities.has(id)) {
54345
+ this.velocities.set(id, { vx: 0, vy: 0 });
54346
+ }
54347
+ const vel = this.velocities.get(id);
54348
+ const pos1 = item.transformation.getTranslation();
54349
+ const mbr1 = item.getMbr();
54350
+ const mass1 = mbr1.getWidth() * mbr1.getHeight();
54351
+ const nearby = this.board.items.getEnclosedOrCrossed(pos1.x - this.MAX_DISTANCE, pos1.y - this.MAX_DISTANCE, pos1.x + this.MAX_DISTANCE * 2, pos1.y + this.MAX_DISTANCE * 2).filter((other) => other.getId() !== id);
54352
+ let ax = 0;
54353
+ let ay = 0;
54354
+ for (const other of nearby) {
54355
+ const pos2 = other.transformation.getTranslation();
54356
+ const mbr2 = other.getMbr();
54357
+ const mass2 = mbr2.getWidth() * mbr2.getHeight();
54358
+ const dx2 = pos2.x - pos1.x;
54359
+ const dy2 = pos2.y - pos1.y;
54360
+ const distSq = dx2 * dx2 + dy2 * dy2 + this.SOFTENING_SQ;
54361
+ const dist = Math.sqrt(distSq);
54362
+ const acc = this.G * mass2 / distSq;
54363
+ ax += acc * dx2 / dist;
54364
+ ay += acc * dy2 / dist;
54365
+ }
54366
+ vel.vx = (vel.vx + ax * dt) * this.DAMPING;
54367
+ vel.vy = (vel.vy + ay * dt) * this.DAMPING;
54368
+ const dx = vel.vx * dt;
54369
+ const dy = vel.vy * dt;
54370
+ if (Math.abs(dx) >= this.MIN_MOVE_PX || Math.abs(dy) >= this.MIN_MOVE_PX) {
54371
+ item.transformation.applyMatrixSilent({
54372
+ translateX: dx,
54373
+ translateY: dy,
54374
+ scaleX: 1,
54375
+ scaleY: 1,
54376
+ shearX: 0,
54377
+ shearY: 0
54378
+ });
54379
+ }
54380
+ }
54381
+ }
54382
+ syncPositions() {
54383
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
54384
+ if (items.length === 0)
54385
+ return;
54386
+ const movedItems = items.map((item) => {
54387
+ const id = item.getId();
54388
+ const pos = item.transformation.getTranslation();
54389
+ const last = this.lastSyncedPositions.get(id);
54390
+ const dx = last ? pos.x - last.x : 0;
54391
+ const dy = last ? pos.y - last.y : 0;
54392
+ this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
54393
+ return { id, dx, dy };
54394
+ }).filter(({ dx, dy }) => Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5);
54395
+ if (movedItems.length === 0)
54396
+ return;
54397
+ const operation = {
54398
+ class: "Transformation",
54399
+ method: "applyMatrix",
54400
+ items: movedItems.map(({ id, dx, dy }) => ({
54401
+ id,
54402
+ matrix: {
54403
+ translateX: dx,
54404
+ translateY: dy,
54405
+ scaleX: 1,
54406
+ scaleY: 1,
54407
+ shearX: 0,
54408
+ shearY: 0
54409
+ }
54410
+ }))
54411
+ };
54412
+ this.board.events.emit(operation);
54413
+ }
54414
+ }
54415
+
54283
54416
  // src/Board.ts
54284
54417
  class Board {
54285
54418
  boardId;
@@ -55302,6 +55435,22 @@ class Board {
55302
55435
  this.selection.quickAddButtons.clear();
55303
55436
  this.presence.cleanup();
55304
55437
  }
55438
+ gravity = null;
55439
+ enableGravity() {
55440
+ if (this.gravity)
55441
+ return;
55442
+ this.gravity = new GravityEngine(this);
55443
+ this.gravity.start();
55444
+ }
55445
+ disableGravity() {
55446
+ if (!this.gravity)
55447
+ return;
55448
+ this.gravity.stop();
55449
+ this.gravity = null;
55450
+ }
55451
+ isGravityEnabled() {
55452
+ return this.gravity !== null;
55453
+ }
55305
55454
  }
55306
55455
  // src/Events/Merge.ts
55307
55456
  var import_slate36 = require("slate");
package/dist/cjs/index.js CHANGED
@@ -18214,6 +18214,16 @@ class Transformation {
18214
18214
  shearY: 0
18215
18215
  }, timeStamp);
18216
18216
  }
18217
+ applyMatrixSilent(matrixData) {
18218
+ this.previous = this.matrix.copy();
18219
+ this.matrix.scale(matrixData.scaleX, matrixData.scaleY);
18220
+ this.matrix.translate(matrixData.translateX, matrixData.translateY);
18221
+ this.subject.publish(this, {
18222
+ class: "Transformation",
18223
+ method: "applyMatrix",
18224
+ items: [{ id: this.id, matrix: matrixData }]
18225
+ });
18226
+ }
18217
18227
  setIsLocked(isLocked, timestamp) {
18218
18228
  if (isLocked) {
18219
18229
  this.emit({
@@ -22380,7 +22390,7 @@ class RichText extends BaseItem {
22380
22390
  }
22381
22391
  getMaxWidth() {
22382
22392
  if (this.autoSize) {
22383
- return this.editor.maxWidth;
22393
+ return this.editor.maxWidth || this.getTransformedContainer().getWidth();
22384
22394
  }
22385
22395
  if (this.isContainerSet) {
22386
22396
  return this.getTransformedContainer().getWidth();
@@ -22415,6 +22425,13 @@ class RichText extends BaseItem {
22415
22425
  const point3 = new Point(left, top);
22416
22426
  if (this.worldMatrixGetter) {
22417
22427
  this.worldMatrixGetter().apply(point3);
22428
+ } else if (this.isInShape) {
22429
+ const item = this.board.items.getById(this.id);
22430
+ if (item) {
22431
+ item.getParentWorldMatrix().apply(point3);
22432
+ } else {
22433
+ this.getParentWorldMatrix().apply(point3);
22434
+ }
22418
22435
  } else {
22419
22436
  this.getParentWorldMatrix().apply(point3);
22420
22437
  }
@@ -22424,7 +22441,7 @@ class RichText extends BaseItem {
22424
22441
  height,
22425
22442
  maxWidth: maxWidth ? maxWidth + 1 : undefined,
22426
22443
  maxHeight,
22427
- textScale: this.isInShape ? 1 : this.getScale()
22444
+ textScale: this.getScale()
22428
22445
  };
22429
22446
  }
22430
22447
  transformCanvas() {
@@ -40483,7 +40500,6 @@ class Sticker extends BaseItem {
40483
40500
  this.linkTo = new LinkTo(this.id, this.board.events);
40484
40501
  this.transformation = new Transformation(this.id, this.board.events);
40485
40502
  this.text = new RichText(board, this.textContainer, this.id, this.transformation, this.linkTo, " ", false, true, this.itemType);
40486
- this.text.worldMatrixGetter = () => this.getParentWorldMatrix();
40487
40503
  this.transformation.subject.subscribe((_subject, op) => {
40488
40504
  this.transformPath();
40489
40505
  if (op.method === "applyMatrix") {
@@ -54280,6 +54296,123 @@ class BoardSelection {
54280
54296
  });
54281
54297
  }
54282
54298
  }
54299
+ // src/Gravity/GravityEngine.ts
54300
+ class GravityEngine {
54301
+ board;
54302
+ velocities = new Map;
54303
+ tickTimer = null;
54304
+ syncTimer = null;
54305
+ lastSyncedPositions = new Map;
54306
+ G = 500;
54307
+ DAMPING = 0.98;
54308
+ TICK_MS = 33;
54309
+ SYNC_MS = 300;
54310
+ MAX_DISTANCE = 3000;
54311
+ SOFTENING_SQ = 50 * 50;
54312
+ MIN_MOVE_PX = 0.1;
54313
+ constructor(board) {
54314
+ this.board = board;
54315
+ }
54316
+ start() {
54317
+ if (this.tickTimer !== null)
54318
+ return;
54319
+ for (const item of this.board.items.listAll()) {
54320
+ this.velocities.set(item.getId(), { vx: 0, vy: 0 });
54321
+ }
54322
+ this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
54323
+ this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
54324
+ }
54325
+ stop() {
54326
+ if (this.tickTimer !== null) {
54327
+ clearInterval(this.tickTimer);
54328
+ this.tickTimer = null;
54329
+ }
54330
+ if (this.syncTimer !== null) {
54331
+ clearInterval(this.syncTimer);
54332
+ this.syncTimer = null;
54333
+ }
54334
+ this.velocities.clear();
54335
+ this.lastSyncedPositions.clear();
54336
+ }
54337
+ tick() {
54338
+ const dt = this.TICK_MS / 1000;
54339
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
54340
+ if (items.length < 2)
54341
+ return;
54342
+ for (const item of items) {
54343
+ const id = item.getId();
54344
+ if (!this.velocities.has(id)) {
54345
+ this.velocities.set(id, { vx: 0, vy: 0 });
54346
+ }
54347
+ const vel = this.velocities.get(id);
54348
+ const pos1 = item.transformation.getTranslation();
54349
+ const mbr1 = item.getMbr();
54350
+ const mass1 = mbr1.getWidth() * mbr1.getHeight();
54351
+ const nearby = this.board.items.getEnclosedOrCrossed(pos1.x - this.MAX_DISTANCE, pos1.y - this.MAX_DISTANCE, pos1.x + this.MAX_DISTANCE * 2, pos1.y + this.MAX_DISTANCE * 2).filter((other) => other.getId() !== id);
54352
+ let ax = 0;
54353
+ let ay = 0;
54354
+ for (const other of nearby) {
54355
+ const pos2 = other.transformation.getTranslation();
54356
+ const mbr2 = other.getMbr();
54357
+ const mass2 = mbr2.getWidth() * mbr2.getHeight();
54358
+ const dx2 = pos2.x - pos1.x;
54359
+ const dy2 = pos2.y - pos1.y;
54360
+ const distSq = dx2 * dx2 + dy2 * dy2 + this.SOFTENING_SQ;
54361
+ const dist = Math.sqrt(distSq);
54362
+ const acc = this.G * mass2 / distSq;
54363
+ ax += acc * dx2 / dist;
54364
+ ay += acc * dy2 / dist;
54365
+ }
54366
+ vel.vx = (vel.vx + ax * dt) * this.DAMPING;
54367
+ vel.vy = (vel.vy + ay * dt) * this.DAMPING;
54368
+ const dx = vel.vx * dt;
54369
+ const dy = vel.vy * dt;
54370
+ if (Math.abs(dx) >= this.MIN_MOVE_PX || Math.abs(dy) >= this.MIN_MOVE_PX) {
54371
+ item.transformation.applyMatrixSilent({
54372
+ translateX: dx,
54373
+ translateY: dy,
54374
+ scaleX: 1,
54375
+ scaleY: 1,
54376
+ shearX: 0,
54377
+ shearY: 0
54378
+ });
54379
+ }
54380
+ }
54381
+ }
54382
+ syncPositions() {
54383
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
54384
+ if (items.length === 0)
54385
+ return;
54386
+ const movedItems = items.map((item) => {
54387
+ const id = item.getId();
54388
+ const pos = item.transformation.getTranslation();
54389
+ const last = this.lastSyncedPositions.get(id);
54390
+ const dx = last ? pos.x - last.x : 0;
54391
+ const dy = last ? pos.y - last.y : 0;
54392
+ this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
54393
+ return { id, dx, dy };
54394
+ }).filter(({ dx, dy }) => Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5);
54395
+ if (movedItems.length === 0)
54396
+ return;
54397
+ const operation = {
54398
+ class: "Transformation",
54399
+ method: "applyMatrix",
54400
+ items: movedItems.map(({ id, dx, dy }) => ({
54401
+ id,
54402
+ matrix: {
54403
+ translateX: dx,
54404
+ translateY: dy,
54405
+ scaleX: 1,
54406
+ scaleY: 1,
54407
+ shearX: 0,
54408
+ shearY: 0
54409
+ }
54410
+ }))
54411
+ };
54412
+ this.board.events.emit(operation);
54413
+ }
54414
+ }
54415
+
54283
54416
  // src/Board.ts
54284
54417
  class Board {
54285
54418
  boardId;
@@ -55302,6 +55435,22 @@ class Board {
55302
55435
  this.selection.quickAddButtons.clear();
55303
55436
  this.presence.cleanup();
55304
55437
  }
55438
+ gravity = null;
55439
+ enableGravity() {
55440
+ if (this.gravity)
55441
+ return;
55442
+ this.gravity = new GravityEngine(this);
55443
+ this.gravity.start();
55444
+ }
55445
+ disableGravity() {
55446
+ if (!this.gravity)
55447
+ return;
55448
+ this.gravity.stop();
55449
+ this.gravity = null;
55450
+ }
55451
+ isGravityEnabled() {
55452
+ return this.gravity !== null;
55453
+ }
55305
55454
  }
55306
55455
  // src/Events/Merge.ts
55307
55456
  var import_slate36 = require("slate");
package/dist/cjs/node.js CHANGED
@@ -20754,6 +20754,16 @@ class Transformation {
20754
20754
  shearY: 0
20755
20755
  }, timeStamp);
20756
20756
  }
20757
+ applyMatrixSilent(matrixData) {
20758
+ this.previous = this.matrix.copy();
20759
+ this.matrix.scale(matrixData.scaleX, matrixData.scaleY);
20760
+ this.matrix.translate(matrixData.translateX, matrixData.translateY);
20761
+ this.subject.publish(this, {
20762
+ class: "Transformation",
20763
+ method: "applyMatrix",
20764
+ items: [{ id: this.id, matrix: matrixData }]
20765
+ });
20766
+ }
20757
20767
  setIsLocked(isLocked, timestamp) {
20758
20768
  if (isLocked) {
20759
20769
  this.emit({
@@ -24852,7 +24862,7 @@ class RichText extends BaseItem {
24852
24862
  }
24853
24863
  getMaxWidth() {
24854
24864
  if (this.autoSize) {
24855
- return this.editor.maxWidth;
24865
+ return this.editor.maxWidth || this.getTransformedContainer().getWidth();
24856
24866
  }
24857
24867
  if (this.isContainerSet) {
24858
24868
  return this.getTransformedContainer().getWidth();
@@ -24887,6 +24897,13 @@ class RichText extends BaseItem {
24887
24897
  const point3 = new Point(left, top);
24888
24898
  if (this.worldMatrixGetter) {
24889
24899
  this.worldMatrixGetter().apply(point3);
24900
+ } else if (this.isInShape) {
24901
+ const item = this.board.items.getById(this.id);
24902
+ if (item) {
24903
+ item.getParentWorldMatrix().apply(point3);
24904
+ } else {
24905
+ this.getParentWorldMatrix().apply(point3);
24906
+ }
24890
24907
  } else {
24891
24908
  this.getParentWorldMatrix().apply(point3);
24892
24909
  }
@@ -24896,7 +24913,7 @@ class RichText extends BaseItem {
24896
24913
  height,
24897
24914
  maxWidth: maxWidth ? maxWidth + 1 : undefined,
24898
24915
  maxHeight,
24899
- textScale: this.isInShape ? 1 : this.getScale()
24916
+ textScale: this.getScale()
24900
24917
  };
24901
24918
  }
24902
24919
  transformCanvas() {
@@ -42956,7 +42973,6 @@ class Sticker extends BaseItem {
42956
42973
  this.linkTo = new LinkTo(this.id, this.board.events);
42957
42974
  this.transformation = new Transformation(this.id, this.board.events);
42958
42975
  this.text = new RichText(board, this.textContainer, this.id, this.transformation, this.linkTo, " ", false, true, this.itemType);
42959
- this.text.worldMatrixGetter = () => this.getParentWorldMatrix();
42960
42976
  this.transformation.subject.subscribe((_subject, op) => {
42961
42977
  this.transformPath();
42962
42978
  if (op.method === "applyMatrix") {
@@ -56753,6 +56769,123 @@ class BoardSelection {
56753
56769
  });
56754
56770
  }
56755
56771
  }
56772
+ // src/Gravity/GravityEngine.ts
56773
+ class GravityEngine {
56774
+ board;
56775
+ velocities = new Map;
56776
+ tickTimer = null;
56777
+ syncTimer = null;
56778
+ lastSyncedPositions = new Map;
56779
+ G = 500;
56780
+ DAMPING = 0.98;
56781
+ TICK_MS = 33;
56782
+ SYNC_MS = 300;
56783
+ MAX_DISTANCE = 3000;
56784
+ SOFTENING_SQ = 50 * 50;
56785
+ MIN_MOVE_PX = 0.1;
56786
+ constructor(board) {
56787
+ this.board = board;
56788
+ }
56789
+ start() {
56790
+ if (this.tickTimer !== null)
56791
+ return;
56792
+ for (const item of this.board.items.listAll()) {
56793
+ this.velocities.set(item.getId(), { vx: 0, vy: 0 });
56794
+ }
56795
+ this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
56796
+ this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
56797
+ }
56798
+ stop() {
56799
+ if (this.tickTimer !== null) {
56800
+ clearInterval(this.tickTimer);
56801
+ this.tickTimer = null;
56802
+ }
56803
+ if (this.syncTimer !== null) {
56804
+ clearInterval(this.syncTimer);
56805
+ this.syncTimer = null;
56806
+ }
56807
+ this.velocities.clear();
56808
+ this.lastSyncedPositions.clear();
56809
+ }
56810
+ tick() {
56811
+ const dt = this.TICK_MS / 1000;
56812
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
56813
+ if (items.length < 2)
56814
+ return;
56815
+ for (const item of items) {
56816
+ const id = item.getId();
56817
+ if (!this.velocities.has(id)) {
56818
+ this.velocities.set(id, { vx: 0, vy: 0 });
56819
+ }
56820
+ const vel = this.velocities.get(id);
56821
+ const pos1 = item.transformation.getTranslation();
56822
+ const mbr1 = item.getMbr();
56823
+ const mass1 = mbr1.getWidth() * mbr1.getHeight();
56824
+ const nearby = this.board.items.getEnclosedOrCrossed(pos1.x - this.MAX_DISTANCE, pos1.y - this.MAX_DISTANCE, pos1.x + this.MAX_DISTANCE * 2, pos1.y + this.MAX_DISTANCE * 2).filter((other) => other.getId() !== id);
56825
+ let ax = 0;
56826
+ let ay = 0;
56827
+ for (const other of nearby) {
56828
+ const pos2 = other.transformation.getTranslation();
56829
+ const mbr2 = other.getMbr();
56830
+ const mass2 = mbr2.getWidth() * mbr2.getHeight();
56831
+ const dx2 = pos2.x - pos1.x;
56832
+ const dy2 = pos2.y - pos1.y;
56833
+ const distSq = dx2 * dx2 + dy2 * dy2 + this.SOFTENING_SQ;
56834
+ const dist = Math.sqrt(distSq);
56835
+ const acc = this.G * mass2 / distSq;
56836
+ ax += acc * dx2 / dist;
56837
+ ay += acc * dy2 / dist;
56838
+ }
56839
+ vel.vx = (vel.vx + ax * dt) * this.DAMPING;
56840
+ vel.vy = (vel.vy + ay * dt) * this.DAMPING;
56841
+ const dx = vel.vx * dt;
56842
+ const dy = vel.vy * dt;
56843
+ if (Math.abs(dx) >= this.MIN_MOVE_PX || Math.abs(dy) >= this.MIN_MOVE_PX) {
56844
+ item.transformation.applyMatrixSilent({
56845
+ translateX: dx,
56846
+ translateY: dy,
56847
+ scaleX: 1,
56848
+ scaleY: 1,
56849
+ shearX: 0,
56850
+ shearY: 0
56851
+ });
56852
+ }
56853
+ }
56854
+ }
56855
+ syncPositions() {
56856
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
56857
+ if (items.length === 0)
56858
+ return;
56859
+ const movedItems = items.map((item) => {
56860
+ const id = item.getId();
56861
+ const pos = item.transformation.getTranslation();
56862
+ const last = this.lastSyncedPositions.get(id);
56863
+ const dx = last ? pos.x - last.x : 0;
56864
+ const dy = last ? pos.y - last.y : 0;
56865
+ this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
56866
+ return { id, dx, dy };
56867
+ }).filter(({ dx, dy }) => Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5);
56868
+ if (movedItems.length === 0)
56869
+ return;
56870
+ const operation = {
56871
+ class: "Transformation",
56872
+ method: "applyMatrix",
56873
+ items: movedItems.map(({ id, dx, dy }) => ({
56874
+ id,
56875
+ matrix: {
56876
+ translateX: dx,
56877
+ translateY: dy,
56878
+ scaleX: 1,
56879
+ scaleY: 1,
56880
+ shearX: 0,
56881
+ shearY: 0
56882
+ }
56883
+ }))
56884
+ };
56885
+ this.board.events.emit(operation);
56886
+ }
56887
+ }
56888
+
56756
56889
  // src/Board.ts
56757
56890
  class Board {
56758
56891
  boardId;
@@ -57775,6 +57908,22 @@ class Board {
57775
57908
  this.selection.quickAddButtons.clear();
57776
57909
  this.presence.cleanup();
57777
57910
  }
57911
+ gravity = null;
57912
+ enableGravity() {
57913
+ if (this.gravity)
57914
+ return;
57915
+ this.gravity = new GravityEngine(this);
57916
+ this.gravity.start();
57917
+ }
57918
+ disableGravity() {
57919
+ if (!this.gravity)
57920
+ return;
57921
+ this.gravity.stop();
57922
+ this.gravity = null;
57923
+ }
57924
+ isGravityEnabled() {
57925
+ return this.gravity !== null;
57926
+ }
57778
57927
  }
57779
57928
  // src/Events/Merge.ts
57780
57929
  var import_slate35 = require("slate");
@@ -18043,6 +18043,16 @@ class Transformation {
18043
18043
  shearY: 0
18044
18044
  }, timeStamp);
18045
18045
  }
18046
+ applyMatrixSilent(matrixData) {
18047
+ this.previous = this.matrix.copy();
18048
+ this.matrix.scale(matrixData.scaleX, matrixData.scaleY);
18049
+ this.matrix.translate(matrixData.translateX, matrixData.translateY);
18050
+ this.subject.publish(this, {
18051
+ class: "Transformation",
18052
+ method: "applyMatrix",
18053
+ items: [{ id: this.id, matrix: matrixData }]
18054
+ });
18055
+ }
18046
18056
  setIsLocked(isLocked, timestamp) {
18047
18057
  if (isLocked) {
18048
18058
  this.emit({
@@ -22209,7 +22219,7 @@ class RichText extends BaseItem {
22209
22219
  }
22210
22220
  getMaxWidth() {
22211
22221
  if (this.autoSize) {
22212
- return this.editor.maxWidth;
22222
+ return this.editor.maxWidth || this.getTransformedContainer().getWidth();
22213
22223
  }
22214
22224
  if (this.isContainerSet) {
22215
22225
  return this.getTransformedContainer().getWidth();
@@ -22244,6 +22254,13 @@ class RichText extends BaseItem {
22244
22254
  const point3 = new Point(left, top);
22245
22255
  if (this.worldMatrixGetter) {
22246
22256
  this.worldMatrixGetter().apply(point3);
22257
+ } else if (this.isInShape) {
22258
+ const item = this.board.items.getById(this.id);
22259
+ if (item) {
22260
+ item.getParentWorldMatrix().apply(point3);
22261
+ } else {
22262
+ this.getParentWorldMatrix().apply(point3);
22263
+ }
22247
22264
  } else {
22248
22265
  this.getParentWorldMatrix().apply(point3);
22249
22266
  }
@@ -22253,7 +22270,7 @@ class RichText extends BaseItem {
22253
22270
  height,
22254
22271
  maxWidth: maxWidth ? maxWidth + 1 : undefined,
22255
22272
  maxHeight,
22256
- textScale: this.isInShape ? 1 : this.getScale()
22273
+ textScale: this.getScale()
22257
22274
  };
22258
22275
  }
22259
22276
  transformCanvas() {
@@ -40312,7 +40329,6 @@ class Sticker extends BaseItem {
40312
40329
  this.linkTo = new LinkTo(this.id, this.board.events);
40313
40330
  this.transformation = new Transformation(this.id, this.board.events);
40314
40331
  this.text = new RichText(board, this.textContainer, this.id, this.transformation, this.linkTo, " ", false, true, this.itemType);
40315
- this.text.worldMatrixGetter = () => this.getParentWorldMatrix();
40316
40332
  this.transformation.subject.subscribe((_subject, op) => {
40317
40333
  this.transformPath();
40318
40334
  if (op.method === "applyMatrix") {
@@ -54109,6 +54125,123 @@ class BoardSelection {
54109
54125
  });
54110
54126
  }
54111
54127
  }
54128
+ // src/Gravity/GravityEngine.ts
54129
+ class GravityEngine {
54130
+ board;
54131
+ velocities = new Map;
54132
+ tickTimer = null;
54133
+ syncTimer = null;
54134
+ lastSyncedPositions = new Map;
54135
+ G = 500;
54136
+ DAMPING = 0.98;
54137
+ TICK_MS = 33;
54138
+ SYNC_MS = 300;
54139
+ MAX_DISTANCE = 3000;
54140
+ SOFTENING_SQ = 50 * 50;
54141
+ MIN_MOVE_PX = 0.1;
54142
+ constructor(board) {
54143
+ this.board = board;
54144
+ }
54145
+ start() {
54146
+ if (this.tickTimer !== null)
54147
+ return;
54148
+ for (const item of this.board.items.listAll()) {
54149
+ this.velocities.set(item.getId(), { vx: 0, vy: 0 });
54150
+ }
54151
+ this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
54152
+ this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
54153
+ }
54154
+ stop() {
54155
+ if (this.tickTimer !== null) {
54156
+ clearInterval(this.tickTimer);
54157
+ this.tickTimer = null;
54158
+ }
54159
+ if (this.syncTimer !== null) {
54160
+ clearInterval(this.syncTimer);
54161
+ this.syncTimer = null;
54162
+ }
54163
+ this.velocities.clear();
54164
+ this.lastSyncedPositions.clear();
54165
+ }
54166
+ tick() {
54167
+ const dt = this.TICK_MS / 1000;
54168
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
54169
+ if (items.length < 2)
54170
+ return;
54171
+ for (const item of items) {
54172
+ const id = item.getId();
54173
+ if (!this.velocities.has(id)) {
54174
+ this.velocities.set(id, { vx: 0, vy: 0 });
54175
+ }
54176
+ const vel = this.velocities.get(id);
54177
+ const pos1 = item.transformation.getTranslation();
54178
+ const mbr1 = item.getMbr();
54179
+ const mass1 = mbr1.getWidth() * mbr1.getHeight();
54180
+ const nearby = this.board.items.getEnclosedOrCrossed(pos1.x - this.MAX_DISTANCE, pos1.y - this.MAX_DISTANCE, pos1.x + this.MAX_DISTANCE * 2, pos1.y + this.MAX_DISTANCE * 2).filter((other) => other.getId() !== id);
54181
+ let ax = 0;
54182
+ let ay = 0;
54183
+ for (const other of nearby) {
54184
+ const pos2 = other.transformation.getTranslation();
54185
+ const mbr2 = other.getMbr();
54186
+ const mass2 = mbr2.getWidth() * mbr2.getHeight();
54187
+ const dx2 = pos2.x - pos1.x;
54188
+ const dy2 = pos2.y - pos1.y;
54189
+ const distSq = dx2 * dx2 + dy2 * dy2 + this.SOFTENING_SQ;
54190
+ const dist = Math.sqrt(distSq);
54191
+ const acc = this.G * mass2 / distSq;
54192
+ ax += acc * dx2 / dist;
54193
+ ay += acc * dy2 / dist;
54194
+ }
54195
+ vel.vx = (vel.vx + ax * dt) * this.DAMPING;
54196
+ vel.vy = (vel.vy + ay * dt) * this.DAMPING;
54197
+ const dx = vel.vx * dt;
54198
+ const dy = vel.vy * dt;
54199
+ if (Math.abs(dx) >= this.MIN_MOVE_PX || Math.abs(dy) >= this.MIN_MOVE_PX) {
54200
+ item.transformation.applyMatrixSilent({
54201
+ translateX: dx,
54202
+ translateY: dy,
54203
+ scaleX: 1,
54204
+ scaleY: 1,
54205
+ shearX: 0,
54206
+ shearY: 0
54207
+ });
54208
+ }
54209
+ }
54210
+ }
54211
+ syncPositions() {
54212
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
54213
+ if (items.length === 0)
54214
+ return;
54215
+ const movedItems = items.map((item) => {
54216
+ const id = item.getId();
54217
+ const pos = item.transformation.getTranslation();
54218
+ const last = this.lastSyncedPositions.get(id);
54219
+ const dx = last ? pos.x - last.x : 0;
54220
+ const dy = last ? pos.y - last.y : 0;
54221
+ this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
54222
+ return { id, dx, dy };
54223
+ }).filter(({ dx, dy }) => Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5);
54224
+ if (movedItems.length === 0)
54225
+ return;
54226
+ const operation = {
54227
+ class: "Transformation",
54228
+ method: "applyMatrix",
54229
+ items: movedItems.map(({ id, dx, dy }) => ({
54230
+ id,
54231
+ matrix: {
54232
+ translateX: dx,
54233
+ translateY: dy,
54234
+ scaleX: 1,
54235
+ scaleY: 1,
54236
+ shearX: 0,
54237
+ shearY: 0
54238
+ }
54239
+ }))
54240
+ };
54241
+ this.board.events.emit(operation);
54242
+ }
54243
+ }
54244
+
54112
54245
  // src/Board.ts
54113
54246
  class Board {
54114
54247
  boardId;
@@ -55131,6 +55264,22 @@ class Board {
55131
55264
  this.selection.quickAddButtons.clear();
55132
55265
  this.presence.cleanup();
55133
55266
  }
55267
+ gravity = null;
55268
+ enableGravity() {
55269
+ if (this.gravity)
55270
+ return;
55271
+ this.gravity = new GravityEngine(this);
55272
+ this.gravity.start();
55273
+ }
55274
+ disableGravity() {
55275
+ if (!this.gravity)
55276
+ return;
55277
+ this.gravity.stop();
55278
+ this.gravity = null;
55279
+ }
55280
+ isGravityEnabled() {
55281
+ return this.gravity !== null;
55282
+ }
55134
55283
  }
55135
55284
  // src/Events/Merge.ts
55136
55285
  import { Path as Path15 } from "slate";
package/dist/esm/index.js CHANGED
@@ -18036,6 +18036,16 @@ class Transformation {
18036
18036
  shearY: 0
18037
18037
  }, timeStamp);
18038
18038
  }
18039
+ applyMatrixSilent(matrixData) {
18040
+ this.previous = this.matrix.copy();
18041
+ this.matrix.scale(matrixData.scaleX, matrixData.scaleY);
18042
+ this.matrix.translate(matrixData.translateX, matrixData.translateY);
18043
+ this.subject.publish(this, {
18044
+ class: "Transformation",
18045
+ method: "applyMatrix",
18046
+ items: [{ id: this.id, matrix: matrixData }]
18047
+ });
18048
+ }
18039
18049
  setIsLocked(isLocked, timestamp) {
18040
18050
  if (isLocked) {
18041
18051
  this.emit({
@@ -22202,7 +22212,7 @@ class RichText extends BaseItem {
22202
22212
  }
22203
22213
  getMaxWidth() {
22204
22214
  if (this.autoSize) {
22205
- return this.editor.maxWidth;
22215
+ return this.editor.maxWidth || this.getTransformedContainer().getWidth();
22206
22216
  }
22207
22217
  if (this.isContainerSet) {
22208
22218
  return this.getTransformedContainer().getWidth();
@@ -22237,6 +22247,13 @@ class RichText extends BaseItem {
22237
22247
  const point3 = new Point(left, top);
22238
22248
  if (this.worldMatrixGetter) {
22239
22249
  this.worldMatrixGetter().apply(point3);
22250
+ } else if (this.isInShape) {
22251
+ const item = this.board.items.getById(this.id);
22252
+ if (item) {
22253
+ item.getParentWorldMatrix().apply(point3);
22254
+ } else {
22255
+ this.getParentWorldMatrix().apply(point3);
22256
+ }
22240
22257
  } else {
22241
22258
  this.getParentWorldMatrix().apply(point3);
22242
22259
  }
@@ -22246,7 +22263,7 @@ class RichText extends BaseItem {
22246
22263
  height,
22247
22264
  maxWidth: maxWidth ? maxWidth + 1 : undefined,
22248
22265
  maxHeight,
22249
- textScale: this.isInShape ? 1 : this.getScale()
22266
+ textScale: this.getScale()
22250
22267
  };
22251
22268
  }
22252
22269
  transformCanvas() {
@@ -40305,7 +40322,6 @@ class Sticker extends BaseItem {
40305
40322
  this.linkTo = new LinkTo(this.id, this.board.events);
40306
40323
  this.transformation = new Transformation(this.id, this.board.events);
40307
40324
  this.text = new RichText(board, this.textContainer, this.id, this.transformation, this.linkTo, " ", false, true, this.itemType);
40308
- this.text.worldMatrixGetter = () => this.getParentWorldMatrix();
40309
40325
  this.transformation.subject.subscribe((_subject, op) => {
40310
40326
  this.transformPath();
40311
40327
  if (op.method === "applyMatrix") {
@@ -54102,6 +54118,123 @@ class BoardSelection {
54102
54118
  });
54103
54119
  }
54104
54120
  }
54121
+ // src/Gravity/GravityEngine.ts
54122
+ class GravityEngine {
54123
+ board;
54124
+ velocities = new Map;
54125
+ tickTimer = null;
54126
+ syncTimer = null;
54127
+ lastSyncedPositions = new Map;
54128
+ G = 500;
54129
+ DAMPING = 0.98;
54130
+ TICK_MS = 33;
54131
+ SYNC_MS = 300;
54132
+ MAX_DISTANCE = 3000;
54133
+ SOFTENING_SQ = 50 * 50;
54134
+ MIN_MOVE_PX = 0.1;
54135
+ constructor(board) {
54136
+ this.board = board;
54137
+ }
54138
+ start() {
54139
+ if (this.tickTimer !== null)
54140
+ return;
54141
+ for (const item of this.board.items.listAll()) {
54142
+ this.velocities.set(item.getId(), { vx: 0, vy: 0 });
54143
+ }
54144
+ this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
54145
+ this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
54146
+ }
54147
+ stop() {
54148
+ if (this.tickTimer !== null) {
54149
+ clearInterval(this.tickTimer);
54150
+ this.tickTimer = null;
54151
+ }
54152
+ if (this.syncTimer !== null) {
54153
+ clearInterval(this.syncTimer);
54154
+ this.syncTimer = null;
54155
+ }
54156
+ this.velocities.clear();
54157
+ this.lastSyncedPositions.clear();
54158
+ }
54159
+ tick() {
54160
+ const dt = this.TICK_MS / 1000;
54161
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
54162
+ if (items.length < 2)
54163
+ return;
54164
+ for (const item of items) {
54165
+ const id = item.getId();
54166
+ if (!this.velocities.has(id)) {
54167
+ this.velocities.set(id, { vx: 0, vy: 0 });
54168
+ }
54169
+ const vel = this.velocities.get(id);
54170
+ const pos1 = item.transformation.getTranslation();
54171
+ const mbr1 = item.getMbr();
54172
+ const mass1 = mbr1.getWidth() * mbr1.getHeight();
54173
+ const nearby = this.board.items.getEnclosedOrCrossed(pos1.x - this.MAX_DISTANCE, pos1.y - this.MAX_DISTANCE, pos1.x + this.MAX_DISTANCE * 2, pos1.y + this.MAX_DISTANCE * 2).filter((other) => other.getId() !== id);
54174
+ let ax = 0;
54175
+ let ay = 0;
54176
+ for (const other of nearby) {
54177
+ const pos2 = other.transformation.getTranslation();
54178
+ const mbr2 = other.getMbr();
54179
+ const mass2 = mbr2.getWidth() * mbr2.getHeight();
54180
+ const dx2 = pos2.x - pos1.x;
54181
+ const dy2 = pos2.y - pos1.y;
54182
+ const distSq = dx2 * dx2 + dy2 * dy2 + this.SOFTENING_SQ;
54183
+ const dist = Math.sqrt(distSq);
54184
+ const acc = this.G * mass2 / distSq;
54185
+ ax += acc * dx2 / dist;
54186
+ ay += acc * dy2 / dist;
54187
+ }
54188
+ vel.vx = (vel.vx + ax * dt) * this.DAMPING;
54189
+ vel.vy = (vel.vy + ay * dt) * this.DAMPING;
54190
+ const dx = vel.vx * dt;
54191
+ const dy = vel.vy * dt;
54192
+ if (Math.abs(dx) >= this.MIN_MOVE_PX || Math.abs(dy) >= this.MIN_MOVE_PX) {
54193
+ item.transformation.applyMatrixSilent({
54194
+ translateX: dx,
54195
+ translateY: dy,
54196
+ scaleX: 1,
54197
+ scaleY: 1,
54198
+ shearX: 0,
54199
+ shearY: 0
54200
+ });
54201
+ }
54202
+ }
54203
+ }
54204
+ syncPositions() {
54205
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
54206
+ if (items.length === 0)
54207
+ return;
54208
+ const movedItems = items.map((item) => {
54209
+ const id = item.getId();
54210
+ const pos = item.transformation.getTranslation();
54211
+ const last = this.lastSyncedPositions.get(id);
54212
+ const dx = last ? pos.x - last.x : 0;
54213
+ const dy = last ? pos.y - last.y : 0;
54214
+ this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
54215
+ return { id, dx, dy };
54216
+ }).filter(({ dx, dy }) => Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5);
54217
+ if (movedItems.length === 0)
54218
+ return;
54219
+ const operation = {
54220
+ class: "Transformation",
54221
+ method: "applyMatrix",
54222
+ items: movedItems.map(({ id, dx, dy }) => ({
54223
+ id,
54224
+ matrix: {
54225
+ translateX: dx,
54226
+ translateY: dy,
54227
+ scaleX: 1,
54228
+ scaleY: 1,
54229
+ shearX: 0,
54230
+ shearY: 0
54231
+ }
54232
+ }))
54233
+ };
54234
+ this.board.events.emit(operation);
54235
+ }
54236
+ }
54237
+
54105
54238
  // src/Board.ts
54106
54239
  class Board {
54107
54240
  boardId;
@@ -55124,6 +55257,22 @@ class Board {
55124
55257
  this.selection.quickAddButtons.clear();
55125
55258
  this.presence.cleanup();
55126
55259
  }
55260
+ gravity = null;
55261
+ enableGravity() {
55262
+ if (this.gravity)
55263
+ return;
55264
+ this.gravity = new GravityEngine(this);
55265
+ this.gravity.start();
55266
+ }
55267
+ disableGravity() {
55268
+ if (!this.gravity)
55269
+ return;
55270
+ this.gravity.stop();
55271
+ this.gravity = null;
55272
+ }
55273
+ isGravityEnabled() {
55274
+ return this.gravity !== null;
55275
+ }
55127
55276
  }
55128
55277
  // src/Events/Merge.ts
55129
55278
  import { Path as Path15 } from "slate";
package/dist/esm/node.js CHANGED
@@ -20571,6 +20571,16 @@ class Transformation {
20571
20571
  shearY: 0
20572
20572
  }, timeStamp);
20573
20573
  }
20574
+ applyMatrixSilent(matrixData) {
20575
+ this.previous = this.matrix.copy();
20576
+ this.matrix.scale(matrixData.scaleX, matrixData.scaleY);
20577
+ this.matrix.translate(matrixData.translateX, matrixData.translateY);
20578
+ this.subject.publish(this, {
20579
+ class: "Transformation",
20580
+ method: "applyMatrix",
20581
+ items: [{ id: this.id, matrix: matrixData }]
20582
+ });
20583
+ }
20574
20584
  setIsLocked(isLocked, timestamp) {
20575
20585
  if (isLocked) {
20576
20586
  this.emit({
@@ -24669,7 +24679,7 @@ class RichText extends BaseItem {
24669
24679
  }
24670
24680
  getMaxWidth() {
24671
24681
  if (this.autoSize) {
24672
- return this.editor.maxWidth;
24682
+ return this.editor.maxWidth || this.getTransformedContainer().getWidth();
24673
24683
  }
24674
24684
  if (this.isContainerSet) {
24675
24685
  return this.getTransformedContainer().getWidth();
@@ -24704,6 +24714,13 @@ class RichText extends BaseItem {
24704
24714
  const point3 = new Point(left, top);
24705
24715
  if (this.worldMatrixGetter) {
24706
24716
  this.worldMatrixGetter().apply(point3);
24717
+ } else if (this.isInShape) {
24718
+ const item = this.board.items.getById(this.id);
24719
+ if (item) {
24720
+ item.getParentWorldMatrix().apply(point3);
24721
+ } else {
24722
+ this.getParentWorldMatrix().apply(point3);
24723
+ }
24707
24724
  } else {
24708
24725
  this.getParentWorldMatrix().apply(point3);
24709
24726
  }
@@ -24713,7 +24730,7 @@ class RichText extends BaseItem {
24713
24730
  height,
24714
24731
  maxWidth: maxWidth ? maxWidth + 1 : undefined,
24715
24732
  maxHeight,
24716
- textScale: this.isInShape ? 1 : this.getScale()
24733
+ textScale: this.getScale()
24717
24734
  };
24718
24735
  }
24719
24736
  transformCanvas() {
@@ -42773,7 +42790,6 @@ class Sticker extends BaseItem {
42773
42790
  this.linkTo = new LinkTo(this.id, this.board.events);
42774
42791
  this.transformation = new Transformation(this.id, this.board.events);
42775
42792
  this.text = new RichText(board, this.textContainer, this.id, this.transformation, this.linkTo, " ", false, true, this.itemType);
42776
- this.text.worldMatrixGetter = () => this.getParentWorldMatrix();
42777
42793
  this.transformation.subject.subscribe((_subject, op) => {
42778
42794
  this.transformPath();
42779
42795
  if (op.method === "applyMatrix") {
@@ -56570,6 +56586,123 @@ class BoardSelection {
56570
56586
  });
56571
56587
  }
56572
56588
  }
56589
+ // src/Gravity/GravityEngine.ts
56590
+ class GravityEngine {
56591
+ board;
56592
+ velocities = new Map;
56593
+ tickTimer = null;
56594
+ syncTimer = null;
56595
+ lastSyncedPositions = new Map;
56596
+ G = 500;
56597
+ DAMPING = 0.98;
56598
+ TICK_MS = 33;
56599
+ SYNC_MS = 300;
56600
+ MAX_DISTANCE = 3000;
56601
+ SOFTENING_SQ = 50 * 50;
56602
+ MIN_MOVE_PX = 0.1;
56603
+ constructor(board) {
56604
+ this.board = board;
56605
+ }
56606
+ start() {
56607
+ if (this.tickTimer !== null)
56608
+ return;
56609
+ for (const item of this.board.items.listAll()) {
56610
+ this.velocities.set(item.getId(), { vx: 0, vy: 0 });
56611
+ }
56612
+ this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
56613
+ this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
56614
+ }
56615
+ stop() {
56616
+ if (this.tickTimer !== null) {
56617
+ clearInterval(this.tickTimer);
56618
+ this.tickTimer = null;
56619
+ }
56620
+ if (this.syncTimer !== null) {
56621
+ clearInterval(this.syncTimer);
56622
+ this.syncTimer = null;
56623
+ }
56624
+ this.velocities.clear();
56625
+ this.lastSyncedPositions.clear();
56626
+ }
56627
+ tick() {
56628
+ const dt = this.TICK_MS / 1000;
56629
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
56630
+ if (items.length < 2)
56631
+ return;
56632
+ for (const item of items) {
56633
+ const id = item.getId();
56634
+ if (!this.velocities.has(id)) {
56635
+ this.velocities.set(id, { vx: 0, vy: 0 });
56636
+ }
56637
+ const vel = this.velocities.get(id);
56638
+ const pos1 = item.transformation.getTranslation();
56639
+ const mbr1 = item.getMbr();
56640
+ const mass1 = mbr1.getWidth() * mbr1.getHeight();
56641
+ const nearby = this.board.items.getEnclosedOrCrossed(pos1.x - this.MAX_DISTANCE, pos1.y - this.MAX_DISTANCE, pos1.x + this.MAX_DISTANCE * 2, pos1.y + this.MAX_DISTANCE * 2).filter((other) => other.getId() !== id);
56642
+ let ax = 0;
56643
+ let ay = 0;
56644
+ for (const other of nearby) {
56645
+ const pos2 = other.transformation.getTranslation();
56646
+ const mbr2 = other.getMbr();
56647
+ const mass2 = mbr2.getWidth() * mbr2.getHeight();
56648
+ const dx2 = pos2.x - pos1.x;
56649
+ const dy2 = pos2.y - pos1.y;
56650
+ const distSq = dx2 * dx2 + dy2 * dy2 + this.SOFTENING_SQ;
56651
+ const dist = Math.sqrt(distSq);
56652
+ const acc = this.G * mass2 / distSq;
56653
+ ax += acc * dx2 / dist;
56654
+ ay += acc * dy2 / dist;
56655
+ }
56656
+ vel.vx = (vel.vx + ax * dt) * this.DAMPING;
56657
+ vel.vy = (vel.vy + ay * dt) * this.DAMPING;
56658
+ const dx = vel.vx * dt;
56659
+ const dy = vel.vy * dt;
56660
+ if (Math.abs(dx) >= this.MIN_MOVE_PX || Math.abs(dy) >= this.MIN_MOVE_PX) {
56661
+ item.transformation.applyMatrixSilent({
56662
+ translateX: dx,
56663
+ translateY: dy,
56664
+ scaleX: 1,
56665
+ scaleY: 1,
56666
+ shearX: 0,
56667
+ shearY: 0
56668
+ });
56669
+ }
56670
+ }
56671
+ }
56672
+ syncPositions() {
56673
+ const items = this.board.items.listAll().filter((item) => !item.transformation.isLocked);
56674
+ if (items.length === 0)
56675
+ return;
56676
+ const movedItems = items.map((item) => {
56677
+ const id = item.getId();
56678
+ const pos = item.transformation.getTranslation();
56679
+ const last = this.lastSyncedPositions.get(id);
56680
+ const dx = last ? pos.x - last.x : 0;
56681
+ const dy = last ? pos.y - last.y : 0;
56682
+ this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
56683
+ return { id, dx, dy };
56684
+ }).filter(({ dx, dy }) => Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5);
56685
+ if (movedItems.length === 0)
56686
+ return;
56687
+ const operation = {
56688
+ class: "Transformation",
56689
+ method: "applyMatrix",
56690
+ items: movedItems.map(({ id, dx, dy }) => ({
56691
+ id,
56692
+ matrix: {
56693
+ translateX: dx,
56694
+ translateY: dy,
56695
+ scaleX: 1,
56696
+ scaleY: 1,
56697
+ shearX: 0,
56698
+ shearY: 0
56699
+ }
56700
+ }))
56701
+ };
56702
+ this.board.events.emit(operation);
56703
+ }
56704
+ }
56705
+
56573
56706
  // src/Board.ts
56574
56707
  class Board {
56575
56708
  boardId;
@@ -57592,6 +57725,22 @@ class Board {
57592
57725
  this.selection.quickAddButtons.clear();
57593
57726
  this.presence.cleanup();
57594
57727
  }
57728
+ gravity = null;
57729
+ enableGravity() {
57730
+ if (this.gravity)
57731
+ return;
57732
+ this.gravity = new GravityEngine(this);
57733
+ this.gravity.start();
57734
+ }
57735
+ disableGravity() {
57736
+ if (!this.gravity)
57737
+ return;
57738
+ this.gravity.stop();
57739
+ this.gravity = null;
57740
+ }
57741
+ isGravityEnabled() {
57742
+ return this.gravity !== null;
57743
+ }
57595
57744
  }
57596
57745
  // src/Events/Merge.ts
57597
57746
  import { Path as Path14 } from "slate";
@@ -133,6 +133,10 @@ export declare class Board {
133
133
  setIsOpen(isOpen: boolean): void;
134
134
  getIsOpen(): boolean;
135
135
  cleanup(): void;
136
+ private gravity;
137
+ enableGravity(): void;
138
+ disableGravity(): void;
139
+ isGravityEnabled(): boolean;
136
140
  }
137
141
  export interface BoardSnapshot {
138
142
  items: (ItemData & {
@@ -0,0 +1,20 @@
1
+ import { Board } from '../Board';
2
+ export declare class GravityEngine {
3
+ private board;
4
+ private velocities;
5
+ private tickTimer;
6
+ private syncTimer;
7
+ private lastSyncedPositions;
8
+ readonly G = 500;
9
+ readonly DAMPING = 0.98;
10
+ readonly TICK_MS = 33;
11
+ readonly SYNC_MS = 300;
12
+ readonly MAX_DISTANCE = 3000;
13
+ readonly SOFTENING_SQ: number;
14
+ readonly MIN_MOVE_PX = 0.1;
15
+ constructor(board: Board);
16
+ start(): void;
17
+ stop(): void;
18
+ private tick;
19
+ private syncPositions;
20
+ }
@@ -61,6 +61,7 @@ export declare class Transformation {
61
61
  rotateBy(degree: number, timeStamp?: number): void;
62
62
  scaleToRelativeTo(x: number, y: number, _point: Point, timeStamp?: number): void;
63
63
  scaleByRelativeTo(x: number, y: number, point: Point, timeStamp?: number): void;
64
+ applyMatrixSilent(matrixData: MatrixData): void;
64
65
  setIsLocked(isLocked: boolean, timestamp?: number): void;
65
66
  apply(op: Operation): void;
66
67
  /** @deprecated Only for replaying legacy events. Do not call directly. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "microboard-temp",
3
- "version": "0.11.8",
3
+ "version": "0.12.0",
4
4
  "description": "A flexible interactive whiteboard library",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",