Test: Difference between revisions

From Open Source Ecology
Jump to navigation Jump to search
No edit summary
No edit summary
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
<html>
<div id="ose-3d-mindmap" style="width:100%; height:700px; border:1px solid #ccc; overflow:hidden; position:relative;"></div>


{|style="float:right;border:1px solid black"
<script src="https://unpkg.com/three@0.160.0/build/three.min.js"></script>
| {{Infobox
<script src="https://unpkg.com/three@0.160.0/examples/js/controls/OrbitControls.js"></script>
|name        = Infobox
|bodystyle    =
|title        = New Project Name
|titlestyle  =  


|image        = [[File:check.png|200px|alt=Example alt text]]
<script>
|imagestyle   =  
(function () {
|caption      = Short description
   const container = document.getElementById('ose-3d-mindmap');
|captionstyle =
   if (!container) return;
|headerstyle  = background:#ccf;
|labelstyle   = background:#ddf;
|datastyle    =


|header1 = Specifications
   const words = [
|label1  = dfd
    "collaborative",
|data1   = dfd
    "design",
|header2 =
    "for",
|label2  = Product Ecology
    "a",
|data2  = What other GVCS tools does this use?
    "transparent",
|header3 =
    "and",
|label3  = License
    "inclusive",
|data3  = [[OSHWA]] and [[OSI]] compliant. CC-BY-SA-4.0 International, GPLv3, [[DIN SPEC 3105]].
    "economy",
|header4 =
    "of",
|label4  = Module 1
    "abundance"
|data4  = Describe features of Module 1
   ];
|header5 =
|label5  = Module 2
|data5  = Describe features of Module 2
|header6 =
|label6  = Key Specification
|data6  = Key spec data point
|header7 =
|label7  = Construction
|data7  = Describe basic construction technique and materials
|header8 =
|label8  = Productivity
|data8  = Describe how this relates to industrial productivity on a small scale
|header9 = Completion Status
|label9  =
|data9  =
|header10 =
|label10  =
|data10   = Describe whether built, prototyped, etc. Link to relevant [[Genealogy]] and [[Status of Completion]].


  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0xffffff);


  const camera = new THREE.PerspectiveCamera(
    50,
    container.clientWidth / container.clientHeight,
    0.1,
    2000
  );
  camera.position.set(0, 0, 260);


|belowstyle = background:#ddf;
  const renderer = new THREE.WebGLRenderer({ antialias: true });
|below = Do you want more of this? [[Get Involved]]
  renderer.setPixelRatio(window.devicePixelRatio || 1);
}}
  renderer.setSize(container.clientWidth, container.clientHeight);
|}
  container.appendChild(renderer.domElement);


=Development=
  const controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.08;
  controls.rotateSpeed = 0.8;
  controls.zoomSpeed = 0.9;
  controls.panSpeed = 0.7;


  const ambient = new THREE.AmbientLight(0xffffff, 1.2);
  scene.add(ambient);


{| class="wikitable"
  const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
|+ Development Template
  dirLight.position.set(120, 150, 200);
!
  scene.add(dirLight);
! Description
! Link to Work Product
! %


|-
  function makeTextSprite(message) {
! scope=row |
    const canvas = document.createElement('canvas');
| '''DESIGN''' ||  || 
    const ctx = canvas.getContext('2d');


|-
    const fontSize = 48;
! scope=row | 1
    const paddingX = 28;
| [[Requirements + Value Proposition]] ||  [[New Project Name Requirements + Value Proposition]]  || 50
    const paddingY = 18;
    ctx.font = 'bold ' + fontSize + 'px Arial';


|-
    const textWidth = Math.ceil(ctx.measureText(message).width);
! scope=row | 2
    canvas.width = textWidth + paddingX * 2;
| [[Industry_Standards]] || [[New Project Name Industry Standards]] || 0
    canvas.height = fontSize + paddingY * 2;


|-
    ctx.font = 'bold ' + fontSize + 'px Arial';
! scope=row | 3
    ctx.textBaseline = 'middle';
| [[Conceptual Design]] || [[New Project Name Conceptual Design]] || 0
    ctx.textAlign = 'center';


|-
    ctx.fillStyle = 'rgba(255,255,255,0.92)';
! scope=row | 4
    ctx.strokeStyle = 'rgba(40,40,40,0.9)';
| [[Module Breakdown]] || [[New Project Name Module Breakdown]]  || 0
    ctx.lineWidth = 3;
    roundRect(ctx, 2, 2, canvas.width - 4, canvas.height - 4, 14, true, true);


|-
    ctx.fillStyle = '#111111';
! scope=row | 5
    ctx.fillText(message, canvas.width / 2, canvas.height / 2);
| [[Design Guide]] || [[New Project Name Design Guide]] || 0


|-
    const texture = new THREE.CanvasTexture(canvas);
! scope=row |
    texture.needsUpdate = true;
| '''TECHNICAL DESIGN''' ||  || 


|-
    const material = new THREE.SpriteMaterial({
! scope=row | 6
      map: texture,
| [[3D CAD]] || [[New Project Name 3D CAD]] || 0
      transparent: true
    });


|-
    const sprite = new THREE.Sprite(material);
! scope=row | 7
| [[Basic Calculations|Calculations]] || [[New Project Name Calculations]] || 0


|-
    const scale = 0.34;
! scope=row | 8
    sprite.scale.set(canvas.width * scale, canvas.height * scale, 1);
| [[Electronics Design]] || [[New Project Name Electronics Design]] || 0


|-
    return sprite;
! scope=row | 9
  }
| [[Wiring and Plumbing]] || [[New Project Name Wiring and Plumbing]] || 0


|-
  function roundRect(ctx, x, y, w, h, r, fill, stroke) {
! scope=row | 10
    if (w < 2 * r) r = w / 2;
| [[Software]] || [[New Project Name Software]] || 0
    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();
! scope=row |
  scene.add(nodeGroup);
| '''BILL OF MATERIALS ||  ||


|-
  const positions = [];
! scope=row | 11
  const radius = 95;
| [[Proper BOM|BOM]] || [[New Project Name BOM]] || 0


|-
  // Distribute words across a sphere
! scope=row | 12
  for (let i = 0; i < words.length; i++) {
| [[vBOM]] || [[New Project Name vBOM]] || 0
    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);
! scope=row | 13
    const y = radius * Math.sin(theta) * Math.sin(phi);
| [[CAM Files]] || [[New Project Name CAM Files]] || 0
    const z = radius * Math.cos(phi);


|-
    positions.push(new THREE.Vector3(x, y, z));
! scope=row | 14
| [[Cut List]] || [[New Project Name Cut List]] || 0


|-
    const sprite = makeTextSprite(words[i]);
! scope=row |
    sprite.position.set(x, y, z);
| '''BUILD''' || ||
    sprite.userData.word = words[i];
    nodeGroup.add(sprite);
  }


|-
  // Connect every word to every other word
! scope=row | 15
  const lineMaterial = new THREE.LineBasicMaterial({
| [[Build Instructions]] || [[New Project Name Build Instructions]] || 0
    color: 0x777777,
    transparent: true,
    opacity: 0.45
  });


|-
  for (let i = 0; i < positions.length; i++) {
! scope=row | 16
    for (let j = i + 1; j < positions.length; j++) {
| [[Fabrication Drawings]] || [[New Project Name Fabrication Drawings]] || 0
      const geometry = new THREE.BufferGeometry().setFromPoints([
        positions[i],
        positions[j]
      ]);
      const line = new THREE.Line(geometry, lineMaterial);
      scene.add(line);
    }
  }


|-
  // Small center marker
! scope=row | 17
  const centerGeom = new THREE.SphereGeometry(3, 16, 16);
| [[Exploded Part Diagram]] || [[New Project Name Exploded Part Diagram]] || 0
  const centerMat = new THREE.MeshBasicMaterial({ color: 0x222222 });
  const centerDot = new THREE.Mesh(centerGeom, centerMat);
  scene.add(centerDot);


|-
  const raycaster = new THREE.Raycaster();
! scope=row | 18
  const pointer = new THREE.Vector2();
| [[Production Engineering]] || [[New Project Name Production Engineering]] || 0


|-
  const info = document.createElement('div');
! scope=row |
  info.style.position = 'absolute';
| '''LIFECYCLE DESIGN''' || ||
  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) {
! scope=row | 19
    const rect = renderer.domElement.getBoundingClientRect();
| [[Build Pictures and Video]] || [[New Project Name Build Pictures and Video]] || 0
    pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
  }


|-
  function onClick() {
! scope=row | 20
    raycaster.setFromCamera(pointer, camera);
| [[Data Collection]] || [[New Project Name Data Collection]] || 0
    const intersects = raycaster.intersectObjects(nodeGroup.children, true);


|-
    if (intersects.length > 0) {
! scope=row | 21
      const obj = intersects[0].object;
| [[Future Work]] || [[New Project Name Future Work]] || 0
      if (obj.userData && obj.userData.word) {
        info.innerHTML = 'Selected: <b>' + obj.userData.word + '</b>';
      }
    }
  }


|-
  renderer.domElement.addEventListener('mousemove', onPointerMove);
! scope=row | 22
  renderer.domElement.addEventListener('click', onClick);
| [[Troubleshooting and Repair]] || [[New Project Name Troubleshooting and Repair]] || 0


|}
  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>

Latest revision as of 15:35, 4 April 2026