class @PlasticineColumn constructor: (@holder) -> @holder = $('.plasticine-column') PlasticineHelpers.setLocale() @drawTooltip() @xScale = d3.scaleBand() @setXScaleRange() @yScale = d3.scaleLinear().range([@holder.height(),0]) @setXAxis() @setYAxis() @svg = d3.select("##{@holder.attr('id')}").append('svg').style('width', @holderWidth()).style('height', @holder.height()).append('g') d3.json(@holder.data('url')).then (data) => @build(data) build: (data) -> columnIds = data.columns[0].y_values.map (d,i) -> "col#{i+1}" colGroup = d3.scaleBand().range(columnIds).domain(columnIds) @xAxisFormat = data.axis_x_format @yAxisFormat = data.axis_y_format @yAxisTickCount = data.axis_y_tick_count @quarterStartMonth = Number(data.quarter_start_month) data.columns.forEach (d) => y0 = 0 d.yValues = colGroup.domain().map (name,i) => { name: name, y0: y0, y1: y0 += PlasticineHelpers.parseValue(d.y_values[i], @yAxisFormat) } d.total = d.yValues[d.yValues.length - 1].y1 d.x = PlasticineHelpers.parseValue(d.x_value, @xAxisFormat) @xScale.domain data.columns.map( (d) -> d.x ) @yScale.domain [0, d3.max(data.columns, (d) => d.total * @holder.data('y-spacing-ratio'))] @drawYAxis() @columns = @svg.append('g').attr("class", "columns").selectAll('.column').data(data.columns) @refreshColumns() @drawXAxis() d3.select(window).on("resize." + @holder.attr("id"), () => @resizeX()) drawTooltip: () -> @holder.append('
') drawXAxis: () -> height = @holder.height() @svg.append('g').attr('class', 'x axis') .attr('transform', 'translate(0,' + height + ')') .call @xAxis @refreshXAxis() drawYAxis: () -> group = @svg.append("g").attr("class", "y axis").call @yAxis group.selectAll("g").filter((d) -> d).classed("minor", true) @refreshYAxis() hideTooltip: () -> @holder.find('.tooltip').hide() holderWidth: () -> @holder.width() refreshColumns: () -> self = this $('g.column').remove() @columns.enter().append("g").attr('class', 'column') .attr('data-x-val', (d) -> d.x_value) .attr('x', (d) => @xScale(d.x)) .attr('transform', (d) => 'translate(' + @xScale(d.x) + ',0)') .on("mouseover", (d) -> self.showTooltip(@, d)) .on("mouseout", (d) -> self.hideTooltip(@)) .selectAll("rect").data((d) => d.yValues).enter() .append("rect") .attr('class', (d,i) => "col#{i+1}") .attr("width", @xScale.bandwidth()) .attr("y", (d) => @yScale d.y1) .attr("height", (d) => @yScale(d.y0) - @yScale(d.y1)) refreshXAxis: () -> @setXAxis() @svg.select('.x.axis').call @xAxis refreshYAxis: () -> @setYAxis() @svg.select('.y.axis').call @yAxis resizeX: () -> d3.select(@svg.node().parentNode).style('width', @holderWidth() + 'px') @setXScaleRange() @refreshXAxis() @refreshYAxis() @hideTooltip() @refreshColumns() setXAxis: () -> @xAxis = d3.axisBottom(@xScale) @xAxis.tickSize -@holder.height() switch @xAxisFormat when 'date' then @xAxis.tickFormat(d3.timeFormat('%b')) when 'quarter' then @xAxis.tickFormat (d) => PlasticineHelpers.toQuarter(d, @quarterStartMonth) when 'year' then @xAxis.tickFormat (d) => PlasticineHelpers.toYear(d, @quarterStartMonth) when 'money' then @xAxis.tickFormat (d) => PlasticineHelpers.toPrice(d) setXScaleRange: () -> columnsMargin = @holder.data('columns-margin') columnsLeftPadding = @holder.data('columns-left-padding') columnsRightPadding = @holder.data('columns-right-padding') width = @holderWidth() @xScale = @xScale.rangeRound([columnsLeftPadding, width - columnsRightPadding]).padding(columnsMargin); setYAxis: () -> @yAxis = d3.axisLeft(@yScale) @yAxis.tickSize -@holderWidth() @yAxis.ticks @yAxisTickCount switch @yAxisFormat when 'date' then @yAxis.tickFormat(d3.timeFormat('%b')) when 'money' then @yAxis.tickFormat (d) => PlasticineHelpers.toPrice(d) showTooltip: (bar, data) -> barNode = $($(bar).find('rect:last-child')[0]) barX = $(bar).attr('x') barY = barNode.attr('y') xPosition = parseInt(barX) + @holder.offset().left yPosition = parseInt(barY) + @holder.offset().top tooltip = @holder.find('.tooltip') tooltip.html(data.tooltip) tooltip.fadeIn 200 tooltipX = xPosition - (tooltip.outerWidth() / 2) + (parseInt(barNode.attr("width")) / 2) d3.select(".tooltip") .style("left", tooltipX + "px") .style("top", (yPosition - tooltip.outerHeight()) + "px")