Skip to content

Instantly share code, notes, and snippets.

@rubyonrailstutor
Created January 9, 2014 21:13

Revisions

  1. @jcdavison jcdavison created this gist Jan 9, 2014.
    144 changes: 144 additions & 0 deletions gistfile1.coffee
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,144 @@
    angular.module('CrowdSound').directive 'csChart', () ->
    restrict: "E"
    scope:
    question: "="
    index: "="
    link: (scope, element, attrs) ->
    scope.data = []

    class PieChart
    constructor: (element) ->
    @width = 350
    @height = 350
    # @oRadius = @width/2
    @iRadius = 50
    @padding = 2
    @layout = d3.layout.pie().value( (d) =>
    d.votes)
    @chart = d3.select(element[0])
    @svg = @chart.append("svg")
    .attr("width", @width)
    .attr("height", @height)
    @color = d3.scale.category10().domain(d3.range(0,10))
    @arcGroup = @svg.append("g")
    .attr("class", "arc")
    .attr("transform", "translate(" + @oRadius() + "," + @oRadius() + ")" )
    @labelGroup = @svg.append("g")
    .attr("class", "label")
    .attr("transform", "translate(" + @oRadius() + "," + @oRadius() + ")" )

    arc: () ->
    d3.svg.arc()
    .innerRadius(@iRadius)
    .outerRadius(@oRadius())

    oRadius: () ->
    @width/2

    toggleWidth: () ->
    width = d3.select("#question#{scope.index}").style("width")
    return if width.match("%")
    if width == "auto" || parseInt(width) < 350
    @width = 220
    @height = 220
    @svg.attr("width", @width).attr("height", @height)
    @arcGroup.attr("transform", "translate(" + @oRadius() + "," + @oRadius() + ")" )
    @labelGroup.attr("transform", "translate(" + @oRadius() + "," + @oRadius() + ")" )
    else
    @width = 350
    @height = 350
    @svg.attr("width", @width).attr("height", @height)
    @arcGroup.attr("transform", "translate(" + @oRadius() + "," + @oRadius() + ")" )
    @labelGroup.attr("transform", "translate(" + @oRadius() + "," + @oRadius() + ")" )

    arcTween: (oldData, d, i) =>
    # if oldData[i]
    # s0 = oldData[i].startAngle
    # e0 = oldData[i].endAngle
    # else
    # s0 = 0
    # e0 = 0
    # i = d3.interpolate({startAngle: s0, endAngle: e0}, {startAngle: d.startAngle, endAngle: d.endAngle})
    i = d3.interpolate(this._current, d)
    (t) =>
    b = i(t)
    @arc()(b)

    render: (oldData, newData) ->
    console.log "render csPie triggered"
    return if _.compact(_.pluck(newData, 'votes')).length is 0
    @toggleWidth()
    pieData = @layout(newData)
    oldPieData = @layout(oldData)
    @arcGroup.selectAll("path").data(pieData)
    .enter().append("path")
    .attr("fill", (d,i) => @color(i) )
    .transition()
    .duration(1000)
    .attr("d", (d) =>
    @arc()(d)
    )
    .each((d) =>
    this._current = d
    )
    @arcGroup.selectAll("path").data(pieData)
    .transition()
    .attr("fill", (d,i) => @color(i) )
    .duration(1000)
    .attrTween("d", (d,i) =>
    @arcTween(oldPieData, d,i));
    @arcGroup.selectAll("path").data(pieData)
    .exit()
    .remove()
    .transition()
    .duration(1000)
    .attrTween("d", (d,i) =>
    @arcTween(oldPieData, d,i));
    @labelGroup.selectAll("text").data(pieData)
    .enter()
    .append("text")
    .transition()
    .duration(500)
    .attr('transform', (d) => 'translate(' + @arc().centroid(d) + ')' )
    .attr('text-anchor', 'middle')
    .text((d) ->
    if d.value is 0
    ""
    else
    d.data.answer.substr(0,10) + " (" + d.value + ")")
    @labelGroup.selectAll("text").data(pieData)
    .transition()
    .duration(500)
    .attr('transform', (d) => 'translate(' + @arc().centroid(d) + ')' )
    .attr('text-anchor', 'middle')
    .text((d) ->
    if d.value is 0
    ""
    else
    d.data.answer.substr(0,10) + " (" + d.value + ")")
    @labelGroup.selectAll("text").data(pieData)
    .exit().remove()
    .transition()
    .duration(500)

    pieChart = new PieChart(element)
    scope.$watch "data",
    (newData, oldData) =>
    if newData
    pieChart.render(oldData, newData)
    ,
    true
    scope.$watch 'question',
    (newData, oldData) ->
    if newData
    rawData = []
    _.each newData.answers, (obj) ->
    if obj.votes?
    datum = {}
    datum.votes = obj.votes
    datum.answer = obj.name
    rawData.push datum
    scope.data = rawData
    ,
    true