| @@ -1,3 +1,5 @@ | |||||
| //#region variables | |||||
| let selected = null; | let selected = null; | ||||
| let prevSelected = null; | let prevSelected = null; | ||||
| let selectedEntity = null; | let selectedEntity = null; | ||||
| @@ -61,6 +63,18 @@ const tagDefs = { | |||||
| goo: "Goo", | goo: "Goo", | ||||
| }; | }; | ||||
| const availableEntities = {}; | |||||
| const availableEntitiesByName = {}; | |||||
| const entities = {}; | |||||
| let ratioInfo; | |||||
| //#endregion | |||||
| //#region units | |||||
| math.createUnit({ | math.createUnit({ | ||||
| ShoeSizeMensUS: { | ShoeSizeMensUS: { | ||||
| prefixes: "long", | prefixes: "long", | ||||
| @@ -380,6 +394,8 @@ math.createUnit("HU", { | |||||
| aliases: ["HUs", "hammerUnits"], | aliases: ["HUs", "hammerUnits"], | ||||
| }); | }); | ||||
| //#endregion | |||||
| const defaultUnits = { | const defaultUnits = { | ||||
| length: { | length: { | ||||
| metric: "meters", | metric: "meters", | ||||
| @@ -515,6 +531,7 @@ const unitChoices = { | |||||
| ], | ], | ||||
| }, | }, | ||||
| }; | }; | ||||
| const config = { | const config = { | ||||
| height: math.unit(1500, "meters"), | height: math.unit(1500, "meters"), | ||||
| x: 0, | x: 0, | ||||
| @@ -530,11 +547,7 @@ const config = { | |||||
| autoSwallowSize: "off" | autoSwallowSize: "off" | ||||
| }; | }; | ||||
| const availableEntities = {}; | |||||
| const availableEntitiesByName = {}; | |||||
| const entities = {}; | |||||
| //#region transforms | |||||
| function constrainRel(coords) { | function constrainRel(coords) { | ||||
| const worldWidth = | const worldWidth = | ||||
| @@ -600,6 +613,10 @@ function pix2pos(coords) { | |||||
| return { x: x, y: y }; | return { x: x, y: y }; | ||||
| } | } | ||||
| //#endregion | |||||
| //#region update | |||||
| function updateEntityElement(entity, element) { | function updateEntityElement(entity, element) { | ||||
| const position = pos2pix({ x: element.dataset.x, y: element.dataset.y }); | const position = pos2pix({ x: element.dataset.x, y: element.dataset.y }); | ||||
| const view = entity.view; | const view = entity.view; | ||||
| @@ -624,7 +641,7 @@ function updateEntityElement(entity, element) { | |||||
| const bonus = (extra ? extra : 1) * (1 / (1 - (bottom ? bottom : 0))); | const bonus = (extra ? extra : 1) * (1 / (1 - (bottom ? bottom : 0))); | ||||
| let height = pixels * bonus; | let height = pixels * bonus; | ||||
| // working around a Firefoxi here | |||||
| // working around a Firefox issue here | |||||
| if (height > 17895698) { | if (height > 17895698) { | ||||
| height = 0; | height = 0; | ||||
| @@ -670,8 +687,6 @@ function updateEntityElement(entity, element) { | |||||
| updateInfo(); | updateInfo(); | ||||
| } | } | ||||
| let ratioInfo; | |||||
| function updateInfo() { | function updateInfo() { | ||||
| let text = ""; | let text = ""; | ||||
| if (config.showRatios) { | if (config.showRatios) { | ||||
| @@ -919,48 +934,6 @@ function updateInfo() { | |||||
| ratioInfo.innerText = text; | ratioInfo.innerText = text; | ||||
| } | } | ||||
| function pickUnit() { | |||||
| if (!config.autoUnits) { | |||||
| return; | |||||
| } | |||||
| let type = null; | |||||
| let category = null; | |||||
| const heightSelect = document.querySelector("#options-height-unit"); | |||||
| currentUnit = heightSelect.value; | |||||
| Object.keys(unitChoices).forEach((unitType) => { | |||||
| Object.keys(unitChoices[unitType]).forEach((unitCategory) => { | |||||
| if (unitChoices[unitType][unitCategory].includes(currentUnit)) { | |||||
| type = unitType; | |||||
| category = unitCategory; | |||||
| } | |||||
| }); | |||||
| }); | |||||
| // This should only happen if the unit selector isn't set up yet. | |||||
| // It doesn't really matter what goes into it. | |||||
| if (type === null || category === null) { | |||||
| return "meters"; | |||||
| } | |||||
| const choices = unitChoices[type][category].map((unit) => { | |||||
| let value = config.height.toNumber(unit); | |||||
| if (value < 1) { | |||||
| value = 1 / value / value; | |||||
| } | |||||
| return [unit, value]; | |||||
| }); | |||||
| heightSelect.value = choices.sort((a, b) => { | |||||
| return a[1] - b[1]; | |||||
| })[0][0]; | |||||
| selectNewUnit(); | |||||
| } | |||||
| function updateEntityProperties(element) { | function updateEntityProperties(element) { | ||||
| entity = entities[element.dataset.key] | entity = entities[element.dataset.key] | ||||
| @@ -1013,6 +986,52 @@ function updateSizes(dirtyOnly = false) { | |||||
| drawRulers(); | drawRulers(); | ||||
| } | } | ||||
| //#endregion | |||||
| function pickUnit() { | |||||
| if (!config.autoUnits) { | |||||
| return; | |||||
| } | |||||
| let type = null; | |||||
| let category = null; | |||||
| const heightSelect = document.querySelector("#options-height-unit"); | |||||
| currentUnit = heightSelect.value; | |||||
| Object.keys(unitChoices).forEach((unitType) => { | |||||
| Object.keys(unitChoices[unitType]).forEach((unitCategory) => { | |||||
| if (unitChoices[unitType][unitCategory].includes(currentUnit)) { | |||||
| type = unitType; | |||||
| category = unitCategory; | |||||
| } | |||||
| }); | |||||
| }); | |||||
| // This should only happen if the unit selector isn't set up yet. | |||||
| // It doesn't really matter what goes into it. | |||||
| if (type === null || category === null) { | |||||
| return "meters"; | |||||
| } | |||||
| const choices = unitChoices[type][category].map((unit) => { | |||||
| let value = config.height.toNumber(unit); | |||||
| if (value < 1) { | |||||
| value = 1 / value / value; | |||||
| } | |||||
| return [unit, value]; | |||||
| }); | |||||
| heightSelect.value = choices.sort((a, b) => { | |||||
| return a[1] - b[1]; | |||||
| })[0][0]; | |||||
| selectNewUnit(); | |||||
| } | |||||
| //#region drawing | |||||
| function cleanRulers() { | function cleanRulers() { | ||||
| rulers = rulers.filter(ruler => { | rulers = rulers.filter(ruler => { | ||||
| if (!ruler.entityKey) { | if (!ruler.entityKey) { | ||||
| @@ -1022,6 +1041,7 @@ function cleanRulers() { | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| function drawRulers() { | function drawRulers() { | ||||
| cleanRulers(); | cleanRulers(); | ||||
| const canvas = document.querySelector("#rulers"); | const canvas = document.querySelector("#rulers"); | ||||
| @@ -1525,6 +1545,10 @@ function drawHorizontalScale(ifDirty = false) { | |||||
| drawTicks(ctx, pixelsPer, heightPer); | drawTicks(ctx, pixelsPer, heightPer); | ||||
| } | } | ||||
| //#endregion | |||||
| //#region entities | |||||
| // Entities are generated as needed, and we make a copy | // Entities are generated as needed, and we make a copy | ||||
| // every time - the resulting objects get mutated, after all. | // every time - the resulting objects get mutated, after all. | ||||
| // But we also want to be able to read some information without | // But we also want to be able to read some information without | ||||
| @@ -1862,6 +1886,8 @@ function makeEntity(info, views, sizes, forms = {}) { | |||||
| return entityTemplate; | return entityTemplate; | ||||
| } | } | ||||
| //#endregion | |||||
| function combineInfo(existing, next) { | function combineInfo(existing, next) { | ||||
| switch (next.mode) { | switch (next.mode) { | ||||
| case "replace": | case "replace": | ||||
| @@ -1875,6 +1901,8 @@ function combineInfo(existing, next) { | |||||
| return existing; | return existing; | ||||
| } | } | ||||
| //#region interaction | |||||
| function clickDown(target, x, y) { | function clickDown(target, x, y) { | ||||
| clicked = target; | clicked = target; | ||||
| movingInBounds = false; | movingInBounds = false; | ||||
| @@ -2000,6 +2028,10 @@ function select(target) { | |||||
| document.querySelector("#fit").disabled = false; | document.querySelector("#fit").disabled = false; | ||||
| } | } | ||||
| //#endregion | |||||
| //#region ui | |||||
| function configFormList(entity, selectedForm) { | function configFormList(entity, selectedForm) { | ||||
| const label = document.querySelector("#options-label-form"); | const label = document.querySelector("#options-label-form"); | ||||
| const list = document.querySelector("#entity-form"); | const list = document.querySelector("#entity-form"); | ||||
| @@ -2379,6 +2411,8 @@ function setNumericInput(input, value, round = 6) { | |||||
| input.value = value.toPrecision(round); | input.value = value.toPrecision(round); | ||||
| } | } | ||||
| //#endregion | |||||
| function getSortedEntities() { | function getSortedEntities() { | ||||
| return Object.keys(entities).sort((a, b) => { | return Object.keys(entities).sort((a, b) => { | ||||
| const entA = entities[a]; | const entA = entities[a]; | ||||
| @@ -3620,10 +3654,6 @@ function prepareSettings(userSettings) { | |||||
| function prepareMenu() { | function prepareMenu() { | ||||
| prepareSidebar(); | prepareSidebar(); | ||||
| updateSaveInfo(); | updateSaveInfo(); | ||||
| if (checkHelpDate()) { | |||||
| document.querySelector("#open-help").classList.add("highlighted"); | |||||
| } | |||||
| } | } | ||||
| function updateSaveInfo() { | function updateSaveInfo() { | ||||
| @@ -3664,6 +3694,7 @@ function getSaves() { | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| function getUserSettings() { | function getUserSettings() { | ||||
| try { | try { | ||||
| const settings = JSON.parse(localStorage.getItem("settings")); | const settings = JSON.parse(localStorage.getItem("settings")); | ||||
| @@ -3689,32 +3720,6 @@ function setUserSettings(settings) { | |||||
| // :( | // :( | ||||
| } | } | ||||
| } | } | ||||
| const lastHelpChange = 1601955834693; | |||||
| function checkHelpDate() { | |||||
| // disabling this for now | |||||
| return false; | |||||
| try { | |||||
| const old = localStorage.getItem("help-viewed"); | |||||
| if (old === null || old < lastHelpChange) { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } catch { | |||||
| console.warn("Could not set the help-viewed date"); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| function setHelpDate() { | |||||
| try { | |||||
| localStorage.setItem("help-viewed", Date.now()); | |||||
| } catch { | |||||
| console.warn("Could not set the help-viewed date"); | |||||
| } | |||||
| } | |||||
| function doYScroll() { | function doYScroll() { | ||||
| const worldHeight = config.height.toNumber("meters"); | const worldHeight = config.height.toNumber("meters"); | ||||
| @@ -5961,8 +5966,6 @@ function pasteScene() { | |||||
| // probably wasn't valid data | // probably wasn't valid data | ||||
| } | } | ||||
| } | } | ||||
| // TODO - don't just search through every single entity | |||||
| // probably just have a way to do lookups directly | |||||
| function findEntity(name) { | function findEntity(name) { | ||||
| return availableEntitiesByName[name]; | return availableEntitiesByName[name]; | ||||
| @@ -6015,7 +6018,7 @@ const migrationDefs = [ | |||||
| }, | }, | ||||
| /* | /* | ||||
| Migration: 4 -> 5 | Migration: 4 -> 5 | ||||
| f | |||||
| Flipping is now stored | Flipping is now stored | ||||
| */ | */ | ||||
| @@ -6128,7 +6131,7 @@ function renderToCanvas() { | |||||
| function exportCanvas(callback) { | function exportCanvas(callback) { | ||||
| /** @type {CanvasRenderingContext2D} */ | /** @type {CanvasRenderingContext2D} */ | ||||
| const ctx = document.querySelector("#display").getContext("2d"); | const ctx = document.querySelector("#display").getContext("2d"); | ||||
| const blob = ctx.canvas.toBlob(callback); | |||||
| ctx.canvas.toBlob(callback); | |||||
| } | } | ||||
| function generateScreenshot(callback) { | function generateScreenshot(callback) { | ||||