@vue-puzzle-vcode/shared 2.0.0 → 2.0.2

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 ADDED
@@ -0,0 +1,9 @@
1
+ # @vue-puzzle-vcode/shared
2
+
3
+ vue-puzzle-vcode 的共享纯函数工具库:Canvas 拼图绘制、拼图块路径、数学/随机数等。无任何框架依赖。
4
+
5
+ > 内部包,被 [`@vue-puzzle-vcode/core`](https://www.npmjs.com/package/@vue-puzzle-vcode/core) 与 [`@vue-puzzle-vcode/ui`](https://www.npmjs.com/package/@vue-puzzle-vcode/ui) 依赖,通常无需直接安装。
6
+
7
+ ## 文档
8
+
9
+ 完整文档与在线 Demo 见主仓库:[github.com/daguanren21/vue-puzzle-vcode](https://github.com/daguanren21/vue-puzzle-vcode#readme)
package/dist/index.cjs CHANGED
@@ -5,9 +5,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
5
5
  * Pure, framework-agnostic utilities: math + canvas drawing for the
6
6
  * sliding-puzzle captcha. No Vue imports here — safe to bundle anywhere.
7
7
  */
8
- /** Random integer in [min, max]. */
8
+ /** Random integer in [min, max] (inclusive). */
9
9
  function randomInt(min, max) {
10
- return Math.ceil(Math.random() * (max - min) + min);
10
+ if (max < min) return min;
11
+ return min + Math.floor(Math.random() * (max - min + 1));
11
12
  }
12
13
  /** Clamp `v` into [min, max]. */
13
14
  function clamp(v, min, max) {
@@ -28,6 +29,41 @@ function computeSliderBaseSize(sliderSize, canvasWidth) {
28
29
  return Math.max(Math.min(Math.round(sliderSize), Math.round(canvasWidth * .5)), 10);
29
30
  }
30
31
  /**
32
+ * Usable track length (canvasWidth - sliderBaseSize), floored at 1 so the
33
+ * drag-compensation term never divides by zero.
34
+ */
35
+ function computeTrackTravel(canvasWidth, sliderBaseSize) {
36
+ return Math.max(1, canvasWidth - sliderBaseSize);
37
+ }
38
+ /**
39
+ * Horizontal offset of the floating puzzle piece, kept in sync with the
40
+ * slider. Compensates for puzzle-vs-slider width mismatch across the track.
41
+ */
42
+ function computePuzzleTranslateX(styleWidth, sliderBaseSize, puzzleBaseSize, trackTravel) {
43
+ const dragged = styleWidth - sliderBaseSize;
44
+ return dragged - (puzzleBaseSize - sliderBaseSize) * (dragged / trackTravel);
45
+ }
46
+ /**
47
+ * Absolute pixel deviation used for pass/fail. The trailing `-3` undoes the
48
+ * shadow crop offset applied when the piece was copied off the main canvas.
49
+ */
50
+ function computeDragDeviation(pinX, styleWidth, sliderBaseSize, puzzleBaseSize, trackTravel) {
51
+ const dragged = styleWidth - sliderBaseSize;
52
+ return Math.abs(pinX - dragged + (puzzleBaseSize - sliderBaseSize) * (dragged / trackTravel) - 3);
53
+ }
54
+ /**
55
+ * Source rectangle used to copy the puzzle piece (and its drop shadow) off
56
+ * the main canvas. `sw`/`sh` are WIDTH/HEIGHT for `getImageData`.
57
+ */
58
+ function computePuzzleCropRect(pinX, pinY, puzzleBaseSize) {
59
+ return {
60
+ sx: pinX - 3,
61
+ sy: pinY - 20,
62
+ sw: puzzleBaseSize + 8,
63
+ sh: puzzleBaseSize + 25
64
+ };
65
+ }
66
+ /**
31
67
  * object-fit: cover mapping of an image onto a canvas.
32
68
  * Returns [x, y, width, height] for drawImage.
33
69
  */
@@ -160,7 +196,8 @@ function drawPuzzleFrame(canvases, img, opts) {
160
196
  ctx.shadowBlur = Math.min(Math.ceil(8 * puzzleScale), 12);
161
197
  ctx.fillStyle = "#ffffaa";
162
198
  ctx.fill();
163
- const imgData = ctx.getImageData(pinX - 3, pinY - 20, pinX + puzzleBaseSize + 5, pinY + puzzleBaseSize + 5);
199
+ const { sx, sy, sw, sh } = computePuzzleCropRect(pinX, pinY, puzzleBaseSize);
200
+ const imgData = ctx.getImageData(sx, sy, sw, sh);
164
201
  ctx2.putImageData(imgData, 0, pinY - 20);
165
202
  ctx.restore();
166
203
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
@@ -193,8 +230,12 @@ const RESET_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAA
193
230
  //#endregion
194
231
  exports.RESET_ICON = RESET_ICON;
195
232
  exports.clamp = clamp;
233
+ exports.computeDragDeviation = computeDragDeviation;
196
234
  exports.computePuzzleBaseSize = computePuzzleBaseSize;
235
+ exports.computePuzzleCropRect = computePuzzleCropRect;
236
+ exports.computePuzzleTranslateX = computePuzzleTranslateX;
197
237
  exports.computeSliderBaseSize = computeSliderBaseSize;
238
+ exports.computeTrackTravel = computeTrackTravel;
198
239
  exports.coverSize = coverSize;
199
240
  exports.drawPuzzleFrame = drawPuzzleFrame;
200
241
  exports.generateRandomImage = generateRandomImage;
package/dist/index.d.cts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Pure, framework-agnostic utilities: math + canvas drawing for the
5
5
  * sliding-puzzle captcha. No Vue imports here — safe to bundle anywhere.
6
6
  */
7
- /** Random integer in [min, max]. */
7
+ /** Random integer in [min, max] (inclusive). */
8
8
  declare function randomInt(min: number, max: number): number;
9
9
  /** Clamp `v` into [min, max]. */
10
10
  declare function clamp(v: number, min: number, max: number): number;
@@ -18,6 +18,31 @@ declare function computePuzzleBaseSize(puzzleScale: number): number;
18
18
  * Faithful port of the original `sliderBaseSize` computed.
19
19
  */
20
20
  declare function computeSliderBaseSize(sliderSize: number, canvasWidth: number): number;
21
+ /**
22
+ * Usable track length (canvasWidth - sliderBaseSize), floored at 1 so the
23
+ * drag-compensation term never divides by zero.
24
+ */
25
+ declare function computeTrackTravel(canvasWidth: number, sliderBaseSize: number): number;
26
+ /**
27
+ * Horizontal offset of the floating puzzle piece, kept in sync with the
28
+ * slider. Compensates for puzzle-vs-slider width mismatch across the track.
29
+ */
30
+ declare function computePuzzleTranslateX(styleWidth: number, sliderBaseSize: number, puzzleBaseSize: number, trackTravel: number): number;
31
+ /**
32
+ * Absolute pixel deviation used for pass/fail. The trailing `-3` undoes the
33
+ * shadow crop offset applied when the piece was copied off the main canvas.
34
+ */
35
+ declare function computeDragDeviation(pinX: number, styleWidth: number, sliderBaseSize: number, puzzleBaseSize: number, trackTravel: number): number;
36
+ /**
37
+ * Source rectangle used to copy the puzzle piece (and its drop shadow) off
38
+ * the main canvas. `sw`/`sh` are WIDTH/HEIGHT for `getImageData`.
39
+ */
40
+ declare function computePuzzleCropRect(pinX: number, pinY: number, puzzleBaseSize: number): {
41
+ sx: number;
42
+ sy: number;
43
+ sw: number;
44
+ sh: number;
45
+ };
21
46
  /**
22
47
  * object-fit: cover mapping of an image onto a canvas.
23
48
  * Returns [x, y, width, height] for drawImage.
@@ -64,4 +89,4 @@ declare function drawPuzzleFrame(canvases: PuzzleCanvases, img: HTMLImageElement
64
89
  */
65
90
  declare const RESET_ICON: string;
66
91
  //#endregion
67
- export { DrawPuzzleFrameOptions, PuzzleCanvases, RESET_ICON, clamp, computePuzzleBaseSize, computeSliderBaseSize, coverSize, drawPuzzleFrame, generateRandomImage, loadImage, randomInt, tracePuzzlePath };
92
+ export { DrawPuzzleFrameOptions, PuzzleCanvases, RESET_ICON, clamp, computeDragDeviation, computePuzzleBaseSize, computePuzzleCropRect, computePuzzleTranslateX, computeSliderBaseSize, computeTrackTravel, coverSize, drawPuzzleFrame, generateRandomImage, loadImage, randomInt, tracePuzzlePath };
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Pure, framework-agnostic utilities: math + canvas drawing for the
5
5
  * sliding-puzzle captcha. No Vue imports here — safe to bundle anywhere.
6
6
  */
7
- /** Random integer in [min, max]. */
7
+ /** Random integer in [min, max] (inclusive). */
8
8
  declare function randomInt(min: number, max: number): number;
9
9
  /** Clamp `v` into [min, max]. */
10
10
  declare function clamp(v: number, min: number, max: number): number;
@@ -18,6 +18,31 @@ declare function computePuzzleBaseSize(puzzleScale: number): number;
18
18
  * Faithful port of the original `sliderBaseSize` computed.
19
19
  */
20
20
  declare function computeSliderBaseSize(sliderSize: number, canvasWidth: number): number;
21
+ /**
22
+ * Usable track length (canvasWidth - sliderBaseSize), floored at 1 so the
23
+ * drag-compensation term never divides by zero.
24
+ */
25
+ declare function computeTrackTravel(canvasWidth: number, sliderBaseSize: number): number;
26
+ /**
27
+ * Horizontal offset of the floating puzzle piece, kept in sync with the
28
+ * slider. Compensates for puzzle-vs-slider width mismatch across the track.
29
+ */
30
+ declare function computePuzzleTranslateX(styleWidth: number, sliderBaseSize: number, puzzleBaseSize: number, trackTravel: number): number;
31
+ /**
32
+ * Absolute pixel deviation used for pass/fail. The trailing `-3` undoes the
33
+ * shadow crop offset applied when the piece was copied off the main canvas.
34
+ */
35
+ declare function computeDragDeviation(pinX: number, styleWidth: number, sliderBaseSize: number, puzzleBaseSize: number, trackTravel: number): number;
36
+ /**
37
+ * Source rectangle used to copy the puzzle piece (and its drop shadow) off
38
+ * the main canvas. `sw`/`sh` are WIDTH/HEIGHT for `getImageData`.
39
+ */
40
+ declare function computePuzzleCropRect(pinX: number, pinY: number, puzzleBaseSize: number): {
41
+ sx: number;
42
+ sy: number;
43
+ sw: number;
44
+ sh: number;
45
+ };
21
46
  /**
22
47
  * object-fit: cover mapping of an image onto a canvas.
23
48
  * Returns [x, y, width, height] for drawImage.
@@ -64,4 +89,4 @@ declare function drawPuzzleFrame(canvases: PuzzleCanvases, img: HTMLImageElement
64
89
  */
65
90
  declare const RESET_ICON: string;
66
91
  //#endregion
67
- export { DrawPuzzleFrameOptions, PuzzleCanvases, RESET_ICON, clamp, computePuzzleBaseSize, computeSliderBaseSize, coverSize, drawPuzzleFrame, generateRandomImage, loadImage, randomInt, tracePuzzlePath };
92
+ export { DrawPuzzleFrameOptions, PuzzleCanvases, RESET_ICON, clamp, computeDragDeviation, computePuzzleBaseSize, computePuzzleCropRect, computePuzzleTranslateX, computeSliderBaseSize, computeTrackTravel, coverSize, drawPuzzleFrame, generateRandomImage, loadImage, randomInt, tracePuzzlePath };
package/dist/index.js CHANGED
@@ -4,9 +4,10 @@
4
4
  * Pure, framework-agnostic utilities: math + canvas drawing for the
5
5
  * sliding-puzzle captcha. No Vue imports here — safe to bundle anywhere.
6
6
  */
7
- /** Random integer in [min, max]. */
7
+ /** Random integer in [min, max] (inclusive). */
8
8
  function randomInt(min, max) {
9
- return Math.ceil(Math.random() * (max - min) + min);
9
+ if (max < min) return min;
10
+ return min + Math.floor(Math.random() * (max - min + 1));
10
11
  }
11
12
  /** Clamp `v` into [min, max]. */
12
13
  function clamp(v, min, max) {
@@ -27,6 +28,41 @@ function computeSliderBaseSize(sliderSize, canvasWidth) {
27
28
  return Math.max(Math.min(Math.round(sliderSize), Math.round(canvasWidth * .5)), 10);
28
29
  }
29
30
  /**
31
+ * Usable track length (canvasWidth - sliderBaseSize), floored at 1 so the
32
+ * drag-compensation term never divides by zero.
33
+ */
34
+ function computeTrackTravel(canvasWidth, sliderBaseSize) {
35
+ return Math.max(1, canvasWidth - sliderBaseSize);
36
+ }
37
+ /**
38
+ * Horizontal offset of the floating puzzle piece, kept in sync with the
39
+ * slider. Compensates for puzzle-vs-slider width mismatch across the track.
40
+ */
41
+ function computePuzzleTranslateX(styleWidth, sliderBaseSize, puzzleBaseSize, trackTravel) {
42
+ const dragged = styleWidth - sliderBaseSize;
43
+ return dragged - (puzzleBaseSize - sliderBaseSize) * (dragged / trackTravel);
44
+ }
45
+ /**
46
+ * Absolute pixel deviation used for pass/fail. The trailing `-3` undoes the
47
+ * shadow crop offset applied when the piece was copied off the main canvas.
48
+ */
49
+ function computeDragDeviation(pinX, styleWidth, sliderBaseSize, puzzleBaseSize, trackTravel) {
50
+ const dragged = styleWidth - sliderBaseSize;
51
+ return Math.abs(pinX - dragged + (puzzleBaseSize - sliderBaseSize) * (dragged / trackTravel) - 3);
52
+ }
53
+ /**
54
+ * Source rectangle used to copy the puzzle piece (and its drop shadow) off
55
+ * the main canvas. `sw`/`sh` are WIDTH/HEIGHT for `getImageData`.
56
+ */
57
+ function computePuzzleCropRect(pinX, pinY, puzzleBaseSize) {
58
+ return {
59
+ sx: pinX - 3,
60
+ sy: pinY - 20,
61
+ sw: puzzleBaseSize + 8,
62
+ sh: puzzleBaseSize + 25
63
+ };
64
+ }
65
+ /**
30
66
  * object-fit: cover mapping of an image onto a canvas.
31
67
  * Returns [x, y, width, height] for drawImage.
32
68
  */
@@ -159,7 +195,8 @@ function drawPuzzleFrame(canvases, img, opts) {
159
195
  ctx.shadowBlur = Math.min(Math.ceil(8 * puzzleScale), 12);
160
196
  ctx.fillStyle = "#ffffaa";
161
197
  ctx.fill();
162
- const imgData = ctx.getImageData(pinX - 3, pinY - 20, pinX + puzzleBaseSize + 5, pinY + puzzleBaseSize + 5);
198
+ const { sx, sy, sw, sh } = computePuzzleCropRect(pinX, pinY, puzzleBaseSize);
199
+ const imgData = ctx.getImageData(sx, sy, sw, sh);
163
200
  ctx2.putImageData(imgData, 0, pinY - 20);
164
201
  ctx.restore();
165
202
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);
@@ -190,4 +227,4 @@ function drawPuzzleFrame(canvases, img, opts) {
190
227
  */
191
228
  const RESET_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAELklEQVRYR+2YW2wUZRTH//9vtlCo\nF9IoIklT3PqgPGi326hoetuaGEhIr9SgCYkkgt2WGOQVCca+GavWdr0GjD4YhG3RB3hply1LQA1t\nEQIxEXapGI2pEkys9LIzx2ylYWfY6e5sF0oi+7hzzvl+3/9855xvhrjNf7zN+XAHcL4Z+n8o6JWT\neYt++W25S596AIZy6TB+n3yo+Nchlk8vmIIVowdXU9c3Q1gDSilBlQwjgBAYFGDvdF58/4milqvZ\nwDpOcXWsb5Uh8hmBqkwXFMhlCN8aX5LXNbRy/T+Z+iXsHAFWRXs3QGQPyLucLDJrK5DgUXdTsxPf\njAEro8E3Ce50EtxsKxPTwCPH3U2jTmJkBJgWTnAMxDeGMEoa0xQ+LJQnCD4HYFkCyAC3RdwN3U7g\nMkpxRTTYrMD91sCJIgCxV5R6O1Jcfy7VwonqLoj9/CqB2kF341qncGkBvRe+ureAWpRgoalCBecM\nFzcdK24YymZRJz5zprgq1tsJwXYL3CVZGvdGHmwZc7JQtra2gE+f712ep2QUYP714DJhaJrXLqXZ\nQszlZwtYdSHoB9ljVk/ePVrSZFL0ZkAlxzQBVseCT8WhZhRThtFB8plk9Zi/qCi8cv0fNxvKFrDy\n4oF11NXXIFy2EII4iBcG3Y03VLZT8OqRd5aFPduvOEpxRayvXolxAKB2g6NgEhobBlc1HHYKY7Wv\nHf5wtVAPgegIlbbZ9seUZ7AyFnwewi9pGoUyDmhrB931kfnC1ZwOeKlLP8GZJi6QLSFP2yep4toX\nSbT3ZQAfX3O6omt8Nhd9r/aHQAUMOQywYBZo5uZD2ThQ2rbPCjlnH6yI9rUryE5DU75ctJaake46\nBe4DuDjF8dFBNA94/AdtiySVxIlpMlTS8td801o70vMigM9huTda2lhcKHVHPO2HZv/P6LIwX7hk\n/+qzPSvUJGMkrg8AQYTkroRdXMlE+HH/twsG6BsOdJHYZlaO/lBZ6weOiiSXqs3Gqj0TeAxx+T75\nDIpgwjC0onD51pQD4JaluPrkR/cpFT9DcoVp84LOgTL/DjtBbglgou+puHwB8lEznPxJw1XSX77V\ntgizBvQNBw4RMqB7xt4Lc3c8lQKJaQHoO4R8ydz0/7MWoCXk8c85MrMC9J3qaafw/WtQlwXST+F3\nBnAeYB4obgJ1BJIuG+YtiKAjVOZ/Pd1ZdwzoG+4uBtSPpjaRbhXLcwF3hzytb2TilgVgT5BkYybB\nrTYC+Rvg5nRpdTRJrIs8+VPXPQXj2i4ItxC4O2NQQUQnN4U9rRcz9nH64p4ceM2lziX5Y4s3KHCd\nUHwE77ecMkMEp6BwhIa2Z6DslZRvfulgHafYLuCas58WLp2aLCFUga70qxOFU6dPFL2W1feYeaU4\n3Y5z/TxnCuYabMEuC043ckdBp4pZ7f8FE5psOI1g6fwAAAAASUVORK5CYII=";
192
229
  //#endregion
193
- export { RESET_ICON, clamp, computePuzzleBaseSize, computeSliderBaseSize, coverSize, drawPuzzleFrame, generateRandomImage, loadImage, randomInt, tracePuzzlePath };
230
+ export { RESET_ICON, clamp, computeDragDeviation, computePuzzleBaseSize, computePuzzleCropRect, computePuzzleTranslateX, computeSliderBaseSize, computeTrackTravel, coverSize, drawPuzzleFrame, generateRandomImage, loadImage, randomInt, tracePuzzlePath };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@vue-puzzle-vcode/shared",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Shared pure utilities for vue-puzzle-vcode (canvas drawing, math)",
5
5
  "license": "ISC",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/javaLuo/vue-puzzle-vcode.git",
8
+ "url": "git+https://github.com/daguanren21/vue-puzzle-vcode.git",
9
9
  "directory": "packages/shared"
10
10
  },
11
11
  "type": "module",
@@ -30,7 +30,8 @@
30
30
  "sideEffects": false,
31
31
  "devDependencies": {
32
32
  "tsdown": "0.22.14",
33
- "typescript": "7.0.2"
33
+ "typescript": "7.0.2",
34
+ "vitest": "4.1.10"
34
35
  },
35
36
  "publishConfig": {
36
37
  "access": "public"
@@ -38,6 +39,7 @@
38
39
  "scripts": {
39
40
  "build": "tsdown",
40
41
  "dev": "tsdown --watch",
41
- "typecheck": "tsc --noEmit"
42
+ "typecheck": "tsc --noEmit",
43
+ "test": "vitest run --root ../.. packages/shared/test"
42
44
  }
43
45
  }