Created
April 15, 2019 09:54
-
-
Save 4096void/1f618cc5c03d5b1e73cbe267b214ed84 to your computer and use it in GitHub Desktop.
multiple lines in one linechart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| license: mit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <script src="https://d3js.org/d3.v5.min.js"></script> | |
| <style> | |
| body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
| </style> | |
| </head> | |
| <body> | |
| <script> | |
| /** | |
| const d3 = require('d3'); | |
| */ | |
| /** | |
| linechart D3 version. | |
| dependency | |
| d3 | |
| todos | |
| add axises DONE | |
| add labels DONE | |
| add path DONE | |
| add gridline DONE | |
| multiple lines in one chart DONE | |
| nice color scheme DONE | |
| mousemove -> tooltip. | |
| https://observablehq.com/@elishaterada/simple-area-chart-with-tooltip | |
| https://observablehq.com/@jianan-li/basic-tooltip | |
| grouped categories. | |
| more customization parameters. | |
| expose update method. | |
| transition. | |
| reverse yAxis and xAxis. | |
| animations. | |
| http://bl.ocks.org/markmarkoh/8700606 | |
| */ | |
| /* utils */ | |
| const roll = Math.random; | |
| const rolln = n => Math.random() * n; | |
| const rollBetween = (n, m) => Math.random() * (m - n) + n; | |
| const max = Math.max; | |
| const k = k => c => c[k]; | |
| const mk = k => c => c.map(i => i[k]); | |
| const arrayMax = i => Math.max.apply(null, i); | |
| function line( | |
| container = 'body', // selector or pure DOM node | |
| width = 500, // default to square | |
| height = width, | |
| margin = Math.max(width, height) / 5, | |
| word = Math.max(width, height) / 30, | |
| isSmooth = false, | |
| yLabel = 'Profit(USD).', | |
| xLabel = 'Time(YEAR).', | |
| ) { | |
| let kv = []; | |
| let kv1 = []; | |
| let kv2 = []; | |
| let kv3 = []; | |
| /* walden theme */ | |
| const colors = [ | |
| '#3fb1e3', | |
| '#6be6c1', | |
| '#626c91', | |
| '#a0a7e6', | |
| '#c4ebad', | |
| '#96dee8', | |
| ]; | |
| for (let i = 2000; i < 2008; i++) { | |
| kv.push({ key: i, value: rollBetween(1000, 2000) }); | |
| kv1.push({ key: i, value: rollBetween(3000, 4000) }); | |
| kv2.push({ key: i, value: rollBetween(5000, 6000) }); | |
| kv3.push({ key: i, value: rollBetween(8000, 9000) }); | |
| } | |
| let kvs = [kv, kv1, kv2, kv3]; | |
| window.kv = kv; | |
| /* scales */ | |
| const xScale = d3 | |
| .scalePoint() | |
| .domain(d3.set(kv.map(k('key'))).values()) // fixme | |
| .rangeRound([0, width]); | |
| const yScale = d3.scaleLinear() | |
| .domain([0, arrayMax(kvs.map(mk('value')).map(arrayMax)) * 1.3]) | |
| .range([height, 0]); | |
| const lineGenerator = d3 | |
| .line() | |
| .x(d => xScale(d.key)) | |
| .y(d => yScale(d.value)) | |
| .curve(d3.curveMonotoneX); // smoothline | |
| /* root */ | |
| const svg = d3 | |
| .select(container) | |
| .append('svg') | |
| .attr('width', width + margin * 2) | |
| .attr('height', height + margin * 2) | |
| .style('margin', '1em') | |
| .style('border', '1px solid #e0e0e0'); | |
| /* y gridlines */ | |
| function make_y_gridlines() { | |
| return d3.axisLeft(yScale) | |
| .ticks(5); | |
| } | |
| /* x axis */ | |
| svg.append('g') | |
| .attr('transform', `translate(${margin}, ${height + margin})`) | |
| .attr('color', '#333') | |
| .style('font-size', '14px') | |
| .call(d3.axisBottom(xScale)); | |
| svg | |
| .append('text') | |
| .attr('transform', `translate(${width + margin - word}, ${height + 1.5 * margin})`) | |
| .text(xLabel); | |
| /* y axis */ | |
| svg.append('g') | |
| .attr('transform', `translate(${margin}, ${margin})`) | |
| .attr('color', '#333') | |
| .style('font-size', '14px') | |
| .call(d3.axisLeft(yScale)); | |
| svg | |
| .append('text') | |
| .attr('x', margin - 2 * word) | |
| .attr('y', margin - 2 * word) | |
| .text(yLabel); | |
| svg | |
| .append('g') | |
| .attr('transform', `translate(${margin}, ${margin})`) | |
| .style('color', '#ddd') | |
| .call(make_y_gridlines() | |
| .tickSize(-width) | |
| .tickFormat('')); | |
| for (let i = 0; i < kvs.length; i++) { | |
| let kv = kvs[i]; | |
| svg.append('path') | |
| .attr('transform', `translate(${margin}, ${margin})`) | |
| .datum(kv) | |
| .style('stroke', colors[i]) | |
| .style('stroke-width', 2) | |
| .style('fill', 'none') | |
| .attr('d', lineGenerator); | |
| svg.selectAll(`circle._${i}`) | |
| .data(kv) | |
| .enter() | |
| .append('circle') | |
| .style('fill', '#fff') | |
| .style('stroke', colors[i]) | |
| .style('stroke-width', 1) | |
| .attr('transform', `translate(${margin}, ${margin})`) | |
| .attr('cx', d => xScale(d.key)) | |
| .attr('cy', d => yScale(d.value)) | |
| .attr('r', 3); | |
| } | |
| /* path animation */ | |
| /* todo mousemove handler */ | |
| const mousemoveHandler = () => { | |
| d3.event.preventDefault(); | |
| console.log('I\'m moving ...'); | |
| }; | |
| /* listen mousemove to add tooltip */ | |
| svg.on('mousemove', mousemoveHandler); | |
| } | |
| line( | |
| 'body', | |
| 320, | |
| ); | |
| </script> | |
| </body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment