@pixodesk/svg-animator-web 1.0.28 → 1.0.29

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/dist/index.cjs CHANGED
@@ -50,6 +50,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
50
50
  var index_exports = {};
51
51
  __export(index_exports, {
52
52
  COLOUR_ATTR_NAMES: () => COLOUR_ATTR_NAMES,
53
+ MISSING_GLYPH_CLASS_NAME: () => MISSING_GLYPH_CLASS_NAME,
53
54
  PX_ANIMATOR_DATA_KEY: () => PX_ANIMATOR_DATA_KEY,
54
55
  PX_ANIM_ATTR_NAME: () => PX_ANIM_ATTR_NAME,
55
56
  PX_ANIM_SRC_ATTR_NAME: () => PX_ANIM_SRC_ATTR_NAME,
@@ -1320,6 +1321,7 @@ var PxScrollSchema = implementsInterface()(px.object({
1320
1321
  subject: px.string().optional(),
1321
1322
  smoothing: px.number().optional(),
1322
1323
  pin: px.boolean().optional(),
1324
+ pinAlign: px.enum(["top", "center", "bottom"]).optional(),
1323
1325
  pinTop: px.number().optional(),
1324
1326
  pinDistance: px.number().optional(),
1325
1327
  range: PxScrollRangeSchema.optional()
@@ -4554,6 +4556,19 @@ var TEXT_ATTR_KEYS = [
4554
4556
  TEXT_CONTENT_ATTR,
4555
4557
  "xml:space"
4556
4558
  ];
4559
+ var PAINT_STATIC_KEYS = [
4560
+ "fillOpacity",
4561
+ "fillRule",
4562
+ "strokeOpacity",
4563
+ "strokeDasharray",
4564
+ "strokeDashoffset",
4565
+ "strokeLinecap",
4566
+ "strokeLinejoin",
4567
+ "strokeMiterlimit",
4568
+ "mixBlendMode",
4569
+ "filter"
4570
+ ];
4571
+ var PAINT_ANIMATE_KEYS = ["fill", "stroke", "strokeWidth", "opacity", "fillOpacity", "strokeOpacity", "strokeDasharray", "strokeDashoffset"];
4557
4572
  function parseLen(v) {
4558
4573
  if (typeof v === "number") return v;
4559
4574
  if (typeof v === "string") {
@@ -4565,17 +4580,39 @@ function parseLen(v) {
4565
4580
  function str(v) {
4566
4581
  return typeof v === "string" ? v : void 0;
4567
4582
  }
4583
+ function paintAnimateOf(node) {
4584
+ const bag = node.animate;
4585
+ if (!bag || typeof bag !== "object") return void 0;
4586
+ let out;
4587
+ for (const k of PAINT_ANIMATE_KEYS) {
4588
+ if (bag[k] !== void 0) (out != null ? out : out = {})[k] = bag[k];
4589
+ }
4590
+ return out;
4591
+ }
4568
4592
  function resolveStyle2(node, parent) {
4569
- var _a, _b, _c, _d, _e, _f, _g;
4570
- return {
4593
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
4594
+ const isTextRoot = node.type === "text";
4595
+ const nodeStyle = node.style;
4596
+ const own = (key) => {
4597
+ var _a2;
4598
+ return isTextRoot ? void 0 : (_a2 = node[key]) != null ? _a2 : nodeStyle == null ? void 0 : nodeStyle[key];
4599
+ };
4600
+ const res = {
4571
4601
  fontFamily: (_a = str(node.fontFamily)) != null ? _a : parent.fontFamily,
4572
4602
  fontSize: (_b = parseLen(node.fontSize)) != null ? _b : parent.fontSize,
4573
4603
  fill: (_c = node.fill) != null ? _c : parent.fill,
4574
4604
  stroke: (_d = node.stroke) != null ? _d : parent.stroke,
4575
4605
  strokeWidth: (_e = node.strokeWidth) != null ? _e : parent.strokeWidth,
4576
4606
  letterSpacing: (_f = parseLen(node.letterSpacing)) != null ? _f : parent.letterSpacing,
4577
- wordSpacing: (_g = parseLen(node.wordSpacing)) != null ? _g : parent.wordSpacing
4607
+ wordSpacing: (_g = parseLen(node.wordSpacing)) != null ? _g : parent.wordSpacing,
4608
+ opacity: (_h = parseLen(own("opacity"))) != null ? _h : parent.opacity,
4609
+ animate: (_i = isTextRoot ? void 0 : paintAnimateOf(node)) != null ? _i : parent.animate
4578
4610
  };
4611
+ for (const key of PAINT_STATIC_KEYS) {
4612
+ const v = (_j = own(key)) != null ? _j : parent[key];
4613
+ if (v !== void 0) res[key] = v;
4614
+ }
4615
+ return res;
4579
4616
  }
4580
4617
  function rootStyleOf(node) {
4581
4618
  var _a, _b, _c;
@@ -4594,6 +4631,11 @@ function paintOf(s) {
4594
4631
  if (s.fill !== void 0) p.fill = s.fill;
4595
4632
  if (s.stroke !== void 0) p.stroke = s.stroke;
4596
4633
  if (s.strokeWidth !== void 0) p.strokeWidth = s.strokeWidth;
4634
+ if (s.opacity !== void 0 && s.opacity !== 1) p.opacity = s.opacity;
4635
+ for (const key of PAINT_STATIC_KEYS) {
4636
+ if (s[key] !== void 0) p[key] = s[key];
4637
+ }
4638
+ if (s.animate !== void 0) p.animate = s.animate;
4597
4639
  return p;
4598
4640
  }
4599
4641
  function glyphFontFor(s, glyphs, soleFont, warnings) {
@@ -4607,6 +4649,7 @@ function soleFontOf(glyphs) {
4607
4649
  return names.length === 1 ? glyphs[names[0]] : void 0;
4608
4650
  }
4609
4651
  var MISSING_GLYPH_ADVANCE_EM = 0.6;
4652
+ var MISSING_GLYPH_CLASS_NAME = "px-missing-glyph";
4610
4653
  function missingGlyphBoxEm(advanceEm, ascentEm) {
4611
4654
  if (advanceEm <= 0 || ascentEm <= 0) return "";
4612
4655
  const inset = 0.08;
@@ -4642,7 +4685,7 @@ function materialiseGlyphTextHorizontal(node, opts) {
4642
4685
  pen.x += g.width * scale;
4643
4686
  } else if (/\S/.test(ch)) {
4644
4687
  const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
4645
- placements.push({ glyphD: missingGlyphBoxEm(advEm, ascentEm), m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
4688
+ placements.push({ glyphD: missingGlyphBoxEm(advEm, ascentEm), m: [scale, 0, 0, scale, pen.x, pen.y], paint, isMissing: true, line, x: pen.x, y: pen.y, scale });
4646
4689
  pen.x += advEm * scale;
4647
4690
  } else {
4648
4691
  pen.x += (g ? g.width : 0) * scale;
@@ -4833,7 +4876,7 @@ function collectAlongPathCells(node, glyphs, soleFont, warnings) {
4833
4876
  } else if (/\S/.test(ch)) {
4834
4877
  const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
4835
4878
  const boxAdv = wEm * scale;
4836
- cells.push({ glyphD: missingGlyphBoxEm(wEm, ascentEm), widthEm: wEm, scale, paint, midBase: adv + boxAdv / 2 });
4879
+ cells.push({ glyphD: missingGlyphBoxEm(wEm, ascentEm), widthEm: wEm, scale, paint, isMissing: true, midBase: adv + boxAdv / 2 });
4837
4880
  adv += boxAdv;
4838
4881
  } else {
4839
4882
  adv += (g ? g.width : 0) * scale;
@@ -4889,6 +4932,7 @@ function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLengt
4889
4932
  const placements = placeCells.map((c) => ({
4890
4933
  glyphD: c.glyphD,
4891
4934
  paint: c.paint,
4935
+ isMissing: c.isMissing,
4892
4936
  m: alongAffine(sampler, base + c.midBase * k, c.scale, c.widthEm, perp)
4893
4937
  }));
4894
4938
  return toGroup(node, buildPaths(placements, create, warnings), create);
@@ -4977,12 +5021,13 @@ function buildAnimatedAlongPath(cells, sampler, distOf, times, loop, create, isC
4977
5021
  const transform = { keyframes: kfs };
4978
5022
  if (loop !== void 0) transform.loop = loop;
4979
5023
  const animate = { transform };
5024
+ if (c.paint.animate) Object.assign(animate, c.paint.animate);
4980
5025
  if (isClip && opKfs.some((k) => k.value === 0)) {
4981
5026
  const op = { keyframes: opKfs };
4982
5027
  if (loop !== void 0) op.loop = loop;
4983
5028
  animate.opacity = op;
4984
5029
  }
4985
- out.push(create("path", __spreadProps2(__spreadValues2({ d }, paintProps(c.paint)), { animate }), []));
5030
+ out.push(create("path", __spreadProps2(__spreadValues2(__spreadValues2({ d }, paintProps(c.paint)), missingGlyphProps(c.isMissing)), { animate }), []));
4986
5031
  }
4987
5032
  return out;
4988
5033
  }
@@ -4991,24 +5036,34 @@ function paintProps(paint) {
4991
5036
  if (paint.fill !== void 0) p.fill = paint.fill;
4992
5037
  if (paint.stroke !== void 0) p.stroke = paint.stroke;
4993
5038
  if (paint.strokeWidth !== void 0) p.strokeWidth = paint.strokeWidth;
5039
+ if (paint.opacity !== void 0) p.opacity = paint.opacity;
5040
+ for (const key of PAINT_STATIC_KEYS) {
5041
+ if (paint[key] !== void 0) p[key] = paint[key];
5042
+ }
4994
5043
  return p;
4995
5044
  }
5045
+ function missingGlyphProps(isMissing) {
5046
+ return isMissing ? { class: MISSING_GLYPH_CLASS_NAME } : {};
5047
+ }
4996
5048
  function buildPaths(placements, create, warnings) {
4997
- var _a, _b, _c;
4998
5049
  if (!placements.length) {
4999
5050
  warnings == null ? void 0 : warnings.push("textGlyphs: nothing to render");
5000
5051
  return [];
5001
5052
  }
5002
5053
  const byPaint = /* @__PURE__ */ new Map();
5003
5054
  for (const p of placements) {
5004
- const key = JSON.stringify([(_a = p.paint.fill) != null ? _a : null, (_b = p.paint.stroke) != null ? _b : null, (_c = p.paint.strokeWidth) != null ? _c : null]);
5055
+ const key = JSON.stringify([p.paint, !!p.isMissing]);
5005
5056
  const baked = transformPathData(p.glyphD, p.m);
5006
5057
  const entry = byPaint.get(key);
5007
5058
  if (entry) entry.d += baked;
5008
- else byPaint.set(key, { paint: p.paint, d: baked });
5059
+ else byPaint.set(key, { paint: p.paint, d: baked, isMissing: p.isMissing });
5009
5060
  }
5010
5061
  const out = [];
5011
- for (const { paint, d } of byPaint.values()) out.push(create("path", __spreadValues2({ d }, paintProps(paint)), []));
5062
+ for (const { paint, d, isMissing } of byPaint.values()) {
5063
+ out.push(create("path", __spreadValues2(__spreadValues2(__spreadValues2({
5064
+ d
5065
+ }, paintProps(paint)), missingGlyphProps(isMissing)), paint.animate !== void 0 ? { animate: __spreadValues2({}, paint.animate) } : {}), []));
5066
+ }
5012
5067
  return out;
5013
5068
  }
5014
5069
  function toGroup(node, children, create) {
@@ -6728,8 +6783,11 @@ function createScrollDriver(subject, config, onProgress) {
6728
6783
  driver.refresh();
6729
6784
  return driver;
6730
6785
  }
6786
+ function pinScrollportHeight(svgRoot) {
6787
+ const scroller = findNearestScroller(svgRoot, "y");
6788
+ return scroller ? scroller.clientHeight : document.documentElement.clientHeight;
6789
+ }
6731
6790
  function applyScrollPin(svgRoot, scroll) {
6732
- var _a;
6733
6791
  const styled = svgRoot;
6734
6792
  if (!(scroll == null ? void 0 : scroll.pin) || !styled.style) return () => {
6735
6793
  };
@@ -6737,7 +6795,28 @@ function applyScrollPin(svgRoot, scroll) {
6737
6795
  const prevPosition = style.position;
6738
6796
  const prevTop = style.top;
6739
6797
  style.position = "sticky";
6740
- style.top = ((_a = scroll.pinTop) != null ? _a : 0) + "px";
6798
+ const alignFactor = scroll.pinAlign === "center" ? 0.5 : scroll.pinAlign === "bottom" ? 1 : 0;
6799
+ const applyTop = () => {
6800
+ var _a;
6801
+ const extra = (_a = scroll.pinTop) != null ? _a : 0;
6802
+ if (!alignFactor) {
6803
+ style.top = extra + "px";
6804
+ return;
6805
+ }
6806
+ const portSize = pinScrollportHeight(svgRoot);
6807
+ const ownSize = svgRoot.getBoundingClientRect().height;
6808
+ style.top = Math.round((portSize - ownSize) * alignFactor + extra) + "px";
6809
+ };
6810
+ applyTop();
6811
+ let resizeObserver = null;
6812
+ const onWindowResize = alignFactor ? applyTop : null;
6813
+ if (alignFactor) {
6814
+ if (onWindowResize) window.addEventListener("resize", onWindowResize);
6815
+ if (typeof ResizeObserver !== "undefined") {
6816
+ resizeObserver = new ResizeObserver(applyTop);
6817
+ resizeObserver.observe(svgRoot);
6818
+ }
6819
+ }
6741
6820
  let wrapper = null;
6742
6821
  const parent = svgRoot.parentElement;
6743
6822
  if (scroll.pinDistance && scroll.pinDistance > 0 && parent) {
@@ -6748,6 +6827,8 @@ function applyScrollPin(svgRoot, scroll) {
6748
6827
  wrapper.appendChild(svgRoot);
6749
6828
  }
6750
6829
  return () => {
6830
+ if (onWindowResize) window.removeEventListener("resize", onWindowResize);
6831
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
6751
6832
  style.position = prevPosition;
6752
6833
  style.top = prevTop;
6753
6834
  if (wrapper == null ? void 0 : wrapper.parentElement) {
@@ -7015,6 +7096,7 @@ if (typeof window !== "undefined") {
7015
7096
  // Annotate the CommonJS export names for ESM import in node:
7016
7097
  0 && (module.exports = {
7017
7098
  COLOUR_ATTR_NAMES,
7099
+ MISSING_GLYPH_CLASS_NAME,
7018
7100
  PX_ANIMATOR_DATA_KEY,
7019
7101
  PX_ANIM_ATTR_NAME,
7020
7102
  PX_ANIM_SRC_ATTR_NAME,