You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.3 KiB
181 lines
4.3 KiB
function ui_offline() { |
|
document.body.classList.add('offline'); |
|
document.querySelector('.offline-toast').classList.remove('hidden'); |
|
} |
|
|
|
function ui_online() { |
|
document.body.classList.remove('offline'); |
|
document.querySelector('.offline-toast').classList.add('hidden'); |
|
} |
|
|
|
async function insert_image(state, context, file) { |
|
const bitmap = await createImageBitmap(file); |
|
|
|
const p = { 'x': state.cursor.x, 'y': state.cursor.y }; |
|
const canvasp = screen_to_canvas(state, p); |
|
|
|
canvasp.x -= bitmap.width / 2; |
|
canvasp.y -= bitmap.height / 2; |
|
|
|
const form_data = new FormData(); |
|
form_data.append('file', file); |
|
|
|
const resp = await fetch(`/api/image?deskId=${state.desk_id}`, { |
|
method: 'post', |
|
body: form_data, |
|
}) |
|
|
|
if (resp.ok) { |
|
const image_id = await resp.text(); |
|
const event = image_event(image_id, canvasp.x, canvasp.y); |
|
await queue_event(state, event); |
|
} |
|
} |
|
|
|
function event_size(event) { |
|
let size = 4; // type |
|
|
|
switch (event.type) { |
|
case EVENT.PREDRAW: |
|
case EVENT.MOVE_CURSOR: { |
|
size += 4 * 2; |
|
break; |
|
} |
|
|
|
case EVENT.LEAVE: |
|
case EVENT.CLEAR: { |
|
break; |
|
} |
|
|
|
case EVENT.SET_COLOR: { |
|
size += 4; |
|
break; |
|
} |
|
|
|
case EVENT.SET_WIDTH: { |
|
size += 2; |
|
break; |
|
} |
|
|
|
case EVENT.STROKE: { |
|
size += 4 + 2 + 2 + 4 + event.points.length * 4 * 2; // u32 stroke id + u16 (count) + u16 (width) + u32 (color + count * (f32, f32) points |
|
break; |
|
} |
|
|
|
case EVENT.UNDO: |
|
case EVENT.REDO: { |
|
break; |
|
} |
|
|
|
case EVENT.IMAGE: |
|
case EVENT.IMAGE_MOVE: { |
|
size += 4 + 4 + 4; // file id + x + y |
|
break; |
|
} |
|
|
|
case EVENT.ERASER: { |
|
size += 4; // stroke id |
|
break; |
|
} |
|
|
|
default: { |
|
console.error('fuck'); |
|
} |
|
} |
|
|
|
return size; |
|
} |
|
|
|
function find_touch(touchlist, id) { |
|
for (const touch of touchlist) { |
|
if (touch.identifier === id) { |
|
return touch; |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
function find_image(state, image_id) { |
|
for (let i = state.events.length - 1; i >= 0; --i) { |
|
const event = state.events[i]; |
|
if (event.type === EVENT.IMAGE && !event.deleted && event.image_id === image_id) { |
|
return event; |
|
} |
|
} |
|
} |
|
|
|
// TODO: move these to a file? TypedVector |
|
function tv_create(class_name, capacity) { |
|
return { |
|
'class_name': class_name, |
|
'data': new class_name(capacity), |
|
'capacity': capacity, |
|
'size': 0, |
|
}; |
|
} |
|
|
|
function tv_data(tv) { |
|
return tv.data.subarray(0, tv.size); |
|
} |
|
|
|
function tv_ensure(tv, capacity) { |
|
if (tv.capacity < capacity) { |
|
const new_tv = tv_create(tv.class_name, capacity); |
|
|
|
new_tv.data.set(tv_data(tv)); |
|
new_tv.size = tv.size; |
|
|
|
return new_tv; |
|
} |
|
|
|
return tv; |
|
} |
|
|
|
function tv_ensure_by(tv, by) { |
|
return tv_ensure(tv, round_to_pow2(tv.size + by, 4096)); |
|
} |
|
|
|
function tv_add(tv, item) { |
|
tv.data[tv.size++] = item; |
|
} |
|
|
|
function tv_pop(tv) { |
|
const result = tv.data[tv.size - 1]; |
|
tv.size--; |
|
return result; |
|
} |
|
|
|
function tv_append(tv, typedarray) { |
|
tv.data.set(typedarray, tv.size); |
|
tv.size += typedarray.length; |
|
} |
|
|
|
function tv_clear(tv) { |
|
tv.size = 0; |
|
} |
|
|
|
function HTML(html) { |
|
const template = document.createElement('template'); |
|
template.innerHTML = html.trim(); |
|
return template.content.firstChild; |
|
} |
|
|
|
function insert_player_cursor(state, player_id) { |
|
const color = random_bright_color_from_seed(parseInt(player_id)); |
|
const path_copy = state.cursor_path.cloneNode(); |
|
path_copy.style.fill = color; |
|
const cursor = HTML(`<svg viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" class="player-cursor" data-player-id="${player_id}">${path_copy.outerHTML}</svg>`); |
|
document.querySelector('.html-hud').appendChild(cursor); |
|
return cursor; |
|
} |
|
|
|
async function load_player_cursor_template(state) { |
|
const resp = await fetch('icons/player-cursor.svg'); |
|
const text = await resp.text(); |
|
const parser = new DOMParser(); |
|
const parsed_xml = parser.parseFromString(text, 'image/svg+xml'); |
|
const path = parsed_xml.querySelector('path'); |
|
|
|
state.cursor_path = path; |
|
}
|
|
|