compostjs 0.0.4 → 0.0.8
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/.claude/settings.local.json +11 -0
- package/README.md +38 -37
- package/dist/compost.js +168 -230
- package/dist/core.js +1530 -1686
- package/dist/helpers.js +31 -0
- package/dist/html.js +252 -364
- package/index.html +49 -0
- package/package.json +36 -41
- package/dist/bundle.js +0 -829
- package/dist/main.js +0 -217
package/README.md
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
|
-
# Compost.js: Composable data visualization library
|
|
2
|
-
|
|
3
|
-
Compost is a data visualization library that lets you compose rich interactive data visualizations
|
|
4
|
-
from a small number of basic primitives. The library is based on the functional programming idea of
|
|
5
|
-
composable domain-specific languages. Compost is simple (implemented in just 700 lines of code) and
|
|
6
|
-
easy to understand. Compost is a plain JavaScript library. You use it by writing JavaScript code
|
|
7
|
-
that generates a chart using some 15 basic Compost primitives.
|
|
8
|
-
|
|
9
|
-
For more information, see the [Compost web page and documentation](https://compostjs.github.io/compost).
|
|
10
|
-
|
|
11
|
-
## Getting started with Compost
|
|
12
|
-
|
|
13
|
-
Compost is written using [the F# language](https://fsharp.org) and compiled to JavaScript
|
|
14
|
-
using [the Fable compiler](https://fable.io). To build Compost, you will need to install
|
|
15
|
-
[.NET Core](https://dotnet.microsoft.com/download). You may also want to get the
|
|
16
|
-
[Ionide plugin](http://ionide.io/) for Visual Studio Code.
|
|
17
|
-
|
|
18
|
-
### Developing Compost
|
|
19
|
-
To work on Compost, you can use the WebPack dev server. The following will serve the
|
|
20
|
-
`public/index.html` file and compile the `src/project/demos.js` source code at
|
|
21
|
-
http://localhost:8080
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
npm
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
# Compost.js: Composable data visualization library
|
|
2
|
+
|
|
3
|
+
Compost is a data visualization library that lets you compose rich interactive data visualizations
|
|
4
|
+
from a small number of basic primitives. The library is based on the functional programming idea of
|
|
5
|
+
composable domain-specific languages. Compost is simple (implemented in just 700 lines of code) and
|
|
6
|
+
easy to understand. Compost is a plain JavaScript library. You use it by writing JavaScript code
|
|
7
|
+
that generates a chart using some 15 basic Compost primitives.
|
|
8
|
+
|
|
9
|
+
For more information, see the [Compost web page and documentation](https://compostjs.github.io/compost).
|
|
10
|
+
|
|
11
|
+
## Getting started with Compost
|
|
12
|
+
|
|
13
|
+
Compost is written using [the F# language](https://fsharp.org) and compiled to JavaScript
|
|
14
|
+
using [the Fable compiler](https://fable.io). To build Compost, you will need to install
|
|
15
|
+
[.NET Core](https://dotnet.microsoft.com/download). You may also want to get the
|
|
16
|
+
[Ionide plugin](http://ionide.io/) for Visual Studio Code.
|
|
17
|
+
|
|
18
|
+
### Developing Compost
|
|
19
|
+
To work on Compost, you can use the WebPack dev server. The following will serve the
|
|
20
|
+
`public/index.html` file and compile the `src/project/demos.js` source code at
|
|
21
|
+
http://localhost:8080
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
npm install
|
|
25
|
+
npm start
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Building Compost
|
|
29
|
+
There are two ways to build Compost. Running `npm run build` will use `fable-splitter`
|
|
30
|
+
to generate nice JavaScript files for a NPM package in the `dist` folder, which is then
|
|
31
|
+
packaged and published on NPM. Running `npm run standalone` builds a standalone
|
|
32
|
+
JavaScript file that is added to the `releases` folder of the `docs` with the current
|
|
33
|
+
version number in the filename (and also updates the `latest` file).
|
|
34
|
+
This should all happen automatically when using `npm run release`.
|
|
35
|
+
|
|
36
|
+
## What is the story behind the name??
|
|
37
|
+
|
|
38
|
+

|
package/dist/compost.js
CHANGED
|
@@ -1,230 +1,168 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { equals } from "./fable-library.
|
|
7
|
-
import { renderTo, createVirtualDomApp } from "./html";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
case "touchstart":
|
|
173
|
-
{
|
|
174
|
-
return new EventHandler(4, "TouchStart", function (me$$3, tupledArg$$3) {
|
|
175
|
-
f$$2([Helpers$$$formatValue(tupledArg$$3[0]), Helpers$$$formatValue(tupledArg$$3[1]), me$$3]);
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
case "touchmove":
|
|
180
|
-
{
|
|
181
|
-
return new EventHandler(5, "TouchMove", function (me$$4, tupledArg$$4) {
|
|
182
|
-
f$$2([Helpers$$$formatValue(tupledArg$$4[0]), Helpers$$$formatValue(tupledArg$$4[1]), me$$4]);
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
case "click":
|
|
187
|
-
{
|
|
188
|
-
return new EventHandler(3, "Click", function (me$$5, tupledArg$$5) {
|
|
189
|
-
f$$2([Helpers$$$formatValue(tupledArg$$5[0]), Helpers$$$formatValue(tupledArg$$5[1]), me$$5]);
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
case "mouseleave":
|
|
194
|
-
{
|
|
195
|
-
return new EventHandler(7, "MouseLeave", function (me$$6) {
|
|
196
|
-
f$$2([me$$6]);
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
case "touchend":
|
|
201
|
-
{
|
|
202
|
-
return new EventHandler(6, "TouchEnd", function (me$$7) {
|
|
203
|
-
f$$2([me$$7]);
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
default:
|
|
208
|
-
{
|
|
209
|
-
const clo1$$3 = toFail(printf("Unsupported event type '%s' passed to the 'on' primitive."));
|
|
210
|
-
return clo1$$3(k);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}, Object.keys(o));
|
|
214
|
-
})), s$$10);
|
|
215
|
-
},
|
|
216
|
-
|
|
217
|
-
interactive(id, init, update, render) {
|
|
218
|
-
createVirtualDomApp(id, init, function render$$1(t$$2, s$$12) {
|
|
219
|
-
const el = document.getElementById(id);
|
|
220
|
-
return Compost$0024$0024$0024createSvg(false, false, el.clientWidth, el.clientHeight, render(t$$2, s$$12));
|
|
221
|
-
}, update);
|
|
222
|
-
},
|
|
223
|
-
|
|
224
|
-
render(id$$1, viz) {
|
|
225
|
-
const el$$1 = document.getElementById(id$$1);
|
|
226
|
-
const svg = Compost$0024$0024$0024createSvg(false, false, el$$1.clientWidth, el$$1.clientHeight, viz);
|
|
227
|
-
renderTo(el$$1, svg);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
};
|
|
1
|
+
import { Compost_createSvg, EventHandler, HorizontalAlign, VerticalAlign, Derived_Bar, Derived_Column, Derived_Font, Derived_StrokeColor, Derived_FillColor, Shape, Scale, categorical, Value, continuous } from "./core.js";
|
|
2
|
+
import { printf, toFail } from "./fable_modules/fable-library-js.4.28.0/String.js";
|
|
3
|
+
import { map as map_1, item } from "./fable_modules/fable-library-js.4.28.0/Array.js";
|
|
4
|
+
import { toList, map, delay, toArray } from "./fable_modules/fable-library-js.4.28.0/Seq.js";
|
|
5
|
+
import { ofArray } from "./fable_modules/fable-library-js.4.28.0/List.js";
|
|
6
|
+
import { defaultOf, equals } from "./fable_modules/fable-library-js.4.28.0/Util.js";
|
|
7
|
+
import { renderTo, createVirtualDomApp, DomNode, DomAttribute } from "./html.js";
|
|
8
|
+
|
|
9
|
+
export function Helpers_formatValue(v) {
|
|
10
|
+
if (v.tag === 1) {
|
|
11
|
+
return v.fields[0].fields[0];
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return [v.fields[0].fields[0], v.fields[1]];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function Helpers_parseValue(v) {
|
|
19
|
+
if ((typeof(v)=='number')) {
|
|
20
|
+
return new Value(1, [new continuous(v)]);
|
|
21
|
+
}
|
|
22
|
+
else if (Array.isArray(v)) {
|
|
23
|
+
const a = v;
|
|
24
|
+
if (a.length !== 2) {
|
|
25
|
+
toFail(printf("Cannot parse value: %A. Expected a number or an array with two elements."))(a);
|
|
26
|
+
}
|
|
27
|
+
if (!((typeof(item(1, a))=='number'))) {
|
|
28
|
+
toFail(printf("Cannot parse value: %A. The second element should be a number."))(a);
|
|
29
|
+
}
|
|
30
|
+
return new Value(0, [new categorical(item(0, a)), item(1, a)]);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return toFail(printf("Cannot parse value: %A. Expected a number or an array with two elements."))(v);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const scale = {
|
|
38
|
+
continuous(lo, hi) {
|
|
39
|
+
return new Scale(0, [new continuous(lo), new continuous(hi)]);
|
|
40
|
+
},
|
|
41
|
+
categorical(cats) {
|
|
42
|
+
return new Scale(1, [toArray(delay(() => map((c) => (new categorical(c)), cats)))]);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const compost = {
|
|
47
|
+
scaleX(sc, sh) {
|
|
48
|
+
return new Shape(3, [sc, undefined, sh]);
|
|
49
|
+
},
|
|
50
|
+
scaleY(sc_1, sh_1) {
|
|
51
|
+
return new Shape(3, [undefined, sc_1, sh_1]);
|
|
52
|
+
},
|
|
53
|
+
scale(sx, sy, sh_2) {
|
|
54
|
+
return new Shape(3, [sx, sy, sh_2]);
|
|
55
|
+
},
|
|
56
|
+
nestX(lx, hx, s) {
|
|
57
|
+
return new Shape(4, [Helpers_parseValue(lx), Helpers_parseValue(hx), s]);
|
|
58
|
+
},
|
|
59
|
+
nestY(ly, hy, s_1) {
|
|
60
|
+
return new Shape(5, [Helpers_parseValue(ly), Helpers_parseValue(hy), s_1]);
|
|
61
|
+
},
|
|
62
|
+
nest(lx_1, hx_1, ly_1, hy_1, s_2) {
|
|
63
|
+
return new Shape(5, [Helpers_parseValue(ly_1), Helpers_parseValue(hy_1), new Shape(4, [Helpers_parseValue(lx_1), Helpers_parseValue(hx_1), s_2])]);
|
|
64
|
+
},
|
|
65
|
+
overlay(sh_3) {
|
|
66
|
+
return new Shape(9, [ofArray(sh_3)]);
|
|
67
|
+
},
|
|
68
|
+
padding(t, r, b, l, s_3) {
|
|
69
|
+
return new Shape(12, [[t, r, b, l], s_3]);
|
|
70
|
+
},
|
|
71
|
+
fillColor(c, s_4) {
|
|
72
|
+
return Derived_FillColor(c, s_4);
|
|
73
|
+
},
|
|
74
|
+
strokeColor(c_1, s_5) {
|
|
75
|
+
return Derived_StrokeColor(c_1, s_5);
|
|
76
|
+
},
|
|
77
|
+
font(f, c_2, s_6) {
|
|
78
|
+
return Derived_Font(f, c_2, s_6);
|
|
79
|
+
},
|
|
80
|
+
column(xp, yp) {
|
|
81
|
+
return Derived_Column(new categorical(xp), new continuous(yp));
|
|
82
|
+
},
|
|
83
|
+
bar(xp_1, yp_1) {
|
|
84
|
+
return Derived_Bar(new continuous(xp_1), new categorical(yp_1));
|
|
85
|
+
},
|
|
86
|
+
bubble(xp_2, yp_2, w, h) {
|
|
87
|
+
return new Shape(7, [Helpers_parseValue(xp_2), Helpers_parseValue(yp_2), w, h]);
|
|
88
|
+
},
|
|
89
|
+
text(xp_3, yp_3, t_1, s_7, r_1) {
|
|
90
|
+
const r_2 = equals(r_1, defaultOf()) ? 0 : r_1;
|
|
91
|
+
const s_8 = equals(s_7, defaultOf()) ? "" : s_7;
|
|
92
|
+
const va = (s_8.indexOf("baseline") >= 0) ? (new VerticalAlign(0, [])) : ((s_8.indexOf("hanging") >= 0) ? (new VerticalAlign(2, [])) : (new VerticalAlign(1, [])));
|
|
93
|
+
const ha = (s_8.indexOf("start") >= 0) ? (new HorizontalAlign(0, [])) : ((s_8.indexOf("end") >= 0) ? (new HorizontalAlign(2, [])) : (new HorizontalAlign(1, [])));
|
|
94
|
+
return new Shape(1, [Helpers_parseValue(xp_3), Helpers_parseValue(yp_3), va, ha, r_2, t_1]);
|
|
95
|
+
},
|
|
96
|
+
shape(a) {
|
|
97
|
+
return new Shape(8, [toList(delay(() => map((p) => [Helpers_parseValue(item(0, p)), Helpers_parseValue(item(1, p))], a)))]);
|
|
98
|
+
},
|
|
99
|
+
line(a_1) {
|
|
100
|
+
return new Shape(6, [toList(delay(() => map((p_1) => [Helpers_parseValue(item(0, p_1)), Helpers_parseValue(item(1, p_1))], a_1)))]);
|
|
101
|
+
},
|
|
102
|
+
axes(a_2, s_9) {
|
|
103
|
+
return new Shape(10, [a_2.indexOf("top") >= 0, a_2.indexOf("right") >= 0, a_2.indexOf("bottom") >= 0, a_2.indexOf("left") >= 0, s_9]);
|
|
104
|
+
},
|
|
105
|
+
on(o, s_10) {
|
|
106
|
+
return new Shape(11, [toList(delay(() => map((k) => {
|
|
107
|
+
let f_2;
|
|
108
|
+
const f_1 = o[k];
|
|
109
|
+
f_2 = ((args) => {
|
|
110
|
+
f_1(...args);
|
|
111
|
+
});
|
|
112
|
+
return (k === "mousedown") ? (new EventHandler(2, [(me, tupledArg) => {
|
|
113
|
+
f_2([Helpers_formatValue(tupledArg[0]), Helpers_formatValue(tupledArg[1]), me]);
|
|
114
|
+
}])) : ((k === "mouseup") ? (new EventHandler(1, [(me_1, tupledArg_1) => {
|
|
115
|
+
f_2([Helpers_formatValue(tupledArg_1[0]), Helpers_formatValue(tupledArg_1[1]), me_1]);
|
|
116
|
+
}])) : ((k === "mousemove") ? (new EventHandler(0, [(me_2, tupledArg_2) => {
|
|
117
|
+
f_2([Helpers_formatValue(tupledArg_2[0]), Helpers_formatValue(tupledArg_2[1]), me_2]);
|
|
118
|
+
}])) : ((k === "touchstart") ? (new EventHandler(4, [(me_3, tupledArg_3) => {
|
|
119
|
+
f_2([Helpers_formatValue(tupledArg_3[0]), Helpers_formatValue(tupledArg_3[1]), me_3]);
|
|
120
|
+
}])) : ((k === "touchmove") ? (new EventHandler(5, [(me_4, tupledArg_4) => {
|
|
121
|
+
f_2([Helpers_formatValue(tupledArg_4[0]), Helpers_formatValue(tupledArg_4[1]), me_4]);
|
|
122
|
+
}])) : ((k === "click") ? (new EventHandler(3, [(me_5, tupledArg_5) => {
|
|
123
|
+
f_2([Helpers_formatValue(tupledArg_5[0]), Helpers_formatValue(tupledArg_5[1]), me_5]);
|
|
124
|
+
}])) : ((k === "mouseleave") ? (new EventHandler(7, [(me_6) => {
|
|
125
|
+
f_2([me_6]);
|
|
126
|
+
}])) : ((k === "touchend") ? (new EventHandler(6, [(me_7) => {
|
|
127
|
+
f_2([me_7]);
|
|
128
|
+
}])) : toFail(printf("Unsupported event type \'%s\' passed to the \'on\' primitive."))(k))))))));
|
|
129
|
+
}, Object.keys(o)))), s_10]);
|
|
130
|
+
},
|
|
131
|
+
svg(w_1, h_1, shape) {
|
|
132
|
+
return Compost_createSvg(false, false, w_1, h_1, shape);
|
|
133
|
+
},
|
|
134
|
+
html(tag, attrs, children) {
|
|
135
|
+
const attrs_1 = toArray(delay(() => map((a_3) => {
|
|
136
|
+
const p_2 = attrs[a_3];
|
|
137
|
+
return ((typeof(p_2)) === "function") ? [a_3, new DomAttribute(0, [(e, h_2) => {
|
|
138
|
+
p_2(...[e, h_2]);
|
|
139
|
+
}])] : [a_3, new DomAttribute(1, [p_2])];
|
|
140
|
+
}, Object.keys(attrs))));
|
|
141
|
+
const children_1 = map_1((c_3) => {
|
|
142
|
+
if ((typeof(c_3)) === "string") {
|
|
143
|
+
return new DomNode(0, [c_3]);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
return c_3;
|
|
147
|
+
}
|
|
148
|
+
}, children);
|
|
149
|
+
return new DomNode(1, [defaultOf(), tag, attrs_1, children_1]);
|
|
150
|
+
},
|
|
151
|
+
interactive(id, init, update, render) {
|
|
152
|
+
createVirtualDomApp(id, init, (t_2, s_12) => {
|
|
153
|
+
const el = document.getElementById(id);
|
|
154
|
+
const res = render(t_2, s_12);
|
|
155
|
+
if (equals(res["constructor"], (new DomNode(0, [""]))["constructor"])) {
|
|
156
|
+
return res;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
return Compost_createSvg(false, false, el.clientWidth, el.clientHeight, res);
|
|
160
|
+
}
|
|
161
|
+
}, update);
|
|
162
|
+
},
|
|
163
|
+
render(id_1, viz) {
|
|
164
|
+
const el_1 = document.getElementById(id_1);
|
|
165
|
+
renderTo(el_1, Compost_createSvg(false, false, el_1.clientWidth, el_1.clientHeight, viz));
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
|