* Register a new chart type.
*/
@register = (Subclass) ->
+ console.log "ChartType.register(#Subclass)"
KNOWN_CHART_TYPES[ Subclass::typeName ] = Subclass
/**
* @returns {ChartType}
*/
@create = (model, view) ->
+ console.log "ChartType.create(#model) ->", model
return null unless Type = @lookup model
new Type model, view
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
} = require 'kraken/util'
{ ChartType,
} = require 'kraken/chart/chart-type'
+{ D3ChartElement,
+} = require 'kraken/chart/type/d3/d3-chart-element'
+
root = do -> this
legend : '.graph-legend'
- # constructor: function D3ChartType
- -> super ...
-
+ -> super ...
+
getData: ->
@model.dataset.getColumns()
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
+++ /dev/null
-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
--- /dev/null
+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
+
--- /dev/null
+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
+
+
+
+++ /dev/null
-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
-
-
-
--- /dev/null
+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
+
+
+
+
+
-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
*
* @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
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
-exports = _fmt
+module.exports = exports = _fmt
- timeseries
- csv
- index
- - op
+ - op
- backbone
- parser
- cascade
+ - formatters
- index
- base:
- scaffold:
- 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