@chartts/gl 0.1.3 → 0.1.5
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/README.md +55 -0
- package/dist/bar3d.cjs +4 -4
- package/dist/bar3d.d.cts +2 -2
- package/dist/bar3d.d.ts +2 -2
- package/dist/bar3d.js +1 -1
- package/dist/{chunk-M24XMYGG.js → chunk-AGG2KSBO.js} +418 -83
- package/dist/chunk-AGG2KSBO.js.map +1 -0
- package/dist/{chunk-Q4JAQOV3.cjs → chunk-OTQKQDB6.cjs} +419 -82
- package/dist/chunk-OTQKQDB6.cjs.map +1 -0
- package/dist/{factory-Cp9Kr7aa.d.cts → factory-jQSzXhK4.d.cts} +4 -1
- package/dist/{factory-Cp9Kr7aa.d.ts → factory-jQSzXhK4.d.ts} +4 -1
- package/dist/flow-gl.cjs +4 -4
- package/dist/flow-gl.d.cts +2 -2
- package/dist/flow-gl.d.ts +2 -2
- package/dist/flow-gl.js +1 -1
- package/dist/globe3d.cjs +4 -4
- package/dist/globe3d.d.cts +4 -3
- package/dist/globe3d.d.ts +4 -3
- package/dist/globe3d.js +1 -1
- package/dist/graph-gl.cjs +4 -4
- package/dist/graph-gl.d.cts +2 -2
- package/dist/graph-gl.d.ts +2 -2
- package/dist/graph-gl.js +1 -1
- package/dist/index.cjs +60 -52
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/line3d.cjs +4 -4
- package/dist/line3d.d.cts +2 -2
- package/dist/line3d.d.ts +2 -2
- package/dist/line3d.js +1 -1
- package/dist/lines-gl.cjs +4 -4
- package/dist/lines-gl.d.cts +2 -2
- package/dist/lines-gl.d.ts +2 -2
- package/dist/lines-gl.js +1 -1
- package/dist/lines3d.cjs +4 -4
- package/dist/lines3d.d.cts +2 -2
- package/dist/lines3d.d.ts +2 -2
- package/dist/lines3d.js +1 -1
- package/dist/map3d.cjs +4 -4
- package/dist/map3d.d.cts +2 -2
- package/dist/map3d.d.ts +2 -2
- package/dist/map3d.js +1 -1
- package/dist/scatter-gl.cjs +4 -4
- package/dist/scatter-gl.d.cts +2 -2
- package/dist/scatter-gl.d.ts +2 -2
- package/dist/scatter-gl.js +1 -1
- package/dist/scatter3d.cjs +4 -4
- package/dist/scatter3d.d.cts +2 -2
- package/dist/scatter3d.d.ts +2 -2
- package/dist/scatter3d.js +1 -1
- package/dist/surface3d.cjs +4 -4
- package/dist/surface3d.d.cts +2 -2
- package/dist/surface3d.d.ts +2 -2
- package/dist/surface3d.js +1 -1
- package/dist/torus3d-NpDo5Nb5.d.ts +15 -0
- package/dist/torus3d-fgZpxxQZ.d.cts +15 -0
- package/dist/torus3d.cjs +20 -0
- package/dist/torus3d.cjs.map +1 -0
- package/dist/torus3d.d.cts +2 -0
- package/dist/torus3d.d.ts +2 -0
- package/dist/torus3d.js +3 -0
- package/dist/torus3d.js.map +1 -0
- package/package.json +10 -4
- package/dist/chunk-M24XMYGG.js.map +0 -1
- package/dist/chunk-Q4JAQOV3.cjs.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://www.npmjs.com/package/@chartts/gl"><img src="https://img.shields.io/npm/v/@chartts/gl?color=06B6D4&label=npm" alt="npm version" /></a>
|
|
3
|
+
<a href="https://github.com/chartts/chartts/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-06B6D4" alt="MIT License" /></a>
|
|
4
|
+
<a href="https://chartts.com"><img src="https://img.shields.io/badge/docs-chartts.com-06B6D4" alt="Documentation" /></a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
# @chartts/gl
|
|
8
|
+
|
|
9
|
+
WebGL chart types for Chartts. GPU-accelerated 3D and high-performance 2D charts.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @chartts/gl @chartts/core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Chart types
|
|
18
|
+
|
|
19
|
+
| Type | Import |
|
|
20
|
+
|------|--------|
|
|
21
|
+
| 3D Bar | `@chartts/gl/bar3d` |
|
|
22
|
+
| 3D Line | `@chartts/gl/line3d` |
|
|
23
|
+
| 3D Scatter | `@chartts/gl/scatter3d` |
|
|
24
|
+
| 3D Surface | `@chartts/gl/surface3d` |
|
|
25
|
+
| 3D Globe | `@chartts/gl/globe3d` |
|
|
26
|
+
| GL Scatter (2D, 100k+ points) | `@chartts/gl/scatter-gl` |
|
|
27
|
+
| GL Lines (2D, high-perf) | `@chartts/gl/lines-gl` |
|
|
28
|
+
| GL Flow (particle animation) | `@chartts/gl/flow-gl` |
|
|
29
|
+
| GL Graph (force layout) | `@chartts/gl/graph-gl` |
|
|
30
|
+
| 3D Lines | `@chartts/gl/lines3d` |
|
|
31
|
+
| 3D Map | `@chartts/gl/map3d` |
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { createGLChart } from "@chartts/gl"
|
|
37
|
+
import { bar3dChartType } from "@chartts/gl/bar3d"
|
|
38
|
+
|
|
39
|
+
const chart = createGLChart(container, bar3dChartType, data, {
|
|
40
|
+
width: 800,
|
|
41
|
+
height: 600,
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Part of Chartts
|
|
46
|
+
|
|
47
|
+
Beautiful charts. Tiny bundle. Every framework.
|
|
48
|
+
|
|
49
|
+
- [Documentation](https://chartts.com/docs)
|
|
50
|
+
- [GitHub](https://github.com/chartts/chartts)
|
|
51
|
+
- [All packages](https://www.npmjs.com/org/chartts)
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
MIT
|
package/dist/bar3d.cjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkOTQKQDB6_cjs = require('./chunk-OTQKQDB6.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
Object.defineProperty(exports, "Bar3D", {
|
|
8
8
|
enumerable: true,
|
|
9
|
-
get: function () { return
|
|
9
|
+
get: function () { return chunkOTQKQDB6_cjs.Bar3D; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "createBar3DPlugin", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkOTQKQDB6_cjs.createBar3DPlugin; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "createGLChart", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkOTQKQDB6_cjs.createGLChart; }
|
|
18
18
|
});
|
|
19
19
|
//# sourceMappingURL=bar3d.cjs.map
|
|
20
20
|
//# sourceMappingURL=bar3d.cjs.map
|
package/dist/bar3d.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { e as GLChartTypePlugin } from './factory-
|
|
2
|
-
export { B as Bar3D, b as GLChartData, c as GLChartInstance, d as GLChartOptions, f as GLDataPoint, x as createGLChart } from './factory-
|
|
1
|
+
import { e as GLChartTypePlugin } from './factory-jQSzXhK4.cjs';
|
|
2
|
+
export { B as Bar3D, b as GLChartData, c as GLChartInstance, d as GLChartOptions, f as GLDataPoint, x as createGLChart } from './factory-jQSzXhK4.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Bar3D — cuboid mesh per bar, Phong lit.
|
package/dist/bar3d.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { e as GLChartTypePlugin } from './factory-
|
|
2
|
-
export { B as Bar3D, b as GLChartData, c as GLChartInstance, d as GLChartOptions, f as GLDataPoint, x as createGLChart } from './factory-
|
|
1
|
+
import { e as GLChartTypePlugin } from './factory-jQSzXhK4.js';
|
|
2
|
+
export { B as Bar3D, b as GLChartData, c as GLChartInstance, d as GLChartOptions, f as GLDataPoint, x as createGLChart } from './factory-jQSzXhK4.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Bar3D — cuboid mesh per bar, Phong lit.
|
package/dist/bar3d.js
CHANGED
|
@@ -1811,20 +1811,37 @@ function createSurface3DPlugin() {
|
|
|
1811
1811
|
}
|
|
1812
1812
|
|
|
1813
1813
|
// src/charts/globe3d/globe3d-type.ts
|
|
1814
|
+
var GLOBE_RADIUS = 3;
|
|
1815
|
+
var SEGMENTS = 128;
|
|
1816
|
+
var RINGS = 64;
|
|
1814
1817
|
function latLngToXYZ(lat, lng, radius) {
|
|
1815
1818
|
const phi = (90 - lat) * Math.PI / 180;
|
|
1816
1819
|
const theta = (lng + 180) * Math.PI / 180;
|
|
1817
|
-
return [
|
|
1820
|
+
return [
|
|
1821
|
+
-radius * Math.sin(phi) * Math.cos(theta),
|
|
1822
|
+
radius * Math.cos(phi),
|
|
1823
|
+
radius * Math.sin(phi) * Math.sin(theta)
|
|
1824
|
+
];
|
|
1825
|
+
}
|
|
1826
|
+
function angularDistance(lat1, lng1, lat2, lng2) {
|
|
1827
|
+
const p1 = lat1 * Math.PI / 180, p2 = lat2 * Math.PI / 180;
|
|
1828
|
+
const dl = (lng2 - lng1) * Math.PI / 180;
|
|
1829
|
+
return Math.acos(
|
|
1830
|
+
Math.min(1, Math.max(
|
|
1831
|
+
-1,
|
|
1832
|
+
Math.sin(p1) * Math.sin(p2) + Math.cos(p1) * Math.cos(p2) * Math.cos(dl)
|
|
1833
|
+
))
|
|
1834
|
+
);
|
|
1818
1835
|
}
|
|
1819
1836
|
function createGlobe3DPlugin() {
|
|
1820
1837
|
let sphereVBO = null;
|
|
1821
1838
|
let sphereIBO = null;
|
|
1822
1839
|
let sphereIndexCount = 0;
|
|
1823
|
-
let pointVBO = null;
|
|
1824
|
-
let pointCount = 0;
|
|
1825
1840
|
const modelMatrix = mat4();
|
|
1841
|
+
let locationColors = /* @__PURE__ */ new Map();
|
|
1826
1842
|
const normalMatrix = new Float32Array(9);
|
|
1827
|
-
let
|
|
1843
|
+
let screenPoints = [];
|
|
1844
|
+
let seriesInfo = [];
|
|
1828
1845
|
return {
|
|
1829
1846
|
type: "globe3d",
|
|
1830
1847
|
prepare(ctx) {
|
|
@@ -1838,108 +1855,199 @@ function createGlobe3DPlugin() {
|
|
|
1838
1855
|
[...MESH_VERT_UNIFORMS, ...MESH_FRAG_UNIFORMS],
|
|
1839
1856
|
MESH_VERT_ATTRIBUTES
|
|
1840
1857
|
);
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
POINT_FRAG,
|
|
1845
|
-
[...POINT_VERT_UNIFORMS, ...POINT_FRAG_UNIFORMS],
|
|
1846
|
-
POINT_VERT_ATTRIBUTES
|
|
1847
|
-
);
|
|
1848
|
-
const globeRadius = 3;
|
|
1849
|
-
const segments = 64, rings = 32;
|
|
1850
|
-
const sphereColor = [0.12, 0.22, 0.48];
|
|
1851
|
-
const sv = [], si = [];
|
|
1852
|
-
for (let ring = 0; ring <= rings; ring++) {
|
|
1853
|
-
const phi = ring / rings * Math.PI;
|
|
1854
|
-
for (let seg = 0; seg <= segments; seg++) {
|
|
1855
|
-
const theta = seg / segments * Math.PI * 2;
|
|
1856
|
-
const nx = Math.sin(phi) * Math.cos(theta), ny = Math.cos(phi), nz = Math.sin(phi) * Math.sin(theta);
|
|
1857
|
-
sv.push(nx * globeRadius, ny * globeRadius, nz * globeRadius, nx, ny, nz, ...sphereColor);
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
for (let ring = 0; ring < rings; ring++) for (let seg = 0; seg < segments; seg++) {
|
|
1861
|
-
const a = ring * (segments + 1) + seg, b = a + segments + 1;
|
|
1862
|
-
si.push(a, b, a + 1, a + 1, b, b + 1);
|
|
1863
|
-
}
|
|
1864
|
-
if (sphereVBO) sphereVBO.update(new Float32Array(sv));
|
|
1865
|
-
else sphereVBO = createVertexBuffer(gl, new Float32Array(sv), gl.STATIC_DRAW);
|
|
1866
|
-
if (sphereIBO) sphereIBO.update(new Uint16Array(si));
|
|
1867
|
-
else sphereIBO = createIndexBuffer(gl, new Uint16Array(si), gl.STATIC_DRAW);
|
|
1868
|
-
sphereIndexCount = si.length;
|
|
1869
|
-
globePoints = [];
|
|
1870
|
-
const pv = [];
|
|
1858
|
+
const locationMap = /* @__PURE__ */ new Map();
|
|
1859
|
+
seriesInfo = [];
|
|
1860
|
+
screenPoints = [];
|
|
1871
1861
|
for (let sIdx = 0; sIdx < series.length; sIdx++) {
|
|
1872
1862
|
const s = series[sIdx];
|
|
1873
|
-
const
|
|
1863
|
+
const colorHex = s.color ?? theme.colors[sIdx % theme.colors.length];
|
|
1864
|
+
seriesInfo.push({ name: s.name, color: colorHex });
|
|
1874
1865
|
for (let di = 0; di < s.values.length; di++) {
|
|
1875
1866
|
const lat = s.y?.[di] ?? 0, lng = s.x?.[di] ?? 0, value = s.values[di];
|
|
1876
|
-
const
|
|
1877
|
-
|
|
1878
|
-
|
|
1867
|
+
const label = data.categories?.[di] ?? "";
|
|
1868
|
+
const key = `${lat.toFixed(1)}_${lng.toFixed(1)}`;
|
|
1869
|
+
let loc = locationMap.get(key);
|
|
1870
|
+
if (!loc) {
|
|
1871
|
+
loc = { lat, lng, totalValue: 0, label, entries: [] };
|
|
1872
|
+
locationMap.set(key, loc);
|
|
1873
|
+
}
|
|
1874
|
+
loc.totalValue += Math.abs(value);
|
|
1875
|
+
loc.entries.push({ si: sIdx, di, value });
|
|
1876
|
+
const [wx, wy, wz] = latLngToXYZ(lat, lng, GLOBE_RADIUS);
|
|
1877
|
+
screenPoints.push({ si: sIdx, di, lat, lng, wx, wy, wz, value, name: s.name, label });
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
const patches = [];
|
|
1881
|
+
locationColors = /* @__PURE__ */ new Map();
|
|
1882
|
+
let maxVal = 0;
|
|
1883
|
+
for (const loc of locationMap.values()) if (loc.totalValue > maxVal) maxVal = loc.totalValue;
|
|
1884
|
+
if (maxVal === 0) maxVal = 1;
|
|
1885
|
+
let locIdx = 0;
|
|
1886
|
+
for (const loc of locationMap.values()) {
|
|
1887
|
+
const colorHex = theme.colors[locIdx % theme.colors.length];
|
|
1888
|
+
locationColors.set(loc.label, colorHex);
|
|
1889
|
+
const color = hexToRGB(colorHex);
|
|
1890
|
+
const normValue = loc.totalValue / maxVal;
|
|
1891
|
+
patches.push({ lat: loc.lat, lng: loc.lng, value: loc.totalValue, normValue, color, si: 0, di: locIdx, name: loc.label, label: loc.label });
|
|
1892
|
+
locIdx++;
|
|
1893
|
+
}
|
|
1894
|
+
const baseColor = [0.03, 0.05, 0.12];
|
|
1895
|
+
const patchRadius = 0.8;
|
|
1896
|
+
const gratLatStep = 30, gratLngStep = 30;
|
|
1897
|
+
const gratWidth = 0.015;
|
|
1898
|
+
const gratColor = [0.08, 0.12, 0.22];
|
|
1899
|
+
const verts = [];
|
|
1900
|
+
const indices = [];
|
|
1901
|
+
for (let ring = 0; ring <= RINGS; ring++) {
|
|
1902
|
+
const phi = ring / RINGS * Math.PI;
|
|
1903
|
+
const lat = 90 - ring / RINGS * 180;
|
|
1904
|
+
for (let seg = 0; seg <= SEGMENTS; seg++) {
|
|
1905
|
+
const theta = seg / SEGMENTS * Math.PI * 2;
|
|
1906
|
+
const lng = seg / SEGMENTS * 360 - 180;
|
|
1907
|
+
const nx = Math.sin(phi) * Math.cos(theta);
|
|
1908
|
+
const ny = Math.cos(phi);
|
|
1909
|
+
const nz = Math.sin(phi) * Math.sin(theta);
|
|
1910
|
+
let r = baseColor[0], g = baseColor[1], b = baseColor[2];
|
|
1911
|
+
const latMod = (lat % gratLatStep + gratLatStep) % gratLatStep;
|
|
1912
|
+
const latDist = Math.min(latMod, gratLatStep - latMod) * Math.PI / 180;
|
|
1913
|
+
const lngMod = (lng % gratLngStep + gratLngStep) % gratLngStep;
|
|
1914
|
+
const lngDist = Math.min(lngMod, gratLngStep - lngMod) * Math.PI / 180;
|
|
1915
|
+
const gratDist = Math.min(latDist, lngDist);
|
|
1916
|
+
if (gratDist < gratWidth) {
|
|
1917
|
+
const gratT = 1 - gratDist / gratWidth;
|
|
1918
|
+
r = r + (gratColor[0] - r) * gratT;
|
|
1919
|
+
g = g + (gratColor[1] - g) * gratT;
|
|
1920
|
+
b = b + (gratColor[2] - b) * gratT;
|
|
1921
|
+
}
|
|
1922
|
+
let ar = 0, ag = 0, ab = 0;
|
|
1923
|
+
for (const patch of patches) {
|
|
1924
|
+
const dist = angularDistance(lat, lng, patch.lat, patch.lng);
|
|
1925
|
+
if (dist < patchRadius) {
|
|
1926
|
+
const t = 1 - dist / patchRadius;
|
|
1927
|
+
const influence = t * (0.4 + t * 0.6) * patch.normValue;
|
|
1928
|
+
ar += patch.color[0] * influence;
|
|
1929
|
+
ag += patch.color[1] * influence;
|
|
1930
|
+
ab += patch.color[2] * influence;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
if (ar > 0.01 || ag > 0.01 || ab > 0.01) {
|
|
1934
|
+
r = Math.min(1, r + ar);
|
|
1935
|
+
g = Math.min(1, g + ag);
|
|
1936
|
+
b = Math.min(1, b + ab);
|
|
1937
|
+
}
|
|
1938
|
+
verts.push(
|
|
1939
|
+
nx * GLOBE_RADIUS,
|
|
1940
|
+
ny * GLOBE_RADIUS,
|
|
1941
|
+
nz * GLOBE_RADIUS,
|
|
1942
|
+
nx,
|
|
1943
|
+
ny,
|
|
1944
|
+
nz,
|
|
1945
|
+
r,
|
|
1946
|
+
g,
|
|
1947
|
+
b
|
|
1948
|
+
);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
for (let ring = 0; ring < RINGS; ring++) {
|
|
1952
|
+
for (let seg = 0; seg < SEGMENTS; seg++) {
|
|
1953
|
+
const a = ring * (SEGMENTS + 1) + seg;
|
|
1954
|
+
const b = a + SEGMENTS + 1;
|
|
1955
|
+
indices.push(a, a + 1, b, a + 1, b + 1, b);
|
|
1879
1956
|
}
|
|
1880
1957
|
}
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1958
|
+
const vertArr = new Float32Array(verts);
|
|
1959
|
+
const idxArr = new Uint16Array(indices);
|
|
1960
|
+
if (sphereVBO) sphereVBO.update(vertArr);
|
|
1961
|
+
else sphereVBO = createVertexBuffer(gl, vertArr, gl.DYNAMIC_DRAW);
|
|
1962
|
+
if (sphereIBO) sphereIBO.update(idxArr);
|
|
1963
|
+
else sphereIBO = createIndexBuffer(gl, idxArr, gl.DYNAMIC_DRAW);
|
|
1964
|
+
sphereIndexCount = indices.length;
|
|
1884
1965
|
mat4Identity(modelMatrix);
|
|
1885
1966
|
},
|
|
1886
1967
|
render(ctx) {
|
|
1887
1968
|
const { renderer, camera } = ctx;
|
|
1888
1969
|
const gl = renderer.gl;
|
|
1889
1970
|
const progress = ctx.animationProgress;
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1971
|
+
const prog = renderer.getProgram("mesh");
|
|
1972
|
+
prog.use();
|
|
1973
|
+
prog.setMat4("u_projView", camera.projViewMatrix);
|
|
1974
|
+
prog.setMat4("u_model", modelMatrix);
|
|
1894
1975
|
mat3NormalFromMat4(normalMatrix, modelMatrix);
|
|
1895
|
-
|
|
1896
|
-
setLightUniforms(
|
|
1897
|
-
|
|
1976
|
+
prog.setMat3("u_normalMatrix", normalMatrix);
|
|
1977
|
+
setLightUniforms(prog, defaultLightConfig(), camera.position);
|
|
1978
|
+
prog.setFloat("u_opacity", progress);
|
|
1898
1979
|
if (sphereVBO && sphereIBO) {
|
|
1980
|
+
gl.disable(gl.CULL_FACE);
|
|
1899
1981
|
sphereVBO.bind();
|
|
1900
|
-
const
|
|
1901
|
-
{ location:
|
|
1902
|
-
{ location:
|
|
1903
|
-
{ location:
|
|
1982
|
+
const layout = createVertexLayout([
|
|
1983
|
+
{ location: prog.attributes["a_position"], size: 3 },
|
|
1984
|
+
{ location: prog.attributes["a_normal"], size: 3 },
|
|
1985
|
+
{ location: prog.attributes["a_color"], size: 3 }
|
|
1904
1986
|
]);
|
|
1905
|
-
applyVertexLayout(gl,
|
|
1987
|
+
applyVertexLayout(gl, layout);
|
|
1906
1988
|
sphereIBO.bind();
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
if (pointProg && pointVBO && pointCount > 0) {
|
|
1912
|
-
pointProg.use();
|
|
1913
|
-
pointProg.setMat4("u_projView", camera.projViewMatrix);
|
|
1914
|
-
pointProg.setMat4("u_model", modelMatrix);
|
|
1915
|
-
pointProg.setFloat("u_pixelRatio", renderer.pixelRatio);
|
|
1916
|
-
pointProg.setFloat("u_sizeAttenuation", 30);
|
|
1917
|
-
pointProg.setFloat("u_opacity", progress);
|
|
1918
|
-
pointVBO.bind();
|
|
1919
|
-
const pl = createVertexLayout([
|
|
1920
|
-
{ location: pointProg.attributes["a_position"], size: 3 },
|
|
1921
|
-
{ location: pointProg.attributes["a_color"], size: 3 },
|
|
1922
|
-
{ location: pointProg.attributes["a_size"], size: 1 }
|
|
1923
|
-
]);
|
|
1924
|
-
applyVertexLayout(gl, pl);
|
|
1925
|
-
gl.drawArrays(gl.POINTS, 0, pointCount);
|
|
1926
|
-
disableVertexLayout(gl, pl);
|
|
1989
|
+
const indexType = gl.UNSIGNED_SHORT;
|
|
1990
|
+
gl.drawElements(gl.TRIANGLES, sphereIndexCount, indexType, 0);
|
|
1991
|
+
disableVertexLayout(gl, layout);
|
|
1992
|
+
gl.enable(gl.CULL_FACE);
|
|
1927
1993
|
}
|
|
1928
1994
|
},
|
|
1995
|
+
renderOverlay(ctx, ctx2d) {
|
|
1996
|
+
const { camera, width, height, theme, animationProgress } = ctx;
|
|
1997
|
+
if (animationProgress < 0.5) return;
|
|
1998
|
+
ctx2d.save();
|
|
1999
|
+
const seenLabels = /* @__PURE__ */ new Set();
|
|
2000
|
+
ctx2d.font = `${theme.fontSize - 1}px ${theme.fontFamily}`;
|
|
2001
|
+
ctx2d.textBaseline = "middle";
|
|
2002
|
+
for (const sp of screenPoints) {
|
|
2003
|
+
if (!sp.label || seenLabels.has(sp.label)) continue;
|
|
2004
|
+
const screen = projectToScreen(
|
|
2005
|
+
new Float32Array([sp.wx, sp.wy, sp.wz]),
|
|
2006
|
+
camera.projViewMatrix,
|
|
2007
|
+
width,
|
|
2008
|
+
height
|
|
2009
|
+
);
|
|
2010
|
+
if (!screen || screen.z < -1 || screen.z > 1 || screen.z > 0.97) continue;
|
|
2011
|
+
seenLabels.add(sp.label);
|
|
2012
|
+
const locColor = locationColors.get(sp.label) ?? theme.textColor;
|
|
2013
|
+
ctx2d.fillStyle = locColor;
|
|
2014
|
+
ctx2d.globalAlpha = 0.9;
|
|
2015
|
+
ctx2d.beginPath();
|
|
2016
|
+
ctx2d.arc(screen.x, screen.y, 3, 0, Math.PI * 2);
|
|
2017
|
+
ctx2d.fill();
|
|
2018
|
+
ctx2d.fillStyle = theme.textColor;
|
|
2019
|
+
ctx2d.globalAlpha = 0.85;
|
|
2020
|
+
ctx2d.textAlign = "left";
|
|
2021
|
+
ctx2d.fillText(sp.label, screen.x + 8, screen.y);
|
|
2022
|
+
}
|
|
2023
|
+
ctx2d.restore();
|
|
2024
|
+
},
|
|
1929
2025
|
needsLoop() {
|
|
1930
2026
|
return false;
|
|
1931
2027
|
},
|
|
1932
2028
|
hitTest(ctx, x, y) {
|
|
1933
2029
|
const { camera, width, height } = ctx;
|
|
1934
2030
|
let closest = null;
|
|
1935
|
-
let closestDist =
|
|
1936
|
-
for (const
|
|
1937
|
-
const screen = projectToScreen(
|
|
2031
|
+
let closestDist = 25;
|
|
2032
|
+
for (const sp of screenPoints) {
|
|
2033
|
+
const screen = projectToScreen(
|
|
2034
|
+
new Float32Array([sp.wx, sp.wy, sp.wz]),
|
|
2035
|
+
camera.projViewMatrix,
|
|
2036
|
+
width,
|
|
2037
|
+
height
|
|
2038
|
+
);
|
|
1938
2039
|
if (!screen || screen.z < -1 || screen.z > 1) continue;
|
|
1939
2040
|
const dist = Math.sqrt((screen.x - x) ** 2 + (screen.y - y) ** 2);
|
|
1940
2041
|
if (dist < closestDist) {
|
|
1941
2042
|
closestDist = dist;
|
|
1942
|
-
closest = {
|
|
2043
|
+
closest = {
|
|
2044
|
+
seriesIndex: sp.si,
|
|
2045
|
+
dataIndex: sp.di,
|
|
2046
|
+
value: sp.value,
|
|
2047
|
+
x: sp.lng,
|
|
2048
|
+
y: sp.lat,
|
|
2049
|
+
seriesName: sp.label || sp.name
|
|
2050
|
+
};
|
|
1943
2051
|
}
|
|
1944
2052
|
}
|
|
1945
2053
|
return closest;
|
|
@@ -1949,9 +2057,7 @@ function createGlobe3DPlugin() {
|
|
|
1949
2057
|
sphereVBO = null;
|
|
1950
2058
|
sphereIBO?.destroy();
|
|
1951
2059
|
sphereIBO = null;
|
|
1952
|
-
|
|
1953
|
-
pointVBO = null;
|
|
1954
|
-
globePoints = [];
|
|
2060
|
+
screenPoints = [];
|
|
1955
2061
|
}
|
|
1956
2062
|
};
|
|
1957
2063
|
}
|
|
@@ -3382,6 +3488,230 @@ function createGraphGLPlugin() {
|
|
|
3382
3488
|
};
|
|
3383
3489
|
}
|
|
3384
3490
|
|
|
3491
|
+
// src/charts/torus3d/torus3d-type.ts
|
|
3492
|
+
var RADIAL_SEGMENTS = 64;
|
|
3493
|
+
var HEIGHT_STEPS = 200;
|
|
3494
|
+
var TOTAL_HEIGHT = 6;
|
|
3495
|
+
var MIN_RADIUS = 0.6;
|
|
3496
|
+
var MAX_RADIUS = 2;
|
|
3497
|
+
function createTorus3DPlugin() {
|
|
3498
|
+
let vbo = null;
|
|
3499
|
+
let ibo = null;
|
|
3500
|
+
let indexCount = 0;
|
|
3501
|
+
let use32bit = false;
|
|
3502
|
+
const modelMatrix = mat4();
|
|
3503
|
+
const normalMatrix = new Float32Array(9);
|
|
3504
|
+
let labelPoints = [];
|
|
3505
|
+
return {
|
|
3506
|
+
type: "torus3d",
|
|
3507
|
+
prepare(ctx) {
|
|
3508
|
+
const { renderer, data, options, theme } = ctx;
|
|
3509
|
+
const gl = renderer.gl;
|
|
3510
|
+
const series = data.series;
|
|
3511
|
+
renderer.registerProgram(
|
|
3512
|
+
"mesh",
|
|
3513
|
+
MESH_VERT,
|
|
3514
|
+
MESH_FRAG,
|
|
3515
|
+
[...MESH_VERT_UNIFORMS, ...MESH_FRAG_UNIFORMS],
|
|
3516
|
+
MESH_VERT_ATTRIBUTES
|
|
3517
|
+
);
|
|
3518
|
+
const s = series[0];
|
|
3519
|
+
if (!s || s.values.length === 0) return;
|
|
3520
|
+
const opts = options;
|
|
3521
|
+
const intensity = opts.intensity ?? 1;
|
|
3522
|
+
const numRings = s.values.length;
|
|
3523
|
+
let maxVal = 0;
|
|
3524
|
+
for (const v of s.values) if (Math.abs(v) > maxVal) maxVal = Math.abs(v);
|
|
3525
|
+
if (maxVal === 0) maxVal = 1;
|
|
3526
|
+
const ringRadii = [];
|
|
3527
|
+
for (let i = 0; i < numRings; i++) {
|
|
3528
|
+
const norm = Math.abs(s.values[i]) / maxVal;
|
|
3529
|
+
ringRadii.push((MIN_RADIUS + norm * (MAX_RADIUS - MIN_RADIUS)) * intensity);
|
|
3530
|
+
}
|
|
3531
|
+
const ringColors = [];
|
|
3532
|
+
const ringHexColors = [];
|
|
3533
|
+
for (let i = 0; i < numRings; i++) {
|
|
3534
|
+
const hex = theme.colors[i % theme.colors.length];
|
|
3535
|
+
ringHexColors.push(hex);
|
|
3536
|
+
ringColors.push(hexToRGB(hex));
|
|
3537
|
+
}
|
|
3538
|
+
function catmullRom(p0, p1, p2, p3, t) {
|
|
3539
|
+
return 0.5 * (2 * p1 + (-p0 + p2) * t + (2 * p0 - 5 * p1 + 4 * p2 - p3) * t * t + (-p0 + 3 * p1 - 3 * p2 + p3) * t * t * t);
|
|
3540
|
+
}
|
|
3541
|
+
function radiusAt(t) {
|
|
3542
|
+
const f = t * (numRings - 1);
|
|
3543
|
+
const i = Math.max(0, Math.min(Math.floor(f), numRings - 2));
|
|
3544
|
+
const frac = f - i;
|
|
3545
|
+
const p0 = ringRadii[Math.max(0, i - 1)];
|
|
3546
|
+
const p1 = ringRadii[i];
|
|
3547
|
+
const p2 = ringRadii[Math.min(numRings - 1, i + 1)];
|
|
3548
|
+
const p3 = ringRadii[Math.min(numRings - 1, i + 2)];
|
|
3549
|
+
return Math.max(MIN_RADIUS * 0.5, catmullRom(p0, p1, p2, p3, frac));
|
|
3550
|
+
}
|
|
3551
|
+
function colorAt(t) {
|
|
3552
|
+
const f = t * (numRings - 1);
|
|
3553
|
+
const i = Math.max(0, Math.min(Math.floor(f), numRings - 2));
|
|
3554
|
+
const frac = f - i;
|
|
3555
|
+
const c0 = ringColors[Math.max(0, i - 1)];
|
|
3556
|
+
const c1 = ringColors[i];
|
|
3557
|
+
const c2 = ringColors[Math.min(numRings - 1, i + 1)];
|
|
3558
|
+
const c3 = ringColors[Math.min(numRings - 1, i + 2)];
|
|
3559
|
+
return [
|
|
3560
|
+
Math.max(0, Math.min(1, catmullRom(c0[0], c1[0], c2[0], c3[0], frac))),
|
|
3561
|
+
Math.max(0, Math.min(1, catmullRom(c0[1], c1[1], c2[1], c3[1], frac))),
|
|
3562
|
+
Math.max(0, Math.min(1, catmullRom(c0[2], c1[2], c2[2], c3[2], frac)))
|
|
3563
|
+
];
|
|
3564
|
+
}
|
|
3565
|
+
const verts = [];
|
|
3566
|
+
const indices = [];
|
|
3567
|
+
labelPoints = [];
|
|
3568
|
+
for (let h = 0; h <= HEIGHT_STEPS; h++) {
|
|
3569
|
+
const t = h / HEIGHT_STEPS;
|
|
3570
|
+
const y = (t - 0.5) * TOTAL_HEIGHT;
|
|
3571
|
+
const radius = radiusAt(t);
|
|
3572
|
+
const color = colorAt(t);
|
|
3573
|
+
const eps = 2e-3;
|
|
3574
|
+
const rPrev = radiusAt(Math.max(0, t - eps));
|
|
3575
|
+
const rNext = radiusAt(Math.min(1, t + eps));
|
|
3576
|
+
const drdy = (rNext - rPrev) / (2 * eps * TOTAL_HEIGHT);
|
|
3577
|
+
for (let seg = 0; seg <= RADIAL_SEGMENTS; seg++) {
|
|
3578
|
+
const theta = seg / RADIAL_SEGMENTS * Math.PI * 2;
|
|
3579
|
+
const cosT = Math.cos(theta);
|
|
3580
|
+
const sinT = Math.sin(theta);
|
|
3581
|
+
const nx = cosT;
|
|
3582
|
+
const ny = -drdy;
|
|
3583
|
+
const nz = sinT;
|
|
3584
|
+
const nlen = Math.sqrt(nx * nx + ny * ny + nz * nz) || 1;
|
|
3585
|
+
verts.push(
|
|
3586
|
+
radius * cosT,
|
|
3587
|
+
y,
|
|
3588
|
+
radius * sinT,
|
|
3589
|
+
nx / nlen,
|
|
3590
|
+
ny / nlen,
|
|
3591
|
+
nz / nlen,
|
|
3592
|
+
color[0],
|
|
3593
|
+
color[1],
|
|
3594
|
+
color[2]
|
|
3595
|
+
);
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3598
|
+
for (let i = 0; i < numRings; i++) {
|
|
3599
|
+
const t = (i + 0.5) / numRings;
|
|
3600
|
+
const y = (t - 0.5) * TOTAL_HEIGHT;
|
|
3601
|
+
const r = ringRadii[i];
|
|
3602
|
+
labelPoints.push({
|
|
3603
|
+
si: 0,
|
|
3604
|
+
di: i,
|
|
3605
|
+
wx: r + 0.4,
|
|
3606
|
+
wy: y,
|
|
3607
|
+
wz: 0,
|
|
3608
|
+
value: s.values[i],
|
|
3609
|
+
label: data.categories?.[i] ?? `${i + 1}`,
|
|
3610
|
+
color: ringHexColors[i]
|
|
3611
|
+
});
|
|
3612
|
+
}
|
|
3613
|
+
for (let h = 0; h < HEIGHT_STEPS; h++) {
|
|
3614
|
+
for (let seg = 0; seg < RADIAL_SEGMENTS; seg++) {
|
|
3615
|
+
const a = h * (RADIAL_SEGMENTS + 1) + seg;
|
|
3616
|
+
const b = a + RADIAL_SEGMENTS + 1;
|
|
3617
|
+
indices.push(a, a + 1, b, a + 1, b + 1, b);
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
const capStart = verts.length / 9;
|
|
3621
|
+
const bottomColor = colorAt(0);
|
|
3622
|
+
verts.push(0, -0.5 * TOTAL_HEIGHT, 0, 0, -1, 0, bottomColor[0], bottomColor[1], bottomColor[2]);
|
|
3623
|
+
const topColor = colorAt(1);
|
|
3624
|
+
verts.push(0, 0.5 * TOTAL_HEIGHT, 0, 0, 1, 0, topColor[0], topColor[1], topColor[2]);
|
|
3625
|
+
for (let seg = 0; seg < RADIAL_SEGMENTS; seg++) {
|
|
3626
|
+
indices.push(capStart, seg + 1, seg);
|
|
3627
|
+
const topRow = HEIGHT_STEPS * (RADIAL_SEGMENTS + 1);
|
|
3628
|
+
indices.push(capStart + 1, topRow + seg, topRow + seg + 1);
|
|
3629
|
+
}
|
|
3630
|
+
const vertArr = new Float32Array(verts);
|
|
3631
|
+
use32bit = verts.length / 9 > 65535;
|
|
3632
|
+
const idxArr = use32bit ? new Uint32Array(indices) : new Uint16Array(indices);
|
|
3633
|
+
if (vbo) vbo.update(vertArr);
|
|
3634
|
+
else vbo = createVertexBuffer(gl, vertArr, gl.DYNAMIC_DRAW);
|
|
3635
|
+
if (ibo) ibo.update(idxArr);
|
|
3636
|
+
else ibo = createIndexBuffer(gl, idxArr, gl.DYNAMIC_DRAW);
|
|
3637
|
+
indexCount = indices.length;
|
|
3638
|
+
mat4Identity(modelMatrix);
|
|
3639
|
+
},
|
|
3640
|
+
render(ctx) {
|
|
3641
|
+
const { renderer, camera } = ctx;
|
|
3642
|
+
const gl = renderer.gl;
|
|
3643
|
+
const prog = renderer.getProgram("mesh");
|
|
3644
|
+
prog.use();
|
|
3645
|
+
prog.setMat4("u_projView", camera.projViewMatrix);
|
|
3646
|
+
prog.setMat4("u_model", modelMatrix);
|
|
3647
|
+
mat3NormalFromMat4(normalMatrix, modelMatrix);
|
|
3648
|
+
prog.setMat3("u_normalMatrix", normalMatrix);
|
|
3649
|
+
setLightUniforms(prog, defaultLightConfig(), camera.position);
|
|
3650
|
+
prog.setFloat("u_opacity", ctx.animationProgress);
|
|
3651
|
+
if (vbo && ibo) {
|
|
3652
|
+
gl.disable(gl.CULL_FACE);
|
|
3653
|
+
vbo.bind();
|
|
3654
|
+
const layout = createVertexLayout([
|
|
3655
|
+
{ location: prog.attributes["a_position"], size: 3 },
|
|
3656
|
+
{ location: prog.attributes["a_normal"], size: 3 },
|
|
3657
|
+
{ location: prog.attributes["a_color"], size: 3 }
|
|
3658
|
+
]);
|
|
3659
|
+
applyVertexLayout(gl, layout);
|
|
3660
|
+
ibo.bind();
|
|
3661
|
+
gl.drawElements(gl.TRIANGLES, indexCount, use32bit ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT, 0);
|
|
3662
|
+
disableVertexLayout(gl, layout);
|
|
3663
|
+
gl.enable(gl.CULL_FACE);
|
|
3664
|
+
}
|
|
3665
|
+
},
|
|
3666
|
+
renderOverlay(ctx, ctx2d) {
|
|
3667
|
+
const { camera, width, height, theme, animationProgress } = ctx;
|
|
3668
|
+
if (animationProgress < 0.3) return;
|
|
3669
|
+
ctx2d.save();
|
|
3670
|
+
ctx2d.font = `bold ${theme.fontSize}px ${theme.fontFamily}`;
|
|
3671
|
+
ctx2d.textBaseline = "middle";
|
|
3672
|
+
for (const lp of labelPoints) {
|
|
3673
|
+
const screen = projectToScreen(new Float32Array([lp.wx, lp.wy, lp.wz]), camera.projViewMatrix, width, height);
|
|
3674
|
+
if (!screen || screen.z < -1 || screen.z > 1) continue;
|
|
3675
|
+
ctx2d.fillStyle = lp.color;
|
|
3676
|
+
ctx2d.globalAlpha = 0.9;
|
|
3677
|
+
ctx2d.beginPath();
|
|
3678
|
+
ctx2d.arc(screen.x, screen.y, 4, 0, Math.PI * 2);
|
|
3679
|
+
ctx2d.fill();
|
|
3680
|
+
ctx2d.fillStyle = theme.textColor;
|
|
3681
|
+
ctx2d.globalAlpha = 0.85;
|
|
3682
|
+
ctx2d.textAlign = "left";
|
|
3683
|
+
ctx2d.fillText(`${lp.label}: ${lp.value}`, screen.x + 10, screen.y);
|
|
3684
|
+
}
|
|
3685
|
+
ctx2d.restore();
|
|
3686
|
+
},
|
|
3687
|
+
needsLoop() {
|
|
3688
|
+
return false;
|
|
3689
|
+
},
|
|
3690
|
+
hitTest(ctx, x, y) {
|
|
3691
|
+
const { camera, width, height } = ctx;
|
|
3692
|
+
let closest = null;
|
|
3693
|
+
let closestDist = 30;
|
|
3694
|
+
for (const lp of labelPoints) {
|
|
3695
|
+
const screen = projectToScreen(new Float32Array([lp.wx, lp.wy, lp.wz]), camera.projViewMatrix, width, height);
|
|
3696
|
+
if (!screen || screen.z < -1 || screen.z > 1) continue;
|
|
3697
|
+
const dist = Math.sqrt((screen.x - x) ** 2 + (screen.y - y) ** 2);
|
|
3698
|
+
if (dist < closestDist) {
|
|
3699
|
+
closestDist = dist;
|
|
3700
|
+
closest = { seriesIndex: lp.si, dataIndex: lp.di, value: lp.value, x: screen.x, y: screen.y, seriesName: lp.label };
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
return closest;
|
|
3704
|
+
},
|
|
3705
|
+
dispose() {
|
|
3706
|
+
vbo?.destroy();
|
|
3707
|
+
vbo = null;
|
|
3708
|
+
ibo?.destroy();
|
|
3709
|
+
ibo = null;
|
|
3710
|
+
labelPoints = [];
|
|
3711
|
+
}
|
|
3712
|
+
};
|
|
3713
|
+
}
|
|
3714
|
+
|
|
3385
3715
|
// src/api/factory.ts
|
|
3386
3716
|
function Scatter3D(container, opts) {
|
|
3387
3717
|
const { data, ...options } = opts;
|
|
@@ -3458,7 +3788,12 @@ function GraphGL(container, opts) {
|
|
|
3458
3788
|
const { data, ...options } = opts;
|
|
3459
3789
|
return createGLChart(container, createGraphGLPlugin(), data, options);
|
|
3460
3790
|
}
|
|
3791
|
+
function Torus3D(container, opts) {
|
|
3792
|
+
const { data, ...options } = opts;
|
|
3793
|
+
if (!options.camera) options.camera = { position: [4, 2, 6], target: [0, 0, 0] };
|
|
3794
|
+
return createGLChart(container, createTorus3DPlugin(), data, options);
|
|
3795
|
+
}
|
|
3461
3796
|
|
|
3462
|
-
export { Bar3D, DEFAULT_GL_THEME, FlowGL, Globe3D, GraphGL, LIGHT_GL_THEME, Line3D, Lines3D, LinesGL, Map3D, Scatter3D, ScatterGL, Surface3D, applyVertexLayout, compileShader, createBar3DPlugin, createCamera, createFlowGLPlugin, createGLChart, createGLRenderer, createGlobe3DPlugin, createGraphGLPlugin, createGrid3D, createIndexBuffer, createLine3DPlugin, createLines3DPlugin, createLinesGLPlugin, createMap3DPlugin, createOrbitControls, createPickingSystem, createScatter3DPlugin, createScatterGLPlugin, createShaderProgram, createSurface3DPlugin, createVertexBuffer, createVertexLayout, defaultLightConfig, hexToRGB, mat4, mat4Identity, mat4Invert, mat4LookAt, mat4Multiply, mat4Perspective, projectToScreen, resolveTheme, setLightUniforms, toRad, updateCamera, updateOrbitControls, vec3 };
|
|
3463
|
-
//# sourceMappingURL=chunk-
|
|
3464
|
-
//# sourceMappingURL=chunk-
|
|
3797
|
+
export { Bar3D, DEFAULT_GL_THEME, FlowGL, Globe3D, GraphGL, LIGHT_GL_THEME, Line3D, Lines3D, LinesGL, Map3D, Scatter3D, ScatterGL, Surface3D, Torus3D, applyVertexLayout, compileShader, createBar3DPlugin, createCamera, createFlowGLPlugin, createGLChart, createGLRenderer, createGlobe3DPlugin, createGraphGLPlugin, createGrid3D, createIndexBuffer, createLine3DPlugin, createLines3DPlugin, createLinesGLPlugin, createMap3DPlugin, createOrbitControls, createPickingSystem, createScatter3DPlugin, createScatterGLPlugin, createShaderProgram, createSurface3DPlugin, createTorus3DPlugin, createVertexBuffer, createVertexLayout, defaultLightConfig, hexToRGB, mat4, mat4Identity, mat4Invert, mat4LookAt, mat4Multiply, mat4Perspective, projectToScreen, resolveTheme, setLightUniforms, toRad, updateCamera, updateOrbitControls, vec3 };
|
|
3798
|
+
//# sourceMappingURL=chunk-AGG2KSBO.js.map
|
|
3799
|
+
//# sourceMappingURL=chunk-AGG2KSBO.js.map
|