/** * Home Scene * * @param {number} floor_plan_id The floor plan to render. * @param {object} data Sensor data. */ beestat.component.scene = function(floor_plan_id, data) { this.floor_plan_id_ = floor_plan_id; this.data_ = data; beestat.component.apply(this, arguments); }; beestat.extend(beestat.component.scene, beestat.component); // beestat.component.scene.sun_light_intensity = 1; // beestat.component.scene.moon_light_intensity = 0.3; /** * Brightness of the top-down light. This gives definition to the sides of * meshes by lighting the tops. Increase this for more edge definition. */ beestat.component.scene.directional_light_top_intensity = 0.25; /** * Brightness of the ambient light. Works with the top light to provide a base * level of light to the scene. */ beestat.component.scene.ambient_light_intensity = 0.3; // beestat.component.scene.ambient_light_intensity_sky = 0.4; // beestat.component.scene.moon_opacity = 0.9; // beestat.component.scene.turbidity = 10; // beestat.component.scene.rayleigh = 0.5; // beestat.component.scene.mie_coefficient = 0.001; // beestat.component.scene.mie_directional_g = 0.95; // beestat.component.scene.turbidity = 14; // beestat.component.scene.rayleigh = 0.7; // beestat.component.scene.mie_coefficient = 0.008; // beestat.component.scene.mie_directional_g = 0.9; // beestat.component.scene.shadow_map_size = 4096; /** * Rerender the scene by removing the primary group, then re-adding it and the * floor plan. This avoids having to reconstruct everything and then also * having to manually save camera info etc. */ beestat.component.scene.prototype.rerender = function() { this.scene_.remove(this.main_group_); this.add_main_group_(); this.add_floor_plan_(); }; /** * Set the width of this component. * * @param {number} width */ beestat.component.scene.prototype.set_width = function(width) { this.width_ = width; this.camera_.aspect = this.width_ / this.height_; this.camera_.updateProjectionMatrix(); this.renderer_.setSize(this.width_, this.height_); }; /** * Decorate * * @param {rocket.Elements} parent */ beestat.component.scene.prototype.decorate_ = function(parent) { const self = this; // Dark background to help reduce apparant flicker when resizing parent.style('background', '#202a30'); this.debug_ = { 'axes': false, // 'directional_light_moon_helper': false, // 'directional_light_sun_helper': false, 'directional_light_top_helper': false, // 'grid': false, 'watcher': false }; this.width_ = this.state_.scene_width || 800; this.height_ = 500; this.add_scene_(parent); // this.add_background_(parent); this.add_renderer_(parent); this.add_camera_(); this.add_controls_(parent); this.add_skybox_(parent); // this.add_sky_(); // this.add_moon_(); // this.add_directional_light_moon_(); // this.add_directional_light_sun_(); this.add_ambient_light_(); this.add_directional_light_top_(); // this.add_ground_(); // this.add_ground_limited_(); this.add_main_group_(); this.add_floor_plan_(); /** * Example of how to do a roof * * const geometry = new THREE.ConeGeometry(1.5, 1, 4, 1, false, Math.PI/4); * const material = new THREE.MeshPhongMaterial({ * 'color': new THREE.Color(beestat.style.color.gray.dark) * }); * const roof = new THREE.Mesh( * geometry, * material * ); * roof.position.set( * 1, 2.5, 1 * ); * roof.castShadow = true; * roof.receiveShadow = true; * * this.scene_.add(roof); */ const animate = function() { requestAnimationFrame(animate); self.controls_.update(); self.renderer_.render(self.scene_, self.camera_); }; animate(); }; /** * Add the scene. Everything gets added to the scene. * * @param {rocket.Elements} parent Parent */ beestat.component.scene.prototype.add_scene_ = function(parent) { this.scene_ = new THREE.Scene(); if (this.debug_.axes === true) { this.scene_.add( new THREE.AxesHelper(800) .setColors( 0xff0000, 0x00ff00, 0x0000ff ) ); } if (this.debug_.watcher === true) { this.debug_info_ = {}; this.debug_container_ = $.createElement('div').style({ 'position': 'absolute', 'top': (beestat.style.size.gutter / 2), 'left': (beestat.style.size.gutter / 2), 'padding': (beestat.style.size.gutter / 2), 'background': 'rgba(0, 0, 0, 0.5)', 'color': '#fff', 'font-family': 'Consolas, Courier, Monospace', 'white-space': 'pre' }); parent.appendChild(this.debug_container_); } }; /** * Add the renderer. * * @param {rocket.Elements} parent */ beestat.component.scene.prototype.add_renderer_ = function(parent) { this.renderer_ = new THREE.WebGLRenderer({ 'antialias': true }); this.renderer_.setSize(this.width_, this.height_); // this.renderer_.setSize(window.innerWidth, window.innerHeight); // this.renderer_.shadowMap.enabled = true; // this.renderer_.shadowMap.autoUpdate = false; /* * Added these to make the sky not look like crap. * https://threejs.org/examples/webgl_shaders_sky.html */ // this.renderer_.toneMapping = THREE.ACESFilmicToneMapping; // this.renderer_.toneMappingExposure = 0.5; // this.renderer_.toneMappingExposure = 0.2; parent[0].appendChild(this.renderer_.domElement); }; /** * Add a camera and point it at the scene. */ beestat.component.scene.prototype.add_camera_ = function() { const field_of_view = 75; const aspect_ratio = window.innerWidth / window.innerHeight; const near_plane = 1; const far_plane = 100000; this.camera_ = new THREE.PerspectiveCamera( field_of_view, aspect_ratio, near_plane, far_plane ); this.camera_.position.x = 400; this.camera_.position.y = 400; this.camera_.position.z = 400; }; /** * Add camera controls. * * @param {rocket.Elements} parent */ beestat.component.scene.prototype.add_controls_ = function(parent) { this.controls_ = new THREE.OrbitControls(this.camera_, parent[0]); this.controls_.enableDamping = true; this.controls_.enablePan = false; this.controls_.maxDistance = 1000; this.controls_.minDistance = 400; this.controls_.maxPolarAngle = Math.PI / 2.5; }; /** * Add a skybox background. Generated using Spacescape with the Unity export * settings. After export: bottom is rotated CW 90°; top is roted 90°CCW. * * nx -> bk * ny -> dn * nz -> lf * px -> ft * py -> up * pz -> rt * * @link https://www.mapcore.org/topic/24535-online-tools-to-convert-cubemaps-to-panoramas-and-vice-versa/ * @link https://jaxry.github.io/panorama-to-cubemap/ * @link http://alexcpeterson.com/spacescape/ */ beestat.component.scene.prototype.add_skybox_ = function() { const skybox_name = 'cloudy'; const loader = new THREE.CubeTextureLoader(); loader.setPath('img/visualize/' + skybox_name + '/'); const texture = loader.load([ 'front.png', 'back.png', 'up.png', 'down.png', 'right.png', 'left.png' ]); this.scene_.background = texture; }; /** * Add the sky to the scene. This is a shader that draws on the inside of a * box really far away. The size of the sun can be tweaked with the * sunAngularDiameterCos shader parameter in threejs.js. * * The sky material uniforms are configured to make the sky look generally * nice. They are tweaked for the eclipse simulation to darken the sky. */ /*beestat.component.scene.prototype.add_sky_ = function() { this.sky_ = new THREE.Sky(); // Makes the sky box really big. this.sky_.scale.setScalar(4500000); this.sky_.material.uniforms.turbidity.value = beestat.component.scene.turbidity; this.sky_.material.uniforms.rayleigh.value = beestat.component.scene.rayleigh; this.sky_.material.uniforms.mieCoefficient.value = beestat.component.scene.mie_coefficient; this.sky_.material.uniforms.mieDirectionalG.value = beestat.component.scene.mie_directional_g; this.scene_.add(this.sky_); };*/ /** * Adds a moon sprite to the scene. The scale is set arbitrarily to make it * roughly the size of the sun. */ /*beestat.component.scene.prototype.add_moon_ = function() { const map = new THREE.TextureLoader().load('img/moon.png'); const material = new THREE.SpriteMaterial({'map': map}); const scale = 700; this.moon_ = new THREE.Sprite(material); this.moon_.scale.set(scale, scale, scale); // this.scene_.add(this.moon_); };*/ /** * Adds a faint moon light so the moon can cast shadows at night. */ /*beestat.component.scene.prototype.add_directional_light_moon_ = function() { this.directional_light_moon_ = new THREE.DirectionalLight( 0xfffbab, 0.2 ); this.directional_light_moon_.castShadow = true; this.directional_light_moon_.shadow.mapSize.width = beestat.component.scene.shadow_map_size; this.directional_light_moon_.shadow.mapSize.height = beestat.component.scene.shadow_map_size; this.directional_light_moon_.shadow.camera.left = -1000; this.directional_light_moon_.shadow.camera.right = 1000; this.directional_light_moon_.shadow.camera.top = 1000; this.directional_light_moon_.shadow.camera.bottom = -1000; this.directional_light_moon_.shadow.camera.far = 10000; // this.scene_.add(this.directional_light_moon_); if (this.debug_.directional_light_moon_helper === true) { this.directional_light_moon_helper_ = new THREE.DirectionalLightHelper( this.directional_light_moon_ ); this.scene_.add(this.directional_light_moon_helper_); this.directional_light_moon_camera_helper_ = new THREE.CameraHelper( this.directional_light_moon_.shadow.camera ); this.scene_.add(this.directional_light_moon_camera_helper_); } };*/ /** * Add a strong sun light to the scene. */ /*beestat.component.scene.prototype.add_directional_light_sun_ = function() { // Directional light to cast shadows. this.directional_light_sun_ = new THREE.DirectionalLight( 0xffffff, beestat.component.scene.sun_light_intensity ); this.directional_light_sun_.castShadow = true; // this.directional_light_sun_.shadow.bias = -0.00009; // this.directional_light_sun_.shadow.radius = 32; this.directional_light_sun_.shadow.mapSize.width = beestat.component.scene.shadow_map_size; this.directional_light_sun_.shadow.mapSize.height = beestat.component.scene.shadow_map_size; this.directional_light_sun_.shadow.camera.left = -1000; this.directional_light_sun_.shadow.camera.right = 1000; this.directional_light_sun_.shadow.camera.top = 1000; this.directional_light_sun_.shadow.camera.bottom = -1000; this.directional_light_sun_.shadow.camera.far = 10000; this.scene_.add(this.directional_light_sun_); if (this.debug_.directional_light_sun_helper === true) { this.directional_light_sun_helper_ = new THREE.DirectionalLightHelper( this.directional_light_sun_ ); this.scene_.add(this.directional_light_sun_helper_); this.directional_light_sun_camera_helper_ = new THREE.CameraHelper( this.directional_light_sun_.shadow.camera ); this.scene_.add(this.directional_light_sun_camera_helper_); } };*/ /** * Consistent directional light that provides definition to the edge of meshes * by lighting the top. */ beestat.component.scene.prototype.add_directional_light_top_ = function() { this.directional_light_top_ = new THREE.DirectionalLight( 0xffffff, beestat.component.scene.directional_light_top_intensity ); this.directional_light_top_.position.set(0, 1000, 0); this.scene_.add(this.directional_light_top_); if (this.debug_.directional_light_top_helper === true) { this.directional_light_top_helper_ = new THREE.DirectionalLightHelper( this.directional_light_top_, 500 ); this.scene_.add(this.directional_light_top_helper_); } }; /** * Ambient lighting so nothing is shrouded in darkness. */ beestat.component.scene.prototype.add_ambient_light_ = function() { /** * Base ambient light to keep everything visible (mostly at night). The * intensity of this light does not change. */ this.scene_.add(new THREE.AmbientLight( 0xffffff, beestat.component.scene.ambient_light_intensity )); }; /** * Set the date and thus the position of the sun/moon. */ beestat.component.scene.prototype.update_ = function() { const self = this; const floor_plan = beestat.cache.floor_plan[this.floor_plan_id_]; const time = this.date_.format('HH:mm'); // Set the color of each room floor_plan.data.groups.forEach(function(group) { group.rooms.forEach(function(room) { let color; if ( room.sensor_id !== undefined && self.data_.series[self.data_type_][room.sensor_id] !== undefined && self.data_.series[self.data_type_][room.sensor_id][time] !== undefined ) { const value = self.data_.series[self.data_type_][room.sensor_id][time]; /** * Set the percentage between the min and max. Special case for if min * and max are equal to avoid math issues. */ let percentage; if ( self.heat_map_min_ === self.heat_map_max_ && value === self.heat_map_min_ ) { percentage = 0.5; } else { percentage = Math.min( 1, Math.max( 0, (value - self.heat_map_min_) / (self.heat_map_max_ - self.heat_map_min_) ) ); } color = beestat.style.rgb_to_hex( self.gradient_[Math.floor((self.gradient_.length - 1) * percentage)] ); } else { color = beestat.style.color.gray.dark; } self.rooms_[room.room_id].material.color.setHex(color.replace('#', '0x')); }); }); let address; if (floor_plan.address_id !== null) { // todo should be undefined? address = beestat.cache.address[floor_plan.address_id]; } else { address = { 'normalized': { 'metadata': { 'latitude': 0, 'longitude': 0 } } }; } // After sunset may need to hide the sun light source...or maybe wean it's brightness off or something. // TODO TEMP TO KEEP LIGHTING CONSISTENT // const date = new Date('2022-08-16 12:00:00'); // const date = this.date_.toDate(); /*const date = moment() .hour(12) .minute(0) .second(0) .toDate(); const sun_object_vector = new THREE.Vector3(); const moon_object_vector = new THREE.Vector3(); const sun_light_vector = new THREE.Vector3(); const moon_light_vector = new THREE.Vector3(); // Get sun and moon positions. const sun_position = SunCalc.getPosition( date, address.normalized.metadata.latitude, address.normalized.metadata.longitude ); const moon_position = SunCalc.getMoonPosition( date, address.normalized.metadata.latitude, address.normalized.metadata.longitude ); const moon_illumination = SunCalc.getMoonIllumination(date); // Set the position of the vectors. sun_object_vector.setFromSphericalCoords( 10000, sun_position.altitude - (Math.PI / 2), sun_position.azimuth ); moon_object_vector.setFromSphericalCoords( 10000, moon_position.altitude - (Math.PI / 2), moon_position.azimuth ); // Set the position of the vectors. sun_light_vector.setFromSphericalCoords( 5000, sun_position.altitude - (Math.PI / 2), sun_position.azimuth ); moon_light_vector.setFromSphericalCoords( 5000, moon_position.altitude - (Math.PI / 2), moon_position.azimuth ); // TODO This will change based on size distance etc const eclipse_begins_distance = 660; const sun_moon_distance = sun_object_vector.distanceTo(moon_object_vector); const eclipse_percentage = Math.max( 0, (1 - (sun_moon_distance / eclipse_begins_distance)) );*/ /* * this.ambient_light_sky_.intensity = * beestat.component.scene.ambient_light_intensity_sky * eclipse_multiplier; */ /* * this.directional_light_sun_.intensity = * this.directional_light_sun_.intensity * eclipse_multiplier; */ // Set light intensities by altitude and eclipse percentage. /* this.ambient_light_sky_.intensity = Math.max( 0, beestat.component.scene.ambient_light_intensity_sky * Math.sin(sun_position.altitude) * (1 - eclipse_percentage) );*/ // this.moon_.material.opacity = 0.2; /** * Mess up the sky during an eclipse */ // Turn down to 0 /*if (this.sky_ !== undefined) { this.sky_.material.uniforms.rayleigh.value = beestat.component.scene.rayleigh * (1 - eclipse_percentage); // Turn down to almost 0 this.sky_.material.uniforms.mieCoefficient.value = Math.max( 0.00001, beestat.component.scene.mie_coefficient * (1 - eclipse_percentage) ); // Increase to almost 1 this.sky_.material.uniforms.mieDirectionalG.value = Math.max( beestat.component.scene.mie_directional_g, 0.9999 * eclipse_percentage ); this.sky_.material.uniforms.sunPosition.value.copy(sun_object_vector); }*/ /* * this.renderer_.toneMappingExposure = Math.max( * 0.1, // Minimum exposure * beestat.component.scene.tone_mapping_exposure * eclipse_multiplier * ); */ // Set the brightness of the sun /*if (this.directional_light_sun_ !== undefined) { this.directional_light_sun_.intensity = beestat.component.scene.sun_light_intensity * Math.sin(sun_position.altitude) * (1 - eclipse_percentage); this.directional_light_sun_.position.copy(sun_light_vector); } // Set the brightness of the moon if (this.directional_light_moon_ !== undefined) { this.directional_light_moon_.intensity = beestat.component.scene.moon_light_intensity * moon_illumination.fraction; this.directional_light_moon_.position.copy(moon_light_vector); } if (this.moon_ !== undefined) { this.moon_.position.copy(moon_object_vector); }*/ // TODO size of moon based on distance? Might not be worth it haha. /* * this.directional_light_moon_.intensity = 0; * this.directional_light_sun_.intensity = 0; */ // Update the directional light positions // Update the position of the sun and moon in the sky // this.sky2_.material.uniforms.sunPosition.value.copy(moon_object_vector); // Update shadows /*this.renderer_.shadowMap.needsUpdate = true; if (this.debug_.directional_light_moon_helper === true) { this.directional_light_moon_helper_.update(); this.directional_light_moon_camera_helper_.update(); } if (this.debug_.directional_light_sun_helper === true) { this.directional_light_sun_helper_.update(); this.directional_light_sun_camera_helper_.update(); }*/ if (this.debug_.directional_light_top_helper === true) { this.directional_light_top_helper_.update(); // this.directional_light_top_camera_helper_.update(); } // Update debug watcher if (this.debug_.watcher === true) { // this.debug_info_.date = date; this.update_debug_(); } }; /** * Add some type of ground for the house to sit on. */ /*beestat.component.scene.prototype.add_ground_ = function() { const size = 40000; const texture = new THREE.TextureLoader().load('img/grass.jpg'); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set(1000, 1000); const geometry = new THREE.PlaneGeometry(size, size); const material = new THREE.MeshLambertMaterial({ // 'map': texture, 'color': new THREE.Color(beestat.style.color.green.dark), 'side': THREE.DoubleSide }); const plane = new THREE.Mesh(geometry, material); plane.rotation.x += Math.PI / 2; plane.receiveShadow = true; this.scene_.add(plane); if (this.debug_.grid === true) { const grid_size = 100; const grid_divisions = grid_size; const grid_color_center_line = new THREE.Color(beestat.style.color.lightblue.base); const grid_color_grid = new THREE.Color(beestat.style.color.green.base); const grid_helper = new THREE.GridHelper( grid_size, grid_divisions, grid_color_center_line, grid_color_grid ); this.scene_.add(grid_helper); } }; */ /*beestat.component.scene.prototype.add_ground_limited_ = function() { const height = 24; const bounding_box = beestat.floor_plan.get_bounding_box(this.floor_plan_id_); const size = Math.max(bounding_box.width, bounding_box.height) + 120; // const texture = new THREE.TextureLoader().load('img/grass.jpg'); // texture.wrapS = THREE.RepeatWrapping; // texture.wrapT = THREE.RepeatWrapping; // texture.repeat.set(1000, 1000); const geometry = new THREE.BoxGeometry(size, size, height); const material = new THREE.MeshLambertMaterial({ // 'map': texture, 'color': new THREE.Color(beestat.style.color.green.dark), 'side': THREE.DoubleSide }); const box = new THREE.Mesh(geometry, material); box.translateY(height / -2); box.rotation.x += Math.PI / 2; // box.receiveShadow = true; this.scene_.add(box); if (this.debug_.grid === true) { const grid_size = 100; const grid_divisions = grid_size; const grid_color_center_line = new THREE.Color(beestat.style.color.lightblue.base); const grid_color_grid = new THREE.Color(beestat.style.color.green.base); const grid_helper = new THREE.GridHelper( grid_size, grid_divisions, grid_color_center_line, grid_color_grid ); this.scene_.add(grid_helper); } };*/ /** * Add a background. */ // beestat.component.scene.prototype.add_background_ = function() { // this.scene_.background = new THREE.Color(beestat.style.color.bluegray.dark); // } /** * Add a room. Room coordinates are absolute. * * @param {THREE.Group} layer The layer the room belongs to. * @param {object} group The group the room belongs to. * @param {object} room The room to add. */ beestat.component.scene.prototype.add_room_ = function(layer, group, room) { const color = beestat.style.color.gray.dark; var clipper_offset = new ClipperLib.ClipperOffset(); clipper_offset.AddPath( room.points, ClipperLib.JoinType.jtSquare, ClipperLib.EndType.etClosedPolygon ); var clipper_hole = new ClipperLib.Path(); clipper_offset.Execute(clipper_hole, -1.5); // Full height // const extrude_height = (room.height || group.height) - 3; // Just the floor plan const extrude_height = 6; // Create a shape using the points of the room. const shape = new THREE.Shape(); const first_point = clipper_hole[0].shift(); shape.moveTo(first_point.x, first_point.y); clipper_hole[0].forEach(function(point) { shape.lineTo(point.x, point.y); }); // Extrude the shape and create the mesh. const extrude_settings = { 'depth': extrude_height, 'bevelEnabled': false, // 'bevelThickness': 1, // 'bevelSize': 1, // 'bevelOffset': 1, // 'bevelSegments': 5 }; const geometry = new THREE.ExtrudeGeometry( shape, extrude_settings ); // const material = new THREE.MeshBasicMaterial({ const material = new THREE.MeshPhongMaterial({ 'color': color, // 'transparent': true, // 'opacity': 0.5 }); // material.opacity = 0.5; const mesh = new THREE.Mesh(geometry, material); mesh.position.z = -extrude_height - (room.elevation || group.elevation); // Translate the mesh to the room x/y position. mesh.translateX(room.x); mesh.translateY(room.y); // Shadows are neat. mesh.castShadow = true; // mesh.receiveShadow = true; // Add the mesh to the group. this.main_group_.add(mesh); // Store a reference to the mesh representing each room. if (this.rooms_ === undefined) { this.rooms_ = {}; } this.rooms_[room.room_id] = mesh; layer.add(mesh); }; /** * Add a helpful debug window that can be refreshed with the contents of * this.debug_info_. * * @param {rocket.Elements} parent */ beestat.component.scene.prototype.add_debug_ = function(parent) { if (this.debug_.watcher === true) { this.debug_info_ = {}; this.debug_container_ = $.createElement('div').style({ 'position': 'absolute', 'top': (beestat.style.size.gutter / 2), 'left': (beestat.style.size.gutter / 2), 'padding': (beestat.style.size.gutter / 2), 'background': 'rgba(0, 0, 0, 0.5)', 'color': '#fff', 'font-family': 'Consolas, Courier, Monospace', 'white-space': 'pre' }); parent.appendChild(this.debug_container_); } }; /** * Update the debug window. */ beestat.component.scene.prototype.update_debug_ = function() { if (this.debug_.watcher === true) { this.debug_container_.innerHTML( JSON.stringify(this.debug_info_, null, 2) ); } }; /** * Add a group containing all of the extruded geometry that can be transformed * all together. */ beestat.component.scene.prototype.add_main_group_ = function() { const bounding_box = beestat.floor_plan.get_bounding_box(this.floor_plan_id_); // this.floor_plan_center_x_ = ; // this.floor_plan_center_y_ = (bounding_box.bottom + bounding_box.top) / 2; // this.view_box_.x = center_x - (this.view_box_.width / 2); // this.view_box_.y = center_y - (this.view_box_.height / 2); this.main_group_ = new THREE.Group(); this.main_group_.translateX((bounding_box.right + bounding_box.left) / -2); this.main_group_.translateZ((bounding_box.bottom + bounding_box.top) / -2); // this.main_group_.rotation.x = -Math.PI / 2; // this.main_group_.rotation.x = Math.PI / 2; this.scene_.add(this.main_group_); }; /** * Add the floor plan to the scene. */ beestat.component.scene.prototype.add_floor_plan_ = function() { const self = this; const floor_plan = beestat.cache.floor_plan[this.floor_plan_id_]; this.layers_ = {}; floor_plan.data.groups.forEach(function(group, i) { const layer = new THREE.Group(); self.main_group_.add(layer); self.layers_['group_' + i] = layer; group.rooms.forEach(function(room) { self.add_room_(layer, group, room); }); }); }; /** * Set the current date. * * @param {moment} date * * @return {beestat.component.scene} */ beestat.component.scene.prototype.set_date = function(date) { this.date_ = date; if (this.rendered_ === true) { this.update_(); } return this; }; /** * Set the type of data this scene is visualizing. * * @param {string} data_type temperature|occupancy * * @return {beestat.component.scene} */ beestat.component.scene.prototype.set_data_type = function(data_type) { this.data_type_ = data_type; if (this.rendered_ === true) { this.update_(); } return this; }; /** * Set the min value of the heat map. * * @param {string} heat_map_min * * @return {beestat.component.scene} */ beestat.component.scene.prototype.set_heat_map_min = function(heat_map_min) { this.heat_map_min_ = heat_map_min; if (this.rendered_ === true) { this.update_(); } return this; }; /** * Set the max value of the heat map. * * @param {string} heat_map_max * * @return {beestat.component.scene} */ beestat.component.scene.prototype.set_heat_map_max = function(heat_map_max) { this.heat_map_max_ = heat_map_max; if (this.rendered_ === true) { this.update_(); } return this; }; /** * Set the visibility of a layer. * * @param {string} layer_name * @param {boolean} visible * * @return {beestat.component.scene} */ beestat.component.scene.prototype.set_layer_visible = function(layer_name, visible) { this.layers_[layer_name].visible = visible; return this; }; /** * Set whether or not auto-rotate is enabled. * * @param {boolean} auto_rotate * * @return {beestat.component.scene} */ beestat.component.scene.prototype.set_auto_rotate = function(auto_rotate) { this.controls_.autoRotate = auto_rotate; return this; }; /** * Set the gradient. * * @param {boolean} gradient * * @return {beestat.component.scene} */ beestat.component.scene.prototype.set_gradient = function(gradient) { this.gradient_ = gradient; return this; }; /** * Get the state of the camera. * * @return {object} */ beestat.component.scene.prototype.get_camera_state = function() { return this.camera_.matrix.toArray(); }; /** * Restore the state of the camera. * * @param {object} camera_state */ beestat.component.scene.prototype.set_camera_state = function(camera_state) { this.camera_.matrix.fromArray(camera_state); this.camera_.matrix.decompose( this.camera_.position, this.camera_.quaternion, this.camera_.scale ); };