Test: Difference between revisions

From Open Source Ecology
Jump to navigation Jump to search
No edit summary
No edit summary
 
(102 intermediate revisions by the same user not shown)
Line 1: Line 1:
<!DOCTYPE html>
<html>
<html>
<head>
<div id="ose-3d-mindmap" style="width:100%; height:700px; border:1px solid #ccc; overflow:hidden; position:relative;"></div>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
  box-sizing: border-box;
}


.row::after {
<script src="https://unpkg.com/three@0.160.0/build/three.min.js"></script>
  content: "";
<script src="https://unpkg.com/three@0.160.0/examples/js/controls/OrbitControls.js"></script>
  clear: both;
  display: table;
}


[class*="col-"] {
<script>
   float: left;
(function () {
   padding: 15px;
   const container = document.getElementById('ose-3d-mindmap');
}
   if (!container) return;


html {
  const words = [
  font-family: "Lucida Sans", sans-serif;
    "collaborative",
}
    "design",
    "for",
    "a",
    "transparent",
    "and",
    "inclusive",
    "economy",
    "of",
    "abundance"
  ];


.header {
  const scene = new THREE.Scene();
   background-color: #9933cc;
   scene.background = new THREE.Color(0xffffff);
  color: #ffffff;
  padding: 15px;
}


.menu ul {
  const camera = new THREE.PerspectiveCamera(
   list-style-type: none;
    50,
   margin: 0;
    container.clientWidth / container.clientHeight,
  padding: 0;
    0.1,
}
    2000
   );
   camera.position.set(0, 0, 260);


.menu li {
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  padding: 8px;
   renderer.setPixelRatio(window.devicePixelRatio || 1);
   margin-bottom: 7px;
   renderer.setSize(container.clientWidth, container.clientHeight);
   background-color: #33b5e5;
   container.appendChild(renderer.domElement);
   color: #ffffff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
}


.menu li:hover {
  const controls = new THREE.OrbitControls(camera, renderer.domElement);
   background-color: #0099cc;
  controls.enableDamping = true;
}
   controls.dampingFactor = 0.08;
  controls.rotateSpeed = 0.8;
  controls.zoomSpeed = 0.9;
  controls.panSpeed = 0.7;


.aside {
  const ambient = new THREE.AmbientLight(0xffffff, 1.2);
  background-color: #33b5e5;
   scene.add(ambient);
  padding: 15px;
  color: #ffffff;
  text-align: center;
  font-size: 14px;
   box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
}


.footer {
  const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
  background-color: #0099cc;
   dirLight.position.set(120, 150, 200);
   color: #ffffff;
   scene.add(dirLight);
   text-align: center;
  font-size: 12px;
  padding: 15px;
}


/* For mobile phones: */
  function makeTextSprite(message) {
[class*="col-"] {
    const canvas = document.createElement('canvas');
  width: 100%;
    const ctx = canvas.getContext('2d');
}


@media only screen and (min-width: 600px) {
    const fontSize = 48;
  /* For tablets: */
    const paddingX = 28;
  .col-s-1 {width: 8.33%;}
    const paddingY = 18;
  .col-s-2 {width: 16.66%;}
    ctx.font = 'bold ' + fontSize + 'px Arial';
  .col-s-3 {width: 25%;}
  .col-s-4 {width: 33.33%;}
  .col-s-5 {width: 41.66%;}
  .col-s-6 {width: 50%;}
  .col-s-7 {width: 58.33%;}
  .col-s-8 {width: 66.66%;}
  .col-s-9 {width: 75%;}
  .col-s-10 {width: 83.33%;}
  .col-s-11 {width: 91.66%;}
  .col-s-12 {width: 100%;}
}
@media only screen and (min-width: 768px) {
  /* For desktop: */
  .col-1 {width: 8.33%;}
  .col-2 {width: 16.66%;}
  .col-3 {width: 25%;}
  .col-4 {width: 33.33%;}
  .col-5 {width: 41.66%;}
  .col-6 {width: 50%;}
  .col-7 {width: 58.33%;}
  .col-8 {width: 66.66%;}
  .col-9 {width: 75%;}
  .col-10 {width: 83.33%;}
  .col-11 {width: 91.66%;}
  .col-12 {width: 100%;}
}
</style>
</head>
<body>


<div class="header">
    const textWidth = Math.ceil(ctx.measureText(message).width);
  <h1>Chania</h1>
    canvas.width = textWidth + paddingX * 2;
</div>
    canvas.height = fontSize + paddingY * 2;


<div class="row">
    ctx.font = 'bold ' + fontSize + 'px Arial';
  <div class="col-3 col-s-3 menu">
    ctx.textBaseline = 'middle';
     <ul>
     ctx.textAlign = 'center';
      <li>The Flight</li>
      <li>The City</li>
      <li>The Island</li>
      <li>The Food</li>
    </ul>
  </div>


  <div class="col-6 col-s-9">
    ctx.fillStyle = 'rgba(255,255,255,0.92)';
     <h1>The City</h1>
    ctx.strokeStyle = 'rgba(40,40,40,0.9)';
     <p>Chania is the capital of the Chania region on the island of Crete. The city can be divided in two parts, the old town and the modern city.</p>
     ctx.lineWidth = 3;
  </div>
     roundRect(ctx, 2, 2, canvas.width - 4, canvas.height - 4, 14, true, true);


  <div class="col-3 col-s-12">
    ctx.fillStyle = '#111111';
     <div class="aside">
     ctx.fillText(message, canvas.width / 2, canvas.height / 2);
      <h2>What?</h2>
      <p>Chania is a city on the island of Crete.</p>
      <h2>Where?</h2>
      <p>Crete is a Greek island in the Mediterranean Sea.</p>
      <h2>How?</h2>
      <p>You can reach Chania airport from all over Europe.</p>
    </div>
  </div>
</div>


<div class="footer">
    const texture = new THREE.CanvasTexture(canvas);
  <p>Resize the browser window to see how the content respond to the resizing.</p>
    texture.needsUpdate = true;
</div>


</body>
    const material = new THREE.SpriteMaterial({
      map: texture,
      transparent: true
    });
 
    const sprite = new THREE.Sprite(material);
 
    const scale = 0.34;
    sprite.scale.set(canvas.width * scale, canvas.height * scale, 1);
 
    return sprite;
  }
 
  function roundRect(ctx, x, y, w, h, r, fill, stroke) {
    if (w < 2 * r) r = w / 2;
    if (h < 2 * r) r = h / 2;
    ctx.beginPath();
    ctx.moveTo(x + r, y);
    ctx.arcTo(x + w, y, x + w, y + h, r);
    ctx.arcTo(x + w, y + h, x, y + h, r);
    ctx.arcTo(x, y + h, x, y, r);
    ctx.arcTo(x, y, x + w, y, r);
    ctx.closePath();
    if (fill) ctx.fill();
    if (stroke) ctx.stroke();
  }
 
  const nodeGroup = new THREE.Group();
  scene.add(nodeGroup);
 
  const positions = [];
  const radius = 95;
 
  // Distribute words across a sphere
  for (let i = 0; i < words.length; i++) {
    const phi = Math.acos(-1 + (2 * i + 1) / words.length);
    const theta = Math.sqrt(words.length * Math.PI) * phi;
 
    const x = radius * Math.cos(theta) * Math.sin(phi);
    const y = radius * Math.sin(theta) * Math.sin(phi);
    const z = radius * Math.cos(phi);
 
    positions.push(new THREE.Vector3(x, y, z));
 
    const sprite = makeTextSprite(words[i]);
    sprite.position.set(x, y, z);
    sprite.userData.word = words[i];
    nodeGroup.add(sprite);
  }
 
  // Connect every word to every other word
  const lineMaterial = new THREE.LineBasicMaterial({
    color: 0x777777,
    transparent: true,
    opacity: 0.45
  });
 
  for (let i = 0; i < positions.length; i++) {
    for (let j = i + 1; j < positions.length; j++) {
      const geometry = new THREE.BufferGeometry().setFromPoints([
        positions[i],
        positions[j]
      ]);
      const line = new THREE.Line(geometry, lineMaterial);
      scene.add(line);
    }
  }
 
  // Small center marker
  const centerGeom = new THREE.SphereGeometry(3, 16, 16);
  const centerMat = new THREE.MeshBasicMaterial({ color: 0x222222 });
  const centerDot = new THREE.Mesh(centerGeom, centerMat);
  scene.add(centerDot);
 
  const raycaster = new THREE.Raycaster();
  const pointer = new THREE.Vector2();
 
  const info = document.createElement('div');
  info.style.position = 'absolute';
  info.style.left = '12px';
  info.style.top = '12px';
  info.style.padding = '8px 10px';
  info.style.background = 'rgba(255,255,255,0.9)';
  info.style.border = '1px solid #ccc';
  info.style.fontFamily = 'Arial, sans-serif';
  info.style.fontSize = '14px';
  info.style.color = '#111';
  info.style.zIndex = '10';
  info.innerHTML = 'Drag to rotate. Scroll to zoom. Click a word.';
  container.appendChild(info);
 
  function onPointerMove(event) {
    const rect = renderer.domElement.getBoundingClientRect();
    pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
  }
 
  function onClick() {
    raycaster.setFromCamera(pointer, camera);
    const intersects = raycaster.intersectObjects(nodeGroup.children, true);
 
    if (intersects.length > 0) {
      const obj = intersects[0].object;
      if (obj.userData && obj.userData.word) {
        info.innerHTML = 'Selected: <b>' + obj.userData.word + '</b>';
      }
    }
  }
 
  renderer.domElement.addEventListener('mousemove', onPointerMove);
  renderer.domElement.addEventListener('click', onClick);
 
  function resize() {
    const w = container.clientWidth;
    const h = container.clientHeight;
    camera.aspect = w / h;
    camera.updateProjectionMatrix();
    renderer.setSize(w, h);
  }
 
  window.addEventListener('resize', resize);
 
  function animate() {
    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
  }
 
  animate();
})();
</script>
</html>
</html>

Latest revision as of 15:35, 4 April 2026