User:Monster Domosed/common.js: Difference between revisionsGive feedback
No edit summary |
Undo Tag: Undo |
||
| Line 2: | Line 2: | ||
* Rotatable Model Viewer — with 2D / 3D toggle | * Rotatable Model Viewer — with 2D / 3D toggle | ||
* All <img> elements created in JS to bypass MediaWiki sanitizer. | * All <img> elements created in JS to bypass MediaWiki sanitizer. | ||
*/ | */ | ||
(function () { | (function () { | ||
| Line 33: | Line 30: | ||
startFrame = +el.dataset.startFrame || 0, | startFrame = +el.dataset.startFrame || 0, | ||
sensitivity = +el.dataset.sensitivity || 5; | sensitivity = +el.dataset.sensitivity || 5; | ||
var hint = el.querySelector('.rotatable-model-hint'), | var hint = el.querySelector('.rotatable-model-hint'), | ||
| Line 52: | Line 44: | ||
is2D = false, | is2D = false, | ||
dragOK = true, | dragOK = true, | ||
ready = false; | ready = false; // true once the strip image has loaded | ||
/* ============================================================ | /* ============================================================ | ||
3D SPRITE STRIP | 3D SPRITE STRIP | ||
============================================================ */ | ============================================================ */ | ||
var img = makeImg(imageUrl, '', 'rm-strip'); | var img = makeImg(imageUrl, '', 'rm-strip'); | ||
img.style.height = | // Set explicit display dimensions | ||
img.style.width = ( | // width = single frame width × number of frames | ||
// height = frame height | |||
img.style.height = fh + 'px'; | |||
img.style.width = (fw * count) + 'px'; | |||
img.addEventListener('load', function () { | img.addEventListener('load', function () { | ||
| Line 73: | Line 68: | ||
el.insertBefore(img, el.firstChild); | el.insertBefore(img, el.firstChild); | ||
// Handle cached images | |||
if (img.complete && img.naturalWidth > 0) { | if (img.complete && img.naturalWidth > 0) { | ||
ready = true; | ready = true; | ||
| Line 80: | Line 76: | ||
/* ============================================================ | /* ============================================================ | ||
2D STATIC IMAGE | 2D STATIC IMAGE | ||
============================================================ */ | ============================================================ */ | ||
var staticImg = null; | var staticImg = null; | ||
if (image2dUrl) { | if (image2dUrl) { | ||
staticImg = makeImg(image2dUrl, '', 'rm-static'); | staticImg = makeImg(image2dUrl, '', 'rm-static'); | ||
el.insertBefore(staticImg, el.firstChild); | el.insertBefore(staticImg, el.firstChild); | ||
} | } | ||
| Line 136: | Line 127: | ||
/* ============================================================ | /* ============================================================ | ||
FRAME DISPLAY | FRAME DISPLAY | ||
============================================================ */ | ============================================================ */ | ||
function show(idx) { | function show(idx) { | ||
cur = ((idx % count) + count) % count; | cur = ((idx % count) + count) % count; | ||
img.style.left = | // Move the strip so that frame `cur` is visible in the viewport | ||
img.style.top = | var offset = cur * fw; | ||
img.style.left = '-' + offset + 'px'; | |||
img.style.top = '0px'; | |||
} | } | ||
| Line 194: | Line 187: | ||
/* ============================================================ | /* ============================================================ | ||
DRAG (mouse + touch) | DRAG (mouse + touch) | ||
One frame per `sensitivity` pixels of movement. | |||
Clamped to ±1 frame per event to prevent skipping. | |||
============================================================ */ | ============================================================ */ | ||
function startDrag(x0) { | function startDrag(x0) { | ||
| Line 205: | Line 200: | ||
acc += dx; | acc += dx; | ||
// Convert accumulated pixels to frame steps | |||
while (acc >= sensitivity) { | while (acc >= sensitivity) { | ||
acc -= sensitivity; | acc -= sensitivity; | ||
| Line 247: | Line 243: | ||
}, { passive: false }); | }, { passive: false }); | ||
/* ---- wheel: always ±1 frame per tick ---- */ | |||
el.addEventListener('wheel', function (e) { | el.addEventListener('wheel', function (e) { | ||
if (!dragOK || !ready) return; | if (!dragOK || !ready) return; | ||
| Line 253: | Line 250: | ||
}, { passive: false }); | }, { passive: false }); | ||
/* ---- keyboard ---- */ | |||
el.setAttribute('tabindex', '0'); | el.setAttribute('tabindex', '0'); | ||
el.addEventListener('keydown', function (e) { | el.addEventListener('keydown', function (e) { | ||
| Line 261: | Line 259: | ||
}); | }); | ||
/* ---- nav buttons ---- */ | |||
if (wrap) { | if (wrap) { | ||
var bL = wrap.querySelector('.rm-btn-left'), | var bL = wrap.querySelector('.rm-btn-left'), | ||
| Line 270: | Line 269: | ||
} | } | ||
/* ---- initial frame ---- */ | |||
show(startFrame); | show(startFrame); | ||
} | } | ||
/* ---- scan & init ---- */ | |||
function initAll(root) { | function initAll(root) { | ||
var els = (root || document).querySelectorAll('.rotatable-model'); | var els = (root || document).querySelectorAll('.rotatable-model'); | ||