summaryrefslogtreecommitdiffstats
path: root/debian/missing-sources/epoch/src/basic/bar.coffee
diff options
context:
space:
mode:
Diffstat (limited to 'debian/missing-sources/epoch/src/basic/bar.coffee')
-rw-r--r--debian/missing-sources/epoch/src/basic/bar.coffee273
1 files changed, 273 insertions, 0 deletions
diff --git a/debian/missing-sources/epoch/src/basic/bar.coffee b/debian/missing-sources/epoch/src/basic/bar.coffee
new file mode 100644
index 0000000..8fbc427
--- /dev/null
+++ b/debian/missing-sources/epoch/src/basic/bar.coffee
@@ -0,0 +1,273 @@
+# Static bar chart implementation (using d3).
+class Epoch.Chart.Bar extends Epoch.Chart.Plot
+ defaults =
+ type: 'bar'
+ style: 'grouped'
+ orientation: 'vertical'
+ padding:
+ bar: 0.08
+ group: 0.1
+ outerPadding:
+ bar: 0.08
+ group: 0.1
+
+ horizontal_specific =
+ tickFormats:
+ top: Epoch.Formats.si
+ bottom: Epoch.Formats.si
+ left: Epoch.Formats.regular
+ right: Epoch.Formats.regular
+
+ horizontal_defaults = Epoch.Util.defaults(horizontal_specific, defaults)
+
+ optionListeners =
+ 'option:orientation': 'orientationChanged'
+ 'option:padding': 'paddingChanged'
+ 'option:outerPadding': 'paddingChanged'
+ 'option:padding:bar': 'paddingChanged'
+ 'option:padding:group': 'paddingChanged'
+ 'option:outerPadding:bar': 'paddingChanged'
+ 'option:outerPadding:group': 'paddingChanged'
+
+ constructor: (@options={}) ->
+ if @_isHorizontal()
+ @options = Epoch.Util.defaults(@options, horizontal_defaults)
+ else
+ @options = Epoch.Util.defaults(@options, defaults)
+ super(@options)
+ @onAll optionListeners
+ @draw()
+
+ # @return [Boolean] True if the chart is vertical, false otherwise
+ _isVertical: ->
+ @options.orientation == 'vertical'
+
+ # @return [Boolean] True if the chart is horizontal, false otherwise
+ _isHorizontal: ->
+ @options.orientation == 'horizontal'
+
+ # @return [Function] The scale used to generate the chart's x scale.
+ x: ->
+ if @_isVertical()
+ d3.scale.ordinal()
+ .domain(Epoch.Util.domain(@getVisibleLayers()))
+ .rangeRoundBands([0, @innerWidth()], @options.padding.group, @options.outerPadding.group)
+ else
+ extent = @extent((d) -> d.y)
+ extent[0] = Math.min(0, extent[0])
+ d3.scale.linear()
+ .domain(extent)
+ .range([0, @width - @margins.left - @margins.right])
+
+ # @return [Function] The x scale used to render the horizontal bar chart.
+ x1: (x0) ->
+ d3.scale.ordinal()
+ .domain((layer.category for layer in @getVisibleLayers()))
+ .rangeRoundBands([0, x0.rangeBand()], @options.padding.bar, @options.outerPadding.bar)
+
+ # @return [Function] The y scale used to render the bar chart.
+ y: ->
+ if @_isVertical()
+ extent = @extent((d) -> d.y)
+ extent[0] = Math.min(0, extent[0])
+ d3.scale.linear()
+ .domain(extent)
+ .range([@height - @margins.top - @margins.bottom, 0])
+ else
+ d3.scale.ordinal()
+ .domain(Epoch.Util.domain(@getVisibleLayers()))
+ .rangeRoundBands([0, @innerHeight()], @options.padding.group, @options.outerPadding.group)
+
+ # @return [Function] The x scale used to render the vertical bar chart.
+ y1: (y0) ->
+ d3.scale.ordinal()
+ .domain((layer.category for layer in @getVisibleLayers()))
+ .rangeRoundBands([0, y0.rangeBand()], @options.padding.bar, @options.outerPadding.bar)
+
+ # Remaps the bar chart data into a form that is easier to display.
+ # @return [Array] The reorganized data.
+ _remapData: ->
+ map = {}
+ for layer in @getVisibleLayers()
+ className = 'bar ' + layer.className.replace(/\s*layer\s*/, '')
+ for entry in layer.values
+ map[entry.x] ?= []
+ map[entry.x].push { label: layer.category, y: entry.y, className: className }
+ ({group: k, values: v} for own k, v of map)
+
+ # Draws the bar char.
+ draw: ->
+ if @_isVertical()
+ @_drawVertical()
+ else
+ @_drawHorizontal()
+ super()
+
+ # Draws the bar chart with a vertical orientation
+ _drawVertical: ->
+ [x0, y] = [@x(), @y()]
+ x1 = @x1(x0)
+ height = @height - @margins.top - @margins.bottom
+ data = @_remapData()
+
+ # 1) Join
+ layer = @g.selectAll(".layer")
+ .data(data, (d) -> d.group)
+
+ # 2) Update
+ layer.transition().duration(750)
+ .attr("transform", (d) -> "translate(#{x0(d.group)}, 0)")
+
+ # 3) Enter / Create
+ layer.enter().append("g")
+ .attr('class', 'layer')
+ .attr("transform", (d) -> "translate(#{x0(d.group)}, 0)")
+
+ rects = layer.selectAll('rect')
+ .data((group) -> group.values)
+
+ rects.attr('class', (d) -> d.className)
+
+ rects.transition().duration(600)
+ .attr('x', (d) -> x1(d.label))
+ .attr('y', (d) -> y(d.y))
+ .attr('width', x1.rangeBand())
+ .attr('height', (d) -> height - y(d.y))
+
+ rects.enter().append('rect')
+ .attr('class', (d) -> d.className)
+ .attr('x', (d) -> x1(d.label))
+ .attr('y', (d) -> y(d.y))
+ .attr('width', x1.rangeBand())
+ .attr('height', (d) -> height - y(d.y))
+
+ rects.exit().transition()
+ .duration(150)
+ .style('opacity', '0')
+ .remove()
+
+ # 4) Update new and existing
+
+ # 5) Exit / Remove
+ layer.exit()
+ .transition()
+ .duration(750)
+ .style('opacity', '0')
+ .remove()
+
+ # Draws the bar chart with a horizontal orientation
+ _drawHorizontal: ->
+ [x, y0] = [@x(), @y()]
+ y1 = @y1(y0)
+ width = @width - @margins.left - @margins.right
+ data = @_remapData()
+
+ # 1) Join
+ layer = @g.selectAll(".layer")
+ .data(data, (d) -> d.group)
+
+ # 2) Update
+ layer.transition().duration(750)
+ .attr("transform", (d) -> "translate(0, #{y0(d.group)})")
+
+ # 3) Enter / Create
+ layer.enter().append("g")
+ .attr('class', 'layer')
+ .attr("transform", (d) -> "translate(0, #{y0(d.group)})")
+
+ rects = layer.selectAll('rect')
+ .data((group) -> group.values)
+
+ rects.attr('class', (d) -> d.className)
+
+ rects.transition().duration(600)
+ .attr('x', (d) -> 0)
+ .attr('y', (d) -> y1(d.label))
+ .attr('height', y1.rangeBand())
+ .attr('width', (d) -> x(d.y))
+
+ rects.enter().append('rect')
+ .attr('class', (d) -> d.className)
+ .attr('x', (d) -> 0)
+ .attr('y', (d) -> y1(d.label))
+ .attr('height', y1.rangeBand())
+ .attr('width', (d) -> x(d.y))
+
+ rects.exit().transition()
+ .duration(150)
+ .style('opacity', '0')
+ .remove()
+
+ # 4) Update new and existing
+
+ # 5) Exit / Remove
+ layer.exit()
+ .transition()
+ .duration(750)
+ .style('opacity', '0')
+ .remove()
+
+ # Generates specific tick marks to emulate d3's linear scale axis ticks
+ # for ordinal scales. Note: this should only be called if the user has
+ # defined a set number of ticks for a given axis.
+ # @param [Number] numTicks Number of ticks to generate
+ # @param [String] dataKey Property name of a datum to use for the tick value
+ # @return [Array] The ticks for the given axis
+ _getTickValues: (numTicks, dataKey='x') ->
+ return [] unless @data[0]?
+ total = @data[0].values.length
+ step = Math.ceil(total / numTicks)|0
+ tickValues = (@data[0].values[i].x for i in [0...total] by step)
+
+ # @return [Function] d3 axis to use for the bottom of the visualization.
+ bottomAxis: ->
+ axis = d3.svg.axis().scale(@x()).orient('bottom')
+ .ticks(@options.ticks.bottom)
+ .tickFormat(@options.tickFormats.bottom)
+ if @_isVertical() and @options.ticks.bottom?
+ axis.tickValues @_getTickValues(@options.ticks.bottom)
+ axis
+
+ # @return [Function] d3 axis to use for the top of the visualization.
+ topAxis: ->
+ axis = d3.svg.axis().scale(@x()).orient('top')
+ .ticks(@options.ticks.top)
+ .tickFormat(@options.tickFormats.top)
+ if @_isVertical() and @options.ticks.top?
+ axis.tickValues @_getTickValues(@options.ticks.top)
+ axis
+
+ # @return [Function] d3 axis to use on the left of the visualization.
+ leftAxis: ->
+ axis = d3.svg.axis().scale(@y()).orient('left')
+ .ticks(@options.ticks.left)
+ .tickFormat(@options.tickFormats.left)
+ if @_isHorizontal() and @options.ticks.left?
+ axis.tickValues @_getTickValues(@options.ticks.left)
+ axis
+
+ # @return [Function] d3 axis to use on the right of the visualization.
+ rightAxis: ->
+ axis = d3.svg.axis().scale(@y()).orient('right')
+ .ticks(@options.ticks.right)
+ .tickFormat(@options.tickFormats.right)
+ if @_isHorizontal() and @options.ticks.right?
+ axis.tickValues @_getTickValues(@options.ticks.right)
+ axis
+
+ # Updates orientation in response <code>option:orientation</code>.
+ orientationChanged: ->
+ top = @options.tickFormats.top
+ bottom = @options.tickFormats.bottom
+ left = @options.tickFormats.left
+ right = @options.tickFormats.right
+
+ @options.tickFormats.left = top
+ @options.tickFormats.right = bottom
+ @options.tickFormats.top = left
+ @options.tickFormats.bottom = right
+
+ @draw()
+
+ # Updates padding in response to <code>option:padding:*</code> and <code>option:outerPadding:*</code>.
+ paddingChanged: -> @draw()