@linear_non/stellar-libs 1.0.8 → 1.0.10
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 +1 -1
- package/package.json +1 -1
- package/src/SpritePlayer/index.js +100 -26
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A collection of lightweight, reusable frontend UI behavior modules — built to work seamlessly with [`stellar-kit`](https://www.npmjs.com/package/@linear_non/stellar-kit) and the [Stellar](https://github.com/nonlinearstudio/stellar) frontend system. Each library is self-contained, configurable, and designed to be dropped into modular websites. Also is a project that is constantly growing and we are adding new updates all the time.
|
|
4
4
|
|
|
5
|
-
## ✨
|
|
5
|
+
## ✨ Available Libs
|
|
6
6
|
|
|
7
7
|
- Designed for plug-and-play
|
|
8
8
|
- **Sticky**: Basic sticky logic for DOM elements
|
package/package.json
CHANGED
|
@@ -14,14 +14,18 @@ export default class SpritePlayer {
|
|
|
14
14
|
total = 0,
|
|
15
15
|
progress = 0,
|
|
16
16
|
fileExtension = "png",
|
|
17
|
-
cache = null,
|
|
18
|
-
persistent = false,
|
|
17
|
+
cache = null,
|
|
18
|
+
persistent = false,
|
|
19
|
+
alpha_path = null, // { mobile, desktop }
|
|
20
|
+
fileAlpha = null,
|
|
21
|
+
useAlpha = false,
|
|
19
22
|
}) {
|
|
20
23
|
const rect = bounds(container)
|
|
21
|
-
this.progress = progress
|
|
24
|
+
this.progress = gsap.utils.clamp(0, 1, progress)
|
|
22
25
|
this.persistent = persistent
|
|
26
|
+
this.isAlpha = !!useAlpha
|
|
23
27
|
|
|
24
|
-
this.dom = { container, reference: container, images: [] }
|
|
28
|
+
this.dom = { container, reference: container, images: [], alphaImages: [] }
|
|
25
29
|
this.canvas = {
|
|
26
30
|
el: canvas,
|
|
27
31
|
ctx: canvas.getContext("2d"),
|
|
@@ -37,6 +41,8 @@ export default class SpritePlayer {
|
|
|
37
41
|
total,
|
|
38
42
|
file_extension: fileExtension,
|
|
39
43
|
cache,
|
|
44
|
+
alpha_path,
|
|
45
|
+
fileAlpha,
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
this.state = { loaded: false }
|
|
@@ -45,27 +51,44 @@ export default class SpritePlayer {
|
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
async loadImages() {
|
|
48
|
-
const { mobile_path, desktop_path,
|
|
49
|
-
|
|
54
|
+
const { mobile_path, desktop_path, alpha_path, file_name, fileAlpha, total, file_extension, cache } =
|
|
55
|
+
this.settings
|
|
56
|
+
|
|
57
|
+
const originBase = sniffer.isDesktop ? desktop_path : mobile_path || desktop_path
|
|
58
|
+
const originAlpha = alpha_path
|
|
59
|
+
? sniffer.isDesktop
|
|
60
|
+
? alpha_path.desktop || alpha_path.mobile
|
|
61
|
+
: alpha_path.mobile || alpha_path.desktop
|
|
62
|
+
: null
|
|
63
|
+
|
|
64
|
+
const make = (origin, name) =>
|
|
65
|
+
new ImageLoader({
|
|
66
|
+
origin,
|
|
67
|
+
fileName: name,
|
|
68
|
+
extension: file_extension,
|
|
69
|
+
total,
|
|
70
|
+
cache,
|
|
71
|
+
useWorker: true,
|
|
72
|
+
}).load()
|
|
50
73
|
|
|
51
|
-
const loader = new ImageLoader({
|
|
52
|
-
origin,
|
|
53
|
-
fileName: file_name,
|
|
54
|
-
extension: file_extension,
|
|
55
|
-
total,
|
|
56
|
-
cache, // pass cache Map if you have one
|
|
57
|
-
useWorker: true,
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
// (optional) forward progress
|
|
61
74
|
const onProgress = e => emitter.emit("sprite:progress", { instance: this, ...e })
|
|
62
75
|
emitter.on(ImageLoader.events.PROGRESS, onProgress)
|
|
63
76
|
|
|
64
|
-
const images = await
|
|
77
|
+
const [images, alphaImages] = await Promise.all([
|
|
78
|
+
make(originBase, file_name),
|
|
79
|
+
originAlpha && fileAlpha ? make(originAlpha, fileAlpha) : Promise.resolve([]),
|
|
80
|
+
])
|
|
65
81
|
|
|
66
82
|
emitter.off?.(ImageLoader.events.PROGRESS, onProgress)
|
|
67
83
|
|
|
68
84
|
this.dom.images = images
|
|
85
|
+
this.dom.alphaImages = alphaImages
|
|
86
|
+
|
|
87
|
+
if (this.isAlpha && this.dom.alphaImages.length) {
|
|
88
|
+
this.dom.alphaImages = this.dom.alphaImages.map(img => this.toAlphaFromLuma(img))
|
|
89
|
+
}
|
|
90
|
+
if (this.isAlpha && !this.dom.alphaImages.length) this.isAlpha = false
|
|
91
|
+
|
|
69
92
|
this.frameCount = images.length
|
|
70
93
|
this.state.loaded = true
|
|
71
94
|
emitter.emit("sprite:loaded", this)
|
|
@@ -89,9 +112,31 @@ export default class SpritePlayer {
|
|
|
89
112
|
Object.assign(this.canvas, { width: rect.width, height: rect.height, rect, area, offset })
|
|
90
113
|
}
|
|
91
114
|
|
|
115
|
+
// grayscale -> alpha (returns a canvas)
|
|
116
|
+
toAlphaFromLuma(img) {
|
|
117
|
+
const w = img.naturalWidth || img.width,
|
|
118
|
+
h = img.naturalHeight || img.height
|
|
119
|
+
const c = document.createElement("canvas")
|
|
120
|
+
c.width = w
|
|
121
|
+
c.height = h
|
|
122
|
+
const x = c.getContext("2d")
|
|
123
|
+
x.drawImage(img, 0, 0, w, h)
|
|
124
|
+
const d = x.getImageData(0, 0, w, h)
|
|
125
|
+
const a = d.data
|
|
126
|
+
for (let i = 0; i < a.length; i += 4) {
|
|
127
|
+
const lum = a[i] * 0.2126 + a[i + 1] * 0.7152 + a[i + 2] * 0.0722
|
|
128
|
+
a[i] = 0
|
|
129
|
+
a[i + 1] = 0
|
|
130
|
+
a[i + 2] = 0
|
|
131
|
+
a[i + 3] = lum
|
|
132
|
+
}
|
|
133
|
+
x.putImageData(d, 0, 0)
|
|
134
|
+
return c
|
|
135
|
+
}
|
|
136
|
+
|
|
92
137
|
drawImageCover(ctx, img, area, offset) {
|
|
93
|
-
const iw = img.naturalWidth
|
|
94
|
-
|
|
138
|
+
const iw = img.naturalWidth || img.width
|
|
139
|
+
const ih = img.naturalHeight || img.height
|
|
95
140
|
const cw = area.width,
|
|
96
141
|
ch = area.height
|
|
97
142
|
const ir = iw / ih,
|
|
@@ -116,14 +161,24 @@ export default class SpritePlayer {
|
|
|
116
161
|
this.scroll = current
|
|
117
162
|
|
|
118
163
|
const { ctx, width, height, area, offset } = this.canvas
|
|
119
|
-
const { images } = this.dom
|
|
164
|
+
const { images, alphaImages } = this.dom
|
|
120
165
|
const total = this.frameCount || images.length || 1
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
const
|
|
166
|
+
const index = Math.min(total - 1, Math.round(this.progress * (total - 1)))
|
|
167
|
+
const base = images[index]
|
|
168
|
+
const hasMasks = this.isAlpha && alphaImages.length === images.length
|
|
169
|
+
const mask = hasMasks ? alphaImages[index] : null
|
|
124
170
|
|
|
125
171
|
ctx.clearRect(0, 0, width, height)
|
|
126
|
-
if (
|
|
172
|
+
if (!base) return
|
|
173
|
+
|
|
174
|
+
this.drawImageCover(ctx, base, area, offset)
|
|
175
|
+
|
|
176
|
+
if (mask) {
|
|
177
|
+
ctx.save()
|
|
178
|
+
ctx.globalCompositeOperation = "destination-in"
|
|
179
|
+
this.drawImageCover(ctx, mask, area, offset)
|
|
180
|
+
ctx.restore()
|
|
181
|
+
}
|
|
127
182
|
}
|
|
128
183
|
|
|
129
184
|
resize = () => this.configureCanvas()
|
|
@@ -137,11 +192,30 @@ export default class SpritePlayer {
|
|
|
137
192
|
emitter.off(EVENTS.APP_RESIZE, this.resize)
|
|
138
193
|
}
|
|
139
194
|
|
|
195
|
+
setProgress(p) {
|
|
196
|
+
this.progress = gsap.utils.clamp(0, 1, p)
|
|
197
|
+
}
|
|
198
|
+
show() {
|
|
199
|
+
this.isVisible = true
|
|
200
|
+
}
|
|
201
|
+
hide() {
|
|
202
|
+
this.isVisible = false
|
|
203
|
+
const { ctx, width, height } = this.canvas
|
|
204
|
+
ctx.clearRect(0, 0, width, height)
|
|
205
|
+
}
|
|
206
|
+
enableAlpha(v = true) {
|
|
207
|
+
this.isAlpha = !!v
|
|
208
|
+
}
|
|
209
|
+
|
|
140
210
|
destroy() {
|
|
141
211
|
this.off()
|
|
142
|
-
|
|
143
|
-
|
|
212
|
+
if (!this.persistent) {
|
|
213
|
+
const revoke = img => img?.src?.startsWith("blob:") && URL.revokeObjectURL(img.src)
|
|
214
|
+
this.dom.images.forEach(revoke)
|
|
215
|
+
this.dom.alphaImages.forEach(revoke)
|
|
216
|
+
}
|
|
144
217
|
this.dom.images = []
|
|
218
|
+
this.dom.alphaImages = []
|
|
145
219
|
}
|
|
146
220
|
|
|
147
221
|
async init() {
|