Test: Difference between revisions

From Open Source Ecology
Jump to navigation Jump to search
(Undo revision 228353 by Marcin (talk))
No edit summary
 
(100 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