diff --git a/WebApp/src/components/widgets/gauge-circular.css b/WebApp/src/components/widgets/gauge-circular.css new file mode 100644 index 0000000..e69de29 diff --git a/WebApp/src/components/widgets/gauge-circular.tsx b/WebApp/src/components/widgets/gauge-circular.tsx new file mode 100644 index 0000000..9c0fdf9 --- /dev/null +++ b/WebApp/src/components/widgets/gauge-circular.tsx @@ -0,0 +1,81 @@ +import m from 'mithril'; +import { Gauge } from 'components/widgets/gauge'; +import { Pipe } from 'utilities/pipe'; + +require('./gauge-circular.css'); + +export class GaugeCircular extends Gauge { + constructor(vnode: any) { + super(vnode); + } + + createSvg(svgElement: SVGElement) { + let w = Math.round(svgElement.clientWidth); + let h = Math.round(svgElement.clientHeight); + + svgElement.setAttribute('viewBox', "0 0 "+w+" "+h); + + let svgRound = (v: number) => Math.round(v * 100.0) / 100.0; + + const arcRatio = 0.75; // from 0.5 for half circle to 1.0 for full circle + const gaugeWidthRatio = 0.15; // relative to the smallest dimension of the drawing area + const lineThickness = 1; + + let gaugeWidth = Math.round(Math.min(w, h) * gaugeWidthRatio); + let gaugeRadius = Math.round(Math.min(w, h) * 0.5 - gaugeWidth * 0.5 - lineThickness - 1); + let cx = Math.round(w * 0.5); let cy = Math.round(h * 0.5); + + let openingHalfAngle = Math.PI * (1.0 - arcRatio); + let arcLength = Math.PI * 2.0 * gaugeRadius * arcRatio; + let startx = svgRound(cx - Math.sin(openingHalfAngle) * gaugeRadius); + let starty = svgRound(cy + Math.cos(openingHalfAngle) * gaugeRadius); + let dx = svgRound(2.0 * Math.sin(openingHalfAngle) * gaugeRadius); + + let outlineArcRatio = (arcLength + lineThickness*2.0) / (Math.PI * 2.0 * gaugeRadius); + let outlineOpeningHalfAngle = Math.PI * (1.0 - outlineArcRatio); + let outlineStartx = svgRound(cx - Math.sin(outlineOpeningHalfAngle) * gaugeRadius); + let outlineStarty = svgRound(cy + Math.cos(outlineOpeningHalfAngle) * gaugeRadius); + let outlineDx = svgRound(2.0 * Math.sin(outlineOpeningHalfAngle) * gaugeRadius); + + let bgOutline = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + bgOutline.setAttribute('d', 'M'+outlineStartx+' '+outlineStarty+' a'+gaugeRadius+' '+gaugeRadius+' 0 1 1 '+outlineDx+' 0'); + bgOutline.setAttribute('style', 'stroke-width: '+(gaugeWidth+lineThickness*2)); + bgOutline.classList.add('gauge-bg-outline'); + svgElement.append(bgOutline); + + let bg = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + bg.setAttribute('d', 'M'+startx+' '+starty+' a'+gaugeRadius+' '+gaugeRadius+' 0 1 1 '+dx+' 0'); + bg.setAttribute('style', 'stroke-width: '+(gaugeWidth)); + bg.classList.add('gauge-bg'); + svgElement.append(bg); + + let barHeight = 15; + const barGap = barHeight * 0.2; + let numBars = Math.round(h / (barHeight + barGap)); + + let bh = (h - (numBars+1)*barGap) / numBars; + barHeight = Math.round(bh); + + /*for(let barIdx = 0; barIdx < numBars; ++barIdx) { + let bar = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); + bar.setAttribute('width', (w - barGap * 2).toString()); + bar.setAttribute('height', barHeight.toString()); + bar.classList.add('gauge-bar'); + bar.classList.toggle('lit', false); + + bar.setAttribute('x', barGap.toString()); + bar.setAttribute('y', (h - barIdx * (bh+barGap) - barGap - barHeight).toString()); + + svgElement.append(bar); + + this.bars.push(bar); + }*/ + } + + oncreate(vnode: any) { + let svgElement: SVGElement = vnode.dom.querySelector('svg'); + this.createSvg(svgElement); + + super.oncreate(vnode); + } +} diff --git a/WebApp/src/components/widgets/gauge.css b/WebApp/src/components/widgets/gauge.css index e0650d4..bdb5362 100644 --- a/WebApp/src/components/widgets/gauge.css +++ b/WebApp/src/components/widgets/gauge.css @@ -1,6 +1,11 @@ div.gauge { display: flex; flex-direction: column; + text-align: center; +} + +div.gauge svg { + flex: 1; } div.gauge span.integral-value { @@ -23,6 +28,16 @@ rect.gauge-bg { stroke: rgb(0,0,0) } +path.gauge-bg-outline { + stroke: rgb(0,0,0); + fill: none; +} + +path.gauge-bg { + stroke: rgb(255,255,255); + fill: none; +} + rect.gauge-bar { fill: rgb(230,230,230); stroke-width: 1; diff --git a/WebApp/src/components/widgets/widget.css b/WebApp/src/components/widgets/widget.css index 91f075f..da638e6 100644 --- a/WebApp/src/components/widgets/widget.css +++ b/WebApp/src/components/widgets/widget.css @@ -1,3 +1,11 @@ -div.widget svg { +div.widgets-row { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + display: flex; + flex-direction: row; +} + +div.widget { flex: 1; + margin: 0.2rem; } diff --git a/WebApp/src/pages/dashboard/dashboard-page.css b/WebApp/src/pages/dashboard/dashboard-page.css index 926c749..e8661f3 100644 --- a/WebApp/src/pages/dashboard/dashboard-page.css +++ b/WebApp/src/pages/dashboard/dashboard-page.css @@ -2,12 +2,3 @@ div.dashboard-page { width: 100%; height: 100%; } - -div.widgets-row { - display: flex; - flex-direction: row; -} - -div.widget { - flex: 1; -} diff --git a/WebApp/src/pages/dashboard/dashboard-page.tsx b/WebApp/src/pages/dashboard/dashboard-page.tsx index 4daf59b..5ecb73c 100644 --- a/WebApp/src/pages/dashboard/dashboard-page.tsx +++ b/WebApp/src/pages/dashboard/dashboard-page.tsx @@ -5,6 +5,7 @@ import { Pipe } from 'utilities/pipe'; import { Clock } from 'components/widgets/clock'; import { GaugeLinear } from 'components/widgets/gauge-linear'; +import { GaugeCircular } from 'components/widgets/gauge-circular'; require('./dashboard-page.css'); @@ -52,7 +53,7 @@ export class DashboardPage extends Page {