UNPKG

wordpress-plugin

Version:

Boilerplate WordPress Plugin structure to support development of JavaScript frameworks: React, Vue, Vanilla, TypeScript, supporting Vite, NextJS, Nuxt, Gatsby, and JSX/TSX Components (like MUI), CSS (like Tailwind + Unity), data APIs (like REST and GraphQ

1,411 lines (1,210 loc) 67.9 kB
/** * ThreeDGarden - Custom Admin JavaScript * *************************************************************************************** */ class Game { /** INIT CLASS CONSTRUCTOR */ constructor() { /** PARAMETERS FROM PHP */ const pluginName = postdata.plugin_name; const pluginVersion = postdata.plugin_version; const pluginURL = postdata.plugin_url; const themeURI = postdata.theme_uri; const restURL = postdata.rest_url; const worldID = postdata.world_id; console.log("-----------------------"); console.log("pluginName-------------"); console.log(pluginName, pluginVersion); console.log("-----------------------"); /** INSTANTIATE COMMON VARIABLES */ this.scene; this.grid; this.camera; this.controls; this.gui; this.gui = new dat.GUI({ autoPlace: true, closeOnTop: true }); this.gui.close(); this.gui.domElement.id = 'gui'; this.guiFolderRotation = this.gui.addFolder("Rotation + Animation"); //this.guiFolderAnimation = this.guiFolderRotation.addFolder("Animation"); this.guiFolderCameras = this.gui.addFolder("Camera Position"); this.guiFolderLights = this.gui.addFolder("Directional Light"); this.guiFolderAllotments = this.gui.addFolder("Allotments"); this.guiFolderBeds = this.gui.addFolder("Beds"); this.guiFolderPlants = this.gui.addFolder("Plants"); //this.guiFolderInfospots = this.gui.addFolder("Infospots"); this.guiFolderAnnotations = this.gui.addFolder("Annotations"); this.renderer; this.container; this.canvas; this.loader = new THREE.TextureLoader(); this.params = { ANIMATE: false, data: { world: [{id: worldID}], scene: [], allotment: [], bed: [], plant: [], planting_plan: [] } }; this.guiFolderRotation.add(this.params, "ANIMATE").name("Run Animation"); /** POINTER HOVERS + CLICKS */ this.raycaster = new THREE.Raycaster(); this.pointer = new THREE.Vector2(); this.INTERSECTED1; this.INTERSECTED2; /** REST API URLS */ this.API_URL_SCENES = `${restURL}scene/?_embed&per_page=100`; this.API_URL_ALLOTMENTS = `${restURL}allotment/?_embed&per_page=100`; this.API_URL_BEDS = `${restURL}bed/?_embed&per_page=100`; this.API_URL_PLANTING_PLANS = `${restURL}planting_plan/?_embed&per_page=100`; this.API_URL_PLANTS = `${restURL}plant/?_embed&per_page=100`; this.api_urls = [ this.API_URL_SCENES, this.API_URL_ALLOTMENTS, this.API_URL_BEDS, this.API_URL_PLANTING_PLANS, this.API_URL_PLANTS ]; // assign this scope to game const game = this; this.assetsPath = '../assets/'; this.clock = new THREE.Clock(); this.init(); window.onError = function(error){ console.error(JSON.stringify(error)); } } init() { /** FETCH ALL DATA *********************************************************************** */ Promise.allSettled( this.api_urls.map( url => fetch(url) .then(results => results.json()) .then(data => { let type = data[0].type; switch (type) { case "scene" : this.params.data.scene = [...data]; break; case "allotment" : this.params.data.allotment = [...data]; break; case "bed" : this.params.data.bed = [...data]; break; case "plant" : this.params.data.plant = [...data]; break; case "planting_plan" : this.params.data.planting_plan = [...data]; break; default : break; } // console.log("-----------------"); // console.log(data); // console.log("-----------------"); }) .catch(() => { return null }) ) ) .then(results => { // (*) //console.log(results); results.forEach((result, num) => { if (result.status == "fulfilled") { //alert(`${urls[num]}: ${result.value.status}`); //console.log(result); } if (result.status == "rejected") { //alert(`${urls[num]}: ${result.reason}`); console.log(result); } }) console.log("-----------------"); console.log("this.params.data------"); console.log(this.params.data); console.log("-----------------"); /** * init scene constructor */ this.buildScene(); } ) .catch(() => { return null }); //throwError(); } /** * BUILD SCENE * *************************************************************************************** */ buildScene() { // console.log("-----------------------"); // console.log("this.params.data.scene------"); // console.log(this.params.data.scene); // console.log(this.params.data.scene.length); // console.log("-----------------------"); let wpScene = this.params.data.scene[0]; this.sceneID = wpScene.id; console.log("-----------------------"); console.log("wpScene----------------"); console.log(wpScene); console.log("-----------------------"); /** THREE JS SCENE ******************************************************************* */ this.scene = new THREE.Scene(); // load the 3D cube map? if ( wpScene.acf.scene_background_image_px ) { let cubeMapURLs = [ wpScene.acf.scene_background_image_px, wpScene.acf.scene_background_image_nx, wpScene.acf.scene_background_image_py, wpScene.acf.scene_background_image_ny, wpScene.acf.scene_background_image_pz, wpScene.acf.scene_background_image_nz ]; let reflectionCube = new THREE.CubeTextureLoader().load(cubeMapURLs); reflectionCube.format = THREE.RGBFormat; this.scene.background = reflectionCube; } // load the 2D background image? else if ( wpScene.acf.scene_background_image ) { // let bgTexture = loader.load(wpScene.acf.scene_background_image); // this.scene.background = bgTexture; let bgTexture = this.loader.load( wpScene.acf.scene_background_image, () => { const rt = new THREE.WebGLCubeRenderTarget(bgTexture.image.height); rt.fromEquirectangularTexture(renderer, bgTexture); this.scene.background = rt; } ); } // load the background color? else if ( wpScene.acf.scene_background_color ) { this.scene.background = new THREE.Color(wpScene.acf.scene_background_color); //this.scene.fog = new THREE.Fog(0xFFFFFF, 0, 500); } /** GEOMETRIES *********************************************************************** */ this.plane = this.getPlane( wpScene.acf.scene_plane_width_x, wpScene.acf.scene_plane_length_y, wpScene.acf.scene_plane_background_color ); this.plane.name = "plane-jane"; this.plane.rotation.x = -Math.PI / 2; // -90 degrees in radians //this.plane.position.z = 10; //this.plane.rotation.z += 0.002; this.guiFolderRotation.add(this.plane.rotation, "x", -Math.PI, Math.PI).listen(); this.guiFolderRotation.add(this.plane.rotation, "y", -Math.PI, Math.PI).listen(); this.guiFolderRotation.add(this.plane.rotation, "z", -Math.PI, Math.PI).listen(); /** TEXTURES ************************************************************************* */ if ( wpScene.acf.scene_plane_texture_image ) { this.plane.material.roughness = 0.0; //this.plane.material.map = this.loader.load('/wp-content/plugins/threed-garden/admin/media/textures/grasslight-big.jpg'); this.plane.material.map = this.loader.load(wpScene.acf.scene_plane_texture_image); // this.plane.material.bumpMap = this.loader.load('/wp-content/plugins/threed-garden/admin/media/textures/grasslight-big-nm.jpg'); // this.plane.material.bumpMap = this.loader.load(wpScene.acf.scene_plane_texture_image); // this.plane.material.bumpScale = 0.01; this.planeTextureMap = this.plane.material.map; this.planeTextureMap.wrapS = THREE.RepeatWrapping; this.planeTextureMap.wrapT = THREE.RepeatWrapping; this.planeTextureMap.repeat.set(4, 4); } /** GRID ***************************************************************************** */ this.grid = new THREE.GridHelper( 200, 50, 0x333333, 0x333333 ); this.grid.rotation.x = Math.PI/2; // 90 degrees in radians this.plane.add(this.grid); /** LIGHTS *************************************************************************** */ // this.pointLight = this.getPointLight(0xFFFFFF, 4.0); // this.pointLight.position.set( -20, -60, 20 ); // //this.pointLight.intensity = 3.0; // this.spotLight = this.getSpotLight(0xFFFFFF, 4.0); // this.spotLight.position.set( -20, -60, 20 ); // //this.spotLight.intensity = 3.0; this.directionalLight = this.getDirectionalLight(0xFFFFFF, 2.1); this.directionalLight.position.set( -90, -120, 120 ); //this.directionalLight.intensity = 2.4; this.helper = new THREE.CameraHelper(this.directionalLight.shadow.camera); this.ambientLight = this.getAmbientLight(0xFFFFFF, 0.2); //this.ambientLight.position.set( -100, -100, 25 ); //this.ambientLight.intensity = 3.0; this.guiFolderLights.add(this.directionalLight, "intensity", 0, 20); this.guiFolderLights.add(this.directionalLight.position, "x", -500, 500); this.guiFolderLights.add(this.directionalLight.position, "y", -500, 500); this.guiFolderLights.add(this.directionalLight.position, "z", -500, 500); /** SCENE ***************************************************************************** */ // add objects to scene //this.plane.add(this.structure); //this.plane.add(this.pointLight); //this.plane.add(this.spotLight); this.plane.add(this.directionalLight); this.plane.add(this.ambientLight); this.scene.add(this.helper); this.scene.add(this.plane); /** CAMERA **************************************************************************** */ this.camera = new THREE.PerspectiveCamera( 55, window.innerWidth/window.innerHeight, 0.1, 1000 ); this.camera.name = "garden-cam-1"; this.camera.position.set(86, 64, 182); //this.camera.lookAt(new THREE.Vector3(0, 0, 0)); // overridden by OrbitControls.target this.guiFolderCameras.add(this.camera.position, "x", -500, 500).listen(); this.guiFolderCameras.add(this.camera.position, "y", -500, 500).listen(); this.guiFolderCameras.add(this.camera.position, "z", -500, 500).listen(); /** RENDERER ************************************************************************** */ this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); this.renderer.shadowMap.enabled = true; this.renderer.setSize(window.innerWidth - 240, window.innerHeight - 100); // utilize javascript prototyping.. add variables to the dom element :) this.renderer.domElement.camera = this.camera; this.renderer.domElement.targetList = this.plane.children; this.renderer.domElement.addEventListener("pointermove", this.onPointerMove, false); this.renderer.domElement.addEventListener("pointerdown", this.onPointerDown, false); /** CONTROLS *************************************************************************** */ this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement); this.controls.enableDamping = true; this.controls.dampingFactor = 0.25; this.controls.enableZoom = true; this.controls.rotateSpeed = 0.5; this.controls.autoRotate = false; this.controls.autoRotateSpeed = 0.03; this.controls.minDistance = 0.01; this.controls.maxDistance = 240; this.controls.maxPolarAngle = Math.PI/2 - .04; this.controls.target = new THREE.Vector3(0, 0, 0); // where the camera actually points //this.controls.target.set(0, 5, 0); // alternate way of setting target of camera this.renderer.domElement.controls = this.controls; /** WEBGL CANVAS *********************************************************************** */ this.container = document.querySelector('#webgl'); this.container.append(this.gui.domElement); this.container.append(this.renderer.domElement); this.canvas = this.renderer.domElement; /** BUILD ALLOTMENTS ******************************************************************* */ this.buildAllotments( this.params.data.allotment, this.plane, this.sceneID // the post-to-post relationship <3 ); /** ANIMATE + RENDER (continuous rendering) ******************************************** */ //this.updateAnnotationPosition(this.camera, this.renderer.domElement); this.animate(); //return this.scene; } animate () { // assign this scope to game const game = this; requestAnimationFrame( function(){ game.animate(); } ); this.watchPointer(this.camera, this.plane.children); this.controls.update(); TWEEN.update(); // this.plane.rotation.x += 0.002; // this.plane.rotation.y += 0.002; if ( this.params.ANIMATE ) { this.plane.rotation.z -= 0.0007; } this.renderer.render(this.scene, this.camera); // infospot annotations // this.updateAnnotationOpacity(this.camera, 20, 25); // this.updateAnnotationPosition( // this.camera, // this.renderer.domElement.width, // this.renderer.domElement.height, // positionX, positionY, positionZ, annotation // ); } /** * BUILD "ALLOTMENTS" FROM REST API POST OBJECT ************************************************************ */ buildAllotments(postObject, plane, sceneID) { // console.log("-------------------------"); // console.log("postObject ALLOTMENTS----"); // console.log(postObject); // console.log("-------------------------"); var filteredPostObject = postObject.filter(function (obj) { return obj.acf.allotment_scene == sceneID; }); // console.log("filteredPostObject-------"); // console.log(filteredPostObject); // console.log("-------------------------"); filteredPostObject.forEach( function(key) { // console.log("-------------------------"); // console.log("key.id (postObject)------"); // console.log(key.id); // console.log(key); // console.log("-------------------------"); // BUILD ALLOTMENT OBJECT GROUP let allotment = {}; allotment.parameters = {}; allotment.position = {}; allotment.images = {}; allotment.parameters.x = parseInt(key.acf.allotment_width); allotment.parameters.y = parseInt(key.acf.allotment_length); allotment.parameters.z = parseInt(key.acf.allotment_height); // 0 allotment.position.x = parseInt(key.acf.allotment_position_x); allotment.position.y = parseInt(key.acf.allotment_position_y); allotment.position.z = parseInt(key.acf.allotment_position_z); allotment.images.texture = key.acf.allotment_texture_image; allotment.images.featured = game.getFeaturedImage(key); allotment.shape = key.acf.allotment_shape; allotment.color = key.acf.allotment_color; allotment.title = key.title.rendered; allotment.postID = key.id; allotment.description = key.content.rendered; allotment.link = key.link; console.log("-------------------------"); console.log("allotment----------------"); console.log(allotment); console.log("-------------------------"); let structure = game.getGeometry( allotment.shape, allotment.parameters.x, allotment.parameters.y, allotment.parameters.z, allotment.color ); // console.log("-------------------------"); // console.log("allotment structure----------"); // console.log(structure); // console.log("-------------------------"); structure.name = allotment.title; structure.userData.type = "structure"; structure.userData.postID = allotment.postID; structure.userData.description = allotment.description; structure.userData.annotation = allotment.title; structure.userData.link = allotment.link; structure.position.x = allotment.position.x; structure.position.y = allotment.position.y; structure.position.z = (structure.geometry.parameters.depth / 2) + allotment.position.z; // - 10 for gap between plane structure.material.roughness = 0.9; if (allotment.images.texture != null && allotment.images.texture != false) { structure.material.map = game.loader.load(allotment.images.texture); for (let i = 0; i < structure.material.length; i++) { // hightlight object //structure.material[i].color.set(0xff0000); structure.material[i].map = game.loader.load(allotment.images.texture); //structure.faces[i].materialIndex = 1; //console.log(intersects[i]); // structure.material[i].bumpMap = loader.load(allotment.images.texture); // structure.material[i].bumpScale = 0.05; let structureTextureMap = structure.material[i].map; structureTextureMap.wrapS = THREE.RepeatWrapping; structureTextureMap.wrapT = THREE.RepeatWrapping; structureTextureMap.repeat.set(4, 4); } } plane.add(structure); //this.guiFolderAllotments.add(structure.geometry.parameters, "depth", 0, allotment.parameters.z); // console.log("-------------------------"); // console.log("allotment----------------"); // console.log(structure); // console.log("-------------------------"); /** BUILD BEDS IN THIS ALLOTMENT ************************************************** */ // game.buildBeds( // game.params.data.bed, // plane, // allotment.postID, // the post-to-post relationship <3 // structure.position.x, structure.position.y, 0 //structure.position.z // ) /** INFOSPOTS ********************************************************************* */ let infospot = game.makeInfospotSphere( structure.name, structure.position.x, structure.position.y, allotment.parameters.z + 3, allotment.postID, structure.userData.annotation, structure.userData.link ); infospot.name = `INFOSPOT: ${structure.name}`; infospot.visible = true; game.guiFolderAllotments.add(infospot, "visible").name("InfoSphere").listen(); // plane.add(infospot); }); /** END ALLOTMENTS ****************************************************************** */ // console.log("-------------------------"); // console.log("plane.children-----------"); // console.log(plane.children); // console.log("-------------------------"); // return plane.children; } /** * BUILD "BEDS" FROM REST API POST OBJECT ************************************************************ */ buildBeds(postObject, plane, allotmentID, posOffsetX, posOffsetY, posOffsetZ) { console.log("-------------------------"); console.log("postObject BEDS----------"); console.log(postObject); console.log("-------------------------"); // only show beds for this allotment structure var filteredPostObject = postObject.filter(function (obj) { return obj.acf.bed_allotment == allotmentID; }); // console.log("filteredPostObject-------"); // console.log(filteredPostObject); // console.log("-------------------------"); filteredPostObject.forEach( function(key) { // console.log("-------------------------"); // console.log("key.id (postObject)------"); // console.log(key.id); // console.log(key); // console.log("-------------------------"); let bed = {}; bed.parameters = {}; bed.position = {}; bed.images = {}; bed.parameters.x = parseInt(key.acf.bed_width) / 12; bed.parameters.y = parseInt(key.acf.bed_length) / 12; bed.parameters.z = parseInt(key.acf.bed_height) / 12; bed.position.x = parseInt(key.acf.bed_position_x) / 12 + posOffsetX; bed.position.y = parseInt(key.acf.bed_position_y) / 12 + posOffsetY; bed.position.z = parseInt(key.acf.bed_position_z) / 12 + (bed.parameters.z / 2); // + posOffsetZ; bed.images.texture = key.acf.bed_texture_image; bed.images.featured = game.getFeaturedImage(key); bed.shape = key.acf.bed_shape; bed.color = key.acf.bed_color; bed.title = key.title.rendered; bed.postID = key.id; bed.description = key.content.rendered; bed.link = key.link; // console.log("-------------------------"); // console.log("bed----------------"); // console.log(bed); // console.log("-------------------------"); let structure = game.getGeometry( bed.shape, bed.parameters.x, bed.parameters.y, bed.parameters.z, bed.color ); structure.name = bed.title; structure.userData.type = "structure"; structure.userData.postID = bed.postID; structure.userData.description = bed.description; structure.userData.annotation = bed.title; structure.userData.link = bed.link; structure.position.x = bed.position.x ? bed.position.x : 0; structure.position.y = bed.position.y ? bed.position.y : 0; structure.position.z = bed.position.z ? bed.position.z : 0; //structure.rotation.x = -Math.PI / 2; // -90 degrees in radians structure.material.roughness = 0.9; if (bed.images.texture != null && bed.images.texture != false) { structure.material.map = game.loader.load(bed.images.texture); for (let i = 0; i < structure.material.length; i++) { // hightlight object //structure.material[i].color.set(0xff0000); structure.material[i].map = game.loader.load(bed.images.texture); //structure.faces[i].materialIndex = 1; //console.log(intersects[i]); // structure.material[i].bumpMap = loader.load(bed.images.texture); // structure.material[i].bumpScale = 0.05; let structureTextureMap = structure.material[i].map; structureTextureMap.wrapS = THREE.RepeatWrapping; structureTextureMap.wrapT = THREE.RepeatWrapping; structureTextureMap.repeat.set(4, 4); } } plane.add(structure); // console.log("-------------------------"); // console.log("bed----------------------"); // console.log(structure); // console.log("-------------------------"); /** BUILD PLANTS IN THIS BED, ACCORDING TO PLANTING PLANS ************************* */ buildPlantingPlans( game.params.data.planting_plan, plane, bed.postID, // the post-to-post relationship <3 structure.position.x, structure.position.y, 0 //structure.position.z ) /** INFOSPOTS ********************************************************************* */ let infospot = game.makeInfospotSphere( structure.name, structure.position.x, structure.position.y, bed.parameters.z + 3, bed.postID, structure.userData.annotation, structure.userData.link ); infospot.name = `INFOSPOT: ${structure.name}`; infospot.visible = false; game.guiFolderBeds.add(infospot, "visible").name("InfoSphere").listen(); plane.add(infospot); }); /** END BEDS *********************************************************************** */ // console.log("-------------------------"); // console.log("plane.children-----------"); // console.log(plane.children); // console.log("-------------------------"); // return plane.children; } /** * BUILD "PLANTS" FROM REST API POST OBJECT ************************************************************ */ buildPlantingPlans(postObject, plane, bedID, posOffsetX, posOffsetY, posOffsetZ) { // console.log("-------------------------"); // console.log("postObject PLANTING PLANS"); // console.log(postObject); // console.log("-------------------------"); // only show plants for this planting plan's bed structure var filteredPostObject = []; var matches = []; postObject.forEach(function (obj) { obj.acf.planting_plan_bed_plant_schedule.forEach(function(i) { if ( i.planting_plan_bed == bedID ) { //console.log("MATCHED at: ", i); //matches.push(i); //matches.push(obj); matches.pushIfNotExist(obj, function(e) { return e.id === obj.id; }); } }) filteredPostObject = [...matches]; }); // if ( filteredPostObject.length > 0 ) { // console.log("filteredPostObject-------"); // console.log(filteredPostObject); // console.log("-------------------------"); // } // for each planting plan.. filteredPostObject.forEach( function(key) { // console.log("-------------------------"); // console.log("key.id (filteredPostObject)------"); // console.log(key.id); // console.log(key); // console.log("-------------------------"); // for each planting plan bed-plant schedule.. key.acf.planting_plan_bed_plant_schedule.forEach(function(key2) { // console.log("key2-------"); // console.log(key2); // console.log("-------------------------"); // only for this bed.. if ( key2.planting_plan_bed == bedID ) { // show this plant (or multiple plants) in this bed.. var filteredPlant = params.data.plant.filter(function (obj) { return obj.id == key2.planting_plan_plant; }); // console.log("filteredPlant------------"); // console.log(filteredPlant); // console.log("-------------------------"); // for this plant in this bed.. filteredPlant.forEach(function(key3) { // console.log("key3---------------------"); // console.log(key3); // console.log("-------------------------"); let plant = {}; plant.parameters = {}; plant.position = {}; plant.images = {}; plant.parameters.x = parseInt(key3.acf.plant_width) / 12; plant.parameters.y = parseInt(key3.acf.plant_length) / 12; plant.parameters.z = parseInt(key3.acf.plant_height) / 12; plant.position.x = parseInt(key2.plant_position_x) / 12 + posOffsetX; plant.position.y = parseInt(key2.plant_position_y) / 12 + posOffsetY; plant.position.z = parseInt(key2.plant_position_z) / 12 + (plant.parameters.z / 2); // + posOffsetZ; plant.images.texture = key3.acf.plant_texture_image; plant.images.featured = getFeaturedImage(key); plant.shape = key3.acf.plant_shape; plant.color = key3.acf.plant_color; plant.title = key3.title.rendered; plant.postID = key3.id; plant.description = key3.content.rendered; plant.link = key3.link; // console.log("-------------------------"); // console.log("plant----------------"); // console.log(plant); // console.log("-------------------------"); let structure = getGeometry( "Tree", // "Bush", // plant.shape, plant.parameters.x, plant.parameters.y, plant.parameters.z, plant.color ); structure.name = plant.title; structure.userData.type = "structure"; structure.userData.postID = plant.postID; structure.userData.description = plant.description; structure.userData.annotation = plant.title; structure.userData.link = plant.link; structure.position.x = plant.position.x ? plant.position.x : 0; structure.position.y = plant.position.y ? plant.position.y : 0; structure.position.z = plant.position.z ? plant.position.z : 0; structure.rotation.x = Math.PI / 2; // 90 degrees in radians structure.material.roughness = 0.9; if (plant.images.texture != null && plant.images.texture != false) { structure.material.map = loader.load(plant.images.texture); for (let i = 0; i < structure.material.length; i++) { // hightlight object //structure.material[i].color.set(0xff0000); structure.material[i].map = loader.load(plant.images.texture); //structure.faces[i].materialIndex = 1; //console.log(intersects[i]); // structure.material[i].bumpMap = loader.load(plant.images.texture); // structure.material[i].bumpScale = 0.05; let structureTextureMap = structure.material[i].map; structureTextureMap.wrapS = THREE.RepeatWrapping; structureTextureMap.wrapT = THREE.RepeatWrapping; structureTextureMap.repeat.set(4, 4); } } plane.add(structure); console.log("-------------------------"); console.log("plant structure----------"); console.log(structure); console.log("-------------------------"); /** INFOSPOTS ********************************************************************* */ let infospot = makeInfospotSphere( structure.name, structure.position.x, structure.position.y, plant.parameters.z + 3, plant.postID, structure.userData.annotation, structure.userData.link ); infospot.name = `INFOSPOT: ${structure.name}`; infospot.visible = false; guiFolderBeds.add(infospot, "visible").name("InfoSphere").listen(); plane.add(infospot); }) } // end if }) }); /** END PLANTS *************************************************************************** */ // console.log("-------------------------"); // console.log("plane.children-----------"); // console.log(plane.children); // console.log("-------------------------"); // return plane.children; } getGeometry(shape, x, y, z, color){ let geometry; let material; let mesh; console.log("-------------------------"); console.log("mesh-----------"); console.log(mesh); console.log("-------------------------"); switch (shape) { case 'Box': geometry = new THREE.BoxGeometry(x, y, z); // let opacMaterial = new THREE.MeshStandardMaterial({ // transparent: true, // opacity: 0.0, // alphaTest: 1.0, // color: color, // side: THREE.DoubleSide, // depthWrite: false // }); material = new THREE.MeshStandardMaterial({ transparent: true, opacity: 0.8, color: color, side: THREE.DoubleSide, depthWrite: true }); mesh = new THREE.Mesh( geometry, [ material, material, material, material ] ); mesh.castShadow = true; break; case 'Cone': geometry = new THREE.ConeGeometry(x/2, y/2, z, 32, 1, true); material = new THREE.MeshStandardMaterial({ color: color, side: THREE.DoubleSide }); mesh = new THREE.Mesh(geometry, material); mesh.castShadow = true; mesh.rotation.x = Math.PI / 2; // 90 degrees in radians break; case 'Cylinder': geometry = new THREE.CylinderGeometry(x/2, y/2, z, 32, 1, true); material = new THREE.MeshStandardMaterial({ color: color, side: THREE.DoubleSide }); mesh = new THREE.Mesh(geometry, material); mesh.castShadow = true; mesh.rotation.x = Math.PI / 2; // 90 degrees in radians break; case 'InfoSphere': geometry = new THREE.SphereGeometry(x, y, z); material = new THREE.MeshStandardMaterial({ color: color, side: THREE.DoubleSide }); mesh = new THREE.Mesh(geometry, material); mesh.castShadow = true; //mesh.rotation.x = Math.PI / 2; // 90 degrees in radians break; case 'Sphere': geometry = new THREE.SphereGeometry(x, y, z); material = new THREE.MeshStandardMaterial({ color: color, side: THREE.DoubleSide }); mesh = new THREE.Mesh(geometry, material); mesh.castShadow = true; //mesh.rotation.x = Math.PI / 2; // 90 degrees in radians break; case 'Tree': let tree = new THREE.Tree({ generations : 3, // # for branch' hierarchy length : 1.0, // length of root branch uvLength : 3.0, // uv.v ratio against geometry length (recommended is generations * length) radius : 0.1, // radius of root branch radiusSegments : 8, // # of radius segments for each branch geometry heightSegments : 8 // # of height segments for each branch geometry }); geometry = THREE.TreeGeometry.build(tree); //geometry = new THREE.SphereGeometry(x, y, z); material = new THREE.MeshStandardMaterial({ color: color, side: THREE.DoubleSide }); mesh = new THREE.Mesh(geometry, material); mesh.castShadow = true; //mesh.rotation.x = Math.PI / 2; // 90 degrees in radians break; // case 'Bush': // // CAST // geometry = new THREE.CubeGeometry(x, y, z); // //color = new THREE.Color(0xff0000); // color = new THREE.Color("rgb(153,90,0)"); // material = new THREE.MeshPhongMaterial({ color: color, wireframe: false }); // mesh = new THREE.Mesh(geometry, material); // scene.add(mesh); // mesh.matrix.makeTranslation(0,-125,0); // mesh.matrixAutoUpdate = false; // var levels = 4; // slow? lower this // var edge_w = 100; // var edge_h = 150; // function bush(n, mat, c) { // if(n > 0) { // var new_mat = new THREE.Matrix4(); // var new_mat2 = new THREE.Matrix4(); // var new_mat_t0 = new THREE.Matrix4(); // var new_mat_t = new THREE.Matrix4(); // var new_mat_r = new THREE.Matrix4(); // var new_mat_r2 = new THREE.Matrix4(); // var new_mat_s = new THREE.Matrix4(); // var mat2 = mat.clone(); // var col1 = c.clone(); // var col2 = c.clone(); // //col1.offsetHSL(0.12,0,0); // col1.g += 0.64/levels; // material = new THREE.MeshPhongMaterial( { color:col1, wireframe: false } ); // mesh = new THREE.Mesh(geometry, material); // new_mat_t0.makeTranslation(edge_w/2,0,0); // new_mat_t.makeTranslation(0,edge_h,0); // new_mat_r.makeRotationZ(-Math.PI/4); // new_mat_r2.makeRotationY(Math.PI/2); // new_mat_s.makeScale(0.75,0.75,0.75); // new_mat.multiply(new_mat_r2); // // new_mat.multiply(new_mat_t0); // new_mat.multiply(new_mat_r); // new_mat.multiply(new_mat_s); // new_mat.multiply(new_mat_t); // new_mat.multiply(mat); // mesh.matrix.copy(new_mat); // mesh.matrixAutoUpdate=false; // mesh.updateMatrix=false; // // scene.add(mesh); // bush(n-1, mesh.matrix.clone(), col1); // //col2.offsetHSL(0.12,0,0); // col2.g += 0.64/levels; // material = new THREE.MeshPhongMaterial( { color:col2, wireframe: false } ); // mesh = new THREE.Mesh(geometry, material); // new_mat_t0.makeTranslation(-edge_w/2,0,0); // new_mat_t.makeTranslation(0,edge_h,0); // new_mat_r.makeRotationZ(Math.PI/4); // new_mat_r2.makeRotationY(Math.PI/2); // new_mat_s.makeScale(0.75,0.75,0.75); // new_mat2.multiply(new_mat_r2); // // new_mat2.multiply(new_mat_t0); // new_mat2.multiply(new_mat_r); // new_mat2.multiply(new_mat_s); // new_mat2.multiply(new_mat_t); // new_mat2.multiply(mat); // mesh.matrix.copy(new_mat2); // mesh.matrixAutoUpdate=false; // mesh.updateMatrix=false; // // scene.add(mesh); // bush(n-1, mesh.matrix.clone(), col2); // } // } // bush(levels, mesh.matrix, color); default: geometry = new THREE.BoxGeometry(x, y, z); material = new THREE.MeshStandardMaterial({ color: color, side: THREE.DoubleSide }); mesh = new THREE.Mesh(geometry, material); mesh.castShadow = true; break; } console.log("-------------------------"); console.log("mesh-----------"); console.log(mesh); console.log("-------------------------"); return mesh; } getPlane(x, y, color){ let geometry = new THREE.PlaneGeometry(x, y); let material = new THREE.MeshStandardMaterial({ color: color, side: THREE.DoubleSide }); let mesh = new THREE.Mesh(geometry, material); mesh.receiveShadow = true; return mesh; } getPointLight(color, intensity){ let light = new THREE.PointLight(color, intensity); light.castShadow = true; light.shadow.bias = 0.001; light.shadow.mapSize.width = 4096; //default = 1024 light.shadow.mapSize.height = 4096; //default = 1024 return light; } getSpotLight(color, intensity){ let light = new THREE.SpotLight(color, intensity); light.castShadow = true; light.shadow.bias = 0.001; light.shadow.mapSize.width = 2048; //default = 1024 light.shadow.mapSize.height = 2048; //default = 1024 return light; } getDirectionalLight(color, intensity){ let light = new THREE.DirectionalLight(color, intensity); light.castShadow = true; light.shadow.bias = 0.001; light.shadow.mapSize.width = 4096; //default = 1024 light.shadow.mapSize.height = 4096; //default = 1024 light.shadow.camera.left = -1000; //default = -5 light.shadow.camera.bottom = -1000; //default = -5 light.shadow.camera.right = 1000; //default = 5 light.shadow.camera.top = 1000; //default = 5 return light; } getAmbientLight(color, intensity){ let light = new THREE.AmbientLight(color, intensity); return light; } /** * INFOSPOTS ************************************************************************************** */ makeInfospotSprite(message, positionX, positionY, positionZ) { /** * infospot */ let infospotCanvas = document.querySelector("#infospot") let ctx = infospotCanvas.getContext("2d"); let x = 32; let y = 32; let radius = 30; let startAngle = 0; let endAngle = Math.PI * 2; // background ctx.fillStyle = "rgba(0, 0, 0, 0.8)"; ctx.beginPath(); ctx.arc(x, y, radius, startAngle, endAngle); ctx.fill(); // border ctx.strokeStyle = "rgba(255, 255, 255, 0.8)"; ctx.lineWidth = 4; ctx.beginPath(); ctx.arc(x, y, radius, startAngle, endAngle); ctx.stroke(); // foreground ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; ctx.font = "40px sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; // text ctx.fillText(message, x, y); const infospotTexture = new THREE.CanvasTexture( infospotCanvas[0] //document.querySelector("#infospot") //$("#infospot") ); const infospotMaterial = new THREE.SpriteMaterial({ map: infospotTexture, opacity: 0.8, transparent: true, depthTest: false, depthWrite: false }); let infospot = new THREE.Sprite(infospotMaterial); infospot.position.set(positionX, positionY, positionZ); infospot.scale.set(2, 2, 2); infospot.visible = true; return infospot; } makeInfospotSphere(message, positionX, positionY, positionZ, postID, contentHTML, link) { /** * INFOSPOT ******************************************************************** */ let structure = game.getGeometry( "InfoSphere", 0.90, // radius 32, // width segments 32, // height segments 0x2e3959 ); structure.name = message; structure.userData.type = "infospot"; structure.userData.postID = postID; structure.userData.description = ""; structure.userData.annotation = contentHTML; structure.userData.link = link; // structure.position.x = positionX; // structure.position.y = positionY; // structure.position.z = positionZ; structure.position.set(positionX, positionY, positionZ); //structure.rotation.x = -Math.PI / 2; // -90 degrees in radians //structure.scale.set(2, 2, 2); structure.visible = true; /** * ANNOTATION ****************************************************************** */ // let vector = new THREE.Vector3(structure.position.x, structure.position.y, 0); //camera.position.z //structure.position.z // camera.updateProjectionMatrix(); // camera.updateMatrixWorld(); // let vector = new THREE.Vector3(); // vector.setFromMatrixPosition(structure.matrixWorld); vector.project(camera); vector.x = Math.round((0.5 + vector.x / 2) * (game.renderer.domElement.width / window.devicePixelRatio)); vector.y = Math.round((0.5 - vector.y / 2) * (game.renderer.domElement.height / window.devicePixelRatio)); // vector.x = (structure.position.x / (window.innerWidth - 240)) * 2 - 1; // vector.y = -(structure.position.y / (window.innerHeight - 100)) * 2 + 1; // vector.x = Math.round( ( vector.x + 1 ) * game.renderer.domElement.width / 2 ); // vector.y = Math.round( ( - vector.y + 1 ) * game.renderer.domElement.height / 2 ); let annoPosTop = vector.x; let annoPosLeft = vector.y; // // let annoPosTop = 100; // let annoPosLeft = 240; let annotation = game.makeAnnotation( structure.userData.link, structure.name, annoPosTop, annoPosLeft ) annotation.name = `ANNOTATION: ${structure.name}`; annotation.userData.type = "annotation"; annotation.userData.postID = postID; annotation.userData.description = ""; annotation.userData.annotation = structure.name; annotation.userData.link = link; annotation.visible = false; // does nothing, but keeps status accurate // console.log("-------------------------"); // console.log("annotation---------------------"); // console.log(annotation); // console.log("-------------------------"); structure.add(annotation); return structure; } makeAnnotation(link, contentHTML, positionX, positionY) { let annoDiv = document.createElement('div'); annoDiv.classList.add("annotation"); annoDiv.innerHTML = ` <a href="${link}" target="_blank">${contentHTML}</a> (${positionX}, ${positionY}) <span class="dismiss" onclick="dismiss(this);">x</span> `; annoDiv.hidden = true; annoDiv.style.display = "none"; //block annoDiv.style.top = `${positionY}px`; annoDiv.style.left = `${positionX}px`; game.guiFolderAnnotations.add(annoDiv, "hidden").listen(); game.guiFolderAnnotations.add(annoDiv.style, "display").listen(); game.guiFolderAnnotations.add(annoDiv.style, "top").listen(); game.guiFolderAnnotations.add(annoDiv.style, "left").listen(); document.body.appendChild( annoDiv ); // Make the DIV element draggable game.dragElement(annoDiv); let cssObject = new THREE.CSS3DObject( annoDiv ); // trying to do stuff to a cssObject does nothing :( // // we reference the same position and rotation // cssObject.position = rendererDomElement.position; // cssObject.rotation = rendererDomElement.rotation; // cssObject.position.set(positionX, positionY, positionZ); // cssObject.scale.set(3, 3, 3); // cssObject.visible = true; // console.log("------------------"); // console.log("cssObject---------"); // console.log(cssObject); // console.log("------------------"); //return annoDiv; return cssObject; } makeTextSprite(message, parameters) { if ( parameters === undefined ) parameters = {}; let fontface = parameters.hasOwnProperty("fontface") ? parameters["fontface"] : "Arial"; let fontsize = parameters.hasOwnProperty("fontsize") ? parameters["fontsize"] : 18; let borderThickness = parameters.hasOwnProperty("borderThickness") ? parameters["borderThickness"] : 4; let borderColor = parameters.hasOwnProperty("borderColor") ? parameters["borderColor"] : { r:0, g:0, b:0, a:1.0 }; let backgroundColor = parameters.hasOwnProperty("backgroundColor") ? parameters["backgroundColor"] : { r:255, g:255, b:255, a:1.0 }; let newCanvas = document.createElement('canvas'); let context = newCanvas.getContext('2d'); context.font = "Bold " + fontsize + "px " + fontface; //context.textAlign = "center"; // get size data (height depends only on font size) let metrics = context.measureText( message ); let textWidth = metrics.width; // console.log("-------------------------"); // console.log("metrics------------------"); // console.log(textWidth); // console.log("-------------------------"); // background color context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + "," + backgroundColor.b + "," + backgroundColor.a + ")"; // border color context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + "," + borderColor.b + "," + borderColor.a + ")"; context.lineWidth = borderThickness; game.roundRect( context, borderThickness/2, borderThickness/2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6 ); // 1.4 is extra height factor for text below baseline: g,j,p,q. // text color context.fillStyle = "rgba(0, 0, 0, 1.0)"; context.fillText( message, borderThickness, fontsize + borderThickness); // canvas contents will be used for a texture let texture = new THREE.Texture(newCanvas); texture.needsUpdate = true; let spriteMaterial = new THREE.SpriteMaterial( { map: texture, transparent: true, depthTest: false, depthWrite: false } //, useScreenCoordinates: false, alignment: spriteAlignment ); let sprite = new THREE.Sprite( spriteMaterial ); sprite.scale.set(50, 25, 1.0); return sprite; } // function for drawing rounded rectangles roundRect(ctx, x, y, w, h, r) { ctx.beginPath(); ctx.moveTo(x+r, y); ctx.lineTo(x+w-r, y); ctx.quadraticCurveTo(x+w, y, x+w, y+r); ctx.lineTo(x+w, y+h-r); ctx.quadraticCurveTo(x+w, y+h, x+w-r, y+h); ctx.lineTo(x+r, y+h); ctx.quadraticCurveTo(x, y+h, x, y+h-r); ctx.lineTo(x, y+r); ctx.quadraticCurveTo(x, y, x+r, y); ctx.closePath(); ctx.fill(); ctx.stroke(); } updateAnnotationOpacity(camera, meshPosition, annotationPosition) { const meshDistance = camera.position.distanceTo(meshPosition); const annotationDistance = camera.position.distanceTo(annotationPosition); let annotationBehindObject = annotationDistance > meshDistance; //annotation.material.opacity = annotationBehindObject ? 0.5 : 1; // Do you want an infospot that changes size according to its position? // Comment out the following line and the `::before` pseudo-element. //annotation.material.opacity = 1; } updateAnnotationPosition(camera, width, height, positionX, positionY, positionZ, annotation) { let vector = new THREE.Vector3(positionX, positionY, positionZ); //let annotation = $(".annotation")[0]; vector.project(camera); vector.x = Math.round((0.5 + vector.x / 2) * (width / window.devicePixelRatio)); vector.y = Math.round((0.5 - vector.y / 2) * (height / window.devicePixelRatio)); annotation.style.top = `${vector.y}px`; annotation.style.left = `${vector.x}px`; //annotation.style.opacity = annotationBehindObject ? 0.25 : 1; annotation.style.opacity = 1; annotation.style.display = "block"; // console.log("------------------"); // console.log("annotation--------"); // console.log(annotation); // console.log("------------------"); } /** * POINTER HOVERS + CLICKS ******************************************************************** */ // when the pointer moves and hovers watchPointer(camera, targetList){ // update the picking ray with the camera and pointer position this.raycaster.setFromCamera(game.pointer, camera); //raycaster.set( camera.getWorldPosition(), camera.getWorldDirection() ); //let helper2 = new THREE.CameraHelper(directionalLight.shadow.camera); // calculate objects intersecting the picking ray const intersects = this.raycaster.intersectObjects(targetList); // if there is one (or more) intersections if ( intersects.length > 0 ) { /* do something to object intersected? (testing purposes only) for (let i = 0; i < intersects.length; i++) { // hightlight object for (let j = 0; j < intersects[i].object.material.length; j++) { intersects[i].object.material[j].color.setHex( 0xff0000 ); } } */ // if the closest object intersected is not the currently stored intersection object if ( intersects[0].object != this.INTERSECTED1 ) { // restore previous intersection object (if it exists) to its original color if ( this.INTERSECTED1 ) { if ( this.INTERSECTED1.material.constructor.name == "Array" ) { for (let i = 0; i < this.INTERSECTED1.material.length; i++) { this.INTERSECTED1.material[i].color.setHex( this.INTERSECTED1.currentHex ); } } else { this.INTERSECTED1.material.color.setHex( this.INTERSECTED1.currentHex ); } } // store reference to closest object as current intersection object this.INTERSECTED1 = intersects[0].object; // console.log("-------------------------"); // console.log("this.INTERSECTED1-------------"); // console.log(this.INTERSECTED1); // console.log("-------------------------"); if ( this.INTERSECTED1.material.constructor.name == "Array" ) { // SEPARATE FOR LOOPS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // store color of closest object (for later restoration) for (let i = 0; i < this.INTERSECTED1.material.length; i++) { this.INTERSECTED1.currentHex = this.INTERSECTED1.material[i].color.getHex(); } // set a new color for closest object for (let i = 0; i < this.INTERSECTED1.material.length; i++) { this.INTERSECTED1.material[i].color.setHex( 0xdddd00 ); } // SEPARATE FOR LOOPS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } else { // store color of closest object (for later restoration) this.INTERSECTED1.currentHex = this.INTERSECTED1.material.color.getHex(); // set a new color for closest object this.INTERSECTED1.material.color.setHex( 0xdddd00 ); } } } // there are no intersections else { // restore p