mirror of
git://f0xx.org/android_cast
synced 2026-07-29 07:39:15 +03:00
snap
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Hub landing globe — orthographic Canvas2D (globe3d=1).
|
* Hub landing globe — orthographic Canvas2D (globe3d=1).
|
||||||
* Phase 1: E–W parallels only (SVG hub ellipses → body → Y-rotation → canvas stroke).
|
* Grid: hub SVG ellipses (E–W) + meridian paths (N–S) traced on sphere, then Y-rotated.
|
||||||
* Phase 2 (after confirm): N–S meridians from SVG.
|
* Land: ortho hub disk on front face; mercator-flat only on back wrap (avoids front squeeze).
|
||||||
*/
|
*/
|
||||||
export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 };
|
export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 };
|
||||||
|
|
||||||
@@ -12,13 +12,42 @@ const FRONT_Z = 0.04;
|
|||||||
const RASTER_SCALE = 2;
|
const RASTER_SCALE = 2;
|
||||||
const AXIS_STEPS = 160;
|
const AXIS_STEPS = 160;
|
||||||
|
|
||||||
/** Same ellipses as hub-logo-fragment-globe-grid-overlay.svg (E–W / parallel to equator). */
|
/** hub-logo-fragment-globe-grid-overlay.svg — E–W parallels. */
|
||||||
const HUB_EW_PARALLELS = [
|
const HUB_EW_PARALLELS = [
|
||||||
{ cx: 720, cy: 560, rx: 318, ry: 11, width: 7.5, bright: true },
|
{ cx: 720, cy: 560, rx: 318, ry: 11, bright: true },
|
||||||
{ cx: 720, cy: 392, rx: 260, ry: 39, width: 7.5, bright: false },
|
{ cx: 720, cy: 392, rx: 260, ry: 39, bright: false },
|
||||||
{ cx: 720, cy: 728, rx: 260, ry: 39, width: 7.5, bright: false },
|
{ cx: 720, cy: 728, rx: 260, ry: 39, bright: false },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** Same SVG — N–S meridians (line + quadratic beziers). */
|
||||||
|
const HUB_NS_MERIDIANS = [
|
||||||
|
{ prime: true, points: sampleLinePoints(720, 248, 720, 872, AXIS_STEPS) },
|
||||||
|
{ prime: false, points: sampleQuadPoints(620, 248, 358, 560, 620, 872, AXIS_STEPS) },
|
||||||
|
{ prime: false, points: sampleQuadPoints(820, 248, 1082, 560, 820, 872, AXIS_STEPS) },
|
||||||
|
];
|
||||||
|
|
||||||
|
function sampleLinePoints(x0, y0, x1, y1, steps) {
|
||||||
|
const pts = [];
|
||||||
|
for (let i = 0; i <= steps; i++) {
|
||||||
|
const t = i / steps;
|
||||||
|
pts.push({ x: x0 + (x1 - x0) * t, y: y0 + (y1 - y0) * t });
|
||||||
|
}
|
||||||
|
return pts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sampleQuadPoints(x0, y0, cx, cy, x1, y1, steps) {
|
||||||
|
const pts = [];
|
||||||
|
for (let i = 0; i <= steps; i++) {
|
||||||
|
const t = i / steps;
|
||||||
|
const u = 1 - t;
|
||||||
|
pts.push({
|
||||||
|
x: u * u * x0 + 2 * u * t * cx + t * t * x1,
|
||||||
|
y: u * u * y0 + 2 * u * t * cy + t * t * y1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return pts;
|
||||||
|
}
|
||||||
|
|
||||||
function hubAsset(rel, build) {
|
function hubAsset(rel, build) {
|
||||||
const link = document.querySelector('link[href*="hub.css"]');
|
const link = document.querySelector('link[href*="hub.css"]');
|
||||||
const base = link ? (link.getAttribute('href') || '').replace(/[^/]*$/, '') : '';
|
const base = link ? (link.getAttribute('href') || '').replace(/[^/]*$/, '') : '';
|
||||||
@@ -137,6 +166,17 @@ function hubPixelToBody(hpX, hpY) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hubPointsToBodyRing(points) {
|
||||||
|
const out = [];
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
const body = hubPixelToBody(points[i].x, points[i].y);
|
||||||
|
if (body) {
|
||||||
|
out.push(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
function ellipseBodyRing(ellipse, steps) {
|
function ellipseBodyRing(ellipse, steps) {
|
||||||
const out = [];
|
const out = [];
|
||||||
for (let i = 0; i <= steps; i++) {
|
for (let i = 0; i <= steps; i++) {
|
||||||
@@ -165,6 +205,18 @@ function parallelStyle(bright, scale, z) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function meridianStyle(prime, scale, z) {
|
||||||
|
const t = Math.max(0, Math.min(1, (z - FRONT_Z) / (0.95 - FRONT_Z)));
|
||||||
|
if (t <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const alpha = prime ? 0.5 + 0.48 * t : 0.3 + 0.45 * t;
|
||||||
|
return {
|
||||||
|
color: 'rgba(238,245,255,' + alpha.toFixed(3) + ')',
|
||||||
|
width: Math.max(prime ? 3 : 2.5, scale * (prime ? 0.0095 : 0.008)) * (0.45 + 0.55 * t),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function strokeBodyRing(ctx, cx, cy, r, rotY, bodies, styleAt) {
|
function strokeBodyRing(ctx, cx, cy, r, rotY, bodies, styleAt) {
|
||||||
let run = [];
|
let run = [];
|
||||||
|
|
||||||
@@ -210,20 +262,25 @@ function strokeBodyRing(ctx, cx, cy, r, rotY, bodies, styleAt) {
|
|||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Phase 1 — E–W hub parallels (equator + pole ellipses from SVG). */
|
/** Hub SVG grid: E–W ellipses + N–S meridian paths (matches globe3d=0 artwork geometry). */
|
||||||
function drawEwParallels(ctx, cx, cy, r, rotY, layoutScale) {
|
function drawHubGrid(ctx, cx, cy, r, rotY, layoutScale) {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(cx, cy, r, 0, Math.PI * 2);
|
ctx.arc(cx, cy, r, 0, Math.PI * 2);
|
||||||
ctx.clip();
|
ctx.clip();
|
||||||
|
|
||||||
HUB_EW_PARALLELS.forEach(function (ellipse) {
|
HUB_EW_PARALLELS.forEach(function (ellipse) {
|
||||||
const ring = ellipseBodyRing(ellipse, AXIS_STEPS);
|
strokeBodyRing(ctx, cx, cy, r, rotY, ellipseBodyRing(ellipse, AXIS_STEPS), function (z) {
|
||||||
strokeBodyRing(ctx, cx, cy, r, rotY, ring, function (z) {
|
|
||||||
return parallelStyle(ellipse.bright, layoutScale, z);
|
return parallelStyle(ellipse.bright, layoutScale, z);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
HUB_NS_MERIDIANS.forEach(function (mer) {
|
||||||
|
strokeBodyRing(ctx, cx, cy, r, rotY, hubPointsToBodyRing(mer.points), function (z) {
|
||||||
|
return meridianStyle(mer.prime, layoutScale, z);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,12 +311,27 @@ function isLandPixel(r, g, b, a) {
|
|||||||
return a > 10 && r > 100 && g < 140 && b < 140;
|
return a > 10 && r > 100 && g < 140 && b < 140;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Light hub grid strokes baked into hub-logo-fragment-globe.svg (vector grid drawn separately). */
|
||||||
|
function isGridPixel(r, g, b, a) {
|
||||||
|
if (a < 12) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const lum = r * 0.299 + g * 0.587 + b * 0.114;
|
||||||
|
if (lum < 125) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (g < 155 || b < 155) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Math.max(r, g, b) - Math.min(r, g, b) < 85;
|
||||||
|
}
|
||||||
|
|
||||||
function sampleOceanRgba(globe, tex) {
|
function sampleOceanRgba(globe, tex) {
|
||||||
if (tex.z <= FRONT_Z) {
|
if (tex.z <= FRONT_Z) {
|
||||||
return [OCEAN_FALLBACK.r, OCEAN_FALLBACK.g, OCEAN_FALLBACK.b, 255];
|
return [OCEAN_FALLBACK.r, OCEAN_FALLBACK.g, OCEAN_FALLBACK.b, 255];
|
||||||
}
|
}
|
||||||
const s = sampleHub(globe, tex);
|
const s = sampleHub(globe, tex);
|
||||||
if (s[3] > 8) {
|
if (s[3] > 8 && !isGridPixel(s[0], s[1], s[2], s[3])) {
|
||||||
return [s[0], s[1], s[2], 255];
|
return [s[0], s[1], s[2], 255];
|
||||||
}
|
}
|
||||||
return [OCEAN_FALLBACK.r, OCEAN_FALLBACK.g, OCEAN_FALLBACK.b, 255];
|
return [OCEAN_FALLBACK.r, OCEAN_FALLBACK.g, OCEAN_FALLBACK.b, 255];
|
||||||
@@ -271,6 +343,10 @@ function sampleLandRgba(continents, mercFlat, tex) {
|
|||||||
if (ortho[3] > 6) {
|
if (ortho[3] > 6) {
|
||||||
return ortho;
|
return ortho;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (tex.z > -FRONT_Z) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
const ll = texLonLat(tex);
|
const ll = texLonLat(tex);
|
||||||
const flat = sampleMercFlat(mercFlat, ll.lon, ll.lat);
|
const flat = sampleMercFlat(mercFlat, ll.lon, ll.lat);
|
||||||
@@ -467,7 +543,7 @@ export async function mountHubGlobe(stage, opts) {
|
|||||||
return l || [0, 0, 0, 0];
|
return l || [0, 0, 0, 0];
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
drawEwParallels(ctx, cx, cy, r, rotation, layoutScale);
|
drawHubGrid(ctx, cx, cy, r, rotation, layoutScale);
|
||||||
drawRim(ctx, globeImg, cx, cy, r, rim, layoutScale);
|
drawRim(ctx, globeImg, cx, cy, r, rim, layoutScale);
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
@@ -537,7 +613,7 @@ export async function mountHubGlobe(stage, opts) {
|
|||||||
|
|
||||||
raf = requestAnimationFrame(tick);
|
raf = requestAnimationFrame(tick);
|
||||||
stage.dataset.globe3d = 'active';
|
stage.dataset.globe3d = 'active';
|
||||||
stage.dataset.globeAxis = 'ew-parallels';
|
stage.dataset.globeAxis = 'ew-ns-grid';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
destroy() {
|
destroy() {
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ unset($__platformDir);
|
|||||||
var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover'));
|
var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover'));
|
||||||
var logoEnabled = !!(stage && supportsSvg && supportsLayout);
|
var logoEnabled = !!(stage && supportsSvg && supportsLayout);
|
||||||
|
|
||||||
var logoBuild = '20260606globe12';
|
var logoBuild = '20260606globe14';
|
||||||
|
|
||||||
function hubAsset(rel) {
|
function hubAsset(rel) {
|
||||||
var link = document.querySelector('link[href*="hub.css"]');
|
var link = document.querySelector('link[href*="hub.css"]');
|
||||||
|
|||||||
Reference in New Issue
Block a user