| @@ -1,3 +1,5 @@ | |||
| //#region variables | |||
| let selected = null; | |||
| let prevSelected = null; | |||
| let selectedEntity = null; | |||
| @@ -61,6 +63,18 @@ const tagDefs = { | |||
| goo: "Goo", | |||
| }; | |||
| const availableEntities = {}; | |||
| const availableEntitiesByName = {}; | |||
| const entities = {}; | |||
| let ratioInfo; | |||
| //#endregion | |||
| //#region units | |||
| math.createUnit({ | |||
| ShoeSizeMensUS: { | |||
| prefixes: "long", | |||
| @@ -380,6 +394,8 @@ math.createUnit("HU", { | |||
| aliases: ["HUs", "hammerUnits"], | |||
| }); | |||
| //#endregion | |||
| const defaultUnits = { | |||
| length: { | |||
| metric: "meters", | |||
| @@ -515,6 +531,7 @@ const unitChoices = { | |||
| ], | |||
| }, | |||
| }; | |||
| const config = { | |||
| height: math.unit(1500, "meters"), | |||
| x: 0, | |||
| @@ -530,11 +547,7 @@ const config = { | |||
| autoSwallowSize: "off" | |||
| }; | |||
| const availableEntities = {}; | |||
| const availableEntitiesByName = {}; | |||
| const entities = {}; | |||
| //#region transforms | |||
| function constrainRel(coords) { | |||
| const worldWidth = | |||
| @@ -600,6 +613,10 @@ function pix2pos(coords) { | |||
| return { x: x, y: y }; | |||
| } | |||
| //#endregion | |||
| //#region update | |||
| function updateEntityElement(entity, element) { | |||
| const position = pos2pix({ x: element.dataset.x, y: element.dataset.y }); | |||
| const view = entity.view; | |||
| @@ -624,7 +641,7 @@ function updateEntityElement(entity, element) { | |||
| const bonus = (extra ? extra : 1) * (1 / (1 - (bottom ? bottom : 0))); | |||
| let height = pixels * bonus; | |||
| // working around a Firefoxi here | |||
| // working around a Firefox issue here | |||
| if (height > 17895698) { | |||
| height = 0; | |||
| @@ -670,8 +687,6 @@ function updateEntityElement(entity, element) { | |||
| updateInfo(); | |||
| } | |||
| let ratioInfo; | |||
| function updateInfo() { | |||
| let text = ""; | |||
| if (config.showRatios) { | |||
| @@ -919,48 +934,6 @@ function updateInfo() { | |||
| 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) { | |||
| entity = entities[element.dataset.key] | |||
| @@ -1013,6 +986,52 @@ function updateSizes(dirtyOnly = false) { | |||
| 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() { | |||
| rulers = rulers.filter(ruler => { | |||
| if (!ruler.entityKey) { | |||
| @@ -1022,6 +1041,7 @@ function cleanRulers() { | |||
| } | |||
| }); | |||
| } | |||
| function drawRulers() { | |||
| cleanRulers(); | |||
| const canvas = document.querySelector("#rulers"); | |||
| @@ -1525,6 +1545,10 @@ function drawHorizontalScale(ifDirty = false) { | |||
| drawTicks(ctx, pixelsPer, heightPer); | |||
| } | |||
| //#endregion | |||
| //#region entities | |||
| // Entities are generated as needed, and we make a copy | |||
| // every time - the resulting objects get mutated, after all. | |||
| // But we also want to be able to read some information without | |||
| @@ -1862,6 +1886,8 @@ function makeEntity(info, views, sizes, forms = {}) { | |||
| return entityTemplate; | |||
| } | |||
| //#endregion | |||
| function combineInfo(existing, next) { | |||
| switch (next.mode) { | |||
| case "replace": | |||
| @@ -1875,6 +1901,8 @@ function combineInfo(existing, next) { | |||
| return existing; | |||
| } | |||
| //#region interaction | |||
| function clickDown(target, x, y) { | |||
| clicked = target; | |||
| movingInBounds = false; | |||
| @@ -2000,6 +2028,10 @@ function select(target) { | |||
| document.querySelector("#fit").disabled = false; | |||
| } | |||
| //#endregion | |||
| //#region ui | |||
| function configFormList(entity, selectedForm) { | |||
| const label = document.querySelector("#options-label-form"); | |||
| const list = document.querySelector("#entity-form"); | |||
| @@ -2379,6 +2411,8 @@ function setNumericInput(input, value, round = 6) { | |||
| input.value = value.toPrecision(round); | |||
| } | |||
| //#endregion | |||
| function getSortedEntities() { | |||
| return Object.keys(entities).sort((a, b) => { | |||
| const entA = entities[a]; | |||
| @@ -3620,10 +3654,6 @@ function prepareSettings(userSettings) { | |||
| function prepareMenu() { | |||
| prepareSidebar(); | |||
| updateSaveInfo(); | |||
| if (checkHelpDate()) { | |||
| document.querySelector("#open-help").classList.add("highlighted"); | |||
| } | |||
| } | |||
| function updateSaveInfo() { | |||
| @@ -3664,6 +3694,7 @@ function getSaves() { | |||
| return false; | |||
| } | |||
| } | |||
| function getUserSettings() { | |||
| try { | |||
| 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() { | |||
| const worldHeight = config.height.toNumber("meters"); | |||
| @@ -5961,8 +5966,6 @@ function pasteScene() { | |||
| // 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) { | |||
| return availableEntitiesByName[name]; | |||
| @@ -6015,7 +6018,7 @@ const migrationDefs = [ | |||
| }, | |||
| /* | |||
| Migration: 4 -> 5 | |||
| f | |||
| Flipping is now stored | |||
| */ | |||
| @@ -6128,7 +6131,7 @@ function renderToCanvas() { | |||
| function exportCanvas(callback) { | |||
| /** @type {CanvasRenderingContext2D} */ | |||
| const ctx = document.querySelector("#display").getContext("2d"); | |||
| const blob = ctx.canvas.toBlob(callback); | |||
| ctx.canvas.toBlob(callback); | |||
| } | |||
| function generateScreenshot(callback) { | |||