mirror of
https://github.com/beestat/app.git
synced 2025-07-09 03:04:07 -04:00
Added undo/redo
This commit is contained in:
parent
0572527d6f
commit
46340a3dd8
@ -443,6 +443,7 @@ input[type=radio] {
|
|||||||
.icon.cloud_question:before { content: "\F0A39"; }
|
.icon.cloud_question:before { content: "\F0A39"; }
|
||||||
.icon.code_tags:before { content: "\F0174"; }
|
.icon.code_tags:before { content: "\F0174"; }
|
||||||
.icon.cog:before { content: "\F0493"; }
|
.icon.cog:before { content: "\F0493"; }
|
||||||
|
.icon.delete:before { content: "\F01B4"; }
|
||||||
.icon.dots_vertical:before { content: "\F01D9"; }
|
.icon.dots_vertical:before { content: "\F01D9"; }
|
||||||
.icon.download:before { content: "\F01DA"; }
|
.icon.download:before { content: "\F01DA"; }
|
||||||
.icon.earth:before { content: "\F01E7"; }
|
.icon.earth:before { content: "\F01E7"; }
|
||||||
@ -500,7 +501,10 @@ input[type=radio] {
|
|||||||
.icon.numeric_9_box:before { content: "\F03BC"; }
|
.icon.numeric_9_box:before { content: "\F03BC"; }
|
||||||
.icon.open_in_new:before { content: "\F03CC"; }
|
.icon.open_in_new:before { content: "\F03CC"; }
|
||||||
.icon.patreon:before { content: "\F0882"; }
|
.icon.patreon:before { content: "\F0882"; }
|
||||||
|
.icon.pencil:before { content: "\F03EB"; }
|
||||||
|
.icon.plus:before { content: "\F0415"; }
|
||||||
.icon.pound:before { content: "\F0423"; }
|
.icon.pound:before { content: "\F0423"; }
|
||||||
|
.icon.redo:before { content: "\F044E"; }
|
||||||
.icon.refresh:before { content: "\F0450"; }
|
.icon.refresh:before { content: "\F0450"; }
|
||||||
.icon.resistor:before { content: "\F0B44"; }
|
.icon.resistor:before { content: "\F0B44"; }
|
||||||
.icon.snowflake:before { content: "\F0717"; }
|
.icon.snowflake:before { content: "\F0717"; }
|
||||||
@ -509,6 +513,7 @@ input[type=radio] {
|
|||||||
.icon.thumb_up:before { content: "\F0513"; }
|
.icon.thumb_up:before { content: "\F0513"; }
|
||||||
.icon.tune:before { content: "\F062E"; }
|
.icon.tune:before { content: "\F062E"; }
|
||||||
.icon.twitter:before { content: "\F0544"; }
|
.icon.twitter:before { content: "\F0544"; }
|
||||||
|
.icon.undo:before { content: "\F054C"; }
|
||||||
.icon.update:before { content: "\F06B0"; }
|
.icon.update:before { content: "\F06B0"; }
|
||||||
.icon.vector_square_plus:before { content: "\F18DB"; }
|
.icon.vector_square_plus:before { content: "\F18DB"; }
|
||||||
.icon.vector_square_remove:before { content: "\F18DC"; }
|
.icon.vector_square_remove:before { content: "\F18DC"; }
|
||||||
@ -530,9 +535,6 @@ input[type=radio] {
|
|||||||
.icon.wifi_strength_1_alert:before { content: "\F0920"; }
|
.icon.wifi_strength_1_alert:before { content: "\F0920"; }
|
||||||
.icon.wifi_strength_4:before { content: "\F0928"; }
|
.icon.wifi_strength_4:before { content: "\F0928"; }
|
||||||
.icon.zigbee:before { content: "\F0D41"; }
|
.icon.zigbee:before { content: "\F0D41"; }
|
||||||
.icon.pencil:before { content: "\F03EB"; }
|
|
||||||
.icon.plus:before { content: "\F0415"; }
|
|
||||||
.icon.delete:before { content: "\F01B4"; }
|
|
||||||
|
|
||||||
.icon.f16:before { font-size: 16px; }
|
.icon.f16:before { font-size: 16px; }
|
||||||
.icon.f24:before { font-size: 24px; }
|
.icon.f24:before { font-size: 24px; }
|
||||||
|
@ -8,6 +8,7 @@ beestat.component.card.floor_plan_editor = function(thermostat_id) {
|
|||||||
this.thermostat_id_ = thermostat_id;
|
this.thermostat_id_ = thermostat_id;
|
||||||
|
|
||||||
var change_function = beestat.debounce(function() {
|
var change_function = beestat.debounce(function() {
|
||||||
|
// todo replace these with (if entity set active false?)
|
||||||
delete self.state_.active_group;
|
delete self.state_.active_group;
|
||||||
delete self.state_.active_room;
|
delete self.state_.active_room;
|
||||||
|
|
||||||
@ -71,10 +72,42 @@ beestat.component.card.floor_plan_editor.prototype.decorate_contents_ = function
|
|||||||
center_container.appendChild(get_started_button);
|
center_container.appendChild(get_started_button);
|
||||||
} else {
|
} else {
|
||||||
const floor_plan = beestat.cache.floor_plan[beestat.setting('floor_plan_id')];
|
const floor_plan = beestat.cache.floor_plan[beestat.setting('floor_plan_id')];
|
||||||
if (this.state_.active_group === undefined) {
|
|
||||||
this.state_.active_group = floor_plan.data.groups[0];
|
// Set group ids if they are not set.
|
||||||
|
floor_plan.data.groups.forEach(function(group) {
|
||||||
|
if (group.group_id === undefined) {
|
||||||
|
group.group_id = window.crypto.randomUUID();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is an active_group_id, override whatever the current active
|
||||||
|
* group is. Used for undo/redo.
|
||||||
|
*/
|
||||||
|
if (this.state_.active_group_id !== undefined) {
|
||||||
|
for (let i = 0; i < floor_plan.data.groups.length; i++) {
|
||||||
|
if (floor_plan.data.groups[i].group_id === this.state_.active_group_id) {
|
||||||
|
this.state_.active_group = floor_plan.data.groups[i];
|
||||||
|
delete this.state_.active_group_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is no active group, set it to best guess of ground floor.
|
||||||
|
if (this.state_.active_group === undefined) {
|
||||||
|
let closest_distance = Infinity;
|
||||||
|
let closest_group;
|
||||||
|
floor_plan.data.groups.forEach(function(group) {
|
||||||
|
if (Math.abs(group.elevation) < closest_distance) {
|
||||||
|
closest_group = group;
|
||||||
|
closest_distance = Math.abs(group.elevation);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.state_.active_group = closest_group;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorate everything.
|
||||||
const drawing_pane_container = $.createElement('div');
|
const drawing_pane_container = $.createElement('div');
|
||||||
drawing_pane_container.style({
|
drawing_pane_container.style({
|
||||||
'position': 'relative',
|
'position': 'relative',
|
||||||
@ -135,7 +168,14 @@ beestat.component.card.floor_plan_editor.prototype.decorate_drawing_pane_ = func
|
|||||||
self.update_floor_plan_();
|
self.update_floor_plan_();
|
||||||
self.rerender();
|
self.rerender();
|
||||||
});
|
});
|
||||||
this.floor_plan_.addEventListener('clear_room', self.rerender.bind(this));
|
this.floor_plan_.addEventListener('undo', function() {
|
||||||
|
self.update_floor_plan_();
|
||||||
|
self.rerender();
|
||||||
|
});
|
||||||
|
this.floor_plan_.addEventListener('redo', function() {
|
||||||
|
self.update_floor_plan_();
|
||||||
|
self.rerender();
|
||||||
|
});
|
||||||
this.floor_plan_.addEventListener('change_group', self.rerender.bind(this));
|
this.floor_plan_.addEventListener('change_group', self.rerender.bind(this));
|
||||||
|
|
||||||
// Add all of the entities to the SVG.
|
// Add all of the entities to the SVG.
|
||||||
@ -170,17 +210,28 @@ beestat.component.card.floor_plan_editor.prototype.decorate_drawing_pane_ = func
|
|||||||
// Update GUI when a room is selected.
|
// Update GUI when a room is selected.
|
||||||
room_entity.addEventListener('activate', function() {
|
room_entity.addEventListener('activate', function() {
|
||||||
self.floor_plan_.update_infobox();
|
self.floor_plan_.update_infobox();
|
||||||
|
self.floor_plan_.update_toolbar();
|
||||||
|
self.update_info_pane_();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update GUI when a room is deselected.
|
||||||
|
room_entity.addEventListener('inactivate', function() {
|
||||||
|
self.floor_plan_.update_infobox();
|
||||||
|
self.floor_plan_.update_toolbar();
|
||||||
self.update_info_pane_();
|
self.update_info_pane_();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Activate the currently active room (mostly for rerenders).
|
// Activate the currently active room (mostly for rerenders).
|
||||||
if (room === self.state_.active_room) {
|
if (
|
||||||
|
self.state_.active_room_entity !== undefined &&
|
||||||
|
room.room_id === self.state_.active_room_entity.get_room().room_id
|
||||||
|
) {
|
||||||
room_entity.set_active(true);
|
room_entity.set_active(true);
|
||||||
} else {
|
|
||||||
// Render the room and save to the list of current entities.
|
|
||||||
room_entity.render(self.floor_plan_.get_g());
|
|
||||||
self.entities_.room.push(room_entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render the room and save to the list of current entities.
|
||||||
|
room_entity.render(self.floor_plan_.get_g());
|
||||||
|
self.entities_.room.push(room_entity);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -489,6 +540,8 @@ beestat.component.card.floor_plan_editor.prototype.get_subtitle_ = function() {
|
|||||||
* only run so fast.
|
* only run so fast.
|
||||||
*/
|
*/
|
||||||
beestat.component.card.floor_plan_editor.prototype.update_floor_plan_ = function() {
|
beestat.component.card.floor_plan_editor.prototype.update_floor_plan_ = function() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
window.clearTimeout(this.update_timeout_);
|
window.clearTimeout(this.update_timeout_);
|
||||||
this.update_timeout_ = window.setTimeout(function() {
|
this.update_timeout_ = window.setTimeout(function() {
|
||||||
new beestat.api()
|
new beestat.api()
|
||||||
@ -498,7 +551,7 @@ beestat.component.card.floor_plan_editor.prototype.update_floor_plan_ = function
|
|||||||
{
|
{
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'floor_plan_id': beestat.setting('floor_plan_id'),
|
'floor_plan_id': beestat.setting('floor_plan_id'),
|
||||||
'data': beestat.cache.floor_plan[beestat.setting('floor_plan_id')].data
|
'data': self.get_floor_plan_data_(beestat.setting('floor_plan_id'))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'update_floor_plan'
|
'update_floor_plan'
|
||||||
@ -507,6 +560,25 @@ beestat.component.card.floor_plan_editor.prototype.update_floor_plan_ = function
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get floor plan data with UUIDs stripped.
|
||||||
|
*
|
||||||
|
* @param {number} floor_plan_id Floor plan ID
|
||||||
|
*
|
||||||
|
* @return {object} The modified floor plan data.
|
||||||
|
*/
|
||||||
|
beestat.component.card.floor_plan_editor.prototype.get_floor_plan_data_ = function(floor_plan_id) {
|
||||||
|
const floor_plan = beestat.cache.floor_plan[floor_plan_id];
|
||||||
|
const data = beestat.clone(floor_plan.data);
|
||||||
|
data.groups.forEach(function(group) {
|
||||||
|
delete group.group_id;
|
||||||
|
group.rooms.forEach(function(room) {
|
||||||
|
delete room.room_id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decorate the menu.
|
* Decorate the menu.
|
||||||
*
|
*
|
||||||
@ -557,7 +629,6 @@ beestat.component.card.floor_plan_editor.prototype.decorate_top_right_ = functio
|
|||||||
).render();
|
).render();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.add_menu_item(new beestat.component.menu_item()
|
menu.add_menu_item(new beestat.component.menu_item()
|
||||||
|
@ -132,7 +132,12 @@ beestat.component.floor_plan.prototype.render = function(parent) {
|
|||||||
e.key.toLowerCase() === 'z' &&
|
e.key.toLowerCase() === 'z' &&
|
||||||
e.ctrlKey === true
|
e.ctrlKey === true
|
||||||
) {
|
) {
|
||||||
console.log('undo');
|
self.undo_();
|
||||||
|
} else if (
|
||||||
|
e.key.toLowerCase() === 'y' &&
|
||||||
|
e.ctrlKey === true
|
||||||
|
) {
|
||||||
|
self.redo_();
|
||||||
} else if (
|
} else if (
|
||||||
e.key === 'ArrowLeft' ||
|
e.key === 'ArrowLeft' ||
|
||||||
e.key === 'ArrowRight' ||
|
e.key === 'ArrowRight' ||
|
||||||
@ -150,16 +155,16 @@ beestat.component.floor_plan.prototype.render = function(parent) {
|
|||||||
|
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case 'ArrowLeft':
|
case 'ArrowLeft':
|
||||||
entity.set_xy(x === null ? null : x - 1, y);
|
entity.set_xy(x === null ? null : x - 1, y, 'update');
|
||||||
break;
|
break;
|
||||||
case 'ArrowRight':
|
case 'ArrowRight':
|
||||||
entity.set_xy(x === null ? null : x + 1, y);
|
entity.set_xy(x === null ? null : x + 1, y, 'update');
|
||||||
break;
|
break;
|
||||||
case 'ArrowUp':
|
case 'ArrowUp':
|
||||||
entity.set_xy(x, y === null ? null : y - 1);
|
entity.set_xy(x, y === null ? null : y - 1, 'update');
|
||||||
break;
|
break;
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
entity.set_xy(x, y === null ? null : y + 1);
|
entity.set_xy(x, y === null ? null : y + 1, 'update');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -492,6 +497,48 @@ beestat.component.floor_plan.prototype.update_toolbar = function() {
|
|||||||
.addEventListener('click', this.toggle_snapping_.bind(this))
|
.addEventListener('click', this.toggle_snapping_.bind(this))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Undo
|
||||||
|
const undo_button = new beestat.component.tile()
|
||||||
|
.set_icon('undo')
|
||||||
|
.set_title('Undo [Ctrl+Z]')
|
||||||
|
.set_background_color(beestat.style.color.bluegray.base);
|
||||||
|
this.button_group_.add_button(undo_button);
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.can_undo_() === true
|
||||||
|
) {
|
||||||
|
undo_button
|
||||||
|
.set_background_hover_color(beestat.style.color.bluegray.light)
|
||||||
|
.set_text_color(beestat.style.color.gray.light)
|
||||||
|
.addEventListener('click', function() {
|
||||||
|
self.undo_();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
undo_button
|
||||||
|
.set_text_color(beestat.style.color.bluegray.dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redo
|
||||||
|
const redo_button = new beestat.component.tile()
|
||||||
|
.set_icon('redo')
|
||||||
|
.set_title('redo [Ctrl+Y]')
|
||||||
|
.set_background_color(beestat.style.color.bluegray.base);
|
||||||
|
this.button_group_.add_button(redo_button);
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.can_redo_() === true
|
||||||
|
) {
|
||||||
|
redo_button
|
||||||
|
.set_background_hover_color(beestat.style.color.bluegray.light)
|
||||||
|
.set_text_color(beestat.style.color.gray.light)
|
||||||
|
.addEventListener('click', function() {
|
||||||
|
self.redo_();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
redo_button
|
||||||
|
.set_text_color(beestat.style.color.bluegray.dark);
|
||||||
|
}
|
||||||
|
|
||||||
// Zoom in
|
// Zoom in
|
||||||
const zoom_in_button = new beestat.component.tile()
|
const zoom_in_button = new beestat.component.tile()
|
||||||
.set_icon('magnify_plus_outline')
|
.set_icon('magnify_plus_outline')
|
||||||
@ -624,12 +671,15 @@ beestat.component.floor_plan.prototype.toggle_snapping_ = function() {
|
|||||||
* @param {object} room Optional room to copy from.
|
* @param {object} room Optional room to copy from.
|
||||||
*/
|
*/
|
||||||
beestat.component.floor_plan.prototype.add_room_ = function(room) {
|
beestat.component.floor_plan.prototype.add_room_ = function(room) {
|
||||||
|
this.save_buffer();
|
||||||
|
|
||||||
const svg_view_box = this.view_box_;
|
const svg_view_box = this.view_box_;
|
||||||
|
|
||||||
let new_room;
|
let new_room;
|
||||||
if (room === undefined) {
|
if (room === undefined) {
|
||||||
const new_room_size = 120;
|
const new_room_size = 120;
|
||||||
new_room = {
|
new_room = {
|
||||||
|
'room_id': window.crypto.randomUUID(),
|
||||||
'x': svg_view_box.x + (svg_view_box.width / 2) - (new_room_size / 2),
|
'x': svg_view_box.x + (svg_view_box.width / 2) - (new_room_size / 2),
|
||||||
'y': svg_view_box.y + (svg_view_box.height / 2) - (new_room_size / 2),
|
'y': svg_view_box.y + (svg_view_box.height / 2) - (new_room_size / 2),
|
||||||
'points': [
|
'points': [
|
||||||
@ -665,6 +715,7 @@ beestat.component.floor_plan.prototype.add_room_ = function(room) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
new_room = {
|
new_room = {
|
||||||
|
'room_id': window.crypto.randomUUID(),
|
||||||
'x': svg_view_box.x + (svg_view_box.width / 2) - ((max_x - min_x) / 2),
|
'x': svg_view_box.x + (svg_view_box.width / 2) - ((max_x - min_x) / 2),
|
||||||
'y': svg_view_box.y + (svg_view_box.height / 2) - ((max_y - min_y) / 2),
|
'y': svg_view_box.y + (svg_view_box.height / 2) - ((max_y - min_y) / 2),
|
||||||
'points': beestat.clone(room.points)
|
'points': beestat.clone(room.points)
|
||||||
@ -672,11 +723,10 @@ beestat.component.floor_plan.prototype.add_room_ = function(room) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.state_.active_group.rooms.push(new_room);
|
this.state_.active_group.rooms.push(new_room);
|
||||||
this.state_.active_room = new_room;
|
new beestat.component.floor_plan_entity.room(this, this.state_)
|
||||||
|
.set_room(new_room)
|
||||||
if (this.state_.active_point_entity !== undefined) {
|
.set_group(this.state_.active_group)
|
||||||
this.state_.active_point_entity.set_active(false);
|
.set_active(true);
|
||||||
}
|
|
||||||
|
|
||||||
this.dispatchEvent('add_room');
|
this.dispatchEvent('add_room');
|
||||||
};
|
};
|
||||||
@ -685,6 +735,8 @@ beestat.component.floor_plan.prototype.add_room_ = function(room) {
|
|||||||
* Remove the currently active room.
|
* Remove the currently active room.
|
||||||
*/
|
*/
|
||||||
beestat.component.floor_plan.prototype.remove_room_ = function() {
|
beestat.component.floor_plan.prototype.remove_room_ = function() {
|
||||||
|
this.save_buffer();
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
const index = this.state_.active_group.rooms.findIndex(function(active_room) {
|
const index = this.state_.active_group.rooms.findIndex(function(active_room) {
|
||||||
@ -718,13 +770,14 @@ beestat.component.floor_plan.prototype.clear_room_ = function() {
|
|||||||
if (this.state_.active_point_entity !== undefined) {
|
if (this.state_.active_point_entity !== undefined) {
|
||||||
this.state_.active_point_entity.set_active(false);
|
this.state_.active_point_entity.set_active(false);
|
||||||
}
|
}
|
||||||
this.dispatchEvent('clear_room');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the currently active point.
|
* Remove the currently active point.
|
||||||
*/
|
*/
|
||||||
beestat.component.floor_plan.prototype.remove_point_ = function() {
|
beestat.component.floor_plan.prototype.remove_point_ = function() {
|
||||||
|
this.save_buffer();
|
||||||
|
|
||||||
if (this.state_.active_room.points.length > 3) {
|
if (this.state_.active_room.points.length > 3) {
|
||||||
for (let i = 0; i < this.state_.active_room.points.length; i++) {
|
for (let i = 0; i < this.state_.active_room.points.length; i++) {
|
||||||
if (this.state_.active_point === this.state_.active_room.points[i]) {
|
if (this.state_.active_point === this.state_.active_room.points[i]) {
|
||||||
@ -934,3 +987,121 @@ beestat.component.floor_plan.prototype.center_content = function() {
|
|||||||
this.update_view_box_();
|
this.update_view_box_();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the current state to the undo/redo buffer.
|
||||||
|
*
|
||||||
|
* @param {boolean} clear Whether or not to allow clearing future buffer
|
||||||
|
* entries.
|
||||||
|
*/
|
||||||
|
beestat.component.floor_plan.prototype.save_buffer = function(clear = true) {
|
||||||
|
const buffer_size = 1000;
|
||||||
|
|
||||||
|
if (this.state_.buffer === undefined) {
|
||||||
|
this.state_.buffer = [];
|
||||||
|
this.state_.buffer_pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the buffer pointer is not at the end, clear those out.
|
||||||
|
if (
|
||||||
|
clear === true &&
|
||||||
|
this.state_.buffer_pointer !== this.state_.buffer.length + 1
|
||||||
|
) {
|
||||||
|
this.state_.buffer.length = this.state_.buffer_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state_.buffer.push({
|
||||||
|
'floor_plan': beestat.clone(beestat.cache.floor_plan[beestat.setting('floor_plan_id')]),
|
||||||
|
'active_room_entity': this.state_.active_room_entity,
|
||||||
|
'active_group_id': this.state_.active_group.group_id
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the buffer gets too long shrink it.
|
||||||
|
if (this.state_.buffer.length > buffer_size) {
|
||||||
|
this.state_.buffer.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the buffer pointer. It always points at the index where the next
|
||||||
|
* buffer write will happen.
|
||||||
|
*/
|
||||||
|
this.state_.buffer_pointer = this.state_.buffer.length;
|
||||||
|
|
||||||
|
this.update_toolbar();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo
|
||||||
|
*/
|
||||||
|
beestat.component.floor_plan.prototype.undo_ = function() {
|
||||||
|
if (this.can_undo_() === true) {
|
||||||
|
/**
|
||||||
|
* When undoing, first save the buffer if the pointer is at the end to
|
||||||
|
* capture the current state then shift the buffer pointer back an extra.
|
||||||
|
*/
|
||||||
|
if (this.state_.buffer_pointer === this.state_.buffer.length) {
|
||||||
|
this.save_buffer(false);
|
||||||
|
this.state_.buffer_pointer--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrement buffer pointer back to the previous row.
|
||||||
|
this.state_.buffer_pointer--;
|
||||||
|
|
||||||
|
// Restore the floor plan.
|
||||||
|
beestat.cache.floor_plan[this.floor_plan_id_] =
|
||||||
|
beestat.clone(this.state_.buffer[this.state_.buffer_pointer].floor_plan);
|
||||||
|
|
||||||
|
// Restore any active room.
|
||||||
|
this.state_.active_room_entity =
|
||||||
|
this.state_.buffer[this.state_.buffer_pointer].active_room_entity;
|
||||||
|
|
||||||
|
// Restore any active group.
|
||||||
|
this.state_.active_group_id =
|
||||||
|
this.state_.buffer[this.state_.buffer_pointer].active_group_id;
|
||||||
|
|
||||||
|
this.update_toolbar();
|
||||||
|
this.dispatchEvent('undo');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not you can undo.
|
||||||
|
*
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
beestat.component.floor_plan.prototype.can_undo_ = function() {
|
||||||
|
return this.state_.buffer_pointer > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redo
|
||||||
|
*/
|
||||||
|
beestat.component.floor_plan.prototype.redo_ = function() {
|
||||||
|
if (this.can_redo_() === true) {
|
||||||
|
this.state_.buffer_pointer++;
|
||||||
|
// Restore the floor plan.
|
||||||
|
beestat.cache.floor_plan[this.floor_plan_id_] =
|
||||||
|
beestat.clone(this.state_.buffer[this.state_.buffer_pointer].floor_plan);
|
||||||
|
|
||||||
|
// Restore any active room.
|
||||||
|
this.state_.active_room_entity =
|
||||||
|
this.state_.buffer[this.state_.buffer_pointer].active_room_entity;
|
||||||
|
|
||||||
|
// Restore any active group.
|
||||||
|
this.state_.active_group_id =
|
||||||
|
this.state_.buffer[this.state_.buffer_pointer].active_group_id;
|
||||||
|
|
||||||
|
this.update_toolbar();
|
||||||
|
this.dispatchEvent('redo');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not you can redo.
|
||||||
|
*
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
beestat.component.floor_plan.prototype.can_redo_ = function() {
|
||||||
|
return this.state_.buffer !== undefined &&
|
||||||
|
this.state_.buffer_pointer + 1 < this.state_.buffer.length;
|
||||||
|
};
|
||||||
|
@ -189,6 +189,7 @@ beestat.component.floor_plan_entity.prototype.mousemove_handler_ = function(e) {
|
|||||||
if (this.dragged_ === false) {
|
if (this.dragged_ === false) {
|
||||||
this.dispatchEvent('drag_start');
|
this.dispatchEvent('drag_start');
|
||||||
this.dragged_ = true;
|
this.dragged_ = true;
|
||||||
|
this.floor_plan_.save_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.after_mousemove_handler_(e);
|
this.after_mousemove_handler_(e);
|
||||||
@ -218,6 +219,7 @@ beestat.component.floor_plan_entity.prototype.mouseup_handler_ = function(e) {
|
|||||||
// If the mouse was actually moved at all then fire the drag stop event.
|
// If the mouse was actually moved at all then fire the drag stop event.
|
||||||
if (this.dragged_ === true) {
|
if (this.dragged_ === true) {
|
||||||
this.dispatchEvent('drag_stop');
|
this.dispatchEvent('drag_stop');
|
||||||
|
this.dispatchEvent('update');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.after_mouseup_handler_(e);
|
this.after_mouseup_handler_(e);
|
||||||
|
@ -15,7 +15,6 @@ beestat.extend(beestat.component.floor_plan_entity.point, beestat.component.floo
|
|||||||
*/
|
*/
|
||||||
beestat.component.floor_plan_entity.point.prototype.decorate_ = function(parent) {
|
beestat.component.floor_plan_entity.point.prototype.decorate_ = function(parent) {
|
||||||
this.decorate_rect_(parent);
|
this.decorate_rect_(parent);
|
||||||
|
|
||||||
this.set_draggable_(true);
|
this.set_draggable_(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -125,10 +124,15 @@ beestat.component.floor_plan_entity.point.prototype.set_room = function(room) {
|
|||||||
*
|
*
|
||||||
* @param {number} x The x position of this entity.
|
* @param {number} x The x position of this entity.
|
||||||
* @param {number} y The y position of this entity.
|
* @param {number} y The y position of this entity.
|
||||||
|
* @param {string} event Optional event to fire when done.
|
||||||
*
|
*
|
||||||
* @return {beestat.component.floor_plan_entity.point} This.
|
* @return {beestat.component.floor_plan_entity.point} This.
|
||||||
*/
|
*/
|
||||||
beestat.component.floor_plan_entity.point.prototype.set_xy = function(x, y) {
|
beestat.component.floor_plan_entity.point.prototype.set_xy = function(x, y, event = 'lesser_update') {
|
||||||
|
if (event === 'update') {
|
||||||
|
this.floor_plan_.save_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
let clamped_x = x + this.room_.get_x();
|
let clamped_x = x + this.room_.get_x();
|
||||||
let clamped_y = y + this.room_.get_y();
|
let clamped_y = y + this.room_.get_y();
|
||||||
|
|
||||||
@ -146,7 +150,7 @@ beestat.component.floor_plan_entity.point.prototype.set_xy = function(x, y) {
|
|||||||
|
|
||||||
this.update_rect_();
|
this.update_rect_();
|
||||||
|
|
||||||
this.dispatchEvent('update');
|
this.dispatchEvent(event);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@ -349,6 +353,8 @@ beestat.component.floor_plan_entity.point.prototype.set_active = function(active
|
|||||||
} else {
|
} else {
|
||||||
delete this.state_.active_point;
|
delete this.state_.active_point;
|
||||||
delete this.state_.active_point_entity;
|
delete this.state_.active_point_entity;
|
||||||
|
|
||||||
|
this.dispatchEvent('inactivate');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.rendered_ === true) {
|
if (this.rendered_ === true) {
|
||||||
|
@ -111,18 +111,17 @@ beestat.component.floor_plan_entity.prototype.decorate_points_ = function(parent
|
|||||||
.render(parent);
|
.render(parent);
|
||||||
|
|
||||||
// Update when a point is moved
|
// Update when a point is moved
|
||||||
point_entity.addEventListener('update', function() {
|
point_entity.addEventListener('lesser_update', function() {
|
||||||
self.update_polygon_();
|
self.update_polygon_();
|
||||||
self.update_walls_();
|
self.update_walls_();
|
||||||
self.dispatchEvent('update');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// When a point is done moving normalize the points
|
// When a point is done moving normalize the points
|
||||||
point_entity.addEventListener('drag_stop', function() {
|
point_entity.addEventListener('update', function() {
|
||||||
self.normalize_points_();
|
self.normalize_points_();
|
||||||
self.update_points_();
|
self.update_points_();
|
||||||
self.update_walls_();
|
|
||||||
self.update_polygon_();
|
self.update_polygon_();
|
||||||
|
self.update_walls_();
|
||||||
self.update_snap_points_();
|
self.update_snap_points_();
|
||||||
self.dispatchEvent('update');
|
self.dispatchEvent('update');
|
||||||
});
|
});
|
||||||
@ -174,25 +173,16 @@ beestat.component.floor_plan_entity.prototype.decorate_walls_ = function(parent)
|
|||||||
.render(parent);
|
.render(parent);
|
||||||
self.walls_.push(wall_entity);
|
self.walls_.push(wall_entity);
|
||||||
|
|
||||||
wall_entity.addEventListener('update', function() {
|
wall_entity.addEventListener('lesser_update', function() {
|
||||||
self.update_polygon_();
|
self.update_polygon_();
|
||||||
self.update_points_();
|
self.update_points_();
|
||||||
self.update_walls_();
|
self.update_walls_();
|
||||||
self.dispatchEvent('update');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear any active points on drag start.
|
wall_entity.addEventListener('update', function() {
|
||||||
wall_entity.addEventListener('drag_start', function() {
|
|
||||||
if (self.active_point_entity_ !== undefined) {
|
|
||||||
self.active_point_entity_.set_active(false);
|
|
||||||
delete self.active_point_entity_;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
wall_entity.addEventListener('drag_stop', function() {
|
|
||||||
self.normalize_points_();
|
self.normalize_points_();
|
||||||
self.update_polygon_();
|
|
||||||
self.update_points_();
|
self.update_points_();
|
||||||
|
self.update_polygon_();
|
||||||
self.update_walls_();
|
self.update_walls_();
|
||||||
self.update_snap_points_();
|
self.update_snap_points_();
|
||||||
self.dispatchEvent('update');
|
self.dispatchEvent('update');
|
||||||
@ -240,6 +230,20 @@ beestat.component.floor_plan_entity.prototype.update_walls_ = function() {
|
|||||||
* @return {beestat.component.floor_plan_entity.room} This.
|
* @return {beestat.component.floor_plan_entity.room} This.
|
||||||
*/
|
*/
|
||||||
beestat.component.floor_plan_entity.room.prototype.set_active = function(active) {
|
beestat.component.floor_plan_entity.room.prototype.set_active = function(active) {
|
||||||
|
/**
|
||||||
|
* Always clear the active point and wall when clicking on a room, even if
|
||||||
|
* it's already active. Also force a toolbar update. This is a little hacky
|
||||||
|
* but works.
|
||||||
|
*/
|
||||||
|
if (this.state_.active_point_entity !== undefined) {
|
||||||
|
this.state_.active_point_entity.set_active(false);
|
||||||
|
this.floor_plan_.update_toolbar();
|
||||||
|
}
|
||||||
|
if (this.state_.active_wall_entity !== undefined) {
|
||||||
|
this.state_.active_wall_entity.set_active(false);
|
||||||
|
this.floor_plan_.update_toolbar();
|
||||||
|
}
|
||||||
|
|
||||||
if (active !== this.active_) {
|
if (active !== this.active_) {
|
||||||
this.active_ = active;
|
this.active_ = active;
|
||||||
|
|
||||||
@ -270,13 +274,13 @@ beestat.component.floor_plan_entity.room.prototype.set_active = function(active)
|
|||||||
if (this.state_.active_point_entity !== undefined) {
|
if (this.state_.active_point_entity !== undefined) {
|
||||||
this.state_.active_point_entity.set_active(false);
|
this.state_.active_point_entity.set_active(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.dispatchEvent('inactivate');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.rendered_ === true) {
|
if (this.rendered_ === true) {
|
||||||
this.rerender();
|
this.rerender();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.floor_plan_.update_toolbar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -337,6 +341,11 @@ beestat.component.floor_plan_entity.room.prototype.set_room = function(room) {
|
|||||||
this.x_ = room.x;
|
this.x_ = room.x;
|
||||||
this.y_ = room.y;
|
this.y_ = room.y;
|
||||||
|
|
||||||
|
// Ensure a UUID is set on the room.
|
||||||
|
if (this.room_.room_id === undefined) {
|
||||||
|
this.room_.room_id = window.crypto.randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -359,10 +368,15 @@ beestat.component.floor_plan_entity.room.prototype.set_group = function(group) {
|
|||||||
*
|
*
|
||||||
* @param {number} x The x position of this entity.
|
* @param {number} x The x position of this entity.
|
||||||
* @param {number} y The y position of this entity.
|
* @param {number} y The y position of this entity.
|
||||||
|
* @param {string} event Optional event to fire when done.
|
||||||
*
|
*
|
||||||
* @return {beestat.component.floor_plan_entity} This.
|
* @return {beestat.component.floor_plan_entity} This.
|
||||||
*/
|
*/
|
||||||
beestat.component.floor_plan_entity.room.prototype.set_xy = function(x, y) {
|
beestat.component.floor_plan_entity.room.prototype.set_xy = function(x, y, event = 'lesser_update') {
|
||||||
|
if (event === 'update') {
|
||||||
|
this.floor_plan_.save_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
let clamped_x = x;
|
let clamped_x = x;
|
||||||
let clamped_y = y;
|
let clamped_y = y;
|
||||||
|
|
||||||
@ -382,7 +396,7 @@ beestat.component.floor_plan_entity.room.prototype.set_xy = function(x, y) {
|
|||||||
this.room_.x = Math.round(clamped_x);
|
this.room_.x = Math.round(clamped_x);
|
||||||
this.room_.y = Math.round(clamped_y);
|
this.room_.y = Math.round(clamped_y);
|
||||||
|
|
||||||
this.dispatchEvent('update');
|
this.dispatchEvent(event);
|
||||||
|
|
||||||
return beestat.component.floor_plan_entity.prototype.set_xy.apply(
|
return beestat.component.floor_plan_entity.prototype.set_xy.apply(
|
||||||
this,
|
this,
|
||||||
@ -485,7 +499,6 @@ beestat.component.floor_plan_entity.room.prototype.after_mouseup_handler_ = func
|
|||||||
if (this.dragged_ === true) {
|
if (this.dragged_ === true) {
|
||||||
this.clear_snap_lines_();
|
this.clear_snap_lines_();
|
||||||
this.update_snap_points_();
|
this.update_snap_points_();
|
||||||
this.dispatchEvent('update');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,6 +65,8 @@ beestat.component.floor_plan_entity.wall.prototype.decorate_line_ = function(par
|
|||||||
* @param {Event} e
|
* @param {Event} e
|
||||||
*/
|
*/
|
||||||
beestat.component.floor_plan_entity.wall.prototype.add_point = function(e) {
|
beestat.component.floor_plan_entity.wall.prototype.add_point = function(e) {
|
||||||
|
this.floor_plan_.save_buffer();
|
||||||
|
|
||||||
const room = this.room_.get_room();
|
const room = this.room_.get_room();
|
||||||
for (let i = 0; i < room.points.length; i++) {
|
for (let i = 0; i < room.points.length; i++) {
|
||||||
if (this.point_1_ === room.points[i]) {
|
if (this.point_1_ === room.points[i]) {
|
||||||
@ -303,10 +305,15 @@ beestat.component.floor_plan_entity.wall.prototype.set_room = function(room) {
|
|||||||
*
|
*
|
||||||
* @param {number} x The x position of this entity.
|
* @param {number} x The x position of this entity.
|
||||||
* @param {number} y The y position of this entity.
|
* @param {number} y The y position of this entity.
|
||||||
|
* @param {string} event Optional event to fire when done.
|
||||||
*
|
*
|
||||||
* @return {beestat.component.floor_plan_entity.wall} This.
|
* @return {beestat.component.floor_plan_entity.wall} This.
|
||||||
*/
|
*/
|
||||||
beestat.component.floor_plan_entity.wall.prototype.set_xy = function(x, y) {
|
beestat.component.floor_plan_entity.wall.prototype.set_xy = function(x, y, event = 'lesser_update') {
|
||||||
|
if (event === 'update') {
|
||||||
|
this.floor_plan_.save_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
let clamped_x = x + this.room_.get_x();
|
let clamped_x = x + this.room_.get_x();
|
||||||
let clamped_y = y + this.room_.get_y();
|
let clamped_y = y + this.room_.get_y();
|
||||||
|
|
||||||
@ -326,7 +333,7 @@ beestat.component.floor_plan_entity.wall.prototype.set_xy = function(x, y) {
|
|||||||
this.point_2_.y = Math.round(clamped_y - this.room_.get_y());
|
this.point_2_.y = Math.round(clamped_y - this.room_.get_y());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchEvent('update');
|
this.dispatchEvent(event);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@ -568,6 +575,8 @@ beestat.component.floor_plan_entity.wall.prototype.set_active = function(active)
|
|||||||
this.dispatchEvent('activate');
|
this.dispatchEvent('activate');
|
||||||
} else {
|
} else {
|
||||||
delete this.state_.active_wall_entity;
|
delete this.state_.active_wall_entity;
|
||||||
|
|
||||||
|
this.dispatchEvent('inactivate');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.rendered_ === true) {
|
if (this.rendered_ === true) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user