canvu-react 0.3.31 → 0.3.33

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.js CHANGED
@@ -1043,17 +1043,154 @@ function svgNumber(value) {
1043
1043
  const rounded = Math.round(value * 100) / 100;
1044
1044
  return Number.isInteger(rounded) ? String(rounded) : String(rounded);
1045
1045
  }
1046
- function approximateEllipsePerimeter(rx, ry) {
1047
- if (rx <= 0 || ry <= 0) return 0;
1048
- return Math.PI * (3 * (rx + ry) - Math.sqrt((3 * rx + ry) * (rx + 3 * ry)));
1049
- }
1050
- function architecturalCloudScallopCount(rx, ry, amplitude) {
1051
- const perimeter = approximateEllipsePerimeter(rx, ry);
1052
- const targetScallopLength = Math.max(10, amplitude * 2);
1046
+ function architecturalCloudScallopCount(perimeter, amplitude) {
1047
+ const targetScallopLength = Math.max(18, amplitude * 2.45);
1053
1048
  let count = Math.max(12, Math.round(perimeter / targetScallopLength));
1054
1049
  if (count % 2 === 1) count += 1;
1055
1050
  return count;
1056
1051
  }
1052
+ function roundedRectMetrics(width, height, inset, radius) {
1053
+ const left = inset;
1054
+ const top = inset;
1055
+ const right = width - inset;
1056
+ const bottom = height - inset;
1057
+ const rectWidth = Math.max(0, right - left);
1058
+ const rectHeight = Math.max(0, bottom - top);
1059
+ const normalizedRadius = Math.max(
1060
+ 0,
1061
+ Math.min(radius, rectWidth / 2, rectHeight / 2)
1062
+ );
1063
+ const centerX = width / 2;
1064
+ const topHalfLength = Math.max(0, right - normalizedRadius - centerX);
1065
+ const horizontalLength = Math.max(0, rectWidth - normalizedRadius * 2);
1066
+ const verticalLength = Math.max(0, rectHeight - normalizedRadius * 2);
1067
+ const arcLength = normalizedRadius * (Math.PI / 2);
1068
+ return {
1069
+ left,
1070
+ top,
1071
+ right,
1072
+ bottom,
1073
+ radius: normalizedRadius,
1074
+ centerX,
1075
+ topHalfLength,
1076
+ horizontalLength,
1077
+ verticalLength,
1078
+ arcLength,
1079
+ perimeter: horizontalLength * 2 + verticalLength * 2 + Math.PI * 2 * normalizedRadius
1080
+ };
1081
+ }
1082
+ function pointOnLine(startX, startY, endX, endY, t) {
1083
+ return [startX + (endX - startX) * t, startY + (endY - startY) * t];
1084
+ }
1085
+ function pointOnArc(centerX, centerY, radius, startAngle, endAngle, t) {
1086
+ const theta = startAngle + (endAngle - startAngle) * t;
1087
+ return [centerX + Math.cos(theta) * radius, centerY + Math.sin(theta) * radius];
1088
+ }
1089
+ function pointOnRoundedRectPath(metrics, distance) {
1090
+ if (metrics.perimeter <= 0) return [metrics.centerX, metrics.top];
1091
+ let remaining = (distance % metrics.perimeter + metrics.perimeter) % metrics.perimeter;
1092
+ const consume = (length) => {
1093
+ if (length <= 1e-9) return null;
1094
+ if (remaining <= length) return remaining / length;
1095
+ remaining -= length;
1096
+ return null;
1097
+ };
1098
+ let t = consume(metrics.topHalfLength);
1099
+ if (t != null) {
1100
+ return pointOnLine(
1101
+ metrics.centerX,
1102
+ metrics.top,
1103
+ metrics.right - metrics.radius,
1104
+ metrics.top,
1105
+ t
1106
+ );
1107
+ }
1108
+ t = consume(metrics.arcLength);
1109
+ if (t != null) {
1110
+ return pointOnArc(
1111
+ metrics.right - metrics.radius,
1112
+ metrics.top + metrics.radius,
1113
+ metrics.radius,
1114
+ -Math.PI / 2,
1115
+ 0,
1116
+ t
1117
+ );
1118
+ }
1119
+ t = consume(metrics.verticalLength);
1120
+ if (t != null) {
1121
+ return pointOnLine(
1122
+ metrics.right,
1123
+ metrics.top + metrics.radius,
1124
+ metrics.right,
1125
+ metrics.bottom - metrics.radius,
1126
+ t
1127
+ );
1128
+ }
1129
+ t = consume(metrics.arcLength);
1130
+ if (t != null) {
1131
+ return pointOnArc(
1132
+ metrics.right - metrics.radius,
1133
+ metrics.bottom - metrics.radius,
1134
+ metrics.radius,
1135
+ 0,
1136
+ Math.PI / 2,
1137
+ t
1138
+ );
1139
+ }
1140
+ t = consume(metrics.horizontalLength);
1141
+ if (t != null) {
1142
+ return pointOnLine(
1143
+ metrics.right - metrics.radius,
1144
+ metrics.bottom,
1145
+ metrics.left + metrics.radius,
1146
+ metrics.bottom,
1147
+ t
1148
+ );
1149
+ }
1150
+ t = consume(metrics.arcLength);
1151
+ if (t != null) {
1152
+ return pointOnArc(
1153
+ metrics.left + metrics.radius,
1154
+ metrics.bottom - metrics.radius,
1155
+ metrics.radius,
1156
+ Math.PI / 2,
1157
+ Math.PI,
1158
+ t
1159
+ );
1160
+ }
1161
+ t = consume(metrics.verticalLength);
1162
+ if (t != null) {
1163
+ return pointOnLine(
1164
+ metrics.left,
1165
+ metrics.bottom - metrics.radius,
1166
+ metrics.left,
1167
+ metrics.top + metrics.radius,
1168
+ t
1169
+ );
1170
+ }
1171
+ t = consume(metrics.arcLength);
1172
+ if (t != null) {
1173
+ return pointOnArc(
1174
+ metrics.left + metrics.radius,
1175
+ metrics.top + metrics.radius,
1176
+ metrics.radius,
1177
+ Math.PI,
1178
+ Math.PI * 1.5,
1179
+ t
1180
+ );
1181
+ }
1182
+ t = consume(metrics.topHalfLength);
1183
+ if (t != null) {
1184
+ return pointOnLine(
1185
+ metrics.left + metrics.radius,
1186
+ metrics.top,
1187
+ metrics.centerX,
1188
+ metrics.top,
1189
+ t
1190
+ );
1191
+ }
1192
+ return [metrics.centerX, metrics.top];
1193
+ }
1057
1194
  function buildRectSvg(width, height, style = DEFAULT_STROKE_STYLE) {
1058
1195
  return `<rect width="${width}" height="${height}" fill="none" stroke="${style.stroke}" stroke-width="${style.strokeWidth}" rx="4"${strokeOpacityAttr(style)} />`;
1059
1196
  }
@@ -1067,33 +1204,34 @@ function buildArchitecturalCloudPathD(width, height, strokeWidth = DEFAULT_STROK
1067
1204
  const h = Math.max(0, height);
1068
1205
  if (w <= 0 || h <= 0) return "";
1069
1206
  const inset = Math.max(0.5, strokeWidth / 2);
1070
- const outerRx = Math.max(0, w / 2 - inset);
1071
- const outerRy = Math.max(0, h / 2 - inset);
1072
- if (outerRx <= 0 || outerRy <= 0) return "";
1207
+ const outerWidth = Math.max(0, w - inset * 2);
1208
+ const outerHeight = Math.max(0, h - inset * 2);
1209
+ if (outerWidth <= 0 || outerHeight <= 0) return "";
1073
1210
  const amplitude = Math.min(
1074
- outerRx * 0.45,
1075
- outerRy * 0.45,
1076
- Math.max(2, Math.min(8, Math.min(w, h) * 0.04))
1211
+ outerWidth * 0.12,
1212
+ outerHeight * 0.12,
1213
+ Math.max(5, Math.min(14, Math.min(w, h) * 0.07))
1077
1214
  );
1078
- const innerRx = Math.max(0, outerRx - amplitude);
1079
- const innerRy = Math.max(0, outerRy - amplitude);
1080
- const scallopCount = architecturalCloudScallopCount(innerRx, innerRy, amplitude);
1081
- const angleStep = Math.PI * 2 / scallopCount;
1082
- const cx = w / 2;
1083
- const cy = h / 2;
1084
- const startAngle = -Math.PI / 2;
1085
- const pointOnEllipse = (theta, radiusX, radiusY) => [
1086
- cx + Math.cos(theta) * radiusX,
1087
- cy + Math.sin(theta) * radiusY
1088
- ];
1089
- const [startX, startY] = pointOnEllipse(startAngle, innerRx, innerRy);
1215
+ const radius = Math.min(
1216
+ outerWidth / 2,
1217
+ outerHeight / 2,
1218
+ Math.max(amplitude * 2.5, outerHeight * 0.43)
1219
+ );
1220
+ const outer = roundedRectMetrics(w, h, inset, radius);
1221
+ const inner = roundedRectMetrics(
1222
+ w,
1223
+ h,
1224
+ inset + amplitude,
1225
+ Math.max(0, radius - amplitude)
1226
+ );
1227
+ const scallopCount = architecturalCloudScallopCount(outer.perimeter, amplitude);
1228
+ const [startX, startY] = pointOnRoundedRectPath(inner, 0);
1090
1229
  const segments = [`M${svgNumber(startX)} ${svgNumber(startY)}`];
1091
1230
  for (let index = 0; index < scallopCount; index += 1) {
1092
- const segmentStart = startAngle + index * angleStep;
1093
- const segmentMid = segmentStart + angleStep / 2;
1094
- const segmentEnd = segmentStart + angleStep;
1095
- const [controlX, controlY] = pointOnEllipse(segmentMid, outerRx, outerRy);
1096
- const [endX, endY] = pointOnEllipse(segmentEnd, innerRx, innerRy);
1231
+ const controlDistance = (index + 0.5) / scallopCount * outer.perimeter;
1232
+ const endDistance = (index + 1) / scallopCount * inner.perimeter;
1233
+ const [controlX, controlY] = pointOnRoundedRectPath(outer, controlDistance);
1234
+ const [endX, endY] = pointOnRoundedRectPath(inner, endDistance);
1097
1235
  segments.push(
1098
1236
  `Q${svgNumber(controlX)} ${svgNumber(controlY)} ${svgNumber(endX)} ${svgNumber(endY)}`
1099
1237
  );