Auto-load d3 line chart type.
authorDavid Schoonover <dsc@wikimedia.org>
Wed, 20 Jun 2012 16:00:37 +0000 (09:00 -0700)
committerDavid Schoonover <dsc@wikimedia.org>
Wed, 20 Jun 2012 16:00:37 +0000 (09:00 -0700)
lib/chart/chart-type.co
lib/chart/index.co
lib/chart/type/d3/d3-bar-chart-type.co
lib/chart/type/d3/d3-geo-chart-type.co
lib/chart/type/d3/d3-line-chart-type.co
lib/chart/type/d3/index.co
lib/util/op.co
www/css/chart.styl
www/d3-test.jade
www/modules.yaml

index d66b435..2030a90 100644 (file)
@@ -166,7 +166,7 @@ class exports.ChartType extends ReadyEmitter
                 proto.options_ordered = spec
                 proto.options = _.synthesize spec, -> [it.name, it]
                 proto.ready = true
-                @emit 'ready', this
+                @triggerReady()
             error: ~> console.error "Error loading #{@typeName} spec! #it"
         this
     
index 5a02eb2..a961cba 100644 (file)
@@ -1,5 +1,7 @@
-chart_type = require 'kraken/chart/chart-type'
+chart_type   = require 'kraken/chart/chart-type'
 chart_option = require 'kraken/chart/option'
-dygraphs = require 'kraken/chart/type/dygraphs'
+dygraphs     = require 'kraken/chart/type/dygraphs'
+d3_charts    = require 'kraken/chart/type/d3'
 
-exports import chart_type import chart_option import dygraphs
+exports import chart_type import chart_option \
+        import dygraphs import d3_charts
index e1fc007..347244b 100644 (file)
@@ -3,8 +3,30 @@ d3 = require 'd3'
 { _, op,
 } = require 'kraken/util'
 { ChartType,
-} = require 'kraken/chart'
+} = require 'kraken/chart/chart-type'
 
 
 
-exports.foo = 1
+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 ...
+    
+    
index 26d5ad9..2238b31 100644 (file)
@@ -3,12 +3,12 @@ ColorBrewer = require 'colorbrewer'
 { _, op,
 } = require 'kraken/util'
 { ChartType,
-} = require 'kraken/chart'
+} = require 'kraken/chart/chart-type'
 
 
 
 
-class GeoWorldChartType extends ChartType
+class exports.GeoWorldChartType extends ChartType
     __bind__ : <[ dygNumberFormatter dygNumberFormatterHTML ]>
     SPEC_URL : '/schema/d3/d3-geo-world.json'
     
index 6446686..3646aa5 100644 (file)
@@ -4,10 +4,10 @@ ColorBrewer = require 'colorbrewer'
 { _, op,
 } = require 'kraken/util'
 { ChartType,
-} = require 'kraken/chart'
+} = require 'kraken/chart/chart-type'
 
 
-class LineChartType extends ChartType
+class exports.LineChartType extends ChartType
     __bind__ : <[ determineSize ]>
     SPEC_URL : '/schema/d3/d3-line.json'
     
@@ -31,6 +31,10 @@ class LineChartType extends ChartType
     
     
     
+    getData: ->
+        @model.dataset.getColumns()
+    
+    
     transform: ->
         dataset = @model.dataset
         options = @model.getOptions() import @determineSize()
@@ -39,85 +43,71 @@ class LineChartType extends ChartType
         options
     
     
-    renderChart: (rawData, viewport, options, lastChart) ->
-        viewport.empty()
-        
+    renderChart: (data, viewport, options, lastChart) ->
         ### Starting with http://bost.ocks.org/mike/chart/
         
-        
-        # formatDate = d3.time.format("%b %Y")
-        # chart = timeSeriesChart()
-        #     .x (d) -> formatDate.parse(d.date)
-        #     .y (d) -> +d.price
-        # d3.csv("sp500.csv", (data) ->
-        #   d3.select("#example")
-        #       .datum(data)
-        #       .call(chart)
-        
         margin = {top: 20, right: 20, bottom: 20, left: 20}
         width  = 760
         height = 320
-        xValue = (d) -> d[0]
-        yValue = (d) -> d[1]
         xScale = d3.time.scale()
         yScale = d3.scale.linear()
-        xAxis  = d3.svg.axis().scale(xScale).orient("bottom").tickSize(6, 0)
-        X      = (d) -> xScale(d[0])
-        Y      = (d) -> yScale(d[1])
-        line   = d3.svg.line().x(X).y(Y)
         
+        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 ]
         
-        chart = (selection) ->
-            selection.each (data) ->
-            
-                # Convert data to standard representation greedily
-                # this is needed for nondeterministic accessors.
-                data = data.map (d, i) ->
-                    [ xValue.call(data, d, i), yValue.call(data, d, i) ]
-                
-                
-                # Update the x-scale.
-                xScale
-                    .domain d3.extent data, xValue
-                    .range [ 0, width - margin.left - margin.right ]
-                
-                # Update the y-scale.
-                yScale
-                    .domain [ 0, d3.max data, yValue ]
-                    .range [ height - margin.top - margin.bottom, 0 ]
-                
-                # Select the svg element, if it exists.
-                svg = d3.select(this).selectAll("svg").data([data])
-                
-                # Otherwise, create the skeletal chart.
-                gEnter = svg.enter().append("svg").append("g")
-                gEnter.append("path")
-                    .attr "class", "line"
-                    .style "stroke", (d, i) -> options.colors[i]
-                gEnter.append("g").attr("class", "x axis")
-                
-                # Update the outer dimensions.
-                svg .attr("width", width)
-                    .attr("height", height)
-                
-                # Update the inner dimensions.
-                g = svg.select("g")
-                    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
-                
-                # Update the line path.
-                g.select(".line")
-                    .attr("d", line)
-                
-                # Update the x-axis.
-                g.select(".x.axis")
-                    .attr("transform", "translate(0," + yScale.range()[0] + ")")
-                    .call(xAxis)
+        # Update the y-scale with the extents of the data.
+        yScale
+            .domain d3.extent allValues
+            .range [ height - margin.top - margin.bottom, 0 ]
         
-        d3.select viewport.0
-            .datum rawData
-            .call chart
+        # 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
+        
+        # Create/Update the line paths.
+        lines = frame.selectAll "path.line"
+            .data cols.map -> d3.zip dates, it
+        lines.enter().append "path"
+            .attr "class", "line"
+        lines.exit().remove()
+        
+        X = (d, i) -> xScale d[0]
+        Y = (d, i) -> yScale d[1]
+        line = d3.svg.line().x(X).y(Y)
+        # frame.selectAll "path.line"
+        lines.attr "d", line
+            .style "stroke", (col, i) -> options.colors[i]
+        
+        svg
     
     
     
-
-module.exports = exports = LineChartType
\ No newline at end of file
index 3a488eb..5651289 100644 (file)
@@ -1,5 +1,5 @@
-bar  = require 'kraken/chart/type/d3/d3-bar-chart-type'
-geo  = require 'kraken/chart/type/d3/d3-geo-chart-type'
 line = require 'kraken/chart/type/d3/d3-line-chart-type'
+# geo  = require 'kraken/chart/type/d3/d3-geo-chart-type'
+# bar  = require 'kraken/chart/type/d3/d3-bar-chart-type'
 
-exports import bar import geo import line
+exports import line # import geo import bar
index 2fb5172..e434d65 100644 (file)
@@ -24,6 +24,7 @@ module.exports = op =
     ok      : (o)     -> o?
     notOk   : (o)     -> o!?
     
+    ### manipulate function args/arity
     first   : (a)     -> a
     second  : (_,a)   -> a
     nth     : (n) ->
@@ -32,12 +33,24 @@ module.exports = op =
             case 1 then op.second
             default     -> arguments[n]
     
+    # reverse the order of the first two args
     flip    : (fn) ->
         (a, b) ->
             arguments[0] = b
             arguments[1] = a
             fn.apply this, arguments
     
+    # only pass n args
+    aritize : (fn, cxt, n) ->
+        [n, cxt] = [cxt, null] if arguments.length < 3
+        -> fn.apply cxt ? this, [].slice.call(arguments, 0, n)
+    
+    # only pass the first argument
+    it      : (fn, cxt) ->
+        -> fn.call cxt ? this, it
+    
+    
+    
     ### reduce-ordered values & accessors
     khas      : (k,o)       ->  k in o
     kget      : (k,o)       ->  o[k]
index b9b7239..8ba548d 100644 (file)
@@ -5,7 +5,13 @@
     .line
       fill none
       stroke #000
-      stroke-width 1.5px
+      stroke-width 3px
     
+    .axis
+        font-size 11px
+        color #666
+        
+        text
+            fill #666
     
 
index b9c1123..968e48f 100644 (file)
@@ -26,14 +26,13 @@ block main-scripts
         ChartType     = require('kraken/chart').ChartType
         data          = require('kraken/data'); DataSource = data.DataSource; DataSourceList = data.DataSourceList
         _graph        = require('kraken/graph'); Graph = _graph.Graph; GraphList = _graph.GraphList; GraphEditView = _graph.GraphEditView
-        LineChartType = require('kraken/chart/type/d3/d3-line-chart-type')
+        //LineChartType = require('kraken/chart/type/d3/d3-line-chart-type')
         
         // run on DOM-ready
         jQuery(function(){
             root.app = new AppView(function(){
                 this.model = root.graph = new Graph({ id:'d3-test' }, { parse:true })
                 this.view  = root.view  = new GraphEditView({ model:this.model })
-                this.view.chartType = this.model.chartType = new LineChartType(this.model, this.view);
             });
         });
     
index 4ee875a..e571f9a 100644 (file)
@@ -113,8 +113,8 @@ dev:
                 - type:
                     - d3:
                         - d3-line-chart-type
-                        - d3-geo-chart-type
-                        - d3-bar-chart-type
+                        # - d3-geo-chart-type
+                        # - d3-bar-chart-type
                         - index
                     - dygraphs
                     - index