My earth object renders fine, but I get about 6 different console errors saying “Cannot read property ‘render’ of undefined”. I have researched and it looks like it is somehow losing the context of the renderer object. I have declared the variable at the top of my JS file, so not sure how the context could be lost in my animate function… Here is my entire JS file:
//Define namespace
var EarthView3D = EarthView3D || {};
//THREE JS setup variables
var camera, scene, renderer, labelRenderer, earth;
$(document).ready(function () {
EarthView3D.GetSiteCoordList(); // This must run before initializing EarthView, Init() is called in success property or ajax call.
EarthView3D.Animate(); // This renders the initialized 3D Earth.
}); /* END DOCUMENT READY */
EarthView3D.GetSiteCoordList = function () {
$.ajax({
url: basePath + 'EarthView3D/GetSiteCoords',
type: 'GET',
dataType: 'html',
cache: false,
success: function (data) {
// Set the siteObjects, defined at the top of this file.
var siteObjects = JSON.parse(data);
EarthView3D.Init(siteObjects);
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Error retrieving site coordinates for earth view.');
},
complete: function (jqXHR, textStatus) {
}
});
}
EarthView3D.Init = function (siteObjects) {
const EARTH_RADIUS = 225;
const EARTH_SEGMENTS = 75;
const EARTH_RINGS = 75;
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000); //-87 pixels for header and dev environment bar.
camera.position.set(-70, 375, 500);
scene = new THREE.Scene();
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
scene.add(camera);
// Starfield
var starGeometry = new THREE.SphereGeometry(1000, 50, 50);
var starMaterial = new THREE.MeshPhongMaterial({
map: new THREE.ImageUtils.loadTexture(basePath + 'Content/images/galaxy_starfield.png'),
side: THREE.DoubleSide,
shininess: 0
});
var starField = new THREE.Mesh(starGeometry, starMaterial);
scene.add(starField);
// Create group to hold sphere and texture, makes up the earth.
earth = new THREE.Group();
scene.add(earth);
// Create sphere and texture, and mesh together using texture loader
var loader = new THREE.TextureLoader();
loader.load(basePath + 'Content/images/earth_clouds_16k.jpg', function (texture) {
// Create the sphere
var sphere = new THREE.SphereGeometry(EARTH_RADIUS, EARTH_SEGMENTS, EARTH_RINGS);
// Map the texture to the material.
var material = new THREE.MeshBasicMaterial({
map: texture
});
// Create a new mesh with sphere geometry.
var mesh = new THREE.Mesh(sphere, material);
// Add mesh to globe
earth.add(mesh);
});
scene.add(earth);
// Add siteObjects to Earth
for (var i = 0; i < siteObjects.length; i++) {
var siteID = siteObjects[i].ID;
var name = siteObjects[i].Name;
var lat = siteObjects[i].LAT;
var lon = siteObjects[i].LON;
var status = siteObjects[i].Status;
// Create dot for each site
var siteDiv = document.createElement('div');
siteDiv.className = 'dot';
siteDiv.setAttribute("id", name);
siteDiv.setAttribute("title", name);
siteDiv.style.backgroundColor =
status == "FMC" ? "green" :
status == "PMC" ? "yellow" : "red";
//Create label to append to each site's dot
var siteDivLabel = document.createElement('label');
siteDivLabel.setAttribute("id", name + '_label');
siteDivLabel.setAttribute("title", name + ' label');
siteDivLabel.textContent = name;
//Setting the label's class (Some labels need to display on different sides of the dot so that all can be seen in initial view.)
if (siteID == 6 || siteID == 9) { // 6 is BUckley, 9 is COD
siteDivLabel.className = 'label_top_right';
} else if (siteID == 12 || siteID == 20 || siteID == 19) { // 12 is FGA, 20 is PAFB, 19 is MDIOC
siteDivLabel.className = 'label_bottom_right';
} else if (siteID == 8) { // 8 is CMD
siteDivLabel.className = 'label_bottom_left';
} else {
siteDivLabel.className = 'label_top_left';
}
siteDiv.appendChild(siteDivLabel);
var siteDot = new THREE.CSS2DObject(siteDiv);
siteDiv.parent = siteDot;
siteDot.element.style.cursor = "pointer";
// Add click event for each dot/label that takes them to the site section for the dashboard homepage.
siteDot.element.onclick = function (e) {
var id = $(this).attr('id');
window.location = basePath + 'Dashboard?id=' + id;
};
var sitePosition = EarthView3D.CalcPosFromLatLonRad(lat, lon, EARTH_RADIUS);
// Some code to slightly move certain site markers around from their original position so that they don't overlap each other too much.
if (siteID == 5) { // 5 is boulder
siteDot.position.set(sitePosition[0] - 1, sitePosition[1] + 1, Math.abs(sitePosition[2]));
} else if (siteID == 8) { // 8 is CMD
siteDot.position.set(sitePosition[0] - 1, sitePosition[1] - 1, Math.abs(sitePosition[2]));
} else if (siteID == 20) { // 20 is PAFB
siteDot.position.set(sitePosition[0] + 1, sitePosition[1] - 6, Math.abs(sitePosition[2]));
} else if (siteID == 19) { // 19 is MDIOC
siteDot.position.set(sitePosition[0] + 5, sitePosition[1] + 4, Math.abs(sitePosition[2]));
} else if (siteID == 6) { // 6 is Buckley
siteDot.position.set(sitePosition[0] + 2, sitePosition[1] + 3, Math.abs(sitePosition[2]));
} else {
siteDot.position.set(sitePosition[0], sitePosition[1], Math.abs(sitePosition[2]));
}
earth.add(siteDot);
}
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor(0xffffff, 0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
var earthContainer = document.getElementById('earth_container');
earthContainer.appendChild(renderer.domElement);
labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = 0;
document.body.appendChild(labelRenderer.domElement);
// For rotation and mouse controls
var controls = new THREE.OrbitControls(camera, labelRenderer.domElement);
controls.minDistance = 300;
controls.maxDistance = 800;
};
/* Referenced from answer found here:
https://stackoverflow.com/questions/28365948/javascript-latitude-longitude-to-xyz-position-on-earth-threejs
*/
EarthView3D.CalcPosFromLatLonRad = function (lat, lon, radius) {
var phi = (90 - lat) * (Math.PI / 180)
var theta = (lon + 180) * (Math.PI / 180)
x = -((radius) * Math.sin(phi) * Math.cos(theta))
z = ((radius) * Math.sin(phi) * Math.sin(theta))
y = ((radius) * Math.cos(phi))
return [x, y, z];
};
EarthView3D.Animate = function () {
//earth.rotation.y -= .0004; - Rotation was causing shaking of markers/labels, so commented out.
requestAnimationFrame(EarthView3D.Animate);
renderer.render(scene, camera);
labelRenderer.render(scene, camera);
};