@chartts/gl 0.1.3 → 0.1.4

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.
@@ -1811,20 +1811,36 @@ 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 [-radius * Math.sin(phi) * Math.cos(theta), radius * Math.cos(phi), radius * Math.sin(phi) * Math.sin(theta)];
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();
1826
1841
  const normalMatrix = new Float32Array(9);
1827
- let globePoints = [];
1842
+ let screenPoints = [];
1843
+ let seriesInfo = [];
1828
1844
  return {
1829
1845
  type: "globe3d",
1830
1846
  prepare(ctx) {
@@ -1838,93 +1854,178 @@ function createGlobe3DPlugin() {
1838
1854
  [...MESH_VERT_UNIFORMS, ...MESH_FRAG_UNIFORMS],
1839
1855
  MESH_VERT_ATTRIBUTES
1840
1856
  );
1841
- renderer.registerProgram(
1842
- "point3d",
1843
- POINT_VERT,
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 = [];
1857
+ const patches = [];
1858
+ let maxVal = 0;
1859
+ for (const s of series) for (const v of s.values) if (Math.abs(v) > maxVal) maxVal = Math.abs(v);
1860
+ if (maxVal === 0) maxVal = 1;
1861
+ seriesInfo = [];
1862
+ screenPoints = [];
1871
1863
  for (let sIdx = 0; sIdx < series.length; sIdx++) {
1872
1864
  const s = series[sIdx];
1873
- const color = hexToRGB(s.color ?? theme.colors[sIdx % theme.colors.length]);
1865
+ const colorHex = s.color ?? theme.colors[sIdx % theme.colors.length];
1866
+ const color = hexToRGB(colorHex);
1867
+ seriesInfo.push({ name: s.name, color: colorHex });
1874
1868
  for (let di = 0; di < s.values.length; di++) {
1875
1869
  const lat = s.y?.[di] ?? 0, lng = s.x?.[di] ?? 0, value = s.values[di];
1876
- const [wx, wy, wz] = latLngToXYZ(lat, lng, globeRadius * (1 + value * 5e-3));
1877
- pv.push(wx, wy, wz, color[0], color[1], color[2], Math.max(4, value * 0.3));
1878
- globePoints.push({ si: sIdx, di, lat, lng, wx, wy, wz, value, name: s.name });
1870
+ const normValue = Math.abs(value) / maxVal;
1871
+ patches.push({ lat, lng, value, normValue, color, si: sIdx, di, name: s.name, label: data.categories?.[di] ?? "" });
1872
+ const [wx, wy, wz] = latLngToXYZ(lat, lng, GLOBE_RADIUS);
1873
+ screenPoints.push({ si: sIdx, di, lat, lng, wx, wy, wz, value, name: s.name, label: data.categories?.[di] ?? "" });
1879
1874
  }
1880
1875
  }
1881
- if (pointVBO) pointVBO.update(new Float32Array(pv));
1882
- else pointVBO = createVertexBuffer(gl, new Float32Array(pv), gl.DYNAMIC_DRAW);
1883
- pointCount = globePoints.length;
1876
+ const baseColor = [0.03, 0.05, 0.12];
1877
+ const patchRadius = 0.8;
1878
+ const gratLatStep = 30, gratLngStep = 30;
1879
+ const gratWidth = 0.015;
1880
+ const gratColor = [0.08, 0.12, 0.22];
1881
+ console.log(`[Globe3D] Building sphere ${SEGMENTS}x${RINGS}, ${patches.length} data patches`);
1882
+ const verts = [];
1883
+ const indices = [];
1884
+ let patchedVerts = 0;
1885
+ for (let ring = 0; ring <= RINGS; ring++) {
1886
+ const phi = ring / RINGS * Math.PI;
1887
+ const lat = 90 - ring / RINGS * 180;
1888
+ for (let seg = 0; seg <= SEGMENTS; seg++) {
1889
+ const theta = seg / SEGMENTS * Math.PI * 2;
1890
+ const lng = seg / SEGMENTS * 360 - 180;
1891
+ const nx = Math.sin(phi) * Math.cos(theta);
1892
+ const ny = Math.cos(phi);
1893
+ const nz = Math.sin(phi) * Math.sin(theta);
1894
+ let r = baseColor[0], g = baseColor[1], b = baseColor[2];
1895
+ const latMod = (lat % gratLatStep + gratLatStep) % gratLatStep;
1896
+ const latDist = Math.min(latMod, gratLatStep - latMod) * Math.PI / 180;
1897
+ const lngMod = (lng % gratLngStep + gratLngStep) % gratLngStep;
1898
+ const lngDist = Math.min(lngMod, gratLngStep - lngMod) * Math.PI / 180;
1899
+ const gratDist = Math.min(latDist, lngDist);
1900
+ if (gratDist < gratWidth) {
1901
+ const gratT = 1 - gratDist / gratWidth;
1902
+ r = r + (gratColor[0] - r) * gratT;
1903
+ g = g + (gratColor[1] - g) * gratT;
1904
+ b = b + (gratColor[2] - b) * gratT;
1905
+ }
1906
+ let ar = 0, ag = 0, ab = 0;
1907
+ for (const patch of patches) {
1908
+ const dist = angularDistance(lat, lng, patch.lat, patch.lng);
1909
+ if (dist < patchRadius) {
1910
+ const t = 1 - dist / patchRadius;
1911
+ const influence = t * (0.4 + t * 0.6) * patch.normValue;
1912
+ ar += patch.color[0] * influence;
1913
+ ag += patch.color[1] * influence;
1914
+ ab += patch.color[2] * influence;
1915
+ }
1916
+ }
1917
+ if (ar > 0.01 || ag > 0.01 || ab > 0.01) {
1918
+ patchedVerts++;
1919
+ r = Math.min(1, r + ar);
1920
+ g = Math.min(1, g + ag);
1921
+ b = Math.min(1, b + ab);
1922
+ }
1923
+ verts.push(
1924
+ nx * GLOBE_RADIUS,
1925
+ ny * GLOBE_RADIUS,
1926
+ nz * GLOBE_RADIUS,
1927
+ nx,
1928
+ ny,
1929
+ nz,
1930
+ r,
1931
+ g,
1932
+ b
1933
+ );
1934
+ }
1935
+ }
1936
+ console.log(`[Globe3D] ${patchedVerts} / ${(RINGS + 1) * (SEGMENTS + 1)} vertices colored by data`);
1937
+ for (let ring = 0; ring < RINGS; ring++) {
1938
+ for (let seg = 0; seg < SEGMENTS; seg++) {
1939
+ const a = ring * (SEGMENTS + 1) + seg;
1940
+ const b = a + SEGMENTS + 1;
1941
+ indices.push(a, b, a + 1, a + 1, b, b + 1);
1942
+ }
1943
+ }
1944
+ const vertArr = new Float32Array(verts);
1945
+ const idxArr = new Uint16Array(indices);
1946
+ if (sphereVBO) sphereVBO.update(vertArr);
1947
+ else sphereVBO = createVertexBuffer(gl, vertArr, gl.DYNAMIC_DRAW);
1948
+ if (sphereIBO) sphereIBO.update(idxArr);
1949
+ else sphereIBO = createIndexBuffer(gl, idxArr, gl.DYNAMIC_DRAW);
1950
+ sphereIndexCount = indices.length;
1884
1951
  mat4Identity(modelMatrix);
1885
1952
  },
1886
1953
  render(ctx) {
1887
1954
  const { renderer, camera } = ctx;
1888
1955
  const gl = renderer.gl;
1889
1956
  const progress = ctx.animationProgress;
1890
- const meshProg = renderer.getProgram("mesh");
1891
- meshProg.use();
1892
- meshProg.setMat4("u_projView", camera.projViewMatrix);
1893
- meshProg.setMat4("u_model", modelMatrix);
1957
+ const prog = renderer.getProgram("mesh");
1958
+ prog.use();
1959
+ prog.setMat4("u_projView", camera.projViewMatrix);
1960
+ prog.setMat4("u_model", modelMatrix);
1894
1961
  mat3NormalFromMat4(normalMatrix, modelMatrix);
1895
- meshProg.setMat3("u_normalMatrix", normalMatrix);
1896
- setLightUniforms(meshProg, defaultLightConfig(), camera.position);
1897
- meshProg.setFloat("u_opacity", progress * 0.9);
1962
+ prog.setMat3("u_normalMatrix", normalMatrix);
1963
+ setLightUniforms(prog, defaultLightConfig(), camera.position);
1964
+ prog.setFloat("u_opacity", progress);
1898
1965
  if (sphereVBO && sphereIBO) {
1899
1966
  sphereVBO.bind();
1900
- const ml = createVertexLayout([
1901
- { location: meshProg.attributes["a_position"], size: 3 },
1902
- { location: meshProg.attributes["a_normal"], size: 3 },
1903
- { location: meshProg.attributes["a_color"], size: 3 }
1967
+ const layout = createVertexLayout([
1968
+ { location: prog.attributes["a_position"], size: 3 },
1969
+ { location: prog.attributes["a_normal"], size: 3 },
1970
+ { location: prog.attributes["a_color"], size: 3 }
1904
1971
  ]);
1905
- applyVertexLayout(gl, ml);
1972
+ applyVertexLayout(gl, layout);
1906
1973
  sphereIBO.bind();
1907
- gl.drawElements(gl.TRIANGLES, sphereIndexCount, gl.UNSIGNED_SHORT, 0);
1908
- disableVertexLayout(gl, ml);
1974
+ const indexType = gl.UNSIGNED_SHORT;
1975
+ gl.drawElements(gl.TRIANGLES, sphereIndexCount, indexType, 0);
1976
+ disableVertexLayout(gl, layout);
1909
1977
  }
1910
- const pointProg = renderer.getProgram("point3d");
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);
1978
+ },
1979
+ renderOverlay(ctx, ctx2d) {
1980
+ const { camera, width, height, theme, animationProgress } = ctx;
1981
+ if (animationProgress < 0.5) return;
1982
+ ctx2d.save();
1983
+ const seenLabels = /* @__PURE__ */ new Set();
1984
+ ctx2d.font = `${theme.fontSize - 1}px ${theme.fontFamily}`;
1985
+ ctx2d.textBaseline = "middle";
1986
+ for (const sp of screenPoints) {
1987
+ if (!sp.label || seenLabels.has(sp.label)) continue;
1988
+ const screen = projectToScreen(
1989
+ new Float32Array([sp.wx, sp.wy, sp.wz]),
1990
+ camera.projViewMatrix,
1991
+ width,
1992
+ height
1993
+ );
1994
+ if (!screen || screen.z < -1 || screen.z > 1 || screen.z > 0.97) continue;
1995
+ seenLabels.add(sp.label);
1996
+ ctx2d.fillStyle = theme.textColor;
1997
+ ctx2d.globalAlpha = 0.7;
1998
+ ctx2d.beginPath();
1999
+ ctx2d.arc(screen.x, screen.y, 2.5, 0, Math.PI * 2);
2000
+ ctx2d.fill();
2001
+ ctx2d.fillStyle = theme.textColor;
2002
+ ctx2d.globalAlpha = 0.85;
2003
+ ctx2d.textAlign = "left";
2004
+ ctx2d.fillText(sp.label, screen.x + 8, screen.y);
2005
+ }
2006
+ if (seriesInfo.length > 1) {
2007
+ const lx = 12, ly = height - 14 - seriesInfo.length * 18;
2008
+ ctx2d.fillStyle = "rgba(0,0,0,0.45)";
2009
+ ctx2d.globalAlpha = 1;
2010
+ ctx2d.beginPath();
2011
+ ctx2d.roundRect(lx - 6, ly - 8, 120, seriesInfo.length * 18 + 12, 6);
2012
+ ctx2d.fill();
2013
+ ctx2d.textAlign = "left";
2014
+ ctx2d.textBaseline = "top";
2015
+ ctx2d.font = `${theme.fontSize - 1}px ${theme.fontFamily}`;
2016
+ for (let i = 0; i < seriesInfo.length; i++) {
2017
+ const s = seriesInfo[i];
2018
+ const y = ly + i * 18;
2019
+ ctx2d.fillStyle = s.color;
2020
+ ctx2d.globalAlpha = 0.9;
2021
+ ctx2d.beginPath();
2022
+ ctx2d.arc(lx + 4, y + 6, 4, 0, Math.PI * 2);
2023
+ ctx2d.fill();
2024
+ ctx2d.fillStyle = "rgba(255,255,255,0.8)";
2025
+ ctx2d.fillText(s.name, lx + 14, y);
2026
+ }
1927
2027
  }
2028
+ ctx2d.restore();
1928
2029
  },
1929
2030
  needsLoop() {
1930
2031
  return false;
@@ -1932,14 +2033,26 @@ function createGlobe3DPlugin() {
1932
2033
  hitTest(ctx, x, y) {
1933
2034
  const { camera, width, height } = ctx;
1934
2035
  let closest = null;
1935
- let closestDist = 20;
1936
- for (const gp of globePoints) {
1937
- const screen = projectToScreen(new Float32Array([gp.wx, gp.wy, gp.wz]), camera.projViewMatrix, width, height);
2036
+ let closestDist = 25;
2037
+ for (const sp of screenPoints) {
2038
+ const screen = projectToScreen(
2039
+ new Float32Array([sp.wx, sp.wy, sp.wz]),
2040
+ camera.projViewMatrix,
2041
+ width,
2042
+ height
2043
+ );
1938
2044
  if (!screen || screen.z < -1 || screen.z > 1) continue;
1939
2045
  const dist = Math.sqrt((screen.x - x) ** 2 + (screen.y - y) ** 2);
1940
2046
  if (dist < closestDist) {
1941
2047
  closestDist = dist;
1942
- closest = { seriesIndex: gp.si, dataIndex: gp.di, value: gp.value, x: gp.lng, y: gp.lat, seriesName: gp.name };
2048
+ closest = {
2049
+ seriesIndex: sp.si,
2050
+ dataIndex: sp.di,
2051
+ value: sp.value,
2052
+ x: sp.lng,
2053
+ y: sp.lat,
2054
+ seriesName: sp.label || sp.name
2055
+ };
1943
2056
  }
1944
2057
  }
1945
2058
  return closest;
@@ -1949,9 +2062,7 @@ function createGlobe3DPlugin() {
1949
2062
  sphereVBO = null;
1950
2063
  sphereIBO?.destroy();
1951
2064
  sphereIBO = null;
1952
- pointVBO?.destroy();
1953
- pointVBO = null;
1954
- globePoints = [];
2065
+ screenPoints = [];
1955
2066
  }
1956
2067
  };
1957
2068
  }
@@ -3460,5 +3571,5 @@ function GraphGL(container, opts) {
3460
3571
  }
3461
3572
 
3462
3573
  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-M24XMYGG.js.map
3464
- //# sourceMappingURL=chunk-M24XMYGG.js.map
3574
+ //# sourceMappingURL=chunk-XGQDO4VO.js.map
3575
+ //# sourceMappingURL=chunk-XGQDO4VO.js.map