232 lines
12 KiB
Plaintext
232 lines
12 KiB
Plaintext
#load "../../lib/app.uce"
|
|
|
|
COMPONENT:PROGRESSBAR(Request& context)
|
|
{
|
|
starter_register_js("components/gauges/common.js", context);
|
|
starter_register_css("themes/common/css/gauges.css", context);
|
|
|
|
String gauge_id = first(context.call["id"].to_string(), "progressbar-" + std::to_string((u64)time()));
|
|
String layout = first(context.call["layout"].to_string(), "horizontal");
|
|
String style = context.call["style"].to_string();
|
|
String item_style = context.call["item-style"].to_string();
|
|
String value_style = context.call["value-style"].to_string();
|
|
String bar_style = context.call["bar-style"].to_string();
|
|
String title = context.call["title"].to_string();
|
|
String subtitle = context.call["subtitle"].to_string();
|
|
|
|
<>
|
|
<section class="gauge-set progressbar-set progressbar-set-<?= layout ?>" id="<?= gauge_id ?>" style="<?= style ?>">
|
|
<? if(title != "") { ?>
|
|
<div class="gauge-set-header">
|
|
<h3><?= title ?></h3>
|
|
<? if(subtitle != "") { ?><p><?= subtitle ?></p><? } ?>
|
|
</div>
|
|
<? } ?>
|
|
<? if(layout == "horizontal") { ?>
|
|
<div class="progressbar-grid progressbar-grid-horizontal">
|
|
<? context.call["items"].each([&](DTree bar, String bar_id) {
|
|
DTree merged = context.call["scale"];
|
|
bar.each([&](DTree item, String key) { merged[key] = item; });
|
|
String label = first(merged["label"].to_string(), bar_id);
|
|
String tooltip = merged["tooltip"].to_string();
|
|
String unit = merged["unit"].to_string();
|
|
f64 min_value = atof(first(merged["min"].to_string(), "0").c_str());
|
|
f64 max_value = atof(first(merged["max"].to_string(), "100").c_str());
|
|
f64 value = atof(first(merged["value"].to_string(), "0").c_str());
|
|
f64 vrange = max_value - min_value;
|
|
if(vrange == 0) vrange = 1;
|
|
s32 pct = (s32)std::max(0.0, std::min(100.0, ((value - min_value) / vrange) * 100.0));
|
|
String color = first(merged["color"].to_string(), "var(--primary)");
|
|
?><section class="gauge-card progressbar-card progressbar-card-horizontal" title="<?= tooltip ?>" style="<?= item_style ?>">
|
|
<div class="progressbar-card-head">
|
|
<div class="gauge-metric-label progressbar-label"><?= label ?></div>
|
|
<div class="gauge-metric-value progressbar-value" style="<?= value_style ?>" id="<?= gauge_id ?>-<?= bar_id ?>-value"><?= merged["value"].to_string() + unit ?></div>
|
|
</div>
|
|
<div class="progressbar-background progressbar-background-horizontal">
|
|
<div class="progressbar-bar" id="<?= gauge_id ?>-<?= bar_id ?>-bar" style="background-color: <?= color ?>; <?= bar_style ?> width: <?= std::to_string(pct) ?>%;"></div>
|
|
</div>
|
|
<? if(tooltip != "") { ?><div class="gauge-metric-meta progressbar-meta"><?= tooltip ?></div><? } ?>
|
|
</section><?
|
|
}); ?>
|
|
</div>
|
|
<? } else { ?>
|
|
<div class="progressbar-grid progressbar-grid-vertical" style="--progressbar-height: <?= first(context.call["height"].to_string(), "240") ?>px;">
|
|
<? context.call["items"].each([&](DTree bar, String bar_id) {
|
|
DTree merged = context.call["scale"];
|
|
bar.each([&](DTree item, String key) { merged[key] = item; });
|
|
String label = first(merged["label"].to_string(), bar_id);
|
|
String tooltip = merged["tooltip"].to_string();
|
|
String unit = merged["unit"].to_string();
|
|
f64 min_value = atof(first(merged["min"].to_string(), "0").c_str());
|
|
f64 max_value = atof(first(merged["max"].to_string(), "100").c_str());
|
|
f64 value = atof(first(merged["value"].to_string(), "0").c_str());
|
|
f64 vrange = max_value - min_value;
|
|
if(vrange == 0) vrange = 1;
|
|
s32 pct = (s32)std::max(0.0, std::min(100.0, ((value - min_value) / vrange) * 100.0));
|
|
String color = first(merged["color"].to_string(), "var(--primary)");
|
|
?><section class="gauge-card progressbar-card progressbar-card-vertical" title="<?= tooltip ?>" style="<?= item_style ?>">
|
|
<div class="gauge-metric-label progressbar-label"><?= label ?></div>
|
|
<div class="progressbar-background progressbar-background-vertical">
|
|
<div class="progressbar-bar" id="<?= gauge_id ?>-<?= bar_id ?>-bar" style="background-color: <?= color ?>; <?= bar_style ?> height: <?= std::to_string(pct) ?>%;"></div>
|
|
</div>
|
|
<div class="gauge-metric-value progressbar-value" style="<?= value_style ?>" id="<?= gauge_id ?>-<?= bar_id ?>-value"><?= merged["value"].to_string() + unit ?></div>
|
|
<? if(tooltip != "") { ?><div class="gauge-metric-meta progressbar-meta"><?= tooltip ?></div><? } ?>
|
|
</section><?
|
|
}); ?>
|
|
</div>
|
|
<? } ?>
|
|
</section>
|
|
<? if(context.call["listen"].to_string() != "") { ?>
|
|
<script>
|
|
window.ProgressbarComponents = window.ProgressbarComponents || {
|
|
start_listen : function(prop) {
|
|
$.events.on('value-broadcast', function(data) {
|
|
if(!prop.items || !prop.items[data.name]) return;
|
|
let bar = Object.assign({}, prop.scale || {}, prop.items[data.name]);
|
|
let vrange = (Number(bar.max || 100) - Number(bar.min || 0));
|
|
if (!vrange) vrange = 1;
|
|
let pct = Math.min(100, Math.max(0, (Number(data.value) - Number(bar.min || 0)) / vrange * 100));
|
|
let barEl = document.getElementById(prop.id + '-' + data.name + '-bar');
|
|
let valueEl = document.getElementById(prop.id + '-' + data.name + '-value');
|
|
if (valueEl) valueEl.textContent = data.value + (bar.unit || '');
|
|
if (barEl) {
|
|
if (prop.layout === 'vertical') barEl.style.height = pct + '%';
|
|
else barEl.style.width = pct + '%';
|
|
}
|
|
});
|
|
}
|
|
};
|
|
ProgressbarComponents.start_listen(<?: json_encode(context.call) ?>);
|
|
</script>
|
|
<? } ?>
|
|
</>
|
|
}
|
|
|
|
COMPONENT:NEEDLEGAUGE(Request& context)
|
|
{
|
|
starter_register_css("themes/common/css/gauges.css", context);
|
|
String gauge_id = first(context.call["id"].to_string(), "needlegauge-" + std::to_string((u64)time()));
|
|
String style = context.call["style"].to_string();
|
|
String title = context.call["title"].to_string();
|
|
String subtitle = context.call["subtitle"].to_string();
|
|
s32 size = (s32)int_val(first(context.call["size"].to_string(), "200"));
|
|
|
|
<>
|
|
<section class="gauge-set needlegauge-set" id="<?= gauge_id ?>" style="<?= style ?>">
|
|
<? if(title != "") { ?><div class="gauge-set-header"><h3><?= title ?></h3><? if(subtitle != "") { ?><p><?= subtitle ?></p><? } ?></div><? } ?>
|
|
<div class="needlegauge-grid">
|
|
<? context.call["items"].each([&](DTree item, String item_id) {
|
|
String label = first(item["label"].to_string(), item_id);
|
|
String tooltip = item["tooltip"].to_string();
|
|
String unit = item["unit"].to_string();
|
|
f64 min_value = atof(first(item["min"].to_string(), "0").c_str());
|
|
f64 max_value = atof(first(item["max"].to_string(), "100").c_str());
|
|
f64 value = atof(first(item["value"].to_string(), "0").c_str());
|
|
f64 pct = (value - min_value) / (max_value - min_value == 0 ? 1.0 : (max_value - min_value));
|
|
pct = std::max(0.0, std::min(1.0, pct));
|
|
f64 angle = -2.6 + pct * 2.2;
|
|
?><section class="gauge-card needlegauge-card">
|
|
<div class="gauge-metric-label needlegauge-label-head"><?= label ?></div>
|
|
<div class="needlegauge-visual">
|
|
<svg width="<?= std::to_string(size) ?>" height="<?= std::to_string(size / 1.8) ?>" viewBox="0 0 200 120" class="needlegauge-svg">
|
|
<path d="M 20 100 A 80 80 0 0 1 180 100" fill="none" stroke='var(--border)' stroke-width="10" opacity="0.3"/>
|
|
<line id="<?= gauge_id ?>-<?= item_id ?>-needle" class="needle" x1="100" y1="100" x2="40" y2="100" stroke='var(--primary)' stroke-width="4" stroke-linecap="round" style="transform-origin: 100px 100px; transform: rotate(<?= std::to_string(angle) ?>rad); transition: transform 0.3s ease;"/>
|
|
<circle cx="100" cy="100" r="7" fill='var(--primary)'/>
|
|
</svg>
|
|
</div>
|
|
<div class="needlegauge-info">
|
|
<div class="gauge-metric-value needlegauge-value" id="<?= gauge_id ?>-<?= item_id ?>-value"><?= item["value"].to_string() + unit ?></div>
|
|
<? if(tooltip != "") { ?><div class="gauge-metric-meta needlegauge-meta"><?= tooltip ?></div><? } ?>
|
|
</div>
|
|
</section><?
|
|
}); ?>
|
|
</div>
|
|
</section>
|
|
<? if(context.call["listen"].to_string() != "") { ?>
|
|
<script>
|
|
window.NeedlegaugeComponents = window.NeedlegaugeComponents || {
|
|
start_listen : function(prop) {
|
|
$.events.on('value-broadcast', function(data) {
|
|
if(!prop.items || !prop.items[data.name]) return;
|
|
let item = Object.assign({}, prop.scale || {}, prop.items[data.name]);
|
|
let min = Number(item.min || 0);
|
|
let max = Number(item.max || 100);
|
|
let pct = (Number(data.value) - min) / ((max - min) || 1);
|
|
pct = Math.min(1, Math.max(0, pct));
|
|
let angle = -2.6 + pct * 2.2;
|
|
let needle = document.getElementById(prop.id + '-' + data.name + '-needle');
|
|
let valueEl = document.getElementById(prop.id + '-' + data.name + '-value');
|
|
if (needle) needle.style.transform = 'rotate(' + angle + 'rad)';
|
|
if (valueEl) valueEl.textContent = data.value + (item.unit || '');
|
|
});
|
|
}
|
|
};
|
|
NeedlegaugeComponents.start_listen(<?= json_encode(context.call) ?>);
|
|
</script>
|
|
<? } ?>
|
|
</>
|
|
}
|
|
|
|
COMPONENT:ARCGAUGE(Request& context)
|
|
{
|
|
starter_register_js("components/gauges/common.js", context);
|
|
starter_register_css("themes/common/css/gauges.css", context);
|
|
String gauge_id = first(context.call["id"].to_string(), "arcgauge-" + std::to_string((u64)time()));
|
|
String title = context.call["title"].to_string();
|
|
String subtitle = context.call["subtitle"].to_string();
|
|
String style = context.call["style"].to_string();
|
|
|
|
<>
|
|
<div class="arcgauge-set" id="<?= gauge_id ?>" style="<?= style ?>">
|
|
<? if(title != "") { ?><div class="arcgauge-set-header"><h3><?= title ?></h3><? if(subtitle != "") { ?><p><?= subtitle ?></p><? } ?></div><? } ?>
|
|
<div class="arcgauge-grid">
|
|
<? context.call["items"].each([&](DTree item, String item_id) {
|
|
f64 value = atof(first(item["value"].to_string(), "0").c_str());
|
|
f64 max_value = atof(first(item["max"].to_string(), "100").c_str());
|
|
s32 precision = (s32)int_val(first(item["precision"].to_string(), "1"));
|
|
f64 pct = max_value > 0.0 ? std::max(0.0, std::min(100.0, (value / max_value) * 100.0)) : 0.0;
|
|
f64 arc_length = (pct / 100.0) * 157.08;
|
|
char buf[64];
|
|
snprintf(buf, sizeof(buf), ("%." + std::to_string(precision) + "f").c_str(), value);
|
|
?><section class="arcgauge-card">
|
|
<div class="arcgauge-label"><?= first(item["label"].to_string(), item_id) ?></div>
|
|
<svg class="arcgauge-svg" viewBox="0 0 120 68" aria-hidden="true">
|
|
<path class="arcgauge-track" d="M 10 60 A 50 50 0 0 1 110 60" fill="none" stroke-width="5" stroke-linecap="round"/>
|
|
<path id="<?= gauge_id ?>-<?= item_id ?>-arc" class="arcgauge-arc-dyn" d="M 10 60 A 50 50 0 0 1 110 60" fill="none" stroke='var(--success, #10b981)' stroke-width="5" stroke-linecap="round" stroke-dasharray="<?= std::to_string(arc_length) ?> 157.08"/>
|
|
<text id="<?= gauge_id ?>-<?= item_id ?>-text" class="arcgauge-value" x="60" y="47" text-anchor="middle"><?= String(buf) + item["unit"].to_string() ?></text>
|
|
<text class="arcgauge-caption" x="60" y="62" text-anchor="middle"><?= first(item["caption"].to_string(), "") ?></text>
|
|
</svg>
|
|
<div class="arcgauge-meta" id="<?= gauge_id ?>-<?= item_id ?>-meta"><?= first(item["meta"].to_string(), "--") ?></div>
|
|
</section><?
|
|
}); ?>
|
|
</div>
|
|
</div>
|
|
<? if(context.call["listen"].to_string() != "") { ?>
|
|
<script>
|
|
window.ArcgaugeComponents = window.ArcgaugeComponents || {
|
|
start_listen : function(prop) {
|
|
$.events.on('value-broadcast', function(data) {
|
|
if(!prop.items || !prop.items[data.name]) return;
|
|
const item = Object.assign({}, prop.items[data.name]);
|
|
if (typeof GaugeComponents !== 'undefined') {
|
|
GaugeComponents.updateArcGauge({
|
|
arcId: prop.id + '-' + data.name + '-arc',
|
|
textId: prop.id + '-' + data.name + '-text',
|
|
metaId: prop.id + '-' + data.name + '-meta',
|
|
value: Number(data.value),
|
|
max: Number(item.max || 100),
|
|
suffix: item.unit || '',
|
|
precision: item.precision,
|
|
color: item.color,
|
|
meta: data.meta != null ? data.meta : null
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
ArcgaugeComponents.start_listen(<?= json_encode(context.call) ?>);
|
|
</script>
|
|
<? } ?>
|
|
</>
|
|
}
|