@frybynite/image-cloud 0.2.8 → 0.2.9
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 +5 -3
- package/dist/image-cloud-auto-init.js +46 -19
- package/dist/image-cloud-auto-init.js.map +1 -1
- package/dist/image-cloud.js +229 -202
- package/dist/image-cloud.js.map +1 -1
- package/dist/image-cloud.umd.js +3 -3
- package/dist/image-cloud.umd.js.map +1 -1
- package/dist/index.d.ts +12 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Image Cloud Library
|
|
4
4
|
|
|
5
|
-
A TypeScript library for creating interactive image clouds with animated scattered layouts and zoom effects. Supports multiple image sources (
|
|
5
|
+
A TypeScript library for creating interactive image clouds with animated scattered layouts and zoom effects. Supports multiple image sources (static URLs, JSON endpoints, Google Drive) and layout algorithms.
|
|
6
6
|
|
|
7
7
|
> [!WARNING]
|
|
8
8
|
> ⚠️ All minor versions of this library before 1.0 (e.g., 0.1, 0.2, ...) will include breaking changes during development. Please re-test every time before upgrading until we have published v1.0.
|
|
@@ -15,7 +15,7 @@ A TypeScript library for creating interactive image clouds with animated scatter
|
|
|
15
15
|
- 🔍 Zoom/focus interactions with keyboard navigation
|
|
16
16
|
- 🎨 State-based image styling (borders, shadows, filters for default/hover/focused)
|
|
17
17
|
- 📱 Responsive design with adaptive sizing
|
|
18
|
-
- 🖼️ Multiple image sources (
|
|
18
|
+
- 🖼️ Multiple image sources (static URLs, JSON endpoints, Google Drive, composite loaders)
|
|
19
19
|
- 🛠️ Interactive configurator for visual configuration
|
|
20
20
|
- 📦 Zero runtime dependencies
|
|
21
21
|
- 🔷 Full TypeScript support
|
|
@@ -121,7 +121,7 @@ await cloud.init();
|
|
|
121
121
|
|
|
122
122
|
For detailed configuration, see the documentation in the `docs/` folder:
|
|
123
123
|
|
|
124
|
-
1. **[Loaders](docs/LOADERS.md)** — Configure image sources (static URLs, local paths, Google Drive folders)
|
|
124
|
+
1. **[Loaders](docs/LOADERS.md)** — Configure image sources (static URLs, JSON endpoints, local paths, Google Drive folders)
|
|
125
125
|
2. **[Layout Generators](docs/GENERATORS.md)** — Choose and customize layout algorithms (radial, grid, spiral, cluster, random)
|
|
126
126
|
3. **[Image Sizing](docs/IMAGE_SIZING.md)** — Control base sizes, variance, and responsive/adaptive behavior
|
|
127
127
|
4. **[Full Parameter Reference](docs/PARAMETERS.md)** — Complete configuration options for animation, interaction, styling, and more
|
|
@@ -169,6 +169,8 @@ Check out the `examples/` directory for various usage patterns:
|
|
|
169
169
|
- `cdn-umd-example.html` - Traditional script tag / CDN usage
|
|
170
170
|
- `auto-init-example.html` - HTML data attribute initialization
|
|
171
171
|
- `static-loader-example.html` - Static image URLs
|
|
172
|
+
- `static-urls-shorthand-example.html` - Simplest static loader: direct URL array shorthand
|
|
173
|
+
- `static-json-source-example.html` - Load images from a JSON endpoint
|
|
172
174
|
- `google-drive-loader-example.html` - Google Drive folder source
|
|
173
175
|
- `layout-algorithms.html` - Compare all layout algorithms
|
|
174
176
|
- `entry-animations.html` - Entry animation styles
|
|
@@ -95,7 +95,9 @@ const kt = ".fbn-ic-gallery{--fbn-ic-bg-primary: #05060F;--fbn-ic-bg-secondary:
|
|
|
95
95
|
}),
|
|
96
96
|
static: Object.freeze({
|
|
97
97
|
sources: [],
|
|
98
|
-
// Must be provided by user
|
|
98
|
+
// Must be provided by user (or use urls shorthand)
|
|
99
|
+
urls: void 0,
|
|
100
|
+
// Shorthand for sources: [{ type: 'urls', urls: [...] }]
|
|
99
101
|
validateUrls: !0,
|
|
100
102
|
validationTimeout: 5e3,
|
|
101
103
|
validationMethod: "head",
|
|
@@ -299,7 +301,7 @@ function Bt(o) {
|
|
|
299
301
|
}
|
|
300
302
|
};
|
|
301
303
|
}
|
|
302
|
-
function
|
|
304
|
+
function Jt(o = {}) {
|
|
303
305
|
var s;
|
|
304
306
|
const t = Xt(o), e = Bt(o);
|
|
305
307
|
let i = o.image;
|
|
@@ -333,6 +335,7 @@ function Vt(o = {}) {
|
|
|
333
335
|
...y.loader.static,
|
|
334
336
|
...o.loader.static,
|
|
335
337
|
sources: o.loader.static.sources || y.loader.static.sources,
|
|
338
|
+
urls: o.loader.static.urls || void 0,
|
|
336
339
|
allowedExtensions: o.loader.static.allowedExtensions || y.loader.static.allowedExtensions
|
|
337
340
|
})), o.layout && (n.layout = {
|
|
338
341
|
...y.layout,
|
|
@@ -396,7 +399,7 @@ function Vt(o = {}) {
|
|
|
396
399
|
...o.rendering.performance
|
|
397
400
|
})), o.debug !== void 0 && (n.debug = o.debug), n;
|
|
398
401
|
}
|
|
399
|
-
function
|
|
402
|
+
function Vt(o, t) {
|
|
400
403
|
return { ...o ? zt[o] : zt.playful, ...t };
|
|
401
404
|
}
|
|
402
405
|
function Kt(o, t) {
|
|
@@ -675,7 +678,7 @@ function re(o) {
|
|
|
675
678
|
let A;
|
|
676
679
|
switch (p) {
|
|
677
680
|
case "bounce": {
|
|
678
|
-
const _ =
|
|
681
|
+
const _ = Vt(
|
|
679
682
|
n.bouncePreset,
|
|
680
683
|
n.bounce
|
|
681
684
|
);
|
|
@@ -1244,24 +1247,24 @@ class fe {
|
|
|
1244
1247
|
for (let F = 0; F < t; F++) {
|
|
1245
1248
|
let $, N, G = 0;
|
|
1246
1249
|
if (M && F >= z) {
|
|
1247
|
-
const
|
|
1248
|
-
G = Math.floor(
|
|
1250
|
+
const V = F - z, J = V % z;
|
|
1251
|
+
G = Math.floor(V / z) + 1, _[J]++, a.fillDirection === "row" ? ($ = J % g, N = Math.floor(J / g)) : (N = J % f, $ = Math.floor(J / f));
|
|
1249
1252
|
} else
|
|
1250
1253
|
a.fillDirection === "row" ? ($ = F % g, N = Math.floor(F / g)) : (N = F % f, $ = Math.floor(F / f));
|
|
1251
1254
|
let H = A + $ * (x + a.gap) + x / 2, it = O + N * (L + a.gap) + L / 2;
|
|
1252
1255
|
if (a.stagger === "row" && N % 2 === 1 ? H += x / 2 : a.stagger === "column" && $ % 2 === 1 && (it += L / 2), G > 0) {
|
|
1253
|
-
const
|
|
1254
|
-
H +=
|
|
1256
|
+
const V = (G - 1) % Lt.length, J = Lt[V];
|
|
1257
|
+
H += J.x * K, it += J.y * K;
|
|
1255
1258
|
}
|
|
1256
1259
|
if (a.jitter > 0) {
|
|
1257
|
-
const
|
|
1258
|
-
H += this.random(-
|
|
1260
|
+
const V = x / 2 * a.jitter, J = L / 2 * a.jitter;
|
|
1261
|
+
H += this.random(-V, V), it += this.random(-J, J);
|
|
1259
1262
|
}
|
|
1260
1263
|
let nt = H, ot = it;
|
|
1261
1264
|
if (!M && a.fillDirection === "row") {
|
|
1262
|
-
const
|
|
1263
|
-
if (N === Math.floor((t - 1) / g) &&
|
|
1264
|
-
const Mt =
|
|
1265
|
+
const V = t % g || g;
|
|
1266
|
+
if (N === Math.floor((t - 1) / g) && V < g) {
|
|
1267
|
+
const Mt = V * x + (V - 1) * a.gap;
|
|
1265
1268
|
let St = 0;
|
|
1266
1269
|
a.alignment === "center" ? St = (C - Mt) / 2 : a.alignment === "end" && (St = C - Mt), nt += St;
|
|
1267
1270
|
}
|
|
@@ -1270,8 +1273,8 @@ class fe {
|
|
|
1270
1273
|
nt = Math.max(yt, Math.min(nt, vt)), ot = Math.max(Ht, Math.min(ot, _t));
|
|
1271
1274
|
let wt = 0;
|
|
1272
1275
|
if (u === "random") {
|
|
1273
|
-
const
|
|
1274
|
-
a.jitter > 0 ? wt = this.random(
|
|
1276
|
+
const V = ((q = (tt = this.imageConfig.rotation) == null ? void 0 : tt.range) == null ? void 0 : q.min) ?? -15, J = ((Y = (et = this.imageConfig.rotation) == null ? void 0 : et.range) == null ? void 0 : Y.max) ?? 15;
|
|
1277
|
+
a.jitter > 0 ? wt = this.random(V * a.jitter, J * a.jitter) : wt = this.random(V, J);
|
|
1275
1278
|
}
|
|
1276
1279
|
let xt;
|
|
1277
1280
|
M && G > 0 ? xt = 50 - G : xt = M ? 100 + F : F + 1, n.push({
|
|
@@ -2575,8 +2578,8 @@ class Le {
|
|
|
2575
2578
|
}
|
|
2576
2579
|
class Oe {
|
|
2577
2580
|
constructor(t = {}) {
|
|
2578
|
-
if (this._prepared = !1, this._discoveredUrls = [], this.validateUrls = t.validateUrls !== !1, this.validationTimeout = t.validationTimeout ?? 5e3, this.validationMethod = t.validationMethod ?? "head", this.sources = t.sources ?? []
|
|
2579
|
-
throw new Error("StaticImageLoader requires at least one source to be configured");
|
|
2581
|
+
if (this._prepared = !1, this._discoveredUrls = [], this.validateUrls = t.validateUrls !== !1, this.validationTimeout = t.validationTimeout ?? 5e3, this.validationMethod = t.validationMethod ?? "head", this.debugLogging = t.debugLogging ?? !1, t.urls && Array.isArray(t.urls) && t.urls.length > 0 ? this.sources = [{ type: "urls", urls: t.urls }, ...t.sources ?? []] : this.sources = t.sources ?? [], !this.sources || this.sources.length === 0)
|
|
2582
|
+
throw new Error("StaticImageLoader requires at least one source (or urls shorthand) to be configured");
|
|
2580
2583
|
this.log("StaticImageLoader initialized with config:", t);
|
|
2581
2584
|
}
|
|
2582
2585
|
/**
|
|
@@ -2625,7 +2628,7 @@ class Oe {
|
|
|
2625
2628
|
* @returns Promise resolving to array of valid URLs from this source
|
|
2626
2629
|
*/
|
|
2627
2630
|
async processSource(t, e) {
|
|
2628
|
-
return !t || !t.type ? (console.warn("Invalid source object (missing type):", t), []) : t.type === "urls" ? await this.processUrls(t.urls || [], e) : t.type === "path" ? await this.processPath(t.basePath, t.files || [], e) : (console.warn(`Unknown source type: ${t.type}`), []);
|
|
2631
|
+
return !t || !t.type ? (console.warn("Invalid source object (missing type):", t), []) : t.type === "urls" ? await this.processUrls(t.urls || [], e) : t.type === "path" ? await this.processPath(t.basePath, t.files || [], e) : t.type === "json" ? await this.processJson(t.url, e) : (console.warn(`Unknown source type: ${t.type}`), []);
|
|
2629
2632
|
}
|
|
2630
2633
|
/**
|
|
2631
2634
|
* Process a list of direct URLs
|
|
@@ -2670,6 +2673,30 @@ class Oe {
|
|
|
2670
2673
|
}
|
|
2671
2674
|
return n;
|
|
2672
2675
|
}
|
|
2676
|
+
/**
|
|
2677
|
+
* Process a JSON endpoint source
|
|
2678
|
+
* Fetches a JSON endpoint that returns { images: string[] }
|
|
2679
|
+
* @param url - JSON endpoint URL
|
|
2680
|
+
* @param filter - Filter to apply to discovered images
|
|
2681
|
+
* @returns Promise resolving to array of validated URLs
|
|
2682
|
+
*/
|
|
2683
|
+
async processJson(t, e) {
|
|
2684
|
+
if (!t)
|
|
2685
|
+
return console.warn("url is required for json-type sources"), [];
|
|
2686
|
+
this.log(`Fetching JSON endpoint: ${t}`);
|
|
2687
|
+
const i = new AbortController(), n = setTimeout(() => i.abort(), 1e4);
|
|
2688
|
+
try {
|
|
2689
|
+
const s = await fetch(t, { signal: i.signal });
|
|
2690
|
+
if (clearTimeout(n), !s.ok)
|
|
2691
|
+
throw new Error(`HTTP ${s.status} fetching ${t}`);
|
|
2692
|
+
const r = await s.json();
|
|
2693
|
+
if (!r || !Array.isArray(r.images))
|
|
2694
|
+
throw new Error('JSON source must return JSON with shape { "images": ["url1", "url2", ...] }');
|
|
2695
|
+
return this.log(`JSON endpoint returned ${r.images.length} image(s)`), await this.processUrls(r.images, e);
|
|
2696
|
+
} catch (s) {
|
|
2697
|
+
throw clearTimeout(n), s instanceof Error && s.name === "AbortError" ? new Error(`Timeout fetching JSON endpoint: ${t}`) : s;
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2673
2700
|
/**
|
|
2674
2701
|
* Validate a single URL using HEAD request
|
|
2675
2702
|
* @param url - URL to validate
|
|
@@ -2879,7 +2906,7 @@ function Ue() {
|
|
|
2879
2906
|
class He {
|
|
2880
2907
|
constructor(t = {}) {
|
|
2881
2908
|
var i, n, s, r, a, h;
|
|
2882
|
-
this.fullConfig =
|
|
2909
|
+
this.fullConfig = Jt(t), t.container instanceof HTMLElement ? (this.containerRef = t.container, this.containerId = null) : (this.containerRef = null, this.containerId = t.container || "imageCloud"), this.imagesLoaded = !1, this.imageElements = [], this.imageLayouts = [], this.currentImageHeight = 225, this.currentFocusIndex = null, this.hoveredImage = null, this.resizeTimeout = null, this.displayQueue = [], this.queueInterval = null, this.loadGeneration = 0, this.animationEngine = new Qt(this.fullConfig.animation), this.layoutEngine = new xe({
|
|
2883
2910
|
layout: this.fullConfig.layout,
|
|
2884
2911
|
image: this.fullConfig.image
|
|
2885
2912
|
}), this.zoomEngine = new Te(this.fullConfig.interaction.focus, this.animationEngine, this.fullConfig.styling), this.defaultStyles = ft((i = this.fullConfig.styling) == null ? void 0 : i.default), this.hoverStyles = ft((n = this.fullConfig.styling) == null ? void 0 : n.hover), this.defaultClassName = (r = (s = this.fullConfig.styling) == null ? void 0 : s.default) == null ? void 0 : r.className, this.hoverClassName = (h = (a = this.fullConfig.styling) == null ? void 0 : a.hover) == null ? void 0 : h.className;
|