From 7b5addcd64e0086ae1125c878630fd7807b41ab0 Mon Sep 17 00:00:00 2001 From: brian Date: Fri, 4 Oct 2019 16:08:05 -0800 Subject: [PATCH] fix tests and get example wired up --- README.md | 21 ++- examples/index.html | 93 +++++++++++++ package-lock.json | 45 +++++- package.json | 7 +- rollup.config.js | 6 +- src/erddap-timeseries-chart.js | 242 +++++++++++++++++++++++++++------ 6 files changed, 367 insertions(+), 47 deletions(-) create mode 100644 examples/index.html diff --git a/README.md b/README.md index 950f1eb..59a9eb3 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Create timeseries and QC chart: ``` + ``` @@ -33,6 +34,12 @@ Create QC-only chart: ``` +Create curtain plot: + +``` + +``` + API --- @@ -40,7 +47,15 @@ API - ``data(arr)`` - ``x(fn)`` - ``y(fn)`` -- ``x_label(str)`` -- ``y_label(str)`` -- ``qc_options(arr)`` +- ``width(number)`` +- ``height(number)`` +- ``xLabel(str)`` +- ``yLabel(str)`` +- ``qcOptions(arr)`` - qc_option: ``{code:4,color:#FF0000,label:'Fail'}`` + +- ``drawLine`` +- ``drawQc`` +- ``drawCurtain`` +- ``getDataAtX`` +- ``getDataAtXY`` diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 0000000..3fd8055 --- /dev/null +++ b/examples/index.html @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + diff --git a/package-lock.json b/package-lock.json index 15daec3..0baa25e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "erddap-timeseries-chart-js", + "name": "erddap-timeseries-chart", "version": "0.0.1", "lockfileVersion": 1, "requires": true, @@ -88,11 +88,46 @@ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.3.2.tgz", "integrity": "sha512-cg73UOh7D7e72FQQER4l5aXnEwlizah8TIggMn8qtEO/7APe5s6bAZhlDlVw0BRml6Qi4bd44WJ5HGuiK7fRyw==" }, + "d3-axis": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", + "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==" + }, + "d3-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz", + "integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg==" + }, + "d3-format": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.1.tgz", + "integrity": "sha512-TUswGe6hfguUX1CtKxyG2nymO+1lyThbkS1ifLX0Sr+dOQtAD5gkrffpHnx+yHNKUZ0Bmg5T4AjUQwugPDrm0g==" + }, + "d3-interpolate": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.3.2.tgz", + "integrity": "sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w==", + "requires": { + "d3-color": "1" + } + }, "d3-path": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.8.tgz", "integrity": "sha512-J6EfUNwcMQ+aM5YPOB8ZbgAZu6wc82f/0WFxrxwV6Ll8wBwLaHLKCqQ5Imub02JriCVVdPjgI+6P3a4EWJCxAg==" }, + "d3-scale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.1.0.tgz", + "integrity": "sha512-3edyEBwbwQG400VbgaepQC9ZYFX3h92flLHIUa1+nvZp/mqCYdxNM9zGTjKtPcSAuBCyPePdMQOapsD0qNALrg==", + "requires": { + "d3-array": "1.2.0 - 2", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, "d3-selection": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.0.tgz", @@ -111,6 +146,14 @@ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" }, + "d3-time-format": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.3.tgz", + "integrity": "sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA==", + "requires": { + "d3-time": "1" + } + }, "deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", diff --git a/package.json b/package.json index 1f4417d..6ceed92 100644 --- a/package.json +++ b/package.json @@ -7,14 +7,15 @@ "d3-module" ], "license": "BSD-3-Clause", - "jsnext:main": "index", "homepage": "https://github.com/{USERNAME}/erddap-timeseries-chart", "repository": { "type": "git", "url": "https://github.com/{USERNAME}/erddap-timeseries-chart" }, - "module":"index", + "main": "build/erddap-timeseries-chart.js", + "module": "src/index", "files": [ + "dist/**/*.js", "src/**/*.js" ], "scripts": { @@ -31,6 +32,8 @@ }, "dependencies": { "d3-array": "^2.3.2", + "d3-axis": "^1.0.12", + "d3-scale": "^3.1.0", "d3-selection": "^1.4.0", "d3-shape": "^1.3.5", "d3-time": "^1.1.0" diff --git a/rollup.config.js b/rollup.config.js index b6d75ec..f14afa0 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,6 +1,6 @@ export default { input: 'src/index.js', - external: [ 'd3-selection','d3-array','d3-shape','d3-selection','d3-time' ], + external: [ 'd3-selection','d3-array','d3-shape','d3-axis','d3-scale' ], output:{ format: 'umd', name:'d3', @@ -10,7 +10,9 @@ export default { globals:{ 'd3-array':'d3', 'd3-shape':'d3', - 'd3-selection':'d3' + 'd3-selection':'d3', + 'd3-axis':'d3', + 'd3-scale':'d3' } } } diff --git a/src/erddap-timeseries-chart.js b/src/erddap-timeseries-chart.js index d7ee69d..12469e9 100644 --- a/src/erddap-timeseries-chart.js +++ b/src/erddap-timeseries-chart.js @@ -1,32 +1,50 @@ -import d3 from "d3-selection"; -//import d3Shape from "d3-shape"; -//import d3Time from "d3-time"; +import d3Shape from "d3-shape"; +import d3Array from "d3-array"; +import d3Scale from "d3-scale"; +import d3Axis from "d3-axis"; -export default function(){ +function chart(){ let x = function(d){return d[0]}, - y = function(d){return d[1]}, - qc = function(d){return d[2]}, - x_label, - y_label, - qc_options, - data; - - - - function chart(){ + y = function(d){return d[1]}, + z = function(d){return d[2]}, + qc = function(d){return d[3]}, + width = 800, + height = 400, + margin = { + top:20, + right:30, + bottom:30, + left:40 + }, + xDomain, + yDomain, + zDomain, + xLabel, + yLabel, + qcOptions, + data, + chartType = 'line', + chartOptions, + _selection; + function calculateDomains(){ + if(x && y && data){ + xDomain = d3Array.extent(data,x); + yDomain = d3Array.extent(data,y) + } + } - - - return chart; + function chart(context){ + _selection = context.selection ? context.selection() : context; + chart.draw(); } chart.data = function(_){ if (!arguments.length) return data; data = _; - return data; + return chart; } @@ -34,12 +52,16 @@ export default function(){ if (!arguments.length) return x; - if(!typeof _ !== 'function'){ + if(typeof _ !== 'function'){ throw(Error('x must be a function')) } x = _; - return x; + + if(data){ + xDomain = d3Array.extent(data,x) + } + return chart; } @@ -47,53 +69,195 @@ export default function(){ if (!arguments.length) return y; - if(!typeof _ !== 'function'){ + if(typeof _ !== 'function'){ throw(Error('y must be a function')) } y = _; - return y; + return chart; + + } + + chart.z = function(_){ + + if (!arguments.length) return z; + + if(typeof _ !== 'function'){ + throw(Error('y must be a function')) + } + + z = _; + if(data){ + z_domain = d3Array.extent(data,z) + } + return chart; } - chart.y_label = function(_){ - if (!arguments.length) return y_label; + chart.width = function(_){ + if (!arguments.length) return width; + + _ = +_; + + if(typeof _ !== 'number' && !isNaN(_)){ + throw(Error('width must be a number')) + } + + width = _; + return chart; + } + + chart.height = function(_){ + if (!arguments.length) return height; + + _ = +_; + + if(typeof _ !== 'number' && !isNaN(_)){ + throw(Error('width must be a number')) + } + + height = _; + return chart; + } + + chart.yLabel = function(_){ + if (!arguments.length) return yLabel; if(typeof _ !== 'string' || typeof _ !== 'number'){ - throw(Error('y_label must be a number or a string')) + throw(Error('yLabel must be a number or a string')) } - y_label = _; - return y_label; + yLabel = _; + return yLabel; } - chart.x_label = function(_){ + chart.xLabel = function(_){ - if (!arguments.length) return x_label; + if (!arguments.length) return xLabel; if(typeof _ !== 'string' || typeof _ !== 'number'){ - throw(Error('x_label must be a number or a string')) + throw(Error('xLabel must be a number or a string')) } - x_label = _; - return x_label; + xLabel = _; + return xLabel; } - chart.qc_options = function(_){ - if (!arguments.length) return qc_options; + chart.qcOptions = function(_){ + if (!arguments.length) return qcOptions; if(typeof _ !== 'array'){ - throw(Error('qc_options must be a number or a string')) + throw(Error('qcOptions must be an array')) } - qc_options = _; - return qc_options; + qcOptions = _; + return chart; } - return chart; + chart.chartType = function(_,options){ + if (!arguments.length) return qcOptions; + + if(typeof _ !== 'string'){ + //eventually support function + throw(Error('chartType must be an array')) + } + + if(options && typeof options !== 'object'){ + throw(Error('chartOptions must be an object')) + } + + chartType = _; + if(options){ + chartOptions = options; + } + return chart; + } + + chart.draw = function(){ + switch(chartType){ + case 'line': + drawLine(); + break; + + default: + throw(Error('Unsupported chart type')) + } + + } + + + function drawLine(){ + + if(!_selection){ + throw(Error('must be called from a selection')) + } + + //could allow scales to be passed in + calculateDomains(); + + + if(xDomain && yDomain){ + let xScale = d3Scale.scaleUtc() + .domain(xDomain) + .range([margin.left, width - margin.right]), + + yScale = d3Scale.scaleLinear() + .domain(yDomain).nice() + .range([height - margin.bottom, margin.top]), + + xAxis = g => g + .attr("transform", `translate(0,${height - margin.bottom})`) + .call(d3Axis.axisBottom(xScale).ticks(width / 80).tickSizeOuter(0)), + //need to add xLabel if exists here + + + yAxis = g => g + .attr("transform", `translate(${margin.left},0)`) + .call(d3Axis.axisLeft(yScale)) + .call(g => g.select(".domain").remove()), + //add yLabel here + + line = d3Shape.line() + .defined(d => !isNaN(+x(d))) + .x(d=>xScale(x(d))) + .y(d=>yScale(y(d))); + + + + _selection.append("g") + .call(xAxis); + + _selection.append("g") + .call(yAxis); + + //should make styles properties that can be overridden + _selection.append("path") + .datum(data) + .attr("fill", "none") + .attr("stroke", "#333") + .attr("stroke-width", 1.5) + .attr("stroke-linejoin", "round") + .attr("stroke-linecap", "round") + .attr("d", line); + + + + + //option to overlay dots on line + + } + + + + + + } + + return chart; +} -} \ No newline at end of file +export default chart; \ No newline at end of file