Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
27 views7 pages

Graph HTML

Uploaded by

2ft5tykyf2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views7 pages

Graph HTML

Uploaded by

2ft5tykyf2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 7

<!

doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>2.5D Spherical Graph — Demo</title>
<style>
html,body{height:100%;margin:0;background:#0b1220;color:#ddd;font-
family:Inter,system-ui,Arial}
#container{width:100%;height:100%;position:relative;overflow:hidden}
#ui {
position:absolute;right:12px;top:12px;background:rgba(10,12,20,0.45);
color:#fff;padding:10px;border-radius:8px;font-size:13px;backdrop-filter:
blur(6px);
}
#legend {position:absolute;left:12px;bottom:12px;background:rgba(10,12,20,0.45);
padding:8px;border-radius:8px;}
.label {
padding:4px 7px;background:rgba(0,0,0,0.6);border-radius:4px;font-weight:600;
font-size:12px;color:#fff;pointer-events:none;white-space:nowrap;
}
a.small{font-size:12px;color:#9fd; text-decoration:none}
</style>
</head>
<body>
<div id="container"></div>
<div id="ui">
<div><strong>2.5D Spherical Graph</strong></div>
<div style="margin-top:6px">
<label style="display:block">Node scale <input id="nodeScale" type="range"
min="0.2" max="3" step="0.1" value="1"></label>
<label>Auto rotate <input id="autoRotate" type="checkbox" checked></label>
</div>
<div style="margin-top:6px"><small><a class="small" href="#"
id="toggleLabels">Toggle labels</a></small></div>
</div>
<div id="legend">
<div style="font-size:12px;margin-bottom:6px">Legend</div>
<div style="display:flex;gap:8px;align-items:center">
<div style="width:12px;height:12px;border-radius:50%;background:#ff8c42"></
div><div style="font-size:12px">High value</div>
</div>
<div style="display:flex;gap:8px;align-items:center;margin-top:4px">
<div style="width:12px;height:12px;border-radius:50%;background:#4499ff"></
div><div style="font-size:12px">Low value</div>
</div>
</div>

<!-- Three.js from CDN -->


<script src="https://unpkg.com/[email protected]/build/three.min.js"></script>
<script
src="https://unpkg.com/[email protected]/examples/js/controls/OrbitControls.js"></
script>

<script>
/*
2.5D Spherical Graph — Interactive demo
Data format: array of nodes:
{ id, name, lat (deg), lon (deg), value (0..1), group (optional) }
*/

const sampleData = [
{id:1, name:"Core", lat: 10, lon: -10, value: 0.95, group: "A"},
{id:2, name:"Node B", lat: 40, lon: 60, value: 0.7, group: "A"},
{id:3, name:"Node C", lat: -20, lon: 120, value: 0.4, group: "B"},
{id:4, name:"Node D", lat: -45, lon: -140, value: 0.25, group: "B"},
{id:5, name:"Node E", lat: 60, lon: -60, value: 0.5, group: "C"}
];

const connections = [
[1,2],[1,3],[2,5],[3,4],[4,5]
];

const container = document.getElementById('container');

const scene = new THREE.Scene();


scene.fog = new THREE.FogExp2(0x071019, 0.06);

const camera = new THREE.PerspectiveCamera(50, innerWidth/innerHeight, 0.1, 1000);


camera.position.set(0, 0, 8);

const renderer = new THREE.WebGLRenderer({antialias:true, alpha:true});


renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
container.appendChild(renderer.domElement);

// controls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.enablePan = false;
controls.minDistance = 4;
controls.maxDistance = 30;

// lighting
const hemi = new THREE.HemisphereLight(0xbfe8ff, 0x202030, 0.9);
scene.add(hemi);
const spot = new THREE.PointLight(0xffffff, 0.9);
spot.position.set(5,5,5);
scene.add(spot);

// globe base (subtle glassy)


const globeRadius = 3;
const globeGeo = new THREE.SphereGeometry(globeRadius, 64, 40);
const globeMat = new THREE.MeshPhysicalMaterial({
color: 0x0f2a46,
metalness: 0.1,
roughness: 0.2,
transmission: 0.5,
transparent: true,
opacity: 0.9,
clearcoat: 0.6,
clearcoatRoughness: 0.1
});
const globeMesh = new THREE.Mesh(globeGeo, globeMat);
globeMesh.renderOrder = 0;
scene.add(globeMesh);

// faint grid lines (latitude/longitude)


const gridMat = new THREE.LineBasicMaterial({color:0x2b4b6b, transparent:true,
opacity:0.35});
const gridLines = new THREE.Group();
for(let lat=-80; lat<=80; lat+=20){
const radius = globeRadius * Math.cos(THREE.MathUtils.degToRad(lat));
const y = globeRadius * Math.sin(THREE.MathUtils.degToRad(lat));
const circle = new THREE.CircleGeometry(radius, 128);
circle.vertices = circle.attributes.position.array; // compatibility
const geom = new THREE.BufferGeometry();
const pts = [];
for(let i=0;i<=128;i++){
const a = i/128 * Math.PI * 2;
pts.push(new THREE.Vector3(Math.cos(a)*radius, y, Math.sin(a)*radius));
}
geom.setFromPoints(pts);
const line = new THREE.Line(geom, gridMat);
gridLines.add(line);
}
scene.add(gridLines);

// node group
const nodeGroup = new THREE.Group();
scene.add(nodeGroup);

// helper: lat/lon -> 3D point on sphere


function latLonToVector3(lat, lon, radius){
const phi = THREE.MathUtils.degToRad(90 - lat);
const theta = THREE.MathUtils.degToRad(lon + 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);
}

// color scale: maps value 0..1 into blue->orange


function valueToColor(v){
const c1 = new THREE.Color(0x4499ff); // low
const c2 = new THREE.Color(0xff8c42); // high
return c1.lerp(c2, THREE.MathUtils.clamp(v,0,1));
}

// create node sprite label


function makeLabel(text){
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.font = '600 36px sans-serif';
const padding = 12;
const w = Math.ceil(ctx.measureText(text).width) + padding*2;
const h = 48;
canvas.width = w;
canvas.height = h;
// background
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(0,0,w,h);
// text
ctx.fillStyle = '#fff';
ctx.font = '600 26px sans-serif';
ctx.textBaseline = 'middle';
ctx.fillText(text, padding, h/2 + 2);
const tex = new THREE.CanvasTexture(canvas);
tex.minFilter = THREE.LinearFilter;
const sprite = new THREE.Sprite(new THREE.SpriteMaterial({map: tex,
transparent:true}));
sprite.scale.set((w/64), (h/64), 1);
return sprite;
}

// add nodes
const nodeData = [];
const labelSprites = [];
for(const d of sampleData){
const pos = latLonToVector3(d.lat, d.lon, globeRadius + 0.06 +
(d.value*0.12)); // slightly above surface
const color = valueToColor(d.value);
// sphere
const sphereGeo = new THREE.SphereGeometry(0.05 + d.value*0.14, 16, 12);
const sphereMat = new THREE.MeshStandardMaterial({
color: color,
emissive: color.clone().multiplyScalar(0.12),
metalness: 0.4,
roughness: 0.3
});
const nodeMesh = new THREE.Mesh(sphereGeo, sphereMat);
nodeMesh.position.copy(pos);
nodeMesh.userData = {...d, basePos: pos.clone()};
nodeGroup.add(nodeMesh);
nodeData.push(nodeMesh);

// glow (a transparent, slightly larger sprite)


const spriteMat = new THREE.SpriteMaterial({
map: new THREE.TextureLoader().load(createGlowCanvas(color.getStyle())),
blending: THREE.AdditiveBlending,
opacity: 0.65,
depthWrite: false
});
const glow = new THREE.Sprite(spriteMat);
glow.scale.set(0.6 + d.value*0.6, 0.6 + d.value*0.6, 1);
glow.position.copy(pos);
nodeGroup.add(glow);

// label
const sprite = makeLabel(d.name + ' • ' + Math.round(d.value*100) + '%');
sprite.position.copy(pos.clone().multiplyScalar(1.06));
scene.add(sprite);
labelSprites.push(sprite);
}

// create connectors with smooth curve


const connGroup = new THREE.Group();
for(const pair of connections){
const a = nodeData.find(n=>n.userData.id===pair[0]);
const b = nodeData.find(n=>n.userData.id===pair[1]);
if(!a || !b) continue;
const mid = a.position.clone().add(b.position).multiplyScalar(0.5);
// push midpoint slightly outwards to create an arc
const direction = mid.clone().normalize();
const arcHeight = 0.6 + (a.userData.value + b.userData.value) * 0.5;
mid.add(direction.multiplyScalar(arcHeight));
const curve = new THREE.CatmullRomCurve3([a.position.clone(), mid,
b.position.clone()]);
const pts = curve.getPoints(60);
const geom = new THREE.BufferGeometry().setFromPoints(pts);
const mat = new THREE.LineBasicMaterial({color:0xffffff, linewidth:1,
transparent:true, opacity:0.45});
const line = new THREE.Line(geom, mat);
connGroup.add(line);
}
scene.add(connGroup);

// small subtle rim outline (2.5D layering effect)


const rim = new THREE.Mesh(
new THREE.SphereGeometry(globeRadius + 0.02, 64, 32),
new THREE.MeshBasicMaterial({color:0xffffff, transparent:true, opacity:0.035})
);
scene.add(rim);

// helpers
function createGlowCanvas(colorStyle){
const size = 128;
const c = document.createElement('canvas');
c.width=c.height=size;
const ctx = c.getContext('2d');
const g = ctx.createRadialGradient(size/2,size/2,0,size/2,size/2,size/2);
g.addColorStop(0, colorStyle);
g.addColorStop(0.2, colorStyle);
g.addColorStop(0.7, 'rgba(0,0,0,0.05)');
g.addColorStop(1, 'rgba(0,0,0,0)');
ctx.fillStyle = g;
ctx.fillRect(0,0,size,size);
return c.toDataURL();
}

// interaction: raycast hover for tiny pop


const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
let hovered = null;

function onPointerMove(e){
const rect = renderer.domElement.getBoundingClientRect();
pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
}
window.addEventListener('pointermove', onPointerMove);

renderer.domElement.addEventListener('click', (e)=>{
if(hovered){
alert('Clicked: ' + hovered.userData.name + '\\nvalue: ' +
hovered.userData.value);
}
});

// UI bindings
const nodeScaleEl = document.getElementById('nodeScale');
const autoRotateEl = document.getElementById('autoRotate');
const toggleLabels = document.getElementById('toggleLabels');
let labelsOn = true;
toggleLabels.addEventListener('click', (ev)=>{ev.preventDefault(); labelsOn = !
labelsOn; labelSprites.forEach(s=>s.visible=labelsOn);});

window.addEventListener('resize', ()=>{
camera.aspect = innerWidth/innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});

// animation
const clock = new THREE.Clock();

function animate(){
requestAnimationFrame(animate);
const t = clock.getElapsedTime();

// gentle globe breathing / parallax (2.5D feel)


globeMesh.rotation.y += (autoRotateEl.checked ? 0.004 : 0) ;
gridLines.rotation.y = globeMesh.rotation.y * 0.98;
rim.rotation.copy(globeMesh.rotation);

// node subtle bob & face labels to camera


const scaleFactor = parseFloat(nodeScaleEl.value);
nodeData.forEach((n, i)=>{
// bobbing
const offset = 0.06 * Math.sin(t*1.2 + i);
const target =
n.userData.basePos.clone().normalize().multiplyScalar(globeRadius + 0.06 +
n.userData.value*0.12 + offset);
n.position.lerp(target, 0.08);
// scale by UI
n.scale.setScalar(scaleFactor);
// label facing camera
labelSprites[i].position.copy(n.position.clone().multiplyScalar(1.06));
labelSprites[i].lookAt(camera.position);
});

// hover detection
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(nodeData, false);
if(intersects.length){
const obj = intersects[0].object;
if(hovered !== obj){
if(hovered) hovered.material.emissive.multiplyScalar(0.2);
hovered = obj;
hovered.material.emissive = hovered.material.emissive.clone().add(new
THREE.Color(0x333333));
}
} else {
if(hovered) {
// restore
hovered.material.emissive.multiplyScalar(0.6);
hovered = null;
}
}

controls.update();
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>

You might also like