@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.
Files changed (164) hide show
  1. package/package.json +3 -1
  2. package/CHANGELOG.md +0 -29
  3. package/build +0 -45
  4. package/doc/charts.md +0 -58
  5. package/doc/config.md +0 -44
  6. package/doc/draft/chart.md +0 -146
  7. package/doc/draft/data.md +0 -8
  8. package/doc/draft/definition.md +0 -0
  9. package/doc/draft/events.md +0 -0
  10. package/doc/draft/filter.md +0 -0
  11. package/doc/draft/lifecycle.md +0 -89
  12. package/doc/spec.md +0 -89
  13. package/doc/todo.md +0 -27
  14. package/doc/utils/tip.md +0 -84
  15. package/src/data/en-US/category +0 -20
  16. package/src/data/en-US/fruit +0 -39
  17. package/src/data/en-US/movie +0 -125
  18. package/src/data/en-US/name +0 -58
  19. package/src/data/index.ls +0 -34
  20. package/src/data/zh-TW/category +0 -20
  21. package/src/data/zh-TW/fruits +0 -38
  22. package/src/data/zh-TW/movie +0 -125
  23. package/src/data/zh-TW/names +0 -105
  24. package/src/index.ls +0 -323
  25. package/src/index.styl +0 -6
  26. package/src/utils/axis.ls +0 -229
  27. package/src/utils/config.ls +0 -11
  28. package/src/utils/data.ls +0 -104
  29. package/src/utils/format.ls +0 -30
  30. package/src/utils/legend.ls +0 -134
  31. package/src/utils/legend.styl +0 -37
  32. package/src/utils/tint.ls +0 -66
  33. package/src/utils/tip.ls +0 -97
  34. package/web/src/pug/base.pug +0 -21
  35. package/web/src/pug/block/axis/0.0.1/index.ls +0 -32
  36. package/web/src/pug/block/axis/0.0.1/index.pug +0 -1
  37. package/web/src/pug/block/axis-bubble/0.0.1/index.ls +0 -137
  38. package/web/src/pug/block/axis-bubble/0.0.1/index.pug +0 -1
  39. package/web/src/pug/block/bar/0.0.1/index.ls +0 -270
  40. package/web/src/pug/block/bar/0.0.1/index.pug +0 -35
  41. package/web/src/pug/block/bar-list/0.0.1/index.ls +0 -81
  42. package/web/src/pug/block/bar-list/0.0.1/index.pug +0 -30
  43. package/web/src/pug/block/bar-race/0.0.1/index.ls +0 -79
  44. package/web/src/pug/block/bar-race/0.0.1/index.pug +0 -21
  45. package/web/src/pug/block/base/0.0.1/index.ls +0 -66
  46. package/web/src/pug/block/base/0.0.1/index.pug +0 -5
  47. package/web/src/pug/block/blank/0.0.1/index.ls +0 -21
  48. package/web/src/pug/block/blank/0.0.1/index.pug +0 -1
  49. package/web/src/pug/block/bubble/0.0.1/index.ls +0 -218
  50. package/web/src/pug/block/bubble/0.0.1/index.pug +0 -42
  51. package/web/src/pug/block/curve-bar/0.0.1/index.ls +0 -85
  52. package/web/src/pug/block/curve-bar/0.0.1/index.pug +0 -16
  53. package/web/src/pug/block/curve-bar/0.0.1/sample.js +0 -338
  54. package/web/src/pug/block/dumbbell/0.0.1/index.ls +0 -86
  55. package/web/src/pug/block/dumbbell/0.0.1/index.pug +0 -1
  56. package/web/src/pug/block/empty/0.0.1/index.ls +0 -28
  57. package/web/src/pug/block/empty/0.0.1/index.pug +0 -2
  58. package/web/src/pug/block/gauge/0.0.1/index.ls +0 -96
  59. package/web/src/pug/block/gauge/0.0.1/index.pug +0 -31
  60. package/web/src/pug/block/gauge/0.0.1/sample.js +0 -338
  61. package/web/src/pug/block/line/0.0.1/index.ls +0 -297
  62. package/web/src/pug/block/line/0.0.1/index.pug +0 -33
  63. package/web/src/pug/block/number/0.0.1/index.ls +0 -65
  64. package/web/src/pug/block/number/0.0.1/index.pug +0 -20
  65. package/web/src/pug/block/percent-list/0.0.1/index.ls +0 -161
  66. package/web/src/pug/block/percent-list/0.0.1/index.pug +0 -34
  67. package/web/src/pug/block/pie/0.0.1/index.ls +0 -121
  68. package/web/src/pug/block/pie/0.0.1/index.pug +0 -19
  69. package/web/src/pug/block/pie/0.0.1/sample.js +0 -338
  70. package/web/src/pug/block/pie-bubble/0.0.1/index.ls +0 -181
  71. package/web/src/pug/block/pie-bubble/0.0.1/index.pug +0 -40
  72. package/web/src/pug/block/radar/0.0.1/index.ls +0 -109
  73. package/web/src/pug/block/radar/0.0.1/index.pug +0 -1
  74. package/web/src/pug/block/radar/0.0.1/xx +0 -285
  75. package/web/src/pug/block/scatter/0.0.1/index.ls +0 -124
  76. package/web/src/pug/block/scatter/0.0.1/index.pug +0 -30
  77. package/web/src/pug/block/sheet/0.0.1/index.ls +0 -34
  78. package/web/src/pug/block/sheet/0.0.1/index.pug +0 -5
  79. package/web/src/pug/block/table/0.0.1/index.ls +0 -36
  80. package/web/src/pug/block/table/0.0.1/index.pug +0 -3
  81. package/web/src/pug/block/taiwancounty/0.0.1/index.ls +0 -70
  82. package/web/src/pug/block/taiwancounty/0.0.1/index.pug +0 -64
  83. package/web/src/pug/block/taiwantown/0.0.1/index.ls +0 -44
  84. package/web/src/pug/block/taiwantown/0.0.1/index.pug +0 -52
  85. package/web/src/pug/block/taiwanvillage/0.0.1/index.ls +0 -49
  86. package/web/src/pug/block/taiwanvillage/0.0.1/index.pug +0 -52
  87. package/web/src/pug/block/treemap/0.0.1/index.ls +0 -168
  88. package/web/src/pug/block/treemap/0.0.1/index.pug +0 -42
  89. package/web/src/pug/block/voronoi-treemap/0.0.1/index.ls +0 -170
  90. package/web/src/pug/block/voronoi-treemap/0.0.1/index.pug +0 -17
  91. package/web/src/pug/block/voronoi-treemap/0.0.1/sample.js +0 -241
  92. package/web/src/pug/block/wordcloud/0.0.1/index.ls +0 -57
  93. package/web/src/pug/block/wordcloud/0.0.1/index.pug +0 -1
  94. package/web/src/pug/block/worldmap/0.0.1/index.ls +0 -77
  95. package/web/src/pug/block/worldmap/0.0.1/index.pug +0 -12
  96. package/web/src/pug/index.ls +0 -72
  97. package/web/src/pug/index.pug +0 -51
  98. package/web/src/styl/index.styl +0 -6
  99. package/web/static/assets/block/cache.js +0 -4
  100. package/web/static/assets/custom-lib/d3/d3-array.v2.js +0 -1182
  101. package/web/static/assets/custom-lib/d3/d3-array.v2.min.js +0 -2
  102. package/web/static/assets/custom-lib/d3/d3-array.v3.js +0 -1273
  103. package/web/static/assets/custom-lib/d3/d3-array.v3.min.js +0 -1273
  104. package/web/static/assets/custom-lib/d3/d3-axis.v2.min.js +0 -2
  105. package/web/static/assets/custom-lib/d3/d3-brush.v2.min.js +0 -2
  106. package/web/static/assets/custom-lib/d3/d3-color.v2.min.js +0 -2
  107. package/web/static/assets/custom-lib/d3/d3-dispatch.v2.min.js +0 -2
  108. package/web/static/assets/custom-lib/d3/d3-drag.v2.min.js +0 -2
  109. package/web/static/assets/custom-lib/d3/d3-ease.v2.min.js +0 -2
  110. package/web/static/assets/custom-lib/d3/d3-force-boundary.v0.0.1.min.js +0 -2
  111. package/web/static/assets/custom-lib/d3/d3-force.v2.min.js +0 -2
  112. package/web/static/assets/custom-lib/d3/d3-format.v2.min.js +0 -2
  113. package/web/static/assets/custom-lib/d3/d3-geo.v2.js +0 -3127
  114. package/web/static/assets/custom-lib/d3/d3-geo.v2.min.js +0 -2
  115. package/web/static/assets/custom-lib/d3/d3-hierarchy.v2.min.js +0 -2
  116. package/web/static/assets/custom-lib/d3/d3-interpolate.v2.min.js +0 -2
  117. package/web/static/assets/custom-lib/d3/d3-path.v2.min.js +0 -2
  118. package/web/static/assets/custom-lib/d3/d3-quadtree.v2.min.js +0 -2
  119. package/web/static/assets/custom-lib/d3/d3-random.v2.min.js +0 -2
  120. package/web/static/assets/custom-lib/d3/d3-scale-chromatic.v1.min.js +0 -2
  121. package/web/static/assets/custom-lib/d3/d3-selection.v2.min.js +0 -2
  122. package/web/static/assets/custom-lib/d3/d3-shape.v2.min.js +0 -2
  123. package/web/static/assets/custom-lib/d3/d3-timer.v2.min.js +0 -2
  124. package/web/static/assets/custom-lib/d3/d3-transition.v2.min.js +0 -2
  125. package/web/static/assets/custom-lib/d3/d3.v4.js +0 -17178
  126. package/web/static/assets/custom-lib/d3/d3.v4.min.js +0 -2
  127. package/web/static/assets/custom-lib/d3/d3.v6.js +0 -19708
  128. package/web/static/assets/data/countrycode.json +0 -1
  129. package/web/static/assets/data/world-110m.json +0 -1
  130. package/web/static/assets/data/zh-to-alpha2.json +0 -1
  131. package/web/static/assets/img/fluid.svg +0 -16
  132. package/web/static/block/axis/0.0.1/index.html +0 -74
  133. package/web/static/block/axis-bubble/0.0.1/index.html +0 -217
  134. package/web/static/block/bar/0.0.1/index.html +0 -576
  135. package/web/static/block/bar-list/0.0.1/index.html +0 -226
  136. package/web/static/block/bar-race/0.0.1/index.html +0 -179
  137. package/web/static/block/base/0.0.1/index.html +0 -197
  138. package/web/static/block/blank/0.0.1/index.html +0 -37
  139. package/web/static/block/bubble/0.0.1/index.html +0 -422
  140. package/web/static/block/bubble/0.0.1/test.html +0 -0
  141. package/web/static/block/curve-bar/0.0.1/index.html +0 -143
  142. package/web/static/block/dumbbell/0.0.1/index.html +0 -173
  143. package/web/static/block/empty/0.0.1/index.html +0 -76
  144. package/web/static/block/gauge/0.0.1/index.html +0 -145
  145. package/web/static/block/line/0.0.1/index.html +0 -566
  146. package/web/static/block/number/0.0.1/index.html +0 -147
  147. package/web/static/block/percent-list/0.0.1/index.html +0 -311
  148. package/web/static/block/pie/0.0.1/index.html +0 -276
  149. package/web/static/block/pie-bubble/0.0.1/index.html +0 -353
  150. package/web/static/block/radar/0.0.1/index.html +0 -144
  151. package/web/static/block/scatter/0.0.1/index.html +0 -246
  152. package/web/static/block/sheet/0.0.1/index.html +0 -98
  153. package/web/static/block/table/0.0.1/index.html +0 -67
  154. package/web/static/block/taiwancounty/0.0.1/index.html +0 -197
  155. package/web/static/block/taiwantown/0.0.1/index.html +0 -205
  156. package/web/static/block/taiwanvillage/0.0.1/index.html +0 -215
  157. package/web/static/block/treemap/0.0.1/index.html +0 -355
  158. package/web/static/block/voronoi-treemap/0.0.1/index.html +0 -345
  159. package/web/static/block/wordcloud/0.0.1/index.html +0 -87
  160. package/web/static/block/worldmap/0.0.1/index.html +0 -202
  161. package/web/static/css/index.css +0 -6
  162. package/web/static/css/index.min.css +0 -1
  163. package/web/static/favicon.ico +0 -0
  164. 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
@@ -1,6 +0,0 @@
1
- div[plug=layout]
2
- width: 100%
3
- height: 100%
4
- .pdl-layout
5
- width: 100%
6
- height: 100%
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
@@ -1,11 +0,0 @@
1
- config = preset:
2
- default:
3
- margin: type: \number
4
- font:
5
- size: type: \number, min: 1, max: 256, step: 1, default: 16
6
- color: type: \color
7
- palette: type: \palette
8
- background: type: \color
9
-
10
- if chart? => chart.{}utils.config = config
11
-
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