@plotdb/chart 0.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 (177) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +50 -0
  3. package/build +39 -0
  4. package/dist/chart.css +8 -0
  5. package/dist/chart.js +603 -0
  6. package/dist/chart.min.css +1 -0
  7. package/dist/chart.min.js +1 -0
  8. package/dist/data/index.js +73 -0
  9. package/dist/utils/axis.js +357 -0
  10. package/dist/utils/axis.min.js +1 -0
  11. package/dist/utils/config.js +33 -0
  12. package/dist/utils/config.min.js +1 -0
  13. package/dist/utils/data.js +238 -0
  14. package/dist/utils/data.min.js +1 -0
  15. package/dist/utils/format.js +70 -0
  16. package/dist/utils/format.min.js +1 -0
  17. package/dist/utils/legend.css +40 -0
  18. package/dist/utils/legend.js +263 -0
  19. package/dist/utils/legend.min.css +1 -0
  20. package/dist/utils/legend.min.js +1 -0
  21. package/dist/utils/tint.js +138 -0
  22. package/dist/utils/tint.min.js +1 -0
  23. package/dist/utils/tip.js +148 -0
  24. package/dist/utils/tip.min.js +1 -0
  25. package/doc/charts.md +58 -0
  26. package/doc/config.md +44 -0
  27. package/doc/draft/chart.md +146 -0
  28. package/doc/draft/data.md +8 -0
  29. package/doc/draft/definition.md +0 -0
  30. package/doc/draft/events.md +0 -0
  31. package/doc/draft/filter.md +0 -0
  32. package/doc/draft/lifecycle.md +89 -0
  33. package/doc/spec.md +89 -0
  34. package/doc/todo.md +27 -0
  35. package/doc/utils/tip.md +84 -0
  36. package/package.json +83 -0
  37. package/src/chart.ls +320 -0
  38. package/src/chart.styl +6 -0
  39. package/src/data/en-US/category +20 -0
  40. package/src/data/en-US/fruit +39 -0
  41. package/src/data/en-US/movie +125 -0
  42. package/src/data/en-US/name +58 -0
  43. package/src/data/index.ls +34 -0
  44. package/src/data/zh-TW/category +20 -0
  45. package/src/data/zh-TW/fruits +38 -0
  46. package/src/data/zh-TW/movie +125 -0
  47. package/src/data/zh-TW/names +105 -0
  48. package/src/utils/axis.ls +229 -0
  49. package/src/utils/config.ls +11 -0
  50. package/src/utils/data.ls +104 -0
  51. package/src/utils/format.ls +30 -0
  52. package/src/utils/legend.ls +134 -0
  53. package/src/utils/legend.styl +37 -0
  54. package/src/utils/tint.ls +66 -0
  55. package/src/utils/tip.ls +97 -0
  56. package/web/src/pug/base.pug +19 -0
  57. package/web/src/pug/block/axis/0.0.1/index.ls +38 -0
  58. package/web/src/pug/block/axis/0.0.1/index.pug +1 -0
  59. package/web/src/pug/block/axis-bubble/0.0.1/index.ls +141 -0
  60. package/web/src/pug/block/axis-bubble/0.0.1/index.pug +1 -0
  61. package/web/src/pug/block/bar/0.0.1/index.ls +274 -0
  62. package/web/src/pug/block/bar/0.0.1/index.pug +35 -0
  63. package/web/src/pug/block/bar-list/0.0.1/index.ls +85 -0
  64. package/web/src/pug/block/bar-list/0.0.1/index.pug +30 -0
  65. package/web/src/pug/block/bar-race/0.0.1/index.ls +83 -0
  66. package/web/src/pug/block/bar-race/0.0.1/index.pug +21 -0
  67. package/web/src/pug/block/base/0.0.1/index.ls +67 -0
  68. package/web/src/pug/block/base/0.0.1/index.pug +5 -0
  69. package/web/src/pug/block/blank/0.0.1/index.ls +25 -0
  70. package/web/src/pug/block/blank/0.0.1/index.pug +1 -0
  71. package/web/src/pug/block/bubble/0.0.1/index.ls +220 -0
  72. package/web/src/pug/block/bubble/0.0.1/index.pug +28 -0
  73. package/web/src/pug/block/curve-bar/0.0.1/index.ls +89 -0
  74. package/web/src/pug/block/curve-bar/0.0.1/index.pug +16 -0
  75. package/web/src/pug/block/curve-bar/0.0.1/sample.js +338 -0
  76. package/web/src/pug/block/dumbbell/0.0.1/index.ls +90 -0
  77. package/web/src/pug/block/dumbbell/0.0.1/index.pug +1 -0
  78. package/web/src/pug/block/empty/0.0.1/index.ls +27 -0
  79. package/web/src/pug/block/empty/0.0.1/index.pug +2 -0
  80. package/web/src/pug/block/gauge/0.0.1/index.ls +100 -0
  81. package/web/src/pug/block/gauge/0.0.1/index.pug +31 -0
  82. package/web/src/pug/block/gauge/0.0.1/sample.js +338 -0
  83. package/web/src/pug/block/line/0.0.1/index.ls +265 -0
  84. package/web/src/pug/block/line/0.0.1/index.pug +33 -0
  85. package/web/src/pug/block/number/0.0.1/index.ls +69 -0
  86. package/web/src/pug/block/number/0.0.1/index.pug +20 -0
  87. package/web/src/pug/block/percent-list/0.0.1/index.ls +167 -0
  88. package/web/src/pug/block/percent-list/0.0.1/index.pug +34 -0
  89. package/web/src/pug/block/pie/0.0.1/index.ls +125 -0
  90. package/web/src/pug/block/pie/0.0.1/index.pug +19 -0
  91. package/web/src/pug/block/pie/0.0.1/sample.js +338 -0
  92. package/web/src/pug/block/pie-bubble/0.0.1/index.ls +185 -0
  93. package/web/src/pug/block/pie-bubble/0.0.1/index.pug +40 -0
  94. package/web/src/pug/block/radar/0.0.1/index.ls +113 -0
  95. package/web/src/pug/block/radar/0.0.1/index.pug +1 -0
  96. package/web/src/pug/block/radar/0.0.1/xx +285 -0
  97. package/web/src/pug/block/scatter/0.0.1/index.ls +128 -0
  98. package/web/src/pug/block/scatter/0.0.1/index.pug +30 -0
  99. package/web/src/pug/block/sheet/0.0.1/index.ls +38 -0
  100. package/web/src/pug/block/sheet/0.0.1/index.pug +5 -0
  101. package/web/src/pug/block/table/0.0.1/index.ls +40 -0
  102. package/web/src/pug/block/table/0.0.1/index.pug +3 -0
  103. package/web/src/pug/block/taiwantown/0.0.1/index.ls +48 -0
  104. package/web/src/pug/block/taiwantown/0.0.1/index.pug +52 -0
  105. package/web/src/pug/block/taiwanvillage/0.0.1/index.ls +53 -0
  106. package/web/src/pug/block/taiwanvillage/0.0.1/index.pug +52 -0
  107. package/web/src/pug/block/treemap/0.0.1/index.ls +172 -0
  108. package/web/src/pug/block/treemap/0.0.1/index.pug +42 -0
  109. package/web/src/pug/block/voronoi-treemap/0.0.1/index.ls +174 -0
  110. package/web/src/pug/block/voronoi-treemap/0.0.1/index.pug +17 -0
  111. package/web/src/pug/block/voronoi-treemap/0.0.1/sample.js +241 -0
  112. package/web/src/pug/block/wordcloud/0.0.1/index.ls +61 -0
  113. package/web/src/pug/block/wordcloud/0.0.1/index.pug +1 -0
  114. package/web/src/pug/block/worldmap/0.0.1/index.ls +83 -0
  115. package/web/src/pug/block/worldmap/0.0.1/index.pug +12 -0
  116. package/web/src/pug/index.ls +72 -0
  117. package/web/src/pug/index.pug +52 -0
  118. package/web/src/styl/index.styl +0 -0
  119. package/web/static/assets/block/cache.js +4 -0
  120. package/web/static/assets/custom-lib/d3/d3-array.v2.min.js +2 -0
  121. package/web/static/assets/custom-lib/d3/d3-axis.v2.min.js +2 -0
  122. package/web/static/assets/custom-lib/d3/d3-brush.v2.min.js +2 -0
  123. package/web/static/assets/custom-lib/d3/d3-color.v2.min.js +2 -0
  124. package/web/static/assets/custom-lib/d3/d3-dispatch.v2.min.js +2 -0
  125. package/web/static/assets/custom-lib/d3/d3-drag.v2.min.js +2 -0
  126. package/web/static/assets/custom-lib/d3/d3-ease.v2.min.js +2 -0
  127. package/web/static/assets/custom-lib/d3/d3-force-boundary.v0.0.1.min.js +2 -0
  128. package/web/static/assets/custom-lib/d3/d3-force.v2.min.js +2 -0
  129. package/web/static/assets/custom-lib/d3/d3-format.v2.min.js +2 -0
  130. package/web/static/assets/custom-lib/d3/d3-hierarchy.v2.min.js +2 -0
  131. package/web/static/assets/custom-lib/d3/d3-interpolate.v2.min.js +2 -0
  132. package/web/static/assets/custom-lib/d3/d3-path.v2.min.js +2 -0
  133. package/web/static/assets/custom-lib/d3/d3-quadtree.v2.min.js +2 -0
  134. package/web/static/assets/custom-lib/d3/d3-random.v2.min.js +2 -0
  135. package/web/static/assets/custom-lib/d3/d3-scale-chromatic.v1.min.js +2 -0
  136. package/web/static/assets/custom-lib/d3/d3-selection.v2.min.js +2 -0
  137. package/web/static/assets/custom-lib/d3/d3-shape.v2.min.js +2 -0
  138. package/web/static/assets/custom-lib/d3/d3-timer.v2.min.js +2 -0
  139. package/web/static/assets/custom-lib/d3/d3-transition.v2.min.js +2 -0
  140. package/web/static/assets/custom-lib/d3/d3.v4.js +17178 -0
  141. package/web/static/assets/custom-lib/d3/d3.v4.min.js +2 -0
  142. package/web/static/assets/data/countrycode.json +1 -0
  143. package/web/static/assets/data/world-110m.json +1 -0
  144. package/web/static/assets/data/zh-to-alpha2.json +1 -0
  145. package/web/static/assets/img/fluid.svg +16 -0
  146. package/web/static/block/axis/0.0.1/index.html +79 -0
  147. package/web/static/block/axis-bubble/0.0.1/index.html +222 -0
  148. package/web/static/block/bar/0.0.1/index.html +581 -0
  149. package/web/static/block/bar-list/0.0.1/index.html +231 -0
  150. package/web/static/block/bar-race/0.0.1/index.html +184 -0
  151. package/web/static/block/base/0.0.1/index.html +197 -0
  152. package/web/static/block/blank/0.0.1/index.html +42 -0
  153. package/web/static/block/bubble/0.0.1/index.html +402 -0
  154. package/web/static/block/bubble/0.0.1/test.html +0 -0
  155. package/web/static/block/curve-bar/0.0.1/index.html +148 -0
  156. package/web/static/block/dumbbell/0.0.1/index.html +178 -0
  157. package/web/static/block/empty/0.0.1/index.html +76 -0
  158. package/web/static/block/gauge/0.0.1/index.html +150 -0
  159. package/web/static/block/line/0.0.1/index.html +540 -0
  160. package/web/static/block/number/0.0.1/index.html +152 -0
  161. package/web/static/block/percent-list/0.0.1/index.html +316 -0
  162. package/web/static/block/pie/0.0.1/index.html +281 -0
  163. package/web/static/block/pie-bubble/0.0.1/index.html +358 -0
  164. package/web/static/block/radar/0.0.1/index.html +149 -0
  165. package/web/static/block/scatter/0.0.1/index.html +251 -0
  166. package/web/static/block/sheet/0.0.1/index.html +103 -0
  167. package/web/static/block/table/0.0.1/index.html +73 -0
  168. package/web/static/block/taiwantown/0.0.1/index.html +210 -0
  169. package/web/static/block/taiwanvillage/0.0.1/index.html +220 -0
  170. package/web/static/block/treemap/0.0.1/index.html +360 -0
  171. package/web/static/block/voronoi-treemap/0.0.1/index.html +350 -0
  172. package/web/static/block/wordcloud/0.0.1/index.html +92 -0
  173. package/web/static/block/worldmap/0.0.1/index.html +207 -0
  174. package/web/static/css/index.css +0 -0
  175. package/web/static/css/index.min.css +0 -0
  176. package/web/static/favicon.ico +0 -0
  177. package/web/static/index.html +153 -0
package/doc/spec.md ADDED
@@ -0,0 +1,89 @@
1
+ # Chart Spec.
2
+
3
+ PlotDB.js 2.0?
4
+
5
+ - consider `plotdb` structure
6
+ - abstract certain functionality ( popup? )
7
+ - wrapped in `@plotdb/block` for:
8
+ - libraries / css isolation so it's possible to run d3v3, v4, v5, v6 at the same time.
9
+ - well-defined version / module name
10
+ - centralized registry
11
+ - `@plotdb/datadom` aware for easily creating webpage with charts.
12
+
13
+
14
+ ## Data Object
15
+
16
+ Except chart object, we still need additional data for chart to render, including:
17
+
18
+ - `raw` - the real data. maybe from database, or from csv, etc.
19
+ - `binding` - mapping between data dimension and chart dimension.
20
+ - `config` - how chart is rendered.
21
+
22
+
23
+ ### Raw
24
+
25
+ Raw data. Compiles to array of object ( store in `data` member variable ) according to the given `binding`, with additional fields below in each element:
26
+
27
+ - `_idx`: order of this element in `data`.
28
+ - `_raw`: raw data corresponding to this object
29
+
30
+
31
+
32
+ ### Binding
33
+
34
+ binding is an object containing mapping from data fields to map dimensions:
35
+
36
+ `dimension-name`: {
37
+ key: `field-key`,
38
+ name: `field-name`,
39
+ description: `field-description`,
40
+ filter: <filter-object>
41
+ },
42
+ `dimension-name`: [
43
+ {key: `field-key`}, ...
44
+ ]
45
+
46
+ detail of the object describing data fields:
47
+
48
+ - `key`: unique identifier of the corresponding field. used to look up field values in `raw`.
49
+ - `name`: field name. optional. fall back to `key` if not provided.
50
+ - `description`: field description. optional.
51
+ - `types`: optional. hash of probability for each types. e.g., following types hash suggests a `Category` type:
52
+
53
+ {
54
+ R: 0.1
55
+ O: 0.1
56
+ N: 0.3
57
+ C: 1.0
58
+ }
59
+
60
+ - `filter`: filter information about this field. it can be either:
61
+ - object with following fields:
62
+ - e.g., `{type: "range", value: [1992, 2002]}`
63
+ - list of values. e.g., ['Apple', 'Orange']
64
+
65
+
66
+ #### Filter
67
+
68
+ possible filter format:
69
+
70
+ - plain array. indicate chosen values of the specific dimension. e.g., `["Apple", "Orange"]`.
71
+ - object in `{type, value}` format, where
72
+ - `type`: indicate the type of this filter.
73
+ - `value`: value according to the specific type.
74
+
75
+
76
+ With following possible types and the meaning of their corresponding value:
77
+
78
+ - `index`: an array of position of chosen elements.
79
+ - `exclude`: an array of items to be excluded.
80
+ - `range`: a 2 elements array indicating the range of chosen values.
81
+ - `enum`: an array of chosen elements. identical to the `plain array` format.
82
+
83
+
84
+ ## Events
85
+
86
+ - `filter`
87
+ - `select` / `hover`: fired when some elements with data selected / hovered.A
88
+ - n array of `{data, node}` pair should be sent along.
89
+
package/doc/todo.md ADDED
@@ -0,0 +1,27 @@
1
+ # todo
2
+
3
+ - 如果省略 bind, 則可以直接用 dimension 對應到 data 中的欄位?
4
+ - 混合文字的數值也有可能是 type O. 如 104年, 105年, etc
5
+ - 在有可能做 unpivot 的情況下, 因為 column 難免要寫上單位(年), 這個問題避不掉, 勢必要處理.
6
+ - support zmgr in tip
7
+ - performance
8
+
9
+
10
+ ## layout
11
+
12
+ explicitly define `layout.update`, `layout.render` and consider following scenario:
13
+
14
+ chart.resize -> layout.update
15
+
16
+ by adding additional action / api such as:
17
+
18
+ - before-update
19
+ - after-update
20
+ - before-render
21
+ - after-render
22
+
23
+
24
+ ## config
25
+
26
+ consider adding additional `config` function for correctly updating config. ( we have `config` now but it's used to set cfg object only. )
27
+
@@ -0,0 +1,84 @@
1
+ # chart.utils.tip
2
+
3
+ tooltip utility. use ldview to render content
4
+
5
+ ## usage
6
+
7
+ new chart.utils.tip({ ... });
8
+
9
+ constructor options:
10
+
11
+ - `root`: root node to store tip element.
12
+ - one of `relative`, `absolute` or `fixed` position is needed for this element
13
+ - `ndoe`: tip node to use. A default one will be created if omitted.
14
+ - `margin`: margin between tip and cursor. default 10px if omitted.
15
+ - `type`: trigger type of tip. either `over` or `move`. default `move`.
16
+ - `accessor`: accessor function for retrieving data from active event.
17
+ - default null if omitted.
18
+ - if provided, function takes {evt: eventObject} as input, and should return
19
+ - null, if no data is bound to this event
20
+ - a data object if there is any data bound to this event.
21
+ - when provided, `chart.utils.tip` automatically handle mouse events for tip popping.
22
+ - `range`: function returning bounding box of tip ( {x,y,width,height} ). optional.
23
+ - this box shares the same coordinate origin with `root`'s `getBoundingClientRect`.
24
+ - `view`: text handler for ldview. if omitted, handler with following names will be use:
25
+ - `name`
26
+ - `value`
27
+ - `zmgr`: `zmgr` module, use this to get z-index if provided. use `10` instead
28
+
29
+
30
+ ## API
31
+
32
+ - `render(opt)`: show tip based on the given options:
33
+ - `evt`: mouse event. `clientX` and `clientY` members will be used.
34
+ - `node`: target node. optional. used to get corresponding bounding box.
35
+ - bounding box hints `chart.util.tip` the position a tip should be placed.
36
+ - `box`: if `node` is omitted, `render` checks `box` for bounding box information. a box should contains:
37
+ - `x` / `y`: left-top coordinate of the box, or centroid of the box if width / height are omitted.
38
+ - `width` / `height`: box size, optional.
39
+ - `data`: data to be shown. will be set as context to internal ldview object.
40
+ - `toggle(v)`: set `v` to true to enable tip, otherwise to disable tip.
41
+ - tip is by default enabled after constructed.
42
+ - `hide()`: hide tip. this is a debounced function ( with @loadingio/debounce.js ) so you can also `hide().now()`.
43
+ - `destroy()`: destroy function, release unused resources.
44
+
45
+
46
+ ## Styling
47
+
48
+ With d3js, this is the minimal tip construct:
49
+
50
+ new chart.utils.tip({
51
+ root: myRoot,
52
+ accessor: function({evt}) { return (evt.target? d3.select(evt.target).datum() : null); }
53
+ });
54
+
55
+ To style your own tip, make a tip element first ( with HTML, yet we write this example in Pug for convenience ):
56
+
57
+ .my-tip
58
+ # ... some fancy design ...
59
+ div(ld="name")
60
+ div(ld="value")
61
+ div(ld="my-custom-field")
62
+
63
+ then pass it to tip cosntructor. To support `my-custom-field`, you need to also add `view` option:
64
+
65
+ new chart.utils.tip({
66
+ node: '.my-tip', ...
67
+ view:
68
+ name: ({ctx}) -> ctx.name
69
+ value: ({ctx}) -> ctx.name
70
+ "my-custom-field": ({ctx}) -> some-function(ctx, ctx.some-value);
71
+ });
72
+
73
+
74
+ ## Custom Behavior
75
+
76
+ With `accessor`, `chart.utils.tip` bind action automatically for you. However, you can also decide how tip should interact with your design by calling `render` manually.
77
+
78
+ tip = new chart.utils.tip({
79
+ /* ... construct without `accessor` option ... */
80
+ });
81
+ /* only trigger tip when clicking something */
82
+ myRoot.addEventListener("click", function(evt) {
83
+ tip.render({evt: evt, data: myData});
84
+ });
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "author": "zbryikt",
3
+ "name": "@plotdb/chart",
4
+ "license": "MIT",
5
+ "description": "plotdb charts",
6
+ "version": "0.0.2",
7
+ "homepage": "https://github.com/plotdb/chart",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/plotdb/chart"
11
+ },
12
+ "engines": {
13
+ "node": ">=10.14.1",
14
+ "npm": ">=6.4.1"
15
+ },
16
+ "scripts": {
17
+ "start": "npx server -r web -o true",
18
+ "postinstall": "npx fedep"
19
+ },
20
+ "devDependencies": {
21
+ "@loadingio/bootstrap.ext": "^0.0.1",
22
+ "@loadingio/ldquery": "^2.2.0",
23
+ "@loadingio/loading.css": "^2.0.1",
24
+ "@plotdb/layout": "^0.0.10",
25
+ "@plotdb/pdmap-world": "^0.0.3",
26
+ "@plotdb/sheet": "^0.1.7",
27
+ "@zbryikt/template": "^2.3.22",
28
+ "bootstrap": "^4.5.2",
29
+ "fedep": "^0.0.16",
30
+ "ldloader": "^2.0.1",
31
+ "ldview": "^0.2.3",
32
+ "livescript": "^1.6.0",
33
+ "uglify-js": "^3.2.0",
34
+ "uglifycss": "^0.0.29"
35
+ },
36
+ "frontendDependencies": {
37
+ "root": "web/static/assets/lib",
38
+ "modules": [
39
+ "bootstrap",
40
+ "@loadingio/bootstrap.ext",
41
+ "@loadingio/ldquery",
42
+ "@loadingio/loading.css",
43
+ "@loadingio/ldcolorpicker",
44
+ "@loadingio/debounce.js",
45
+ "@plotdb/pdmap-world",
46
+ "@plotdb/block",
47
+ "@plotdb/csscope",
48
+ "@plotdb/rescope",
49
+ "@plotdb/layout",
50
+ "@plotdb/sheet",
51
+ "@plotdb/konfig",
52
+ "@zbryikt/voronoijs",
53
+ "choosefont.js",
54
+ "proxise",
55
+ "ldloader",
56
+ "ldcover",
57
+ "ldcolor",
58
+ "ldslider",
59
+ "wrap-svg-text",
60
+ "ldpalettepicker",
61
+ "ldview"
62
+ ]
63
+ },
64
+ "dependencies": {
65
+ "@loadingio/debounce.js": "^0.0.1",
66
+ "@loadingio/ldcolorpicker": "^2.0.4",
67
+ "@plotdb/block": "^2.1.0",
68
+ "@plotdb/csscope": "^2.0.0",
69
+ "@plotdb/konfig": "^1.2.5",
70
+ "@plotdb/rescope": "^3.0.0",
71
+ "@zbryikt/voronoijs": "^0.0.1",
72
+ "choosefont.js": "^0.0.1",
73
+ "ldcolor": "^0.0.4",
74
+ "ldcover": "^2.0.0",
75
+ "ldpalettepicker": "^3.1.3",
76
+ "ldslider": "^2.0.6",
77
+ "proxise": "^0.1.3",
78
+ "wrap-svg-text": "^0.0.6"
79
+ },
80
+ "peerDependencies": {
81
+ "proxise": "^0.1.2"
82
+ }
83
+ }
package/src/chart.ls ADDED
@@ -0,0 +1,320 @@
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
+ if @raw and Array.isArray(@raw) => return
172
+ if @use-sample => @ <<< (if @mod.sample => @mod.sample! or {} else {}){raw, binding}
173
+ if !@raw => @raw = []
174
+ .then ~>
175
+ defcfg = default-config(@mod.config or {})
176
+ with-default @cfg, defcfg
177
+ if @layout-opt =>
178
+ if !(layout?) => console.warn "[@plotdb/chart] layout-opt is set yet @plotdb/layout is not found."
179
+ else
180
+ if !layout-root =>
181
+ console.error "[@plotdb/chart] cannot determine root node for @plotdb/layout."
182
+ console.error "[@plotdb/chart] config layout properly or disable layout by setting layout to false"
183
+ @layout = new layout(
184
+ if typeof(@layout-opt) == \object => ({} <<< @layout-opt <<< {watch-resize: false})
185
+ else {root: layout-root, watch-resize: false}
186
+ )
187
+
188
+ # we don't know when resizeObserver will call _resize but we need it to be called.
189
+ # thus, we lock execution here until resizeObserver calls _resize
190
+ _resize-lock = proxise ~> resizeObserver.add(@root, @); return null
191
+ # however, if somewhat resizeObserver won't be called soon ( due to invisibility of node )
192
+ # we then may want to get around it.
193
+ # see also: `resizeObserver.add` above.
194
+ if @force-init and !@root.offsetParent or window.getComputedStyle(@root).display == \none => return
195
+ # - unlocker
196
+ @_resize = -> _resize-lock.resolve!
197
+ # - locker
198
+ _resize-lock!
199
+ .then ~>
200
+ # once resizeObserver called _resize, we temporarily disable it until init is finished.
201
+ @_resize = ~>
202
+ .then ~>
203
+ # if no layout used, we init directly. otherwise we will call mod.init in layout.init
204
+ # we have to do this because:
205
+ # - layout prepare necessary dom which may be used by init
206
+ # - but init may generate necessary dom for layout.update
207
+ init = ~> if @mod.init => @mod.init.apply(@)
208
+ if !@layout => return init!
209
+ layout-lock = proxise ~> Promise.resolve(@layout.init init); return null
210
+ @_layout = ~> layout-lock.resolve!
211
+ @layout.on \render, ~> @_layout!
212
+ layout-lock!
213
+ .then ~>
214
+ # once layout prepared, we temporarily disable layout update event until init is finished.
215
+ @_layout = ~>
216
+ Promise.resolve!
217
+ .then ~>
218
+ # if for any reason user doesn't want to render right after init
219
+ # then we just lock it until set-raw.
220
+ if !@delay-render => return
221
+ @render-lock = proxise ~>
222
+ @render-lock!
223
+ .then ~>
224
+ # init is finished and we are prepared to render.
225
+ @_resize = ~> @resize!; @render!
226
+ @_layout = ~> @parse!; @bind!; @resize!; @render!
227
+ @parse!
228
+ @bind!
229
+ @resize!
230
+ @render!
231
+ # explicit return non-promise so init is declared as finished
232
+ # and won't block following codes.
233
+ return
234
+
235
+ parse: ->
236
+ @data = @raw.map (r,i) ~>
237
+ ret = {}
238
+ [{k,v} for k,v of @binding].map ({k,v}) ~>
239
+ if !v => return
240
+ ret[k] = if @mod.{}dimension{}[k].multiple => v.map -> r[it.key]
241
+ else r[v.key]
242
+ t = @mod.{}dimension{}[k].type
243
+ # TODO Since 'RC' is also possible, we should add and check the matched type instead of supported type.
244
+ if /[RIT]/.exec(t) and !/[CN]/.exec(t) =>
245
+ ret[k] = if Array.isArray(ret[k]) => ret[k].map(->parseFloat(it)) else parseFloat(ret[k])
246
+ ret._raw = r
247
+ ret._idx = i
248
+ ret
249
+ if @mod.parse => @mod.parse.apply @
250
+ bind: -> if @mod.bind => @mod.bind.apply @
251
+ start: ->
252
+ @_aniloop.run!
253
+ if @mod.start => @mod.start.apply @
254
+ stop: ->
255
+ @_aniloop.pause!
256
+ if @mod.stop => @mod.stop.apply @
257
+ resize: ->
258
+ # layout resize is disabled to prevent unnecessary rendering.
259
+ # however, we still need layout to be update ( without firing render event )
260
+ if @layout => @layout.update false
261
+ @box = @root.getBoundingClientRect!
262
+ if @mod.resize => @mod.resize.apply @
263
+ tick: -> if @mod.tick => @mod.tick.apply @
264
+ render: -> if @mod.render => @mod.render.apply @
265
+ destroy: ->
266
+ Promise.resolve!then ~>
267
+ if @_select => @root.removeEventListener \click, @_select
268
+ if @_hover => @root.removeEventListener \mouseover, @_hover
269
+ resizeObserver.delete @root
270
+ if @layout => @layout.destroy!
271
+ @stop!
272
+ if @mod.destroy => return @mod.destroy.apply @
273
+
274
+ config: (opt) ->
275
+ if !(opt? and opt) => return @cfg
276
+ @cfg <<< opt
277
+
278
+ set-bind: (n,b) ->
279
+ @binding[n] = b
280
+ @parse!
281
+ @bind!
282
+ @resize!
283
+ @render!
284
+
285
+ set-raw: (raw, binding, reinit = false) ->
286
+ if !Array.isArray(raw) => {raw,binding,reinit} = raw
287
+ if raw? => @raw = raw
288
+ if binding? => @binding = binding
289
+ # if there is render-lock, then we are still in initing process and no need to reinit.
290
+ # reinit is only needed if there is no render-lock
291
+ if @render-lock =>
292
+ @render-lock.resolve!
293
+ @render-lock = null
294
+ else
295
+ if reinit and @mod.init => @mod.init.apply(@)
296
+ @parse!
297
+ @bind!
298
+ @resize!
299
+ @render!
300
+ on: (n, cb) -> (if Array.isArray(n) => n else [n]).map (n) ~> @evt-handler.[][n].push cb
301
+ fire: (n, ...v) -> for cb in (@evt-handler[n] or []) => cb.apply @, v
302
+ filter: (filters = {}, internal = false) ->
303
+ bs = []
304
+ for k,v of @binding =>
305
+ u = if Array.isArray(v) => v else [v]
306
+ u = u.map (v) -> {k,v}
307
+ bs ++= u
308
+ for k,v of filters =>
309
+ bs
310
+ .filter(-> it.k == k)
311
+ .map -> it.v.filter = v
312
+ if internal => @fire \filter, filters
313
+ if @mod.filter => @mod.filter.apply @, [filters, internal]
314
+ @parse!
315
+ @bind!
316
+ @resize!
317
+ @render!
318
+
319
+ if module? => module.exports = chart
320
+ else if window? => window.chart = chart
package/src/chart.styl ADDED
@@ -0,0 +1,6 @@
1
+ div[plug=layout]
2
+ width: 100%
3
+ height: 100%
4
+ .pdl-layout
5
+ width: 100%
6
+ height: 100%
@@ -0,0 +1,20 @@
1
+ books
2
+ business
3
+ education
4
+ entertainment
5
+ finance
6
+ food & drink
7
+ games
8
+ health & fitness
9
+ lifestyle
10
+ medical
11
+ music
12
+ navigation
13
+ news
14
+ photography
15
+ productivity
16
+ social network
17
+ sports
18
+ travel
19
+ utilities
20
+ weather
@@ -0,0 +1,39 @@
1
+ apricot
2
+ pomegranate
3
+ kiwi
4
+ mango
5
+ pear
6
+ watermelon
7
+ strawberry
8
+ nectarine
9
+ blackberry
10
+ raspberry
11
+ boysenberry
12
+ dragonfruit
13
+ lemon
14
+ cherry
15
+ satsuma
16
+ guava
17
+ orange
18
+ apple
19
+ kumquat
20
+ cantaloupe
21
+ grape
22
+ clementine
23
+ grapefruit
24
+ lime
25
+ tangerine
26
+ fig
27
+ peach
28
+ coconut
29
+ pineapple
30
+ plum
31
+ honeydew
32
+ papaya
33
+ starfruit
34
+ jujube
35
+ blueberry
36
+ banana
37
+ passon fruit
38
+ avocado
39
+ huckleberry