diff --git a/elements/linechart.js b/elements/linechart.js new file mode 100644 index 0000000..2b226e9 --- /dev/null +++ b/elements/linechart.js @@ -0,0 +1,153 @@ +import { withComponent, props } from 'skatejs'; +import { Timeseries } from '../lib/timeseries'; +import { colors } from '../lib/colors'; + +const Component = withComponent(); + +class LineChart extends Component { + static props = { + timeseries: props.string, + days: props.number, + interpolate: props.boolean, + accumulate: props.boolean, + data: props.array, + shape: props.string, + }; + + + connected() { + if (!this.timeseries || !this.timeseries.length) { + return; + } + const daySlots = this.days || 1; + const endDate = new Date(); + const promises = this.timeseries.split(' ').map((dataset) => { + const ts = new Timeseries(dataset, endDate, daySlots); + if (!this.ts) { + // We need one for labeling + this.ts = ts; + } + return ts.getData({ + interpolate: this.interpolate, + accumulate: this.accumulate, + usePreviousValue: false, + }); + }); + Promise.all(promises) + .then((res) => { + this.data = res; + }); + } + + renderer(renderRoot, render) { + const root = renderRoot; + while (root.firstChild) { + root.removeChild(root.firstChild); + } + root.appendChild(render()); + } + + joinDays(values, slotLabels) { + let data = []; + let labels = []; + // Padding is hack for https://github.com/plotly/plotly.js/issues/1516 + let pad = ''; + values.forEach((val, idx) => { + let vals = val; + if (idx === values.length - 1) { + // Last one, remove trailing zeros + let lastVal = vals.length - 1; + for (let i = lastVal; i > 0; i--) { + if (vals[i] !== 0) { + lastVal = i; + break; + } + } + vals = val.slice(0, lastVal); + } + data = data.concat(vals); + labels = labels.concat(slotLabels.slice(0, vals.length).map(label => `${label}${pad}`)); + pad += ' '; + }); + + const daySlots = this.days || 1; + if (data.length > daySlots * 24) { + const surplus = data.length - daySlots * 24; + data = data.slice(surplus); + console.log(this.days * 24, surplus, data.length); + labels = labels.slice(surplus); + } + + return { + data, + labels, + }; + } + + render({ data, ts, shape }) { + const el = document.createElement('div'); + if (!data || !data.length || !ts) { + // No data yet + return el; + } + const lineShape = shape || 'spline'; + const graphData = data.map((values, idx) => { + const d = this.joinDays(values, this.ts.getSlotLabels()); + const res = { + x: d.labels, + y: d.data, + type: 'scatter', + mode: 'lines', + name: this.timeseries.split(' ')[idx], + line: { + shape: lineShape, + }, + }; + if (colors[idx]) { + res.line.color = colors[idx]; + } + return res; + }); + console.log(graphData); + const layout = { + yaxis: { + tickfont: { + family: 'Source Code Pro', + }, + tickcolor: '#204a87', + gridcolor: '#204a87', + }, + xaxis: { + type: 'category', + tickfont: { + family: 'Source Code Pro', + }, + tickcolor: '#204a87', + gridcolor: '#204a87', + }, + font: { + family: ['Source Code Pro', 'sans-serif'], + size: 16, + color: '#fff', + outlineColor: 'transparent', + }, + legend: { + orientation: 'h', + x: 0, + y: 0, + font: { + family: 'Source Code Pro', + }, + }, + showlegend: true, + paper_bgcolor: 'transparent', + plot_bgcolor: 'transparent', + }; + Plotly.newPlot(el, graphData, layout, { + staticPlot: true, + }); + return el; + } +} + +customElements.define('cbase-linechart', LineChart); diff --git a/index.js b/index.js index 57af70c..04a6266 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,13 @@ import currentstate from './elements/currentstate'; import heatmap from './elements/heatmap'; +import linechart from './elements/linechart'; import polar from './elements/polar'; import time from './elements/time'; export default { currentstate, heatmap, + linechart, polar, time, }; diff --git a/lib/colors.js b/lib/colors.js new file mode 100644 index 0000000..5554546 --- /dev/null +++ b/lib/colors.js @@ -0,0 +1,13 @@ +export const colors = [ + '#fff', + 'hsl(0, 98%, 46%)', + 'hsl(35, 98%, 46%)', + 'hsl(60, 98%, 46%)', + 'hsl(135, 98%, 46%)', + 'hsl(160, 98%, 46%)', + 'hsl(185, 98%, 46%)', + 'hsl(210, 98%, 46%)', + 'hsl(285, 98%, 46%)', + 'hsl(310, 98%, 46%)', + 'hsl(335, 98%, 46%)', +];