anime-cursor 0.3.0 → 0.3.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.
- package/README.md +30 -18
- package/dist/anime-cursor.esm.js +6 -12
- package/dist/anime-cursor.umd.js +14 -20
- package/dist/anime-cursor.umd.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,20 +55,18 @@ Here is an example of how to use AnimeCursor:
|
|
|
55
55
|
- Ensure the initialization code is placed **within** the `<body>` tag of your HTML document.
|
|
56
56
|
- For optimal performance, it is recommended to initialize AnimeCursor **before** the DOM has fully loaded, as certain features require execution prior to the completion of DOM loading.
|
|
57
57
|
|
|
58
|
-
```
|
|
59
|
-
<script>
|
|
58
|
+
```javascript
|
|
60
59
|
new AnimeCursor({
|
|
61
60
|
cursors: {
|
|
62
|
-
// each type of cursor needs
|
|
61
|
+
// each type of cursor needs size and image
|
|
63
62
|
idle: {
|
|
64
63
|
size: [64,64],
|
|
65
64
|
image: 'https://example.com/cursor_default.png', // static cursor only needs image
|
|
66
65
|
default: true // set this cursor as default cursor
|
|
67
|
-
// only default cursor doesn't needs tags
|
|
68
66
|
},
|
|
69
67
|
// sprite animated cursor needs frames and duration
|
|
70
68
|
pointer: {
|
|
71
|
-
tags: ['a', 'button'],
|
|
69
|
+
tags: ['a', 'button'], // if you need certain types of elements to trigger this cursor, set the tags
|
|
72
70
|
size: [64,64],
|
|
73
71
|
image: 'https://example.com/cursor_pointer.png',
|
|
74
72
|
frames: 3,
|
|
@@ -81,11 +79,19 @@ new AnimeCursor({
|
|
|
81
79
|
tags: ['p', 'h1', 'h2', 'span'],
|
|
82
80
|
size: [32, 64],
|
|
83
81
|
image: 'https://example.com/cursor_text.gif'
|
|
82
|
+
},
|
|
83
|
+
haha: {
|
|
84
|
+
size: [32,32],
|
|
85
|
+
image: 'https://example.com/cursor_haha.png',
|
|
86
|
+
frames: 12,
|
|
87
|
+
duration: 1,
|
|
88
|
+
pixel: true, // if the image is origin size pixel art, set pixel to true
|
|
89
|
+
scale: [2,2] // scale the cursor
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
92
|
});
|
|
87
|
-
</script>
|
|
88
93
|
```
|
|
94
|
+
For non-default cursors, if you need a specific element to trigger the cursor, manually add the `data-cursor` attribute to the element. For example: if you want the `<div class="custom-div"></div>` to trigger the `haha` cursor, you need to add `data-cursor="haha"` to it, and the modified code should be as follows: `<div class="custom-div" data-cursor="haha"></div>`. This way, when the cursor hovers over the `custom-div` element, the cursor will switch to the `haha` style.
|
|
89
95
|
|
|
90
96
|
## ⚙️ Configuration Options
|
|
91
97
|
|
|
@@ -218,37 +224,43 @@ new AnimeCursor({...});
|
|
|
218
224
|
- 请务必将初始化代码置于HTML文档的 **`<body>`** 标签内部。
|
|
219
225
|
- 为获得最佳性能,建议在DOM完全加载**之前**初始化AnimeCursor,因其部分功能需在DOM加载完成前执行。
|
|
220
226
|
|
|
221
|
-
```
|
|
222
|
-
<script>
|
|
227
|
+
```javascript
|
|
223
228
|
new AnimeCursor({
|
|
224
229
|
cursors: {
|
|
225
|
-
// 每种光标都需要
|
|
230
|
+
// 每种光标都需要 size 和 image
|
|
226
231
|
default: {
|
|
227
232
|
size: [64,64],
|
|
228
|
-
image: '
|
|
233
|
+
image: 'https://example.com/cursor_default.png', // 静态光标只需要图片链接
|
|
229
234
|
default: true // 将此光标设为默认光标
|
|
230
|
-
// 默认光标不需要 tags
|
|
231
235
|
},
|
|
232
236
|
// 精灵图动画光标还需要 frames 和 duration
|
|
233
237
|
pointer: {
|
|
234
|
-
tags: ['a', 'button'],
|
|
238
|
+
tags: ['a', 'button'], // 如果需要某类元素触发该光标,设置 tags
|
|
235
239
|
size: [64,64],
|
|
236
|
-
image: '
|
|
240
|
+
image: 'https://example.com/cursor_pointer.png',
|
|
237
241
|
frames: 3,
|
|
238
242
|
duration: 0.3,
|
|
239
|
-
pingpong: true, //
|
|
240
|
-
offset: [10,
|
|
243
|
+
pingpong: true, // 启用乒乓循环
|
|
244
|
+
offset: [10,4] // 如果指针位置不在左上角,设置 offset
|
|
241
245
|
},
|
|
242
246
|
// gif 光标不需要 frames 或 duration
|
|
243
247
|
text: {
|
|
244
248
|
tags: ['p', 'h1', 'h2', 'span'],
|
|
245
|
-
size: [32,
|
|
246
|
-
image: '
|
|
249
|
+
size: [32,64],
|
|
250
|
+
image: 'https://example.com/cursor_text.gif'
|
|
251
|
+
},
|
|
252
|
+
haha: {
|
|
253
|
+
size: [32,32],
|
|
254
|
+
image: 'https://example.com/cursor_haha.png',
|
|
255
|
+
frames: 12,
|
|
256
|
+
duration: 1,
|
|
257
|
+
pixel: true, // 如果是原尺寸像素图,启用像素化渲染
|
|
258
|
+
scale: [2,2] // 缩放光标
|
|
247
259
|
}
|
|
248
260
|
}
|
|
249
261
|
});
|
|
250
|
-
</script>
|
|
251
262
|
```
|
|
263
|
+
对于非默认光标,如果需要某元素触发该光标,请手动为该元素添加 `data-cursor`。例如:如果你想让 `<div class="custom-div"></div>` 触发 `haha` 光标,那么就要为其添加 `data-cursor="haha"`,修改完后应该是这样:`<div class="custom-div" data-cursor="haha"></div>`。这样当光标指向 `custom-div` 元素时,光标就会切换到 `haha`。
|
|
252
264
|
|
|
253
265
|
## ⚙️ 配置项说明
|
|
254
266
|
|
package/dist/anime-cursor.esm.js
CHANGED
|
@@ -198,14 +198,8 @@ class AnimeCursor {
|
|
|
198
198
|
throw new Error('AnimeCursor init failed');
|
|
199
199
|
}
|
|
200
200
|
});
|
|
201
|
-
|
|
202
|
-
if (!cfg.
|
|
203
|
-
if (!Array.isArray(cfg.tags) || cfg.tags.length === 0) {
|
|
204
|
-
console.error(`[AnimeCursor] non-default cursor "${name}" must define at least one tag`);
|
|
205
|
-
throw new Error('AnimeCursor init failed');
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (cfg.default && cfg.tags !== undefined && !Array.isArray(cfg.tags)) {
|
|
201
|
+
|
|
202
|
+
if (cfg.tags !== undefined && !Array.isArray(cfg.tags)) {
|
|
209
203
|
console.error(`[AnimeCursor] default cursor "${name}" 's tags must be an array if provided`);
|
|
210
204
|
throw new Error('AnimeCursor init failed');
|
|
211
205
|
}
|
|
@@ -425,7 +419,7 @@ class AnimeCursor {
|
|
|
425
419
|
if (this.disabled) return;
|
|
426
420
|
|
|
427
421
|
for (const [type, cfg] of Object.entries(this.options.cursors)) {
|
|
428
|
-
if (!cfg.tags || cfg.tags.length === 0) continue;
|
|
422
|
+
if (!cfg.tags || !Array.isArray(cfg.tags) || cfg.tags.length === 0) continue;
|
|
429
423
|
|
|
430
424
|
cfg.tags.forEach(tag => {
|
|
431
425
|
const tagName = tag.toUpperCase();
|
|
@@ -504,6 +498,6 @@ class AnimeCursor {
|
|
|
504
498
|
|
|
505
499
|
return 2147483646; // 浏览器安全最大值 2147483647 减一为留给debug覆盖
|
|
506
500
|
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
export { AnimeCursor as default };
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export { AnimeCursor as default };
|
package/dist/anime-cursor.umd.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
3
|
-
typeof define === 'function' && define.amd ? define(factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.AnimeCursor = factory());
|
|
5
|
-
})(this, (function () { 'use strict';
|
|
6
|
-
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.AnimeCursor = factory());
|
|
5
|
+
})(this, (function () { 'use strict';
|
|
6
|
+
|
|
7
7
|
// AnimeCursor by github@ShuninYu
|
|
8
8
|
// v0.3.0
|
|
9
9
|
|
|
@@ -204,14 +204,8 @@
|
|
|
204
204
|
throw new Error('AnimeCursor init failed');
|
|
205
205
|
}
|
|
206
206
|
});
|
|
207
|
-
|
|
208
|
-
if (!cfg.
|
|
209
|
-
if (!Array.isArray(cfg.tags) || cfg.tags.length === 0) {
|
|
210
|
-
console.error(`[AnimeCursor] non-default cursor "${name}" must define at least one tag`);
|
|
211
|
-
throw new Error('AnimeCursor init failed');
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
if (cfg.default && cfg.tags !== undefined && !Array.isArray(cfg.tags)) {
|
|
207
|
+
|
|
208
|
+
if (cfg.tags !== undefined && !Array.isArray(cfg.tags)) {
|
|
215
209
|
console.error(`[AnimeCursor] default cursor "${name}" 's tags must be an array if provided`);
|
|
216
210
|
throw new Error('AnimeCursor init failed');
|
|
217
211
|
}
|
|
@@ -431,7 +425,7 @@
|
|
|
431
425
|
if (this.disabled) return;
|
|
432
426
|
|
|
433
427
|
for (const [type, cfg] of Object.entries(this.options.cursors)) {
|
|
434
|
-
if (!cfg.tags || cfg.tags.length === 0) continue;
|
|
428
|
+
if (!cfg.tags || !Array.isArray(cfg.tags) || cfg.tags.length === 0) continue;
|
|
435
429
|
|
|
436
430
|
cfg.tags.forEach(tag => {
|
|
437
431
|
const tagName = tag.toUpperCase();
|
|
@@ -510,8 +504,8 @@
|
|
|
510
504
|
|
|
511
505
|
return 2147483646; // 浏览器安全最大值 2147483647 减一为留给debug覆盖
|
|
512
506
|
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
return AnimeCursor;
|
|
516
|
-
|
|
517
|
-
}));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return AnimeCursor;
|
|
510
|
+
|
|
511
|
+
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?module.exports=s():"function"==typeof define&&define.amd?define(s):(e="undefined"!=typeof globalThis?globalThis:e||self).AnimeCursor=s()}(this,function(){"use strict";let e=null;return class{static get instance(){return e}static destroy(){return!!e&&(e.destroy(),!0)}static refresh(){return!!e&&(e.refresh(),!0)}static disable(){return!!e&&(e.disable(),!0)}static enable(){return!!e&&(e.enable(),!0)}constructor(s={}){return e?(console.warn("[AnimeCursor] AnimeCursor already exists."),e):(this.options={displayOnLoad:!1,enableTouch:!1,debug:!1,...s},this.disabled=!1,this.options.enableTouch||this.isMouseLikeDevice()?(this.cursorEl=null,this.lastCursorType=null,this.debugEl=null,this.styleEl=null,this._onMouseMove=null,this._validateOptions(),this._injectPreload(),this._checkDomLoad(),void(e=this)):(this.disabled=!0,void(this.options.debug&&console.warn("[AnimeCursor] Touch device detected, cursor disabled."))))}isMouseLikeDevice(){if(!this.disabled)return window.matchMedia("(pointer: fine)").matches}refresh(){this.disabled||(this.options.debug&&console.info("[AnimeCursor] starting refresh..."),this._bindElements(!0))}destroy(){if(!this.disabled){this._onMouseMove&&(document.removeEventListener("mousemove",this._onMouseMove),this._onMouseMove=null),this.cursorEl&&(this.cursorEl.remove(),this.cursorEl=null),this.debugEl&&(this.debugEl.remove(),this.debugEl=null),this.styleEl&&(this.styleEl.remove(),this.styleEl=null);for(const e of Object.values(this.options.cursors))e.tags&&Array.isArray(e.tags)&&e.tags.forEach(e=>{document.querySelectorAll(e).forEach(e=>{e.dataset.cursorBound&&(delete e.dataset.cursor,delete e.dataset.cursorBound)})});this.lastCursorType=null,e===this&&(e=null)}}disable(){this.disabled||(this.disabled=!0,this.cursorEl&&(this.cursorEl.style.display="none",this.styleEl.innerHTML=this.styleEl.innerHTML.replace("* {cursor: none !important;}",""),console.log("[AnimeCursor] AnimeCursor disabled!")))}enable(){this.disabled&&(this.disabled=!1,this.cursorEl&&(this.cursorEl.style.display="",this.styleEl.innerHTML+="* {cursor: none; !important;}",console.log("[AnimeCursor] AnimeCursor enabled!")))}_validateOptions(){if(!this.disabled){if(!this.options||!this.options.cursors)throw console.error("[AnimeCursor] missing cursors set up"),new Error("AnimeCursor init failed");this.defaultCursorType=null;for(const[e,s]of Object.entries(this.options.cursors))if(!0===s.default){if(this.defaultCursorType)throw new Error("[AnimeCursor] There can only be one default cursor");this.defaultCursorType=e}for(const[e,s]of Object.entries(this.options.cursors)){if(["size","image"].forEach(t=>{if(void 0===s[t])throw console.error(`[AnimeCursor] cursor "${e}" missing required setting: ${t}`),new Error("AnimeCursor init failed")})
|
|
1
|
+
!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?module.exports=s():"function"==typeof define&&define.amd?define(s):(e="undefined"!=typeof globalThis?globalThis:e||self).AnimeCursor=s()}(this,function(){"use strict";let e=null;return class{static get instance(){return e}static destroy(){return!!e&&(e.destroy(),!0)}static refresh(){return!!e&&(e.refresh(),!0)}static disable(){return!!e&&(e.disable(),!0)}static enable(){return!!e&&(e.enable(),!0)}constructor(s={}){return e?(console.warn("[AnimeCursor] AnimeCursor already exists."),e):(this.options={displayOnLoad:!1,enableTouch:!1,debug:!1,...s},this.disabled=!1,this.options.enableTouch||this.isMouseLikeDevice()?(this.cursorEl=null,this.lastCursorType=null,this.debugEl=null,this.styleEl=null,this._onMouseMove=null,this._validateOptions(),this._injectPreload(),this._checkDomLoad(),void(e=this)):(this.disabled=!0,void(this.options.debug&&console.warn("[AnimeCursor] Touch device detected, cursor disabled."))))}isMouseLikeDevice(){if(!this.disabled)return window.matchMedia("(pointer: fine)").matches}refresh(){this.disabled||(this.options.debug&&console.info("[AnimeCursor] starting refresh..."),this._bindElements(!0))}destroy(){if(!this.disabled){this._onMouseMove&&(document.removeEventListener("mousemove",this._onMouseMove),this._onMouseMove=null),this.cursorEl&&(this.cursorEl.remove(),this.cursorEl=null),this.debugEl&&(this.debugEl.remove(),this.debugEl=null),this.styleEl&&(this.styleEl.remove(),this.styleEl=null);for(const e of Object.values(this.options.cursors))e.tags&&Array.isArray(e.tags)&&e.tags.forEach(e=>{document.querySelectorAll(e).forEach(e=>{e.dataset.cursorBound&&(delete e.dataset.cursor,delete e.dataset.cursorBound)})});this.lastCursorType=null,e===this&&(e=null)}}disable(){this.disabled||(this.disabled=!0,this.cursorEl&&(this.cursorEl.style.display="none",this.styleEl.innerHTML=this.styleEl.innerHTML.replace("* {cursor: none !important;}",""),console.log("[AnimeCursor] AnimeCursor disabled!")))}enable(){this.disabled&&(this.disabled=!1,this.cursorEl&&(this.cursorEl.style.display="",this.styleEl.innerHTML+="* {cursor: none; !important;}",console.log("[AnimeCursor] AnimeCursor enabled!")))}_validateOptions(){if(!this.disabled){if(!this.options||!this.options.cursors)throw console.error("[AnimeCursor] missing cursors set up"),new Error("AnimeCursor init failed");this.defaultCursorType=null;for(const[e,s]of Object.entries(this.options.cursors))if(!0===s.default){if(this.defaultCursorType)throw new Error("[AnimeCursor] There can only be one default cursor");this.defaultCursorType=e}for(const[e,s]of Object.entries(this.options.cursors)){if(["size","image"].forEach(t=>{if(void 0===s[t])throw console.error(`[AnimeCursor] cursor "${e}" missing required setting: ${t}`),new Error("AnimeCursor init failed")}),void 0!==s.tags&&!Array.isArray(s.tags))throw console.error(`[AnimeCursor] default cursor "${e}" 's tags must be an array if provided`),new Error("AnimeCursor init failed");if(void 0!==s.duration&&"number"!=typeof s.duration)throw console.error(`[AnimeCursor] cursor "${e}" 's duration must be a number(seconds)`),new Error("AnimeCursor init failed")}}}_checkDomLoad(){const e=()=>{this._injectHTML(),this._injectCSS(),this._bindElements(),this._bindMouse()};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e()}_injectPreload(){if(this.disabled)return;const e=new Set;for(const s of Object.values(this.options.cursors))s.image&&e.add(s.image);e.forEach(e=>{const s=document.createElement("link");s.rel="preload",s.as="image",s.href=e,e.startsWith("http")&&!e.startsWith(window.location.origin)&&(s.crossOrigin="anonymous"),document.head.appendChild(s),this.options.debug&&console.info(`[AnimeCursor] Preloading image: ${e}`)}),this.options.debug&&e.size>0&&console.info(`[AnimeCursor] Preloaded ${e.size} cursor image(s)`)}_injectHTML(){if(this.disabled)return;const e=document.createElement("div");if(e.id="anime-cursor",this.options.debug){e.className="cursor-default cursor-debugmode";const s=document.createElement("div");s.className="anime-cursor-debug",document.body.appendChild(s),this.debugEl=s}else e.className="cursor-default";this.options.displayOnLoad?e.style.display="block":(e.style.display="none",e.dataset.animecursorHide="true"),document.body.appendChild(e),this.cursorEl=e}_injectCSS(){if(this.disabled)return;const e=document.createElement("style");e.id="animecursor-styles";let s="";s+=`\n * {cursor: none !important;}\n #anime-cursor {\n position: fixed;\n top: 0;\n left: 0;\n pointer-events: none;\n background-repeat: no-repeat;\n transform-origin: 0 0;\n transform-style: preserve-3d;\n z-index: ${this._getMaxZIndex()};\n }\n .cursor-debugmode {\n border: 1px solid green;\n }\n .anime-cursor-debug {\n position: fixed;\n top: 0;\n left: 0;\n width: fit-content;\n height: fit-content;\n padding: 5px;\n font-size: 16px;\n text-wrap: nowrap;\n color: red;\n pointer-events: none;\n overflow: visible;\n z-index: 2147483647;\n }\n .anime-cursor-debug::before {\n position: absolute;\n content: "";\n top: 0;\n left: 0;\n width: 100vw;\n height: 1px;\n background-color: red;\n }\n .anime-cursor-debug::after {\n position: absolute;\n content: "";\n top: 0;\n left: 0;\n width: 1px;\n height: 100vh;\n background-color: red;\n }\n `;for(const[e,o]of Object.entries(this.options.cursors)){const n=`.cursor-${e}`,r=o.size,i=o.frames,l=o.image,d=o.offset,a=o.zIndex,u=o.scale,c=l.toLowerCase().endsWith(".gif");var t;t=o.pixel?"pixelated":"auto",s+=`\n ${n} {\n width: ${r[0]}px;\n height: ${r[1]}px;\n background-image: url("${l}");\n image-rendering: ${t};\n ${u||d?`transform: ${[u&&`scale(${u[0]}, ${u[1]})`,d&&`translate(-${d[0]}px, -${d[1]}px)`].filter(Boolean).join(" ")};`:""}\n \n ${void 0!==a?`z-index:${a};`:""}\n }`;const h=o.duration;if(!c&&i>1&&"number"==typeof h){const t=`animecursor_${e}`;s+=`\n ${n} {\n animation: ${t} steps(${i}) ${h}s infinite ${o.pingpong?"alternate":""};\n }\n\n @keyframes ${t} {\n from { background-position: 0 0; }\n to { background-position: -${r[0]*i}px 0; }\n }\n `}}e.textContent=s,document.head.appendChild(e),this.styleEl=e}_bindElements(e){if(!this.disabled){for(const[e,s]of Object.entries(this.options.cursors))s.tags&&Array.isArray(s.tags)&&0!==s.tags.length&&s.tags.forEach(s=>{const t=s.toUpperCase();document.querySelectorAll(t).forEach(s=>{s.dataset.cursor||(s.dataset.cursor=e,s.dataset.cursorBound="true")})});e&&console.info("[AnimeCursor] refresh done")}}_bindMouse(){this.disabled||(this._onMouseMove=e=>{if(this.disabled)return;const s=e.clientX,t=e.clientY;this.cursorEl.style.left=s+"px",this.cursorEl.style.top=t+"px",this.cursorEl.dataset.animecursorHide&&(this.cursorEl.style.display="block"),this.debugEl&&(this.debugEl.style.left=s+"px",this.debugEl.style.top=t+"px");let o=null;const n=document.elementFromPoint(s,t);n&&n.dataset&&n.dataset.cursor?o=n.dataset.cursor:this.defaultCursorType&&(o=this.defaultCursorType),o&&(this.debugEl&&(this.debugEl.textContent=`(${s}px , ${t}px) ${o}`),o!==this.lastCursorType&&(this.debugEl?this.cursorEl.className=`cursor-${o} cursor-debugmode`:this.cursorEl.className=`cursor-${o}`,this.lastCursorType=o))},document.addEventListener("mousemove",this._onMouseMove),console.log("[AnimeCursor] AnimeCursor setted up."))}_getMaxZIndex(){if(!this.disabled)return 2147483646}}});
|