158 lines
3.4 KiB
JavaScript
158 lines
3.4 KiB
JavaScript
let space;
|
|
let spaceId;
|
|
|
|
let scale = 1;
|
|
|
|
let editing;
|
|
let dragging;
|
|
let moved;
|
|
let offset;
|
|
|
|
function mousemove(event) {
|
|
let left = (event.clientX - space.offsetLeft) * scale - offset.x;
|
|
let top = (event.clientY - space.offsetTop) * scale - offset.y;
|
|
dragging.style.left = `${left < 0 ? 0 : left}px`;
|
|
dragging.style.top = `${top < 0 ? 0 : top}px`;
|
|
moved = true;
|
|
save(dragging);
|
|
}
|
|
|
|
let saving;
|
|
let queue;
|
|
|
|
function save(span) {
|
|
if (saving) {
|
|
queue = span;
|
|
return;
|
|
}
|
|
saving = true;
|
|
window.emit('save_span', {
|
|
thread: spaceId,
|
|
id: span.id ? span.id.slice(4) : '',
|
|
content: span.innerText,
|
|
x: span.style.left.slice(0, -2),
|
|
y: span.style.top.slice(0, -2),
|
|
scale: span.scale
|
|
}, msg => {
|
|
if (!msg.success)
|
|
console.log('span save failed: ' + msg.message);
|
|
if (!span.id)
|
|
span.id = 'span' + msg.id;
|
|
saving = false;
|
|
if (queue) {
|
|
save(queue);
|
|
queue = null;
|
|
}
|
|
});
|
|
}
|
|
|
|
function add(s) {
|
|
let span = document.createElement('span');
|
|
span.classList.add('span');
|
|
if (s.id)
|
|
span.id = 'span' + s.id;
|
|
span.innerText = s.content;
|
|
span.contentEditable = true;
|
|
span.spellcheck = false;
|
|
span.scale = s.scale;
|
|
span.style.left = `${s.x}px`;
|
|
span.style.top = `${s.y}px`;
|
|
span.style.transform = `translate(-50%, -50%) scale(${s.scale})`;
|
|
span.onkeydown = function(event) {
|
|
if (event.key === 'Enter' && !event.getModifierState('Shift')) {
|
|
event.preventDefault();
|
|
editing = null;
|
|
span.blur();
|
|
}
|
|
};
|
|
span.oninput = function(event) {
|
|
save(this);
|
|
};
|
|
span.onblur = function(event) {
|
|
if (this.innerText)
|
|
return;
|
|
save(this);
|
|
this.remove();
|
|
};
|
|
span.onwheel = function(event) {
|
|
event.preventDefault();
|
|
if (event.deltaY < 0 && this.scale >= 200)
|
|
return;
|
|
this.scale *= 1 - event.deltaY * .001;
|
|
this.style.transform = `translate(-50%, -50%) scale(${this.scale})`;
|
|
save(this);
|
|
};
|
|
span.onmousedown = function(event) {
|
|
if (dragging || editing === this)
|
|
return;
|
|
dragging = this;
|
|
event.preventDefault();
|
|
offset = {
|
|
x: event.clientX - (space.offsetLeft + this.offsetLeft),
|
|
y: event.clientY - (space.offsetTop + this.offsetTop)
|
|
};
|
|
moved = false;
|
|
document.addEventListener('mousemove', mousemove);
|
|
};
|
|
span.onmouseup = function(event) {
|
|
event.stopPropagation();
|
|
document.removeEventListener('mousemove', mousemove);
|
|
dragging = null;
|
|
if (moved)
|
|
return;
|
|
this.focus();
|
|
editing = this;
|
|
};
|
|
space.append(span);
|
|
return span;
|
|
}
|
|
|
|
window.socket.on('span', msg => {
|
|
if (msg.thread !== spaceId)
|
|
return;
|
|
let span = document.getElementById('span' + msg.id);
|
|
if (span) {
|
|
span.innerText = msg.content;
|
|
span.x = msg.x;
|
|
span.y = msg.y;
|
|
span.scale = msg.scale;
|
|
span.style.transform = `translate(-50%, -50%) scale(${msg.scale})`;
|
|
}
|
|
else
|
|
add(msg);
|
|
});
|
|
|
|
export default function loadSpace() {
|
|
if (!space) {
|
|
space = document.getElementById('space');
|
|
space.onmouseup = event => {
|
|
if (dragging) {
|
|
dragging.onmouseup(event);
|
|
return;
|
|
}
|
|
if (editing) {
|
|
if (event.target !== editing)
|
|
editing = null;
|
|
return;
|
|
}
|
|
editing = add({
|
|
x: event.offsetX + space.scrollLeft,
|
|
y: event.offsetY + space.scrollTop,
|
|
scale: 1,
|
|
content: ''
|
|
});
|
|
editing.focus();
|
|
};
|
|
}
|
|
if (spaceId === window.threadId)
|
|
return;
|
|
spaceId = window.threadId;
|
|
space.innerHTML = '';
|
|
window.emit('get_space', { thread: window.threadId }, msg => {
|
|
if (!msg.success)
|
|
console.log('get space failed: ' + msg.message);
|
|
for (const span of msg.spans)
|
|
add(span);
|
|
});
|
|
};
|