睿能科技
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

448 lines
12 KiB

//#region assets/images/home/earth_light_gray_white.png
var earth_light_gray_white_default = "" + new URL("../images/earth_light_gray_white-D7Fpf71y.png", import.meta.url).href;
//#endregion
//#region assets/images/about/location.svg
var location_default = "data:image/svg+xml,%3csvg%20viewBox='0%200%2030%2041.1846'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%20width='30.000000'%20height='41.184570'%20fill='none'%20customFrame='%23000000'%3e%3cpath%20id='减去顶层'%20d='M14.898%2041.1845C14.898%2041.1845%2030%2031.7422%2030%2014.8666C30%206.6297%2023.2653%200%2015.102%200C6.73469%200%200%206.6297%200%2014.8666C0%2030.5368%2014.898%2041.1845%2014.898%2041.1845ZM20.2041%2015.0225C20.2041%2017.7964%2017.9198%2020.045%2015.102%2020.045C12.2843%2020.045%2010%2017.7964%2010%2015.0225C10%2012.2487%2012.2843%2010%2015.102%2010C17.9198%2010%2020.2041%2012.2487%2020.2041%2015.0225Z'%20fill='rgb(239,67,53)'%20fill-rule='evenodd'%20/%3e%3c/svg%3e";
//#endregion
//#region js/earth.js
(function() {
const getUiLang = window.getUiLang || (() => (location.pathname.split("/")[1] === "en" ? "en" : "zh"));
function markerName(data) {
return getUiLang() === "en" ? (data.nameEn || data.nameZh) : (data.nameZh || data.nameEn);
}
const canvas = document.getElementById("earth-canvas");
if (!canvas || !window.THREE) return;
const container = canvas.parentElement;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(40, container.clientWidth / container.clientHeight, .1, 1e3);
camera.position.z = 1.5;
const renderer = new THREE.WebGLRenderer({
canvas,
alpha: true,
antialias: true
});
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.setPixelRatio(window.devicePixelRatio);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = .05;
controls.enablePan = true;
controls.enableZoom = false;
controls.autoRotate = false;
controls.rotateSpeed = .1;
controls.minPolarAngle = Math.PI / 2;
controls.maxPolarAngle = Math.PI / 2;
const geometry = new THREE.SphereGeometry(.5, 64, 64);
const hemiLight = new THREE.HemisphereLight("#e0e0e0", "#6a8aaa", .5);
scene.add(hemiLight);
const bounceLight = new THREE.DirectionalLight("#000000", .1);
bounceLight.position.set(0, -5, 0);
scene.add(bounceLight);
const ambientLight = new THREE.AmbientLight("#e0e0e0", .9);
scene.add(ambientLight);
const textureLoader = new THREE.TextureLoader();
const material = new THREE.MeshPhongMaterial({
color: "#efefef",
emissive: "#000000",
shininess: 20,
transparent: true,
opacity: .9
});
const earth = new THREE.Mesh(geometry, material);
earth.renderOrder = 0;
textureLoader.load(earth_light_gray_white_default, function(texture) {
material.map = texture;
material.color.setHex(16777215);
material.needsUpdate = true;
}, void 0, function(err) {
console.warn("Earth texture failed to load, using default color.", err);
});
scene.add(earth);
const markersData = [
{
nameZh: "上海",
nameEn: "Shanghai",
lat: 31.2304,
lon: 121.4737
},
{
nameZh: "东京",
nameEn: "Tokyo",
lat: 35.6762,
lon: 139.6503
},
{
nameZh: "伊斯坦布尔",
nameEn: "Istanbul",
lat: 41.0082,
lon: 28.9784
},
{
nameZh: "伦敦",
nameEn: "London",
lat: 51.5074,
lon: -.1278
},
{
nameZh: "加尔各答",
nameEn: "Kolkata",
lat: 22.5726,
lon: 88.3639
},
{
nameZh: "北京",
nameEn: "Beijing",
lat: 39.9042,
lon: 116.4074
},
{
nameZh: "华沙",
nameEn: "Warsaw",
lat: 52.2297,
lon: 21.0122
},
{
nameZh: "南京",
nameEn: "Nanjing",
lat: 32.0603,
lon: 118.7969
},
{
nameZh: "吉隆坡",
nameEn: "Kuala Lumpur",
lat: 3.139,
lon: 101.6869
},
{
nameZh: "圣保罗",
nameEn: "São Paulo",
lat: -23.5505,
lon: -46.6333
},
{
nameZh: "圣安东尼奥",
nameEn: "San Antonio",
lat: 29.4241,
lon: -98.4936
},
{
nameZh: "墨西哥城",
nameEn: "Mexico City",
lat: 19.4326,
lon: -99.1332
},
{
nameZh: "多伦多",
nameEn: "Toronto",
lat: 43.6532,
lon: -79.3832
},
{
nameZh: "奥克兰",
nameEn: "Auckland",
lat: -36.8485,
lon: 174.7633
},
{
nameZh: "孟买",
nameEn: "Mumbai",
lat: 19.076,
lon: 72.8777
},
{
nameZh: "安地比斯",
nameEn: "Antibes",
lat: 43.5804,
lon: 7.1251
},
{
nameZh: "山景城",
nameEn: "Mountain View",
lat: 37.3861,
lon: -122.0839
},
{
nameZh: "巴黎",
nameEn: "Paris",
lat: 48.8566,
lon: 2.3522
},
{
nameZh: "布宜诺斯艾利斯",
nameEn: "Buenos Aires",
lat: -34.6037,
lon: -58.3816
},
{
nameZh: "开普敦",
nameEn: "Cape Town",
lat: -33.9249,
lon: 18.4241
},
{
nameZh: "悉尼",
nameEn: "Sydney",
lat: -33.8688,
lon: 151.2093
},
{
nameZh: "新加坡",
nameEn: "Singapore",
lat: 1.3521,
lon: 103.8198
},
{
nameZh: "新德里",
nameEn: "New Delhi",
lat: 28.6139,
lon: 77.209
},
{
nameZh: "曼谷",
nameEn: "Bangkok",
lat: 13.7563,
lon: 100.5018
},
{
nameZh: "法兰克福",
nameEn: "Frankfurt",
lat: 50.1109,
lon: 8.6821
},
{
nameZh: "波哥大",
nameEn: "Bogotá",
lat: 4.711,
lon: -74.0721
},
{
nameZh: "深圳",
nameEn: "Shenzhen",
lat: 22.5431,
lon: 114.0579
},
{
nameZh: "牛津",
nameEn: "Oxford",
lat: 51.752,
lon: -1.2577
},
{
nameZh: "特拉维夫",
nameEn: "Tel Aviv",
lat: 32.0853,
lon: 34.7818
},
{
nameZh: "科伦坡",
nameEn: "Colombo",
lat: 6.9271,
lon: 79.8612
},
{
nameZh: "米兰",
nameEn: "Milan",
lat: 45.4642,
lon: 9.19
},
{
nameZh: "纽约",
nameEn: "New York",
lat: 40.7128,
lon: -74.006
},
{
nameZh: "莫斯科",
nameEn: "Moscow",
lat: 55.7558,
lon: 37.6173
},
{
nameZh: "达卡",
nameEn: "Dhaka",
lat: 23.8103,
lon: 90.4125
},
{
nameZh: "迪拜",
nameEn: "Dubai",
lat: 25.2048,
lon: 55.2708
},
{
nameZh: "邦加罗尔",
nameEn: "Bengaluru",
lat: 12.9716,
lon: 77.5946
},
{
nameZh: "金奈",
nameEn: "Chennai",
lat: 13.0827,
lon: 80.2707
},
{
nameZh: "雅加达",
nameEn: "Jakarta",
lat: -6.2088,
lon: 106.8456
},
{
nameZh: "首尔",
nameEn: "Seoul",
lat: 37.5665,
lon: 126.978
},
{
nameZh: "香港",
nameEn: "Hong Kong",
lat: 22.3193,
lon: 114.1694
},
{
nameZh: "全球总部福州",
nameEn: "Global HQ Fuzhou",
lat: 26.0745,
lon: 119.2965
}
];
const markerMeshes = [];
let fuzhouMarkerMesh = null;
function latLonToVector3(lat, lon, radius = 1) {
const phi = (90 - lat) * (Math.PI / 180);
const theta = (lon + 180) * (Math.PI / 180);
const x = -radius * Math.sin(phi) * Math.cos(theta);
const y = radius * Math.cos(phi);
const z = radius * Math.sin(phi) * Math.sin(theta);
return new THREE.Vector3(x, y, z);
}
const defaultMarkerGeometry = new THREE.CircleGeometry(.012, 24);
const defaultMarkerMaterial = new THREE.MeshBasicMaterial({
color: 15680309,
side: THREE.FrontSide,
depthWrite: false,
transparent: true,
opacity: 1
});
const svgWidth = .03;
const svgHeight = .04;
const locationTexture = textureLoader.load(location_default);
const fuzhouMarkerGeometry = new THREE.PlaneGeometry(svgWidth, svgHeight);
fuzhouMarkerGeometry.translate(0, svgHeight / 2, 0);
const fuzhouMarkerMaterial = new THREE.MeshBasicMaterial({
map: locationTexture,
color: 16777215,
side: THREE.FrontSide,
depthWrite: false,
transparent: true,
opacity: 1
});
markersData.forEach((data) => {
const position = latLonToVector3(data.lat, data.lon, .5);
let marker;
if (data.nameZh === "全球总部福州") {
marker = new THREE.Mesh(fuzhouMarkerGeometry, fuzhouMarkerMaterial);
fuzhouMarkerMesh = marker;
} else marker = new THREE.Mesh(defaultMarkerGeometry, defaultMarkerMaterial);
marker.position.copy(position);
const normal = position.clone().normalize();
marker.position.add(normal.multiplyScalar(.01));
marker.renderOrder = 1;
marker.userData = { name: markerName(data), nameZh: data.nameZh };
earth.add(marker);
markerMeshes.push(marker);
});
const targetLon = 9.6869;
earth.rotation.y = -(targetLon * Math.PI / 180) + Math.PI;
const tooltip = document.createElement("div");
tooltip.style.position = "absolute";
tooltip.style.padding = "8px";
tooltip.style.color = "#2E353A";
tooltip.style.fontSize = "16px";
tooltip.style.fontFamily = "MiSans VF";
tooltip.style.textAlign = "center";
tooltip.style.lineHeight = "20px";
tooltip.style.whiteSpace = "nowrap";
tooltip.style.pointerEvents = "none";
tooltip.style.display = "none";
tooltip.style.zIndex = "1000";
tooltip.style.transform = "translate(-50%, 15px)";
tooltip.classList.add("tooltip-arrow");
container.appendChild(tooltip);
const fuzhouTooltip = tooltip.cloneNode(true);
fuzhouTooltip.innerHTML = (window.t || ((k) => k))("earth.hq_fuzhou_html");
container.appendChild(fuzhouTooltip);
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
canvas.addEventListener("mousemove", (e) => {
const rect = canvas.getBoundingClientRect();
mouse.x = (e.clientX - rect.left) / rect.width * 2 - 1;
mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(markerMeshes);
if (intersects.length > 0) {
const object = intersects[0].object;
const name = object.userData.name;
if (object.userData.nameZh !== "全球总部福州") {
tooltip.textContent = name;
tooltip.style.display = "block";
const vector = object.position.clone();
object.updateWorldMatrix(true, false);
vector.setFromMatrixPosition(object.matrixWorld);
vector.project(camera);
const containerRect = container.getBoundingClientRect();
const x = (vector.x * .5 + .5) * rect.width + (rect.left - containerRect.left);
const y = (-(vector.y * .5) + .5) * rect.height + (rect.top - containerRect.top);
tooltip.style.left = `${x}px`;
tooltip.style.top = `${y - 10}px`;
} else tooltip.style.display = "none";
document.body.style.cursor = "pointer";
} else {
tooltip.style.display = "none";
document.body.style.cursor = "default";
}
});
function animate() {
requestAnimationFrame(animate);
earth.rotation.y += 5e-4;
markerMeshes.forEach((marker) => {
marker.lookAt(camera.position);
const worldPosition = new THREE.Vector3();
marker.getWorldPosition(worldPosition);
const viewDirection = new THREE.Vector3().subVectors(camera.position, worldPosition).normalize();
const dot = worldPosition.clone().normalize().dot(viewDirection);
let scaleValue = Math.max(0, dot);
scaleValue = Math.pow(scaleValue, .5);
marker.scale.setScalar(scaleValue);
});
if (fuzhouMarkerMesh) {
const worldPosition = new THREE.Vector3();
fuzhouMarkerMesh.getWorldPosition(worldPosition);
const viewDirection = new THREE.Vector3().subVectors(camera.position, worldPosition).normalize();
if (worldPosition.clone().normalize().dot(viewDirection) > 0) {
fuzhouTooltip.style.display = "block";
const vector = fuzhouMarkerMesh.position.clone();
fuzhouMarkerMesh.updateWorldMatrix(true, false);
vector.setFromMatrixPosition(fuzhouMarkerMesh.matrixWorld);
vector.project(camera);
const rect = canvas.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const x = (vector.x * .5 + .5) * rect.width + (rect.left - containerRect.left);
const y = (-(vector.y * .5) + .5) * rect.height + (rect.top - containerRect.top);
fuzhouTooltip.style.left = `${x}px`;
fuzhouTooltip.style.top = `${y - 10}px`;
} else fuzhouTooltip.style.display = "none";
}
controls.update();
renderer.render(scene, camera);
}
animate();
window.addEventListener("resize", () => {
const width = container.clientWidth;
const height = container.clientHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
});
})();
//#endregion