Checkpoint on Data UI
authordsc <dsc@wikimedia.org>
Thu, 12 Apr 2012 17:40:32 +0000 (10:40 -0700)
committerdsc <dsc@wikimedia.org>
Thu, 12 Apr 2012 17:40:32 +0000 (10:40 -0700)
data/graphs/ohai.json
lib/dataset/dataset-model.co
lib/dataset/datasource-model.co
lib/graph/graph-edit-view.co
lib/graph/graph-model.co
lib/server/controllers/datasource.co
lib/server/controllers/graph.co
lib/util/underscore/index.co
www/css/graph.styl
www/layout.jade

index 311a2eb..1be77f0 100644 (file)
 {
-    "id": "ohai", 
-    "name": "ohai", 
-    "slug": "ohai", 
-    "desc": "", 
-    "dataset": "/data/datasources/rc/rc_new_article_count.csv", 
+    "id": "ohai",
+    "slug": "ohai",
+    
+    "name": "ohai~",
+    "desc": "A graph for the testing of great justice.",
+    
+    "dataset": "/data/datasources/rc/rc_page_requests.csv",
+    "data" : {
+        "metrics" : {
+            "defaults" : {
+                "source_id" : "rc_page_requests"
+            },
+            "columns" : [
+                {
+                    "source_col" : 1,
+                    "label"      : "All Wikipedias (+Mobile)",
+                    "color"      : "#E62F74"
+                }, {
+                    "source_col" : 2,
+                    "label"      : "English",
+                    "color"      : "#244792"
+                }
+            ]
+        }
+    },
+    
     "width": "auto",
-    "height": 320, 
+    "height": 600,
+    
     "parents": [
         "root"
-    ], 
-    "chartType": "dygraphs", 
+    ],
+    
+    "chartType": "dygraphs",
     "options": {
-        "animatedZooms": true, 
-        "avoidMinZero": false, 
-        "axis": null, 
-        "axisLabelColor": "#666666", 
-        "axisLabelFontSize": 14, 
-        "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": true, 
-        "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, 
+        "animatedZooms": true,
+        "avoidMinZero": false,
+        "axis": null,
+        "axisLabelColor": "#666666",
+        "axisLabelFontSize": 14,
+        "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": true,
+        "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
     }
 }
index c5b591d..9cd82d3 100644 (file)
@@ -17,16 +17,17 @@ ColorBrewer = require 'colorbrewer'
  */
 DataSet = exports.DataSet = BaseModel.extend do # {{{
     urlRoot : '/datasets'
+    ready : false
     
     /**
      * @type DataSourceList
      */
-    sources : []
+    sources : null
     
     /**
      * @type MetricList
      */
-    metrics : []
+    metrics : null
     
     
     constructor: function DataSet
@@ -34,14 +35,29 @@ DataSet = exports.DataSet = BaseModel.extend do # {{{
     
     initialize : ->
         BaseModel::initialize ...
-        @sources = new DataSourceList @attributes.sources
-        @metrics = new MetricList     @attributes.metrics
+        @sources = new DataSourceList
+        if @attributes.metrics
+            @metrics = that.columns = new MetricList that.columns
     
     
     defaults : ->
-        sources : [] # XXX: needed? metrics now implies this info
-        metrics : []
-        # lines   : []
+        palette : null
+        lines   : []
+        metrics :
+            defaults : {}
+            columns  : []
+    
+    
+    load: (opts={}) ->
+        return this if @ready and not opts.force
+        @wait()
+        @trigger 'load', this
+        Seq()
+            .seq ~>
+                @ready = true
+                @trigger 'ready', this
+                @unwait() # terminates the `load` wait
+        this
     
     
     /**
index 1d31584..d51b904 100644 (file)
@@ -16,13 +16,33 @@ DataSource = exports.DataSource = BaseModel.extend do # {{{
     
     initialize: ->
         BaseModel::initialize ...
-        
+    
     
     defaults: ->
-        {}
+        id            : ''
+        url           : ''
+        format        : 'json'
+        
+        name          : ''
+        shortName     : ''
+        title         : ''
+        subtitle      : ''
+        desc          : ''
+        notes         : ''
+        
+        timespan : 
+            start     : null
+            stop      : null
+            step      : '1mo'
+        
+        columns       : []
+        
+        chart : 
+            chartType : 'dygraphs'
+            options   : {}
     
     url: ->
-        "/data/#{@id}.json"
+        "/datasources/#{@id}.json"
     
 # }}}
 
index 51d393c..67fd78d 100644 (file)
@@ -109,7 +109,7 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{
         @$el.on 'click', '.graph-options-tab', @onFirstClickRenderOptionsTab
         
         ### Graph Data UI
-        @data = @addSubview '.graph-data-pane', new DataView { model:@model.get('dataset'), graph_id:@id }
+        @data = @addSubview '.graph-data-pane', new DataView { model:@model.get('data'), graph_id:@id }
         @$el.find '.graph-data-pane' .append @data.render().el
         @data
             .on 'change',        @onDataChange, this
@@ -279,9 +279,10 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{
         @checkWaiting()
     
     render: ->
-        return this unless @ready
+        return this unless @ready and not @_rendering
+        @_rendering = true
         @wait()
-        @checkWaiting() # fix up the spinner element as the DOM is now settled
+        @checkWaiting()
         @renderDetails()
         @attachSubviews()
         # _.invoke @subviews, 'render'
@@ -289,6 +290,7 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{
         @updateURL()
         @trigger 'render', this
         @unwait()
+        @_rendering = false
         this
     
     renderAll: ->
index 21d9d5f..a6914cd 100644 (file)
@@ -91,7 +91,7 @@ Graph = exports.Graph = BaseModel.extend do # {{{
         @chartType = ChartType.lookup @get('chartType')
         
         # Insert submodels in place of JSON
-        @set 'dataset', new DataSet(@get('dataset')), {+silent}
+        @set 'data', new DataSet(@get('data') or @get('dataset')), {+silent}
         
         @trigger 'init', this
         @load() if opts.autoload
index c556f23..1f89863 100644 (file)
@@ -1,10 +1,17 @@
 fs         = require 'fs'
-Seq        = require 'seq'
+path       = require 'path'
+{existsSync:exists} = path
+
+_          = require 'underscore'
+yaml       = require 'js-yaml'
 findit     = require 'findit'
-Controller = require '../controller'
+Seq        = require 'seq'
 
-YAML_EXT_PAT = /\.ya?ml$/i
+Controller = require '../controller'
 
+EXT_PAT          = /\.[^\.]*$/i
+YAML_EXT_PAT     = /\.ya?ml$/i
+YAML_OR_JSON_PAT = /\.(json|ya?ml)$/i
 
 
 /**
@@ -19,17 +26,55 @@ class DataSourceController extends Controller
     
     -> super ...
     
+    
+    toFile: (id) -> "#{@dataDir}/#id.json"
+    
     /**
-     * Returns a JSON listing of the datasource metadata files.
+     * Auto-load :id for related requests.
+     */
+    autoload: (id, cb) ->
+        file = @toFile id
+        parser = JSON.parse
+        
+        yamlFile = file.replace /\.json$/i, '.yaml'
+        if exists yamlFile 
+            file = yamlFile
+            parser = yaml.load
+        
+        err, data <- fs.readFile file, 'utf8'
+        if 'ENOENT' is err?.code
+            return cb null, {}
+        if err
+            console.error "DataSourceController.autoload(#id, #{typeof cb}) -->\nerr"
+            return cb err
+        try
+            cb null, parser data
+        catch err
+            console.error "DataSourceController.autoload(#id, #{typeof cb}) -->\nerr"
+            cb err
+    
+    /**
+     * GET /datasources
+     * @returns {Object} JSON listing of the datasource metadata files.
      */
     index : (req, res, next) ->
         files = findit.sync @dataDir
         # fs.readdir @dataDir, (err, files) ->
         res.send do
-            files.filter -> /\.(json|ya?ml)$/i.test it
+            files.filter -> YAML_OR_JSON_PAT.test it
                  .map    -> "#it".replace YAML_EXT_PAT, '.json'
     
     /**
+     * GET /datasources/:datasource
+     */
+    show: (req, res) ->
+        res.send req.datasource
+        # if req.format is 'json'
+        #     res.send req.datasource
+        # else
+        #     res.render 'datasource/view'
+    
+    /**
      * Returns the aggregated JSON content of the datasource metadata files.
      */
     allData : (req, res, next) ->
@@ -38,7 +83,7 @@ class DataSourceController extends Controller
         Seq(findit.sync @dataDir)
             # .seq ~> @ok findit.sync @dataDir
             # .flatten()
-            .filter -> /\.(json|ya?ml)$/.test it
+            .filter -> YAML_OR_JSON_PAT.test it
             .seq ->
                 files := @stack.slice()
                 # console.log 'files:', files
@@ -60,13 +105,13 @@ class DataSourceController extends Controller
                     # console.log "#f ok!", data
                     @ok v
                 catch err
-                    console.error "[/data/all] catch! #err"
+                    console.error "[/datasources] catch! #err"
                     console.error err
                     console.error that if err.stack
                     res.send { error:String(err), partial_data:data }
             .seq -> res.send data
             .catch (err) ->
-                console.error '[/data/all] catch!'
+                console.error '[/datasources] catch!'
                 console.error err
                 console.error that if err.stack
                 res.send { error:String(err), partial_data:data }
index d3921ce..4697f46 100644 (file)
@@ -1,10 +1,11 @@
-_        = require 'underscore'
-fs       = require 'fs'
-path     = require 'path'
-yaml     = require 'js-yaml'
-
+fs         = require 'fs'
+path       = require 'path'
 {existsSync:exists} = path
+
+_          = require 'underscore'
+yaml       = require 'js-yaml'
 {mkdirp, mkdirpAsync} = require '../mkdirp'
+
 Controller = require '../controller'
 
 
index 7e57eef..cc9d458 100644 (file)
@@ -9,9 +9,12 @@ _.mixin require 'kraken/util/underscore/string'
 
 
 ## Debug
-_.dump = (o, label='dump') ->
+_.dump = (o, label='dump', expanded=false) ->
     if not _.isArray(o) and _.isObject(o)
-        console.group label
+        if expanded
+            console.group label
+        else
+            console.groupCollapsed label
         for k, v in o
             console.log "#k:", v
         console.groupEnd()
index ce12b87..ab49bd1 100644 (file)
@@ -187,6 +187,12 @@ section.graph
             &:hover
                 opacity 0.6
         
+        input.value:not([type="checkbox"])
+            width 240px
+            font-family menlo, monospace
+        textarea
+            resize none
+        
         .shortname
             font-weight bold
             color white
@@ -196,9 +202,6 @@ section.graph
             font-weight bold
             // line-height 1.5
             // font-size 100%
-        input.value:not([type="checkbox"])
-            width 240px
-            font-family menlo, monospace
         .type
             &::before
                 content "Type: "
index c6859c1..4b3591c 100644 (file)
@@ -2,7 +2,7 @@ include mixins/helpers
 include mixins/forms
 
 !!! html
-html
+html(lang="en", dir="ltr")
     head
         block head
             meta(http-equiv="content-type", content="text/html; charset=utf-8")