From c2ef858a1d29293dddd34e4c130c2ef3dcd0021b Mon Sep 17 00:00:00 2001 From: dsc Date: Thu, 12 Apr 2012 10:40:32 -0700 Subject: [PATCH] Checkpoint on Data UI --- data/graphs/ohai.json | 219 ++++++++++++++++++---------------- lib/dataset/dataset-model.co | 30 ++++- lib/dataset/datasource-model.co | 26 ++++- lib/graph/graph-edit-view.co | 8 +- lib/graph/graph-model.co | 2 +- lib/server/controllers/datasource.co | 61 ++++++++-- lib/server/controllers/graph.co | 11 +- lib/util/underscore/index.co | 7 +- www/css/graph.styl | 9 +- www/layout.jade | 2 +- 10 files changed, 239 insertions(+), 136 deletions(-) diff --git a/data/graphs/ohai.json b/data/graphs/ohai.json index 311a2eb..1be77f0 100644 --- a/data/graphs/ohai.json +++ b/data/graphs/ohai.json @@ -1,111 +1,124 @@ { - "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 } } diff --git a/lib/dataset/dataset-model.co b/lib/dataset/dataset-model.co index c5b591d..9cd82d3 100644 --- a/lib/dataset/dataset-model.co +++ b/lib/dataset/dataset-model.co @@ -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 /** diff --git a/lib/dataset/datasource-model.co b/lib/dataset/datasource-model.co index 1d31584..d51b904 100644 --- a/lib/dataset/datasource-model.co +++ b/lib/dataset/datasource-model.co @@ -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" # }}} diff --git a/lib/graph/graph-edit-view.co b/lib/graph/graph-edit-view.co index 51d393c..67fd78d 100644 --- a/lib/graph/graph-edit-view.co +++ b/lib/graph/graph-edit-view.co @@ -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: -> diff --git a/lib/graph/graph-model.co b/lib/graph/graph-model.co index 21d9d5f..a6914cd 100644 --- a/lib/graph/graph-model.co +++ b/lib/graph/graph-model.co @@ -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 diff --git a/lib/server/controllers/datasource.co b/lib/server/controllers/datasource.co index c556f23..1f89863 100644 --- a/lib/server/controllers/datasource.co +++ b/lib/server/controllers/datasource.co @@ -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 } diff --git a/lib/server/controllers/graph.co b/lib/server/controllers/graph.co index d3921ce..4697f46 100644 --- a/lib/server/controllers/graph.co +++ b/lib/server/controllers/graph.co @@ -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' diff --git a/lib/util/underscore/index.co b/lib/util/underscore/index.co index 7e57eef..cc9d458 100644 --- a/lib/util/underscore/index.co +++ b/lib/util/underscore/index.co @@ -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() diff --git a/www/css/graph.styl b/www/css/graph.styl index ce12b87..ab49bd1 100644 --- a/www/css/graph.styl +++ b/www/css/graph.styl @@ -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: " diff --git a/www/layout.jade b/www/layout.jade index c6859c1..4b3591c 100644 --- a/www/layout.jade +++ b/www/layout.jade @@ -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") -- 1.7.0.4