174 lines
7.0 KiB
PHP
Executable File
174 lines
7.0 KiB
PHP
Executable File
<script>
|
|
|
|
window.NeedlegaugeComponents = window.NeedlegaugeComponents || {
|
|
|
|
start_listen : function(prop) {
|
|
$.events.on('value-broadcast', function(data) {
|
|
if(prop.items[data.name]) {
|
|
// update value text
|
|
let item = Object.assign({}, prop.scale, prop.items[data.name]);
|
|
$('#' + prop.id + '-' + data.name + '-value').text(data.value + (item.unit || ''));
|
|
let vrange = (item.max || 100) - (item.min || 0);
|
|
let pct_value = GaugeComponents.clampValue((data.value - (item.min || 0)) / vrange, 0, 1);
|
|
let angle = -Math.PI + item.angle_start + (pct_value * (item.angle_end - item.angle_start));
|
|
$('#' + prop.id + '-' + data.name + '-needle').css('transform', 'rotate(' + angle + 'rad)');
|
|
|
|
}
|
|
});
|
|
},
|
|
|
|
}
|
|
|
|
</script><?php
|
|
|
|
include_js('components/gauges/common.js');
|
|
include_css('themes/common/css/gauges.css');
|
|
|
|
return [
|
|
|
|
'render' => function($prop) {
|
|
$prop['id'] = !empty($prop['id']) ? $prop['id'] : 'needlegauge-' . uniqid();
|
|
$prop['style'] = (string)($prop['style'] ?? '');
|
|
$prop['items'] = (array)($prop['items'] ?? array());
|
|
$prop['scale'] = (array)($prop['scale'] ?? array());
|
|
$prop['size'] = first($prop['size'] ?? false, 200);
|
|
$prop['subtitle'] = (string)($prop['subtitle'] ?? '');
|
|
$prop['scale']['angle_start'] = first($prop['scale']['angle_start'], -pi());
|
|
$prop['scale']['angle_end'] = first($prop['scale']['angle_end'], 0);
|
|
$prop['img_height'] = first($prop['img_height'] ?? false,
|
|
$prop['size'] * max(cos(first($prop['scale']['angle_start'], -pi())), cos(first($prop['scale']['angle_end'], 0))));
|
|
?>
|
|
<section class="gauge-set needlegauge-set" id="<?= asafe($prop['id']) ?>" style="<?= asafe($prop['style']) ?>">
|
|
<?php if(isset($prop['title'])) { ?>
|
|
<div class="gauge-set-header">
|
|
<h3><?= safe($prop['title']) ?></h3>
|
|
<?php if($prop['subtitle'] !== '') { ?><p><?= safe($prop['subtitle']) ?></p><?php } ?>
|
|
</div>
|
|
<?php } ?>
|
|
<div class="needlegauge-grid">
|
|
<?php
|
|
foreach($prop['items'] as $item_id => $item)
|
|
{
|
|
$item = array_merge($prop['scale'], $item);
|
|
$item['min'] = first($item['min'] ?? false, 0);
|
|
$item['max'] = first($item['max'] ?? false, 100);
|
|
$item['tooltip'] = (string)($item['tooltip'] ?? '');
|
|
$item['unit'] = (string)($item['unit'] ?? '');
|
|
$item['color'] = $item['color'] ?? false;
|
|
$item['label'] = (string)first($item['label'] ?? false, ucfirst((string)$item_id));
|
|
$vrange = ($item['max'] - $item['min']);
|
|
$pct_value = clamp(($item['value'] - $item['min']) / $vrange, 0, 1);
|
|
$needle_angle = -pi() + $item['angle_start'] + ($pct_value * ($item['angle_end'] - $item['angle_start']));
|
|
$needle_color = first($item['color'] ?? false, '#888888');
|
|
if(is_array($item['color'])) {
|
|
$color_entry = pick_entry_from_range($item['color'], $item['value']);
|
|
$needle_color = first($color_entry['color'] ?? false, '#888888');
|
|
}
|
|
$tick_interval = first($item['ticks-every'], $vrange / 20);
|
|
$label_interval = first($item['value-labels-every'], $vrange / 4);
|
|
$tick_number = 0;
|
|
$ticks_html = '';
|
|
$min_angle = first($item['angle_start']);
|
|
$max_angle = first($item['angle_end']);
|
|
$tick_color = first($item['tick-color'], '#888888');
|
|
|
|
for($v = $item['min']; $v <= $item['max']; $v += $tick_interval)
|
|
{
|
|
$tick_number++;
|
|
$angle = $min_angle + (($v-$item['min'])/$vrange) * ($max_angle - $min_angle);
|
|
|
|
$x1 = $prop['size']/2 + cos($angle) * $prop['size']*0.38;
|
|
$y1 = $prop['size']/2 + sin($angle) * $prop['size']*0.38;
|
|
$x2 = $prop['size']/2 + cos($angle) * $prop['size']*0.41;
|
|
$y2 = $prop['size']/2 + sin($angle) * $prop['size']*0.41;
|
|
|
|
$ticks_html .= '<line x1="'.($x1).'" y1="'.($y1).'" x2="'.($x2).'" y2="'.($y2).'"
|
|
stroke="'. $tick_color .'" stroke-width="1"/>';
|
|
|
|
}
|
|
|
|
for($v = $item['min']; $v <= $item['max']; $v += $label_interval)
|
|
{
|
|
$tick_number++;
|
|
$angle = $min_angle + (($v-$item['min'])/$vrange) * ($max_angle - $min_angle);
|
|
|
|
$x1 = $prop['size']/2 + cos($angle) * $prop['size']*0.35;
|
|
$y1 = $prop['size']/2 + sin($angle) * $prop['size']*0.35;
|
|
$x2 = $prop['size']/2 + cos($angle) * $prop['size']*0.41;
|
|
$y2 = $prop['size']/2 + sin($angle) * $prop['size']*0.41;
|
|
|
|
$ticks_html .= '<line x1="'.($x1).'" y1="'.($y1).'" x2="'.($x2).'" y2="'.($y2).'"
|
|
stroke="'. $tick_color .'" stroke-width="3"/>';
|
|
|
|
$lx = $prop['size']/2 + cos($angle) * $prop['size']*0.45;
|
|
$ly = $prop['size']/2 + sin($angle) * $prop['size']*0.45;
|
|
$ticks_html .= '<text x="'.($lx).'" y="'.($ly).'" text-anchor="middle" dominant-baseline="central"
|
|
font-size="10" fill="'. $tick_color .'">'.($v == 0 ? '0' : $v).'</text>';
|
|
}
|
|
|
|
?>
|
|
<section class="gauge-card needlegauge-card">
|
|
<div class="gauge-metric-label needlegauge-label-head"><?= safe($item['label']) ?></div>
|
|
|
|
<div class="needlegauge-visual">
|
|
<svg id="<?= $prop['id'] ?>-<?= $item_id ?>-svg" width="<?= $prop['size'] ?>" height="<?= $prop['img_height'] ?>" class="needlegauge-svg"
|
|
viewBox="0 0 <?= $prop['size'] ?> <?= $prop['img_height'] ?>">
|
|
|
|
<?php
|
|
if(is_array($item['color']))
|
|
{
|
|
foreach($item['color'] as $range)
|
|
{
|
|
$angle_from = $min_angle + ((max($range['from'], $item['min']) - $item['min']) / $vrange) * ($max_angle - $min_angle);
|
|
$angle_to = $min_angle + ((min($range['to'], $item['max']) - $item['min']) / $vrange) * ($max_angle - $min_angle);
|
|
$color = $range['color'] ?? 'rgba(120,120,120,0.5)';
|
|
SVG::circle_segment($prop['size']/2, $prop['size']/2, $prop['size']*0.4,
|
|
$angle_from, $angle_to, $color, 8, 'rgba(0,0,0,0)', 'opacity:0.25');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SVG::circle_segment($prop['size']/2, $prop['size']/2, $prop['size']*0.4,
|
|
$min_angle, $max_angle, $tick_color, 8, 'rgba(0,0,0,0)', 'opacity:0.25');
|
|
}
|
|
?>
|
|
|
|
<g class="ticks">
|
|
<?= $ticks_html ?>
|
|
</g>
|
|
|
|
<line id="<?= $prop['id'] ?>-<?= $item_id ?>-needle" class="needle"
|
|
x1="<?= $prop['size']*0.55 ?>" y1="<?= $prop['size']*0.5 ?>" x2="<?= $prop['size']*0.1 ?>" y2="<?= $prop['size']*0.5 ?>"
|
|
stroke="<?= ($needle_color) ?>" stroke-width="3" stroke-linecap="round"
|
|
style="transform-origin: <?= $prop['size']/2 ?>px <?= $prop['size']/2 ?>px;
|
|
transform: rotate(<?= ($needle_angle) ?>rad); transition: transform 0.3s ease;"/>
|
|
|
|
<circle cx="<?= $prop['size']/2 ?>" cy="<?= $prop['size']/2 ?>" r="6" fill="<?= $needle_color ?>"/>
|
|
|
|
</svg>
|
|
</div>
|
|
|
|
<div class="needlegauge-info">
|
|
<div class="gauge-metric-value needlegauge-value" id="<?= $prop['id'] ?>-<?= $item_id ?>-value"
|
|
title="<?= asafe($item['tooltip']) ?>">
|
|
<?= safe($item['value']) ?><?= safe($item['unit']) ?>
|
|
</div>
|
|
<?php if($item['tooltip'] !== '') { ?><div class="gauge-metric-meta needlegauge-meta"><?= safe($item['tooltip']) ?></div><?php } ?>
|
|
</div>
|
|
</section>
|
|
<?php
|
|
}
|
|
?>
|
|
</div>
|
|
</section>
|
|
<?php
|
|
if(!empty($prop['listen']))
|
|
{
|
|
?><script>
|
|
NeedlegaugeComponents.start_listen(<?= jsafe($prop) ?>);
|
|
</script><?php
|
|
}
|
|
}
|
|
|
|
];
|