From: dsc Date: Mon, 7 May 2012 19:52:35 +0000 (-0700) Subject: DataSet UI now wired up properly, woo. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=f9fe00015881e8f01cc8a12287c718e273be8c19;p=limn.git DataSet UI now wired up properly, woo. --- diff --git a/lib/dataset/data-view.co b/lib/dataset/data-view.co index d36cc61..b947e9a 100644 --- a/lib/dataset/data-view.co +++ b/lib/dataset/data-view.co @@ -47,7 +47,7 @@ DataView = exports.DataView = BaseView.extend do # {{{ @addSubview @dataset_view .on 'add-metric', @onMetricsChanged, this .on 'remove-metric', @onMetricsChanged, this - .on 'edit-metric', @editMetric, this + .on 'select-metric', @selectMetric, this @render() @triggerReady() @@ -87,6 +87,7 @@ DataView = exports.DataView = BaseView.extend do # {{{ .on 'metric-update', @onUpdateMetric, this .on 'metric-change', @onUpdateMetric, this @metric_views.push @addSubview view + @renderSubviews() metric removeMetric: (metric) -> @@ -96,14 +97,15 @@ DataView = exports.DataView = BaseView.extend do # {{{ @removeSubview view metric - editMetric: (metric) -> - console.log "#this.editMetric!", metric + selectMetric: (metric) -> + # console.log "#this.selectMetric!", metric @metric_views.invoke 'hide' @metric_edit_view = @metric_views.findByModel metric @metric_edit_view?.show() _.delay @onMetricsChanged, 10 onMetricsChanged: -> + return unless @dataset_view oldMinHeight = parseInt @$el.css 'min-height' newMinHeight = Math.max do @dataset_view.$el.height() diff --git a/lib/dataset/dataset-model.co b/lib/dataset/dataset-model.co index 5d0fa33..44e3a4c 100644 --- a/lib/dataset/dataset-model.co +++ b/lib/dataset/dataset-model.co @@ -34,16 +34,16 @@ DataSet = exports.DataSet = BaseModel.extend do # {{{ metrics : [] - constructor: function DataSet - BaseModel ... + constructor: function DataSet (attributes={}, opts) + @metrics = new MetricList attributes.metrics + BaseModel.call this, attributes, opts initialize : -> BaseModel::initialize ... - @metrics = new MetricList @attributes.metrics + @set 'metrics', @metrics, {+silent} @on 'change:metrics', @onMetricChange, this - load: (opts={}) -> @resetReady() if opts.force return this if @loading or @ready @@ -67,6 +67,34 @@ DataSet = exports.DataSet = BaseModel.extend do # {{{ @triggerReady() this + # refreshSubModels: -> + # # @set 'metrics', @metrics.toJSON(), {+silent} + # @set 'metrics', _.pluck(@metrics.models, 'attributes'), {+silent} + # this + + /** + * Override to handle the case where one of our rich sub-objects is attempted + * to be overridden with a native object. + */ + set: (key, value, opts) -> + # return DataSet.__super__.set ... unless @metrics + + if _.isObject(key) and key? + [values, opts] = [key, value] + else + values = { "#key": value } + opts or= {} + + for key, value in values + continue unless key is 'metrics' and _.isArray value + @metrics.reset value + delete values[key] + unless opts.silent + DataSet.__super__.set.call this, 'metrics', value, {+silent} + DataSet.__super__.set.call this, 'metrics', @metrics, opts + + DataSet.__super__.set.call this, values, opts + /* * * * TimeSeriesData interface * * * {{{ */ @@ -74,18 +102,21 @@ DataSet = exports.DataSet = BaseModel.extend do # {{{ * @returns {Array} The reified dataset, materialized to a list of rows including timestamps. */ getData: -> + return [] unless @ready _.zip ...@getColumns() /** * @returns {Array} List of all columns (including date column). */ getColumns: -> - [ @getDateColumn() ].concat @getDataColumns() + return [] unless @ready + _.compact [ @getDateColumn() ].concat @getDataColumns() /** * @returns {Array} The date column. */ getDateColumn: -> + return [] unless @ready dates = @metrics.onlyOk().invoke 'getDateColumn' maxLen = _.max _.pluck dates, 'length' _.find dates, -> it.length is maxLen @@ -94,33 +125,45 @@ DataSet = exports.DataSet = BaseModel.extend do # {{{ * @returns {Array} List of all columns except the date column. */ getDataColumns: -> + return [] unless @ready @metrics.onlyOk().invoke 'getData' /** * @returns {Array} List of column labels. */ getLabels: -> + return [] unless @ready [ 'Date' ].concat @metrics.onlyOk().invoke 'getLabel' - # }}} - getColors: -> + return [] unless @ready @metrics.onlyOk().pluck 'color' + # }}} + + newMetric: -> index = @metrics.length @metrics.add m = new Metric { index, color:ColorBrewer.Spectral[11][index] } + # @get 'metrics' .push m.attributes + # @trigger 'change:metrics', this, @metrics, 'metrics' + # @trigger 'change', this, @metrics, 'metrics' m onMetricChange: -> console.log "#this.onMetricChange! ready=#{@ready}" @resetReady() - @metrics.reset @get 'metrics' @load() - # TODO: toJSON() must ensure columns in MetricList are ordered by index + + # XXX: toJSON() must ensure columns in MetricList are ordered by index # ...in theory, MetricList.comparator now does this + # toJSON: -> + # @refreshSubModels() + # json = DataSet.__super__.toJSON ... + # json.metrics = json.metrics.map -> it.toJSON?() or it + # json # }}} diff --git a/lib/dataset/dataset-view.co b/lib/dataset/dataset-view.co index e19efcb..34d7ff7 100644 --- a/lib/dataset/dataset-view.co +++ b/lib/dataset/dataset-view.co @@ -14,7 +14,7 @@ DataSetView = exports.DataSetView = BaseView.extend do # {{{ events: 'click .new-metric-button' : 'newMetric' - 'click .metrics .dataset-metric' : 'editMetric' + 'click .metrics .dataset-metric' : 'selectMetric' views_by_cid : {} active_view : null @@ -43,25 +43,24 @@ DataSetView = exports.DataSetView = BaseView.extend do # {{{ addMetric: (metric) -> console.log "#this.addMetric!", metric - if metric.view - @removeSubview metric.view.remove() + if @views_by_cid[metric.cid] + @removeSubview that delete @views_by_cid[metric.cid] view = @addSubview new DataSetMetricView {model:metric, @graph_id} @views_by_cid[metric.cid] = view - @$ '.metrics' .append view.render().el - - # @render() + # @$ '.metrics' .append view.render().el @trigger 'add-metric', metric, view, this + @render() view removeMetric: (metric) -> console.log "#this.removeMetric!", metric - if view = metric.view - @removeSubview view.remove() + if view = @views_by_cid[metric.cid] + @removeSubview view delete @views_by_cid[metric.cid] @trigger 'remove-metric', metric, view, this - metric.view + view addAllMetrics: -> console.log "#this.addAllMetrics! --> #{@model.metrics}" @@ -69,18 +68,17 @@ DataSetView = exports.DataSetView = BaseView.extend do # {{{ @model.metrics.each @addMetric, this this - editMetric: (metric) -> - # console.log "#this.editMetric!", metric + selectMetric: (metric) -> if metric instanceof [jQuery.Event, Event] metric = $ metric.currentTarget .data 'model' view = @active_view = @views_by_cid[metric.cid] - console.log "#this.editMetric!", metric + # console.log "#this.selectMetric!", metric @$ '.metrics .dataset-metric' .removeClass 'metric-active' view.$el.addClass 'metric-active' view.$el.find '.activity-arrow' .css 'font-size', 2+view.$el.height() - @trigger 'edit-metric', metric, view, this + @trigger 'select-metric', metric, view, this this @@ -120,8 +118,8 @@ DataSetMetricView = exports.DataSetMetricView = BaseView.extend do # {{{ 'disabled' if m.disabled, ]).map( -> "metric-#it" ).join ' ' source : - if m.source_id and m.source_col_name - "#{m.source_id}.#{m.source_col_name}" + if m.source_id and m.source_col + "#{m.source_id}[#{m.source_col}]" else 'No source' timespan : diff --git a/lib/dataset/metric-edit-view.co b/lib/dataset/metric-edit-view.co index f0d787c..4b5be60 100644 --- a/lib/dataset/metric-edit-view.co +++ b/lib/dataset/metric-edit-view.co @@ -52,6 +52,7 @@ MetricEditView = exports.MetricEditView = BaseView.extend do # {{{ update: -> MetricEditView.__super__.update ... + @$ '.metric-label' .attr 'placeholder', @model.getPlaceholderLabel() # Update the color picker @$ '.color-swatch' @@ -85,6 +86,7 @@ MetricEditView = exports.MetricEditView = BaseView.extend do # {{{ onSourceMetricChange: (metric) -> console.log "#this.onSourceMetricChange!", metric + @$ '.metric-label' .attr 'placeholder', @model.getPlaceholderLabel() @trigger 'metric-change', @model, this this diff --git a/lib/dataset/metric-model.co b/lib/dataset/metric-model.co index e3b6ce6..7083738 100644 --- a/lib/dataset/metric-model.co +++ b/lib/dataset/metric-model.co @@ -64,7 +64,7 @@ Metric = exports.Metric = BaseModel.extend do # {{{ getPlaceholderLabel: -> col = @get 'source_col' - name = "#{@source.get 'shortName'}, #{@source.getColumnName col}" if @source and col > 0 + name = "#{@source.get 'shortName'}, #{@source.getColumnName col}" if @source and col >= 0 name or @NEW_METRIC_LABEL getSourceColumnName: -> @@ -73,9 +73,12 @@ Metric = exports.Metric = BaseModel.extend do # {{{ load: (opts={}) -> - source_id = @get 'source_id' + source_id = @get 'source_id' @resetReady() if opts.force or @source?.id is not source_id - return this if not source_id or @loading or @ready + return this if @loading or @ready + + unless source_id and @get('source_col') >= 0 + return @triggerReady() console.log "#this.load()..." @updateId() diff --git a/lib/graph/graph-edit-view.co b/lib/graph/graph-edit-view.co index 54656cf..eec0146 100644 --- a/lib/graph/graph-edit-view.co +++ b/lib/graph/graph-edit-view.co @@ -104,7 +104,7 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ ### Graph Data UI - @data_view = @addSubview new DataView { model:@model.get('data'), graph_id:@id } + @data_view = @addSubview new DataView { model:@model.dataset, graph_id:@id } @data_view .on 'start-waiting', @wait, this .on 'stop-waiting', @unwait, this @@ -275,7 +275,7 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ valueFormatter : @numberFormatterHTML # console.log "#this.render!", dataset - _.dump options, 'options' + # _.dump options, 'options' # Always rerender the chart to sidestep the case where we need to push defaults into # dygraphs to reset the current option state. @@ -308,7 +308,7 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ # @renderDetails() # @attachSubviews() # _.invoke @subviews, 'render' - BaseView::render ... + GraphEditView.__super__.render ... @renderChart() # @updateURL() @trigger 'render', this @@ -321,11 +321,11 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ * Update the page URL using HTML5 History API */ updateURL: -> - data = @toJSON() + json = @toJSON() title = "#{@model.get('name') or 'New Graph'} | Edit Graph | GraphKit" url = @toURL('edit') - # console.log 'History.pushState', JSON.stringify(data), title, url - History.pushState data, title, url + # console.log 'History.pushState', JSON.stringify(json), title, url + History.pushState json, title, url ### }}} @@ -397,7 +397,7 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ # \toptions: #{JSON.stringify options} # \t^opts: #{JSON.stringify _.intersection _.keys(changes), _.keys(options)} # """ - @chart?.updateOptions file:that if changes?.dataset + # @chart?.updateOptions file:that if changes?.dataset @chartOptions options, {+silent} if changes?.options onScaffoldChange: (scaffold, value, key, field) -> @@ -435,8 +435,8 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ onDetailsSubmit: -> console.log "#this.onDetailsSubmit!" - data = @$ 'form.graph-details' .formData() - @model.set data + details = @$ 'form.graph-details' .formData() + @model.set details false onOptionsSubmit: -> diff --git a/lib/graph/graph-model.co b/lib/graph/graph-model.co index 8790325..2d231f5 100644 --- a/lib/graph/graph-model.co +++ b/lib/graph/graph-model.co @@ -98,6 +98,7 @@ Graph = exports.Graph = BaseModel.extend do # {{{ # Insert submodels in place of JSON @dataset = new DataSet {id:@id, ...@get 'data'} + # .on 'change', @onDataSetChange, this @set 'data', @dataset, {+silent} @trigger 'init', this @@ -121,9 +122,9 @@ Graph = exports.Graph = BaseModel.extend do # {{{ next.ok() success : @unwaitAnd (model, res) ~> # console.log "#{this}.fetch() --> success!", res + # Update the DataSet model with the new values @dataset.set @get 'data' - @trigger 'change:data', this, @dataset, 'data' - @trigger 'change', this, @dataset, 'data' + @set 'data', @dataset, {+silent} next.ok res # Load Parents... @@ -166,9 +167,11 @@ Graph = exports.Graph = BaseModel.extend do # {{{ Seq @dataset.metrics.models .parEach_ (next, metric) -> metric.once 'ready', next.ok .load() - .parEach_ (next, metric) -> - metric.source - .on 'load-data-success', next.ok .loadData() + .parEach_ (next, metric) ~> + unless metric.source + console.warn "#{this}.loadData() -- Skipping metric #metric with invalid source!", metric + return next.ok() + metric.source.on 'load-data-success', next.ok .loadData() .seq ~> console.log "#{this}.loadData() complete!" @loading = false @@ -176,6 +179,9 @@ Graph = exports.Graph = BaseModel.extend do # {{{ @triggerReady 'dataReady', 'data-ready' this + onDataSetChange: -> + console.log "#this.onDataSetChange!" + @set 'data', @dataset, {+silent} ### Accessors @@ -184,7 +190,7 @@ Graph = exports.Graph = BaseModel.extend do # {{{ if _.startsWith key, 'options.' @getOption key.slice(8) else - (@..__super__ or BaseModel::).get.call this, key + Graph.__super__.get.call this, key set: (key, value, opts) -> @@ -195,7 +201,7 @@ Graph = exports.Graph = BaseModel.extend do # {{{ values = { "#key": value } values = @parse values - setter = (@..__super__ or BaseModel::).set + setter = Graph.__super__.set # Merge options in, firing granulated change events if values.options @@ -215,7 +221,7 @@ Graph = exports.Graph = BaseModel.extend do # {{{ - ### Chart Option Accessors ### + ### Chart Option Accessors {{{ hasOption: (key) -> @getOption(key) is void @@ -266,8 +272,8 @@ Graph = exports.Graph = BaseModel.extend do # {{{ options - - ### Serialization + # }}} + ### Serialization {{{ parse: (data) -> data = JSON.parse data if typeof data is 'string' @@ -300,8 +306,8 @@ Graph = exports.Graph = BaseModel.extend do # {{{ toJSON: (opts={}) -> opts = {+keepDefaults, +keepUnchanged} import opts # use jQuery's deep-copy implementation -- XXX: Deep-copy no longer necessary thanks to @getOptions() - # json = $.extend true, {}, @attributes json = _.clone(@attributes) import { options:@getOptions(opts) } + # { data: ...json } toKVPairs: (opts={}) -> @@ -346,6 +352,8 @@ Graph = exports.Graph = BaseModel.extend do # {{{ toPermalink: -> "#{root.location.protocol}//#{window.location.host}#{@toLink()}" + # }}} + ### Graph Cache for parent-lookup new ModelCache Graph diff --git a/lib/template/metric-edit.jade b/lib/template/metric-edit.jade index 8b2a9d3..a95e2a7 100644 --- a/lib/template/metric-edit.jade +++ b/lib/template/metric-edit.jade @@ -7,7 +7,7 @@ section.metric-edit-ui input.metric-color(type='hidden', id="#{graph_id}_metric", name="color", value=color) .color-swatch.input-append.color(data-color="#{color}", data-color-format="hex") input.metric-color(type='hidden', id="#{graph_id}_metric_color", name="color", value=color) - span.add-on: i(style="background-color: #{color};") + span.add-on: i(style="background-color: #{color};", title="#{color}") input.metric-label(type='text', id="#{graph_id}_metric_label", name='label', placeholder='#{placeholder_label}', value=label)