jigsawpuzzlegame 1.0.7 → 1.0.8

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.
package/README.md CHANGED
@@ -52,10 +52,11 @@ Make sure your container has a defined size:
52
52
 
53
53
  | Option | Type | Default | Description |
54
54
  |--------|------|---------|-------------|
55
- | `image` | string | `null` | URL or data URL of the image to use for the puzzle |
56
- | `numPieces` | number | `20` | Number of puzzle pieces (approximate - actual count depends on optimal grid layout) |
57
- | `shapeType` | number | `0` | Shape type for puzzle pieces (0-3):<br>• `0` - Classic jigsaw shape (curved tabs)<br>• `1` - Alternative shape 1<br>• `2` - Alternative shape 2<br>• `3` - Straight edges (rectangular pieces) |
58
- | `allowRotation` | boolean | `false` | Whether pieces can be rotated by clicking/tapping (90° increments) |
55
+ | `image` | string | `null` | URL or data URL of the image to use for the puzzle (ignored if `savedData` is provided) |
56
+ | `savedData` | string\|null | `null` | JSON string of saved game state:<br>• Non-empty string: use this saved data<br>• Empty string (`""`): load from localStorage<br>• Not provided or `null`: use normal initialization with `image` and other parameters |
57
+ | `numPieces` | number | `20` | Number of puzzle pieces (approximate - actual count depends on optimal grid layout, ignored if `savedData` is provided) |
58
+ | `shapeType` | number | `0` | Shape type for puzzle pieces (0-3, ignored if `savedData` is provided):<br>• `0` - Classic jigsaw shape (curved tabs)<br>• `1` - Alternative shape 1<br>• `2` - Alternative shape 2<br>• `3` - Straight edges (rectangular pieces) |
59
+ | `allowRotation` | boolean | `false` | Whether pieces can be rotated by clicking/tapping (90° increments, ignored if `savedData` is provided) |
59
60
  | `onReady` | function | `null` | Callback function called when the puzzle is ready (image loaded and displayed) |
60
61
  | `onWin` | function | `null` | Callback function called when the puzzle is completed |
61
62
  | `onStart` | function | `null` | Callback function called when a game starts |
@@ -119,10 +120,10 @@ puzzle.setOptions({
119
120
 
120
121
  ### `save([callback])`
121
122
 
122
- Saves the current game state. If no callback is provided, saves to localStorage.
123
+ Saves the current game state. Gets the state data, converts it to a JSON string, then either calls the callback with the string or saves to localStorage.
123
124
 
124
125
  **Parameters:**
125
- - `callback` (function, optional) - Function that receives the saved data as JSON string
126
+ - `callback` (function, optional) - Function that receives the saved data as JSON string. If not provided, saves to localStorage automatically.
126
127
 
127
128
  ```javascript
128
129
  // Save to localStorage (default)
@@ -135,20 +136,30 @@ puzzle.save((savedData) => {
135
136
  });
136
137
  ```
137
138
 
138
- ### `load([savedData])`
139
+ ### Loading Saved Games
139
140
 
140
- Loads a previously saved game state.
141
-
142
- **Parameters:**
143
- - `savedData` (string, optional) - JSON string of saved data. If not provided, loads from localStorage
141
+ To load a saved game, create a new puzzle instance with the `savedData` option:
144
142
 
145
143
  ```javascript
146
- // Load from localStorage
147
- puzzle.load();
144
+ // Load from explicit string
145
+ const savedString = localStorage.getItem('myPuzzleSave');
146
+ const puzzle = new JigsawPuzzle('puzzle-container', {
147
+ savedData: savedString,
148
+ onReady: () => puzzle.start()
149
+ });
148
150
 
149
- // Load from custom data
150
- const savedData = localStorage.getItem('myPuzzleSave');
151
- puzzle.load(savedData);
151
+ // Load from localStorage automatically (pass empty string)
152
+ const puzzle = new JigsawPuzzle('puzzle-container', {
153
+ savedData: "", // Empty string triggers localStorage lookup
154
+ onReady: () => puzzle.start()
155
+ });
156
+
157
+ // Create new puzzle (no saved data)
158
+ const puzzle = new JigsawPuzzle('puzzle-container', {
159
+ image: 'image.jpg',
160
+ numPieces: 25,
161
+ onReady: () => puzzle.start()
162
+ });
152
163
  ```
153
164
 
154
165
  ### `destroy()`
@@ -196,11 +207,18 @@ function saveGame() {
196
207
  });
197
208
  }
198
209
 
199
- // Load game
210
+ // Load game - create new instance with saved data
200
211
  function loadGame() {
201
212
  const saved = localStorage.getItem('puzzleSave');
202
213
  if (saved) {
203
- puzzle.load(saved);
214
+ if (puzzle) puzzle.destroy();
215
+ puzzle = new JigsawPuzzle('puzzle-container', {
216
+ savedData: saved,
217
+ onReady: () => puzzle.start(),
218
+ onWin: () => {
219
+ alert('You won!');
220
+ }
221
+ });
204
222
  }
205
223
  }
206
224
  ```
@@ -1329,10 +1329,14 @@ export class JigsawPuzzle {
1329
1329
  * Creates a new JigsawPuzzle instance
1330
1330
  * @param {string|HTMLElement} containerId - ID of container div or element itself
1331
1331
  * @param {Object} options - Configuration options
1332
- * @param {string} options.image - Image URL or data URL to use
1333
- * @param {number} options.numPieces - Number of puzzle pieces (default: 20)
1334
- * @param {number} options.shapeType - Shape type 0-3 (default: 0)
1335
- * @param {boolean} options.allowRotation - Allow piece rotation (default: false)
1332
+ * @param {string} options.image - Image URL or data URL to use (ignored if savedData is provided)
1333
+ * @param {string|null} options.savedData - JSON string of saved game state:
1334
+ * - Non-empty string: use this saved data
1335
+ * - Empty string (""): load from localStorage
1336
+ * - Not provided or null: use normal initialization with options.image and other parameters
1337
+ * @param {number} options.numPieces - Number of puzzle pieces (default: 20, ignored if savedData is provided)
1338
+ * @param {number} options.shapeType - Shape type 0-3 (default: 0, ignored if savedData is provided)
1339
+ * @param {boolean} options.allowRotation - Allow piece rotation (default: false, ignored if savedData is provided)
1336
1340
  * @param {Function} options.onReady - Callback when puzzle is ready (image loaded, state 15)
1337
1341
  * @param {Function} options.onWin - Callback when puzzle is solved
1338
1342
  * @param {Function} options.onStart - Callback when game starts
@@ -1389,9 +1393,68 @@ export class JigsawPuzzle {
1389
1393
  this.events.push({ event: "resize" });
1390
1394
  });
1391
1395
 
1392
- // Load initial image if provided
1393
- if (this.options.image) {
1394
- this.setImage(this.options.image);
1396
+ // Handle saved data based on savedData option:
1397
+ // - Non-empty string: use that string
1398
+ // - Empty string: load from localStorage
1399
+ // - Not provided or null: use normal initialization
1400
+ let savedDataString = null;
1401
+
1402
+ if (options.savedData !== undefined && options.savedData !== null) {
1403
+ if (options.savedData === "") {
1404
+ // Empty string: load from localStorage
1405
+ try {
1406
+ savedDataString = localStorage.getItem("savepuzzle");
1407
+ } catch (exception) {
1408
+ // localStorage not available, continue with normal initialization
1409
+ }
1410
+ } else {
1411
+ // Non-empty string: use it directly
1412
+ savedDataString = options.savedData;
1413
+ }
1414
+ }
1415
+ // If savedData is not provided or null, savedDataString remains null and we use normal initialization
1416
+
1417
+ // If saved data found, parse and validate it
1418
+ if (savedDataString) {
1419
+ try {
1420
+ const parsedData = JSON.parse(savedDataString);
1421
+ // Validate signature and required fields
1422
+ if (parsedData.signature === FILE_SIGNATURE && parsedData.src) {
1423
+ this.restoredState = parsedData;
1424
+ // Set image from saved data (will override options.image)
1425
+ this.puzzle.imageLoaded = false;
1426
+ this.puzzle.srcImage.src = parsedData.src;
1427
+ if (parsedData.origin) {
1428
+ this.puzzle.srcImage.dataset.origin = parsedData.origin;
1429
+ }
1430
+ // Start restore flow - check if image is already loaded (cached)
1431
+ if (this.puzzle.srcImage.complete && this.puzzle.srcImage.naturalWidth > 0) {
1432
+ // Image already loaded, trigger load event manually
1433
+ this._imageLoaded();
1434
+ this.state = 158;
1435
+ } else {
1436
+ // Image will load asynchronously
1437
+ this.state = 158;
1438
+ }
1439
+ } else {
1440
+ // Invalid saved data, continue with normal initialization
1441
+ this.restoredState = null;
1442
+ if (this.options.image) {
1443
+ this.setImage(this.options.image);
1444
+ }
1445
+ }
1446
+ } catch (error) {
1447
+ // Invalid JSON, continue with normal initialization
1448
+ this.restoredState = null;
1449
+ if (this.options.image) {
1450
+ this.setImage(this.options.image);
1451
+ }
1452
+ }
1453
+ } else {
1454
+ // No saved data, load initial image if provided
1455
+ if (this.options.image) {
1456
+ this.setImage(this.options.image);
1457
+ }
1395
1458
  }
1396
1459
 
1397
1460
  // Start animation loop
@@ -1563,9 +1626,6 @@ export class JigsawPuzzle {
1563
1626
  } else if (event.event === "srcImageLoaded") {
1564
1627
  this.state = 10;
1565
1628
  return;
1566
- } else if (event.event === "restore") {
1567
- this.state = 150;
1568
- return;
1569
1629
  } else return;
1570
1630
 
1571
1631
  case 20:
@@ -1631,8 +1691,6 @@ export class JigsawPuzzle {
1631
1691
  if (event.event === "nbpieces") {
1632
1692
  this.puzzle.nbPieces = event.nbpieces;
1633
1693
  this.state = 20;
1634
- } else if (event.event === "save") {
1635
- this.state = 120;
1636
1694
  } else if (event.event === "touch") {
1637
1695
  this.moving = {
1638
1696
  xMouseInit: event.position.x,
@@ -1814,61 +1872,6 @@ export class JigsawPuzzle {
1814
1872
  }
1815
1873
  break;
1816
1874
 
1817
- case 120:
1818
- const savedData = this.puzzle.getStateData();
1819
- const savedString = JSON.stringify(savedData);
1820
- if (event && event.callback) {
1821
- event.callback(savedString);
1822
- }
1823
- this.state = 50;
1824
- break;
1825
-
1826
- case 150:
1827
- this.restoredString = "";
1828
- if (event && event.data) {
1829
- this.restoredString = event.data;
1830
- this.state = 155;
1831
- } else {
1832
- try {
1833
- this.restoredString = localStorage.getItem("savepuzzle");
1834
- if (!this.restoredString) this.restoredString = "";
1835
- } catch (exception) {
1836
- this.restoredString = "";
1837
- }
1838
- if (this.restoredString.length === 0) {
1839
- this.state = 15;
1840
- break;
1841
- }
1842
- this.state = 155;
1843
- }
1844
- break;
1845
-
1846
- case 155:
1847
- try {
1848
- this.restoredState = JSON.parse(this.restoredString);
1849
- } catch (error) {
1850
- this.restoredState = null;
1851
- this.state = 10;
1852
- break;
1853
- }
1854
- if (
1855
- !this.restoredState.signature ||
1856
- this.restoredState.signature !== FILE_SIGNATURE ||
1857
- !this.restoredState.src
1858
- ) {
1859
- this.restoredState = null;
1860
- this.state = 10;
1861
- break;
1862
- }
1863
- this.puzzle.imageLoaded = false;
1864
- this.puzzle.srcImage.src = this.restoredState.src;
1865
- if (this.restoredState.origin)
1866
- this.puzzle.srcImage.dataset.origin = this.restoredState.origin;
1867
- else
1868
- delete this.puzzle.srcImage.dataset.origin;
1869
- this.state = 158;
1870
- // fall through
1871
-
1872
1875
  case 158:
1873
1876
  if (event && event.event === "srcImageLoaded") {
1874
1877
  this.state = 160;
@@ -1923,27 +1926,22 @@ export class JigsawPuzzle {
1923
1926
  * @param {Function} callback - Optional callback to receive saved data as JSON string
1924
1927
  */
1925
1928
  save(callback) {
1929
+ // Get state data and convert to string
1930
+ const savedData = this.puzzle.getStateData();
1931
+ const savedString = JSON.stringify(savedData);
1932
+
1933
+ // If callback provided, call it with the string; otherwise save to localStorage
1926
1934
  if (callback) {
1927
- this.events.push({ event: "save", callback });
1935
+ callback(savedString);
1928
1936
  } else {
1929
- // Default: save to localStorage
1930
- this.events.push({ event: "save", callback: (data) => {
1931
- try {
1932
- localStorage.setItem("savepuzzle", data);
1933
- } catch (exception) {
1934
- console.error("Failed to save to localStorage:", exception);
1935
- }
1936
- }});
1937
+ try {
1938
+ localStorage.setItem("savepuzzle", savedString);
1939
+ } catch (exception) {
1940
+ console.error("Failed to save to localStorage:", exception);
1941
+ }
1937
1942
  }
1938
1943
  }
1939
1944
 
1940
- /**
1941
- * Load a saved game state
1942
- * @param {string} savedData - JSON string of saved data, or null to load from localStorage
1943
- */
1944
- load(savedData) {
1945
- this.events.push({ event: "restore", data: savedData });
1946
- }
1947
1945
 
1948
1946
  /**
1949
1947
  * Set the puzzle image
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jigsawpuzzlegame",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "A class for creating a jigsaw puzzle",
5
5
  "keywords": [
6
6
  "jigsaw",
package/game.css DELETED
@@ -1,23 +0,0 @@
1
- /* Demo-specific styles for game.html */
2
- /* Note: Library styles (.polypiece, .gameCanvas) are automatically injected by jigsaw-puzzle-game.js */
3
-
4
- * {
5
- margin: 0;
6
- padding: 0;
7
- box-sizing: border-box;
8
- }
9
-
10
- body {
11
- width: 100vw;
12
- height: 100vh;
13
- overflow: hidden;
14
- background-color: #f0f0f0;
15
- }
16
-
17
- #puzzle-container {
18
- width: 100%;
19
- height: 100%;
20
- position: relative;
21
- background-color: #e8e8e8;
22
- }
23
-