<!-- ShapeDiver Viewer Main Container -->
<div id='sdv-container' class='shapediver-container-flex shapediver-container-fullsize'
     sdv-fullscreen="true">
  <!-- ShapeDiver Viewer Settings Controls Container -->
  <div id='sdv-container-settings' class='shapediver-settings-flex' style='display: none;'></div>
  <!-- ShapeDiver Viewer Viewport Container -->
  <div class='shapediver-viewport-flex'>
    <div id='sdv-container-viewport' class='shapediver-container-fullsize' style='opacity: 0;' 
         logginglevel=0 messagelogginglevel=2>
    </div>
    <!-- The loading icon will be created here -->
  </div>
  <!-- ShapeDiver Viewer Parameter Controls Container -->
  <div id='sdv-container-controls' class='shapediver-controls-flex' style='display: none;'></div>
</div>
var positions;
var livePolyline;
var polylineAsset;
var ghPolyPath, ghDomePath;

// defining effects for hoverable and draggable objects
var hoverEffect = {
  active: {
    name: "colorHighlight",
    options: {
      color: [100, 0, 0]
    }
  }
};
var selectionEffect = {
  active: {
    name: "colorHighlight",
    options: {
      color: [255, 0, 0]
    }
  }
};

// defining a group of hoverable and selectable objects
var discGroup = {
  id: "discs",
  hoverable: true,
  hoverEffect: hoverEffect,
  draggable: true,
  dragEffect: selectionEffect
};

// ShapeDiver Viewer Initialisation
var initSdvApp = function (/*event*/) {
  // Settings can be defined here, or as attributes of the viewport container. Settings defined here take precedence.
  let settings = {
    ticket:
      "cb8278c8bfa097286d283c0925762604b70f78ca1628c16025f29ed500889d9df3ce80a4a72af0352fb0b924f2db212feb78d257cb0e5a2017dbb841f98cb137a564f50da7bf9d752ce26f925e9c95633276c03eadfef95543aca87159f183bbc44d05acb1a2836b5e5f24087437f8045ed39264e232-146fcf51ee3be65bd777d052c0eb9d97",
    modelViewUrl: "eu-central-1",
    showControlsInitial: false,
    showSettingsInitial: false
  };
  // See http://app.shapediver.com/api/SDVApp.ParametricViewer.html for all settings available via the constructor.
  window.api = new SDVApp.ParametricViewer(settings);
  var viewerInit = false;
  api.scene.addEventListener(api.scene.EVENTTYPE.VISIBILITY_ON, function () {
    if (!viewerInit) {
      api.scene.updateInteractionGroups(discGroup);
      let asset = api.scene.get(
        { name: "Points", format: "glb" },
        "CommPlugin_1"
      ).data[0];
      let updateObject = {
        id: asset.id,
        duration: 0,
        interactionGroup: discGroup.id,
        dragPlaneNormal: { x: 0, y: 0, z: 1 }
      };
      api.scene.updatePersistentAsync([updateObject], "CommPlugin_1");

      ghPolyPath = api.scene.get(
        { name: "Polyline", format: "glb" },
        "CommPlugin_1"
      ).data[0].scenePath;
      //ghDomePath = api.scene.get(
      //  { name: "Dome", format: "glb" },
      //  "CommPlugin_1"
      //).data[0].scenePath;
      api.scene.addEventListener(api.scene.EVENTTYPE.DRAG_START, function (
        event
      ) {
        //api.scene.toggleGeometry([], [ghPolyPath, ghDomePath]);
        api.scene.toggleGeometry([], [ghPolyPath]);
      });

      api.scene.addEventListener(api.scene.EVENTTYPE.DRAG_MOVE, updateLine);
      api.scene.addEventListener(api.scene.EVENTTYPE.DRAG_END, updatePoints);

      positions = JSON.parse(
        api.parameters.get({ name: "Positions" }).data[0].value
      );
      api.parameters.addEventListener(
        api.parameters.EVENTTYPE.VALUE_UPDATE,
        function () {
          positions = JSON.parse(
            api.parameters.get({ name: "Positions" }).data[0].value
          );
        }
      );

      // create the live polyline
      polylineAsset = polylineAsset(positions.points);
      api.scene.updateAsync([polylineAsset]);

      // snapping
      snapModule = new SDVApp.apps.snapModule(api);
      let _dragStart = function (e) {
        let index = parseInt(e.scenePath.split(".")[2].split("_")[1]);
        let pos = new THREE.Vector3(positions.points[index][0],
                                       positions.points[index][1],
                                       positions.points[index][2]);
        snapModule.addAnchorElement({
          id: "anchor",
          localPosition: pos
        });
        for (let i = 0; i < 30; i++) {
          for (let j = 0; j < 30; j++) {
            snapModule.addSnapPoint({
              id: "point_" + i.toString() + "_" + j.toString(),
              snapRadius: 0.1,
              position: new THREE.Vector3(-1+i*0.1,-1+j*0.1,0),
              anchorElements: ["anchor"]
            });
          }
        }
      };

      let _dragEnd = function (e) {
        console.log(e);
        snapModule.removeAnchorElement("anchor");
        for (let i = 0; i < 30; i++) {
          for (let j = 0; j < 30; j++) {
            snapModule.removeSnapPoint("point_" + i.toString() + "_" + j.toString());
          }
        }
      };
      snapModule.addEventListener(snapModule.EVENTTYPE.DRAG_START, _dragStart);
      snapModule.addEventListener(snapModule.EVENTTYPE.DRAG_END, _dragEnd);

      viewerInit = true;
    }
  });
};

// there is a slight chance that loading has been completed already
if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", initSdvApp, false);
} else {
  initSdvApp();
}

// update the polyline by calling a parameter update
var updatePoints = function (event) {
  let index = event.scenePath.split(".")[2].split("_")[1];
  let newPos = event.dragPosAbs;
  positions.points[index] = [
    parseFloat(newPos.x.toFixed(1)),
    parseFloat(newPos.y.toFixed(1)),
    parseFloat(newPos.z.toFixed(1))
  ];
  console.log(positions.points);
  api.parameters
    .updateAsync({ name: "Positions", value: JSON.stringify(positions) })
    .then(function () {
      //api.scene.toggleGeometry([ghPolyPath, ghDomePath], []);
      api.scene.toggleGeometry([ghPolyPath], []);
    });
};

// update the polyline live
var updateLine = function (event) {
  let index = parseInt(event.scenePath.split(".")[2].split("_")[1]);
  let newPos = event.dragPosAbs;
  let pos = livePolyline.geometry.attributes.position.array;
  pos[index * 3] = parseFloat(newPos.x.toFixed(1));
  pos[index * 3 + 1] = parseFloat(newPos.y.toFixed(1));
  pos[index * 3 + 2] = parseFloat(newPos.z.toFixed(1));

  livePolyline.geometry.attributes.position.needsUpdate = true;
  api.scene.render();
};

// create a LineLoop THREE objects from a list of points
var threeJSPolyline = function (points) {
  let points3D = [];
  for (let i = 0; i < points.length; i++) {
    points3D.push(new THREE.Vector3(points[i][0], points[i][1], points[i][2]));
  }
  let geometry = new THREE.BufferGeometry().setFromPoints(points3D);
  let polyline = new THREE.LineLoop(geometry, new THREE.LineBasicMaterial());
  livePolyline = polyline;
  return polyline;
};

// create a viewer asset for the polyline THREE object
var polylineAsset = function (points) {
  let polyline = threeJSPolyline(points);
  let material = {
    version: "2.0",
    color: "black"
  };
  let asset = {
    id: "polyline",
    content: [
      {
        format: api.scene.FORMAT.THREE,
        data: {
          threeObject: polyline
        }
      },
      {
        format: "material",
        data: material
      }
    ]
  };
  return asset;
};
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.