squishjs 0.6.41 → 0.7.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.
Files changed (50) hide show
  1. package/.github/workflows/node.js.yml +1 -1
  2. package/LICENSE.md +21 -0
  3. package/README.md +116 -42
  4. package/index.js +11 -1
  5. package/oldsvgexport.js +89 -0
  6. package/package.json +1 -1
  7. package/render-tester.js +120 -0
  8. package/src/BaseNode.js +101 -0
  9. package/src/Game.js +15 -3
  10. package/src/GameNode.js +82 -79
  11. package/src/InternalGameNode.js +4 -3
  12. package/src/Squisher.js +224 -0
  13. package/src/ViewableGame.js +60 -0
  14. package/src/node-types.js +15 -0
  15. package/src/squish.js +90 -349
  16. package/src/squishHelpers/asset.js +63 -0
  17. package/src/squishHelpers/border.js +16 -0
  18. package/src/squishHelpers/color.js +16 -0
  19. package/src/squishHelpers/coordinates2d.js +98 -0
  20. package/src/squishHelpers/effect.js +55 -0
  21. package/src/squishHelpers/fill.js +16 -0
  22. package/src/squishHelpers/handleClick.js +16 -0
  23. package/src/squishHelpers/id.js +16 -0
  24. package/src/squishHelpers/input.js +22 -0
  25. package/src/squishHelpers/playerIds.js +12 -0
  26. package/src/squishHelpers/pos.js +23 -0
  27. package/src/squishHelpers/size.js +23 -0
  28. package/src/squishHelpers/subType.js +16 -0
  29. package/src/squishHelpers/text.js +154 -0
  30. package/src/subtype-mappings.js +10 -0
  31. package/src/subtypes.js +7 -0
  32. package/src/terrain/defs.ts +16 -0
  33. package/src/terrain/index.ts +156 -0
  34. package/src/terrain/terrainFunctions.ts +142 -0
  35. package/src/util/geometry.js +45 -0
  36. package/src/util/index.ts +6 -0
  37. package/src/util/listenable.ts +20 -0
  38. package/src/util/shapes.ts +18 -0
  39. package/src/util/views.js +108 -0
  40. package/test/Layers.test.js +63 -0
  41. package/test/Scale.test.js +235 -0
  42. package/test/Squisher.test.js +49 -0
  43. package/test/StateUpdates.js +10 -0
  44. package/test/Terrain.test.js +0 -1
  45. package/test/main.test.js +55 -35
  46. package/test/utils.js +91 -0
  47. package/testapp.html +26 -0
  48. package/testapp.js +988 -0
  49. package/tsconfig.json +22 -0
  50. package/license.txt +0 -674
@@ -0,0 +1,142 @@
1
+ import { pointDef, boardInfo } from './defs';
2
+
3
+ const placeTerrain = (board: boardInfo[][], { x, y }: pointDef, boardWidth: number, boardHeight: number, keyPoint: pointDef) => {
4
+ if (x < 0 || x >= boardWidth) {
5
+ return;
6
+ } else if (y < 0 || y >= boardHeight) {
7
+ return;
8
+ } else if ( x === keyPoint.x && y === keyPoint.y) {
9
+ return;
10
+ }
11
+
12
+ if (!board[x][y].filled) {
13
+ if (board[x][y].north) {
14
+ board[x][y - 1].south = false;
15
+ }
16
+ if (board[x][y].south) {
17
+ board[x][y + 1].north = false;
18
+ }
19
+ if (board[x][y].east) {
20
+ board[x + 1][y].west = false;
21
+ }
22
+ if (board[x][y].west) {
23
+ board[x - 1][y].east = false;
24
+ }
25
+ board[x][y].filled = true;
26
+ board[x][y].north = false;
27
+ board[x][y].south = false;
28
+ board[x][y].east = false;
29
+ board[x][y].west = false;
30
+ }
31
+ }
32
+
33
+ const square = (board: boardInfo[][], { x, y }: pointDef, boardWidth: number, boardHeight: number, keyPoint: pointDef) => {
34
+ const option = Math.floor(Math.random() * 4);
35
+ placeTerrain(board, { x, y }, boardWidth, boardHeight, keyPoint);
36
+ if (option === 0) { // start point is top left
37
+ placeTerrain(board, { x: x + 1, y }, boardWidth, boardHeight, keyPoint);
38
+ placeTerrain(board, { x, y: y + 1 }, boardWidth, boardHeight, keyPoint);
39
+ placeTerrain(board, { x: x + 1, y: y + 1 }, boardWidth, boardHeight, keyPoint);
40
+ } else if (option === 1) { // start point is top right
41
+ placeTerrain(board, { x: x - 1, y }, boardWidth, boardHeight, keyPoint);
42
+ placeTerrain(board, { x, y: y + 1 }, boardWidth, boardHeight, keyPoint);
43
+ placeTerrain(board, { x: x - 1, y: y + 1 }, boardWidth, boardHeight, keyPoint);
44
+ } else if (option === 2) { // start point is bottom left
45
+ placeTerrain(board, { x, y: y - 1 }, boardWidth, boardHeight, keyPoint);
46
+ placeTerrain(board, { x: x + 1, y }, boardWidth, boardHeight, keyPoint);
47
+ placeTerrain(board, { x: x + 1, y: y - 1 }, boardWidth, boardHeight, keyPoint);
48
+ } else { // start point is bottom right
49
+ placeTerrain(board, { x, y: y - 1 }, boardWidth, boardHeight, keyPoint);
50
+ placeTerrain(board, { x: x - 1, y }, boardWidth, boardHeight, keyPoint);
51
+ placeTerrain(board, { x: x - 1, y: y - 1 }, boardWidth, boardHeight, keyPoint);
52
+ }
53
+ };
54
+
55
+ const line = (board: boardInfo[][], { x, y }: pointDef, boardWidth: number, boardHeight: number, keyPoint: pointDef) => {
56
+ const option = Math.floor(Math.random() * 4);
57
+ placeTerrain(board, { x, y }, boardWidth, boardHeight, keyPoint);
58
+ if (option === 0) { // start point is top
59
+ placeTerrain(board, { x, y: y + 1}, boardWidth, boardHeight, keyPoint);
60
+ placeTerrain(board, { x, y: y + 2 }, boardWidth, boardHeight, keyPoint);
61
+ placeTerrain(board, { x, y: y + 3 }, boardWidth, boardHeight, keyPoint);
62
+ } else if (option === 1) { // start point is left
63
+ placeTerrain(board, { x: x + 1, y }, boardWidth, boardHeight, keyPoint);
64
+ placeTerrain(board, { x: x + 2, y }, boardWidth, boardHeight, keyPoint);
65
+ placeTerrain(board, { x: x + 3, y }, boardWidth, boardHeight, keyPoint);
66
+ } else if (option === 2) { // start point is right
67
+ placeTerrain(board, { x: x - 1, y }, boardWidth, boardHeight, keyPoint);
68
+ placeTerrain(board, { x: x - 2, y }, boardWidth, boardHeight, keyPoint);
69
+ placeTerrain(board, { x: x - 3, y }, boardWidth, boardHeight, keyPoint);
70
+ } else { // start point is bottom
71
+ placeTerrain(board, { x, y: y - 1 }, boardWidth, boardHeight, keyPoint);
72
+ placeTerrain(board, { x, y: y - 2 }, boardWidth, boardHeight, keyPoint);
73
+ placeTerrain(board, { x, y: y - 3 }, boardWidth, boardHeight, keyPoint);
74
+ }
75
+ };
76
+
77
+ const bentLine = (board: boardInfo[][], { x, y }: pointDef, boardWidth: number, boardHeight: number, keyPoint: pointDef) => {
78
+ const option = Math.floor(Math.random() * 4);
79
+ placeTerrain(board, { x, y }, boardWidth, boardHeight, keyPoint);
80
+ if (option === 0) { // start point is top
81
+ placeTerrain(board, { x, y: y + 1 }, boardWidth, boardHeight, keyPoint);
82
+ placeTerrain(board, { x, y: y + 2 }, boardWidth, boardHeight, keyPoint);
83
+ placeTerrain(board, { x: x + 1, y: y + 2 }, boardWidth, boardHeight, keyPoint);
84
+ } else if (option === 1) { // start point is left
85
+ placeTerrain(board, { x: x + 1, y }, boardWidth, boardHeight, keyPoint);
86
+ placeTerrain(board, { x: x + 2, y }, boardWidth, boardHeight, keyPoint);
87
+ placeTerrain(board, { x: x + 2, y: y - 1 }, boardWidth, boardHeight, keyPoint);
88
+ } else if (option === 2) { // start point is right
89
+ placeTerrain(board, { x: x - 1, y }, boardWidth, boardHeight, keyPoint);
90
+ placeTerrain(board, { x: x - 2, y }, boardWidth, boardHeight, keyPoint);
91
+ placeTerrain(board, { x: x - 2, y: y + 1 }, boardWidth, boardHeight, keyPoint);
92
+ } else { // start point is bottom
93
+ placeTerrain(board, { x, y: y - 1 }, boardWidth, boardHeight, keyPoint);
94
+ placeTerrain(board, { x, y: y - 2 }, boardWidth, boardHeight, keyPoint);
95
+ placeTerrain(board, { x: x - 1, y: y - 2 }, boardWidth, boardHeight, keyPoint);
96
+ }
97
+ };
98
+
99
+ const zShape = (board: boardInfo[][], { x, y }: pointDef, boardWidth: number, boardHeight: number, keyPoint: pointDef) => {
100
+ const option = Math.floor(Math.random() * 4);
101
+ placeTerrain(board, { x, y }, boardWidth, boardHeight, keyPoint);
102
+ if (option === 0) { // start point is top
103
+ placeTerrain(board, { x, y: y + 1 }, boardWidth, boardHeight, keyPoint);
104
+ placeTerrain(board, { x: x - 1, y: y + 1 }, boardWidth, boardHeight, keyPoint);
105
+ placeTerrain(board, { x: x - 1, y: y + 2 }, boardWidth, boardHeight, keyPoint);
106
+ } else if (option === 1) { // start point is left
107
+ placeTerrain(board, { x: x + 1, y }, boardWidth, boardHeight, keyPoint);
108
+ placeTerrain(board, { x: x + 1, y: y + 1 }, boardWidth, boardHeight, keyPoint);
109
+ placeTerrain(board, { x: x + 2, y: y + 1 }, boardWidth, boardHeight, keyPoint);
110
+ } else if (option === 2) { // start point is right
111
+ placeTerrain(board, { x: x - 1, y }, boardWidth, boardHeight, keyPoint);
112
+ placeTerrain(board, { x: x - 1, y: y + 1 }, boardWidth, boardHeight, keyPoint);
113
+ placeTerrain(board, { x: x - 2, y: y + 1 }, boardWidth, boardHeight, keyPoint);
114
+ } else { // start point is bottom
115
+ placeTerrain(board, { x, y: y - 1 }, boardWidth, boardHeight, keyPoint);
116
+ placeTerrain(board, { x: x - 1, y: y - 1 }, boardWidth, boardHeight, keyPoint);
117
+ placeTerrain(board, { x: x - 1, y: y - 2 }, boardWidth, boardHeight, keyPoint);
118
+ }
119
+ };
120
+
121
+ const terrainFunctions = [
122
+ square,
123
+ line,
124
+ bentLine,
125
+ zShape
126
+ ];
127
+
128
+ export const getRandomTerrain = () => {
129
+ return terrainFunctions[Math.floor(Math.random() * terrainFunctions.length)];
130
+ };
131
+
132
+ export const getRandomStartPoint = (boardWidth: number, boardHeight: number, keyPoint: pointDef) => {
133
+ const startPoint = {
134
+ x: Math.floor(Math.random() * boardWidth),
135
+ y: Math.floor(Math.random() * boardHeight)
136
+ };
137
+ while (startPoint.x === keyPoint.x && startPoint.y === keyPoint.y) {
138
+ startPoint.x = Math.floor(Math.random() * boardWidth);
139
+ startPoint.y = Math.floor(Math.random() * boardHeight);
140
+ }
141
+ return startPoint;
142
+ };
@@ -0,0 +1,45 @@
1
+ const collisionHelper = (node, nodeToCheck, filter, collisions = []) => {
2
+ // assume rectangles for now
3
+
4
+ if (!filter || (filter(node) && node.node.id !== nodeToCheck.node.id)) {
5
+ // todo: clean this up its gross
6
+ // text does not have coordinates, so make a fake vertices array from the starting point of the text
7
+ const nodeText = node.node.text;
8
+ const vertices = node.node.coordinates2d || [
9
+ [nodeText.x, nodeText.y],
10
+ [nodeText.x, nodeText.y],
11
+ [nodeText.x, nodeText.y],
12
+ [nodeText.x, nodeText.y],
13
+ [nodeText.x, nodeText.y]
14
+ ];
15
+ const verticesToCheck = nodeToCheck.node.coordinates2d;
16
+
17
+ const node1LeftX = vertices[0][0];
18
+ const node1RightX = vertices[1][0];
19
+ const node2LeftX = verticesToCheck[0][0];
20
+ const node2RightX = verticesToCheck[1][0];
21
+
22
+ const node1TopY = vertices[0][1];
23
+ const node1BottomY = vertices[2][1];
24
+ const node2TopY = verticesToCheck[0][1];
25
+ const node2BottomY = verticesToCheck[2][1];
26
+
27
+ const oneToTheLeft = node2RightX < node1LeftX || node1RightX < node2LeftX;
28
+ const oneBelow = node1TopY > node2BottomY || node2TopY > node1BottomY;
29
+ if (!(oneToTheLeft || oneBelow)) {
30
+ collisions.push(node);
31
+ }
32
+ }
33
+
34
+ for (const child in node.node.children) {
35
+ collisionHelper(node.node.children[child], nodeToCheck, filter, collisions);
36
+ }
37
+
38
+ return collisions;
39
+ };
40
+
41
+ const checkCollisions = (root, node, filter = null) => {
42
+ return collisionHelper(root, node, filter);
43
+ };
44
+
45
+ module.exports = { checkCollisions };
@@ -0,0 +1,6 @@
1
+ export const hypLength = (x: number, y: number) => Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
2
+
3
+ // get the first 2 digits after the decimal
4
+ export const getFractional = (number: number) => {
5
+ return Math.round(100 * (number - Math.floor(number)));
6
+ };
@@ -0,0 +1,20 @@
1
+ import { gameNodeDef, internalGameNodeDef } from '../sharedDefs';
2
+ export default (obj: internalGameNodeDef, onChange: () => void) => {
3
+ const handler = {
4
+ get(target: Object, property: PropertyKey, receiver: any) {
5
+ return Reflect.get(target, property, receiver);
6
+ },
7
+ defineProperty(target: Object, property: PropertyKey, descriptor: PropertyDescriptor) {
8
+ const change = Reflect.defineProperty(target, property, descriptor);
9
+ onChange && onChange();
10
+ return change;
11
+ },
12
+ deleteProperty(target: Object, property: PropertyKey) {
13
+ const change = Reflect.deleteProperty(target, property);
14
+ onChange && onChange();
15
+ return change;
16
+ }
17
+ };
18
+
19
+ return new Proxy(obj, handler);
20
+ };
@@ -0,0 +1,18 @@
1
+ export const rectangle = (startX: number, startY: number, width: number, height: number) => {
2
+ return [
3
+ [startX, startY],
4
+ [startX + width, startY],
5
+ [startX + width, startY + height],
6
+ [startX, startY + height],
7
+ [startX, startY],
8
+ ];
9
+ };
10
+
11
+ export const triangle = (x1: number, y1: number, x2: number, y2: number, x3: number, y3: number) => {
12
+ return [
13
+ [x1, y1],
14
+ [x2, y2],
15
+ [x3, y3],
16
+ [x1, y1]
17
+ ];
18
+ };
@@ -0,0 +1,108 @@
1
+ const { GameNode } = require('../GameNode');
2
+ const Shapes = require('../Shapes');
3
+ const ShapeUtils = require('./shapes');
4
+ const GeometryUtils = require('./geometry');
5
+ const Colors = require('../Colors');
6
+
7
+ const getView = (plane, view, playerIds, translation = {}) => {
8
+
9
+ const wouldBeCollisions = GeometryUtils.checkCollisions(plane, {node: {coordinates2d: ShapeUtils.rectangle(view.x, view.y, view.w, view.h)}}, (node) => {
10
+ return node.node.id !== plane.node.id;
11
+ });
12
+
13
+ const convertedRoot = new GameNode.Shape({
14
+ shapeType: Shapes.POLYGON,
15
+ coordinates2d: ShapeUtils.rectangle(0, 0, 0, 0),
16
+ fill: Colors.COLORS.BLACK
17
+ });
18
+
19
+ const convertedNodes = [];
20
+
21
+ if (wouldBeCollisions.length > 0) {
22
+ wouldBeCollisions.forEach(node => {
23
+ let shouldInclude = true;
24
+
25
+ const translatedCoords = [];
26
+
27
+ // same hack as geometry utils
28
+ const vertices = node.node.coordinates2d || [
29
+ [node.node.text.x, node.node.text.y],
30
+ [node.node.text.x, node.node.text.y],
31
+ [node.node.text.x, node.node.text.y],
32
+ [node.node.text.x, node.node.text.y],
33
+ [node.node.text.x, node.node.text.y]
34
+ ];
35
+
36
+ for (let coorPairIndex in vertices) {
37
+ const coordPair = vertices[coorPairIndex];
38
+ const x = coordPair[0];
39
+ const y = coordPair[1];
40
+ let translatedX = Math.max(Math.min(x - view.x, 100), 0);
41
+ let translatedY = Math.max(Math.min(y - view.y, 100), 0);
42
+
43
+ const shouldTranslate = translation.filter ? translation.filter(node) : true;
44
+
45
+ if (shouldTranslate) {
46
+ if (translation.x) {
47
+ translatedX += translation.x;
48
+ }
49
+
50
+ if (translation.y) {
51
+ translatedY += translation.y;
52
+ }
53
+
54
+ if (translatedX < 0 || translatedX > 100) {
55
+ shouldInclude = false;
56
+ }
57
+
58
+ if (translatedY < 0 || translatedY > 100) {
59
+ shouldInclude = false;
60
+ }
61
+ }
62
+
63
+ const xScale = 1//100 / (view.w || 100);
64
+ const yScale = 1//100 / (view.h || 100);
65
+
66
+ translatedX = xScale * translatedX;
67
+ translatedY = yScale * translatedY;
68
+
69
+ translatedCoords.push([translatedX, translatedY]);
70
+ }
71
+
72
+ if (shouldInclude) {
73
+ const copied = node.clone({handleClick: node.node.handleClick === null || node.node.handleClick === undefined ? null : node.node.handleClick});
74
+
75
+ if (translatedCoords && translatedCoords.length) {
76
+ if (copied.node.text) {
77
+ copied.node.text.x = translatedCoords[0][0];
78
+ copied.node.text.y = translatedCoords[0][1];
79
+ }
80
+ if (translatedCoords.length) {
81
+ copied.node.coordinates2d = translatedCoords;
82
+ }
83
+ if (copied.node.asset) {
84
+ const firstPoint = copied.node.coordinates2d[0];
85
+ const secondPoint = copied.node.coordinates2d[1];
86
+ const thirdPoint = copied.node.coordinates2d[2];
87
+ const width = secondPoint[0] - firstPoint[0];
88
+ const height = thirdPoint[1] - secondPoint[1];
89
+ Object.values(copied.node.asset)[0].pos.x = firstPoint[0];
90
+ Object.values(copied.node.asset)[0].pos.y = firstPoint[1];
91
+ Object.values(copied.node.asset)[0].size.x = width;
92
+ Object.values(copied.node.asset)[0].size.y = height;
93
+ }
94
+ }
95
+ copied.node.playerIds = playerIds || [];
96
+ convertedNodes.push(copied);
97
+ }
98
+ });
99
+ }
100
+
101
+ convertedNodes.forEach(c => convertedRoot.addChild(c));
102
+
103
+ return convertedRoot;
104
+ };
105
+
106
+ module.exports = {
107
+ getView
108
+ }
@@ -0,0 +1,63 @@
1
+ const { COLORS } = require("../src/Colors");
2
+ const assert = require("assert");
3
+ const Squisher = require('../src/Squisher');
4
+ const { squish, unsquish } = require('../src/squish');
5
+ const { FakeGame, verifyArrayEquality, rectNode, polygonNode, circleNode } = require('./utils');
6
+
7
+ test("two layers on a base - square over square", () => {
8
+ const base = rectNode({ x: 0, y: 0, width: 100, height: 100, fill: COLORS.RED });
9
+ const layerOne = rectNode({ x: 40, y: 40, width: 20, height: 20, fill: COLORS.BLUE });
10
+ const layerTwo = rectNode({ x: 45, y: 45, width: 10, height: 10, fill: COLORS.GREEN });
11
+
12
+ const game = new FakeGame([
13
+ {
14
+ root: base
15
+ },
16
+ {
17
+ root: layerOne
18
+ },
19
+ {
20
+ root: layerTwo
21
+ }
22
+ ]);
23
+
24
+ const squisher = new Squisher({ game });
25
+
26
+ assert(squisher.state.length === 3);
27
+ verifyArrayEquality(squisher.state[0], squish(base));
28
+ verifyArrayEquality(squisher.state[1], squish(layerOne));
29
+ verifyArrayEquality(squisher.state[2], squish(layerTwo));
30
+ });
31
+
32
+ test("test layer with child added", () => {
33
+ const base = rectNode({ x: 0, y: 0, width: 100, height: 100, fill: COLORS.RED });
34
+ const layer = rectNode({ x: 40, y: 40, width: 20, height: 20, fill: COLORS.BLUE });
35
+
36
+ const game = new FakeGame([
37
+ {
38
+ root: base
39
+ },
40
+ {
41
+ root: layer
42
+ }
43
+ ]);
44
+
45
+ const squisher = new Squisher({ game });
46
+
47
+ const initialState = Array.from(squisher.state);
48
+ assert(initialState.length === 2);
49
+ verifyArrayEquality(initialState[0], squish(base));
50
+ verifyArrayEquality(initialState[1], squish(layer));
51
+
52
+ const child = rectNode({ x: 50, y: 50, height: 25, width: 25, fill: COLORS.WHITE });
53
+
54
+ // adding a child should trigger an update in the squisher and result in a new state
55
+ layer.addChild(child);
56
+
57
+ const expectedLayerValue = [squish(layer), squish(child)].flat();
58
+ const stateWithChild = Array.from(squisher.state);
59
+ assert(stateWithChild.length === 3);
60
+ verifyArrayEquality(stateWithChild[0], squish(base));
61
+ verifyArrayEquality(stateWithChild[1], squish(layer));
62
+ verifyArrayEquality(stateWithChild[2], squish(child));
63
+ });
@@ -0,0 +1,235 @@
1
+ const { COLORS } = require("../src/Colors");
2
+ const assert = require("assert");
3
+ const Squisher = require('../src/Squisher');
4
+ const { unsquish } = require('../src/squish');
5
+
6
+ const { FakeGame, verifyArrayEquality, rectNode, textNode, polygonNode, circleNode, lineNode } = require('./utils');
7
+
8
+ test("90% scale rectangles", () => {
9
+
10
+ /*
11
+ * Red root taking up entirety of container.
12
+ * Four child nodes, each of a different color taking up a quarter of the container.
13
+ * If displayed on a screen, red would not be visible since children cover 100% of the overall space
14
+ */
15
+
16
+ const root = rectNode({ x: 0, y: 0, width: 100, height: 100, fill: COLORS.RED });
17
+ const topLeftCorner = rectNode({ x: 0, y: 0, width: 50, height: 50, fill: COLORS.BLUE });
18
+ const topRightCorner = rectNode({ x: 50, y: 0, width: 50, height: 50, fill: COLORS.GREEN });
19
+ const bottomRightCorner = rectNode({ x: 50, y: 50, width: 50, height: 50, fill: COLORS.BLACK });
20
+ const bottomLeftCorner = rectNode({ x: 0, y: 50, width: 50, height: 50, fill: COLORS.PURPLE});
21
+
22
+ root.addChildren(topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner);
23
+
24
+ const game = new FakeGame([
25
+ {
26
+ root,
27
+ scale: {
28
+ x: .9,
29
+ y: .9
30
+ }
31
+ }
32
+ ]);
33
+
34
+ const squisher = new Squisher({ game });
35
+
36
+ const nodesToRender = squisher.squish(game.getLayers());
37
+
38
+ assert(nodesToRender.length == 5);
39
+
40
+ const rootUnsquished = unsquish(nodesToRender[0]);
41
+ const topLeftUnsquished = unsquish(nodesToRender[1]);
42
+ const topRightUnsquished = unsquish(nodesToRender[2]);
43
+ const bottomRightUnsquished = unsquish(nodesToRender[3]);
44
+ const bottomLeftUnsquished = unsquish(nodesToRender[4]);
45
+
46
+ const rootCoords = rootUnsquished.node.coordinates2d;
47
+ const topLeftCoords = topLeftUnsquished.node.coordinates2d;
48
+ const topRightCoords = topRightUnsquished.node.coordinates2d;
49
+ const bottomRightCoords = bottomRightUnsquished.node.coordinates2d;
50
+ const bottomLeftCoords = bottomLeftUnsquished.node.coordinates2d;
51
+
52
+
53
+ /*
54
+ * Scaled 90% should mean centered with 5% margins
55
+ * Draw path starts at the top left, should match:
56
+ * (5, 5), (95, 5), (95, 95), (5, 95), (5, 5)
57
+ */
58
+ verifyArrayEquality(rootCoords, [
59
+ [5, 5],
60
+ [95, 5],
61
+ [95, 95],
62
+ [5, 95],
63
+ [5, 5]
64
+ ]);
65
+
66
+ /*
67
+ * width is 45, since it was 50% of the container, now scaled down to 90% (0.9 * .5 == 0.45)
68
+ * same as height
69
+ */
70
+ verifyArrayEquality(topLeftCoords, [
71
+ [5, 5],
72
+ [50, 5],
73
+ [50, 50],
74
+ [5, 50],
75
+ [5, 5]
76
+ ]);
77
+
78
+ verifyArrayEquality(topRightCoords, [
79
+ [50, 5],
80
+ [95, 5],
81
+ [95, 50],
82
+ [50, 50],
83
+ [50, 5]
84
+ ]);
85
+
86
+ verifyArrayEquality(bottomRightCoords, [
87
+ [50, 50],
88
+ [95, 50],
89
+ [95, 95],
90
+ [50, 95],
91
+ [50, 50]
92
+ ]);
93
+
94
+ verifyArrayEquality(bottomLeftCoords, [
95
+ [5, 50],
96
+ [50, 50],
97
+ [50, 95],
98
+ [5, 95],
99
+ [5, 50]
100
+ ]);
101
+ });
102
+
103
+ test("50% scale triangle", () => {
104
+
105
+ const root = polygonNode({coordinates: [20, 20, 30, 30, 10, 30, 20, 20], fill: COLORS.GREEN });
106
+
107
+ const game = new FakeGame([
108
+ {
109
+ root,
110
+ scale: {
111
+ x: .5,
112
+ y: .5
113
+ }
114
+ }
115
+ ]);
116
+
117
+ const squisher = new Squisher({ game });
118
+
119
+ const nodesToRender = squisher.squish(game.getLayers());
120
+
121
+ assert(nodesToRender.length == 1);
122
+
123
+ const rootUnsquished = unsquish(nodesToRender[0]);
124
+
125
+ const rootCoords = rootUnsquished.node.coordinates2d;
126
+
127
+ /*
128
+ * 50% scale means we're expecting half of the width & height, plus a margin of 25% on each edge of the container
129
+ * (to account for the full 100% of the container)
130
+ */
131
+ verifyArrayEquality(rootCoords, [
132
+ [35, 35],
133
+ [40, 40],
134
+ [30, 40],
135
+ [35, 35]
136
+ ]);
137
+
138
+ });
139
+
140
+ test("75% scale circle", () => {
141
+
142
+ const root = circleNode({center: {x: 50, y: 50 }, radius: 10, fill: COLORS.PINK });
143
+
144
+ const game = new FakeGame([
145
+ {
146
+ root,
147
+ scale: {
148
+ x: .75,
149
+ y: .75
150
+ }
151
+ }
152
+ ]);
153
+
154
+ const squisher = new Squisher({ game });
155
+ const nodesToRender = squisher.squish(game.getLayers());
156
+
157
+ assert(nodesToRender.length == 1);
158
+
159
+ const rootUnsquished = unsquish(nodesToRender[0]);
160
+
161
+ const rootCoords = rootUnsquished.node.coordinates2d;
162
+
163
+ /*
164
+ * 50% scale means we're expecting half of the width & height, plus a margin of 25% on each edge of the container
165
+ * (to account for the full 100% of the container)
166
+ */
167
+ verifyArrayEquality(rootCoords, [
168
+ 50, 50, 7.5
169
+ ]);
170
+
171
+ });
172
+
173
+ test('ayy lmao', () => {
174
+
175
+ const root = rectNode({ x: 0, y: 0, width: 100, height: 100, fill: COLORS.RED });
176
+ const topLeftCorner = rectNode({ x: 0, y: 0, width: 50, height: 50, fill: COLORS.BLUE });
177
+ const topRightCorner = rectNode({ x: 50, y: 0, width: 50, height: 50, fill: COLORS.GREEN });
178
+ const bottomRightCorner = rectNode({ x: 50, y: 50, width: 50, height: 50, fill: COLORS.BLACK });
179
+ const bottomLeftCorner = rectNode({ x: 0, y: 50, width: 50, height: 50, fill: COLORS.PURPLE});
180
+
181
+ const testTextNode = textNode({ text: 'ayy lmao', x: 75, y: 75, color: COLORS.WHITE, align: 'center' });
182
+ bottomRightCorner.addChild(testTextNode);
183
+
184
+ root.addChildren(topLeftCorner, topRightCorner, bottomRightCorner, bottomLeftCorner);
185
+
186
+ const game = new FakeGame([
187
+ {
188
+ root,
189
+ scale: {
190
+ x: 1,
191
+ y: 1
192
+ }
193
+ }
194
+ ]);
195
+
196
+ const squisher = new Squisher({ game });
197
+
198
+ const squishedLayers = squisher.state;
199
+
200
+ });
201
+
202
+ test("a line", () => {
203
+
204
+ const root = lineNode({coords: [[20, 20], [80, 80]], color: COLORS.ORANGE});
205
+
206
+ const game = new FakeGame([
207
+ {
208
+ root,
209
+ scale: {
210
+ x: 1,
211
+ y: 1
212
+ }
213
+ }
214
+ ]);
215
+
216
+ const squisher = new Squisher({ game });
217
+ const nodesToRender = squisher.squish(game.getLayers());
218
+
219
+ assert(nodesToRender.length == 1);
220
+
221
+ const rootUnsquished = unsquish(nodesToRender[0]);
222
+
223
+ const rootCoords = rootUnsquished.node.coordinates2d;
224
+
225
+ /*
226
+ * 50% scale means we're expecting half of the width & height, plus a margin of 25% on each edge of the container
227
+ * (to account for the full 100% of the container)
228
+ */
229
+ verifyArrayEquality(rootCoords, [
230
+ [20, 20], [80, 80]
231
+ ]);
232
+
233
+ });
234
+
235
+
@@ -0,0 +1,49 @@
1
+ const { COLORS } = require("../src/Colors");
2
+ const assert = require("assert");
3
+ const Squisher = require('../src/Squisher');
4
+ const { unsquish } = require('../src/squish');
5
+
6
+ const { FakeGame, verifyArrayEquality, rectNode, textNode, polygonNode, circleNode, lineNode } = require('./utils');
7
+
8
+ test("squisher listener", () => {
9
+
10
+ const root = lineNode({coords: [[20, 20], [80, 80]], color: COLORS.ORANGE});
11
+
12
+ const game = new FakeGame([
13
+ {
14
+ root,
15
+ scale: {
16
+ x: 1,
17
+ y: 1
18
+ }
19
+ }
20
+ ]);
21
+
22
+ const squisher = new Squisher({ game });
23
+
24
+ let timesInvoked = 0;
25
+
26
+ squisher.addListener((newSquishedState) => {
27
+ if (timesInvoked === 0) {
28
+ assert(newSquishedState.length == 1);
29
+ const updatedRoot = unsquish(newSquishedState[0]);
30
+ verifyArrayEquality(updatedRoot.node.color, COLORS.BLACK);
31
+ } else if (timesInvoked === 1) {
32
+ assert(newSquishedState.length == 1);
33
+ const updatedRoot = unsquish(newSquishedState[0]);
34
+ verifyArrayEquality(updatedRoot.node.color, COLORS.GREEN);
35
+ }
36
+ timesInvoked++;
37
+ });
38
+
39
+ assert(timesInvoked === 0);
40
+
41
+ root.node.color = COLORS.BLACK;
42
+
43
+ assert(timesInvoked === 1);
44
+
45
+ root.node.color = COLORS.GREEN;
46
+ assert(timesInvoked === 2);
47
+ });
48
+
49
+