simview 3.2__py3-none-any.whl
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.
- simview/__init__.py +69 -0
- simview/__main__.py +174 -0
- simview/launcher.py +109 -0
- simview/live.py +204 -0
- simview/merge.py +593 -0
- simview/model.py +690 -0
- simview/py.typed +0 -0
- simview/scene.py +603 -0
- simview/server.py +739 -0
- simview/state.py +190 -0
- simview/static/css/controls.css +36 -0
- simview/static/js/SimView.js +601 -0
- simview/static/js/components/AnimationController.js +654 -0
- simview/static/js/components/BatchManager.js +198 -0
- simview/static/js/components/InteractionController.js +446 -0
- simview/static/js/components/InteractionControls.js +116 -0
- simview/static/js/components/Scene.js +166 -0
- simview/static/js/components/StateStore.js +188 -0
- simview/static/js/config.js +233 -0
- simview/static/js/main.js +3 -0
- simview/static/js/objects/Body.js +616 -0
- simview/static/js/objects/StaticObject.js +181 -0
- simview/static/js/objects/Terrain.js +514 -0
- simview/static/js/objects/utils.js +378 -0
- simview/static/js/ui/AnalysisPanel.js +233 -0
- simview/static/js/ui/BatchLegend.js +207 -0
- simview/static/js/ui/BodyStateWindow.js +521 -0
- simview/static/js/ui/Controls.js +586 -0
- simview/static/js/ui/ErrorMetrics.js +664 -0
- simview/static/js/ui/Legend.js +87 -0
- simview/static/js/ui/PlaybackControls.js +314 -0
- simview/static/js/ui/ScalarPlotter.js +575 -0
- simview/static/js/utils/blobCodec.js +73 -0
- simview/static/js/utils/bodyTransforms.js +151 -0
- simview/static/js/utils/csv.js +46 -0
- simview/static/js/utils/errorMath.js +69 -0
- simview/static/js/utils/injectStyles.js +16 -0
- simview/static/js/utils/interpolate.js +65 -0
- simview/static/js/utils/liveFollow.js +17 -0
- simview/static/js/utils/loadRecordingLibs.js +34 -0
- simview/static/js/utils/viewState.js +226 -0
- simview/static/lib/chroma-js-3.1.2/index.min.js +8 -0
- simview/static/lib/chroma-js-3.1.2/src/Color.js +49 -0
- simview/static/lib/chroma-js-3.1.2/src/chroma.js +10 -0
- simview/static/lib/chroma-js-3.1.2/src/colors/colorbrewer.js +81 -0
- simview/static/lib/chroma-js-3.1.2/src/colors/w3cx11.js +164 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/average.js +88 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/bezier.js +86 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/blend.js +57 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/cubehelix.js +87 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/mix.js +19 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/random.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/generator/scale.js +394 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/_hsx.js +59 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/hcg.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/hsi.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/hsl.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/hsv.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/index.js +1 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/lab.js +19 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/lch.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/lrgb.js +19 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/num.js +15 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/oklab.js +19 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/oklch.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/interpolator/rgb.js +18 -0
- simview/static/lib/chroma-js-3.1.2/src/io/cmyk/cmyk2rgb.js +16 -0
- simview/static/lib/chroma-js-3.1.2/src/io/cmyk/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/cmyk/rgb2cmyk.js +17 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/css2rgb.js +238 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/hsl2css.js +26 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/lab2css.js +24 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/lch2css.js +24 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/oklab2css.js +16 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/oklch2css.js +16 -0
- simview/static/lib/chroma-js-3.1.2/src/io/css/rgb2css.js +61 -0
- simview/static/lib/chroma-js-3.1.2/src/io/gl/index.js +22 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hcg/hcg2rgb.js +55 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hcg/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hcg/rgb2hcg.js +23 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hex/hex2rgb.js +56 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hex/index.js +29 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hex/rgb2hex.js +29 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsi/hsi2rgb.js +45 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsi/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsi/rgb2hsi.js +31 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsl/hsl2rgb.js +35 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsl/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsl/rgb2hsl.js +45 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsv/hsv2rgb.js +47 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsv/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/hsv/rgb2hsv.js +32 -0
- simview/static/lib/chroma-js-3.1.2/src/io/input.js +4 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lab/index.js +28 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lab/lab-constants.js +120 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lab/lab2rgb.js +101 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lab/rgb2lab.js +67 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/hcl2rgb.js +9 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/index.js +35 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/lab2lch.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/lch2lab.js +18 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/lch2rgb.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/io/lch/rgb2lch.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/io/named/index.js +30 -0
- simview/static/lib/chroma-js-3.1.2/src/io/num/index.js +32 -0
- simview/static/lib/chroma-js-3.1.2/src/io/num/num2rgb.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/io/num/rgb2num.js +8 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklab/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklab/oklab2rgb.js +34 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklab/rgb2oklab.js +37 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklch/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklch/oklch2rgb.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/io/oklch/rgb2oklch.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/io/rgb/index.js +44 -0
- simview/static/lib/chroma-js-3.1.2/src/io/temp/index.js +22 -0
- simview/static/lib/chroma-js-3.1.2/src/io/temp/rgb2temperature.js +30 -0
- simview/static/lib/chroma-js-3.1.2/src/io/temp/temperature2rgb.js +39 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/alpha.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/clipped.js +5 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/darken.js +17 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/get.js +13 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/luminance.js +54 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/mix.js +10 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/premultiply.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/saturate.js +15 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/set.js +43 -0
- simview/static/lib/chroma-js-3.1.2/src/ops/shade.js +11 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/analyze.js +191 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/clip_rgb.js +15 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/contrast.js +12 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/contrastAPCA.js +68 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/delta-e.js +62 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/distance.js +17 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/index.js +27 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/last.js +8 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/limit.js +5 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/multiply-matrices.js +36 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/scales.js +15 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/type.js +18 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/unpack.js +17 -0
- simview/static/lib/chroma-js-3.1.2/src/utils/valid.js +11 -0
- simview/static/lib/chroma-js-3.1.2/src/version.js +2 -0
- simview/static/lib/download.js +132 -0
- simview/static/lib/js-colormaps.js +19335 -0
- simview/static/lib/tar.js +334 -0
- simview/static/lib/three-0.174.0/addons/controls/OrbitControls.js +1556 -0
- simview/static/lib/three-0.174.0/addons/libs/lil-gui.module.min.js +8 -0
- simview/static/lib/three-0.174.0/three.core.js +48830 -0
- simview/static/lib/three-0.174.0/three.module.js +17313 -0
- simview/static/lib/uPlot.esm.js +6140 -0
- simview/static/lib/uPlot.min.css +2 -0
- simview/static/textures/contacts/red-cross0.png +0 -0
- simview/static/textures/points/ball0.png +0 -0
- simview/static/textures/points/ball1.png +0 -0
- simview/templates/index.html +81 -0
- simview/utils.py +41 -0
- simview-3.2.dist-info/METADATA +552 -0
- simview-3.2.dist-info/RECORD +163 -0
- simview-3.2.dist-info/WHEEL +5 -0
- simview-3.2.dist-info/entry_points.txt +2 -0
- simview-3.2.dist-info/licenses/LICENSE +28 -0
- simview-3.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type from './type.js';
|
|
2
|
+
|
|
3
|
+
const { log, pow, floor, abs } = Math;
|
|
4
|
+
|
|
5
|
+
export function analyze(data, key = null) {
|
|
6
|
+
const r = {
|
|
7
|
+
min: Number.MAX_VALUE,
|
|
8
|
+
max: Number.MAX_VALUE * -1,
|
|
9
|
+
sum: 0,
|
|
10
|
+
values: [],
|
|
11
|
+
count: 0
|
|
12
|
+
};
|
|
13
|
+
if (type(data) === 'object') {
|
|
14
|
+
data = Object.values(data);
|
|
15
|
+
}
|
|
16
|
+
data.forEach((val) => {
|
|
17
|
+
if (key && type(val) === 'object') val = val[key];
|
|
18
|
+
if (val !== undefined && val !== null && !isNaN(val)) {
|
|
19
|
+
r.values.push(val);
|
|
20
|
+
r.sum += val;
|
|
21
|
+
if (val < r.min) r.min = val;
|
|
22
|
+
if (val > r.max) r.max = val;
|
|
23
|
+
r.count += 1;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
r.domain = [r.min, r.max];
|
|
28
|
+
|
|
29
|
+
r.limits = (mode, num) => limits(r, mode, num);
|
|
30
|
+
|
|
31
|
+
return r;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function limits(data, mode = 'equal', num = 7) {
|
|
35
|
+
if (type(data) == 'array') {
|
|
36
|
+
data = analyze(data);
|
|
37
|
+
}
|
|
38
|
+
const { min, max } = data;
|
|
39
|
+
const values = data.values.sort((a, b) => a - b);
|
|
40
|
+
|
|
41
|
+
if (num === 1) {
|
|
42
|
+
return [min, max];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const limits = [];
|
|
46
|
+
|
|
47
|
+
if (mode.substr(0, 1) === 'c') {
|
|
48
|
+
// continuous
|
|
49
|
+
limits.push(min);
|
|
50
|
+
limits.push(max);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (mode.substr(0, 1) === 'e') {
|
|
54
|
+
// equal interval
|
|
55
|
+
limits.push(min);
|
|
56
|
+
for (let i = 1; i < num; i++) {
|
|
57
|
+
limits.push(min + (i / num) * (max - min));
|
|
58
|
+
}
|
|
59
|
+
limits.push(max);
|
|
60
|
+
} else if (mode.substr(0, 1) === 'l') {
|
|
61
|
+
// log scale
|
|
62
|
+
if (min <= 0) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
'Logarithmic scales are only possible for values > 0'
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const min_log = Math.LOG10E * log(min);
|
|
68
|
+
const max_log = Math.LOG10E * log(max);
|
|
69
|
+
limits.push(min);
|
|
70
|
+
for (let i = 1; i < num; i++) {
|
|
71
|
+
limits.push(pow(10, min_log + (i / num) * (max_log - min_log)));
|
|
72
|
+
}
|
|
73
|
+
limits.push(max);
|
|
74
|
+
} else if (mode.substr(0, 1) === 'q') {
|
|
75
|
+
// quantile scale
|
|
76
|
+
limits.push(min);
|
|
77
|
+
for (let i = 1; i < num; i++) {
|
|
78
|
+
const p = ((values.length - 1) * i) / num;
|
|
79
|
+
const pb = floor(p);
|
|
80
|
+
if (pb === p) {
|
|
81
|
+
limits.push(values[pb]);
|
|
82
|
+
} else {
|
|
83
|
+
// p > pb
|
|
84
|
+
const pr = p - pb;
|
|
85
|
+
limits.push(values[pb] * (1 - pr) + values[pb + 1] * pr);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
limits.push(max);
|
|
89
|
+
} else if (mode.substr(0, 1) === 'k') {
|
|
90
|
+
// k-means clustering
|
|
91
|
+
/*
|
|
92
|
+
implementation based on
|
|
93
|
+
http://code.google.com/p/figue/source/browse/trunk/figue.js#336
|
|
94
|
+
simplified for 1-d input values
|
|
95
|
+
*/
|
|
96
|
+
let cluster;
|
|
97
|
+
const n = values.length;
|
|
98
|
+
const assignments = new Array(n);
|
|
99
|
+
const clusterSizes = new Array(num);
|
|
100
|
+
let repeat = true;
|
|
101
|
+
let nb_iters = 0;
|
|
102
|
+
let centroids = null;
|
|
103
|
+
|
|
104
|
+
// get seed values
|
|
105
|
+
centroids = [];
|
|
106
|
+
centroids.push(min);
|
|
107
|
+
for (let i = 1; i < num; i++) {
|
|
108
|
+
centroids.push(min + (i / num) * (max - min));
|
|
109
|
+
}
|
|
110
|
+
centroids.push(max);
|
|
111
|
+
|
|
112
|
+
while (repeat) {
|
|
113
|
+
// assignment step
|
|
114
|
+
for (let j = 0; j < num; j++) {
|
|
115
|
+
clusterSizes[j] = 0;
|
|
116
|
+
}
|
|
117
|
+
for (let i = 0; i < n; i++) {
|
|
118
|
+
const value = values[i];
|
|
119
|
+
let mindist = Number.MAX_VALUE;
|
|
120
|
+
let best;
|
|
121
|
+
for (let j = 0; j < num; j++) {
|
|
122
|
+
const dist = abs(centroids[j] - value);
|
|
123
|
+
if (dist < mindist) {
|
|
124
|
+
mindist = dist;
|
|
125
|
+
best = j;
|
|
126
|
+
}
|
|
127
|
+
clusterSizes[best]++;
|
|
128
|
+
assignments[i] = best;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// update centroids step
|
|
133
|
+
const newCentroids = new Array(num);
|
|
134
|
+
for (let j = 0; j < num; j++) {
|
|
135
|
+
newCentroids[j] = null;
|
|
136
|
+
}
|
|
137
|
+
for (let i = 0; i < n; i++) {
|
|
138
|
+
cluster = assignments[i];
|
|
139
|
+
if (newCentroids[cluster] === null) {
|
|
140
|
+
newCentroids[cluster] = values[i];
|
|
141
|
+
} else {
|
|
142
|
+
newCentroids[cluster] += values[i];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
for (let j = 0; j < num; j++) {
|
|
146
|
+
newCentroids[j] *= 1 / clusterSizes[j];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// check convergence
|
|
150
|
+
repeat = false;
|
|
151
|
+
for (let j = 0; j < num; j++) {
|
|
152
|
+
if (newCentroids[j] !== centroids[j]) {
|
|
153
|
+
repeat = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
centroids = newCentroids;
|
|
159
|
+
nb_iters++;
|
|
160
|
+
|
|
161
|
+
if (nb_iters > 200) {
|
|
162
|
+
repeat = false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// finished k-means clustering
|
|
167
|
+
// the next part is borrowed from gabrielflor.it
|
|
168
|
+
const kClusters = {};
|
|
169
|
+
for (let j = 0; j < num; j++) {
|
|
170
|
+
kClusters[j] = [];
|
|
171
|
+
}
|
|
172
|
+
for (let i = 0; i < n; i++) {
|
|
173
|
+
cluster = assignments[i];
|
|
174
|
+
kClusters[cluster].push(values[i]);
|
|
175
|
+
}
|
|
176
|
+
let tmpKMeansBreaks = [];
|
|
177
|
+
for (let j = 0; j < num; j++) {
|
|
178
|
+
tmpKMeansBreaks.push(kClusters[j][0]);
|
|
179
|
+
tmpKMeansBreaks.push(kClusters[j][kClusters[j].length - 1]);
|
|
180
|
+
}
|
|
181
|
+
tmpKMeansBreaks = tmpKMeansBreaks.sort((a, b) => a - b);
|
|
182
|
+
limits.push(tmpKMeansBreaks[0]);
|
|
183
|
+
for (let i = 1; i < tmpKMeansBreaks.length; i += 2) {
|
|
184
|
+
const v = tmpKMeansBreaks[i];
|
|
185
|
+
if (!isNaN(v) && limits.indexOf(v) === -1) {
|
|
186
|
+
limits.push(v);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return limits;
|
|
191
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import limit from './limit.js';
|
|
2
|
+
|
|
3
|
+
export default (rgb) => {
|
|
4
|
+
rgb._clipped = false;
|
|
5
|
+
rgb._unclipped = rgb.slice(0);
|
|
6
|
+
for (let i = 0; i <= 3; i++) {
|
|
7
|
+
if (i < 3) {
|
|
8
|
+
if (rgb[i] < 0 || rgb[i] > 255) rgb._clipped = true;
|
|
9
|
+
rgb[i] = limit(rgb[i], 0, 255);
|
|
10
|
+
} else if (i === 3) {
|
|
11
|
+
rgb[i] = limit(rgb[i], 0, 1);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return rgb;
|
|
15
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Color from '../Color.js';
|
|
2
|
+
import '../ops/luminance.js';
|
|
3
|
+
|
|
4
|
+
export default (a, b) => {
|
|
5
|
+
// WCAG contrast ratio
|
|
6
|
+
// see http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
|
|
7
|
+
a = new Color(a);
|
|
8
|
+
b = new Color(b);
|
|
9
|
+
const l1 = a.luminance();
|
|
10
|
+
const l2 = b.luminance();
|
|
11
|
+
return l1 > l2 ? (l1 + 0.05) / (l2 + 0.05) : (l2 + 0.05) / (l1 + 0.05);
|
|
12
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import Color from '../Color.js';
|
|
2
|
+
import mix from '../generator/mix.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @license
|
|
6
|
+
*
|
|
7
|
+
* The APCA contrast prediction algorithm is based of the formulas published
|
|
8
|
+
* in the APCA-1.0.98G specification by Myndex. The specification is available at:
|
|
9
|
+
* https://raw.githubusercontent.com/Myndex/apca-w3/master/images/APCAw3_0.1.17_APCA0.0.98G.svg
|
|
10
|
+
*
|
|
11
|
+
* Note that the APCA implementation is still beta, so please update to
|
|
12
|
+
* future versions of chroma.js when they become available.
|
|
13
|
+
*
|
|
14
|
+
* You can read more about the APCA Readability Criterion at
|
|
15
|
+
* https://readtech.org/ARC/
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// constants
|
|
19
|
+
const W_offset = 0.027;
|
|
20
|
+
const P_in = 0.0005;
|
|
21
|
+
const P_out = 0.1;
|
|
22
|
+
const R_scale = 1.14;
|
|
23
|
+
const B_threshold = 0.022;
|
|
24
|
+
const B_exp = 1.414;
|
|
25
|
+
|
|
26
|
+
export default (text, bg) => {
|
|
27
|
+
// parse input colors
|
|
28
|
+
text = new Color(text);
|
|
29
|
+
bg = new Color(bg);
|
|
30
|
+
// if text color has alpha, blend against background
|
|
31
|
+
if (text.alpha() < 1) {
|
|
32
|
+
text = mix(bg, text, text.alpha(), 'rgb');
|
|
33
|
+
}
|
|
34
|
+
const l_text = lum(...text.rgb());
|
|
35
|
+
const l_bg = lum(...bg.rgb());
|
|
36
|
+
|
|
37
|
+
// soft clamp black levels
|
|
38
|
+
const Y_text =
|
|
39
|
+
l_text >= B_threshold
|
|
40
|
+
? l_text
|
|
41
|
+
: l_text + Math.pow(B_threshold - l_text, B_exp);
|
|
42
|
+
const Y_bg =
|
|
43
|
+
l_bg >= B_threshold ? l_bg : l_bg + Math.pow(B_threshold - l_bg, B_exp);
|
|
44
|
+
|
|
45
|
+
// normal polarity (dark text on light background)
|
|
46
|
+
const S_norm = Math.pow(Y_bg, 0.56) - Math.pow(Y_text, 0.57);
|
|
47
|
+
// reverse polarity (light text on dark background)
|
|
48
|
+
const S_rev = Math.pow(Y_bg, 0.65) - Math.pow(Y_text, 0.62);
|
|
49
|
+
// clamp noise then scale
|
|
50
|
+
const C =
|
|
51
|
+
Math.abs(Y_bg - Y_text) < P_in
|
|
52
|
+
? 0
|
|
53
|
+
: Y_text < Y_bg
|
|
54
|
+
? S_norm * R_scale
|
|
55
|
+
: S_rev * R_scale;
|
|
56
|
+
// clamp minimum contrast then offset
|
|
57
|
+
const S_apc = Math.abs(C) < P_out ? 0 : C > 0 ? C - W_offset : C + W_offset;
|
|
58
|
+
// scale to 100
|
|
59
|
+
return S_apc * 100;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function lum(r, g, b) {
|
|
63
|
+
return (
|
|
64
|
+
0.2126729 * Math.pow(r / 255, 2.4) +
|
|
65
|
+
0.7151522 * Math.pow(g / 255, 2.4) +
|
|
66
|
+
0.072175 * Math.pow(b / 255, 2.4)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import Color from '../Color.js';
|
|
2
|
+
const { sqrt, pow, min, max, atan2, abs, cos, sin, exp, PI } = Math;
|
|
3
|
+
|
|
4
|
+
export default function (a, b, Kl = 1, Kc = 1, Kh = 1) {
|
|
5
|
+
// Delta E (CIE 2000)
|
|
6
|
+
// see http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html
|
|
7
|
+
var rad2deg = function (rad) {
|
|
8
|
+
return (360 * rad) / (2 * PI);
|
|
9
|
+
};
|
|
10
|
+
var deg2rad = function (deg) {
|
|
11
|
+
return (2 * PI * deg) / 360;
|
|
12
|
+
};
|
|
13
|
+
a = new Color(a);
|
|
14
|
+
b = new Color(b);
|
|
15
|
+
const [L1, a1, b1] = Array.from(a.lab());
|
|
16
|
+
const [L2, a2, b2] = Array.from(b.lab());
|
|
17
|
+
const avgL = (L1 + L2) / 2;
|
|
18
|
+
const C1 = sqrt(pow(a1, 2) + pow(b1, 2));
|
|
19
|
+
const C2 = sqrt(pow(a2, 2) + pow(b2, 2));
|
|
20
|
+
const avgC = (C1 + C2) / 2;
|
|
21
|
+
const G = 0.5 * (1 - sqrt(pow(avgC, 7) / (pow(avgC, 7) + pow(25, 7))));
|
|
22
|
+
const a1p = a1 * (1 + G);
|
|
23
|
+
const a2p = a2 * (1 + G);
|
|
24
|
+
const C1p = sqrt(pow(a1p, 2) + pow(b1, 2));
|
|
25
|
+
const C2p = sqrt(pow(a2p, 2) + pow(b2, 2));
|
|
26
|
+
const avgCp = (C1p + C2p) / 2;
|
|
27
|
+
const arctan1 = rad2deg(atan2(b1, a1p));
|
|
28
|
+
const arctan2 = rad2deg(atan2(b2, a2p));
|
|
29
|
+
const h1p = arctan1 >= 0 ? arctan1 : arctan1 + 360;
|
|
30
|
+
const h2p = arctan2 >= 0 ? arctan2 : arctan2 + 360;
|
|
31
|
+
const avgHp =
|
|
32
|
+
abs(h1p - h2p) > 180 ? (h1p + h2p + 360) / 2 : (h1p + h2p) / 2;
|
|
33
|
+
const T =
|
|
34
|
+
1 -
|
|
35
|
+
0.17 * cos(deg2rad(avgHp - 30)) +
|
|
36
|
+
0.24 * cos(deg2rad(2 * avgHp)) +
|
|
37
|
+
0.32 * cos(deg2rad(3 * avgHp + 6)) -
|
|
38
|
+
0.2 * cos(deg2rad(4 * avgHp - 63));
|
|
39
|
+
let deltaHp = h2p - h1p;
|
|
40
|
+
deltaHp =
|
|
41
|
+
abs(deltaHp) <= 180
|
|
42
|
+
? deltaHp
|
|
43
|
+
: h2p <= h1p
|
|
44
|
+
? deltaHp + 360
|
|
45
|
+
: deltaHp - 360;
|
|
46
|
+
deltaHp = 2 * sqrt(C1p * C2p) * sin(deg2rad(deltaHp) / 2);
|
|
47
|
+
const deltaL = L2 - L1;
|
|
48
|
+
const deltaCp = C2p - C1p;
|
|
49
|
+
const sl = 1 + (0.015 * pow(avgL - 50, 2)) / sqrt(20 + pow(avgL - 50, 2));
|
|
50
|
+
const sc = 1 + 0.045 * avgCp;
|
|
51
|
+
const sh = 1 + 0.015 * avgCp * T;
|
|
52
|
+
const deltaTheta = 30 * exp(-pow((avgHp - 275) / 25, 2));
|
|
53
|
+
const Rc = 2 * sqrt(pow(avgCp, 7) / (pow(avgCp, 7) + pow(25, 7)));
|
|
54
|
+
const Rt = -Rc * sin(2 * deg2rad(deltaTheta));
|
|
55
|
+
const result = sqrt(
|
|
56
|
+
pow(deltaL / (Kl * sl), 2) +
|
|
57
|
+
pow(deltaCp / (Kc * sc), 2) +
|
|
58
|
+
pow(deltaHp / (Kh * sh), 2) +
|
|
59
|
+
Rt * (deltaCp / (Kc * sc)) * (deltaHp / (Kh * sh))
|
|
60
|
+
);
|
|
61
|
+
return max(0, min(100, result));
|
|
62
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Color from '../Color.js';
|
|
2
|
+
|
|
3
|
+
// simple Euclidean distance
|
|
4
|
+
export default function (a, b, mode = 'lab') {
|
|
5
|
+
// Delta E (CIE 1976)
|
|
6
|
+
// see http://www.brucelindbloom.com/index.html?Equations.html
|
|
7
|
+
a = new Color(a);
|
|
8
|
+
b = new Color(b);
|
|
9
|
+
const l1 = a.get(mode);
|
|
10
|
+
const l2 = b.get(mode);
|
|
11
|
+
let sum_sq = 0;
|
|
12
|
+
for (let i in l1) {
|
|
13
|
+
const d = (l1[i] || 0) - (l2[i] || 0);
|
|
14
|
+
sum_sq += d * d;
|
|
15
|
+
}
|
|
16
|
+
return Math.sqrt(sum_sq);
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const { PI, min, max } = Math;
|
|
2
|
+
|
|
3
|
+
const rnd2 = (a) => Math.round(a * 100) / 100;
|
|
4
|
+
const rnd3 = (a) => Math.round(a * 100) / 100;
|
|
5
|
+
|
|
6
|
+
export { default as clip_rgb } from './clip_rgb.js';
|
|
7
|
+
export { default as limit } from './limit.js';
|
|
8
|
+
export { default as type } from './type.js';
|
|
9
|
+
export { default as unpack } from './unpack.js';
|
|
10
|
+
export { default as last } from './last.js';
|
|
11
|
+
|
|
12
|
+
const TWOPI = PI * 2;
|
|
13
|
+
const PITHIRD = PI / 3;
|
|
14
|
+
const DEG2RAD = PI / 180;
|
|
15
|
+
const RAD2DEG = 180 / PI;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Reverse the first three elements of an array
|
|
19
|
+
*
|
|
20
|
+
* @param {any[]} arr
|
|
21
|
+
* @returns {any[]}
|
|
22
|
+
*/
|
|
23
|
+
function reverse3(arr) {
|
|
24
|
+
return [...arr.slice(0, 3).reverse(), ...arr.slice(3)];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { PI, TWOPI, PITHIRD, DEG2RAD, RAD2DEG, min, max, rnd2, rnd3, reverse3 };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// from https://www.w3.org/TR/css-color-4/multiply-matrices.js
|
|
2
|
+
export default function multiplyMatrices(A, B) {
|
|
3
|
+
let m = A.length;
|
|
4
|
+
|
|
5
|
+
if (!Array.isArray(A[0])) {
|
|
6
|
+
// A is vector, convert to [[a, b, c, ...]]
|
|
7
|
+
A = [A];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!Array.isArray(B[0])) {
|
|
11
|
+
// B is vector, convert to [[a], [b], [c], ...]]
|
|
12
|
+
B = B.map((x) => [x]);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let p = B[0].length;
|
|
16
|
+
let B_cols = B[0].map((_, i) => B.map((x) => x[i])); // transpose B
|
|
17
|
+
let product = A.map((row) =>
|
|
18
|
+
B_cols.map((col) => {
|
|
19
|
+
if (!Array.isArray(row)) {
|
|
20
|
+
return col.reduce((a, c) => a + c * row, 0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return row.reduce((a, c, i) => a + c * (col[i] || 0), 0);
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if (m === 1) {
|
|
28
|
+
product = product[0]; // Avoid [[a, b, c, ...]]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (p === 1) {
|
|
32
|
+
return product.map((x) => x[0]); // Avoid [[a], [b], [c], ...]]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return product;
|
|
36
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// some pre-defined color scales:
|
|
2
|
+
import chroma from '../chroma.js';
|
|
3
|
+
import '../io/hsl/index.js';
|
|
4
|
+
import scale from '../generator/scale.js';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
cool() {
|
|
8
|
+
return scale([chroma.hsl(180, 1, 0.9), chroma.hsl(250, 0.7, 0.4)]);
|
|
9
|
+
},
|
|
10
|
+
hot() {
|
|
11
|
+
return scale(['#000', '#f00', '#ff0', '#fff'], [0, 0.25, 0.75, 1]).mode(
|
|
12
|
+
'rgb'
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// ported from jQuery's $.type
|
|
2
|
+
const classToType = {};
|
|
3
|
+
for (let name of [
|
|
4
|
+
'Boolean',
|
|
5
|
+
'Number',
|
|
6
|
+
'String',
|
|
7
|
+
'Function',
|
|
8
|
+
'Array',
|
|
9
|
+
'Date',
|
|
10
|
+
'RegExp',
|
|
11
|
+
'Undefined',
|
|
12
|
+
'Null'
|
|
13
|
+
]) {
|
|
14
|
+
classToType[`[object ${name}]`] = name.toLowerCase();
|
|
15
|
+
}
|
|
16
|
+
export default function (obj) {
|
|
17
|
+
return classToType[Object.prototype.toString.call(obj)] || 'object';
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type from './type.js';
|
|
2
|
+
|
|
3
|
+
export default (args, keyOrder = null) => {
|
|
4
|
+
// if called with more than 3 arguments, we return the arguments
|
|
5
|
+
if (args.length >= 3) return Array.prototype.slice.call(args);
|
|
6
|
+
// with less than 3 args we check if first arg is object
|
|
7
|
+
// and use the keyOrder string to extract and sort properties
|
|
8
|
+
if (type(args[0]) == 'object' && keyOrder) {
|
|
9
|
+
return keyOrder
|
|
10
|
+
.split('')
|
|
11
|
+
.filter((k) => args[0][k] !== undefined)
|
|
12
|
+
.map((k) => args[0][k]);
|
|
13
|
+
}
|
|
14
|
+
// otherwise we just return the first argument
|
|
15
|
+
// (which we suppose is an array of args)
|
|
16
|
+
return args[0].slice(0);
|
|
17
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
//download.js v3.0, by dandavis; 2008-2014. [CCBY2] see http://danml.com/download.html for tests/usage
|
|
2
|
+
// v1 landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime
|
|
3
|
+
// v2 added named files via a[download], msSaveBlob, IE (10+) support, and window.URL support for larger+faster saves than dataURLs
|
|
4
|
+
// v3 added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support
|
|
5
|
+
|
|
6
|
+
// data can be a string, Blob, File, or dataURL
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function download(data, strFileName, strMimeType) {
|
|
12
|
+
|
|
13
|
+
var self = window, // this script is only for browsers anyway...
|
|
14
|
+
u = "application/octet-stream", // this default mime also triggers iframe downloads
|
|
15
|
+
m = strMimeType || u,
|
|
16
|
+
x = data,
|
|
17
|
+
D = document,
|
|
18
|
+
a = D.createElement("a"),
|
|
19
|
+
z = function(a){return String(a);},
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
B = self.Blob || self.MozBlob || self.WebKitBlob || z,
|
|
23
|
+
BB = self.MSBlobBuilder || self.WebKitBlobBuilder || self.BlobBuilder,
|
|
24
|
+
fn = strFileName || "download",
|
|
25
|
+
blob,
|
|
26
|
+
b,
|
|
27
|
+
ua,
|
|
28
|
+
fr;
|
|
29
|
+
|
|
30
|
+
//if(typeof B.bind === 'function' ){ B=B.bind(self); }
|
|
31
|
+
|
|
32
|
+
if(String(this)==="true"){ //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback
|
|
33
|
+
x=[x, m];
|
|
34
|
+
m=x[0];
|
|
35
|
+
x=x[1];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
//go ahead and download dataURLs right away
|
|
41
|
+
if(String(x).match(/^data\:[\w+\-]+\/[\w+\-]+[,;]/)){
|
|
42
|
+
return navigator.msSaveBlob ? // IE10 can't do a[download], only Blobs:
|
|
43
|
+
navigator.msSaveBlob(d2b(x), fn) :
|
|
44
|
+
saver(x) ; // everyone else can save dataURLs un-processed
|
|
45
|
+
}//end if dataURL passed?
|
|
46
|
+
|
|
47
|
+
try{
|
|
48
|
+
|
|
49
|
+
blob = x instanceof B ?
|
|
50
|
+
x :
|
|
51
|
+
new B([x], {type: m}) ;
|
|
52
|
+
}catch(y){
|
|
53
|
+
if(BB){
|
|
54
|
+
b = new BB();
|
|
55
|
+
b.append([x]);
|
|
56
|
+
blob = b.getBlob(m); // the blob
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
function d2b(u) {
|
|
64
|
+
var p= u.split(/[:;,]/),
|
|
65
|
+
t= p[1],
|
|
66
|
+
dec= p[2] == "base64" ? atob : decodeURIComponent,
|
|
67
|
+
bin= dec(p.pop()),
|
|
68
|
+
mx= bin.length,
|
|
69
|
+
i= 0,
|
|
70
|
+
uia= new Uint8Array(mx);
|
|
71
|
+
|
|
72
|
+
for(i;i<mx;++i) uia[i]= bin.charCodeAt(i);
|
|
73
|
+
|
|
74
|
+
return new B([uia], {type: t});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function saver(url, winMode){
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if ('download' in a) { //html5 A[download]
|
|
81
|
+
a.href = url;
|
|
82
|
+
a.setAttribute("download", fn);
|
|
83
|
+
a.innerHTML = "downloading...";
|
|
84
|
+
a.style.display = 'none';
|
|
85
|
+
D.body.appendChild(a);
|
|
86
|
+
setTimeout(function() {
|
|
87
|
+
a.click();
|
|
88
|
+
D.body.removeChild(a);
|
|
89
|
+
if(winMode===true){setTimeout(function(){ self.URL.revokeObjectURL(a.href);}, 250 );}
|
|
90
|
+
}, 66);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//do iframe dataURL download (old ch+FF):
|
|
95
|
+
var f = D.createElement("iframe");
|
|
96
|
+
D.body.appendChild(f);
|
|
97
|
+
if(!winMode){ // force a mime that will download:
|
|
98
|
+
url="data:"+url.replace(/^data:([\w\/\-\+]+)/, u);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
f.src = url;
|
|
103
|
+
setTimeout(function(){ D.body.removeChild(f); }, 333);
|
|
104
|
+
|
|
105
|
+
}//end saver
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
if (navigator.msSaveBlob) { // IE10+ : (has Blob, but not a[download] or URL)
|
|
109
|
+
return navigator.msSaveBlob(blob, fn);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if(self.URL){ // simple fast and modern way using Blob and URL:
|
|
113
|
+
saver(self.URL.createObjectURL(blob), true);
|
|
114
|
+
}else{
|
|
115
|
+
// handle non-Blob()+non-URL browsers:
|
|
116
|
+
if(typeof blob === "string" || blob.constructor===z ){
|
|
117
|
+
try{
|
|
118
|
+
return saver( "data:" + m + ";base64," + self.btoa(blob) );
|
|
119
|
+
}catch(y){
|
|
120
|
+
return saver( "data:" + m + "," + encodeURIComponent(blob) );
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Blob but not URL:
|
|
125
|
+
fr=new FileReader();
|
|
126
|
+
fr.onload=function(e){
|
|
127
|
+
saver(this.result);
|
|
128
|
+
};
|
|
129
|
+
fr.readAsDataURL(blob);
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
} /* end download() */
|