@plotdb/chart 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -1
- package/CHANGELOG.md +0 -29
- package/build +0 -45
- package/doc/charts.md +0 -58
- package/doc/config.md +0 -44
- package/doc/draft/chart.md +0 -146
- package/doc/draft/data.md +0 -8
- package/doc/draft/definition.md +0 -0
- package/doc/draft/events.md +0 -0
- package/doc/draft/filter.md +0 -0
- package/doc/draft/lifecycle.md +0 -89
- package/doc/spec.md +0 -89
- package/doc/todo.md +0 -27
- package/doc/utils/tip.md +0 -84
- package/src/data/en-US/category +0 -20
- package/src/data/en-US/fruit +0 -39
- package/src/data/en-US/movie +0 -125
- package/src/data/en-US/name +0 -58
- package/src/data/index.ls +0 -34
- package/src/data/zh-TW/category +0 -20
- package/src/data/zh-TW/fruits +0 -38
- package/src/data/zh-TW/movie +0 -125
- package/src/data/zh-TW/names +0 -105
- package/src/index.ls +0 -323
- package/src/index.styl +0 -6
- package/src/utils/axis.ls +0 -229
- package/src/utils/config.ls +0 -11
- package/src/utils/data.ls +0 -104
- package/src/utils/format.ls +0 -30
- package/src/utils/legend.ls +0 -134
- package/src/utils/legend.styl +0 -37
- package/src/utils/tint.ls +0 -66
- package/src/utils/tip.ls +0 -97
- package/web/src/pug/base.pug +0 -21
- package/web/src/pug/block/axis/0.0.1/index.ls +0 -32
- package/web/src/pug/block/axis/0.0.1/index.pug +0 -1
- package/web/src/pug/block/axis-bubble/0.0.1/index.ls +0 -137
- package/web/src/pug/block/axis-bubble/0.0.1/index.pug +0 -1
- package/web/src/pug/block/bar/0.0.1/index.ls +0 -270
- package/web/src/pug/block/bar/0.0.1/index.pug +0 -35
- package/web/src/pug/block/bar-list/0.0.1/index.ls +0 -81
- package/web/src/pug/block/bar-list/0.0.1/index.pug +0 -30
- package/web/src/pug/block/bar-race/0.0.1/index.ls +0 -79
- package/web/src/pug/block/bar-race/0.0.1/index.pug +0 -21
- package/web/src/pug/block/base/0.0.1/index.ls +0 -66
- package/web/src/pug/block/base/0.0.1/index.pug +0 -5
- package/web/src/pug/block/blank/0.0.1/index.ls +0 -21
- package/web/src/pug/block/blank/0.0.1/index.pug +0 -1
- package/web/src/pug/block/bubble/0.0.1/index.ls +0 -218
- package/web/src/pug/block/bubble/0.0.1/index.pug +0 -42
- package/web/src/pug/block/curve-bar/0.0.1/index.ls +0 -85
- package/web/src/pug/block/curve-bar/0.0.1/index.pug +0 -16
- package/web/src/pug/block/curve-bar/0.0.1/sample.js +0 -338
- package/web/src/pug/block/dumbbell/0.0.1/index.ls +0 -86
- package/web/src/pug/block/dumbbell/0.0.1/index.pug +0 -1
- package/web/src/pug/block/empty/0.0.1/index.ls +0 -28
- package/web/src/pug/block/empty/0.0.1/index.pug +0 -2
- package/web/src/pug/block/gauge/0.0.1/index.ls +0 -96
- package/web/src/pug/block/gauge/0.0.1/index.pug +0 -31
- package/web/src/pug/block/gauge/0.0.1/sample.js +0 -338
- package/web/src/pug/block/line/0.0.1/index.ls +0 -297
- package/web/src/pug/block/line/0.0.1/index.pug +0 -33
- package/web/src/pug/block/number/0.0.1/index.ls +0 -65
- package/web/src/pug/block/number/0.0.1/index.pug +0 -20
- package/web/src/pug/block/percent-list/0.0.1/index.ls +0 -161
- package/web/src/pug/block/percent-list/0.0.1/index.pug +0 -34
- package/web/src/pug/block/pie/0.0.1/index.ls +0 -121
- package/web/src/pug/block/pie/0.0.1/index.pug +0 -19
- package/web/src/pug/block/pie/0.0.1/sample.js +0 -338
- package/web/src/pug/block/pie-bubble/0.0.1/index.ls +0 -181
- package/web/src/pug/block/pie-bubble/0.0.1/index.pug +0 -40
- package/web/src/pug/block/radar/0.0.1/index.ls +0 -109
- package/web/src/pug/block/radar/0.0.1/index.pug +0 -1
- package/web/src/pug/block/radar/0.0.1/xx +0 -285
- package/web/src/pug/block/scatter/0.0.1/index.ls +0 -124
- package/web/src/pug/block/scatter/0.0.1/index.pug +0 -30
- package/web/src/pug/block/sheet/0.0.1/index.ls +0 -34
- package/web/src/pug/block/sheet/0.0.1/index.pug +0 -5
- package/web/src/pug/block/table/0.0.1/index.ls +0 -36
- package/web/src/pug/block/table/0.0.1/index.pug +0 -3
- package/web/src/pug/block/taiwancounty/0.0.1/index.ls +0 -70
- package/web/src/pug/block/taiwancounty/0.0.1/index.pug +0 -64
- package/web/src/pug/block/taiwantown/0.0.1/index.ls +0 -44
- package/web/src/pug/block/taiwantown/0.0.1/index.pug +0 -52
- package/web/src/pug/block/taiwanvillage/0.0.1/index.ls +0 -49
- package/web/src/pug/block/taiwanvillage/0.0.1/index.pug +0 -52
- package/web/src/pug/block/treemap/0.0.1/index.ls +0 -168
- package/web/src/pug/block/treemap/0.0.1/index.pug +0 -42
- package/web/src/pug/block/voronoi-treemap/0.0.1/index.ls +0 -170
- package/web/src/pug/block/voronoi-treemap/0.0.1/index.pug +0 -17
- package/web/src/pug/block/voronoi-treemap/0.0.1/sample.js +0 -241
- package/web/src/pug/block/wordcloud/0.0.1/index.ls +0 -57
- package/web/src/pug/block/wordcloud/0.0.1/index.pug +0 -1
- package/web/src/pug/block/worldmap/0.0.1/index.ls +0 -77
- package/web/src/pug/block/worldmap/0.0.1/index.pug +0 -12
- package/web/src/pug/index.ls +0 -72
- package/web/src/pug/index.pug +0 -51
- package/web/src/styl/index.styl +0 -6
- package/web/static/assets/block/cache.js +0 -4
- package/web/static/assets/custom-lib/d3/d3-array.v2.js +0 -1182
- package/web/static/assets/custom-lib/d3/d3-array.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-array.v3.js +0 -1273
- package/web/static/assets/custom-lib/d3/d3-array.v3.min.js +0 -1273
- package/web/static/assets/custom-lib/d3/d3-axis.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-brush.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-color.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-dispatch.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-drag.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-ease.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-force-boundary.v0.0.1.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-force.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-format.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-geo.v2.js +0 -3127
- package/web/static/assets/custom-lib/d3/d3-geo.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-hierarchy.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-interpolate.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-path.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-quadtree.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-random.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-scale-chromatic.v1.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-selection.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-shape.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-timer.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3-transition.v2.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3.v4.js +0 -17178
- package/web/static/assets/custom-lib/d3/d3.v4.min.js +0 -2
- package/web/static/assets/custom-lib/d3/d3.v6.js +0 -19708
- package/web/static/assets/data/countrycode.json +0 -1
- package/web/static/assets/data/world-110m.json +0 -1
- package/web/static/assets/data/zh-to-alpha2.json +0 -1
- package/web/static/assets/img/fluid.svg +0 -16
- package/web/static/block/axis/0.0.1/index.html +0 -74
- package/web/static/block/axis-bubble/0.0.1/index.html +0 -217
- package/web/static/block/bar/0.0.1/index.html +0 -576
- package/web/static/block/bar-list/0.0.1/index.html +0 -226
- package/web/static/block/bar-race/0.0.1/index.html +0 -179
- package/web/static/block/base/0.0.1/index.html +0 -197
- package/web/static/block/blank/0.0.1/index.html +0 -37
- package/web/static/block/bubble/0.0.1/index.html +0 -422
- package/web/static/block/bubble/0.0.1/test.html +0 -0
- package/web/static/block/curve-bar/0.0.1/index.html +0 -143
- package/web/static/block/dumbbell/0.0.1/index.html +0 -173
- package/web/static/block/empty/0.0.1/index.html +0 -76
- package/web/static/block/gauge/0.0.1/index.html +0 -145
- package/web/static/block/line/0.0.1/index.html +0 -566
- package/web/static/block/number/0.0.1/index.html +0 -147
- package/web/static/block/percent-list/0.0.1/index.html +0 -311
- package/web/static/block/pie/0.0.1/index.html +0 -276
- package/web/static/block/pie-bubble/0.0.1/index.html +0 -353
- package/web/static/block/radar/0.0.1/index.html +0 -144
- package/web/static/block/scatter/0.0.1/index.html +0 -246
- package/web/static/block/sheet/0.0.1/index.html +0 -98
- package/web/static/block/table/0.0.1/index.html +0 -67
- package/web/static/block/taiwancounty/0.0.1/index.html +0 -197
- package/web/static/block/taiwantown/0.0.1/index.html +0 -205
- package/web/static/block/taiwanvillage/0.0.1/index.html +0 -215
- package/web/static/block/treemap/0.0.1/index.html +0 -355
- package/web/static/block/voronoi-treemap/0.0.1/index.html +0 -345
- package/web/static/block/wordcloud/0.0.1/index.html +0 -87
- package/web/static/block/worldmap/0.0.1/index.html +0 -202
- package/web/static/css/index.css +0 -6
- package/web/static/css/index.min.css +0 -1
- package/web/static/favicon.ico +0 -0
- package/web/static/index.html +0 -153
package/src/index.ls
DELETED
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
svgns = "http://www.w3.org/2000/svg"
|
|
2
|
-
|
|
3
|
-
parent = (n, s, e) ->
|
|
4
|
-
m = n
|
|
5
|
-
while n and n != e => n = n.parentNode # must under e
|
|
6
|
-
if n != e => return null
|
|
7
|
-
# if no selector - we are testing if s is under e.
|
|
8
|
-
if !s => return n
|
|
9
|
-
# must match s selector
|
|
10
|
-
n = m
|
|
11
|
-
while n and n != e and (!n.matches or (n.matches and !n.matches(s))) => n = n.parentNode
|
|
12
|
-
if n == e and (!e.matches or !e.matches(s)) => return null
|
|
13
|
-
return n
|
|
14
|
-
|
|
15
|
-
aniloop = ->
|
|
16
|
-
@running = false
|
|
17
|
-
@time = { now: 0, last: 0 }
|
|
18
|
-
@fps 60
|
|
19
|
-
@evt-handler = {}
|
|
20
|
-
@
|
|
21
|
-
|
|
22
|
-
aniloop.prototype = Object.create(Object.prototype) <<< do
|
|
23
|
-
on: (n, cb) -> (if Array.isArray(n) => n else [n]).map (n) ~> @evt-handler.[][n].push cb
|
|
24
|
-
fire: (n, ...v) -> for cb in (@evt-handler[n] or []) => cb.apply @, v
|
|
25
|
-
reset: -> @time = {now: 0}
|
|
26
|
-
set-time: (t) -> @time.now = t
|
|
27
|
-
get-time: -> @time.now
|
|
28
|
-
is-running: -> @running
|
|
29
|
-
toggle: ->
|
|
30
|
-
if it? => @running = !it
|
|
31
|
-
if @running => @pause! else @run!
|
|
32
|
-
pause: -> @running = false
|
|
33
|
-
render: -> @fire \tick, @time.now
|
|
34
|
-
run: (fps) ->
|
|
35
|
-
if fps? => @fps fps
|
|
36
|
-
if @running => return
|
|
37
|
-
@running = true
|
|
38
|
-
requestAnimationFrame (t) ~> @handler(@time.last = t, true)
|
|
39
|
-
throttle: (v = true) -> @is-throttled = v
|
|
40
|
-
fps: ->
|
|
41
|
-
if !(it?) => return @_fps_val
|
|
42
|
-
@_fps_val = it >? 0.01
|
|
43
|
-
@_fps_delay = 1000 / @_fps_val
|
|
44
|
-
handler: (t, force = false) ->
|
|
45
|
-
if !@running => return
|
|
46
|
-
@time.now = t
|
|
47
|
-
delay = if @is-throttled => (@_fps_delay >? 1000) else @_fps_delay
|
|
48
|
-
if force or (@time.now - @time.last) >= delay =>
|
|
49
|
-
@time.last = t
|
|
50
|
-
@render!
|
|
51
|
-
requestAnimationFrame (t) ~> @handler t, false
|
|
52
|
-
|
|
53
|
-
visibilityObserver = do
|
|
54
|
-
list: []
|
|
55
|
-
init: ->
|
|
56
|
-
@inited = true
|
|
57
|
-
[h,vc] = if document.hidden? => <[hidden visibilitychange]>
|
|
58
|
-
else if document.msHidden? => <[hidden visibilitychange]>
|
|
59
|
-
else if document.webkiHidden? => <[webkitHidden webkitvisibilitychange]>
|
|
60
|
-
else <[hidden visibilitychange]>
|
|
61
|
-
document.addEventListener vc, debounce 150, (~>
|
|
62
|
-
th = !!document[h]
|
|
63
|
-
#console.log "visibility changed, #{if th => 'enable' else 'disable'} chart aniloop throttling."
|
|
64
|
-
@list.map -> it.throttle th
|
|
65
|
-
), false
|
|
66
|
-
add: (aniloop) ->
|
|
67
|
-
if !@inited => @init!
|
|
68
|
-
@list.push aniloop
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
resizeObserver = do
|
|
72
|
-
wm: new WeakMap!
|
|
73
|
-
ro: new ResizeObserver (list) ->
|
|
74
|
-
list.map (n) ->
|
|
75
|
-
ret = resizeObserver.wm.get(n.target)
|
|
76
|
-
ret._resize!
|
|
77
|
-
add: (node, obj) ->
|
|
78
|
-
@wm.set node, obj
|
|
79
|
-
@ro.observe node
|
|
80
|
-
# observer won't fire the init event if node is not visible.
|
|
81
|
-
# - nonfixed - offsetParent will be null if it's hidden via the display style property.
|
|
82
|
-
# - fixed - check display property.
|
|
83
|
-
# - reference:
|
|
84
|
-
# - https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent
|
|
85
|
-
# - https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
|
|
86
|
-
# thus, if we want to always fire right after node added, we then need:
|
|
87
|
-
# if !node.offsetParent or window.getComputedStyle(node).display == \none => obj._resize!
|
|
88
|
-
|
|
89
|
-
delete: ->
|
|
90
|
-
@ro.unobserve it
|
|
91
|
-
@wm.delete it
|
|
92
|
-
|
|
93
|
-
with-default = (cfg = {}, defcfg = {}) ->
|
|
94
|
-
defcfg = JSON.parse JSON.stringify defcfg
|
|
95
|
-
_ = (cfg, defcfg) ->
|
|
96
|
-
for k,v of defcfg =>
|
|
97
|
-
if !(cfg[k]?) => cfg[k] = v
|
|
98
|
-
else if typeof(cfg[k]) == \object and typeof(v) == \object => with-default(cfg[k], defcfg[k])
|
|
99
|
-
return cfg
|
|
100
|
-
return _ cfg, defcfg
|
|
101
|
-
|
|
102
|
-
# use this for now since we don't want to strictly depends on konfig. ( TBD )
|
|
103
|
-
default-config = (cfg) ->
|
|
104
|
-
_ = (meta, ret = {}) ->
|
|
105
|
-
ctrls = if meta.child => that else meta
|
|
106
|
-
for id,v of meta =>
|
|
107
|
-
if !v.type => _(v, ret{}[id])
|
|
108
|
-
else if v.default => ret[id] = v.default
|
|
109
|
-
return ret
|
|
110
|
-
return _ cfg
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
chart = (opt={}) ->
|
|
114
|
-
@root = if typeof(opt.root) == \string => document.querySelector(opt.root) else opt.root
|
|
115
|
-
@use-sample = if opt.use-sample? => opt.use-sample else true
|
|
116
|
-
@auto-select = if opt.auto-select? => opt.auto-select else true
|
|
117
|
-
@force-init = if opt.force-init => opt.force-init else false
|
|
118
|
-
@prepare-svg = if opt.prepare-svg? => opt.prepare-svg else true
|
|
119
|
-
@layout-opt = if opt.layout? => opt.layout else true
|
|
120
|
-
@delay-render = opt.delay-render or false
|
|
121
|
-
@data-accessor = if opt.data-accessor? => opt.data-accessor else (->if it => it.data._raw else null)
|
|
122
|
-
@raw = opt.raw or null
|
|
123
|
-
@mod = opt.mod or {}
|
|
124
|
-
@cfg = opt.config or {}
|
|
125
|
-
@seed = opt.seed or Math.random!
|
|
126
|
-
@binding = opt.binding or {}
|
|
127
|
-
@evt-handler = {}
|
|
128
|
-
@init = proxise.once ~> @_init!
|
|
129
|
-
# _resize is for and (should only be) used by `ResizeObserver`
|
|
130
|
-
@_resize = null
|
|
131
|
-
|
|
132
|
-
if @auto-select =>
|
|
133
|
-
@root.addEventListener \click, @_select = (e) ~>
|
|
134
|
-
if !(p = parent e.target, '.data', @root) => return
|
|
135
|
-
@fire \select, [{data: @data-accessor(p), node: p}]
|
|
136
|
-
@root.addEventListener \mouseover, @_hover = (e) ~>
|
|
137
|
-
if !(p = ld$.parent e.target, '.data', @root) => return
|
|
138
|
-
@fire \hover, [{data: @data-accessor(p), node: p}]
|
|
139
|
-
|
|
140
|
-
@
|
|
141
|
-
|
|
142
|
-
chart.prototype = Object.create(Object.prototype) <<< do
|
|
143
|
-
# we use `init` to ensure called once, and put the actual code in _init.
|
|
144
|
-
_init: ->
|
|
145
|
-
if window.getComputedStyle(@root).position == \static => @root.style.position = \relative
|
|
146
|
-
layout-root = if @layout-opt =>
|
|
147
|
-
if typeof(@layout-opt) != \object => @root.querySelector(\.pdl-layout)
|
|
148
|
-
else if typeof(@layout-opt.root) == \string => @root.querySelector(@layout-opt.root)
|
|
149
|
-
else if @layout-opt.root => @layout-opt.root
|
|
150
|
-
else null
|
|
151
|
-
else null
|
|
152
|
-
if @prepare-svg and !(@svg = @root.querySelector \svg) =>
|
|
153
|
-
@svg = document.createElementNS(svgns, "svg")
|
|
154
|
-
@svg.style <<< width: "100%", height: "100%"
|
|
155
|
-
if @layout-opt =>
|
|
156
|
-
if !layout-root =>
|
|
157
|
-
console.error "[@plotdb/chart] layout enabled yet layout root isn't configured properly. "
|
|
158
|
-
r = layout-root.querySelector('[data-type=render]')
|
|
159
|
-
if !r => console.warn """
|
|
160
|
-
[@plotdb/chart] prepareSvg and layout is configured at the same time,
|
|
161
|
-
yet render container for layout is not found. svg is thus appended in the root.
|
|
162
|
-
"""
|
|
163
|
-
(r or @root).appendChild @svg
|
|
164
|
-
|
|
165
|
-
# this can be implemented with singleton pattern
|
|
166
|
-
@_aniloop = new aniloop!
|
|
167
|
-
visibilityObserver.add @_aniloop
|
|
168
|
-
@_aniloop.on \tick, ~> @tick!
|
|
169
|
-
p = Promise.resolve!
|
|
170
|
-
.then ~>
|
|
171
|
-
defcfg = default-config(@mod.config or {})
|
|
172
|
-
with-default @cfg, defcfg
|
|
173
|
-
if @raw and Array.isArray(@raw) => return
|
|
174
|
-
if !@use-sample or !@mod.sample => return
|
|
175
|
-
ret = @mod.sample.apply @
|
|
176
|
-
return if ret.then => ret.then! else Promise.resolve ret
|
|
177
|
-
.then ~> @ <<<(it or {}){raw, binding}
|
|
178
|
-
.then ~>
|
|
179
|
-
if !@raw => @raw = []
|
|
180
|
-
if @layout-opt =>
|
|
181
|
-
if !(layout?) => console.warn "[@plotdb/chart] layout-opt is set yet @plotdb/layout is not found."
|
|
182
|
-
else
|
|
183
|
-
if !layout-root =>
|
|
184
|
-
console.error "[@plotdb/chart] cannot determine root node for @plotdb/layout."
|
|
185
|
-
console.error "[@plotdb/chart] config layout properly or disable layout by setting layout to false"
|
|
186
|
-
@layout = new layout(
|
|
187
|
-
if typeof(@layout-opt) == \object => ({} <<< @layout-opt <<< {watch-resize: false})
|
|
188
|
-
else {root: layout-root, watch-resize: false}
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
# we don't know when resizeObserver will call _resize but we need it to be called.
|
|
192
|
-
# thus, we lock execution here until resizeObserver calls _resize
|
|
193
|
-
_resize-lock = proxise ~> resizeObserver.add(@root, @); return null
|
|
194
|
-
# however, if somewhat resizeObserver won't be called soon ( due to invisibility of node )
|
|
195
|
-
# we then may want to get around it.
|
|
196
|
-
# see also: `resizeObserver.add` above.
|
|
197
|
-
if @force-init and !@root.offsetParent or window.getComputedStyle(@root).display == \none => return
|
|
198
|
-
# - unlocker
|
|
199
|
-
@_resize = -> _resize-lock.resolve!
|
|
200
|
-
# - locker
|
|
201
|
-
_resize-lock!
|
|
202
|
-
.then ~>
|
|
203
|
-
# once resizeObserver called _resize, we temporarily disable it until init is finished.
|
|
204
|
-
@_resize = ~>
|
|
205
|
-
.then ~>
|
|
206
|
-
# if no layout used, we init directly. otherwise we will call mod.init in layout.init
|
|
207
|
-
# we have to do this because:
|
|
208
|
-
# - layout prepare necessary dom which may be used by init
|
|
209
|
-
# - but init may generate necessary dom for layout.update
|
|
210
|
-
init = ~> if @mod.init => @mod.init.apply(@)
|
|
211
|
-
if !@layout => return init!
|
|
212
|
-
layout-lock = proxise ~> Promise.resolve(@layout.init init); return null
|
|
213
|
-
@_layout = ~> layout-lock.resolve!
|
|
214
|
-
@layout.on \render, ~> @_layout!
|
|
215
|
-
layout-lock!
|
|
216
|
-
.then ~>
|
|
217
|
-
# once layout prepared, we temporarily disable layout update event until init is finished.
|
|
218
|
-
@_layout = ~>
|
|
219
|
-
Promise.resolve!
|
|
220
|
-
.then ~>
|
|
221
|
-
# if for any reason user doesn't want to render right after init
|
|
222
|
-
# then we just lock it until set-raw.
|
|
223
|
-
if !@delay-render => return
|
|
224
|
-
@render-lock = proxise ~>
|
|
225
|
-
@render-lock!
|
|
226
|
-
.then ~>
|
|
227
|
-
# init is finished and we are prepared to render.
|
|
228
|
-
@_resize = ~> @resize!; @render!
|
|
229
|
-
@_layout = ~> @parse!; @bind!; @resize!; @render!
|
|
230
|
-
@parse!
|
|
231
|
-
@bind!
|
|
232
|
-
@resize!
|
|
233
|
-
@render!
|
|
234
|
-
# explicit return non-promise so init is declared as finished
|
|
235
|
-
# and won't block following codes.
|
|
236
|
-
return
|
|
237
|
-
|
|
238
|
-
parse: ->
|
|
239
|
-
@data = @raw.map (r,i) ~>
|
|
240
|
-
ret = {}
|
|
241
|
-
[{k,v} for k,v of @binding].map ({k,v}) ~>
|
|
242
|
-
if !v => return
|
|
243
|
-
ret[k] = if @mod.{}dimension{}[k].multiple => v.map -> r[it.key]
|
|
244
|
-
else r[v.key]
|
|
245
|
-
t = @mod.{}dimension{}[k].type
|
|
246
|
-
# TODO Since 'RC' is also possible, we should add and check the matched type instead of supported type.
|
|
247
|
-
if /[RIT]/.exec(t) and !/[CN]/.exec(t) =>
|
|
248
|
-
ret[k] = if Array.isArray(ret[k]) => ret[k].map(->parseFloat(it)) else parseFloat(ret[k])
|
|
249
|
-
ret._raw = r
|
|
250
|
-
ret._idx = i
|
|
251
|
-
ret
|
|
252
|
-
if @mod.parse => @mod.parse.apply @
|
|
253
|
-
bind: -> if @mod.bind => @mod.bind.apply @
|
|
254
|
-
start: ->
|
|
255
|
-
@_aniloop.run!
|
|
256
|
-
if @mod.start => @mod.start.apply @
|
|
257
|
-
stop: ->
|
|
258
|
-
@_aniloop.pause!
|
|
259
|
-
if @mod.stop => @mod.stop.apply @
|
|
260
|
-
resize: ->
|
|
261
|
-
# layout resize is disabled to prevent unnecessary rendering.
|
|
262
|
-
# however, we still need layout to be update ( without firing render event )
|
|
263
|
-
if @layout => @layout.update false
|
|
264
|
-
@box = @root.getBoundingClientRect!
|
|
265
|
-
if @mod.resize => @mod.resize.apply @
|
|
266
|
-
tick: -> if @mod.tick => @mod.tick.apply @
|
|
267
|
-
render: -> if @mod.render => @mod.render.apply @
|
|
268
|
-
destroy: ->
|
|
269
|
-
Promise.resolve!then ~>
|
|
270
|
-
if @_select => @root.removeEventListener \click, @_select
|
|
271
|
-
if @_hover => @root.removeEventListener \mouseover, @_hover
|
|
272
|
-
resizeObserver.delete @root
|
|
273
|
-
if @layout => @layout.destroy!
|
|
274
|
-
@stop!
|
|
275
|
-
if @mod.destroy => return @mod.destroy.apply @
|
|
276
|
-
|
|
277
|
-
config: (opt) ->
|
|
278
|
-
if !(opt? and opt) => return @cfg
|
|
279
|
-
@cfg <<< opt
|
|
280
|
-
|
|
281
|
-
set-bind: (n,b) ->
|
|
282
|
-
@binding[n] = b
|
|
283
|
-
@parse!
|
|
284
|
-
@bind!
|
|
285
|
-
@resize!
|
|
286
|
-
@render!
|
|
287
|
-
|
|
288
|
-
set-raw: (raw, binding, reinit = false) ->
|
|
289
|
-
if !Array.isArray(raw) => {raw,binding,reinit} = raw
|
|
290
|
-
if raw? => @raw = raw
|
|
291
|
-
if binding? => @binding = binding
|
|
292
|
-
# if there is render-lock, then we are still in initing process and no need to reinit.
|
|
293
|
-
# reinit is only needed if there is no render-lock
|
|
294
|
-
if @render-lock =>
|
|
295
|
-
@render-lock.resolve!
|
|
296
|
-
@render-lock = null
|
|
297
|
-
else
|
|
298
|
-
if reinit and @mod.init => @mod.init.apply(@)
|
|
299
|
-
@parse!
|
|
300
|
-
@bind!
|
|
301
|
-
@resize!
|
|
302
|
-
@render!
|
|
303
|
-
on: (n, cb) -> (if Array.isArray(n) => n else [n]).map (n) ~> @evt-handler.[][n].push cb
|
|
304
|
-
fire: (n, ...v) -> for cb in (@evt-handler[n] or []) => cb.apply @, v
|
|
305
|
-
filter: (filters = {}, internal = false) ->
|
|
306
|
-
bs = []
|
|
307
|
-
for k,v of @binding =>
|
|
308
|
-
u = if Array.isArray(v) => v else [v]
|
|
309
|
-
u = u.map (v) -> {k,v}
|
|
310
|
-
bs ++= u
|
|
311
|
-
for k,v of filters =>
|
|
312
|
-
bs
|
|
313
|
-
.filter(-> it.k == k)
|
|
314
|
-
.map -> it.v.filter = v
|
|
315
|
-
if internal => @fire \filter, filters
|
|
316
|
-
if @mod.filter => @mod.filter.apply @, [filters, internal]
|
|
317
|
-
@parse!
|
|
318
|
-
@bind!
|
|
319
|
-
@resize!
|
|
320
|
-
@render!
|
|
321
|
-
|
|
322
|
-
if module? => module.exports = chart
|
|
323
|
-
else if window? => window.chart = chart
|
package/src/index.styl
DELETED
package/src/utils/axis.ls
DELETED
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
ceNS = -> document.createElementNS("http://www.w3.org/2000/svg", it)
|
|
2
|
-
|
|
3
|
-
axis = (opt={}) ->
|
|
4
|
-
@dir = {"bottom": 0, "left": 2}[opt.direction or 'bottom']
|
|
5
|
-
@name = opt.name or \axis
|
|
6
|
-
# unlike legend, we don't use n.layout to layout things, only use its primary size.
|
|
7
|
-
# we will update n.layout's secondary size, it won't affect how we layout things.
|
|
8
|
-
# so we don't need layout.update before rendering.
|
|
9
|
-
# layout.update is still needed after rendering for stuff outside axis to work.
|
|
10
|
-
# TODO still yaxis and xaxis may affect each other to cause a recursive update,
|
|
11
|
-
# so we have to be careful and have some constraint over this. (e.g., set max size of n.layout)
|
|
12
|
-
@layout = opt.layout or new layout root: @root
|
|
13
|
-
@_ticks = []
|
|
14
|
-
@_scale = opt.scale or (->it)
|
|
15
|
-
@_format = opt.format or if chart? => chart.utils.format.simple else (->it)
|
|
16
|
-
@cfg = {tick-size: 8} <<< opt.cfg
|
|
17
|
-
@_map = {} # tick value -> object{v,c,t,n,g}
|
|
18
|
-
@_n = n =
|
|
19
|
-
root: ceNS \g # root node, appended to render node
|
|
20
|
-
layout: @layout.get-node(@name) # decide render region size
|
|
21
|
-
render: @layout.get-group(@name) # render region node
|
|
22
|
-
wrap: null # for wrapping tick text
|
|
23
|
-
domain: ceNS \path # axis domain line
|
|
24
|
-
n.render.appendChild n.root
|
|
25
|
-
n.root.appendChild n.domain
|
|
26
|
-
|
|
27
|
-
n.label = ceNS \text
|
|
28
|
-
n.label.textContent = ''
|
|
29
|
-
n.label
|
|
30
|
-
..setAttribute \dominant-baseline, \hanging
|
|
31
|
-
..setAttribute \text-anchor, \middle
|
|
32
|
-
n.root.appendChild n.label
|
|
33
|
-
@wrapper!
|
|
34
|
-
@layout
|
|
35
|
-
..on \update, ~> @update!
|
|
36
|
-
..on \render, ~> @render!
|
|
37
|
-
@
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
axis.prototype = Object.create(Object.prototype) <<< do
|
|
41
|
-
# while we may only need to update `white-space` and `width`,
|
|
42
|
-
# strangely style changing only works if we replace node with a new one.
|
|
43
|
-
# this is a workaround before we find the root cause.
|
|
44
|
-
wrapper: ->
|
|
45
|
-
n = @_n
|
|
46
|
-
if n.wrap and n.wrap.parentNode => n.wrap.parentNode.removeChild n.wrap
|
|
47
|
-
n.wrap = document.createElement \div
|
|
48
|
-
n.wrap.style <<< {
|
|
49
|
-
visibility: \hidden
|
|
50
|
-
position: \absolute
|
|
51
|
-
top: 0
|
|
52
|
-
left: 0
|
|
53
|
-
pointerEvents: \none
|
|
54
|
-
userSelect: \none
|
|
55
|
-
zIndex: 0
|
|
56
|
-
wordBreak: "break-all"
|
|
57
|
-
lineHeight: \.95em
|
|
58
|
-
} <<< (if @dir < 2 and @cfg.textWidth? => {
|
|
59
|
-
whiteSpace: 'wrap'
|
|
60
|
-
width: "#{@cfg.textWidth >? 1}em"
|
|
61
|
-
} else {whiteSpace: \pre, width: \4em})
|
|
62
|
-
n.layout.appendChild n.wrap
|
|
63
|
-
|
|
64
|
-
config: ->
|
|
65
|
-
if !(it?) => return @cfg
|
|
66
|
-
@cfg <<< it
|
|
67
|
-
if @cfg.format => @format @cfg.format
|
|
68
|
-
@wrapper!
|
|
69
|
-
|
|
70
|
-
format: -> if it? => @_format = it else @_format
|
|
71
|
-
scale: -> if it? => @_scale = it else @_scale
|
|
72
|
-
caption: ->
|
|
73
|
-
if @cfg.show-caption? and !@cfg.show-caption => @_n.label.textContent = ''
|
|
74
|
-
else @_n.label.textContent = it
|
|
75
|
-
update: ->
|
|
76
|
-
ticks: (ticks) ->
|
|
77
|
-
/* (v)alue -> (c)oordinate -> (t)ext -> (n)odes: { g(group), p(path), t(text) } */
|
|
78
|
-
map = {}
|
|
79
|
-
size = @_n.layout.getBoundingClientRect![if @dir < 2 => \width else \height]
|
|
80
|
-
count = Math.round(size / 25)
|
|
81
|
-
itr = Math.round(ticks.length / (count >? 1)) >? 1
|
|
82
|
-
@_ticks = ticks
|
|
83
|
-
.filter (d,i) -> !(i % itr) or i == (ticks.length - 1)
|
|
84
|
-
.map (o) ~>
|
|
85
|
-
if typeof(o) != \object => o = {v: o}
|
|
86
|
-
map[o.v] = @_map{}[o.v] <<< o
|
|
87
|
-
for k,v of @_map => if !map[k] => v.n.g.parentNode.removeChild v.n.g
|
|
88
|
-
@_map = map
|
|
89
|
-
@_ticks
|
|
90
|
-
.filter (o) -> !o.n
|
|
91
|
-
.map (o) ~>
|
|
92
|
-
o.n = g: ceNS(\g), p: ceNS(\path), t: ceNS(\g)
|
|
93
|
-
o.n.g.appendChild o.n.p
|
|
94
|
-
o.n.g.appendChild o.n.t
|
|
95
|
-
@_n.root.appendChild o.n.g
|
|
96
|
-
if isNaN(+o.v) => o.t = o.v
|
|
97
|
-
|
|
98
|
-
render: ->
|
|
99
|
-
n = @_n
|
|
100
|
-
is-horizon = (@dir < 2)
|
|
101
|
-
wrap = n.wrap
|
|
102
|
-
ticks = @_ticks
|
|
103
|
-
if @cfg.enabled? and !@cfg.enabled =>
|
|
104
|
-
if is-horizon => n.layout.style <<< height: "0px", paddingTop: "0", paddingBottom: "0"
|
|
105
|
-
else n.layout.style <<< width: "0px", paddingLeft: "0", paddingRight: "0"
|
|
106
|
-
n.domain.style.display = 'none'
|
|
107
|
-
return
|
|
108
|
-
else
|
|
109
|
-
if is-horizon => n.layout.style <<< height: "", paddingTop: "", paddingBottom: ""
|
|
110
|
-
else n.layout.style <<< width: "", paddingLeft: "", paddingRight: ""
|
|
111
|
-
n.domain.style.display = ''
|
|
112
|
-
font-size = getComputedStyle(wrap).font-size
|
|
113
|
-
box = n.layout.getBoundingClientRect!
|
|
114
|
-
n.domain.style <<< strokeWidth: 1, stroke: \currentColor, fill: \none
|
|
115
|
-
ticks.map (o, idx) ~>
|
|
116
|
-
pos = if !idx => 0 else if idx == ticks.length - 1 => 2 else 1
|
|
117
|
-
o._c = if o.c? => o.c else @_scale(o.v) + (if @_scale.bandwidth => @_scale.bandwidth!/2 else 0)
|
|
118
|
-
o._t = if o.t? => o.t else @_format o.v
|
|
119
|
-
o.n.p.style <<< strokeWidth: 1, stroke: \currentColor, fill: \none
|
|
120
|
-
wrap.textContent = o._t
|
|
121
|
-
wrap.style.textAlign = if is-horizon => <[left center right]>[pos] else <[right left]>[@dir - 2]
|
|
122
|
-
o.n.tt = wrap-svg-text {node: wrap}
|
|
123
|
-
o.n.t.style.font-size = font-size
|
|
124
|
-
o.n.t.textContent = ''
|
|
125
|
-
o.n.t.appendChild o.n.tt
|
|
126
|
-
ticks.sort (a,b) -> a._c - b._c
|
|
127
|
-
|
|
128
|
-
if is-horizon =>
|
|
129
|
-
n.domain.setAttribute \d, "M0 0L#{box.width} 0Z"
|
|
130
|
-
n.label.setAttribute \x, box.width / 2
|
|
131
|
-
else
|
|
132
|
-
n.domain.setAttribute \d, "M0 0L0 #{box.height}Z"
|
|
133
|
-
n.label.setAttribute "transform", "translate(0,#{box.height/2}) rotate(90)"
|
|
134
|
-
ticks.map (o) -> o.box = o.n.t.getBBox!
|
|
135
|
-
@adjust!
|
|
136
|
-
|
|
137
|
-
adjust: ->
|
|
138
|
-
ticks = @_ticks
|
|
139
|
-
is-horizon = (@dir < 2)
|
|
140
|
-
insert = (idx, lv, lc) ~>
|
|
141
|
-
if lc.checked[idx] => return else lc.checked[idx] = true
|
|
142
|
-
tick = ticks[idx]
|
|
143
|
-
# 0: smallest 'screen coord' tick / 1: middle tick / 2: biggest 'screen coord' tick
|
|
144
|
-
# top(0) -> down(2) / left(0) -> right(0)
|
|
145
|
-
pos = if !idx => 0 else if idx == ticks.length - 1 => 2 else 1
|
|
146
|
-
|
|
147
|
-
[coord,text] = [tick._c, tick._t]
|
|
148
|
-
box = tick.box
|
|
149
|
-
offset = {x: -box.x, y: -box.y}
|
|
150
|
-
do-offset = if @_scale.bandwidth => false
|
|
151
|
-
else if @cfg.boundary-tick-offset? => !!@cfg.boundary-tick-offset
|
|
152
|
-
else if @dir < 2 => true else false
|
|
153
|
-
r = if do-offset => pos/2 else 1/2
|
|
154
|
-
if is-horizon => offset.x -= box.width * r # start: 0w, middle: -.5w, end: -w ( left to right )
|
|
155
|
-
else offset.y -= box.height * r # start: 0h, middle: .5h, end: -h ( top to bottom )
|
|
156
|
-
tick.n.tt.setAttribute \transform, "translate(#{offset.x},#{offset.y})"
|
|
157
|
-
|
|
158
|
-
box =
|
|
159
|
-
size: box[if is-horizon => \width else \height]
|
|
160
|
-
size-alt: box[if is-horizon => \height else \width]
|
|
161
|
-
lv: lv, tick: tick, idx: idx
|
|
162
|
-
box.coord = coord - (box.size * r) #(if is-horizon => pos else (2 - pos)) / 2)
|
|
163
|
-
|
|
164
|
-
if is-horizon =>
|
|
165
|
-
tick.n.g.setAttribute \transform, "translate(#{coord},0)"
|
|
166
|
-
tick.n.p.setAttribute \d, "M0 0L0 #{@cfg.tick-size}"
|
|
167
|
-
tick.n.t.setAttribute \transform, "translate(0,#{@cfg.tick-size})"
|
|
168
|
-
else
|
|
169
|
-
tick.n.g.setAttribute \transform, "translate(0,#{coord})"
|
|
170
|
-
tick.n.p.setAttribute \d, "M0 0L-#{@cfg.tick-size} 0"
|
|
171
|
-
tick.n.t.setAttribute \transform, "translate(#{-@cfg.tick-size - box.size-alt - 1},0)"
|
|
172
|
-
|
|
173
|
-
m = 2
|
|
174
|
-
[ip1, ip2] = [ box.coord, box.coord + box.size ]
|
|
175
|
-
[op1, op2] = [ ip1 - m, ip2 + m]
|
|
176
|
-
|
|
177
|
-
overlap = lc.picked
|
|
178
|
-
.filter (b) ->
|
|
179
|
-
[iq1, iq2] = [b.coord, b.coord + b.size]
|
|
180
|
-
[oq1, oq2] = [iq1 - m, iq2 + m]
|
|
181
|
-
return (ip1 > oq1 and ip1 < oq2) or (iq1 > op1 and iq1 < op2)
|
|
182
|
-
.length
|
|
183
|
-
|
|
184
|
-
tick.n.t.style.opacity = if overlap => 0 else 1
|
|
185
|
-
lc.picked.push box
|
|
186
|
-
return !overlap # return true if insert successfully
|
|
187
|
-
|
|
188
|
-
# align lv ( see below commented codes )
|
|
189
|
-
# try to only show ticks in the same level.
|
|
190
|
-
# yet current implementation doesn't work well
|
|
191
|
-
# since we may have different size in each interval even in the same level
|
|
192
|
-
|
|
193
|
-
bfs = (maxlv = 1) ~>
|
|
194
|
-
[lc,fifo] = [{checked:{}, picked: [], node: @_n.wrap}, []]
|
|
195
|
-
lc.font-size = getComputedStyle(lc.node).font-size
|
|
196
|
-
# align lv
|
|
197
|
-
ticks.map -> it.n.t.style.opacity = 0
|
|
198
|
-
if ticks.length =>
|
|
199
|
-
fifo.push [0, ticks.length - 1, 0]
|
|
200
|
-
[0, ticks.length - 1].map -> insert it, 0, lc
|
|
201
|
-
while fifo.length =>
|
|
202
|
-
[L, R, D] = fifo.splice 0, 1 .0
|
|
203
|
-
if D >= maxlv => continue
|
|
204
|
-
M = Math.floor(( L + R ) / 2)
|
|
205
|
-
# align lv
|
|
206
|
-
#if !insert(M, D, lc) => maxlv = D
|
|
207
|
-
insert(M, D, lc)
|
|
208
|
-
if M > L + 1 => fifo.push [L, M, D + 1]
|
|
209
|
-
if R > M + 1 => fifo.push [M, R, D + 1]
|
|
210
|
-
|
|
211
|
-
/* align lv
|
|
212
|
-
lc.picked.map -> if it.lv >= maxlv => it.tick.n.t.style.opacity = 0
|
|
213
|
-
lc.picked = lc.picked.filter -> it.lv < maxlv
|
|
214
|
-
*/
|
|
215
|
-
|
|
216
|
-
size = Math.max.apply(Math, [0] ++ lc.picked.map(-> it.size-alt))
|
|
217
|
-
if @dir < 2 =>
|
|
218
|
-
@_n.label.setAttribute \y, size + @cfg.tick-size
|
|
219
|
-
@_n.layout.style.height = "#{(size + @cfg.tick-size + @_n.label.getBoundingClientRect!height)}px"
|
|
220
|
-
else
|
|
221
|
-
@_n.label.setAttribute \x, 0
|
|
222
|
-
@_n.label.setAttribute \y, 0
|
|
223
|
-
@_n.layout.style.width = "#{(size + @cfg.tick-size + @_n.label.getBoundingClientRect!width)}px"
|
|
224
|
-
box = @_n.layout.getBoundingClientRect!
|
|
225
|
-
@_n.label.setAttribute \transform, "translate(#{-(size + @cfg.tick-size)},#{box.height/2}) rotate(90)"
|
|
226
|
-
@_n.root.setAttribute \transform "translate(#{box.width},0)"
|
|
227
|
-
bfs 5
|
|
228
|
-
|
|
229
|
-
if chart? => chart.{}utils.axis = axis
|
package/src/utils/config.ls
DELETED
package/src/utils/data.ls
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
main =
|
|
2
|
-
number: (opt = {}) ->
|
|
3
|
-
data = opt.data
|
|
4
|
-
.filter -> !(!it or "#{it}".trim! == '')
|
|
5
|
-
len = data
|
|
6
|
-
.filter -> !isNaN(parseFloat(it))
|
|
7
|
-
.length
|
|
8
|
-
(len / data.length)
|
|
9
|
-
|
|
10
|
-
serial: (opt = {}) ->
|
|
11
|
-
data = [] ++ opt.data
|
|
12
|
-
data.sort (a,b) -> b - a
|
|
13
|
-
hash = {}
|
|
14
|
-
for i from 1 til data.length =>
|
|
15
|
-
if isNaN(data[i]) or isNaN(data[i - 1]) =>
|
|
16
|
-
hash[if data[i] > data[i - 1] => "#{data[i]}:#{data[i - 1]}" else "#{data[i - 1]}:#{data[i]}"] = true
|
|
17
|
-
else delta = data[i] - data[i - 1]
|
|
18
|
-
hash[delta] = true
|
|
19
|
-
return 1 / ([k for k of hash].filter(->it != \0).length or 2)
|
|
20
|
-
|
|
21
|
-
text: (opt={}) -> 1 - (@number opt)
|
|
22
|
-
|
|
23
|
-
category: (opt={}) ->
|
|
24
|
-
len = Array.from(new Set(opt.data)).length
|
|
25
|
-
maxlen = opt.data.length
|
|
26
|
-
ret = (1 - (((len - 2) >? 0) / maxlen) - (1 / maxlen)) >? 0 <? 1
|
|
27
|
-
if @number(opt) => ret = ret * 0.9
|
|
28
|
-
return ret
|
|
29
|
-
|
|
30
|
-
parse: (data) ->
|
|
31
|
-
if Array.isArray(data) =>
|
|
32
|
-
head = data.slice 0, 1 .0
|
|
33
|
-
body = data.slice 1
|
|
34
|
-
body = body.map (d,i) ->
|
|
35
|
-
ret = {}
|
|
36
|
-
head.map (h,j) -> ret[h] = d[j]
|
|
37
|
-
ret
|
|
38
|
-
return {head, body}
|
|
39
|
-
return data
|
|
40
|
-
|
|
41
|
-
autotype: (data = []) ->
|
|
42
|
-
head = [k for k of data.0 or {}]
|
|
43
|
-
type = []
|
|
44
|
-
for key in head =>
|
|
45
|
-
d = data.map -> it[key]
|
|
46
|
-
ret = do
|
|
47
|
-
key: key
|
|
48
|
-
types:
|
|
49
|
-
R: main.number({data: d})
|
|
50
|
-
O: main.serial({data: d})
|
|
51
|
-
N: main.text({data: d})
|
|
52
|
-
C: main.category({data: d})
|
|
53
|
-
list = <[R O N C]>.map -> [it, ret.types[it]]
|
|
54
|
-
list.sort (a,b) -> b.1 - a.1
|
|
55
|
-
ret.type = list.0.0
|
|
56
|
-
type.push ret
|
|
57
|
-
|
|
58
|
-
return type
|
|
59
|
-
|
|
60
|
-
autobind: (data = [], dimension = {}) ->
|
|
61
|
-
datatypes = @autotype data
|
|
62
|
-
dims = [{k,v} for k,v of dimension].filter -> !it.v.passive
|
|
63
|
-
dims.sort (a,b) ->
|
|
64
|
-
ret = (a.v.priority or 100) - (b.v.priority or 100)
|
|
65
|
-
if ret != 0 => return ret
|
|
66
|
-
[ma,mb] = [(a.v.type or \R), (b.v.type or \R)].map (t) ->
|
|
67
|
-
Math.min.apply Math, [0 til t.length].map (i) -> "CONR".indexOf(t[i])
|
|
68
|
-
return ma - mb
|
|
69
|
-
for dim in dims =>
|
|
70
|
-
dim.bind = null
|
|
71
|
-
ts = dim.v.type or \RNOC
|
|
72
|
-
for i from 0 til ts.length =>
|
|
73
|
-
t = ts[i]
|
|
74
|
-
datatypes.sort (a, b) ->
|
|
75
|
-
ret = (b.types[t] or 0) - (a.types[t] or 0)
|
|
76
|
-
if b.types[t] == a.types[t] and t == \R => return (a.types.O or 0) - (b.types.O or 0)
|
|
77
|
-
return ret
|
|
78
|
-
for i from 0 til datatypes.length =>
|
|
79
|
-
dt = datatypes[i]
|
|
80
|
-
if dt.types[t] < 0.5 or dt.used or (t == \C and dt.types.R > 0.5) => continue
|
|
81
|
-
dim.bind = if dim.v.multiple => [dt] else dt
|
|
82
|
-
dt.used = true
|
|
83
|
-
break
|
|
84
|
-
for dim in dims =>
|
|
85
|
-
if !dim.v.multiple => continue
|
|
86
|
-
ts = dim.v.type or \RNOC
|
|
87
|
-
for i from 0 til ts.length =>
|
|
88
|
-
t = ts[i]
|
|
89
|
-
datatypes.sort (a, b) ->
|
|
90
|
-
ret = (b[t] or 0) - (a[t] or 0)
|
|
91
|
-
if b[t] == a[t] and t == \R => return (a.O or 0) - (b.O or 0)
|
|
92
|
-
return ret
|
|
93
|
-
for i from 0 til datatypes.length =>
|
|
94
|
-
dt = datatypes[i]
|
|
95
|
-
if dt.types[t] < 0.5 or dt.used or (t == \C and dt.types.R > 0.5) => continue
|
|
96
|
-
dim.bind.push dt
|
|
97
|
-
dt.used = true
|
|
98
|
-
ret = {}
|
|
99
|
-
for dim in dims => if dim.bind =>
|
|
100
|
-
ret[dim.k] = dim.bind
|
|
101
|
-
(if Array.isArray(dim.bind) => dim.bind else [dim.bind]).map -> delete it.used
|
|
102
|
-
return ret
|
|
103
|
-
|
|
104
|
-
if chart? => chart.{}utils.data = main
|