microboard-temp 0.11.9 → 0.12.1

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({
@@ -54286,6 +54296,123 @@ class BoardSelection {
54286
54296
  });
54287
54297
  }
54288
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
+
54289
54416
  // src/Board.ts
54290
54417
  class Board {
54291
54418
  boardId;
@@ -55308,6 +55435,22 @@ class Board {
55308
55435
  this.selection.quickAddButtons.clear();
55309
55436
  this.presence.cleanup();
55310
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
+ }
55311
55454
  }
55312
55455
  // src/Events/Merge.ts
55313
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({
@@ -54286,6 +54296,123 @@ class BoardSelection {
54286
54296
  });
54287
54297
  }
54288
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
+
54289
54416
  // src/Board.ts
54290
54417
  class Board {
54291
54418
  boardId;
@@ -55308,6 +55435,22 @@ class Board {
55308
55435
  this.selection.quickAddButtons.clear();
55309
55436
  this.presence.cleanup();
55310
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
+ }
55311
55454
  }
55312
55455
  // src/Events/Merge.ts
55313
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({
@@ -56759,6 +56769,123 @@ class BoardSelection {
56759
56769
  });
56760
56770
  }
56761
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
+
56762
56889
  // src/Board.ts
56763
56890
  class Board {
56764
56891
  boardId;
@@ -57781,6 +57908,22 @@ class Board {
57781
57908
  this.selection.quickAddButtons.clear();
57782
57909
  this.presence.cleanup();
57783
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
+ }
57784
57927
  }
57785
57928
  // src/Events/Merge.ts
57786
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({
@@ -54115,6 +54125,123 @@ class BoardSelection {
54115
54125
  });
54116
54126
  }
54117
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
+
54118
54245
  // src/Board.ts
54119
54246
  class Board {
54120
54247
  boardId;
@@ -55137,6 +55264,22 @@ class Board {
55137
55264
  this.selection.quickAddButtons.clear();
55138
55265
  this.presence.cleanup();
55139
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
+ }
55140
55283
  }
55141
55284
  // src/Events/Merge.ts
55142
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({
@@ -54108,6 +54118,123 @@ class BoardSelection {
54108
54118
  });
54109
54119
  }
54110
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
+
54111
54238
  // src/Board.ts
54112
54239
  class Board {
54113
54240
  boardId;
@@ -55130,6 +55257,22 @@ class Board {
55130
55257
  this.selection.quickAddButtons.clear();
55131
55258
  this.presence.cleanup();
55132
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
+ }
55133
55276
  }
55134
55277
  // src/Events/Merge.ts
55135
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({
@@ -56576,6 +56586,123 @@ class BoardSelection {
56576
56586
  });
56577
56587
  }
56578
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
+
56579
56706
  // src/Board.ts
56580
56707
  class Board {
56581
56708
  boardId;
@@ -57598,6 +57725,22 @@ class Board {
57598
57725
  this.selection.quickAddButtons.clear();
57599
57726
  this.presence.cleanup();
57600
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
+ }
57601
57744
  }
57602
57745
  // src/Events/Merge.ts
57603
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.9",
3
+ "version": "0.12.1",
4
4
  "description": "A flexible interactive whiteboard library",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",