| 1 |
( function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var Fragment = wp.element.Fragment; |
| 4 |
var registerBlockType = wp.blocks.registerBlockType; |
| 5 |
var __ = wp.i18n.__; |
| 6 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 7 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 8 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 9 |
var PanelBody = wp.components.PanelBody; |
| 10 |
var RangeControl = wp.components.RangeControl; |
| 11 |
var TextControl = wp.components.TextControl; |
| 12 |
var ToggleControl = wp.components.ToggleControl; |
| 13 |
var Button = wp.components.Button; |
| 14 |
var ColorPicker = wp.components.ColorPicker; |
| 15 |
var Popover = wp.components.Popover; |
| 16 |
var useState = wp.element.useState; |
| 17 |
|
| 18 |
var _gcTC, _gcTV; |
| 19 |
function _tc() { return _gcTC || (_gcTC = window.bkbgTypographyControl); } |
| 20 |
function _tv() { return _gcTV || (_gcTV = window.bkbgTypoCssVars); } |
| 21 |
|
| 22 |
// --- SVG helpers --- |
| 23 |
|
| 24 |
// angle=0 → left (min), angle=180 → right (max), going through top |
| 25 |
function polarToCartesian(cx, cy, r, angleDeg) { |
| 26 |
var rad = (angleDeg * Math.PI) / 180; |
| 27 |
return { |
| 28 |
x: cx - r * Math.cos(rad), |
| 29 |
y: cy - r * Math.sin(rad) |
| 30 |
}; |
| 31 |
} |
| 32 |
|
| 33 |
// Compute layout metrics for the semicircle gauge |
| 34 |
function gaugeMetrics(size, strokeWidth) { |
| 35 |
var W = size; |
| 36 |
var H = Math.round(size / 2 + strokeWidth + 8); |
| 37 |
var cx = W / 2; |
| 38 |
var cy = H - Math.round(strokeWidth / 2) - 4; |
| 39 |
var r = cx - strokeWidth * 1.5 - 2; |
| 40 |
var perimeter = Math.PI * r; |
| 41 |
return { W: W, H: H, cx: cx, cy: cy, r: r, perimeter: perimeter }; |
| 42 |
} |
| 43 |
|
| 44 |
// SVG arc path from left through top to right (counterclockwise in SVG) |
| 45 |
function arcPath(cx, cy, r) { |
| 46 |
return ( |
| 47 |
'M ' + (cx - r) + ' ' + cy + |
| 48 |
' A ' + r + ' ' + r + ' 0 1 0 ' + (cx + r) + ' ' + cy |
| 49 |
); |
| 50 |
} |
| 51 |
|
| 52 |
// Find the zone colour for a given 0-100 percentage |
| 53 |
function zoneColor(zones, pct) { |
| 54 |
var color = '#6c3fb5'; |
| 55 |
for (var i = 0; i < zones.length; i++) { |
| 56 |
if (pct <= zones[i].to) { color = zones[i].color; break; } |
| 57 |
color = zones[i].color; // last zone wins if over max |
| 58 |
} |
| 59 |
return color; |
| 60 |
} |
| 61 |
|
| 62 |
// --- Editor SVG preview (shows static, fully-drawn arc at current value) --- |
| 63 |
function GaugePreview(props) { |
| 64 |
var a = props.attrs; |
| 65 |
var sz = a.size || 260; |
| 66 |
var sw = a.strokeWidth || 18; |
| 67 |
var m = gaugeMetrics(sz, sw); |
| 68 |
var p = arcPath(m.cx, m.cy, m.r); |
| 69 |
var min = a.minValue || 0; |
| 70 |
var max = a.maxValue || 100; |
| 71 |
var f = Math.min(1, Math.max(0, (a.value - min) / (max - min))); |
| 72 |
var pct = f * 100; |
| 73 |
var zones = a.colorZones || []; |
| 74 |
var fillColor = zoneColor(zones, pct); |
| 75 |
var lnfs = (a.typoLabel && a.typoLabel.sizeDesktop) || a.labelFontSize || 14; |
| 76 |
|
| 77 |
var children = []; |
| 78 |
|
| 79 |
// Track |
| 80 |
children.push(el('path', { |
| 81 |
key: 'track', d: p, fill: 'none', |
| 82 |
stroke: a.trackColor || '#e5e7eb', |
| 83 |
strokeWidth: sw, strokeLinecap: 'round' |
| 84 |
})); |
| 85 |
|
| 86 |
// Zone arcs |
| 87 |
zones.forEach(function (zone, zi) { |
| 88 |
var zLen = (zone.to - zone.from) / 100 * m.perimeter; |
| 89 |
var zOff = -(zone.from / 100) * m.perimeter; |
| 90 |
children.push(el('path', { |
| 91 |
key: 'z' + zi, d: p, fill: 'none', stroke: zone.color, |
| 92 |
strokeWidth: sw, strokeLinecap: 'butt', |
| 93 |
strokeDasharray: zLen + ' ' + m.perimeter, |
| 94 |
strokeDashoffset: zOff |
| 95 |
})); |
| 96 |
}); |
| 97 |
|
| 98 |
// Ticks |
| 99 |
if (a.showTicks) { |
| 100 |
var tc = a.tickCount || 10; |
| 101 |
for (var t = 0; t <= tc; t++) { |
| 102 |
var pt1 = polarToCartesian(m.cx, m.cy, m.r - sw / 2 - 2, t / tc * 180); |
| 103 |
var pt2 = polarToCartesian(m.cx, m.cy, m.r + sw / 2 + 2, t / tc * 180); |
| 104 |
children.push(el('line', { |
| 105 |
key: 'tk' + t, |
| 106 |
x1: pt1.x, y1: pt1.y, x2: pt2.x, y2: pt2.y, |
| 107 |
stroke: '#9ca3af', strokeWidth: 1.5 |
| 108 |
})); |
| 109 |
} |
| 110 |
} |
| 111 |
|
| 112 |
// Fill arc (editor: fully drawn to current value) |
| 113 |
children.push(el('path', { |
| 114 |
key: 'fill', d: p, fill: 'none', stroke: fillColor, |
| 115 |
strokeWidth: sw, strokeLinecap: 'round', |
| 116 |
strokeDasharray: m.perimeter + ' ' + m.perimeter, |
| 117 |
strokeDashoffset: (1 - f) * m.perimeter |
| 118 |
})); |
| 119 |
|
| 120 |
// Needle |
| 121 |
if (a.showNeedle) { |
| 122 |
var nTip = polarToCartesian(m.cx, m.cy, m.r - sw - 4, f * 180); |
| 123 |
children.push(el('line', { |
| 124 |
key: 'ndle', |
| 125 |
x1: m.cx, y1: m.cy, x2: nTip.x, y2: nTip.y, |
| 126 |
stroke: a.needleColor || '#374151', |
| 127 |
strokeWidth: 3, strokeLinecap: 'round' |
| 128 |
})); |
| 129 |
children.push(el('circle', { |
| 130 |
key: 'nhub', cx: m.cx, cy: m.cy, |
| 131 |
r: sw / 2, fill: a.needleColor || '#374151' |
| 132 |
})); |
| 133 |
} |
| 134 |
|
| 135 |
// Value |
| 136 |
if (a.showValue !== false) { |
| 137 |
children.push(el('text', { |
| 138 |
key: 'val', |
| 139 |
className: 'bkgc-value-text', |
| 140 |
x: m.cx, |
| 141 |
y: m.cy - (a.showNeedle ? sw + 2 : 0), |
| 142 |
textAnchor: 'middle', |
| 143 |
dominantBaseline: 'auto', |
| 144 |
fill: a.valueColor || '#111827' |
| 145 |
}, a.value + (a.unit || ''))); |
| 146 |
} |
| 147 |
|
| 148 |
// Label |
| 149 |
if (a.showLabel !== false && a.label) { |
| 150 |
children.push(el('text', { |
| 151 |
key: 'lbl', |
| 152 |
className: 'bkgc-label-text', |
| 153 |
x: m.cx, y: m.cy + lnfs + 2, |
| 154 |
textAnchor: 'middle', dominantBaseline: 'hanging', |
| 155 |
fill: a.labelColor || '#6b7280' |
| 156 |
}, a.label)); |
| 157 |
} |
| 158 |
|
| 159 |
return el('svg', { |
| 160 |
viewBox: '0 0 ' + m.W + ' ' + m.H, |
| 161 |
width: m.W, height: m.H, |
| 162 |
style: { display: 'block', overflow: 'visible', margin: '0 auto' } |
| 163 |
}, children); |
| 164 |
} |
| 165 |
|
| 166 |
// --- Register --- |
| 167 |
/* ── colour-swatch + popover ── */ |
| 168 |
function BkbgColorSwatch(p) { |
| 169 |
var st = useState(false), open = st[0], setOpen = st[1]; |
| 170 |
return el('div', { style:{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'4px 0', gap:'8px' } }, |
| 171 |
el('span', { style:{ fontSize:'12px', color:'#1e1e1e', flex:1, lineHeight:1.4 } }, p.label), |
| 172 |
el('div', { style:{ position:'relative', flexShrink:0 } }, |
| 173 |
el('button', { type:'button', title: p.value||'none', onClick: function(){ setOpen(!open); }, |
| 174 |
style:{ width:'28px', height:'28px', borderRadius:'4px', border: open ? '2px solid #007cba' : '2px solid #ddd', cursor:'pointer', padding:0, display:'block', background: p.value||'#ffffff', flexShrink:0 } }), |
| 175 |
open && el(Popover, { position:'bottom left', onClose: function(){ setOpen(false); } }, |
| 176 |
el('div', { style:{ padding:'8px' }, onMouseDown: function(e){ e.stopPropagation(); } }, |
| 177 |
el('div', { style:{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:'6px' } }, |
| 178 |
el('strong', { style:{ fontSize:'12px' } }, p.label), |
| 179 |
el(Button, { icon:'no-alt', isSmall:true, onClick: function(){ setOpen(false); } }) |
| 180 |
), |
| 181 |
el(ColorPicker, { color: p.value, enableAlpha:true, onChange: p.onChange }) |
| 182 |
) |
| 183 |
) |
| 184 |
) |
| 185 |
); |
| 186 |
} |
| 187 |
|
| 188 |
registerBlockType('blockenberg/gauge-chart', { |
| 189 |
|
| 190 |
edit: function (props) { |
| 191 |
var attrs = props.attributes; |
| 192 |
var setAttr = props.setAttributes; |
| 193 |
var zones = attrs.colorZones || []; |
| 194 |
|
| 195 |
function updateZone(idx, key, val) { |
| 196 |
var newZones = zones.map(function (z, i) { |
| 197 |
if (i !== idx) return z; |
| 198 |
var updated = {}; |
| 199 |
Object.keys(z).forEach(function (k) { updated[k] = z[k]; }); |
| 200 |
updated[key] = val; |
| 201 |
return updated; |
| 202 |
}); |
| 203 |
setAttr({ colorZones: newZones }); |
| 204 |
} |
| 205 |
|
| 206 |
function addZone() { |
| 207 |
setAttr({ colorZones: zones.concat([{ from: 0, to: 100, color: '#6c3fb5' }]) }); |
| 208 |
} |
| 209 |
|
| 210 |
function removeZone(idx) { |
| 211 |
setAttr({ colorZones: zones.filter(function (_, i) { return i !== idx; }) }); |
| 212 |
} |
| 213 |
|
| 214 |
var wrapStyle = Object.assign({}, |
| 215 |
attrs.bgColor ? { background: attrs.bgColor } : {}, |
| 216 |
_tv()(attrs.typoValue, '--bkgc-vl-'), |
| 217 |
_tv()(attrs.typoLabel, '--bkgc-lb-') |
| 218 |
); |
| 219 |
var blockProps = useBlockProps({ className: 'bkgc-wrap', style: wrapStyle }); |
| 220 |
|
| 221 |
return el(Fragment, null, |
| 222 |
el(InspectorControls, null, |
| 223 |
|
| 224 |
// ── Value ── |
| 225 |
el(PanelBody, { title: __('Value', 'blockenberg'), initialOpen: true }, |
| 226 |
el(RangeControl, { |
| 227 |
label: __('Value', 'blockenberg'), |
| 228 |
value: attrs.value, min: attrs.minValue, max: attrs.maxValue, |
| 229 |
onChange: function (v) { setAttr({ value: v }); } |
| 230 |
}), |
| 231 |
el(TextControl, { |
| 232 |
label: __('Label', 'blockenberg'), |
| 233 |
value: attrs.label, |
| 234 |
onChange: function (v) { setAttr({ label: v }); } |
| 235 |
}), |
| 236 |
el(TextControl, { |
| 237 |
label: __('Unit', 'blockenberg'), |
| 238 |
value: attrs.unit, |
| 239 |
onChange: function (v) { setAttr({ unit: v }); } |
| 240 |
}), |
| 241 |
el(RangeControl, { |
| 242 |
label: __('Min Value', 'blockenberg'), |
| 243 |
value: attrs.minValue, min: -9999, max: attrs.value - 1, |
| 244 |
onChange: function (v) { setAttr({ minValue: v }); } |
| 245 |
}), |
| 246 |
el(RangeControl, { |
| 247 |
label: __('Max Value', 'blockenberg'), |
| 248 |
value: attrs.maxValue, min: attrs.value + 1, max: 99999, |
| 249 |
onChange: function (v) { setAttr({ maxValue: v }); } |
| 250 |
}) |
| 251 |
), |
| 252 |
|
| 253 |
// ── Color Zones ── |
| 254 |
|
| 255 |
el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false }, |
| 256 |
_tc()({ label: __('Value', 'blockenberg'), value: attrs.typoValue, onChange: function (v) { setAttr({ typoValue: v }); } }), |
| 257 |
_tc()({ label: __('Label', 'blockenberg'), value: attrs.typoLabel, onChange: function (v) { setAttr({ typoLabel: v }); } }) |
| 258 |
), |
| 259 |
el(PanelBody, { title: __('Color Zones', 'blockenberg'), initialOpen: false }, |
| 260 |
zones.map(function (zone, idx) { |
| 261 |
return el(PanelBody, { |
| 262 |
key: 'zone-' + idx, |
| 263 |
title: __('Zone', 'blockenberg') + ' ' + (idx + 1), |
| 264 |
initialOpen: idx === 0 |
| 265 |
}, |
| 266 |
el(RangeControl, { |
| 267 |
label: __('From (%)', 'blockenberg'), |
| 268 |
value: zone.from, min: 0, max: 99, |
| 269 |
onChange: function (v) { updateZone(idx, 'from', v); } |
| 270 |
}), |
| 271 |
el(RangeControl, { |
| 272 |
label: __('To (%)', 'blockenberg'), |
| 273 |
value: zone.to, min: 1, max: 100, |
| 274 |
onChange: function (v) { updateZone(idx, 'to', v); } |
| 275 |
}), |
| 276 |
el(BkbgColorSwatch, { |
| 277 |
label: __('Color', 'blockenberg'), |
| 278 |
value: zone.color, |
| 279 |
onChange: function (v) { updateZone(idx, 'color', v); } |
| 280 |
}), |
| 281 |
zones.length > 1 && el(Button, { |
| 282 |
variant: 'secondary', |
| 283 |
isDestructive: true, |
| 284 |
onClick: function () { removeZone(idx); } |
| 285 |
}, __('Remove Zone', 'blockenberg')) |
| 286 |
); |
| 287 |
}), |
| 288 |
el(Button, { |
| 289 |
variant: 'secondary', |
| 290 |
style: { marginTop: '8px' }, |
| 291 |
onClick: addZone |
| 292 |
}, __('+ Add Zone', 'blockenberg')) |
| 293 |
), |
| 294 |
|
| 295 |
// ── Visual ── |
| 296 |
el(PanelBody, { title: __('Visual', 'blockenberg'), initialOpen: false }, |
| 297 |
el(RangeControl, { |
| 298 |
label: __('Size (px)', 'blockenberg'), |
| 299 |
value: attrs.size, min: 100, max: 600, |
| 300 |
onChange: function (v) { setAttr({ size: v }); } |
| 301 |
}), |
| 302 |
el(RangeControl, { |
| 303 |
label: __('Stroke Width', 'blockenberg'), |
| 304 |
value: attrs.strokeWidth, min: 4, max: 50, |
| 305 |
onChange: function (v) { setAttr({ strokeWidth: v }); } |
| 306 |
}), |
| 307 |
el(ToggleControl, { |
| 308 |
label: __('Show Needle', 'blockenberg'), |
| 309 |
checked: attrs.showNeedle, |
| 310 |
onChange: function (v) { setAttr({ showNeedle: v }); }, |
| 311 |
__nextHasNoMarginBottom: true |
| 312 |
}), |
| 313 |
el(ToggleControl, { |
| 314 |
label: __('Show Value', 'blockenberg'), |
| 315 |
checked: attrs.showValue, |
| 316 |
onChange: function (v) { setAttr({ showValue: v }); }, |
| 317 |
__nextHasNoMarginBottom: true |
| 318 |
}), |
| 319 |
el(ToggleControl, { |
| 320 |
label: __('Show Label', 'blockenberg'), |
| 321 |
checked: attrs.showLabel, |
| 322 |
onChange: function (v) { setAttr({ showLabel: v }); }, |
| 323 |
__nextHasNoMarginBottom: true |
| 324 |
}), |
| 325 |
el(ToggleControl, { |
| 326 |
label: __('Show Tick Marks', 'blockenberg'), |
| 327 |
checked: attrs.showTicks, |
| 328 |
onChange: function (v) { setAttr({ showTicks: v }); }, |
| 329 |
__nextHasNoMarginBottom: true |
| 330 |
}), |
| 331 |
attrs.showTicks && el(RangeControl, { |
| 332 |
label: __('Tick Count', 'blockenberg'), |
| 333 |
value: attrs.tickCount, min: 2, max: 20, |
| 334 |
onChange: function (v) { setAttr({ tickCount: v }); } |
| 335 |
}), |
| 336 |
), |
| 337 |
|
| 338 |
// ── Animation ── |
| 339 |
el(PanelBody, { title: __('Animation', 'blockenberg'), initialOpen: false }, |
| 340 |
el(RangeControl, { |
| 341 |
label: __('Animate Duration (ms)', 'blockenberg'), |
| 342 |
value: attrs.animateDuration, min: 200, max: 5000, step: 100, |
| 343 |
onChange: function (v) { setAttr({ animateDuration: v }); } |
| 344 |
}) |
| 345 |
), |
| 346 |
|
| 347 |
// ── Colors ── |
| 348 |
el(PanelColorSettings, { |
| 349 |
title: __('Colors', 'blockenberg'), |
| 350 |
initialOpen: false, |
| 351 |
colorSettings: [ |
| 352 |
{ label: __('Track Color', 'blockenberg'), value: attrs.trackColor, onChange: function (v) { setAttr({ trackColor: v || '#e5e7eb' }); } }, |
| 353 |
{ label: __('Value Color', 'blockenberg'), value: attrs.valueColor, onChange: function (v) { setAttr({ valueColor: v || '#111827' }); } }, |
| 354 |
{ label: __('Label Color', 'blockenberg'), value: attrs.labelColor, onChange: function (v) { setAttr({ labelColor: v || '#6b7280' }); } }, |
| 355 |
{ label: __('Needle Color', 'blockenberg'), value: attrs.needleColor, onChange: function (v) { setAttr({ needleColor: v || '#374151' }); } }, |
| 356 |
{ label: __('Background', 'blockenberg'), value: attrs.bgColor, onChange: function (v) { setAttr({ bgColor: v || '' }); } } |
| 357 |
] |
| 358 |
}) |
| 359 |
), |
| 360 |
|
| 361 |
el('div', blockProps, |
| 362 |
el(GaugePreview, { attrs: attrs }) |
| 363 |
) |
| 364 |
); |
| 365 |
}, |
| 366 |
|
| 367 |
save: function (props) { |
| 368 |
var a = props.attributes; |
| 369 |
var sw = a.strokeWidth; |
| 370 |
var m = gaugeMetrics(a.size, sw); |
| 371 |
var p = arcPath(m.cx, m.cy, m.r); |
| 372 |
var min = a.minValue; |
| 373 |
var max = a.maxValue; |
| 374 |
var zones = a.colorZones || []; |
| 375 |
var valPct = Math.min(100, Math.max(0, (a.value - min) / (max - min) * 100)); |
| 376 |
var fillColor = zoneColor(zones, valPct); |
| 377 |
var lnfs = (a.typoLabel && a.typoLabel.sizeDesktop) || a.labelFontSize || 14; |
| 378 |
|
| 379 |
var wrapStyle = Object.assign({}, |
| 380 |
a.bgColor ? { background: a.bgColor } : {}, |
| 381 |
_tv()(a.typoValue, '--bkgc-vl-'), |
| 382 |
_tv()(a.typoLabel, '--bkgc-lb-') |
| 383 |
); |
| 384 |
|
| 385 |
var blockProps = wp.blockEditor.useBlockProps.save({ |
| 386 |
className: 'bkgc-wrap', |
| 387 |
style: wrapStyle, |
| 388 |
'data-value': a.value, |
| 389 |
'data-min': min, |
| 390 |
'data-max': max, |
| 391 |
'data-duration': a.animateDuration, |
| 392 |
'data-perimeter': m.perimeter, |
| 393 |
'data-unit': a.unit, |
| 394 |
'data-show-needle': a.showNeedle ? '1' : '0', |
| 395 |
'data-r': m.r, |
| 396 |
'data-cx': m.cx, |
| 397 |
'data-cy': m.cy, |
| 398 |
'data-needle-color': a.needleColor || '#374151', |
| 399 |
'data-fill-color': fillColor |
| 400 |
}); |
| 401 |
|
| 402 |
var svgChildren = []; |
| 403 |
|
| 404 |
// Track |
| 405 |
svgChildren.push(el('path', { |
| 406 |
key: 'track', d: p, fill: 'none', |
| 407 |
stroke: a.trackColor || '#e5e7eb', |
| 408 |
strokeWidth: sw, strokeLinecap: 'round' |
| 409 |
})); |
| 410 |
|
| 411 |
// Zone arcs |
| 412 |
zones.forEach(function (zone, zi) { |
| 413 |
var zLen = (zone.to - zone.from) / 100 * m.perimeter; |
| 414 |
var zOff = -(zone.from / 100) * m.perimeter; |
| 415 |
svgChildren.push(el('path', { |
| 416 |
key: 'z' + zi, d: p, fill: 'none', stroke: zone.color, |
| 417 |
strokeWidth: sw, strokeLinecap: 'butt', |
| 418 |
strokeDasharray: zLen + ' ' + m.perimeter, |
| 419 |
strokeDashoffset: zOff |
| 420 |
})); |
| 421 |
}); |
| 422 |
|
| 423 |
// Ticks |
| 424 |
if (a.showTicks) { |
| 425 |
for (var t = 0; t <= a.tickCount; t++) { |
| 426 |
var pt1 = polarToCartesian(m.cx, m.cy, m.r - sw / 2 - 2, t / a.tickCount * 180); |
| 427 |
var pt2 = polarToCartesian(m.cx, m.cy, m.r + sw / 2 + 2, t / a.tickCount * 180); |
| 428 |
svgChildren.push(el('line', { |
| 429 |
key: 'tk' + t, |
| 430 |
x1: pt1.x, y1: pt1.y, x2: pt2.x, y2: pt2.y, |
| 431 |
stroke: '#9ca3af', strokeWidth: 1.5 |
| 432 |
})); |
| 433 |
} |
| 434 |
} |
| 435 |
|
| 436 |
// Fill arc — starts empty (dashoffset = perimeter), JS animates it |
| 437 |
svgChildren.push(el('path', { |
| 438 |
key: 'fill', |
| 439 |
className: 'bkgc-fill', |
| 440 |
d: p, fill: 'none', stroke: fillColor, |
| 441 |
strokeWidth: sw, strokeLinecap: 'round', |
| 442 |
strokeDasharray: m.perimeter + ' ' + m.perimeter, |
| 443 |
strokeDashoffset: m.perimeter |
| 444 |
})); |
| 445 |
|
| 446 |
// Needle pivot at min position (angle=0 = left) |
| 447 |
if (a.showNeedle) { |
| 448 |
var nBase = polarToCartesian(m.cx, m.cy, m.r - sw - 4, 0); |
| 449 |
svgChildren.push(el('line', { |
| 450 |
key: 'ndle', className: 'bkgc-needle', |
| 451 |
x1: m.cx, y1: m.cy, x2: nBase.x, y2: nBase.y, |
| 452 |
stroke: a.needleColor || '#374151', |
| 453 |
strokeWidth: 3, strokeLinecap: 'round' |
| 454 |
})); |
| 455 |
svgChildren.push(el('circle', { |
| 456 |
key: 'nhub', cx: m.cx, cy: m.cy, |
| 457 |
r: sw / 2, fill: a.needleColor || '#374151' |
| 458 |
})); |
| 459 |
} |
| 460 |
|
| 461 |
// Value text — starts at 0, JS counts up |
| 462 |
if (a.showValue) { |
| 463 |
svgChildren.push(el('text', { |
| 464 |
key: 'val', |
| 465 |
className: 'bkgc-value-text', |
| 466 |
x: m.cx, |
| 467 |
y: m.cy - (a.showNeedle ? sw + 2 : 0), |
| 468 |
textAnchor: 'middle', |
| 469 |
dominantBaseline: 'auto', |
| 470 |
fill: a.valueColor || '#111827' |
| 471 |
}, '0' + (a.unit || ''))); |
| 472 |
} |
| 473 |
|
| 474 |
// Label |
| 475 |
if (a.showLabel && a.label) { |
| 476 |
svgChildren.push(el('text', { |
| 477 |
key: 'lbl', |
| 478 |
className: 'bkgc-label-text', |
| 479 |
x: m.cx, y: m.cy + lnfs + 2, |
| 480 |
textAnchor: 'middle', dominantBaseline: 'hanging', |
| 481 |
fill: a.labelColor || '#6b7280' |
| 482 |
}, a.label)); |
| 483 |
} |
| 484 |
|
| 485 |
return el('div', blockProps, |
| 486 |
el('svg', { |
| 487 |
viewBox: '0 0 ' + m.W + ' ' + m.H, |
| 488 |
width: m.W, height: m.H, |
| 489 |
style: { display: 'block', margin: '0 auto', overflow: 'visible' } |
| 490 |
}, svgChildren) |
| 491 |
); |
| 492 |
} |
| 493 |
}); |
| 494 |
}() ); |
| 495 |
|