diff --git a/src_route_history/+layout.ts b/src_route_history/+layout.ts deleted file mode 100644 index a3d1578..0000000 --- a/src_route_history/+layout.ts +++ /dev/null @@ -1 +0,0 @@ -export const ssr = false; diff --git a/src_route_history/+page.svelte b/src_route_history/+page.svelte deleted file mode 100644 index 48fe9e5..0000000 --- a/src_route_history/+page.svelte +++ /dev/null @@ -1,85 +0,0 @@ - - -

Chart goes here

-
- -

Hopefully above 👆

diff --git a/src_route_history/lib.ts b/src_route_history/lib.ts deleted file mode 100644 index dbb6a9d..0000000 --- a/src_route_history/lib.ts +++ /dev/null @@ -1,620 +0,0 @@ -import * as d3 from 'd3'; -import { transition } from 'd3-transition'; - -var defaultColors = [ - '#a6cee3', - '#ff7f00', - '#b2df8a', - '#1f78b4', - '#fdbf6f', - '#33a02c', - '#cab2d6', - '#6a3d9a', - '#fb9a99', - '#e31a1c', - '#ffff99', - '#b15928' -]; - -// utils -function functorkey(v) { - return typeof v === 'function' - ? v - : function(d) { - return d[v]; - }; -} - -function functorkeyscale(v, scale) { - var f = - typeof v === 'function' - ? v - : function(d) { - return d[v]; - }; - return function(d) { - return scale(f(d)); - }; -} - -function keyNotNull(k) { - return function(d) { - return d.hasOwnProperty(k) && d[k] !== null && !isNaN(d[k]); - }; -} - -function fk(v) { - return function(d) { - return d[v]; - }; -} - -function main() { - // default - var height = 480; - var width = 600; - - var drawerHeight = 80; - var drawerTopMargin = 10; - var margin = { top: 10, bottom: 20, left: 30, right: 10 }; - - var series = []; - - var yscale = d3.scaleLinear(); - var xscale = d3.scaleTime(); - yscale.label = ''; - xscale.label = ''; - - var brush = d3.brushX(); - - var svg, container, serieContainer, annotationsContainer, drawerContainer, mousevline; - var fullxscale, tooltipDiv; - - yscale.setformat = function(n) { - return n.toLocaleString(); - }; - xscale.setformat = xscale.tickFormat(); - - // default tool tip function - var _tipFunction = function(date, series) { - var spans = - '' + - series - .filter(function(d) { - console.log('DDD:', d); - return d.item !== undefined && d.item !== null; - }) - .map(function(d) { - return ( - '' + - '' - ); - }) - .join('') + - '
' + - d.options.label + - ' ' + - yscale.setformat(d.item[d.aes.y]) + - '
'; - - return '

' + xscale.setformat(d3.timeDay(date)) + '

' + spans; - }; - - function createLines(serie) { - // https://github.com/d3/d3-shape/blob/master/README.md#curves - var aes = serie.aes; - - if (!serie.options.interpolate) { - serie.options.interpolate = 'linear'; - } else { - // translate curvenames - serie.options.interpolate = - serie.options.interpolate == 'monotone' - ? 'monotoneX' - : serie.options.interpolate == 'step-after' - ? 'stepAfter' - : serie.options.interpolate == 'step-before' - ? 'stepBefore' - : serie.options.interpolate; - } - // to uppercase for d3 curve name - var curveName = - 'curve' + serie.options.interpolate[0].toUpperCase() + serie.options.interpolate.slice(1); - serie.interpolationFunction = d3[curveName] || d3.curveLinear; - - var line = d3 - .line() - .x(functorkeyscale(aes.x, xscale)) - .y(functorkeyscale(aes.y, yscale)) - .curve(serie.interpolationFunction) - .defined(keyNotNull(aes.y)); - - serie.line = line; - - serie.options.label = - serie.options.label || serie.options.name || serie.aes.label || serie.aes.y; - - if (aes.ci_up && aes.ci_down) { - var ciArea = d3 - .area() - .x(functorkeyscale(aes.x, xscale)) - .y0(functorkeyscale(aes.ci_down, yscale)) - .y1(functorkeyscale(aes.ci_up, yscale)) - .curve(serie.interpolationFunction); - serie.ciArea = ciArea; - } - - if (aes.diff) { - serie.diffAreas = [ - d3 - .area() - .x(functorkeyscale(aes.x, xscale)) - .y0(functorkeyscale(aes.y, yscale)) - .y1(function(d) { - if (d[aes.y] > d[aes.diff]) return yscale(d[aes.diff]); - return yscale(d[aes.y]); - }) - .curve(serie.interpolationFunction), - d3 - .area() - .x(functorkeyscale(aes.x, xscale)) - .y1(functorkeyscale(aes.y, yscale)) - .y0(function(d) { - if (d[aes.y] < d[aes.diff]) return yscale(d[aes.diff]); - return yscale(d[aes.y]); - }) - .curve(serie.interpolationFunction) - ]; - } - - serie.find = function(date) { - var bisect = d3.bisector(fk(aes.x)).left; - var i = bisect(serie.data, date) - 1; - if (i == -1) { - return null; - } - - // look to far after serie is defined - if ( - i == serie.data.length - 1 && - serie.data.length > 1 && - Number(date) - Number(serie.data[i][aes.x]) > - Number(serie.data[i][aes.x]) - Number(serie.data[i - 1][aes.x]) - ) { - return null; - } - return serie.data[i]; - }; - } - - function drawSerie(serie) { - if (!serie.linepath) { - console.log(series); - const sorted = [...series[0].data]; - sorted.sort((a, b) => (a.n > b.n ? 1 : -1)); - const min = sorted[0].n; - const max = sorted[sorted.length - 1].n; - console.log('max:', max); - console.log('min:', min); - const midean = (max + min) / 2; - console.log('midean:', midean); - - var linepath = serieContainer - .append('path') - .datum(serie.data.filter((e) => e.n <= midean)) - .attr('class', 'd3_timeseries line') - .attr('d', serie.line) - // .attr('stroke', serie.options.color) - .attr('stroke', 'red') - .attr('stroke-linecap', 'round') - .attr('stroke-width', serie.options.width || 1.5) - .attr('fill', 'none'); - - if (serie.options.dashed) { - if (serie.options.dashed == true || serie.options.dashed == 'dashed') { - serie['stroke-dasharray'] = '5,5'; - } else if (serie.options.dashed == 'long') { - serie['stroke-dasharray'] = '10,10'; - } else if (serie.options.dashed == 'dot') { - serie['stroke-dasharray'] = '2,4'; - } else { - serie['stroke-dasharray'] = serie.options.dashed; - } - linepath.attr('stroke-dasharray', serie['stroke-dasharray']); - } - serie.linepath = linepath; - // serie.hotLine = hotLine; - - if (serie.ciArea) { - serie.cipath = serieContainer - .insert('path', ':first-child') - .datum(serie.data) - .attr('class', 'd3_timeseries ci-area') - .attr('d', serie.ciArea) - .attr('stroke', 'none') - .attr('fill', serie.options.color) - .attr('opacity', serie.options.ci_opacity || 0.3); - } - if (serie.diffAreas) { - serie.diffpaths = serie.diffAreas.map(function(area, i) { - var c = (serie.options.diff_colors ? serie.options.diff_colors : ['green', 'red'])[i]; - return serieContainer - .insert('path', function() { - return linepath.node(); - }) - .datum(serie.data) - .attr('class', 'd3_timeseries diff-area') - .attr('d', area) - .attr('stroke', 'none') - .attr('fill', c) - .attr('opacity', serie.options.diff_opacity || 0.5); - }); - } - } else { - serie.linepath.attr('d', serie.line); - serie.linepath.attr('d', serie.hotLine); - if (serie.ciArea) { - serie.cipath.attr('d', serie.ciArea); - } - if (serie.diffAreas) { - serie.diffpaths[0].attr('d', serie.diffAreas[0]); - serie.diffpaths[1].attr('d', serie.diffAreas[1]); - } - } - } - - function updatefocusRing(xdate) { - var s = annotationsContainer.selectAll('circle.d3_timeseries.focusring'); - - if (xdate == null) { - s = s.data([]); - } else { - s = s.data( - series - .map(function(s) { - return { x: xdate, item: s.find(xdate), aes: s.aes, color: s.options.color }; - }) - .filter(function(d) { - return ( - d.item !== undefined && - d.item !== null && - d.item[d.aes.y] !== null && - !isNaN(d.item[d.aes.y]) - ); - }) - ); - } - - const t = transition().duration(50); - /* - .attr('cx', function(d) { - console.log('aDDD:', d); - - return xscale(d.item[d.aes.n]); - }) - .attr('cy', function(d) { - return yscale(d.item[d.aes.date]); - }); - */ - - s.transition(t); - - s.enter() - .append('circle') - .attr('class', 'd3_timeseries focusring') - .attr('fill', 'none') - .attr('stroke-width', 2) - .attr('r', 5) - .attr('stroke', fk('color')); - - s.exit().remove(); - } - - function updateTip(xdate) { - if (xdate == null) { - tooltipDiv.style('opacity', 0); - } else { - var s = series.map(function(s) { - return { item: s.find(xdate), aes: s.aes, options: s.options }; - }); - - tooltipDiv - .style('opacity', 0.9) - .style('left', margin.left + 5 + xscale(xdate) + 'px') - .style('top', '0px') - .html(_tipFunction(xdate, s)); - } - } - - function drawMiniDrawer() { - var smallyscale = yscale.copy().range([drawerHeight - drawerTopMargin, 0]); - var serie = series[0]; - var line = d3 - .line() - .x(functorkeyscale(serie.aes.x, fullxscale)) - .y(functorkeyscale(serie.aes.y, smallyscale)) - .curve(serie.interpolationFunction) - .defined(keyNotNull(serie.aes.y)); - var linepath = drawerContainer - .insert('path', ':first-child') - .datum(serie.data) - .attr('class', 'd3_timeseries.line') - .attr('transform', 'translate(0,' + drawerTopMargin + ')') - .attr('d', line) - .attr('stroke', serie.options.color) - .attr('stroke-width', serie.options.width || 1.5) - .attr('fill', 'none'); - if (serie.hasOwnProperty('stroke-dasharray')) { - linepath.attr('stroke-dasharray', serie['stroke-dasharray']); - } - } - - function mouseMove() { - var x = d3.pointer(container.node())[0]; - x = xscale.invert(x); - mousevline.datum({ x: x, visible: true }); - mousevline.update(); - updatefocusRing(x); - updateTip(x); - } - function mouseOut() { - mousevline.datum({ x: null, visible: false }); - mousevline.update(); - updatefocusRing(null); - updateTip(null); - } - - var chart = function(elem) { - // compute mins max on all series - series = series.map(function(s) { - var extent = d3.extent(s.data.map(functorkey(s.aes.y))); - s.min = extent[0]; - s.max = extent[1]; - extent = d3.extent(s.data.map(functorkey(s.aes.x))); - s.dateMin = extent[0]; - s.dateMax = extent[1]; - return s; - }); - - // set scales - - yscale - .range([height - margin.top - margin.bottom - drawerHeight - drawerTopMargin, 0]) - .domain([d3.min(series.map(fk('min'))), d3.max(series.map(fk('max')))]) - .nice(); - - xscale - .range([0, width - margin.left - margin.right]) - .domain([d3.min(series.map(fk('dateMin'))), d3.max(series.map(fk('dateMax')))]) - .nice(); - - // if user specify domain - if (yscale.fixedomain) { - // for showing 0 : - // chart.addSerie(...) - // .yscale.domain([0]) - if (yscale.fixedomain.length == 1) { - yscale.fixedomain.push(yscale.domain()[1]); - } - yscale.domain(yscale.fixedomain); - } - - if (xscale.fixedomain) { - xscale.domain(yscale.fixedomain); - } - - fullxscale = xscale.copy(); - - // create svg - svg = d3.select(elem).append('svg').attr('width', width).attr('height', height); - - // clipping for scrolling in focus area - svg - .append('defs') - .append('clipPath') - .attr('id', 'clip') - .append('rect') - .attr('width', width - margin.left - margin.right) - .attr('height', height - margin.bottom - drawerHeight - drawerTopMargin) - .attr('y', -margin.top); - - // container for focus area - container = svg - .insert('g', 'rect.mouse-catch') - .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') - .attr('clip-path', 'url(#clip)'); - - serieContainer = container.append('g'); - annotationsContainer = container.append('g'); - - // mini container at the bottom - drawerContainer = svg - .append('g') - .attr( - 'transform', - 'translate(' + margin.left + ',' + (height - drawerHeight - margin.bottom) + ')' - ); - - // vertical line moving with mouse tip - mousevline = svg.append('g').datum({ - x: new Date(), - visible: false - }); - mousevline - .append('line') - .attr('x1', 0) - .attr('x2', 0) - .attr('y1', yscale.range()[0]) - .attr('y2', yscale.range()[1]) - .attr('class', 'd3_timeseries mousevline'); - // update mouse vline - mousevline.update = function() { - this.attr('transform', function(d) { - return 'translate(' + (margin.left + xscale(d.x)) + ',' + margin.top + ')'; - }).style('opacity', function(d) { - return d.visible ? 1 : 0; - }); - }; - mousevline.update(); - - var xAxis = d3.axisBottom().scale(xscale).tickFormat(xscale.setformat); - var yAxis = d3.axisLeft().scale(yscale).tickFormat(yscale.setformat); - - brush - .extent([ - [fullxscale.range()[0], 0], - [fullxscale.range()[1], drawerHeight - drawerTopMargin] - ]) - - .on('brush', () => { - let selection = d3.event.selection; - - xscale.domain(selection.map(fullxscale.invert, fullxscale)); - - series.forEach(drawSerie); - svg.select('.focus.x.axis').call(xAxis); - mousevline.update(); - updatefocusRing(); - }) - - .on('end', () => { - let selection = d3.event.selection; - if (selection === null) { - xscale.domain(fullxscale.domain()); - - series.forEach(drawSerie); - svg.select('.focus.x.axis').call(xAxis); - mousevline.update(); - updatefocusRing(); - } - }); - - svg - .append('g') - .attr('class', 'd3_timeseries focus x axis') - .attr( - 'transform', - 'translate(' + - margin.left + - ',' + - (height - margin.bottom - drawerHeight - drawerTopMargin) + - ')' - ) - .call(xAxis); - - drawerContainer - .append('g') - .attr('class', 'd3_timeseries x axis') - .attr('transform', 'translate(0,' + drawerHeight + ')') - .call(xAxis); - - drawerContainer - .append('g') - .attr('class', 'd3_timeseries brush') - .call(brush) - .attr('transform', `translate(0, ${drawerTopMargin})`) - .attr('height', drawerHeight - drawerTopMargin); - - svg - .append('g') - .attr('class', 'd3_timeseries y axis') - .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') - .call(yAxis) - .append('text') - .attr('transform', 'rotate(-90)') - .attr('x', -margin.top - d3.mean(yscale.range())) - .attr('dy', '.71em') - .attr('y', -margin.left + 5) - .style('text-anchor', 'middle') - .text(yscale.label); - - // catch event for mouse tip - svg - .append('rect') - .attr('width', width) - .attr('class', 'd3_timeseries mouse-catch') - .attr('height', height - drawerHeight) - // .style('fill','green') - .style('opacity', 0) - .on('mousemove', mouseMove) - .on('mouseout', mouseOut); - - tooltipDiv = d3 - .select(elem) - .style('position', 'relative') - .append('div') - .attr('class', 'd3_timeseries tooltip') - .style('opacity', 0); - - series.forEach(createLines); - series.forEach(drawSerie); - drawMiniDrawer(); - }; - - chart.width = function(_) { - if (!arguments.length) return width; - width = _; - return chart; - }; - - chart.height = function(_) { - if (!arguments.length) return height; - height = _; - return chart; - }; - - chart.margin = function(_) { - if (!arguments.length) return margin; - margin = _; - return chart; - }; - // accessors for margin.left(), margin.right(), margin.top(), margin.bottom() - // UNDEFINED - /* - d3.keys(margin).forEach(function(k) { - chart.margin[k] = function(_) { - if (!arguments.length) return margin[k]; - margin[k] = _; - return chart; - }; - }); - */ - - // scales accessors - var scaleGetSet = function(scale) { - return { - tickFormat: function(_) { - if (!arguments.length) return scale.setformat; - scale.setformat = _; - return chart; - }, - label: function(_) { - if (!arguments.length) return scale.label; - scale.label = _; - return chart; - }, - domain: function(_) { - if (!arguments.length && scale.fixedomain) return scale.fixedomain; - if (!arguments.length) return null; - scale.fixedomain = _; - return chart; - } - }; - }; - - chart.yscale = scaleGetSet(yscale); - chart.xscale = scaleGetSet(xscale); - - chart.addSerie = function(data, aes, options) { - if (!data && series.length > 0) data = series[0].data; - if (!options.color) options.color = defaultColors[series.length % defaultColors.length]; - series.push({ data: data, aes: aes, options: options }); - return chart; - }; - - return chart; -} - -export default main;