const blocksConfig = { margin: {top: 8, right: 10, bottom: 2, left: 10}, fullWidth: 960, fullItemHeight: 69, textOffset: 6 } const layoutMaker = conf => { const width = conf.fullWidth - conf.margin.left - conf.margin.right const itemHeight = conf.fullItemHeight - conf.margin.top - conf.margin.bottom return { width: width, height: itemHeight, fullWidth: conf.fullWidth, fullItemHeight: conf.fullItemHeight, marginTranslate: [conf.margin.left, conf.margin.top], textAnchor: "end", // could eventually land in config textX: width - conf.textOffset, textY: itemHeight - conf.textOffset } } const layout = layoutMaker(blocksConfig) const type = d => Object.assign({}, d, { price: parseFloat(d.price), date: d3.time.format("%b %Y").parse(d.date) }) const timeAccessor = value => value.date const priceAccessor = value => value.price const svgTranslate = ([x, y]) => `translate(${x},${y})` const render = (data, rootElement) => { const itemContainer = rootElement.selectAll("svg") .data(data, s => s.key) .enter().append("svg") .attr("width", s => s.layout.fullWidth) .attr("height", s => s.layout.fullItemHeight) const item = itemContainer .append("g") .attr("transform", s => svgTranslate(s.layout.marginTranslate)) item.append("path") .classed("area", true) .attr("d", s => d3.svg.area() .x( d => s.xScale(s.xAccessor(d))) .y1(d => s.yScale(s.yAccessor(d))) .y0(s.layout.height) (s.values)) item.append("path") .classed("line", true) .attr("d", s => d3.svg.line() .x(d => s.xScale(s.xAccessor(d))) .y(d => s.yScale(s.yAccessor(d))) (s.values)) item.append("text") .attr("x", s => s.layout.textX) .attr("y", s => s.layout.textY) .style("text-anchor", s => s.layout.textAnchor) .text(s => s.key) } const start = () => d3.tsv("stocks.tsv", type, (error, inputData) => { const allDates = inputData.map(timeAccessor) const commonTimeScale = d3.time.scale() .range([0, layout.width]) .domain(d3.extent(allDates)) const symbols = d3.nest() .key(value => value.symbol) .entries(inputData) .map(nestEntry => Object.assign({}, nestEntry, { xAccessor: timeAccessor, yAccessor: priceAccessor, xScale: commonTimeScale, yScale: d3.scale.log() .domain(d3.extent(nestEntry.values, priceAccessor)) .range([layout.height, 0]), layout: layout })) render(symbols, d3.select("body")) })