// zoom.js "use strict"; (() => { // src/custom_setting_types.ts var def_classes = () => { class Numlist2 extends Setting { step; input_container = null; push_btn = null; pop_btn = null; constructor(name, storage_name, default_values = [], desc = "", step = 1, custom_validator = () => true, disabled = false) { super( name, storage_name, [5, 0], disabled, default_values ?? [], desc, custom_validator ); this.step = step; } #new_input(value, i) { const elem = document.createElement("input"); elem.type = "number"; elem.value = value.toString(); elem.step = this.step.toString(); elem.onchange = (ev) => { const parsed = Number.parseFloat(ev.target.value); if (!Number.isNaN(parsed)) { this.value[i] = parsed; this.set(this.value); } }; return elem; } #push_pop_btns() { this.push_btn = document.createElement("button"); this.push_btn.style.color = "#0F0"; this.push_btn.innerText = "+"; this.pop_btn = document.createElement("button"); this.pop_btn.style.color = "#F00"; this.pop_btn.innerText = "-"; this.push_btn.onclick = () => { this.value.push(1); this.input_container.append(this.#new_input(1, this.value.length)); }; this.pop_btn.onclick = () => { this.value.pop(); if (this.input_container.lastChild) { this.input_container.removeChild(this.input_container.lastChild); } }; return [this.push_btn, this.pop_btn]; } disable() { this.push_btn?.setAttribute("disabled", "true"); this.pop_btn?.setAttribute("disabled", "true"); } enable() { this.push_btn?.removeAttribute("disabled"); this.pop_btn?.removeAttribute("disabled"); } build() { const value = this.get(); const container = document.createElement("span"); container.classList.add("setting-span", "zm_nml_setting"); const l_container = document.createElement("span"); const label = document.createElement("span"); label.innerText = this.name; const btn_container = document.createElement("span"); btn_container.classList.add("zm_nml_btn_container"); btn_container.append(...this.#push_pop_btns()); l_container.append(label, document.createElement("br"), btn_container); this.input_container = document.createElement("span"); this.input_container.classList.add("zm_nml_icontainer"); const elems = []; value.forEach((x, i) => { elems.push(this.#new_input(x, i)); }); this.input_container.append(...elems); container.append(l_container, this.input_container); return container; } } class MultiSetting extends Setting { settings; elements = []; multi_input_name; rows = []; constructor(name, storage_name, extra_opts, ...settings) { super( name, storage_name, [255], extra_opts.disabled, extra_opts.default_value ?? 0, extra_opts.desc, void 0 ); this.settings = settings; this.multi_input_name = crypto.randomUUID(); } build() { const container = document.createElement("span"); this.settings.forEach((setting, i) => { const row_container = document.createElement("div"); row_container.classList.add("zm_ms_row"); this.rows.push(row_container); const select_btn = document.createElement("button"); select_btn.classList.add("zm_ms_selbtn"); select_btn.innerText = "#"; const built_item = setting.build(); built_item.classList.add("zm_ms_item"); built_item.dataset.index = i.toString(); row_container.dataset.current = i == this.value ? "true" : "false"; select_btn.onclick = () => { this.set(i); setting.enable(); for (const setting2 of this.settings) setting2.disable(); for (const row of this.rows) { row.dataset.current = "false"; row.querySelectorAll(".zm_ms_item input").forEach((x) => x.setAttribute("disabled", "true")); } built_item.querySelectorAll("input").forEach((x) => x.removeAttribute("disabled")); row_container.dataset.current = "true"; }; row_container.append(select_btn, built_item); container.appendChild(row_container); }); return container; } } class SettingGroup extends Setting { settings; constructor(settings) { super( "", "", [2763], false ); this.settings = settings; } enable() { for (const x of Object.values(this.settings)) { x.enable(); } } disable() { for (const x of Object.values(this.settings)) { x.disable(); } } build() { const container = document.createElement("div"); for (const x of Object.values(this.settings)) { container.appendChild(x.build()); } return container; } get() { return this.settings; } // Override these so the defaults don't do anything set() { } update() { } onUpdate() { } } return { Numlist: Numlist2, MultiSetting, SettingGroup }; }; // src/custom_settings.ts var CustomSettingsManager = class { canvas_bkg; zoom; unl_zoom; show_floater; fpan_speed; cpan_speed; upan_speed; constructor(on_edit) { const { Numlist: Numlist2, MultiSetting, SettingGroup } = def_classes(); const settings_tab = new SettingsTab("zoom.js"); const validator = () => { on_edit.cb(this); return true; }; this.canvas_bkg = new Setting( "Canvas background", "canvas_bkg", settingType.COLOR, false, "#252525", "The colour for the area around the canvas", validator ); this.cpan_speed = new Setting( "Coarse pan speed", "cpan_speed", settingType.NUMBER, false, 10, "The default pan speed", validator ); this.fpan_speed = new Setting( "Fine pan speed", "fpan_speed", settingType.NUMBER, false, 3, "The pan speed when holding shift (F in the floater)", validator ); this.upan_speed = new Setting( "Ultrafine pan speed", "upan_speed", settingType.NUMBER, false, 1, "The pan speed when holding alt (U in the floater)", validator ); this.show_floater = new Setting( "Show floater", "show_floater", settingType.BOOLEAN, false, true, "Whether to show the floater or not", validator ); const zoom_levels = new Numlist2( "Zoom levels", "zoom_levels", [0.5, 1, 2, 3, 6, 12], "Zoom levels", 1, validator ); this.unl_zoom = new SettingGroup({ speed: new Setting( "Zoom speed", "unl_zoom_speed", settingType.NUMBER, false, 2, "The zoom magnitude (as the multiplier to the zoom level every time zoom is used)", validator ), min: new Setting( "Zoom limit (min)", "unl_zlim_min", settingType.NUMBER, false, 0.25, "The lower zoom limit (reducing may lead to rounding error coming back from very low levels)", validator ), max: new Setting( "Zoom limit (max)", "unl_zlim_max", settingType.NUMBER, false, 25, "The upper zoom limit (reducing may lead to rounding error coming back from very high levels)", validator ) }); this.zoom = new MultiSetting( "Zoom mode", "zoom_mode", {}, zoom_levels, this.unl_zoom ); settings_tab.registerSettings( void 0, this.canvas_bkg, this.show_floater, this.zoom ); settings_tab.registerSettings( "Panning", this.cpan_speed, this.fpan_speed, this.upan_speed ); settingsManager.registerTab(settings_tab); } }; // src/handler.ts var Handler = class { settings; patcher; zoom_panning = [0, 0]; zoom_level; constructor(settings, patcher) { this.settings = settings; this.patcher = patcher; this.zoom_level = 1; this.patch_keybinds(); this.patch_floater(); window.getMousePos = (canvas2, evt) => { if (evt.touches) { evt.preventDefault(); evt = evt.touches[0]; isMobile = true; } const rect = canvas2.getBoundingClientRect(); const clx = evt.clientX; const cly = evt.clientY; let x = (clx - rect.left) / this.scale(); let y = (cly - rect.top) / this.scale(); x = Math.floor(x / canvas2.clientWidth * (width + 1)); y = Math.floor(y / canvas2.clientHeight * (height + 1)); return { x, y }; }; runAfterReset(() => { this.zoom_level = 1; this.zoom_panning = [0, 0]; this.rescale(); }); } handle_zoom(direction) { if (this.settings.zoom.value == 0) { switch (direction) { case "in": if (!(this.zoom_level + 1 in this.settings.zoom.settings[0].value)) { break; } this.zoom_level += 1; break; case "out": if (!(this.zoom_level - 1 in this.settings.zoom.settings[0].value)) { break; } this.zoom_level -= 1; break; } } else { const settings = this.settings.zoom.settings[1].settings; const speed = settings.speed.value; const min = settings.min.value; const max = settings.max.value; switch (direction) { case "in": if (this.zoom_level * speed > max) break; this.zoom_level *= speed; break; case "out": if (this.zoom_level / speed < min) break; this.zoom_level /= speed; break; } this.zoom_level = Number(this.zoom_level.toPrecision(3)); } this.rescale(); } handle_pan(direction, speed) { switch (direction) { case "right": this.zoom_panning[0] -= speed; break; case "left": this.zoom_panning[0] += speed; break; case "up": this.zoom_panning[1] += speed; break; case "down": this.zoom_panning[1] -= speed; break; } this.rescale(); } scale() { return this.settings.zoom.value == 0 ? this.settings.zoom.settings[0].value[this.zoom_level] : this.zoom_level; } rescale() { this.log_info(); const x = this.zoom_panning[0] * (pixelSize * this.scale()); const y = this.zoom_panning[1] * (pixelSize * this.scale()); canvas.style.transform = `translate(${x}px, ${y}px) translateX(-50%) scale(${this.scale()})`; } log_info() { const x_pan = (-this.zoom_panning[0]).toString().padEnd(4); const y_pan = (-this.zoom_panning[1]).toString().padEnd(4); this.patcher.zoom_data_div.innerText = ""; this.patcher.zoom_data_div.innerText += `Scale: ${this.scale()}x `; this.patcher.zoom_data_div.innerText += `Pan : ${x_pan}, ${y_pan}`; } patch_keybinds() { keybinds["9"] = () => this.handle_zoom("in"); keybinds["0"] = () => this.handle_zoom("out"); keybinds["w"] = (ev) => this.handle_pan("up", ev.altKey ? this.settings.upan_speed.value : this.settings.cpan_speed.value); keybinds["a"] = (ev) => this.handle_pan("left", ev.altKey ? this.settings.upan_speed.value : this.settings.cpan_speed.value); keybinds["s"] = (ev) => this.handle_pan("down", ev.altKey ? this.settings.upan_speed.value : this.settings.cpan_speed.value); keybinds["d"] = (ev) => this.handle_pan("right", ev.altKey ? this.settings.upan_speed.value : this.settings.cpan_speed.value); keybinds["W"] = () => this.handle_pan("up", this.settings.fpan_speed.value); keybinds["A"] = () => this.handle_pan("left", this.settings.fpan_speed.value); keybinds["S"] = () => this.handle_pan("down", this.settings.fpan_speed.value); keybinds["D"] = () => this.handle_pan("right", this.settings.fpan_speed.value); } speed() { switch (this.patcher.panmode_sel.innerText) { case "C": return this.settings.cpan_speed.value; case "F": return this.settings.fpan_speed.value; case "U": return this.settings.upan_speed.value; default: return 0; } } patch_floater() { document.getElementById("zm_floater_u").onclick = () => this.handle_pan("up", this.speed()); document.getElementById("zm_floater_d").onclick = () => this.handle_pan("down", this.speed()); document.getElementById("zm_floater_l").onclick = () => this.handle_pan("left", this.speed()); document.getElementById("zm_floater_r").onclick = () => this.handle_pan("right", this.speed()); } }; // assets/ctrl_info.html var ctrl_info_default = "