rms-sparklines
Version:
A sparkline collection, written as web components
301 lines (257 loc) • 9.66 kB
text/typescript
// Copyright 2018 Rodrigo Silveira
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import { html, render, TemplateResult } from 'lit-html';
import { BarChart } from '../../util-lib/src/bar-chart';
import { CssColorString } from '../../util-lib/src/valid-colors';
export class RmsSparklineBarChart extends HTMLElement {
public barHeightsArray: number[] = [];
VALID_CHART_TYPES: string = ['positive', 'negative', 'dual', 'tri'].join();
private cssColorString: CssColorString = null;
private barChart: BarChart;
VALID_TYPES: string[] = ['positive', 'negative', 'dual', 'tri'];
POSITIVE = 0;
NEGATIVE = 1;
DUAL = 2;
TRI = 3;
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.cssColorString = new CssColorString();
}
static get observedAttributes(): string[] {
return ['barGap', 'barHeights', 'chartType', 'className', 'fillColorMinus', 'fillColorPlus', 'height', 'fillColorZero', 'minimumBarWidth', 'width'];
}
connectedCallback() {
this.upgradeProperties();
this.render();
}
disconnectedCallback() {
}
attributeChangedCallback(_name: string, _oldValue: any, _newValue: any) {
this.render();
}
private upgradeProperties() {
// Support lazy properties https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
(<any>this).constructor['observedAttributes'].forEach((prop: string) => {
if (this.hasOwnProperty(prop)) {
const value = (<any>this)[prop];
delete (<any>this)[prop];
(<any>this)[prop] = value;
}
});
}
get barGap(): number {
if (this.hasAttribute('barGap')) {
return Number(this.getAttribute('barGap'));
} else {
return 0;
}
}
set barGap(value: number) {
if (value) {
this.setAttribute('barGap', String(value));
} else {
this.removeAttribute('barGap');
}
}
get barHeights(): string {
return this.getAttribute('barHeights');
}
set barHeights(value: string) {
if (value) {
this.setAttribute('barHeights', value);
} else {
this.removeAttribute('barHeights');
}
}
get chartType(): string {
return this.getAttribute('chartType');
}
set chartType(value: string) {
if (value) {
this.setAttribute('chartType', value);
} else {
this.removeAttribute('chartType');
}
}
get className(): string {
return this.getAttribute('className');
}
set className(value: string) {
if (value) {
this.setAttribute('className', value);
} else {
this.removeAttribute('className');
}
}
get fillColorMinus(): string {
return this.getAttribute('fillColorMinus');
}
set fillColorMinus(value: string) {
if (value) {
this.setAttribute('fillColorMinus', value);
} else {
this.removeAttribute('fillColorMinus');
}
}
get fillColorPlus(): string {
return this.getAttribute('fillColorPlus');
}
set fillColorPlus(value: string) {
if (value) {
this.setAttribute('fillColorPlus', value);
} else {
this.removeAttribute('fillColorPlus');
}
}
get fillColorZero(): string {
return this.getAttribute('fillColorZero');
}
set fillColorZero(value: string) {
if (value) {
this.setAttribute('fillColorZero', value);
} else {
this.removeAttribute('fillColorZero');
}
}
get height(): number {
if (this.hasAttribute('height')) {
return Number(this.getAttribute('height'));
} else {
return 0;
}
}
set height(value: number) {
if (value) {
this.setAttribute('height', String(value));
} else {
this.removeAttribute('height');
}
}
get minimumBarWidth(): number {
if (this.hasAttribute('minimumBarWidth')) {
return Number(this.getAttribute('minimumBarWidth'));
} else {
return 0;
}
}
set minimumBarWidth(value: number) {
if (value) {
this.setAttribute('minimumBarWidth', String(value));
} else {
this.removeAttribute('minimumBarWidth');
}
}
get width(): number {
if (this.hasAttribute('width')) {
return Number(this.getAttribute('width'));
} else {
return 0;
}
}
set width(value: number) {
if (value) {
this.setAttribute('width', String(value));
} else {
this.removeAttribute('width');
}
}
private get styles(): TemplateResult {
return html`
<style>
:host {
display: inline-block;
verticalAlign: top;
}
:host([hidden]) {
display: none;
}
.content {
}
</style>
`;
}
private get template(): TemplateResult {
// console.log('RmsSparklineBarChart::template');
const canvasEl = document.createElement('canvas') as HTMLCanvasElement;
canvasEl.width = this.width;
canvasEl.height = this.height;
if (this.className && this.className !== ``) { canvasEl.classList.add(this.className); }
this.barChart = new BarChart(canvasEl, this.chartType, this.barHeightsArray, this.minimumBarWidth, this.barGap, this.fillColorMinus, this.fillColorZero, this.fillColorPlus);
this.barChart.draw();
return html`
${this.styles}
<div class="content">
${canvasEl}
<slot></slot>
</div>
`;
}
render() {
const __this: any = this;
// console.log('RmsSparklineBarChart::render');
// Little debugging
//
// console.log('::render - chartType: ' + this.chartType);
// console.log('::render - barHeights: ' + JSON.stringify(this.barHeights));
// console.log('::render - minimumBarWidth: ' + this.minimumBarWidth);
// console.log('::render - barGap: ' + this.barGap);
// console.log('::render - fillColorMinus: ' + this.fillColorMinus);
// console.log('::render - fillColorZero: ' + this.fillColorZero);
// console.log('::render - fillColorPlus: ' + this.fillColorPlus);
// console.log('::render - width: ' + this.width);
// console.log('::render - height: ' + this.height);
// ensure attribute coherence
//
if (this.VALID_CHART_TYPES.indexOf(this.chartType) === -1) { return; }
switch (this.chartType) {
case this.VALID_TYPES[this.POSITIVE]:
break;
case this.VALID_TYPES[this.NEGATIVE]:
break;
case this.VALID_TYPES[this.DUAL]:
break;
case this.VALID_TYPES[this.TRI]:
break;
default:
break;
}
if (!this.barHeights) { return; }
this.barHeightsArray = JSON.parse(this.barHeights);
if (this.barHeightsArray.length === 0) { return; }
if (this.minimumBarWidth < 3) {return; }
if (this.barGap < 1) { return; }
if (!this.cssColorString.isValid(this.fillColorMinus)) { return; }
if (!this.cssColorString.isValid(this.fillColorZero)) { return; }
if (!this.cssColorString.isValid(this.fillColorPlus)) { return; }
if (this.width === 0) { return; }
if (this.height === 0) { return; }
render(this.template, this.shadowRoot);
this.addEventListener('mousemove', function(event: any) {
// console.log(`RmsSparklineInlineNew::addEventListener`);
// Note that when this function is called, this points to the target element!
__this.barChart.handleMouseMove(event, this);
});
this.addEventListener('mouseout', function() {
// console.log(`RmsSparklineInlineNew::addEventListener`);
__this.barChart.handleMouseOut();
});
}
}
window.customElements.define('rms-sparkline-bar-chart', RmsSparklineBarChart);