@empoweredvote/ev-ui 0.8.1 → 0.8.3
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 +99 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +99 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -12,10 +12,13 @@ function RadarChartCore({
|
|
|
12
12
|
onReplaceTopic = () => {
|
|
13
13
|
},
|
|
14
14
|
size = 400,
|
|
15
|
+
labelFontSize = 13,
|
|
15
16
|
padding = 80,
|
|
17
|
+
labelOffset = 52,
|
|
16
18
|
tightFit = false,
|
|
17
19
|
activeSpoke = null,
|
|
18
|
-
writeIns = {}
|
|
20
|
+
writeIns = {},
|
|
21
|
+
darkMode = false
|
|
19
22
|
}) {
|
|
20
23
|
var _a;
|
|
21
24
|
const radius = size / 2 - 40;
|
|
@@ -86,9 +89,25 @@ function RadarChartCore({
|
|
|
86
89
|
acc[shortTitle] = userAdj > 10 || cmpAdj > 10;
|
|
87
90
|
return acc;
|
|
88
91
|
}, {});
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
const labelMeta = spokes.map(([shortTitle], i) => {
|
|
93
|
+
const angle = 2 * Math.PI * i / numSpokes;
|
|
94
|
+
const lines = wrapLabel(shortTitle, 12);
|
|
95
|
+
const longestLineLen = lines.reduce((m, ln) => ln.length > m ? ln.length : m, 0);
|
|
96
|
+
const estimatedWidth = longestLineLen * labelFontSize * 0.55;
|
|
97
|
+
const sinA = Math.sin(angle);
|
|
98
|
+
const side = sinA < -0.1 ? "left" : sinA > 0.1 ? "right" : "center";
|
|
99
|
+
return { estimatedWidth, side };
|
|
100
|
+
});
|
|
101
|
+
const leftLabelWidths = labelMeta.filter((m) => m.side === "left").map((m) => m.estimatedWidth);
|
|
102
|
+
const rightLabelWidths = labelMeta.filter((m) => m.side === "right").map((m) => m.estimatedWidth);
|
|
103
|
+
const minPadding = 40;
|
|
104
|
+
const maxPadding = padding * 2;
|
|
105
|
+
const rawLeft = Math.min(Math.max(leftLabelWidths.length ? Math.max(...leftLabelWidths) + labelOffset : 0, minPadding), maxPadding);
|
|
106
|
+
const rawRight = Math.min(Math.max(rightLabelWidths.length ? Math.max(...rightLabelWidths) + labelOffset : 0, minPadding), maxPadding);
|
|
107
|
+
const sidePadding = Math.max(rawLeft, rawRight);
|
|
108
|
+
const verticalPadding = padding;
|
|
109
|
+
let tightTop = -verticalPadding;
|
|
110
|
+
let tightHeight = size + verticalPadding * 2;
|
|
92
111
|
if (tightFit && numSpokes > 0) {
|
|
93
112
|
let yMin = Infinity, yMax = -Infinity;
|
|
94
113
|
for (let i = 0; i < numSpokes; i++) {
|
|
@@ -98,8 +117,9 @@ function RadarChartCore({
|
|
|
98
117
|
if (y < yMin) yMin = y;
|
|
99
118
|
if (y > yMax) yMax = y;
|
|
100
119
|
}
|
|
101
|
-
|
|
102
|
-
|
|
120
|
+
const labelMargin = labelOffset + labelFontSize * 2.5;
|
|
121
|
+
tightTop = yMin - labelMargin;
|
|
122
|
+
tightHeight = yMax + labelMargin - tightTop;
|
|
103
123
|
}
|
|
104
124
|
const guidePolygons = [];
|
|
105
125
|
for (let level = 1; level <= 5; level++) {
|
|
@@ -110,7 +130,7 @@ function RadarChartCore({
|
|
|
110
130
|
ring.push(`${centerX + radius * scale * Math.sin(angle)},${centerY - radius * scale * Math.cos(angle)}`);
|
|
111
131
|
}
|
|
112
132
|
guidePolygons.push(
|
|
113
|
-
/* @__PURE__ */ React.createElement("polygon", { key: level, points: ring.join(" "), fill: "none", stroke: "#ccc" })
|
|
133
|
+
/* @__PURE__ */ React.createElement("polygon", { key: level, points: ring.join(" "), fill: "none", stroke: darkMode ? "#555" : "#ccc" })
|
|
114
134
|
);
|
|
115
135
|
}
|
|
116
136
|
const getStanceText = (shortTitle, value) => {
|
|
@@ -147,7 +167,7 @@ function RadarChartCore({
|
|
|
147
167
|
y1: centerY,
|
|
148
168
|
x2: endX,
|
|
149
169
|
y2: endY,
|
|
150
|
-
stroke: isUnanswered ? "#9ca3af" : "#
|
|
170
|
+
stroke: isUnanswered ? "#9ca3af" : darkMode ? "#bbb" : "#888",
|
|
151
171
|
strokeDasharray: isUnanswered ? "4 3" : void 0,
|
|
152
172
|
opacity: isUnanswered ? 0.6 : 1
|
|
153
173
|
}
|
|
@@ -164,6 +184,39 @@ function RadarChartCore({
|
|
|
164
184
|
}
|
|
165
185
|
));
|
|
166
186
|
}),
|
|
187
|
+
spokes.map(([shortTitle], i) => {
|
|
188
|
+
const angle = 2 * Math.PI * i / numSpokes;
|
|
189
|
+
const cosA = Math.cos(angle);
|
|
190
|
+
const isBottom = cosA < -0.5;
|
|
191
|
+
const isTop = cosA > 0.5;
|
|
192
|
+
const lines = wrapLabel(shortTitle, 12);
|
|
193
|
+
const longestLine = lines.reduce((m, ln) => ln.length > m ? ln.length : m, 0);
|
|
194
|
+
const lineHeight = labelFontSize * 1.2;
|
|
195
|
+
const dynamicOffset = lines.length > 1 ? labelOffset + 6 : labelOffset;
|
|
196
|
+
const offset2 = radius + dynamicOffset;
|
|
197
|
+
const labelX = centerX + offset2 * Math.sin(angle);
|
|
198
|
+
let labelY = centerY - offset2 * Math.cos(angle);
|
|
199
|
+
if (isTop && lines.length > 1) labelY -= (lines.length - 1) * lineHeight;
|
|
200
|
+
const isActive = shortTitle === activeSpoke;
|
|
201
|
+
const isUnansweredLabel = !!unansweredSpokes[shortTitle];
|
|
202
|
+
const fSize = labelFontSize;
|
|
203
|
+
return /* @__PURE__ */ React.createElement(
|
|
204
|
+
"text",
|
|
205
|
+
{
|
|
206
|
+
key: `label-${shortTitle}`,
|
|
207
|
+
x: labelX,
|
|
208
|
+
y: labelY,
|
|
209
|
+
textAnchor: "middle",
|
|
210
|
+
dominantBaseline: isBottom ? "hanging" : "auto",
|
|
211
|
+
onClick: () => onReplaceTopic(shortTitle),
|
|
212
|
+
fill: isActive ? "#E85D26" : isUnansweredLabel ? "#9ca3af" : darkMode ? "#D3D7DE" : "#555",
|
|
213
|
+
fontWeight: isActive ? "bold" : "normal",
|
|
214
|
+
style: { cursor: "pointer", userSelect: "none", fontSize: fSize, fontFamily: "sans-serif" }
|
|
215
|
+
},
|
|
216
|
+
isUnansweredLabel && /* @__PURE__ */ React.createElement("title", null, "No stance on file for this topic."),
|
|
217
|
+
lines.map((ln, idx) => /* @__PURE__ */ React.createElement("tspan", { key: idx, x: labelX, dy: idx === 0 ? "0" : `${lineHeight}` }, ln))
|
|
218
|
+
);
|
|
219
|
+
}),
|
|
167
220
|
countChanged ? /* @__PURE__ */ React.createElement(
|
|
168
221
|
"polygon",
|
|
169
222
|
{
|
|
@@ -278,14 +331,14 @@ function RadarChartCore({
|
|
|
278
331
|
{
|
|
279
332
|
xmlns: "http://www.w3.org/1999/xhtml",
|
|
280
333
|
style: {
|
|
281
|
-
background: "
|
|
282
|
-
border: "1px solid #d1d5db",
|
|
283
|
-
borderRadius:
|
|
284
|
-
padding: "
|
|
285
|
-
fontSize:
|
|
334
|
+
background: darkMode ? "#2F3237" : "#ffffff",
|
|
335
|
+
border: darkMode ? "1px solid #59B0C4" : "1px solid #d1d5db",
|
|
336
|
+
borderRadius: 8,
|
|
337
|
+
padding: "7px 11px",
|
|
338
|
+
fontSize: 12,
|
|
286
339
|
lineHeight: 1.4,
|
|
287
|
-
color: "#111",
|
|
288
|
-
boxShadow: "0 2px 8px rgba(0,0,0,0.12)",
|
|
340
|
+
color: darkMode ? "#EBEDEF" : "#111",
|
|
341
|
+
boxShadow: darkMode ? "0 2px 12px rgba(0,0,0,0.4)" : "0 2px 8px rgba(0,0,0,0.12)",
|
|
289
342
|
width: tipW + "px",
|
|
290
343
|
wordWrap: "break-word"
|
|
291
344
|
}
|
|
@@ -296,6 +349,37 @@ function RadarChartCore({
|
|
|
296
349
|
})()
|
|
297
350
|
);
|
|
298
351
|
}
|
|
352
|
+
function wrapLabel(label, maxChars = 12) {
|
|
353
|
+
const str = String(label);
|
|
354
|
+
let rawWords;
|
|
355
|
+
if (str.includes("/")) {
|
|
356
|
+
rawWords = str.split("/").reduce((acc, segment, idx, arr) => {
|
|
357
|
+
const part = idx < arr.length - 1 ? segment + "/" : segment;
|
|
358
|
+
if (part.trim()) acc.push(part.trim());
|
|
359
|
+
return acc;
|
|
360
|
+
}, []);
|
|
361
|
+
} else {
|
|
362
|
+
rawWords = str.split(/\s+/);
|
|
363
|
+
}
|
|
364
|
+
const lines = [];
|
|
365
|
+
let line = "";
|
|
366
|
+
for (const word of rawWords) {
|
|
367
|
+
if (line === "") {
|
|
368
|
+
line = word;
|
|
369
|
+
} else if ((line + " " + word).length <= maxChars) {
|
|
370
|
+
line += " " + word;
|
|
371
|
+
} else {
|
|
372
|
+
lines.push(line);
|
|
373
|
+
line = word;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (line) lines.push(line);
|
|
377
|
+
if (lines.length > 2) {
|
|
378
|
+
const overflow = lines.splice(2).join(" ");
|
|
379
|
+
lines[1] = lines[1] + " " + overflow;
|
|
380
|
+
}
|
|
381
|
+
return lines;
|
|
382
|
+
}
|
|
299
383
|
|
|
300
384
|
// src/Header.jsx
|
|
301
385
|
import React2, { useState as useState3, useRef as useRef2, useEffect as useEffect3 } from "react";
|