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)
data/graphs/d3-test.json
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 f649f56..15446c4 100644 (file)
@@ -1 +1,145 @@
-{"options":{"animatedZooms":true,"avoidMinZero":false,"axis":null,"axisLabelColor":"#666666","axisLabelFontSize":11,"axisLabelFormatter":null,"axisLabelWidth":50,"axisLineColor":"#AAAAAA","axisLineWidth":0.3,"axisTickSize":3,"colorSaturation":1,"colorValue":0.5,"colors":["#FF0097","#EF8158","#83BB32","#182B53","#4596FF","#553DC9","#AD3238","#00FFBC","#F1D950"],"connectSeparatedPoints":false,"customBars":false,"dateWindow":null,"delimiter":",","digitsAfterDecimal":2,"displayAnnotations":false,"drawPoints":true,"drawXAxis":true,"drawXGrid":true,"drawYAxis":true,"drawYGrid":true,"errorBars":false,"file":null,"fillAlpha":0.15,"fillGraph":false,"fractions":false,"gridLineColor":"#D8D8D8","gridLineWidth":0.3,"hideOverlayOnMouseOut":false,"highlightCircleSize":4,"includeZero":false,"interactionModel":null,"isZoomedIgnoreProgrammaticZoom":false,"labels":null,"labelsDiv":null,"labelsDivStyles":null,"labelsDivWidth":250,"labelsKMB":true,"labelsKMG2":false,"labelsSeparateLines":true,"labelsShowZeroValues":true,"legend":"always","logscale":true,"maxNumberWidth":30,"panEdgeFraction":null,"pixelsPerLabel":null,"pixelsPerXLabel":null,"pixelsPerYLabel":null,"pointSize":1,"rangeSelectorHeight":40,"rangeSelectorPlotFillColor":"#A7B1C4","rangeSelectorPlotStrokeColor":"#808FAB","rightGap":20,"rollPeriod":1,"showLabelsOnHighlight":true,"showRangeSelector":false,"showRoller":false,"sigFigs":null,"sigma":2,"stackedGraph":false,"stepPlot":false,"strokePattern":null,"strokeWidth":4,"ticker":null,"title":null,"titleHeight":18,"valueFormatter":null,"valueRange":null,"visibility":null,"wilsonInterval":true,"xAxisHeight":null,"xAxisLabelFormatter":null,"xAxisLabelWidth":55,"xLabelHeight":18,"xValueFormatter":null,"xValueParser":null,"xlabel":null,"y2label":null,"yAxisLabelFormatter":null,"yAxisLabelWidth":50,"yLabelWidth":18,"yValueFormatter":null,"ylabel":null},"slug":"d3-test","name":"","desc":"","notes":"","width":"auto","height":320,"parents":["root"],"data":{"palette":null,"lines":[],"metrics":[{"index":0,"label":"","type":"int","timespan":{"start":null,"end":null,"step":null},"disabled":false,"source_id":"rc_active_editors_count","source_col":1,"color":"#00b2ff","visible":true,"format_value":null,"format_axis":null,"transforms":[],"scale":1},{"index":1,"label":"","type":"int","timespan":{"start":null,"end":null,"step":null},"disabled":false,"source_id":"rc_new_article_count","source_col":1,"color":"rgb(213,62,79)","visible":true,"format_value":null,"format_axis":null,"transforms":[],"scale":1}]},"callout":{"enabled":true,"metric_idx":0,"label":""},"chartType":"dygraphs","id":"d3-test"}
\ No newline at end of file
+{
+    "options": {
+        "animatedZooms": true,
+        "avoidMinZero": false,
+        "axis": null,
+        "axisLabelColor": "#666666",
+        "axisLabelFontSize": 11,
+        "axisLabelFormatter": null,
+        "axisLabelWidth": 50,
+        "axisLineColor": "#AAAAAA",
+        "axisLineWidth": 0.3,
+        "axisTickSize": 3,
+        "colorSaturation": 1,
+        "colorValue": 0.5,
+        "colors": ["#FF0097", "#EF8158", "#83BB32", "#182B53", "#4596FF", "#553DC9", "#AD3238", "#00FFBC", "#F1D950"],
+        "connectSeparatedPoints": false,
+        "customBars": false,
+        "dateWindow": null,
+        "delimiter": ",",
+        "digitsAfterDecimal": 2,
+        "displayAnnotations": false,
+        "drawPoints": true,
+        "drawXAxis": true,
+        "drawXGrid": true,
+        "drawYAxis": true,
+        "drawYGrid": true,
+        "errorBars": false,
+        "file": null,
+        "fillAlpha": 0.15,
+        "fillGraph": false,
+        "fractions": false,
+        "gridLineColor": "#D8D8D8",
+        "gridLineWidth": 0.3,
+        "hideOverlayOnMouseOut": false,
+        "highlightCircleSize": 4,
+        "includeZero": false,
+        "interactionModel": null,
+        "isZoomedIgnoreProgrammaticZoom": false,
+        "labels": null,
+        "labelsDiv": null,
+        "labelsDivStyles": null,
+        "labelsDivWidth": 250,
+        "labelsKMB": true,
+        "labelsKMG2": false,
+        "labelsSeparateLines": true,
+        "labelsShowZeroValues": true,
+        "legend": "always",
+        "logscale": true,
+        "maxNumberWidth": 30,
+        "panEdgeFraction": null,
+        "pixelsPerLabel": null,
+        "pixelsPerXLabel": null,
+        "pixelsPerYLabel": null,
+        "pointSize": 1,
+        "rangeSelectorHeight": 40,
+        "rangeSelectorPlotFillColor": "#A7B1C4",
+        "rangeSelectorPlotStrokeColor": "#808FAB",
+        "rightGap": 20,
+        "rollPeriod": 1,
+        "showLabelsOnHighlight": true,
+        "showRangeSelector": false,
+        "showRoller": false,
+        "sigFigs": null,
+        "sigma": 2,
+        "stackedGraph": false,
+        "stepPlot": false,
+        "strokePattern": null,
+        "strokeWidth": 4,
+        "ticker": null,
+        "title": null,
+        "titleHeight": 18,
+        "valueFormatter": null,
+        "valueRange": null,
+        "visibility": null,
+        "wilsonInterval": true,
+        "xAxisHeight": null,
+        "xAxisLabelFormatter": null,
+        "xAxisLabelWidth": 55,
+        "xLabelHeight": 18,
+        "xValueFormatter": null,
+        "xValueParser": null,
+        "xlabel": null,
+        "y2label": null,
+        "yAxisLabelFormatter": null,
+        "yAxisLabelWidth": 50,
+        "yLabelWidth": 18,
+        "yValueFormatter": null,
+        "ylabel": null
+    },
+    "slug": "d3-test",
+    "name": "",
+    "desc": "",
+    "notes": "",
+    "width": "auto",
+    "height": 320,
+    "parents": ["root"],
+    "data": {
+        "palette": null,
+        "lines": [],
+        "metrics": [{
+            "index": 0,
+            "label": "",
+            "type": "int",
+            "timespan": {
+                "start": null,
+                "end": null,
+                "step": null
+            },
+            "disabled": false,
+            "source_id": "rc_active_editors_count",
+            "source_col": 1,
+            "color": "#00b2ff",
+            "visible": true,
+            "format_value": null,
+            "format_axis": null,
+            "transforms": [],
+            "scale": 1
+        }, {
+            "index": 1,
+            "label": "",
+            "type": "int",
+            "timespan": {
+                "start": null,
+                "end": null,
+                "step": null
+            },
+            "disabled": false,
+            "source_id": "rc_new_article_count",
+            "source_col": 1,
+            "color": "rgb(213,62,79)",
+            "visible": true,
+            "format_value": null,
+            "format_axis": null,
+            "transforms": [],
+            "scale": 1
+        }]
+    },
+    "callout": {
+        "enabled": true,
+        "metric_idx": 0,
+        "label": ""
+    },
+    "chartType": "d3-line",
+    "id": "d3-test"
+}
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