mirror of
https://github.com/beestat/app.git
synced 2026-02-26 05:00:21 -05:00
Optimize
This commit is contained in:
parent
f7f5252ea9
commit
118b67e1d3
@ -4,6 +4,25 @@
|
||||
beestat.component.card.three_d = function() {
|
||||
const self = this;
|
||||
|
||||
if (
|
||||
beestat.component.card.three_d.active_instance_ !== undefined &&
|
||||
beestat.component.card.three_d.active_instance_ !== null &&
|
||||
beestat.component.card.three_d.active_instance_ !== this
|
||||
) {
|
||||
beestat.component.card.three_d.active_instance_.force_dispose_stale_instance_();
|
||||
}
|
||||
beestat.component.card.three_d.active_instance_ = this;
|
||||
|
||||
this.disposed_ = false;
|
||||
|
||||
this.handle_scene_settings_change_ = function() {
|
||||
if (self.disposed_ === true || self.scene_ === undefined) {
|
||||
return;
|
||||
}
|
||||
self.update_scene_();
|
||||
self.update_hud_();
|
||||
};
|
||||
|
||||
// Things that update the scene that don't require a rerender.
|
||||
// TODO these probably need moved to the layer instead of here
|
||||
beestat.dispatcher.addEventListener(
|
||||
@ -14,20 +33,27 @@ beestat.component.card.three_d = function() {
|
||||
'setting.visualize.heat_map_static.temperature.max',
|
||||
'setting.visualize.heat_map_static.occupancy.min',
|
||||
'setting.visualize.heat_map_static.occupancy.max'
|
||||
], function() {
|
||||
self.update_scene_();
|
||||
self.update_hud_();
|
||||
});
|
||||
],
|
||||
this.handle_scene_settings_change_
|
||||
);
|
||||
|
||||
// Rerender the scene when the floor plan changes.
|
||||
beestat.dispatcher.addEventListener('cache.floor_plan', function() {
|
||||
this.handle_floor_plan_cache_change_ = function() {
|
||||
if (self.disposed_ === true || self.scene_ === undefined) {
|
||||
return;
|
||||
}
|
||||
self.scene_.rerender();
|
||||
self.apply_layer_visibility_();
|
||||
self.update_scene_();
|
||||
self.update_hud_();
|
||||
});
|
||||
};
|
||||
|
||||
const change_function = beestat.debounce(function() {
|
||||
// Rerender the scene when the floor plan changes.
|
||||
beestat.dispatcher.addEventListener('cache.floor_plan', this.handle_floor_plan_cache_change_);
|
||||
|
||||
this.handle_runtime_data_change_ = beestat.debounce(function() {
|
||||
if (self.disposed_ === true || self.scene_ === undefined) {
|
||||
return;
|
||||
}
|
||||
self.state_.scene_camera_state = self.scene_.get_camera_state();
|
||||
self.rerender();
|
||||
}, 10);
|
||||
@ -37,7 +63,7 @@ beestat.component.card.three_d = function() {
|
||||
'cache.data.three_d__runtime_sensor',
|
||||
'cache.data.three_d__runtime_thermostat'
|
||||
],
|
||||
change_function
|
||||
this.handle_runtime_data_change_
|
||||
);
|
||||
|
||||
this.scene_settings_menu_open_ = false;
|
||||
@ -396,6 +422,18 @@ beestat.component.card.three_d.prototype.decorate_drawing_pane_ = function(paren
|
||||
beestat.setting('visualize.floor_plan_id'),
|
||||
this.get_data_()
|
||||
);
|
||||
|
||||
const initial_width = parent.getBoundingClientRect().width;
|
||||
if (this.state_.width === undefined && initial_width > 0) {
|
||||
this.state_.width = initial_width;
|
||||
}
|
||||
if (this.state_.width !== undefined && this.state_.width > 0) {
|
||||
this.scene_.set_initial_width(this.state_.width);
|
||||
}
|
||||
if (this.state_.scene_camera_state !== undefined) {
|
||||
this.scene_.set_initial_camera_state(this.state_.scene_camera_state);
|
||||
}
|
||||
|
||||
this.scene_.set_scene_settings(this.scene_settings_values_, {
|
||||
'rerender': false
|
||||
});
|
||||
@ -483,10 +521,6 @@ beestat.component.card.three_d.prototype.decorate_drawing_pane_ = function(paren
|
||||
this.scene_.set_width(this.state_.width);
|
||||
}
|
||||
|
||||
if (this.state_.scene_camera_state !== undefined) {
|
||||
this.scene_.set_camera_state(this.state_.scene_camera_state);
|
||||
}
|
||||
|
||||
beestat.dispatcher.removeEventListener('resize.three_d');
|
||||
beestat.dispatcher.addEventListener('resize.three_d', function() {
|
||||
self.state_.width = parent.getBoundingClientRect().width;
|
||||
@ -545,7 +579,7 @@ beestat.component.card.three_d.prototype.get_weather_settings_from_mode_ = funct
|
||||
switch (weather_mode) {
|
||||
case 'cloudy':
|
||||
return {
|
||||
'cloud_density': 1,
|
||||
'cloud_density': 0.5,
|
||||
'rain_density': 0,
|
||||
'snow_density': 0
|
||||
};
|
||||
@ -2011,8 +2045,82 @@ beestat.component.card.three_d.prototype.get_most_recent_time_with_data_ = funct
|
||||
return null;
|
||||
};
|
||||
|
||||
beestat.component.card.three_d.prototype.dispose = function() {
|
||||
/**
|
||||
* Remove global listeners registered by this card instance.
|
||||
*/
|
||||
beestat.component.card.three_d.prototype.remove_global_listeners_ = function() {
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'setting.visualize.data_type',
|
||||
this.handle_scene_settings_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'setting.visualize.heat_map_values',
|
||||
this.handle_scene_settings_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'setting.visualize.heat_map_static.temperature.min',
|
||||
this.handle_scene_settings_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'setting.visualize.heat_map_static.temperature.max',
|
||||
this.handle_scene_settings_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'setting.visualize.heat_map_static.occupancy.min',
|
||||
this.handle_scene_settings_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'setting.visualize.heat_map_static.occupancy.max',
|
||||
this.handle_scene_settings_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'cache.floor_plan',
|
||||
this.handle_floor_plan_cache_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'cache.data.three_d__runtime_sensor',
|
||||
this.handle_runtime_data_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener(
|
||||
'cache.data.three_d__runtime_thermostat',
|
||||
this.handle_runtime_data_change_
|
||||
);
|
||||
beestat.dispatcher.removeEventListener('resize.three_d');
|
||||
};
|
||||
|
||||
/**
|
||||
* Force teardown for stale card instances that were not formally disposed.
|
||||
*/
|
||||
beestat.component.card.three_d.prototype.force_dispose_stale_instance_ = function() {
|
||||
if (this.disposed_ === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.disposed_ = true;
|
||||
window.clearInterval(this.fps_interval_);
|
||||
delete this.fps_interval_;
|
||||
this.remove_global_listeners_();
|
||||
|
||||
if (this.scene_ !== undefined) {
|
||||
this.scene_.dispose();
|
||||
delete this.scene_;
|
||||
}
|
||||
};
|
||||
|
||||
beestat.component.card.three_d.prototype.dispose = function() {
|
||||
this.disposed_ = true;
|
||||
|
||||
window.clearInterval(this.fps_interval_);
|
||||
delete this.fps_interval_;
|
||||
this.remove_global_listeners_();
|
||||
|
||||
if (this.scene_ !== undefined) {
|
||||
this.scene_.dispose();
|
||||
delete this.scene_;
|
||||
}
|
||||
if (beestat.component.card.three_d.active_instance_ === this) {
|
||||
delete beestat.component.card.three_d.active_instance_;
|
||||
}
|
||||
|
||||
beestat.component.card.prototype.dispose.apply(this, arguments);
|
||||
};
|
||||
|
||||
@ -402,7 +402,11 @@ beestat.component.scene.prototype.with_random_seed_ = function(seed, callback) {
|
||||
*/
|
||||
beestat.component.scene.prototype.rerender = function() {
|
||||
this.reset_celestial_lights_for_rerender_();
|
||||
this.scene_.remove(this.main_group_);
|
||||
if (this.main_group_ !== undefined) {
|
||||
this.dispose_object3d_resources_(this.main_group_);
|
||||
this.scene_.remove(this.main_group_);
|
||||
}
|
||||
this.reset_runtime_scene_references_for_rerender_();
|
||||
this.with_seeded_random_(function() {
|
||||
this.add_main_group_();
|
||||
this.add_floor_plan_();
|
||||
@ -415,6 +419,91 @@ beestat.component.scene.prototype.rerender = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose geometries/materials/textures under an Object3D subtree.
|
||||
*
|
||||
* @param {THREE.Object3D} root
|
||||
*/
|
||||
beestat.component.scene.prototype.dispose_object3d_resources_ = function(root) {
|
||||
if (root === undefined || root === null || typeof root.traverse !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
const disposed_textures = new Set();
|
||||
const disposed_materials = new Set();
|
||||
const dispose_texture = function(texture) {
|
||||
if (
|
||||
texture !== undefined &&
|
||||
texture !== null &&
|
||||
texture.isTexture === true &&
|
||||
disposed_textures.has(texture) !== true
|
||||
) {
|
||||
disposed_textures.add(texture);
|
||||
texture.dispose();
|
||||
}
|
||||
};
|
||||
const dispose_material = function(material) {
|
||||
if (material === undefined || material === null) {
|
||||
return;
|
||||
}
|
||||
if (disposed_materials.has(material) === true) {
|
||||
return;
|
||||
}
|
||||
disposed_materials.add(material);
|
||||
|
||||
for (const key in material) {
|
||||
if (Object.prototype.hasOwnProperty.call(material, key) !== true) {
|
||||
continue;
|
||||
}
|
||||
const value = material[key];
|
||||
if (value !== undefined && value !== null && value.isTexture === true) {
|
||||
dispose_texture(value);
|
||||
}
|
||||
}
|
||||
material.dispose();
|
||||
};
|
||||
|
||||
root.traverse(function(object) {
|
||||
if (object.geometry !== undefined && object.geometry !== null) {
|
||||
object.geometry.dispose();
|
||||
}
|
||||
if (object.material !== undefined && object.material !== null) {
|
||||
if (Array.isArray(object.material) === true) {
|
||||
object.material.forEach(function(material) {
|
||||
dispose_material(material);
|
||||
});
|
||||
} else {
|
||||
dispose_material(object.material);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear references that are recreated each rerender.
|
||||
*/
|
||||
beestat.component.scene.prototype.reset_runtime_scene_references_for_rerender_ = function() {
|
||||
this.meshes_ = {};
|
||||
this.layers_ = {};
|
||||
this.light_sources_ = [];
|
||||
this.tree_foliage_meshes_ = [];
|
||||
this.tree_branch_groups_ = [];
|
||||
|
||||
delete this.floor_plan_group_;
|
||||
delete this.environment_group_;
|
||||
delete this.environment_surface_group_;
|
||||
delete this.weather_group_;
|
||||
delete this.rain_particles_;
|
||||
delete this.snow_particles_;
|
||||
delete this.cloud_sprites_;
|
||||
delete this.cloud_motion_;
|
||||
delete this.weather_profile_target_;
|
||||
delete this.weather_transition_start_profile_;
|
||||
delete this.active_mesh_;
|
||||
delete this.intersected_mesh_;
|
||||
delete this.tree_ground_contact_material_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset celestial objects so rerender can rebuild stars/lights from settings.
|
||||
*/
|
||||
@ -567,13 +656,16 @@ beestat.component.scene.prototype.decorate_ = function(parent) {
|
||||
};
|
||||
this.room_interaction_enabled_ = true;
|
||||
|
||||
this.width_ = this.state_.scene_width || 800;
|
||||
this.width_ = this.initial_width_ || this.state_.scene_width || 800;
|
||||
this.height_ = 500;
|
||||
|
||||
this.add_scene_(parent);
|
||||
this.add_renderer_(parent);
|
||||
this.add_camera_();
|
||||
this.add_controls_(parent);
|
||||
if (this.initial_camera_state_ !== undefined) {
|
||||
this.set_camera_state(this.initial_camera_state_);
|
||||
}
|
||||
this.add_raycaster_(parent);
|
||||
this.add_skybox_(parent);
|
||||
this.add_static_lights_();
|
||||
@ -606,6 +698,34 @@ beestat.component.scene.prototype.decorate_ = function(parent) {
|
||||
animate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set width to use when scene first decorates/renders.
|
||||
*
|
||||
* @param {number} width
|
||||
*
|
||||
* @return {beestat.component.scene}
|
||||
*/
|
||||
beestat.component.scene.prototype.set_initial_width = function(width) {
|
||||
if (Number.isFinite(width) === true && width > 0) {
|
||||
this.initial_width_ = width;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set camera state to apply before first rendered frame.
|
||||
*
|
||||
* @param {object} camera_state
|
||||
*
|
||||
* @return {beestat.component.scene}
|
||||
*/
|
||||
beestat.component.scene.prototype.set_initial_camera_state = function(camera_state) {
|
||||
if (camera_state !== undefined) {
|
||||
this.initial_camera_state_ = camera_state;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add the scene. Everything gets added to the scene.
|
||||
*
|
||||
@ -1246,7 +1366,13 @@ beestat.component.scene.prototype.get_fps = function() {
|
||||
* @return {object}
|
||||
*/
|
||||
beestat.component.scene.prototype.get_camera_state = function() {
|
||||
return this.camera_.matrix.toArray();
|
||||
const state = {
|
||||
'matrix': this.camera_.matrix.toArray()
|
||||
};
|
||||
if (this.controls_ !== undefined && this.controls_.target !== undefined) {
|
||||
state.target = this.controls_.target.toArray();
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1255,12 +1381,40 @@ beestat.component.scene.prototype.get_camera_state = function() {
|
||||
* @param {object} camera_state
|
||||
*/
|
||||
beestat.component.scene.prototype.set_camera_state = function(camera_state) {
|
||||
this.camera_.matrix.fromArray(camera_state);
|
||||
let matrix_state = camera_state;
|
||||
let target_state;
|
||||
if (
|
||||
camera_state !== undefined &&
|
||||
camera_state !== null &&
|
||||
Array.isArray(camera_state) !== true
|
||||
) {
|
||||
matrix_state = camera_state.matrix;
|
||||
target_state = camera_state.target;
|
||||
}
|
||||
|
||||
if (Array.isArray(matrix_state) !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.camera_.matrix.fromArray(matrix_state);
|
||||
this.camera_.matrix.decompose(
|
||||
this.camera_.position,
|
||||
this.camera_.quaternion,
|
||||
this.camera_.scale
|
||||
);
|
||||
|
||||
if (
|
||||
Array.isArray(target_state) === true &&
|
||||
target_state.length >= 3 &&
|
||||
this.controls_ !== undefined
|
||||
) {
|
||||
this.controls_.target.set(
|
||||
Number(target_state[0]) || 0,
|
||||
Number(target_state[1]) || 0,
|
||||
Number(target_state[2]) || 0
|
||||
);
|
||||
this.controls_.update();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1438,6 +1592,20 @@ beestat.component.scene.prototype.dispose = function() {
|
||||
if (this.light_source_glow_geometry_ !== undefined) {
|
||||
this.light_source_glow_geometry_.dispose();
|
||||
}
|
||||
if (this.raycaster_document_mousemove_handler_ !== undefined) {
|
||||
document.removeEventListener('mousemove', this.raycaster_document_mousemove_handler_);
|
||||
delete this.raycaster_document_mousemove_handler_;
|
||||
}
|
||||
if (
|
||||
this.raycaster_dom_element_ !== undefined &&
|
||||
this.raycaster_dom_mousedown_handler_ !== undefined
|
||||
) {
|
||||
this.raycaster_dom_element_.removeEventListener('mousedown', this.raycaster_dom_mousedown_handler_);
|
||||
this.raycaster_dom_element_.removeEventListener('touchstart', this.raycaster_dom_touchstart_handler_);
|
||||
delete this.raycaster_dom_mousedown_handler_;
|
||||
delete this.raycaster_dom_touchstart_handler_;
|
||||
delete this.raycaster_dom_element_;
|
||||
}
|
||||
|
||||
// Clean up THREE.js scene resources
|
||||
if (this.scene_ !== undefined) {
|
||||
|
||||
@ -67,15 +67,18 @@ beestat.component.scene.prototype.add_raycaster_ = function() {
|
||||
*/
|
||||
this.raycaster_pointer_ = new THREE.Vector2(10000, 10000);
|
||||
|
||||
// TODO remove event listener on dispose
|
||||
document.addEventListener('mousemove', function(e) {
|
||||
this.raycaster_document_mousemove_handler_ = function(e) {
|
||||
const rect = self.renderer_.domElement.getBoundingClientRect();
|
||||
self.raycaster_pointer_.x = ( ( e.clientX - rect.left ) / ( rect.right - rect.left ) ) * 2 - 1;
|
||||
self.raycaster_pointer_.y = - ( ( e.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
|
||||
});
|
||||
// TODO remove event listener on dispose
|
||||
this.renderer_.domElement.addEventListener('mousedown', this.mousedown_handler_.bind(this));
|
||||
this.renderer_.domElement.addEventListener('touchstart', this.mousedown_handler_.bind(this));
|
||||
};
|
||||
document.addEventListener('mousemove', this.raycaster_document_mousemove_handler_);
|
||||
|
||||
this.raycaster_dom_element_ = this.renderer_.domElement;
|
||||
this.raycaster_dom_mousedown_handler_ = this.mousedown_handler_.bind(this);
|
||||
this.raycaster_dom_touchstart_handler_ = this.mousedown_handler_.bind(this);
|
||||
this.raycaster_dom_element_.addEventListener('mousedown', this.raycaster_dom_mousedown_handler_);
|
||||
this.raycaster_dom_element_.addEventListener('touchstart', this.raycaster_dom_touchstart_handler_);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ beestat.component.scene.prototype.set_weather = function(weather) {
|
||||
break;
|
||||
case 'cloudy':
|
||||
weather_settings = {
|
||||
'cloud_density': 1,
|
||||
'cloud_density': 0.5,
|
||||
'rain_density': 0,
|
||||
'snow_density': 0
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user