You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			209 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			CoffeeScript
		
	
			
		
		
	
	
			209 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			CoffeeScript
		
	
class Morris.Bar extends Morris.Grid
 | 
						|
  constructor: (options) ->
 | 
						|
    return new Morris.Bar(options) unless (@ instanceof Morris.Bar)
 | 
						|
    super($.extend {}, options, parseTime: false)
 | 
						|
 | 
						|
  init: ->
 | 
						|
    @cumulative = @options.stacked
 | 
						|
 | 
						|
    if @options.hideHover isnt 'always'
 | 
						|
      @hover = new Morris.Hover(parent: @el)
 | 
						|
      @on('hovermove', @onHoverMove)
 | 
						|
      @on('hoverout', @onHoverOut)
 | 
						|
      @on('gridclick', @onGridClick)
 | 
						|
 | 
						|
  # Default configuration
 | 
						|
  #
 | 
						|
  defaults:
 | 
						|
    barSizeRatio: 0.75
 | 
						|
    barGap: 3
 | 
						|
    barColors: [
 | 
						|
      '#0b62a4'
 | 
						|
      '#7a92a3'
 | 
						|
      '#4da74d'
 | 
						|
      '#afd8f8'
 | 
						|
      '#edc240'
 | 
						|
      '#cb4b4b'
 | 
						|
      '#9440ed'
 | 
						|
    ],
 | 
						|
    barOpacity: 1.0
 | 
						|
    barRadius: [0, 0, 0, 0]
 | 
						|
    xLabelMargin: 50
 | 
						|
 | 
						|
  # Do any size-related calculations
 | 
						|
  #
 | 
						|
  # @private
 | 
						|
  calc: ->
 | 
						|
    @calcBars()
 | 
						|
    if @options.hideHover is false
 | 
						|
      @hover.update(@hoverContentForRow(@data.length - 1)...)
 | 
						|
 | 
						|
  # calculate series data bars coordinates and sizes
 | 
						|
  #
 | 
						|
  # @private
 | 
						|
  calcBars: ->
 | 
						|
    for row, idx in @data
 | 
						|
      row._x = @left + @width * (idx + 0.5) / @data.length
 | 
						|
      row._y = for y in row.y
 | 
						|
        if y? then @transY(y) else null
 | 
						|
 | 
						|
  # Draws the bar chart.
 | 
						|
  #
 | 
						|
  draw: ->
 | 
						|
    @drawXAxis() if @options.axes in [true, 'both', 'x']
 | 
						|
    @drawSeries()
 | 
						|
 | 
						|
  # draw the x-axis labels
 | 
						|
  #
 | 
						|
  # @private
 | 
						|
  drawXAxis: ->
 | 
						|
    # draw x axis labels
 | 
						|
    ypos = @bottom + (@options.xAxisLabelTopPadding || @options.padding / 2)
 | 
						|
    prevLabelMargin = null
 | 
						|
    prevAngleMargin = null
 | 
						|
    for i in [0...@data.length]
 | 
						|
      row = @data[@data.length - 1 - i]
 | 
						|
      label = @drawXAxisLabel(row._x, ypos, row.label)
 | 
						|
      textBox = label.getBBox()
 | 
						|
      label.transform("r#{-@options.xLabelAngle}")
 | 
						|
      labelBox = label.getBBox()
 | 
						|
      label.transform("t0,#{labelBox.height / 2}...")
 | 
						|
      if @options.xLabelAngle != 0
 | 
						|
        offset = -0.5 * textBox.width *
 | 
						|
          Math.cos(@options.xLabelAngle * Math.PI / 180.0)
 | 
						|
        label.transform("t#{offset},0...")
 | 
						|
      # try to avoid overlaps
 | 
						|
      if (not prevLabelMargin? or
 | 
						|
          prevLabelMargin >= labelBox.x + labelBox.width or
 | 
						|
          prevAngleMargin? and prevAngleMargin >= labelBox.x) and
 | 
						|
         labelBox.x >= 0 and (labelBox.x + labelBox.width) < @el.width()
 | 
						|
        if @options.xLabelAngle != 0
 | 
						|
          margin = 1.25 * @options.gridTextSize /
 | 
						|
            Math.sin(@options.xLabelAngle * Math.PI / 180.0)
 | 
						|
          prevAngleMargin = labelBox.x - margin
 | 
						|
        prevLabelMargin = labelBox.x - @options.xLabelMargin
 | 
						|
      else
 | 
						|
        label.remove()
 | 
						|
 | 
						|
  # draw the data series
 | 
						|
  #
 | 
						|
  # @private
 | 
						|
  drawSeries: ->
 | 
						|
    groupWidth = @width / @options.data.length
 | 
						|
    numBars = if @options.stacked then 1 else @options.ykeys.length
 | 
						|
    barWidth = (groupWidth * @options.barSizeRatio - @options.barGap * (numBars - 1)) / numBars
 | 
						|
    barWidth = Math.min(barWidth, @options.barSize) if @options.barSize
 | 
						|
    spaceLeft = groupWidth - barWidth * numBars - @options.barGap * (numBars - 1)
 | 
						|
    leftPadding = spaceLeft / 2
 | 
						|
    zeroPos = if @ymin <= 0 and @ymax >= 0 then @transY(0) else null
 | 
						|
    @bars = for row, idx in @data
 | 
						|
      lastTop = 0
 | 
						|
      for ypos, sidx in row._y
 | 
						|
        if ypos != null
 | 
						|
          if zeroPos
 | 
						|
            top = Math.min(ypos, zeroPos)
 | 
						|
            bottom = Math.max(ypos, zeroPos)
 | 
						|
          else
 | 
						|
            top = ypos
 | 
						|
            bottom = @bottom
 | 
						|
 | 
						|
          left = @left + idx * groupWidth + leftPadding
 | 
						|
          left += sidx * (barWidth + @options.barGap) unless @options.stacked
 | 
						|
          size = bottom - top
 | 
						|
 | 
						|
          if @options.verticalGridCondition and @options.verticalGridCondition(row.x)
 | 
						|
            @drawBar(@left + idx * groupWidth, @top, groupWidth, Math.abs(@top - @bottom), @options.verticalGridColor, @options.verticalGridOpacity, @options.barRadius)
 | 
						|
 | 
						|
          top -= lastTop if @options.stacked
 | 
						|
          @drawBar(left, top, barWidth, size, @colorFor(row, sidx, 'bar'),
 | 
						|
              @options.barOpacity, @options.barRadius)
 | 
						|
 | 
						|
          lastTop += size
 | 
						|
        else
 | 
						|
          null
 | 
						|
 | 
						|
  # @private
 | 
						|
  #
 | 
						|
  # @param row  [Object] row data
 | 
						|
  # @param sidx [Number] series index
 | 
						|
  # @param type [String] "bar", "hover" or "label"
 | 
						|
  colorFor: (row, sidx, type) ->
 | 
						|
    if typeof @options.barColors is 'function'
 | 
						|
      r = { x: row.x, y: row.y[sidx], label: row.label }
 | 
						|
      s = { index: sidx, key: @options.ykeys[sidx], label: @options.labels[sidx] }
 | 
						|
      @options.barColors.call(@, r, s, type)
 | 
						|
    else
 | 
						|
      @options.barColors[sidx % @options.barColors.length]
 | 
						|
 | 
						|
  # hit test - returns the index of the row at the given x-coordinate
 | 
						|
  #
 | 
						|
  hitTest: (x) ->
 | 
						|
    return null if @data.length == 0
 | 
						|
    x = Math.max(Math.min(x, @right), @left)
 | 
						|
    Math.min(@data.length - 1,
 | 
						|
      Math.floor((x - @left) / (@width / @data.length)))
 | 
						|
 | 
						|
  # click on grid event handler
 | 
						|
  #
 | 
						|
  # @private
 | 
						|
  onGridClick: (x, y) =>
 | 
						|
    index = @hitTest(x)
 | 
						|
    @fire 'click', index, @data[index].src, x, y
 | 
						|
 | 
						|
  # hover movement event handler
 | 
						|
  #
 | 
						|
  # @private
 | 
						|
  onHoverMove: (x, y) =>
 | 
						|
    index = @hitTest(x)
 | 
						|
    @hover.update(@hoverContentForRow(index)...)
 | 
						|
 | 
						|
  # hover out event handler
 | 
						|
  #
 | 
						|
  # @private
 | 
						|
  onHoverOut: =>
 | 
						|
    if @options.hideHover isnt false
 | 
						|
      @hover.hide()
 | 
						|
 | 
						|
  # hover content for a point
 | 
						|
  #
 | 
						|
  # @private
 | 
						|
  hoverContentForRow: (index) ->
 | 
						|
    row = @data[index]
 | 
						|
    content = "<div class='morris-hover-row-label'>#{row.label}</div>"
 | 
						|
    for y, j in row.y
 | 
						|
      content += """
 | 
						|
        <div class='morris-hover-point' style='color: #{@colorFor(row, j, 'label')}'>
 | 
						|
          #{@options.labels[j]}:
 | 
						|
          #{@yLabelFormat(y)}
 | 
						|
        </div>
 | 
						|
      """
 | 
						|
    if typeof @options.hoverCallback is 'function'
 | 
						|
      content = @options.hoverCallback(index, @options, content, row.src)
 | 
						|
    x = @left + (index + 0.5) * @width / @data.length
 | 
						|
    [content, x]
 | 
						|
 | 
						|
  drawXAxisLabel: (xPos, yPos, text) ->
 | 
						|
    label = @raphael.text(xPos, yPos, text)
 | 
						|
      .attr('font-size', @options.gridTextSize)
 | 
						|
      .attr('font-family', @options.gridTextFamily)
 | 
						|
      .attr('font-weight', @options.gridTextWeight)
 | 
						|
      .attr('fill', @options.gridTextColor)
 | 
						|
 | 
						|
  drawBar: (xPos, yPos, width, height, barColor, opacity, radiusArray) ->
 | 
						|
    maxRadius = Math.max(radiusArray...)
 | 
						|
    if maxRadius == 0 or maxRadius > height
 | 
						|
      path = @raphael.rect(xPos, yPos, width, height)
 | 
						|
    else
 | 
						|
      path = @raphael.path @roundedRect(xPos, yPos, width, height, radiusArray)
 | 
						|
    path
 | 
						|
      .attr('fill', barColor)
 | 
						|
      .attr('fill-opacity', opacity)
 | 
						|
      .attr('stroke', 'none')
 | 
						|
 | 
						|
  roundedRect: (x, y, w, h, r = [0,0,0,0]) ->
 | 
						|
    [ "M", x, r[0] + y, "Q", x, y, x + r[0], y,
 | 
						|
      "L", x + w - r[1], y, "Q", x + w, y, x + w, y + r[1],
 | 
						|
      "L", x + w, y + h - r[2], "Q", x + w, y + h, x + w - r[2], y + h,
 | 
						|
      "L", x + r[3], y + h, "Q", x, y + h, x, y + h - r[3], "Z" ]
 | 
						|
 |