animot-presenter 0.2.6 → 0.2.8

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.
@@ -100,10 +100,23 @@
100
100
  for (const seg of segs) {
101
101
  if (accum + seg.length >= targetLength || seg === segs[segs.length - 1]) {
102
102
  const t = Math.max(0, Math.min(1, seg.length > 0 ? (targetLength - accum) / seg.length : 0));
103
+ let dx = cubicBezDeriv(seg.p0x, seg.p1x, seg.p2x, seg.p3x, t);
104
+ let dy = cubicBezDeriv(seg.p0y, seg.p1y, seg.p2y, seg.p3y, t);
105
+ // Degenerate tangent at endpoints (no Bezier handles) — sample nearby
106
+ if (Math.abs(dx) < 0.001 && Math.abs(dy) < 0.001) {
107
+ const epsilon = t < 0.5 ? 0.01 : -0.01;
108
+ dx = cubicBezDeriv(seg.p0x, seg.p1x, seg.p2x, seg.p3x, t + epsilon);
109
+ dy = cubicBezDeriv(seg.p0y, seg.p1y, seg.p2y, seg.p3y, t + epsilon);
110
+ }
111
+ // Still zero (fully degenerate segment) — use chord direction
112
+ if (Math.abs(dx) < 0.001 && Math.abs(dy) < 0.001) {
113
+ dx = seg.p3x - seg.p0x;
114
+ dy = seg.p3y - seg.p0y;
115
+ }
103
116
  return {
104
117
  x: cubicBez(seg.p0x, seg.p1x, seg.p2x, seg.p3x, t),
105
118
  y: cubicBez(seg.p0y, seg.p1y, seg.p2y, seg.p3y, t),
106
- angle: Math.atan2(cubicBezDeriv(seg.p0y, seg.p1y, seg.p2y, seg.p3y, t), cubicBezDeriv(seg.p0x, seg.p1x, seg.p2x, seg.p3x, t)) * (180 / Math.PI)
119
+ angle: Math.atan2(dy, dx) * (180 / Math.PI)
107
120
  };
108
121
  }
109
122
  accum += seg.length;
@@ -114,8 +127,12 @@
114
127
  function computeMotionPathPosition(
115
128
  mpPoint: { x: number; y: number; angle: number },
116
129
  startPoint: { x: number; y: number; angle: number },
117
- animX: number, animY: number, animW: number, animH: number
130
+ animX: number, animY: number, animW: number, animH: number,
131
+ closed: boolean
118
132
  ): { x: number; y: number } {
133
+ if (!closed) {
134
+ return { x: mpPoint.x - animW / 2, y: mpPoint.y - animH / 2 };
135
+ }
119
136
  const offsetX = (animX + animW / 2) - startPoint.x;
120
137
  const offsetY = (animY + animH / 2) - startPoint.y;
121
138
  const angleDelta = (mpPoint.angle - startPoint.angle) * Math.PI / 180;
@@ -1017,10 +1034,11 @@
1017
1034
  {@const mpProgress = animated?.motionPathProgress?.current ?? 0}
1018
1035
  {@const mpPoint = mpElement && mpConfig ? getPresenterPointOnPath(mpElement.points, mpElement.closed, (mpConfig.startPercent + (mpConfig.endPercent - mpConfig.startPercent) * mpProgress) / 100) : null}
1019
1036
  {@const mpStartPoint = mpElement && mpConfig ? getPresenterPointOnPath(mpElement.points, mpElement.closed, mpConfig.startPercent / 100) : null}
1020
- {@const mpPos = mpPoint && mpStartPoint && animated
1037
+ {@const mpPos = mpPoint && mpStartPoint && animated && mpElement
1021
1038
  ? computeMotionPathPosition(mpPoint, mpStartPoint,
1022
1039
  animated.x.current, animated.y.current,
1023
- animated.width.current, animated.height.current)
1040
+ animated.width.current, animated.height.current,
1041
+ mpElement.closed)
1024
1042
  : null}
1025
1043
  {@const elemX = mpPos ? mpPos.x : (animated?.x.current ?? 0)}
1026
1044
  {@const elemY = mpPos ? mpPos.y : (animated?.y.current ?? 0)}
@@ -1240,6 +1258,27 @@
1240
1258
  </div>
1241
1259
 
1242
1260
  <script module lang="ts">
1261
+ function roundedPolygonPath(pointsStr: string, radius: number): string {
1262
+ const pts = pointsStr.split(/\s+/).map(p => { const [x, y] = p.split(',').map(Number); return { x, y }; });
1263
+ if (pts.length < 3 || radius <= 0) return 'M' + pts.map(p => `${p.x},${p.y}`).join('L') + 'Z';
1264
+ const n = pts.length;
1265
+ const parts: string[] = [];
1266
+ for (let i = 0; i < n; i++) {
1267
+ const prev = pts[(i - 1 + n) % n], curr = pts[i], next = pts[(i + 1) % n];
1268
+ const dx1 = prev.x - curr.x, dy1 = prev.y - curr.y;
1269
+ const dx2 = next.x - curr.x, dy2 = next.y - curr.y;
1270
+ const len1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
1271
+ const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
1272
+ const r = Math.min(radius, len1 / 2, len2 / 2);
1273
+ const sx = curr.x + (dx1 / len1) * r, sy = curr.y + (dy1 / len1) * r;
1274
+ const ex = curr.x + (dx2 / len2) * r, ey = curr.y + (dy2 / len2) * r;
1275
+ parts.push(i === 0 ? `M${sx},${sy}` : `L${sx},${sy}`);
1276
+ parts.push(`Q${curr.x},${curr.y} ${ex},${ey}`);
1277
+ }
1278
+ parts.push('Z');
1279
+ return parts.join(' ');
1280
+ }
1281
+
1243
1282
  function renderShape(type: string, w: number, h: number, br: number, fill: string, stroke: string, sw: number, strokeStyle?: string, strokeDashGap?: number): string {
1244
1283
  let dashAttr = '';
1245
1284
  if (strokeStyle && strokeStyle !== 'solid') {
@@ -1249,20 +1288,24 @@
1249
1288
  const lc = strokeStyle === 'dotted' ? 'round' : 'butt';
1250
1289
  dashAttr = ` stroke-dasharray="${da}" stroke-linecap="${lc}"`;
1251
1290
  }
1291
+ const polyOrPath = (pts: string) => {
1292
+ if (br > 0) return `<path d="${roundedPolygonPath(pts, br)}" fill="${fill}" stroke="${stroke}" stroke-width="${sw}"${dashAttr}/>`;
1293
+ return `<polygon points="${pts}" fill="${fill}" stroke="${stroke}" stroke-width="${sw}"${dashAttr} stroke-linejoin="round"/>`;
1294
+ };
1252
1295
  switch (type) {
1253
1296
  case 'rectangle': return `<rect x="${sw/2}" y="${sw/2}" width="${w-sw}" height="${h-sw}" rx="${br}" ry="${br}" fill="${fill}" stroke="${stroke}" stroke-width="${sw}"${dashAttr}/>`;
1254
1297
  case 'circle': return `<circle cx="${w/2}" cy="${h/2}" r="${Math.min(w,h)/2-sw/2}" fill="${fill}" stroke="${stroke}" stroke-width="${sw}"${dashAttr}/>`;
1255
1298
  case 'ellipse': return `<ellipse cx="${w/2}" cy="${h/2}" rx="${w/2-sw/2}" ry="${h/2-sw/2}" fill="${fill}" stroke="${stroke}" stroke-width="${sw}"${dashAttr}/>`;
1256
- case 'triangle': return `<polygon points="${w/2},${sw/2} ${sw/2},${h-sw/2} ${w-sw/2},${h-sw/2}" fill="${fill}" stroke="${stroke}" stroke-width="${sw}"${dashAttr} stroke-linejoin="round"/>`;
1299
+ case 'triangle': return polyOrPath(`${w/2},${sw/2} ${sw/2},${h-sw/2} ${w-sw/2},${h-sw/2}`);
1257
1300
  case 'star': {
1258
1301
  const cx = w/2, cy = h/2, outerR = Math.min(w,h)/2-sw/2, innerR = outerR*0.4;
1259
1302
  const pts = Array.from({length:10},(_,i)=>{const a=(i*Math.PI/5)-Math.PI/2;const r=i%2===0?outerR:innerR;return`${cx+r*Math.cos(a)},${cy+r*Math.sin(a)}`;}).join(' ');
1260
- return `<polygon points="${pts}" fill="${fill}" stroke="${stroke}" stroke-width="${sw}"${dashAttr} stroke-linejoin="round"/>`;
1303
+ return polyOrPath(pts);
1261
1304
  }
1262
1305
  case 'hexagon': {
1263
1306
  const cx = w/2, cy = h/2, r = Math.min(w,h)/2-sw/2;
1264
1307
  const pts = Array.from({length:6},(_,i)=>{const a=(i*Math.PI/3)-Math.PI/2;return`${cx+r*Math.cos(a)},${cy+r*Math.sin(a)}`;}).join(' ');
1265
- return `<polygon points="${pts}" fill="${fill}" stroke="${stroke}" stroke-width="${sw}"${dashAttr} stroke-linejoin="round"/>`;
1308
+ return polyOrPath(pts);
1266
1309
  }
1267
1310
  default: return '';
1268
1311
  }