Scaffold now connected to graph, and re-renders on submit.
<key>regexFileFilter</key>
<string>!(?x: lib/version.js|package\.json |license\.md|paver-minilib\.zip|\.([oa]|dylib|fla|py[co]|mako\.py|pch|cm[oix]|cache|(xcode)proj)|(fish(_read)?_history|fishd\..*)|/Icon\r|/svn-commit(\.[2-9])?\.tmp|/\.(?!(git|svn|npm)ignore|htaccess|gitmodules)[^/]*)$</string>
<key>regexFolderFilter</key>
- <string>!.*/(?x: data | static/vendor|www/js/kraken-ui | var|target|node_modules|html-template|bin-debug | \.((?!git-hooks)[^/]+) | .*\.(egg-info|framework|app|(pbx?|xcode)proj|xcode|bundle) | CVS|_darcs|_MTN|\{arch\}|blib | .*~\.nib )$</string>
+ <string>!.*/(?x: tmp/dygraphs | data | static/vendor|www/js/kraken-ui | var|target|node_modules|html-template|bin-debug | \.((?!git-hooks)[^/]+) | .*\.(egg-info|framework|app|(pbx?|xcode)proj|xcode|bundle) | CVS|_darcs|_MTN|\{arch\}|blib | .*~\.nib )$</string>
+ <key>selected</key>
+ <true/>
<key>sourceDirectory</key>
<string></string>
</dict>
<true/>
<key>name</key>
<string>source</string>
- <key>selected</key>
- <true/>
</dict>
</array>
<key>fileHierarchyDrawerWidth</key>
<key>caret</key>
<dict>
<key>column</key>
- <integer>8</integer>
+ <integer>11</integer>
<key>line</key>
<integer>10</integer>
</dict>
--- /dev/null
+_ = require 'kraken/underscore'
+{ Field, FieldList, FieldView, Scaffold
+} = require 'kraken/scaffold'
+
+
+GraphModel = exports.GraphModel = Backbone.Model.extend do
+ urlRoot : '/graphs'
+
+ initialize : ->
+ name = @get 'name'
+ if name and not (@id or @has 'id')
+ @id = @attributes.id = _.underscored name
+
+ defaults : ->
+ {
+ name : 'Kraken Graph'
+ dataset : 'data/page_views_by_language.csv'
+ options : {}
+ }
+
+
+
+Graph = exports.Graph = Backbone.View.extend do
+ tagName : 'section'
+ className : 'graph'
+
+ events:
+ 'keypress input' : 'onKeypress'
+ 'submit form.settings' : 'onSubmit'
+
+
+ initialize : (o={}) ->
+ @model or= new GraphModel
+
+ @$el.data { model:@model, view:this }
+ @model.on 'change', @render, this
+ @model.on 'destroy', @remove, this
+
+ @viewport = @$el.find '.viewport'
+ @scaffold = new Scaffold do
+ el: @$el.find 'form.settings'
+ @scaffold.collection.reset CHART_OPTIONS_SPEC
+
+ @render()
+
+
+ chartOptions: (values) ->
+ options = @scaffold.collection
+
+ # @chartOptions 'label', 'label value!'
+ if arguments.length > 1
+ [k, v] = arguments
+ values = { "#k": v }
+
+ if values
+ for k, v in values
+ options.get(k)?.setValue v
+ this
+ else
+ options.values()
+
+ render: ->
+ @viewport.empty()
+
+ # Remove old style, as it confuses dygraph after options update
+ @viewport.attr 'style', ''
+ console.log do
+ 'viewport.{ width=%s, height=%s, style=%s }'
+ @viewport.css('width')
+ @viewport.css('height')
+ @viewport.attr 'style'
+ console.log 'options:', JSON.stringify @chartOptions()
+
+ @chart?.destroy()
+ @chart = new Dygraph do
+ @viewport.0
+ 'data/page_views_by_language.csv'
+ @chartOptions()
+
+ onKeypress: (evt) ->
+ $(evt.target).submit() if evt.keyCode is 13
+
+ onSubmit: ->
+ console.log 'Graph.onSubmit!'
+ @render()
+ false
+
+ toString: ->
+ "Graph()"
+
+
+
+
+
+
+
-g = null
+_ = require 'kraken/underscore'
+{ Field, FieldList, FieldView, Scaffold
+} = require 'kraken/scaffold'
+{Graph} = require 'kraken/graph'
+
+
+
+root = do -> this
main = ->
- g := new Dygraph do
- $ '.graph' .eq 0 .find '.viewport' .0
- 'data/page_views_by_language.csv'
- # {'logscale': true}
+ console.log 'main()'
+
+ # root.g = new Dygraph do
+ # $ '.graph' .eq 0 .find '.viewport' .0
+ # 'data/page_views_by_language.csv'
+ # # {'logscale': true}
+ graph = root.graph = new Graph do
+ el : $ 'section.graph' .eq 0
jQuery main
\ No newline at end of file
--- /dev/null
+_ = require 'kraken/underscore'
+op = require 'kraken/util/op'
+
+
+
+Field = exports.Field = Backbone.Model.extend do # {{{
+ idAttribute : 'name'
+
+ initialize: ->
+ @set 'value', @get('default'), {+silent} if not @has 'value'
+
+ defaults: ->
+ {
+ name : ''
+ type : 'String'
+ default : null
+ desc : ''
+ category : 'General'
+ tags : []
+ examples : []
+ }
+
+ getParser: (type) ->
+ type or= @get 'type'
+ t = _ type.toLowerCase()
+
+ parser = op.toStr
+ if t.startsWith 'integer'
+ parser = op.toInt
+ if t.startsWith 'float'
+ parser = op.toFloat
+ if t.startsWith 'boolean'
+ parser = op.toBool
+ if t.startsWith 'object' or t.startsWith 'array'
+ parser = op.toObject
+ if t.startsWith 'function'
+ parser = (fn) -> eval "(#fn)"
+
+ # TODO: handle 'or' by returning an array of parsers
+ parser
+
+
+ getValue: ->
+ @getParser() @get 'value'
+
+ setValue: (v, options) ->
+ def = @get 'default'
+ if not v and def == null
+ val = null
+ else
+ val = @getParser()(v)
+ @set 'value', val, options
+
+ clearValue: ->
+ @set 'value', @get('default')
+
+ isDefault: ->
+ @get('value') is @get('default')
+
+# }}}
+
+
+FieldList = exports.FieldList = Backbone.Collection.extend do # {{{
+ model : Field
+
+ /**
+ *
+ */
+ values: ->
+ _.synthesize do
+ @models.filter -> not it.isDefault()
+ -> [ it.get('name'), it.getValue() ]
+
+ # @reduce do
+ # (acc, field) ->
+ # k = field.get 'name'
+ # v = field.getValue()
+ # if k and not field.isDefault() and v?
+ # acc[k] = v
+ # acc
+ # {}
+
+# }}}
+
+
+### Views
+
+FieldView = exports.FieldView = Backbone.View.extend do # {{{
+ tagName : 'div'
+ className : 'field'
+
+ events :
+ 'blur .value' : 'update'
+ 'submit .value' : 'update'
+
+
+
+ initialize: ->
+ @$el.data { model:@model, view:this }
+ @model.on 'change', @render, this
+ @model.on 'destroy', @remove, this
+
+ update: ->
+ val = @$el.find('.value').val()
+ current = @model.get 'value'
+ return if val is current
+
+ console.log "#this.update( #current -> #val )"
+ @model.setValue val, {+silent}
+
+ render: ->
+ return @remove() if @model.get 'hidden'
+
+ name = @model.get 'name'
+ id = _.camelize name
+ label = _.humanize name
+ @$el.html """
+ <label class="name" for="#id">#label</label>
+ <input class="value" type="text" id="#id" name="#id">
+ """
+ # @$el.find '.value' .attr 'value', @model.get 'value'
+ @$el.find '.value' .val @model.get 'value'
+ this
+
+ remove: ->
+ @$el.remove()
+ this
+
+ clear: ->
+ @model.destroy()
+ this
+
+ toString: ->
+ "FieldView(#{@model.id})"
+
+# }}}
+
+
+# There are several special options that, if passed, will be attached directly to the view:
+# model, collection, el, id, className, tagName, attributes
+
+Scaffold = exports.Scaffold = Backbone.View.extend do # {{{
+ tagName : 'form'
+ className : 'scaffold'
+
+ collectionType : FieldList
+ subviewType : FieldView
+
+
+ initialize: ->
+ _.bindAll this, 'addOne', 'addAll'
+ # @subviews = []
+
+ CollectionType = @collectionType
+ @collection or= new CollectionType
+ @collection.on 'add', @addOne
+ @collection.on 'reset', @addAll
+ # @collection.on 'all', @render
+
+ @$el.addClass @className
+ .data { model:@collection, view:this }
+ .attr { action:'/save', method:'get' }
+
+
+ addOne: (field) ->
+ SubviewType = @subviewType
+ view = new SubviewType model:field
+ # @subviews.push view
+ @$el.append view.render().el
+ view
+
+ addAll: ->
+ # _.invoke @subviews, 'remove'
+ # @subviews = []
+ @collection.each @addOne
+ this
+
+# }}}
+
app.use compiler do
src : WWW
dest : VAR
- enabled : <[ stylus coco ]>
+ enabled : <[ stylus coco pyyaml ]>
options : stylus : { nib:true, include:"#WWW/css" }
log_level : log_level
_.reduce do
o
(acc, [k, v], idx) ->
- if k and filter(v)
+ if k and filter(v, k)
acc[k] = v
acc
{}
# type coercion (w/ limited parameters for mapping)
parseBool : parseBool
- toBool : (v) -> !! v
+ toBool : parseBool
toInt : (v) -> parseInt v
toFloat : (v) -> parseFloat v
toStr : (v) -> String v
+ toObject : (v) -> JSON.parse v
# comparison
cmp : (x,y) -> if x < y then -1 else (if x > y then 1 else 0)
+
- name: width
type: Integer
default: 480
- color-cycle
- multi-scale
- value-axis-formatters
+
- name: height
type: Integer
default: 320
- color-cycle
- multi-scale
- value-axis-formatters
+
- name: annotationClickHandler
type: function(annotation, point, dygraph, event)
default: null
- handler
examples:
- annotation
+
- name: annotationDblClickHandler
type: function(annotation, point, dygraph, event)
default: null
- handler
examples:
- annotation
+
- name: annotationMouseOutHandler
type: function(annotation, point, dygraph, event)
default: null
- handler
examples:
- annotation
+
- name: annotationMouseOverHandler
type: function(annotation, point, dygraph, event)
default: null
- handler
examples:
- annotation
+
- name: displayAnnotations
type: Boolean
default: false
- annotations
examples:
- annotation-gviz
+
- name: avoidMinZero
type: Boolean
default: false
- axes
examples:
- avoidMinZero
+
- name: axis
type: String or Object
default: null
- steps
- two-axes-vr
- value-axis-formatters
+
- name: axisLabelColor
type: String
default: black
category: Axes
tags:
- axes
+
- name: axisLabelFontSize
type: Integer
default: 14
category: Axes
tags:
- axes
+
- name: axisLabelFormatter
type: function(number or Date, granularity, opts, dygraph)
- default: Depends on the data type
+ default: null
desc: Function to call to format the tick values that appear along an axis. This is usually set on
a per-axis basis. The first parameter is either a number (for a numeric axis) or a Date object
(for a date axis). The second argument specifies how fine-grained the axis is. For date axes,
- x-axis-formatter
- y-axis-formatter
- value-axis-formatters
+
- name: axisLabelWidth
type: Integer
default: 50
tags:
- axes
- labels
+
- name: axisLineColor
type: String
default: black
- axes
examples:
- demo
+
- name: axisLineWidth
type: Float
default: 0.3
category: Axes
tags:
- axes
+
- name: axisTickSize
type: Number
default: '3.0'
category: Axes
tags:
- axes
+
- name: dateWindow
type: Array of two Dates or numbers
- default: Full range of the input is shown
+ default: null
desc: Initially zoom in on a section of the graph. Is of the form [earliest, latest], where earliest/latest
are milliseconds since epoch. If the data for the x-axis is numeric, the values in dateWindow
- must also be numbers.
+ must also be numbers. By default, the full range of the input is shown.
category: Axes
tags:
- axes
- link-interaction
- synchronize
- zoom
+
- name: drawXAxis
type: Boolean
default: true
- axes
examples:
- unboxed-spark
+
- name: drawYAxis
type: Boolean
default: true
examples:
- drawing
- unboxed-spark
+
- name: includeZero
type: Boolean
default: false
- no-range
- numeric-gviz
- small-range-zero
+
- name: logscale
type: Boolean
default: false
examples:
- logscale
- stock
+
- name: panEdgeFraction
type: Float
default: null
- interactive elements
examples:
- zoom
+
- name: pixelsPerLabel
type: Integer
- default: 60 (x-axis) or 30 (y-axes)
+ default: null
desc: Number of pixels to require between each x- and y-label. Larger values will yield a sparser
- axis with fewer ticks. This is set on a per-axis basis.
+ axis with fewer ticks. This is set on a per-axis basis. By default, values are 60 (x-axis) or 30 (y-axes).
category: Axes
tags:
- axes
- grid
examples:
- value-axis-formatters
+
- name: ticker
type: "function(min, max, pixels, opts, dygraph, vals) -> [{v: ..., label: ...}, ...]"
- default: Dygraph.dateTicker or Dygraph.numericTicks
+ default: null
desc: This lets you specify an arbitrary function to generate tick marks on an axis. The tick marks
are an array of (value, label) pairs. The built-in functions go to great lengths to choose good
tick marks so, if you set this option, you'll most likely want to call one of them and modify
- the result. See dygraph-tickers.js for an extensive discussion. This is set on a per-axis basis.
+ the result. By default, uses Dygraph.dateTicker or Dygraph.numericTicks, but see
+ dygraph-tickers.js for an extensive discussion. This is set on a per-axis basis.
category: Axes
tags:
- axes
+
- name: valueRange
type: Array of two numbers
- default: Full range of the input is shown
+ default: null
desc: Explicitly set the vertical range of the graph to [low, high]. This may be set on a per-axis
- basis to define each y-axis separately.
+ basis to define each y-axis separately. By default, the full range of the input is shown.
category: Axes
tags:
- axes
- synchronize
- zoom
- two-axes-vr
+
- name: xAxisHeight
type: Integer
default: null
category: Axes
tags:
- axes
+
- name: xAxisLabelWidth
type: Integer
default: 50
examples:
- x-axis-formatter
- value-axis-formatters
+
- name: yAxisLabelWidth
type: Integer
default: 50
- multi-scale
- two-axes-vr
- value-axis-formatters
+
- name: delimiter
type: String
default: ','
category: CSV parsing
tags:
- csv parsing
+
- name: xValueParser
type: function(str) -> number
- default: parseFloat() or Date.parse()*
+ default: null
desc: A function which parses x-values (i.e. the dependent series). Must return a number, even when
the values are dates. In this case, millis since epoch are used. This is used primarily for parsing
CSV data. *=Dygraphs is slightly more accepting in the dates which it will parse. See code for
category: CSV parsing
tags:
- csv parsing
+
- name: clickCallback
type: function(e, x, points)
default: null
- callbacks
examples:
- callback
+
- name: drawCallback
type: function(dygraph, is_initial)
default: null
- is-zoomed-ignore-programmatic-zoom
- synchronize
- zoom
+
- name: highlightCallback
type: function(event, x, points,row)
default: null
examples:
- callback
- crosshair
+
- name: underlayCallback
type: function(canvas, area, dygraph)
default: null
- linear-regression-fractions
- linear-regression
- underlay-callback
+
- name: unhighlightCallback
type: function(event)
default: null
examples:
- callback
- crosshair
+
- name: zoomCallback
type: function(minDate, maxDate, yRanges)
default: null
- callback
- is-zoomed-ignore-programmatic-zoom
- zoom
+
- name: title
type: String
default: null
- multi-scale
- range-selector
- temperature-sf-ny
+
- name: titleHeight
type: Integer
default: 18
- chart labels
examples:
- styled-chart-labels
+
- name: xLabelHeight
type: Integer
default: 18
category: Chart labels
tags:
- chart labels
+
- name: xlabel
type: String
default: null
- demo
- styled-chart-labels
- multi-scale
+
- name: y2label
type: String
default: null
examples:
- two-axes
- two-axes-vr
+
- name: yLabelWidth
type: Integer
default: 18
category: Chart labels
tags:
- chart labels
+
- name: ylabel
type: String
default: null
- range-selector
- temperature-sf-ny
- two-axes-vr
+
-&n