From: declerambaul Date: Wed, 27 Jun 2012 16:41:05 +0000 (+0200) Subject: Created a D3ChartType ChartType, abstracting the different d3 elements (line,bar... X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=ff573ae0f2e77e96a3bb08ef9e611309b09309a4;p=limn.git Created a D3ChartType ChartType, abstracting the different d3 elements (line,bar) as subclasses of D3ChartElement. --- diff --git a/lib/chart/chart-type.co b/lib/chart/chart-type.co index 2030a90..1aa4b9e 100644 --- a/lib/chart/chart-type.co +++ b/lib/chart/chart-type.co @@ -38,6 +38,7 @@ class exports.ChartType extends ReadyEmitter * Register a new chart type. */ @register = (Subclass) -> + console.log "ChartType.register(#Subclass)" KNOWN_CHART_TYPES[ Subclass::typeName ] = Subclass /** @@ -53,6 +54,7 @@ class exports.ChartType extends ReadyEmitter * @returns {ChartType} */ @create = (model, view) -> + console.log "ChartType.create(#model) ->", model return null unless Type = @lookup model new Type model, view diff --git a/lib/chart/index.co b/lib/chart/index.co index a961cba..c5fd1e2 100644 --- a/lib/chart/index.co +++ b/lib/chart/index.co @@ -1,7 +1,8 @@ chart_type = require 'kraken/chart/chart-type' chart_option = require 'kraken/chart/option' dygraphs = require 'kraken/chart/type/dygraphs' -d3_charts = require 'kraken/chart/type/d3' +d3_chart = require 'kraken/chart/type/d3-chart' +d3_elements = require 'kraken/chart/type/d3' exports import chart_type import chart_option \ - import dygraphs import d3_charts + import dygraphs import d3_chart import d3_elements diff --git a/lib/chart/type/d3/d3-chart-type.co b/lib/chart/type/d3-chart.co similarity index 84% rename from lib/chart/type/d3/d3-chart-type.co rename to lib/chart/type/d3-chart.co index 8f73c54..99d0b6d 100644 --- a/lib/chart/type/d3/d3-chart-type.co +++ b/lib/chart/type/d3-chart.co @@ -5,6 +5,9 @@ ColorBrewer = require 'colorbrewer' } = require 'kraken/util' { ChartType, } = require 'kraken/chart/chart-type' +{ D3ChartElement, +} = require 'kraken/chart/type/d3/d3-chart-element' + root = do -> this @@ -28,11 +31,10 @@ class exports.D3ChartType extends ChartType legend : '.graph-legend' - # constructor: function D3ChartType - -> super ... - + -> super ... + getData: -> @model.dataset.getColumns() @@ -101,18 +103,24 @@ class exports.D3ChartType extends ChartType frame.select ".x.axis.time" .attr "transform", "translate(0,#{yScale.range()[0]})" .call xAxis - + + + + # this is wrong. should work using d3 datajoins. + # i.e. use the enter/exit function to add/remove + # metrics from the graph for i,metric in @model.dataset.metrics.models # metric defined charttype - chartType = metric.get "chartType" + chartElement = metric.get "chartElement" # otherwise the graph defined charttype # FOR NOW take line as default - chartType or= 'd3-line' # @model.get "chartType" + chartElement ?= 'd3-line' # @model.get "chartType" - # create d3 charttype and render it - model = ChartType.create chartType - model.renderChartType metric, frame ,xScale, yScale + # create d3 chart element and render it + chEl = D3ChartElement.create chartElement + console.log chEl + chEl.renderChartElement metric, frame ,xScale, yScale svg diff --git a/lib/chart/type/d3/d3-bar-chart-type.co b/lib/chart/type/d3/d3-bar-chart-type.co deleted file mode 100644 index 0a257ff..0000000 --- a/lib/chart/type/d3/d3-bar-chart-type.co +++ /dev/null @@ -1,241 +0,0 @@ -d3 = require 'd3' - -{ _, op, -} = require 'kraken/util' -{ ChartType, -} = require 'kraken/chart/chart-type' - -root = do -> this - - -class exports.BarChartType extends ChartType - __bind__ : <[ determineSize ]> - SPEC_URL : '/schema/d3/d3-bar.json' - - # NOTE: ChartType.register() must come AFTER `typeName` declaration. - typeName : 'd3-bar' - ChartType.register this - - - /** - * Hash of role-names to the selector which, when applied to the view, - * returns the correct element. - * @type Object - */ - roles : - viewport : '.viewport' - legend : '.graph-legend' - - - -> super ... - - getData: -> - @model.dataset.getColumns() - - - transform: -> - dataset = @model.dataset - options = @model.getOptions() import @determineSize() - options import do - colors : dataset.getColors() - labels : dataset.getLabels() - options - - - renderChartType: (metric, svgEl ,xScale, yScale) -> - - X = (d, i) -> xScale d[0] - Y = (d, i) -> yScale d[1] - - - ### Render the line path - metricBars = root.metricBars = svgEl.append "g" - .attr "class", "metric bars "+metric.get 'label' - - data = d3.zip metric.getDateColumn(),metric.getData() - - ### Render Bars - barWidth = svgEl.attr('width')/data.length - barHeight = (d) -> svgEl.attr('height')-Y(d) - - metricBars.selectAll "bar" - .data data - .enter().append "rect" - .attr "class", (d, i) -> "metric bar #i" - .attr "x", X - .attr "y", Y - .attr "height", barHeight - .attr "width", -> barWidth - .attr "fill", metric.get 'color' - .attr "stroke", "white" - .style "opacity", "0.4" - .style "z-index", -10 - - - # adding event listeners - chT = this - metricBars.selectAll ".metric.bar" - .on "mouseover", (d, i) -> - - svgEl.append "text" - .attr "class", "mf" - .attr "dx", 50 - .attr "dy", 100 - .style "font-size", "0px" - .transition() - .duration(800) - .text "Uh boy, the target would be: "+chT.numberFormatter(d[1]).toString() - .style "font-size", "25px" - .on "mouseout", (d, i) -> - - svgEl.selectAll ".mf" - .transition() - .duration(300) - .text "BUMMER!!!" - .style "font-size", "0px" - .remove() - - - - svgEl - - renderChart: (data, viewport, options, lastChart) -> - ### Starting with http://bost.ocks.org/mike/chart/ - - margin = {top: 20, right: 20, bottom: 20, left: 20} - width = 760 - height = 320 - xScale = d3.time.scale() - yScale = d3.scale.linear() - - dates = data[0] - cols = data.slice(1) - - # Calculate extents using all the data points (but not dates) - # allValues = d3.merge @model.dataset.getDataColumns() - allValues = d3.merge cols - - - # Update the x-scale with the extents of the dates. - xScale - .domain d3.extent dates - .range [ 0, width - margin.left - margin.right ] - - # Update the y-scale with the extents of the data. - yScale - .domain d3.extent allValues - .range [ height - margin.top - margin.bottom, 0 ] - - # Select the svg element, if it exists. - svg = d3.select viewport.0 .selectAll "svg" - .data [cols] - - # ...Otherwise, create the skeletal chart. - enterFrame = svg.enter() - .append "svg" .append "g" - .attr "class", "frame" - enterFrame.append "g" - .attr "class", "x axis time" - - # Update chart dimensions. - svg .attr "width", width - .attr "height", height - frame = svg.select "g.frame" - .attr "transform", "translate(#{margin.left},#{margin.top})" - - # Update the x-axis. - xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(6, 0) - frame.select ".x.axis.time" - .attr "transform", "translate(0,#{yScale.range()[0]})" - .call xAxis - - X = (d, i) -> xScale d[0] - Y = (d, i) -> yScale d[1] - - ### Render Bars - barWidth = svg.attr('width')/dates.length - barHeight = (d) -> svg.attr('height')-Y(d) - - bars = frame.selectAll "g.bars" - .data cols.map -> d3.zip dates, it - bars.enter().append "g" - .attr "class", (col, i) -> "metric bars #i" - bars.exit().remove() - - bars.selectAll ".bar" - .data op.first - .enter().append "rect" - .attr "class", "bar" - .attr "x", X - .attr "y", Y - .attr "height", barHeight - .attr "width", -> barWidth - # TODO grab color from graph spec - .attr "fill", "red" - .attr "stroke", "white" - - - ### Mouse Lens - lens = root.lens = frame.selectAll "g.lens" - .data [[]] - gLens = lens.enter().append "g" - .attr "class", "lens" - .style "z-index", 1e9 - gInner = gLens.append "g" - .attr "transform", "translate(1.5em,0)" - gInner.append "circle" - .attr "r", "1.5em" - # .style "opacity", "0.4" - # .style "fill", "white" - .style "fill", "rgba(255, 255, 255, 0.4)" - .style "stroke", "white" - .style "stroke-width", "3px" - gInner.append "text" - .attr "y", "0.5em" - .attr "text-anchor", "middle" - .style "fill", "white" - .style "font", "12px Helvetica" - .style "font-weight", "bold" - - - mf = frame.selectAll "g.mf" - .data ["mf"] - .enter().append "g" - .attr "class", "mf" - .append "text" - .attr "class", "yoyo" - .attr "dx", 50 - .attr "dy", 100 - - - - bars.selectAll ".bar" - .on "mouseover", (d, i) -> - el = root.el = el # DOM element of event - # {r,g,b} = color = d3.rgb options.colors[i] - mf - .transition() - .duration(300) - .ease("exp") - .text "Uh boy, the target would be:"+d[1] - .style "font-size", "25px" - - - .on "mouseout", (d, i) -> - mf - .transition() - .duration(1000) - .text "BUMMER!!!" - .style "font-size", "0px" - - - - # {x:lineX, y:lineY} = root.pt = line.indexToPoint idx - # lens = frame.select "g.lens" - # .attr "transform", "translate(#lineX, #lineY)" - # lens.select "circle" .style "fill", "rgba(#r, #g, #b, 0.4)" - # lens.select "text" .text Y - - - - svg diff --git a/lib/chart/type/d3/d3-bar-element.co b/lib/chart/type/d3/d3-bar-element.co new file mode 100644 index 0000000..dcb300a --- /dev/null +++ b/lib/chart/type/d3/d3-bar-element.co @@ -0,0 +1,78 @@ +d3 = require 'd3' + +{ _, op, +} = require 'kraken/util' +{ D3ChartElement +} = require 'kraken/chart/type/d3/d3-chart-element' + +_fmt = require 'kraken/util/formatters' + +root = do -> this + +class exports.BarChartType extends D3ChartElement + __bind__ : <[ ]> + SPEC_URL : '/schema/d3/d3-bar.json' + + # NOTE: D3ChartElement.register() must come AFTER `typeName` declaration. + chartElement : 'd3-bar' + D3ChartElement.register this + + -> super ... + + renderChartElement: (metric, svgEl ,xScale, yScale) -> + + X = (d, i) -> xScale d[0] + Y = (d, i) -> yScale d[1] + + + ### Render the line path + metricBars = root.metricBars = svgEl.append "g" + .attr "class", "metric bars "+metric.get 'label' + + data = d3.zip metric.getDateColumn(),metric.getData() + + ### Render Bars + barWidth = svgEl.attr('width')/data.length + barHeight = (d) -> svgEl.attr('height')-Y(d) + + metricBars.selectAll "bar" + .data data + .enter().append "rect" + .attr "class", (d, i) -> "metric bar #i" + .attr "x", X + .attr "y", Y + .attr "height", barHeight + .attr "width", -> barWidth + .attr "fill", metric.get 'color' + .attr "stroke", "white" + .style "opacity", "0.4" + .style "z-index", -10 + + + # adding event listeners + chT = this + metricBars.selectAll ".metric.bar" + .on "mouseover", (d, i) -> + + svgEl.append "text" + .attr "class", "mf" + .attr "dx", 50 + .attr "dy", 100 + .style "font-size", "0px" + .transition() + .duration(800) + .text "Uh boy, the target would be: "+_fmt.numberFormatter(d[1]).toString() + .style "font-size", "25px" + .on "mouseout", (d, i) -> + + svgEl.selectAll ".mf" + .transition() + .duration(300) + .text "BUMMER!!!" + .style "font-size", "0px" + .remove() + + + + svgEl + diff --git a/lib/chart/type/d3/d3-chart-element.co b/lib/chart/type/d3/d3-chart-element.co new file mode 100644 index 0000000..bc93ed1 --- /dev/null +++ b/lib/chart/type/d3/d3-chart-element.co @@ -0,0 +1,79 @@ +d3 = require 'd3' +ColorBrewer = require 'colorbrewer' + +{ _, op, +} = require 'kraken/util' +{ ReadyEmitter, +} = require 'kraken/util/event' +# Base = require 'kraken/base/base' + + +root = do -> this + +/** + * Map of known libraries by name. + * @type Object + */ +KNOWN_CHART_ELEMENTS = exports.KNOWN_CHART_ELEMENTS = {} + +class exports.D3ChartElement extends ReadyEmitter + __bind__ : <[ ]> + SPEC_URL : '/schema/d3/d3-chart.json' + + + ### Class Methods + + /** + * Register a new d3 element + */ + @register = (Subclass) -> + console.log "D3ChartElement.register(#Subclass)" + KNOWN_CHART_ELEMENTS[ Subclass::chartElement ] = Subclass + + /** + * Look up a `charttype` by `typeName`. + */ + @lookup = (name) -> + name = name.get('chartElement') if name instanceof Backbone.Model + KNOWN_CHART_ELEMENTS[name] + + /** + * Look up a chart type by name, returning a new instance + * with the given model (and, optionally, view). + * @returns {D3ChartElement} + */ + @create = (name) -> + console.log "D3ChartElement.create(#name)" + return null unless Type = @lookup name + + new Type + + + () -> + _.bindAll this, ...@__bind__ # TODO: roll up MRO + @loadSpec() unless @ready + super ... + + + + /** + * Load the corresponding chart specification, which includes + * info about valid options, along with their types and defaults. + */ + loadSpec: -> + return this if @ready + proto = @constructor:: + jQuery.ajax do + url : @SPEC_URL + dataType : 'json' + success : (spec) ~> + proto.spec = spec + proto.options_ordered = spec + proto.options = _.synthesize spec, -> [it.name, it] + proto.ready = true + @triggerReady() + error: ~> console.error "Error loading #{@typeName} spec! #it" + this + + + diff --git a/lib/chart/type/d3/d3-geo-chart-type.co b/lib/chart/type/d3/d3-geo-element.co similarity index 100% rename from lib/chart/type/d3/d3-geo-chart-type.co rename to lib/chart/type/d3/d3-geo-element.co diff --git a/lib/chart/type/d3/d3-line-chart-type.co b/lib/chart/type/d3/d3-line-chart-type.co deleted file mode 100644 index e0974f7..0000000 --- a/lib/chart/type/d3/d3-line-chart-type.co +++ /dev/null @@ -1,255 +0,0 @@ -d3 = require 'd3' -ColorBrewer = require 'colorbrewer' - -{ _, op, -} = require 'kraken/util' -{ ChartType, -} = require 'kraken/chart/chart-type' - -root = do -> this - - -class exports.LineChartType extends ChartType - __bind__ : <[ determineSize ]> - SPEC_URL : '/schema/d3/d3-line.json' - - # NOTE: ChartType.register() must come AFTER `typeName` declaration. - typeName : 'd3-line' - ChartType.register this - - - /** - * Hash of role-names to the selector which, when applied to the view, - * returns the correct element. - * @type Object - */ - roles : - viewport : '.viewport' - legend : '.graph-legend' - - - -> super ... - - - getData: -> - @model.dataset.getColumns() - - - transform: -> - dataset = @model.dataset - options = @model.getOptions() import @determineSize() - options import do - colors : dataset.getColors() - labels : dataset.getLabels() - options - - renderChartType: (metric, svgEl ,xScale, yScale) -> - - X = (d, i) -> xScale d[0] - Y = (d, i) -> yScale d[1] - line = d3.svg.line().x(X).y(Y) - - ### Render the line path - metricLine = root.metricLine = svgEl.append "g" - .attr "class", "g metric line "+metric.get 'label' - - data = d3.zip metric.getDateColumn(),metric.getData() - - metricLine.selectAll "path.line" - .data d3.zip data.slice(0,-1), data.slice(1) - .enter().append "path" - .attr "d", line - .attr "class", (d, i) -> "metric line segment #i" - .style "stroke", metric.get 'color' - - - ### Mouse Lens - lens = root.lens = svgEl.selectAll "g.lens" - .data [[]] - gLens = lens.enter().append "g" - .attr "class", "lens" - .style "z-index", 1e9 - gInner = gLens.append "g" - .attr "transform", "translate(1.5em,0)" - gInner.append "circle" - .attr "r", "1.5em" - # .style "opacity", "0.4" - # .style "fill", "white" - .style "fill", "rgba(255, 255, 255, 0.4)" - .style "stroke", "white" - .style "stroke-width", "3px" - gInner.append "text" - .attr "y", "0.5em" - .attr "text-anchor", "middle" - .style "fill", "black" - .style "font", "12px Helvetica" - .style "font-weight", "bold" - - # event listeners - chT = this - metricLine.selectAll ".line.segment" - .on "mouseover", (d, i) -> - - {r,g,b} = color = d3.rgb metric.get 'color' - lineX = (X(d[0])+X(d[1]))/2 - lineY = (Y(d[0])+Y(d[1]))/2 - - - lens = svgEl.select "g.lens" - .attr "transform", "translate(#lineX, #lineY)" - lens.select "circle" .style "fill", "rgba(#r, #g, #b, 0.4)" - lens.select "text" .text -> chT.numberFormatter(d[0][1]).toString() - - - svgEl - - - renderChart: (data, viewport, options, lastChart) -> - ### Starting with http://bost.ocks.org/mike/chart/ - - margin = {top: 20, right: 20, bottom: 20, left: 20} - width = 760 - height = 320 - xScale = d3.time.scale() - yScale = d3.scale.linear() - - dates = data[0] - cols = data.slice(1) - - # Calculate extents using all the data points (but not dates) - # allValues = d3.merge @model.dataset.getDataColumns() - allValues = d3.merge cols - - - # Update the x-scale with the extents of the dates. - xScale - .domain d3.extent dates - .range [ 0, width - margin.left - margin.right ] - - # Update the y-scale with the extents of the data. - yScale - .domain d3.extent allValues - .range [ height - margin.top - margin.bottom, 0 ] - - # Select the svg element, if it exists. - svg = d3.select viewport.0 .selectAll "svg" - .data [cols] - - # ...Otherwise, create the skeletal chart. - enterFrame = svg.enter() - .append "svg" .append "g" - .attr "class", "frame" - enterFrame.append "g" - .attr "class", "x axis time" - - # Update chart dimensions. - svg .attr "width", width - .attr "height", height - frame = svg.select "g.frame" - .attr "transform", "translate(#{margin.left},#{margin.top})" - - # Update the x-axis. - xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(6, 0) - frame.select ".x.axis.time" - .attr "transform", "translate(0,#{yScale.range()[0]})" - .call xAxis - - - ### Render the line paths - lines = root.lines = frame.selectAll "path.line" - .data cols.map -> d3.zip dates, it - lines.enter().append "path" - .attr "class", "metric line" - lines.exit().remove() - - X = (d, i) -> xScale d[0] - Y = (d, i) -> yScale d[1] - line = d3.svg.line().x(X).y(Y) - lines.attr "d", line - .attr "class", (col, i) -> "metric line metric#i" - .style "stroke", (col, i) -> options.colors[i] - .each (col, i) -> - {width} = bbox = @getBBox() - # Add line-to-data position conversions - @indexAtX = d3.scale.quantize() - .domain [0, width] - .range d3.range col.length - @indexToPoint = (idx) -> - @pathSegList.getItem idx - - ### Render Points - points = frame.selectAll "g.points" - .data cols - points.enter().append "g" - .attr "class", (col, i) -> "points points#i" - .property "line", (col, i) -> $(this).parent().find('path.metric.line')[i] - points.exit().remove() - - points.selectAll ".point" - .data op.first - .enter().append "circle" - .attr "class", "point" - .attr "r", "2px" - .property "line", -> $ this .parentsUntil('svg', 'g')[0].line - .style "fill", -> $ this.line .css 'stroke' - .attr "transform", (d, i) -> - {x,y} = @line.indexToPoint i - "translate(#x, #y)" - - - ### Mouse Lens - lens = root.lens = frame.selectAll "g.lens" - .data [[]] - gLens = lens.enter().append "g" - .attr "class", "lens" - .style "z-index", 1e9 - gInner = gLens.append "g" - .attr "transform", "translate(1.5em,0)" - gInner.append "circle" - .attr "r", "1.5em" - # .style "opacity", "0.4" - # .style "fill", "white" - .style "fill", "rgba(255, 255, 255, 0.4)" - .style "stroke", "white" - .style "stroke-width", "3px" - gInner.append "text" - .attr "y", "0.5em" - .attr "text-anchor", "middle" - .style "fill", "white" - .style "font", "12px Helvetica" - .style "font-weight", "bold" - - lines.on "mouseover", (col, i) -> - line = root.line = this # DOM element of event - {r,g,b} = color = d3.rgb options.colors[i] - - # quantize mouse x-location to get for closest data-point (index into data array) - [x,y] = root.pos = d3.mouse line - idx = root.idx = line.indexAtX x - {x:lineX, y:lineY} = root.pt = line.indexToPoint idx - - lens = frame.select "g.lens" - .attr "transform", "translate(#lineX, #lineY)" - lens.select "circle" .style "fill", "rgba(#r, #g, #b, 0.4)" - lens.select "text" .text -> col[idx][1] - - - points.on "mouseover", (d, i) -> - line = root.line = this.line # this is the DOM element of point - {r,g,b} = color = d3.rgb options.colors[i] - - # quantize mouse x-location to get for closest data-point (index into data array) - [x,y] = root.pos = d3.mouse line - idx = root.idx = line.indexAtX x - {x:lineX, y:lineY} = root.pt = line.indexToPoint idx - - lens = frame.select "g.lens" - .attr "transform", "translate(#lineX, #lineY)" - lens.select "circle" .style "fill", "rgba(#r, #g, #b, 0.4)" - lens.select "text" .text -> d[idx] - - - svg - - - diff --git a/lib/chart/type/d3/d3-line-element.co b/lib/chart/type/d3/d3-line-element.co new file mode 100644 index 0000000..aad93d9 --- /dev/null +++ b/lib/chart/type/d3/d3-line-element.co @@ -0,0 +1,84 @@ +d3 = require 'd3' +ColorBrewer = require 'colorbrewer' + +{ _, op, +} = require 'kraken/util' +{ D3ChartElement +} = require 'kraken/chart/type/d3/d3-chart-element' + +_fmt = require 'kraken/util/formatters' + +root = do -> this + +class exports.LineChartElement extends D3ChartElement + __bind__ : <[ ]> + SPEC_URL : '/schema/d3/d3-line.json' + + # NOTE: D3ChartElement.register() must come AFTER `typeName` declaration. + chartElement : 'd3-line' + D3ChartElement.register this + + -> super ... + + renderChartElement: (metric, svgEl ,xScale, yScale) -> + + X = (d, i) -> xScale d[0] + Y = (d, i) -> yScale d[1] + line = d3.svg.line().x(X).y(Y) + + ### Render the line path + metricLine = root.metricLine = svgEl.append "g" + .attr "class", "g metric line "+metric.get 'label' + + data = d3.zip metric.getDateColumn(),metric.getData() + + metricLine.selectAll "path.line" + .data d3.zip data.slice(0,-1), data.slice(1) + .enter().append "path" + .attr "d", line + .attr "class", (d, i) -> "metric line segment #i" + .style "stroke", metric.get 'color' + + + ### Mouse Lens + lens = root.lens = svgEl.selectAll "g.lens" + .data [[]] + gLens = lens.enter().append "g" + .attr "class", "lens" + .style "z-index", 1e9 + gInner = gLens.append "g" + .attr "transform", "translate(1.5em,0)" + gInner.append "circle" + .attr "r", "1.5em" + # .style "opacity", "0.4" + # .style "fill", "white" + .style "fill", "rgba(255, 255, 255, 0.4)" + .style "stroke", "white" + .style "stroke-width", "3px" + gInner.append "text" + .attr "y", "0.5em" + .attr "text-anchor", "middle" + .style "fill", "black" + .style "font", "12px Helvetica" + .style "font-weight", "bold" + + # event listeners + metricLine.selectAll ".line.segment" + .on "mouseover", (d, i) -> + + {r,g,b} = color = d3.rgb metric.get 'color' + lineX = (X(d[0])+X(d[1]))/2 + lineY = (Y(d[0])+Y(d[1]))/2 + + + lens = svgEl.select "g.lens" + .attr "transform", "translate(#lineX, #lineY)" + lens.select "circle" .style "fill", "rgba(#r, #g, #b, 0.4)" + lens.select "text" .text -> _fmt.numberFormatter(d[0][1]).toString() + + svgEl + + + + + diff --git a/lib/chart/type/d3/index.co b/lib/chart/type/d3/index.co index 3baf40d..a18badd 100644 --- a/lib/chart/type/d3/index.co +++ b/lib/chart/type/d3/index.co @@ -1,6 +1,6 @@ -d3chart = require 'kraken/chart/type/d3/d3-chart-type' -line = require 'kraken/chart/type/d3/d3-line-chart-type' -bar = require 'kraken/chart/type/d3/d3-bar-chart-type' -# geo = require 'kraken/chart/type/d3/d3-geo-chart-type' +d3chart = require 'kraken/chart/type/d3/d3-chart-element' +line = require 'kraken/chart/type/d3/d3-line-element' +bar = require 'kraken/chart/type/d3/d3-bar-element' +# geo = require 'kraken/chart/type/d3/d3-geo-element' exports import line import bar import d3chart # import geo diff --git a/lib/util/formatters.co b/lib/util/formatters.co index b30650c..f2c3b95 100644 --- a/lib/util/formatters.co +++ b/lib/util/formatters.co @@ -30,10 +30,17 @@ _fmt = do * * @param {Number} n Number to format. * @param {Number} [digits=2] Number of digits after the decimal to always display. - * @returns {String} Formatted number. + * @param {Boolean} [abbrev=true] Expand number suffixes if false. + * @returns {Object} Formatted number parts. */ - _numberFormatter: (n, digits=2) -> - for [suffix, d] of [['B', 1000000000], ['M', 1000000], ['K', 1000], ['', NaN]] + numberFormatter: (n, digits=2, abbrev=true) -> + suffixes = do + if abbrev + [['B', 1000000000], ['M', 1000000], ['K', 1000], ['', NaN]] + else + [['Billion', 1000000000], ['Million', 1000000], ['', NaN]] + + for [suffix, d] of suffixes break if isNaN d if n >= d n = n / d @@ -42,12 +49,9 @@ _fmt = do parts = s.split '.' whole = _.rchop parts[0], 3 .join ',' fraction = '.' + parts.slice(1).join '.' - { n, digits, whole, fraction, suffix } - - - numberFormatter: (n, digits=2) -> - { whole, fraction, suffix } = _fmt._numberFormatter n, digits - "#whole#fraction#suffix" + { n, digits, whole, fraction, suffix, toString: -> + "#{@whole}#{@fraction}#{if abbrev then '' else ' '}#{@suffix}" + } numberFormatterHTML: (n, digits=2) -> { whole, fraction, suffix } = _fmt._numberFormatter n, digits @@ -61,4 +65,4 @@ _fmt = do -exports = _fmt +module.exports = exports = _fmt diff --git a/www/modules.yaml b/www/modules.yaml index 64c93c2..0f884a3 100644 --- a/www/modules.yaml +++ b/www/modules.yaml @@ -80,10 +80,11 @@ dev: - timeseries - csv - index - - op + - op - backbone - parser - cascade + - formatters - index - base: - scaffold: @@ -112,11 +113,12 @@ dev: - index - type: - d3: - - d3-chart-type - - d3-line-chart-type - - d3-bar-chart-type + - d3-chart-element + - d3-line-element + - d3-bar-element # - d3-geo-chart-type - index + - d3-chart - dygraphs - index - chart-type