From b6b210d269989a6400d6dc9d3f775f24fc032ee5 Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 00:01:43 +0100 Subject: [PATCH 01/12] Added trajectory to text conversion. --- dist/main/editor/editor.js | 8 +- dist/main/solvers/sequence.js | 13 ++-- dist/main/solvers/trajectory.js | 31 ++++---- dist/main/utilities/array.js | 9 +++ dist/main/utilities/trajectory-text.js | 87 +++++++++++++++++++++ src/main/editor/editor.ts | 9 ++- src/main/solvers/sequence.ts | 18 +++-- src/main/solvers/trajectory.ts | 33 ++++---- src/main/utilities/array.ts | 10 +++ src/main/utilities/trajectory-text.ts | 102 +++++++++++++++++++++++++ src/types.d.ts | 1 + 11 files changed, 273 insertions(+), 48 deletions(-) create mode 100644 dist/main/utilities/trajectory-text.js create mode 100644 src/main/utilities/trajectory-text.ts diff --git a/dist/main/editor/editor.js b/dist/main/editor/editor.js index a9ec619..1c46cfd 100644 --- a/dist/main/editor/editor.js +++ b/dist/main/editor/editor.js @@ -15,6 +15,7 @@ import { Trajectory } from "../solvers/trajectory.js"; import { Selector } from "./selector.js"; import { DiscreteRange } from "./range.js"; import { loadBodiesData, loadConfig } from "../utilities/data.js"; +import { trajectoryToText } from "../utilities/trajectory-text.js"; export async function initEditorWithSystem(systems, systemIndex) { const canvas = document.getElementById("three-canvas"); const width = canvas.clientWidth; @@ -179,8 +180,8 @@ export async function initEditorWithSystem(systems, systemIndex) { if (trajectory) trajectory.remove(); }; - const displayFoundTrajectory = () => { - trajectory = new Trajectory(solver.bestSteps, system, config); + const displayFoundTrajectory = (sequence) => { + trajectory = new Trajectory(solver, system, config); trajectory.draw(canvas); trajectory.fillResultControls(resultItems, systemTime, controls); systemTime.input(() => { @@ -192,6 +193,7 @@ export async function initEditorWithSystem(systems, systemIndex) { stepSlider.enable(); trajectory.updatePodPosition(systemTime); console.log(solver.bestDeltaV); + console.log(trajectoryToText(trajectory, sequence)); }; const findTrajectory = async () => { paramsErr.hide(); @@ -225,7 +227,7 @@ export async function initEditorWithSystem(systems, systemIndex) { const perfStart = performance.now(); await solver.searchOptimalTrajectory(sequence, userSettings); console.log(`Search time: ${performance.now() - perfStart} ms`); - displayFoundTrajectory(); + displayFoundTrajectory(sequence); } catch (err) { if (err instanceof Error && err.message != "TRAJECTORY FINDER CANCELLED") diff --git a/dist/main/solvers/sequence.js b/dist/main/solvers/sequence.js index bb50c5c..d3fa789 100644 --- a/dist/main/solvers/sequence.js +++ b/dist/main/solvers/sequence.js @@ -1,3 +1,4 @@ +import { joinStrings } from "../utilities/array.js"; export class FlybySequence { constructor(system, ids) { this.ids = ids; @@ -6,12 +7,12 @@ export class FlybySequence { this.bodies.push(system.bodyFromId(id)); } this.length = this.bodies.length; - const getSubstr = (i) => this.bodies[i].name.substring(0, 2); - let str = getSubstr(0); - for (let i = 1; i < this.length; i++) { - str += "-" + getSubstr(i); - } - this.seqString = str; + const initials = this.bodies.map((body) => body.name.substring(0, 2)); + this.seqString = joinStrings(initials, "-"); + } + get seqStringFullNames() { + const names = this.bodies.map((body) => body.name); + return joinStrings(names, "-"); } static fromString(str, system) { str = str.trim(); diff --git a/dist/main/solvers/trajectory.js b/dist/main/solvers/trajectory.js index 2ec24b8..2fe1232 100644 --- a/dist/main/solvers/trajectory.js +++ b/dist/main/solvers/trajectory.js @@ -3,18 +3,19 @@ import { Orbit } from "../objects/orbit.js"; import { KSPTime } from "../time/time.js"; import { SpriteManager } from "../utilities/sprites.js"; export class Trajectory { - constructor(steps, system, config) { - this.steps = steps; + constructor(solver, system, config) { + this.solver = solver; this.system = system; this.config = config; this._orbitObjects = []; this._spriteObjects = []; this._podSpriteIndex = 0; this.orbits = []; - this._maneuvres = []; - this._flybys = []; + this.maneuvres = []; + this.flybys = []; this._displayedSteps = []; this._spritesUpdateFunId = -1; + this.steps = solver.bestSteps; for (const { orbitElts, attractorId } of this.steps) { const attractor = this.system.bodyFromId(attractorId); const orbit = Orbit.fromOrbitalElements(orbitElts, attractor, config.orbit); @@ -158,15 +159,17 @@ export class Trajectory { progradeDV: progradeDir.dot(deltaV), normalDV: normalDir.dot(deltaV), radialDV: radialDir.dot(deltaV), + totalDV: deltaV.length(), ejectAngle: ejectAngle }; - this._maneuvres.push(details); + this.maneuvres.push(details); } } } _calculateFlybyDetails() { const departureDate = this.steps[0].dateOfStart; - for (const { flyby } of this.steps) { + for (let i = 0; i < this.steps.length; i++) { + const { flyby } = this.steps[i]; if (flyby) { const body = this.system.bodyFromId(flyby.bodyId); let inc = flyby.inclination * 57.2957795131; @@ -178,14 +181,14 @@ export class Trajectory { periAltitude: (flyby.periRadius - body.radius) / 1000, inclinationDeg: inc }; - this._flybys.push(details); + this.flybys.push(details); } } } fillResultControls(resultItems, systemTime, controls) { const depDate = KSPTime(this.steps[0].dateOfStart, this.config.time); const arrDate = KSPTime(this.steps[this.steps.length - 1].dateOfStart, this.config.time); - resultItems.totalDVSpan.innerHTML = this._totalDeltaV.toFixed(1); + resultItems.totalDVSpan.innerHTML = this.totalDeltaV.toFixed(1); resultItems.depDateSpan.innerHTML = depDate.stringYDHMS("hms", "ut"); resultItems.arrDateSpan.innerHTML = arrDate.stringYDHMS("hms", "ut"); const onDateClick = (date) => () => { @@ -207,7 +210,7 @@ export class Trajectory { for (let i = 0; i < this.steps.length; i++) { const { maneuvre, flyby } = this.steps[i]; if (maneuvre) { - const details = this._maneuvres[maneuvreIdx]; + const details = this.maneuvres[maneuvreIdx]; const step = this.steps[details.stepIndex]; const context = step.maneuvre.context; let optionName; @@ -233,7 +236,7 @@ export class Trajectory { selectorOptions.push(option); } else if (flyby) { - const details = this._flybys[flybyIdx]; + const details = this.flybys[flybyIdx]; const bodyName = this.system.bodyFromId(details.bodyId).name; const optionName = `${++optionNumber}: ${bodyName} flyby`; const option = { @@ -251,7 +254,7 @@ export class Trajectory { detailsSelector.change((_, index) => { const option = selectorOptions[index]; if (option.type == "maneuver") { - const details = this._maneuvres[option.origin]; + const details = this.maneuvres[option.origin]; const dateEMT = KSPTime(details.dateMET, this.config.time); resultItems.dateSpan.innerHTML = dateEMT.stringYDHMS("hm", "emt"); resultItems.progradeDVSpan.innerHTML = details.progradeDV.toFixed(1); @@ -272,7 +275,7 @@ export class Trajectory { resultItems.maneuverDiv.hidden = false; } else if (option.type == "flyby") { - const details = this._flybys[option.origin]; + const details = this.flybys[option.origin]; const startDateEMT = KSPTime(details.soiEnterDateMET, this.config.time); const endDateEMT = KSPTime(details.soiExitDateMET, this.config.time); resultItems.startDateSpan.innerHTML = startDateEMT.stringYDHMS("hm", "emt"); @@ -336,9 +339,9 @@ export class Trajectory { pod.position.set(pos.x, pos.y, pos.z); pod.position.multiplyScalar(scale); } - get _totalDeltaV() { + get totalDeltaV() { let total = 0; - for (const details of this._maneuvres) { + for (const details of this.maneuvres) { const x = details.progradeDV; const y = details.normalDV; const z = details.radialDV; diff --git a/dist/main/utilities/array.js b/dist/main/utilities/array.js index 365427c..299b846 100644 --- a/dist/main/utilities/array.js +++ b/dist/main/utilities/array.js @@ -23,3 +23,12 @@ export function shuffleArray(array) { array[j] = tmp; } } +export function joinStrings(arr, sep) { + if (arr.length == 0) + return ""; + let str = arr[0]; + for (let i = 1; i < arr.length; i++) { + str += sep + arr[i]; + } + return str; +} diff --git a/dist/main/utilities/trajectory-text.js b/dist/main/utilities/trajectory-text.js new file mode 100644 index 0000000..caa130a --- /dev/null +++ b/dist/main/utilities/trajectory-text.js @@ -0,0 +1,87 @@ +import { KSPTime } from "../time/time.js"; +import { joinStrings } from "./array.js"; +export function trajectoryToText(traj, seq) { + const { steps, system, config } = traj; + const pairs = []; + const add = (label, data, indent) => { + pairs.push({ label, data, indent }); + }; + const space = () => add("", "", 0); + add("Sequence", seq.seqStringFullNames, 0); + const depDate = KSPTime(steps[0].dateOfStart, config.time); + const arrDate = KSPTime(steps[steps.length - 1].dateOfStart, config.time); + add("Departure", depDate.stringYDHMS("hms", "ut"), 0); + add("Arrival", arrDate.stringYDHMS("hms", "ut"), 0); + add("Total ΔV", `${traj.totalDeltaV.toFixed(1)} m/s`, 0); + space(); + add("Steps", "", 0); + let maneuvreIdx = 0, flybyIdx = 0; + for (let i = 0; i < steps.length; i++) { + const { maneuvre, flyby } = steps[i]; + if (maneuvre) { + space(); + const step = steps[i]; + const details = traj.maneuvres[maneuvreIdx]; + const context = step.maneuvre.context; + const { progradeDV, normalDV, radialDV, totalDV } = details; + let label; + if (context.type == "ejection") { + const startBodyName = system.bodyFromId(step.attractorId).name; + label = `${startBodyName} escape`; + } + else if (context.type == "dsm") { + const originName = system.bodyFromId(context.originId).name; + const targetName = system.bodyFromId(context.targetId).name; + label = `${originName}-${targetName} DSM`; + } + else { + const arrivalBodyName = system.bodyFromId(step.attractorId).name; + label = `${arrivalBodyName} circularization`; + } + add(label, "", 1); + add("Date", KSPTime(details.dateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + if (details.ejectAngle !== undefined) { + add("Ejection angle", `${details.ejectAngle.toFixed(1)}°`, 2); + } + add("ΔV", `${totalDV.toFixed(1)} m/s`, 2); + add("Prograde", `${progradeDV.toFixed(1)}`, 3); + add("Normal", `${normalDV.toFixed(1)}`, 3); + add("Radial", `${radialDV.toFixed(1)}`, 3); + maneuvreIdx++; + } + else if (flyby) { + space(); + const details = traj.flybys[flybyIdx]; + const bodyName = system.bodyFromId(details.bodyId).name; + add(`Flyby around ${bodyName}`, "", 1); + add("SOI enter date", KSPTime(details.soiEnterDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + add("SOI exit date", KSPTime(details.soiExitDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + add("Periapsis altitude", `${details.periAltitude.toFixed(0)} km`, 2); + add("Inclination", `${details.inclinationDeg.toFixed(0)}°`, 2); + flybyIdx++; + } + } + return pairsToString(pairs); +} +function pairsToString(pairs) { + const lines = []; + for (const pair of pairs) { + if (pair.label == "") { + lines.push(""); + continue; + } + let indent = " ".repeat(pair.indent * 2); + lines.push(`${indent}${pair.label}:`); + } + let maxLen = 0; + for (const line of lines) { + maxLen = Math.max(maxLen, line.length); + } + for (let i = 0; i < pairs.length; i++) { + if (pairs[i].label == "" || pairs[i].data == "") + continue; + const spaces = " ".repeat(maxLen - lines[i].length + 1); + lines[i] += spaces + pairs[i].data; + } + return joinStrings(lines, "\n"); +} diff --git a/src/main/editor/editor.ts b/src/main/editor/editor.ts index a21f70c..3c4c289 100644 --- a/src/main/editor/editor.ts +++ b/src/main/editor/editor.ts @@ -16,6 +16,7 @@ import { Selector } from "./selector.js"; import { DiscreteRange } from "./range.js"; import { OrbitingBody } from "../objects/body.js"; import { loadBodiesData, loadConfig } from "../utilities/data.js"; +import { trajectoryToText } from "../utilities/trajectory-text.js"; export async function initEditorWithSystem(systems: SolarSystemData[], systemIndex: number){ @@ -240,8 +241,8 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd if(trajectory) trajectory.remove(); } - const displayFoundTrajectory = () => { - trajectory = new Trajectory(solver.bestSteps, system, config); + const displayFoundTrajectory = (sequence: FlybySequence) => { + trajectory = new Trajectory(solver, system, config); trajectory.draw(canvas); trajectory.fillResultControls(resultItems, systemTime, controls); @@ -256,6 +257,8 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd trajectory.updatePodPosition(systemTime); console.log(solver.bestDeltaV); + + console.log(trajectoryToText(trajectory, sequence)); }; const findTrajectory = async () => { @@ -298,7 +301,7 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd await solver.searchOptimalTrajectory(sequence, userSettings); console.log(`Search time: ${performance.now() - perfStart} ms`); - displayFoundTrajectory(); + displayFoundTrajectory(sequence); } catch(err) { if(err instanceof Error && err.message != "TRAJECTORY FINDER CANCELLED") diff --git a/src/main/solvers/sequence.ts b/src/main/solvers/sequence.ts index d422123..21437d6 100644 --- a/src/main/solvers/sequence.ts +++ b/src/main/solvers/sequence.ts @@ -1,5 +1,6 @@ -import { OrbitingBody } from "../objects/body"; -import { SolarSystem } from "../objects/system"; +import { OrbitingBody } from "../objects/body.js"; +import { SolarSystem } from "../objects/system.js"; +import { joinStrings } from "../utilities/array.js"; export class FlybySequence { public readonly bodies!: OrbitingBody[]; @@ -13,12 +14,13 @@ export class FlybySequence { } this.length = this.bodies.length; - const getSubstr = (i: number) => this.bodies[i].name.substring(0, 2); - let str = getSubstr(0); - for(let i = 1; i < this.length; i++){ - str += "-" + getSubstr(i); - } - this.seqString = str; + const initials = this.bodies.map((body: OrbitingBody) => body.name.substring(0, 2)); + this.seqString = joinStrings(initials, "-"); + } + + get seqStringFullNames(){ + const names = this.bodies.map((body: OrbitingBody) => body.name); + return joinStrings(names, "-"); } static fromString(str: string, system: SolarSystem){ diff --git a/src/main/solvers/trajectory.ts b/src/main/solvers/trajectory.ts index f18b0f7..17c7e8d 100644 --- a/src/main/solvers/trajectory.ts +++ b/src/main/solvers/trajectory.ts @@ -6,21 +6,24 @@ import { KSPTime } from "../time/time.js"; import { CameraController } from "../objects/camera.js"; import { SpriteManager } from "../utilities/sprites.js"; import { OrbitingBody } from "../objects/body.js"; +import { TrajectorySolver } from "./trajectory-solver.js"; export class Trajectory { private _orbitObjects: THREE.Object3D[] = []; private _spriteObjects: THREE.Sprite[][] = []; private _podSpriteIndex: number = 0; + public readonly steps: TrajectoryStep[]; public readonly orbits: Orbit[] = []; - private readonly _maneuvres: ManeuvreDetails[] = []; - private readonly _flybys: FlybyDetails[] = []; + public readonly maneuvres: ManeuvreDetails[] = []; + public readonly flybys: FlybyDetails[] = []; private _displayedSteps: boolean[] = []; private _spritesUpdateFunId: number = -1; - constructor(public readonly steps: TrajectoryStep[], public readonly system: SolarSystem, public readonly config: Config) { + constructor(public readonly solver: TrajectorySolver, public readonly system: SolarSystem, public readonly config: Config) { + this.steps = solver.bestSteps; for(const {orbitElts, attractorId} of this.steps) { const attractor = this.system.bodyFromId(attractorId); const orbit = Orbit.fromOrbitalElements(orbitElts, attractor, config.orbit); @@ -224,16 +227,17 @@ export class Trajectory { ejectAngle = Math.acos(cosA) * 180 / Math.PI; ejectAngle *= Math.sign(u.x*v.y - u.y*v.x); // counter clockwise direction of the angle } - + const details = { stepIndex: i, dateMET: step.dateOfStart - departureDate, progradeDV: progradeDir.dot(deltaV), normalDV: normalDir.dot(deltaV), radialDV: radialDir.dot(deltaV), + totalDV: deltaV.length(), ejectAngle: ejectAngle }; - this._maneuvres.push(details); + this.maneuvres.push(details); } } } @@ -243,7 +247,8 @@ export class Trajectory { */ private _calculateFlybyDetails(){ const departureDate = this.steps[0].dateOfStart; - for(const {flyby} of this.steps){ + for(let i = 0; i < this.steps.length; i++){ + const {flyby} = this.steps[i]; if(flyby){ const body = this.system.bodyFromId(flyby.bodyId); // non oriented inclination compared to x-z plane @@ -256,7 +261,7 @@ export class Trajectory { periAltitude: (flyby.periRadius - body.radius) / 1000, // in km inclinationDeg: inc } - this._flybys.push(details); + this.flybys.push(details); } } } @@ -272,7 +277,7 @@ export class Trajectory { const arrDate = KSPTime(this.steps[this.steps.length-1].dateOfStart, this.config.time); // total delta-V - resultItems.totalDVSpan.innerHTML = this._totalDeltaV.toFixed(1); + resultItems.totalDVSpan.innerHTML = this.totalDeltaV.toFixed(1); // departure date resultItems.depDateSpan.innerHTML = depDate.stringYDHMS("hms", "ut"); // arrival date @@ -305,7 +310,7 @@ export class Trajectory { for(let i = 0; i < this.steps.length; i++){ const {maneuvre, flyby} = this.steps[i]; if(maneuvre){ - const details = this._maneuvres[maneuvreIdx]; + const details = this.maneuvres[maneuvreIdx]; const step = this.steps[details.stepIndex]; const context = (step.maneuvre).context; @@ -333,7 +338,7 @@ export class Trajectory { } else if(flyby){ // details the options in the selector, if it's a flyby - const details = this._flybys[flybyIdx]; + const details = this.flybys[flybyIdx]; const bodyName = this.system.bodyFromId(details.bodyId).name; const optionName = `${++optionNumber}: ${bodyName} flyby`; @@ -358,7 +363,7 @@ export class Trajectory { const option = selectorOptions[index]; if(option.type == "maneuver"){ - const details = this._maneuvres[option.origin]; + const details = this.maneuvres[option.origin]; const dateEMT = KSPTime(details.dateMET, this.config.time); resultItems.dateSpan.innerHTML = dateEMT.stringYDHMS("hm", "emt"); @@ -382,7 +387,7 @@ export class Trajectory { resultItems.maneuverDiv.hidden = false; } else if(option.type == "flyby"){ - const details = this._flybys[option.origin]; + const details = this.flybys[option.origin]; const startDateEMT = KSPTime(details.soiEnterDateMET, this.config.time); const endDateEMT = KSPTime(details.soiExitDateMET, this.config.time); @@ -478,9 +483,9 @@ export class Trajectory { /** * Computes and returns the total delta-V of the trajectory */ - private get _totalDeltaV(){ + public get totalDeltaV(){ let total = 0; - for(const details of this._maneuvres){ + for(const details of this.maneuvres){ const x = details.progradeDV; const y = details.normalDV; const z = details.radialDV; diff --git a/src/main/utilities/array.ts b/src/main/utilities/array.ts index d21753b..1fe5254 100644 --- a/src/main/utilities/array.ts +++ b/src/main/utilities/array.ts @@ -24,4 +24,14 @@ export function shuffleArray(array: T[]){ array[i] = array[j]; array[j] = tmp; } +} + +export function joinStrings(arr: string[], sep: string){ + if(arr.length == 0) + return ""; + let str = arr[0]; + for(let i = 1; i < arr.length; i++){ + str += sep + arr[i]; + } + return str; } \ No newline at end of file diff --git a/src/main/utilities/trajectory-text.ts b/src/main/utilities/trajectory-text.ts new file mode 100644 index 0000000..a6d3ddd --- /dev/null +++ b/src/main/utilities/trajectory-text.ts @@ -0,0 +1,102 @@ +import { FlybySequence } from "../solvers/sequence.js"; +import { Trajectory } from "../solvers/trajectory.js"; +import { KSPTime } from "../time/time.js"; +import { joinStrings } from "./array.js"; + +type pair = {label: string, data: string, indent: number}; + +export function trajectoryToText(traj: Trajectory, seq: FlybySequence) { + const {steps, system, config} = traj; + + const pairs: pair[] = []; + const add = (label: string, data: string, indent: number) => { + pairs.push({label, data, indent} as pair); + }; + const space = () => add("", "", 0); + + + add("Sequence", seq.seqStringFullNames, 0); + + const depDate = KSPTime(steps[0].dateOfStart, config.time); + const arrDate = KSPTime(steps[steps.length-1].dateOfStart, config.time); + add("Departure", depDate.stringYDHMS("hms", "ut"), 0); + add("Arrival", arrDate.stringYDHMS("hms", "ut"), 0); + add("Total ΔV", `${traj.totalDeltaV.toFixed(1)} m/s`, 0); + space(); + add("Steps", "", 0); + + let maneuvreIdx = 0, flybyIdx = 0; + + for(let i = 0; i < steps.length; i++){ + const {maneuvre, flyby} = steps[i]; + if(maneuvre){ + space(); + const step = steps[i]; + const details = traj.maneuvres[maneuvreIdx]; + const context = (step.maneuvre).context; + const {progradeDV, normalDV, radialDV, totalDV} = details; + + let label: string; + if(context.type == "ejection") { + const startBodyName = system.bodyFromId(step.attractorId).name; + label = `${startBodyName} escape`; + } else if(context.type == "dsm") { + const originName = system.bodyFromId(context.originId).name; + const targetName = system.bodyFromId(context.targetId).name; + label = `${originName}-${targetName} DSM`; + } else { + const arrivalBodyName = system.bodyFromId(step.attractorId).name; + label = `${arrivalBodyName} circularization`; + } + add(label, "", 1); + add("Date", KSPTime(details.dateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + if(details.ejectAngle !== undefined){ + add("Ejection angle", `${details.ejectAngle.toFixed(1)}°`, 2); + } + add("ΔV", `${totalDV.toFixed(1)} m/s`, 2); + add("Prograde", `${progradeDV.toFixed(1)}`, 3); + add("Normal", `${normalDV.toFixed(1)}`, 3); + add("Radial", `${radialDV.toFixed(1)}`, 3); + + maneuvreIdx++; + + } else if(flyby){ + space(); + const details = traj.flybys[flybyIdx]; + const bodyName = system.bodyFromId(details.bodyId).name; + add(`Flyby around ${bodyName}`, "", 1); + add("SOI enter date", KSPTime(details.soiEnterDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + add("SOI exit date", KSPTime(details.soiExitDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + add("Periapsis altitude", `${details.periAltitude.toFixed(0)} km`, 2); + add("Inclination", `${details.inclinationDeg.toFixed(0)}°`, 2); + + flybyIdx++; + } + } + + return pairsToString(pairs); +} + + +function pairsToString(pairs: pair[]){ + const lines: string[] = []; + for(const pair of pairs){ + if(pair.label == "") { + lines.push(""); + continue; + } + let indent = " ".repeat(pair.indent*2); + lines.push(`${indent}${pair.label}:`); + } + let maxLen = 0; + for(const line of lines){ + maxLen = Math.max(maxLen, line.length); + } + for(let i = 0; i < pairs.length; i++){ + if(pairs[i].label == "" || pairs[i].data == "") + continue; + const spaces = " ".repeat(maxLen - lines[i].length + 1); + lines[i] += spaces + pairs[i].data; + } + return joinStrings(lines, "\n"); +} diff --git a/src/types.d.ts b/src/types.d.ts index 10f848c..ed9eeff 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -299,6 +299,7 @@ type ManeuvreDetails = { progradeDV: number, normalDV: number, radialDV: number, + totalDV: number, ejectAngle?: number }; From b17398f5aac4f7668b45c38f516817e6ba52563e Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 13:49:33 +0100 Subject: [PATCH 02/12] Added draggable textbox. --- dist/main/editor/draggable-text.js | 60 ++++++++++++++++++++ dist/main/editor/editor.js | 3 +- index.html | 11 ++++ src/main/editor/draggable-text.ts | 77 +++++++++++++++++++++++++ src/main/editor/editor.ts | 4 +- style.css | 91 ++++++++++++++++++++++++++++++ 6 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 dist/main/editor/draggable-text.js create mode 100644 src/main/editor/draggable-text.ts diff --git a/dist/main/editor/draggable-text.js b/dist/main/editor/draggable-text.js new file mode 100644 index 0000000..7c4a6c9 --- /dev/null +++ b/dist/main/editor/draggable-text.js @@ -0,0 +1,60 @@ +export class DraggableTextbox { + static create(title, content) { + const template = document.getElementById("draggable-text-template"); + const div = template.cloneNode(true); + document.body.insertBefore(div, document.body.lastChild); + div.id = `draggable-text-${this.nextId}`; + this.nextId++; + this.boxes.set(div.id, div); + const header = div.getElementsByClassName("draggable-text-header")[0]; + const h = header.getElementsByClassName("draggable-text-title")[0]; + h.innerHTML = title; + const textarea = div.getElementsByTagName("textarea")[0]; + textarea.value = content; + const closeBtn = div.getElementsByClassName("draggable-close-btn")[0]; + closeBtn.onclick = () => div.remove(); + let pos1, pos2, pos3, pos4; + const dragMouseDown = (e) => { + e = e || window.event; + e.preventDefault(); + pos3 = e.clientX; + pos4 = e.clientY; + document.onmouseup = closeDragElement; + document.onmousemove = elementDrag; + this.moveToFront(div.id); + }; + const elementDrag = (e) => { + e = e || window.event; + e.preventDefault(); + pos1 = pos3 - e.clientX; + pos2 = pos4 - e.clientY; + pos3 = e.clientX; + pos4 = e.clientY; + div.style.top = (div.offsetTop - pos2) + "px"; + div.style.left = (div.offsetLeft - pos1) + "px"; + }; + const closeDragElement = () => { + document.onmouseup = null; + document.onmousemove = null; + }; + header.onmousedown = dragMouseDown; + this.moveToFront(div.id); + this.startZ++; + div.hidden = false; + div.style.display = ""; + } + static moveToFront(id) { + const div0 = this.boxes.get(id); + const z0 = parseInt(div0.style.zIndex); + this.boxes.forEach((div, _) => { + const z = parseInt(div.style.zIndex); + if (z > z0) { + div.style.zIndex = (z - 1).toString(); + } + }); + div0.style.zIndex = this.startZ.toString(); + } +} +DraggableTextbox.nextId = 0; +DraggableTextbox.startZ = 9; +DraggableTextbox.boxes = new Map(); diff --git a/dist/main/editor/editor.js b/dist/main/editor/editor.js index 1c46cfd..1424180 100644 --- a/dist/main/editor/editor.js +++ b/dist/main/editor/editor.js @@ -193,7 +193,8 @@ export async function initEditorWithSystem(systems, systemIndex) { stepSlider.enable(); trajectory.updatePodPosition(systemTime); console.log(solver.bestDeltaV); - console.log(trajectoryToText(trajectory, sequence)); + const trajText = trajectoryToText(trajectory, sequence); + console.log(trajText); }; const findTrajectory = async () => { paramsErr.hide(); diff --git a/index.html b/index.html index bddd38f..a13f215 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,8 @@ + + KSP MGA Planner @@ -461,6 +463,15 @@ + + + diff --git a/src/main/editor/draggable-text.ts b/src/main/editor/draggable-text.ts new file mode 100644 index 0000000..7a7566b --- /dev/null +++ b/src/main/editor/draggable-text.ts @@ -0,0 +1,77 @@ +export class DraggableTextbox { + private static nextId = 0; + private static startZ = 9; + private static boxes = new Map(); + + public static create(title: string, content: string){ + const template = document.getElementById("draggable-text-template") as HTMLDivElement; + const div = template.cloneNode(true) as HTMLDivElement; + document.body.insertBefore(div,document.body.lastChild); + div.id = `draggable-text-${this.nextId}`; + this.nextId++; + this.boxes.set(div.id, div); + + const header = div.getElementsByClassName("draggable-text-header")[0] as HTMLDivElement; + const h = header.getElementsByClassName("draggable-text-title")[0] as HTMLTitleElement; + h.innerHTML = title; + + const textarea = div.getElementsByTagName("textarea")[0] as HTMLTextAreaElement; + textarea.value = content; + + const closeBtn = div.getElementsByClassName("draggable-close-btn")[0] as HTMLButtonElement; + closeBtn.onclick = () => div.remove(); + + // from: https://www.w3schools.com/howto/howto_js_draggable.asp + let pos1: number, pos2: number, pos3: number, pos4: number; + const dragMouseDown = (e: any) => { + e = e || window.event; + e.preventDefault(); + // get the mouse cursor position at startup: + pos3 = e.clientX; + pos4 = e.clientY; + document.onmouseup = closeDragElement; + // call a function whenever the cursor moves: + document.onmousemove = elementDrag; + + this.moveToFront(div.id); + } + + const elementDrag = (e: any) => { + e = e || window.event; + e.preventDefault(); + // calculate the new cursor position: + pos1 = pos3 - e.clientX; + pos2 = pos4 - e.clientY; + pos3 = e.clientX; + pos4 = e.clientY; + // set the element's new position: + div.style.top = (div.offsetTop - pos2) + "px"; + div.style.left = (div.offsetLeft - pos1) + "px"; + } + + const closeDragElement = () => { + // stop moving when mouse button is released: + document.onmouseup = null; + document.onmousemove = null; + } + + header.onmousedown = dragMouseDown; + this.moveToFront(div.id); + this.startZ++; + + div.hidden = false; + div.style.display = ""; + } + + private static moveToFront(id: string){ + const div0 = this.boxes.get(id) as HTMLDivElement; + const z0 = parseInt(div0.style.zIndex); + this.boxes.forEach((div, _) => { + const z = parseInt(div.style.zIndex); + if(z > z0){ + div.style.zIndex = (z-1).toString(); + } + }); + div0.style.zIndex = this.startZ.toString(); + } +} \ No newline at end of file diff --git a/src/main/editor/editor.ts b/src/main/editor/editor.ts index 3c4c289..0b748ad 100644 --- a/src/main/editor/editor.ts +++ b/src/main/editor/editor.ts @@ -17,6 +17,7 @@ import { DiscreteRange } from "./range.js"; import { OrbitingBody } from "../objects/body.js"; import { loadBodiesData, loadConfig } from "../utilities/data.js"; import { trajectoryToText } from "../utilities/trajectory-text.js"; +import { DraggableTextbox } from "./draggable-text.js"; export async function initEditorWithSystem(systems: SolarSystemData[], systemIndex: number){ @@ -258,7 +259,8 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd console.log(solver.bestDeltaV); - console.log(trajectoryToText(trajectory, sequence)); + const trajText = trajectoryToText(trajectory, sequence); + console.log(trajText); }; const findTrajectory = async () => { diff --git a/style.css b/style.css index dec1e2d..727a4d7 100644 --- a/style.css +++ b/style.css @@ -570,4 +570,95 @@ footer p { margin-bottom: 0; margin-top: 0; +} + + +/* Draggable text box */ + +.draggable-text-box +{ + position: fixed; + z-index: 9; + + border-style: solid; + border-width: 1px; + border-color: #414242; + border-radius: 5px; + + background-color: #0d0e0e; + + display: flex; + flex-direction: column; + justify-content: space-between; + + top: 100px; + left: 100px; + + box-shadow: 5px 5px 5px rgba(0,0,0,0.6); + -moz-box-shadow: 5px 5px 5px rgba(0,0,0,0.6); + -webkit-box-shadow: 5px 5px 5px rgba(0,0,0,0.6); + -o-box-shadow: 5px 5px 5px rgba(0,0,0,0.6); +} + +.draggable-text-header +{ + padding: 0.3em; + display: flex; + justify-content: space-between; +} + +.draggable-text-header .draggable-text-title +{ + margin-top: 0; + margin-bottom: 0; +} + +.draggable-text-box textarea +{ + /*resize: none;*/ + color: white; + background-color: rgb(22, 23, 24); + margin-bottom: 0; + min-width: 200px; + width: 100%; + + border: none; + overflow: auto; + outline: none; + + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.draggable-close-btn +{ + color: white; + border-radius: 5px; + height: 28px; + width: 28px; + border: 1px solid rgb(54, 54, 54); + background-color: #3e1515; + font-size: 16px; +} + +.draggable-close-btn:hover +{ + cursor: pointer; + background-color: #512424; +} + +.draggable-close-btn:active +{ + cursor: pointer; + background-color: #580e0e; +} + +.draggable-close-btn:disabled +{ + cursor: default; } \ No newline at end of file From 522f5901381d0b488000df1cafeb79440df5ac6f Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 14:46:32 +0100 Subject: [PATCH 03/12] Added button to displayed detailed text panel. Also refactored `button.ts` to use a common `Button` class instead of separate `SubmitButton` and `StopButton` types. --- dist/main/editor/buttons.js | 21 ++------------------- dist/main/editor/editor.js | 32 +++++++++++++++++++++++++++----- index.html | 9 +++++++-- src/main/editor/buttons.ts | 24 ++---------------------- src/main/editor/editor.ts | 33 ++++++++++++++++++++++++++++----- style.css | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 53 deletions(-) diff --git a/dist/main/editor/buttons.js b/dist/main/editor/buttons.js index 9497c11..af35abb 100644 --- a/dist/main/editor/buttons.js +++ b/dist/main/editor/buttons.js @@ -1,4 +1,4 @@ -class Button { +export class Button { constructor(id) { this._btn = document.getElementById(id); } @@ -8,24 +8,7 @@ class Button { disable() { this._btn.disabled = true; } -} -export class SubmitButton extends Button { - constructor(id) { - super(id); - } - click(asyncAction) { - this._btn.onclick = async () => { - this.disable(); - await asyncAction(); - this.enable(); - }; - } -} -export class StopButton extends Button { - constructor(id) { - super(id); - } click(action) { - this._btn.onclick = () => action(); + this._btn.onclick = action; } } diff --git a/dist/main/editor/editor.js b/dist/main/editor/editor.js index 1424180..bdafd28 100644 --- a/dist/main/editor/editor.js +++ b/dist/main/editor/editor.js @@ -9,13 +9,14 @@ import { BodySelector } from "./body-selector.js"; import { EvolutionPlot } from "./plot.js"; import { ProgressMessage } from "./progress-msg.js"; import { SequenceSelector } from "./sequence-selector.js"; -import { SubmitButton, StopButton } from "./buttons.js"; +import { Button } from "./buttons.js"; import { FlybySequence } from "../solvers/sequence.js"; import { Trajectory } from "../solvers/trajectory.js"; import { Selector } from "./selector.js"; import { DiscreteRange } from "./range.js"; import { loadBodiesData, loadConfig } from "../utilities/data.js"; import { trajectoryToText } from "../utilities/trajectory-text.js"; +import { DraggableTextbox } from "./draggable-text.js"; export async function initEditorWithSystem(systems, systemIndex) { const canvas = document.getElementById("three-canvas"); const width = canvas.clientWidth; @@ -121,8 +122,14 @@ export async function initEditorWithSystem(systems, systemIndex) { systemSelector.enable(); } }; - new SubmitButton("sequence-btn").click(() => generateSequences()); - new StopButton("sequence-stop-btn").click(() => generator.cancel()); + const seqGenBtn = new Button("sequence-btn"); + seqGenBtn.click(async () => { + seqGenBtn.disable(); + await generateSequences(); + seqGenBtn.enable(); + }); + const seqStopBtn = new Button("sequence-stop-btn"); + seqStopBtn.click(() => generator.cancel()); } { const timeRangeStart = new TimeSelector("start", config); @@ -147,6 +154,8 @@ export async function initEditorWithSystem(systems, systemIndex) { let trajectory; const detailsSelector = new Selector("details-selector"); const stepSlider = new DiscreteRange("displayed-steps-slider"); + const showTrajDetailsBtn = new Button("show-text-btn"); + showTrajDetailsBtn.disable(); detailsSelector.disable(); stepSlider.disable(); const getSpan = (id) => document.getElementById(id); @@ -177,9 +186,11 @@ export async function initEditorWithSystem(systems, systemIndex) { detailsSelector.clear(); detailsSelector.disable(); stepSlider.disable(); + showTrajDetailsBtn.disable(); if (trajectory) trajectory.remove(); }; + let trajectoryCounter = 0; const displayFoundTrajectory = (sequence) => { trajectory = new Trajectory(solver, system, config); trajectory.draw(canvas); @@ -195,6 +206,11 @@ export async function initEditorWithSystem(systems, systemIndex) { console.log(solver.bestDeltaV); const trajText = trajectoryToText(trajectory, sequence); console.log(trajText); + trajectoryCounter++; + showTrajDetailsBtn.click(() => { + DraggableTextbox.create(`Trajectory ${trajectoryCounter}`, trajText); + }); + showTrajDetailsBtn.enable(); }; const findTrajectory = async () => { paramsErr.hide(); @@ -239,8 +255,14 @@ export async function initEditorWithSystem(systems, systemIndex) { systemSelector.enable(); } }; - new SubmitButton("search-btn").click(() => findTrajectory()); - new StopButton("search-stop-btn").click(() => solver.cancel()); + const searchStartBtn = new Button("search-btn"); + searchStartBtn.click(async () => { + searchStartBtn.disable(); + await findTrajectory(); + searchStartBtn.enable(); + }); + const searchStopBtn = new Button("search-stop-btn"); + searchStopBtn.click(() => solver.cancel()); systemSelector.change((_, index) => { stopLoop(); deltaVPlot.destroy(); diff --git a/index.html b/index.html index a13f215..c6c9236 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ - + KSP MGA Planner @@ -239,7 +239,12 @@
-

Calculated trajectory

+
+

Calculated trajectory

+ +
diff --git a/src/main/editor/buttons.ts b/src/main/editor/buttons.ts index ac285e4..fe5973a 100644 --- a/src/main/editor/buttons.ts +++ b/src/main/editor/buttons.ts @@ -1,4 +1,4 @@ -class Button { +export class Button { protected readonly _btn!: HTMLButtonElement; constructor(id: string) { @@ -12,28 +12,8 @@ class Button { public disable(){ this._btn.disabled = true; } -} - -export class SubmitButton extends Button { - constructor(id: string) { - super(id); - } - - click(asyncAction: () => Promise){ - this._btn.onclick = async () => { - this.disable(); - await asyncAction(); - this.enable(); - }; - } -} - -export class StopButton extends Button { - constructor(id: string) { - super(id); - } click(action: () => void){ - this._btn.onclick = () => action(); + this._btn.onclick = action; } } \ No newline at end of file diff --git a/src/main/editor/editor.ts b/src/main/editor/editor.ts index 0b748ad..bb5f479 100644 --- a/src/main/editor/editor.ts +++ b/src/main/editor/editor.ts @@ -9,7 +9,7 @@ import { BodySelector } from "./body-selector.js"; import { EvolutionPlot } from "./plot.js"; import { ProgressMessage } from "./progress-msg.js"; import { SequenceSelector } from "./sequence-selector.js"; -import { SubmitButton, StopButton } from "./buttons.js"; +import { Button } from "./buttons.js"; import { FlybySequence } from "../solvers/sequence.js"; import { Trajectory } from "../solvers/trajectory.js"; import { Selector } from "./selector.js"; @@ -163,8 +163,14 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd } // Sequence generator buttons - new SubmitButton("sequence-btn").click(() => generateSequences()); - new StopButton("sequence-stop-btn").click(() => generator.cancel()); + const seqGenBtn = new Button("sequence-btn"); + seqGenBtn.click(async () => { + seqGenBtn.disable(); + await generateSequences() + seqGenBtn.enable(); + }); + const seqStopBtn = new Button("sequence-stop-btn"); + seqStopBtn.click(() => generator.cancel()); } { @@ -206,6 +212,9 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd const detailsSelector = new Selector("details-selector"); const stepSlider = new DiscreteRange("displayed-steps-slider"); + const showTrajDetailsBtn = new Button("show-text-btn"); + showTrajDetailsBtn.disable(); + detailsSelector.disable(); stepSlider.disable(); @@ -239,9 +248,11 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd detailsSelector.clear(); detailsSelector.disable(); stepSlider.disable(); + showTrajDetailsBtn.disable(); if(trajectory) trajectory.remove(); } + let trajectoryCounter = 0; const displayFoundTrajectory = (sequence: FlybySequence) => { trajectory = new Trajectory(solver, system, config); trajectory.draw(canvas); @@ -261,6 +272,12 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd const trajText = trajectoryToText(trajectory, sequence); console.log(trajText); + + trajectoryCounter++; + showTrajDetailsBtn.click(() => { + DraggableTextbox.create(`Trajectory ${trajectoryCounter}`, trajText); + }); + showTrajDetailsBtn.enable(); }; const findTrajectory = async () => { @@ -317,8 +334,14 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd }; // Trajectory solver buttons - new SubmitButton("search-btn").click(() => findTrajectory()); - new StopButton("search-stop-btn").click(() => solver.cancel()); + const searchStartBtn = new Button("search-btn"); + searchStartBtn.click(async () => { + searchStartBtn.disable(); + await findTrajectory(); + searchStartBtn.enable(); + }); + const searchStopBtn = new Button("search-stop-btn"); + searchStopBtn.click(() => solver.cancel()); // Configure the system selector callback systemSelector.change((_, index) => { diff --git a/style.css b/style.css index 727a4d7..9d2f9c0 100644 --- a/style.css +++ b/style.css @@ -426,6 +426,36 @@ input[type="range"] justify-content: space-between; } +#result-panel-header-left +{ + display: flex; + justify-content: flex-start; + align-items: center; +} + +#show-text-btn +{ + margin-left: 10px; + background-image: linear-gradient(rgb(0, 93, 163), rgb(0, 60, 105)); +} + +#show-text-btn:hover +{ + background-image: linear-gradient(rgb(0, 78, 138), rgb(0, 60, 105)); +} + +#show-text-btn:active +{ + background-image: none; + background-color: rgb(0, 60, 105); +} + +#show-text-btn:disabled +{ + background-image: none; + background-color: rgb(46, 52, 56); +} + #steps-slider-control-group { margin-bottom: 0; @@ -605,6 +635,7 @@ footer p padding: 0.3em; display: flex; justify-content: space-between; + align-items: center; } .draggable-text-header .draggable-text-title @@ -616,6 +647,7 @@ footer p .draggable-text-box textarea { /*resize: none;*/ + padding: 10px; color: white; background-color: rgb(22, 23, 24); margin-bottom: 0; From 8a8a4d722f26ef0928577fa9ab301221fad4d643 Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 15:03:34 +0100 Subject: [PATCH 04/12] Added to UT conversion in time. --- dist/main/solvers/trajectory.js | 9 +++------ dist/main/time/basetime.js | 6 ++++++ dist/main/time/realtime.js | 6 ++++++ src/main/solvers/trajectory.ts | 9 +++------ src/main/time/basetime.ts | 7 +++++++ src/main/time/realtime.ts | 7 +++++++ src/types.d.ts | 1 + 7 files changed, 33 insertions(+), 12 deletions(-) diff --git a/dist/main/solvers/trajectory.js b/dist/main/solvers/trajectory.js index 2fe1232..e2385c1 100644 --- a/dist/main/solvers/trajectory.js +++ b/dist/main/solvers/trajectory.js @@ -269,8 +269,7 @@ export class Trajectory { else { ejAngleLI.hidden = true; } - const date = depDate.dateSeconds + dateEMT.dateSeconds; - resultItems.dateSpan.onclick = onDateClick(date); + resultItems.dateSpan.onclick = onDateClick(dateEMT.toUT(depDate).dateSeconds); resultItems.flybyDiv.hidden = true; resultItems.maneuverDiv.hidden = false; } @@ -283,10 +282,8 @@ export class Trajectory { resultItems.periAltitudeSpan.innerHTML = details.periAltitude.toFixed(0); resultItems.inclinationSpan.innerHTML = details.inclinationDeg.toFixed(0); resultItems.flybyNumberSpan.innerHTML = (option.origin + 1).toString(); - let enterDate = depDate.dateSeconds + startDateEMT.dateSeconds; - resultItems.startDateSpan.onclick = onDateClick(enterDate); - let exitDate = depDate.dateSeconds + endDateEMT.dateSeconds; - resultItems.endDateSpan.onclick = onDateClick(exitDate); + resultItems.startDateSpan.onclick = onDateClick(startDateEMT.toUT(depDate).dateSeconds); + resultItems.endDateSpan.onclick = onDateClick(endDateEMT.toUT(depDate).dateSeconds); resultItems.flybyDiv.hidden = false; resultItems.maneuverDiv.hidden = true; } diff --git a/dist/main/time/basetime.js b/dist/main/time/basetime.js index 0ab9063..e40b14a 100644 --- a/dist/main/time/basetime.js +++ b/dist/main/time/basetime.js @@ -27,6 +27,12 @@ export class BaseKSPTime { return `T+ ${year - 1}y - ${day - 1}d - ${hmsStr}`; } } + toUT(from) { + if (typeof from == "number") + return new BaseKSPTime(from + this._exactDate, this.config); + else + return new BaseKSPTime(from.dateSeconds + this._exactDate, this.config); + } get dateSeconds() { return this._exactDate; } diff --git a/dist/main/time/realtime.js b/dist/main/time/realtime.js index eb23c40..09cefa7 100644 --- a/dist/main/time/realtime.js +++ b/dist/main/time/realtime.js @@ -43,6 +43,12 @@ export class RealKSPTime { return `T+ ${year}y - ${day}d - ${hmsStr}`; } } + toUT(from) { + if (typeof from == "number") + return new RealKSPTime(from + this._exactDate, this.config); + else + return new RealKSPTime(from.dateSeconds + this._exactDate, this.config); + } get dateSeconds() { return this._exactDate; } diff --git a/src/main/solvers/trajectory.ts b/src/main/solvers/trajectory.ts index 17c7e8d..efd179d 100644 --- a/src/main/solvers/trajectory.ts +++ b/src/main/solvers/trajectory.ts @@ -380,8 +380,7 @@ export class Trajectory { ejAngleLI.hidden = true; } - const date = depDate.dateSeconds + dateEMT.dateSeconds; - resultItems.dateSpan.onclick = onDateClick(date); + resultItems.dateSpan.onclick = onDateClick(dateEMT.toUT(depDate).dateSeconds); resultItems.flybyDiv.hidden = true; resultItems.maneuverDiv.hidden = false; @@ -397,10 +396,8 @@ export class Trajectory { resultItems.inclinationSpan.innerHTML = details.inclinationDeg.toFixed(0); resultItems.flybyNumberSpan.innerHTML = (option.origin + 1).toString(); - let enterDate = depDate.dateSeconds + startDateEMT.dateSeconds; - resultItems.startDateSpan.onclick = onDateClick(enterDate); - let exitDate = depDate.dateSeconds + endDateEMT.dateSeconds; - resultItems.endDateSpan.onclick = onDateClick(exitDate); + resultItems.startDateSpan.onclick = onDateClick(startDateEMT.toUT(depDate).dateSeconds); + resultItems.endDateSpan.onclick = onDateClick(endDateEMT.toUT(depDate).dateSeconds); resultItems.flybyDiv.hidden = false; resultItems.maneuverDiv.hidden = true; diff --git a/src/main/time/basetime.ts b/src/main/time/basetime.ts index 5de52bb..bcd5a42 100644 --- a/src/main/time/basetime.ts +++ b/src/main/time/basetime.ts @@ -29,6 +29,13 @@ export class BaseKSPTime implements IKSPTime { } } + public toUT(from: number | IKSPTime): IKSPTime { + if(typeof from == "number") + return new BaseKSPTime(from + this._exactDate, this.config); + else + return new BaseKSPTime(from.dateSeconds + this._exactDate, this.config); + } + public get dateSeconds(){ return this._exactDate; } diff --git a/src/main/time/realtime.ts b/src/main/time/realtime.ts index 9e61092..4d66ebf 100644 --- a/src/main/time/realtime.ts +++ b/src/main/time/realtime.ts @@ -44,6 +44,13 @@ export class RealKSPTime implements IKSPTime { } } + public toUT(from: number | IKSPTime): IKSPTime { + if(typeof from == "number") + return new RealKSPTime(from + this._exactDate, this.config); + else + return new RealKSPTime(from.dateSeconds + this._exactDate, this.config); + } + public get dateSeconds(){ return this._exactDate; } diff --git a/src/types.d.ts b/src/types.d.ts index ed9eeff..40f0430 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -143,6 +143,7 @@ interface IKSPTime { public displayYDHMS: DateYDH; public readonly defaultDate: number; public stringYDHMS(precision: "h" | "hm" | "hms", display: "emt" | "ut"): string; + public toUT(from: IKSPTime | number): IKSPTime; } type MessageToWorker = From 05c1910f78ab12d4a3bf382691aa6c5630c86247 Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 15:37:39 +0100 Subject: [PATCH 05/12] Added UT time in trajectort text. --- dist/main/utilities/trajectory-text.js | 14 ++++++++++---- src/main/utilities/trajectory-text.ts | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/dist/main/utilities/trajectory-text.js b/dist/main/utilities/trajectory-text.js index caa130a..2f1e84c 100644 --- a/dist/main/utilities/trajectory-text.js +++ b/dist/main/utilities/trajectory-text.js @@ -39,7 +39,9 @@ export function trajectoryToText(traj, seq) { label = `${arrivalBodyName} circularization`; } add(label, "", 1); - add("Date", KSPTime(details.dateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + const dateMET = KSPTime(details.dateMET, config.time); + add("Date", dateMET.toUT(depDate).stringYDHMS("hms", "ut") + " UT", 2); + add("", dateMET.stringYDHMS("hms", "emt") + " MET", 2); if (details.ejectAngle !== undefined) { add("Ejection angle", `${details.ejectAngle.toFixed(1)}°`, 2); } @@ -53,9 +55,13 @@ export function trajectoryToText(traj, seq) { space(); const details = traj.flybys[flybyIdx]; const bodyName = system.bodyFromId(details.bodyId).name; + const enterMET = KSPTime(details.soiEnterDateMET, config.time); + const exitMET = KSPTime(details.soiExitDateMET, config.time); add(`Flyby around ${bodyName}`, "", 1); - add("SOI enter date", KSPTime(details.soiEnterDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); - add("SOI exit date", KSPTime(details.soiExitDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + add("SOI enter date", enterMET.toUT(depDate).stringYDHMS("hms", "ut") + " UT", 2); + add("", enterMET.stringYDHMS("hms", "emt") + " MET", 2); + add("SOI exit date", exitMET.toUT(depDate).stringYDHMS("hms", "ut") + " UT", 2); + add("", exitMET.stringYDHMS("hms", "emt") + " MET", 2); add("Periapsis altitude", `${details.periAltitude.toFixed(0)} km`, 2); add("Inclination", `${details.inclinationDeg.toFixed(0)}°`, 2); flybyIdx++; @@ -78,7 +84,7 @@ function pairsToString(pairs) { maxLen = Math.max(maxLen, line.length); } for (let i = 0; i < pairs.length; i++) { - if (pairs[i].label == "" || pairs[i].data == "") + if (pairs[i].label == "" && pairs[i].data == "") continue; const spaces = " ".repeat(maxLen - lines[i].length + 1); lines[i] += spaces + pairs[i].data; diff --git a/src/main/utilities/trajectory-text.ts b/src/main/utilities/trajectory-text.ts index a6d3ddd..3f53092 100644 --- a/src/main/utilities/trajectory-text.ts +++ b/src/main/utilities/trajectory-text.ts @@ -49,7 +49,9 @@ export function trajectoryToText(traj: Trajectory, seq: FlybySequence) { label = `${arrivalBodyName} circularization`; } add(label, "", 1); - add("Date", KSPTime(details.dateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + const dateMET = KSPTime(details.dateMET, config.time); + add("Date", dateMET.toUT(depDate).stringYDHMS("hms", "ut") + " UT", 2); + add("", dateMET.stringYDHMS("hms", "emt") + " MET", 2); if(details.ejectAngle !== undefined){ add("Ejection angle", `${details.ejectAngle.toFixed(1)}°`, 2); } @@ -64,9 +66,13 @@ export function trajectoryToText(traj: Trajectory, seq: FlybySequence) { space(); const details = traj.flybys[flybyIdx]; const bodyName = system.bodyFromId(details.bodyId).name; + const enterMET = KSPTime(details.soiEnterDateMET, config.time); + const exitMET = KSPTime(details.soiExitDateMET, config.time); add(`Flyby around ${bodyName}`, "", 1); - add("SOI enter date", KSPTime(details.soiEnterDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); - add("SOI exit date", KSPTime(details.soiExitDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2); + add("SOI enter date", enterMET.toUT(depDate).stringYDHMS("hms", "ut") + " UT", 2); + add("", enterMET.stringYDHMS("hms", "emt") + " MET", 2); + add("SOI exit date", exitMET.toUT(depDate).stringYDHMS("hms", "ut") + " UT", 2); + add("", exitMET.stringYDHMS("hms", "emt") + " MET", 2); add("Periapsis altitude", `${details.periAltitude.toFixed(0)} km`, 2); add("Inclination", `${details.inclinationDeg.toFixed(0)}°`, 2); @@ -93,7 +99,7 @@ function pairsToString(pairs: pair[]){ maxLen = Math.max(maxLen, line.length); } for(let i = 0; i < pairs.length; i++){ - if(pairs[i].label == "" || pairs[i].data == "") + if(pairs[i].label == "" && pairs[i].data == "") continue; const spaces = " ".repeat(maxLen - lines[i].length + 1); lines[i] += spaces + pairs[i].data; From 183f70fa47fe4cc575b9d7413c9f026455b39d5a Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 17:25:14 +0100 Subject: [PATCH 06/12] Added copy to clipboard button --- dist/main/editor/draggable-text.js | 2 ++ index.html | 8 ++++++-- src/main/editor/draggable-text.ts | 2 ++ style.css | 29 +++++++++++++++++++++++++++-- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/dist/main/editor/draggable-text.js b/dist/main/editor/draggable-text.js index 7c4a6c9..fb18767 100644 --- a/dist/main/editor/draggable-text.js +++ b/dist/main/editor/draggable-text.js @@ -13,6 +13,8 @@ export class DraggableTextbox { textarea.value = content; const closeBtn = div.getElementsByClassName("draggable-close-btn")[0]; closeBtn.onclick = () => div.remove(); + const copyBtn = div.getElementsByClassName("draggable-copy-btn")[0]; + copyBtn.onclick = () => navigator.clipboard.writeText(content); let pos1, pos2, pos3, pos4; const dragMouseDown = (e) => { e = e || window.event; diff --git a/index.html b/index.html index c6c9236..056b0c3 100644 --- a/index.html +++ b/index.html @@ -469,10 +469,14 @@
+ diff --git a/src/main/editor/draggable-text.ts b/src/main/editor/draggable-text.ts index 7a7566b..71b8e89 100644 --- a/src/main/editor/draggable-text.ts +++ b/src/main/editor/draggable-text.ts @@ -20,6 +20,8 @@ export class DraggableTextbox { const closeBtn = div.getElementsByClassName("draggable-close-btn")[0] as HTMLButtonElement; closeBtn.onclick = () => div.remove(); + const copyBtn = div.getElementsByClassName("draggable-copy-btn")[0] as HTMLButtonElement; + copyBtn.onclick = () => navigator.clipboard.writeText(content); // from: https://www.w3schools.com/howto/howto_js_draggable.asp let pos1: number, pos2: number, pos3: number, pos4: number; diff --git a/style.css b/style.css index 9d2f9c0..3e3bfce 100644 --- a/style.css +++ b/style.css @@ -667,17 +667,23 @@ footer p box-sizing: border-box; } -.draggable-close-btn + +.draggable-close-btn, .draggable-copy-btn { color: white; border-radius: 5px; height: 28px; width: 28px; border: 1px solid rgb(54, 54, 54); - background-color: #3e1515; font-size: 16px; } +/* Close button */ +.draggable-close-btn +{ + background-color: #3e1515; +} + .draggable-close-btn:hover { cursor: pointer; @@ -693,4 +699,23 @@ footer p .draggable-close-btn:disabled { cursor: default; +} + + +/* Copy to clipboard button */ +.draggable-copy-btn +{ + background-color: #344c67; +} + +.draggable-copy-btn:hover +{ + cursor: pointer; + background-color: #4c6786; +} + +.draggable-copy-btn:active +{ + cursor: pointer; + background-color: #22354d; } \ No newline at end of file From f710887a9564d052b25d91f937cf3f03fd7e129b Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 18:02:43 +0100 Subject: [PATCH 07/12] Fixed duplicate textboxes. --- dist/main/editor/draggable-text.js | 33 +++++++++++++++++------- src/main/editor/draggable-text.ts | 41 ++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/dist/main/editor/draggable-text.js b/dist/main/editor/draggable-text.js index fb18767..b9b0bff 100644 --- a/dist/main/editor/draggable-text.js +++ b/dist/main/editor/draggable-text.js @@ -1,18 +1,28 @@ export class DraggableTextbox { static create(title, content) { + for (const [id, item] of this.boxes) { + if (item.title == title) { + this.moveToFront(id); + return; + } + } const template = document.getElementById("draggable-text-template"); const div = template.cloneNode(true); document.body.insertBefore(div, document.body.lastChild); - div.id = `draggable-text-${this.nextId}`; + const id = this.nextId; + div.id = `draggable-text-${id}`; this.nextId++; - this.boxes.set(div.id, div); + this.boxes.set(id, { div, title }); const header = div.getElementsByClassName("draggable-text-header")[0]; const h = header.getElementsByClassName("draggable-text-title")[0]; h.innerHTML = title; const textarea = div.getElementsByTagName("textarea")[0]; textarea.value = content; const closeBtn = div.getElementsByClassName("draggable-close-btn")[0]; - closeBtn.onclick = () => div.remove(); + closeBtn.onclick = () => { + div.remove(); + this.boxes.delete(id); + }; const copyBtn = div.getElementsByClassName("draggable-copy-btn")[0]; copyBtn.onclick = () => navigator.clipboard.writeText(content); let pos1, pos2, pos3, pos4; @@ -23,7 +33,7 @@ export class DraggableTextbox { pos4 = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; - this.moveToFront(div.id); + this.moveToFront(id); }; const elementDrag = (e) => { e = e || window.event; @@ -32,23 +42,28 @@ export class DraggableTextbox { pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; - div.style.top = (div.offsetTop - pos2) + "px"; - div.style.left = (div.offsetLeft - pos1) + "px"; + let top = (div.offsetTop - pos2); + let left = (div.offsetLeft - pos1); + div.style.top = top.toString() + "px"; + div.style.left = left.toString() + "px"; }; const closeDragElement = () => { document.onmouseup = null; document.onmousemove = null; }; header.onmousedown = dragMouseDown; - this.moveToFront(div.id); + textarea.onclick = () => this.moveToFront(id); + this.moveToFront(id); this.startZ++; div.hidden = false; div.style.display = ""; + return id; } static moveToFront(id) { - const div0 = this.boxes.get(id); + const item = this.boxes.get(id); + const div0 = item.div; const z0 = parseInt(div0.style.zIndex); - this.boxes.forEach((div, _) => { + this.boxes.forEach(({ div }, _) => { const z = parseInt(div.style.zIndex); if (z > z0) { div.style.zIndex = (z - 1).toString(); diff --git a/src/main/editor/draggable-text.ts b/src/main/editor/draggable-text.ts index 71b8e89..f9afdbb 100644 --- a/src/main/editor/draggable-text.ts +++ b/src/main/editor/draggable-text.ts @@ -1,15 +1,23 @@ export class DraggableTextbox { private static nextId = 0; private static startZ = 9; - private static boxes = new Map(); + private static boxes = new Map(); public static create(title: string, content: string){ + for(const [id, item] of this.boxes){ + if(item.title == title) { + this.moveToFront(id); + return; + } + } + const template = document.getElementById("draggable-text-template") as HTMLDivElement; const div = template.cloneNode(true) as HTMLDivElement; document.body.insertBefore(div,document.body.lastChild); - div.id = `draggable-text-${this.nextId}`; + const id = this.nextId; + div.id = `draggable-text-${id}`; this.nextId++; - this.boxes.set(div.id, div); + this.boxes.set(id, {div, title}); const header = div.getElementsByClassName("draggable-text-header")[0] as HTMLDivElement; const h = header.getElementsByClassName("draggable-text-title")[0] as HTMLTitleElement; @@ -19,7 +27,10 @@ export class DraggableTextbox { textarea.value = content; const closeBtn = div.getElementsByClassName("draggable-close-btn")[0] as HTMLButtonElement; - closeBtn.onclick = () => div.remove(); + closeBtn.onclick = () => { + div.remove(); + this.boxes.delete(id); + }; const copyBtn = div.getElementsByClassName("draggable-copy-btn")[0] as HTMLButtonElement; copyBtn.onclick = () => navigator.clipboard.writeText(content); @@ -35,7 +46,7 @@ export class DraggableTextbox { // call a function whenever the cursor moves: document.onmousemove = elementDrag; - this.moveToFront(div.id); + this.moveToFront(id); } const elementDrag = (e: any) => { @@ -47,8 +58,10 @@ export class DraggableTextbox { pos3 = e.clientX; pos4 = e.clientY; // set the element's new position: - div.style.top = (div.offsetTop - pos2) + "px"; - div.style.left = (div.offsetLeft - pos1) + "px"; + let top = (div.offsetTop - pos2); + let left = (div.offsetLeft - pos1); + div.style.top = top.toString() + "px"; + div.style.left = left.toString() + "px"; } const closeDragElement = () => { @@ -58,17 +71,23 @@ export class DraggableTextbox { } header.onmousedown = dragMouseDown; - this.moveToFront(div.id); + + textarea.onclick = () => this.moveToFront(id); + + this.moveToFront(id); this.startZ++; div.hidden = false; div.style.display = ""; + + return id } - private static moveToFront(id: string){ - const div0 = this.boxes.get(id) as HTMLDivElement; + public static moveToFront(id: number){ + const item = this.boxes.get(id) as {div: HTMLDivElement, title: string}; + const div0 = item.div; const z0 = parseInt(div0.style.zIndex); - this.boxes.forEach((div, _) => { + this.boxes.forEach(({div}, _) => { const z = parseInt(div.style.zIndex); if(z > z0){ div.style.zIndex = (z-1).toString(); From 5d824b336e8ab94fba523c9683dc9a176126764c Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 23:22:27 +0100 Subject: [PATCH 08/12] Update draggable-text.ts --- dist/main/editor/draggable-text.js | 43 ++++++++++------------ src/main/editor/draggable-text.ts | 59 +++++++++++++----------------- 2 files changed, 46 insertions(+), 56 deletions(-) diff --git a/dist/main/editor/draggable-text.js b/dist/main/editor/draggable-text.js index b9b0bff..d229b94 100644 --- a/dist/main/editor/draggable-text.js +++ b/dist/main/editor/draggable-text.js @@ -25,33 +25,30 @@ export class DraggableTextbox { }; const copyBtn = div.getElementsByClassName("draggable-copy-btn")[0]; copyBtn.onclick = () => navigator.clipboard.writeText(content); - let pos1, pos2, pos3, pos4; - const dragMouseDown = (e) => { + let x, y; + header.onmousedown = (e) => { e = e || window.event; e.preventDefault(); - pos3 = e.clientX; - pos4 = e.clientY; - document.onmouseup = closeDragElement; - document.onmousemove = elementDrag; + x = e.clientX; + y = e.clientY; + document.onmouseup = () => { + document.onmouseup = null; + document.onmousemove = null; + }; + document.onmousemove = (e) => { + e = e || window.event; + e.preventDefault(); + let dx = x - e.clientX; + let dy = y - e.clientY; + x = e.clientX; + y = e.clientY; + let left = div.offsetLeft - dx; + let top = div.offsetTop - dy; + div.style.top = top.toString() + "px"; + div.style.left = left.toString() + "px"; + }; this.moveToFront(id); }; - const elementDrag = (e) => { - e = e || window.event; - e.preventDefault(); - pos1 = pos3 - e.clientX; - pos2 = pos4 - e.clientY; - pos3 = e.clientX; - pos4 = e.clientY; - let top = (div.offsetTop - pos2); - let left = (div.offsetLeft - pos1); - div.style.top = top.toString() + "px"; - div.style.left = left.toString() + "px"; - }; - const closeDragElement = () => { - document.onmouseup = null; - document.onmousemove = null; - }; - header.onmousedown = dragMouseDown; textarea.onclick = () => this.moveToFront(id); this.moveToFront(id); this.startZ++; diff --git a/src/main/editor/draggable-text.ts b/src/main/editor/draggable-text.ts index f9afdbb..9ad0d0c 100644 --- a/src/main/editor/draggable-text.ts +++ b/src/main/editor/draggable-text.ts @@ -34,43 +34,36 @@ export class DraggableTextbox { const copyBtn = div.getElementsByClassName("draggable-copy-btn")[0] as HTMLButtonElement; copyBtn.onclick = () => navigator.clipboard.writeText(content); - // from: https://www.w3schools.com/howto/howto_js_draggable.asp - let pos1: number, pos2: number, pos3: number, pos4: number; - const dragMouseDown = (e: any) => { + let x: number, y: number; + header.onmousedown = (e: MouseEvent) => { e = e || window.event; e.preventDefault(); - // get the mouse cursor position at startup: - pos3 = e.clientX; - pos4 = e.clientY; - document.onmouseup = closeDragElement; - // call a function whenever the cursor moves: - document.onmousemove = elementDrag; + + x = e.clientX; + y = e.clientY; + + document.onmouseup = () => { + document.onmouseup = null; + document.onmousemove = null; + }; + + document.onmousemove = (e: MouseEvent) => { + e = e || window.event; + e.preventDefault(); + + let dx = x - e.clientX; + let dy = y - e.clientY; + x = e.clientX; + y = e.clientY; + + let left = div.offsetLeft - dx; + let top = div.offsetTop - dy; + div.style.top = top.toString() + "px"; + div.style.left = left.toString() + "px"; + }; this.moveToFront(id); - } - - const elementDrag = (e: any) => { - e = e || window.event; - e.preventDefault(); - // calculate the new cursor position: - pos1 = pos3 - e.clientX; - pos2 = pos4 - e.clientY; - pos3 = e.clientX; - pos4 = e.clientY; - // set the element's new position: - let top = (div.offsetTop - pos2); - let left = (div.offsetLeft - pos1); - div.style.top = top.toString() + "px"; - div.style.left = left.toString() + "px"; - } - - const closeDragElement = () => { - // stop moving when mouse button is released: - document.onmouseup = null; - document.onmousemove = null; - } - - header.onmousedown = dragMouseDown; + }; textarea.onclick = () => this.moveToFront(id); From c8254e06ce03d1c1bec570b8785c40ad83bfa02a Mon Sep 17 00:00:00 2001 From: Krafpy Date: Mon, 2 Jan 2023 23:23:45 +0100 Subject: [PATCH 09/12] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 056b0c3..f6c1271 100644 --- a/index.html +++ b/index.html @@ -242,7 +242,7 @@

Calculated trajectory

From b9c925b6e73477e82120ade5f0d3ec72799c116e Mon Sep 17 00:00:00 2001 From: Krafpy Date: Tue, 3 Jan 2023 08:34:56 +0100 Subject: [PATCH 10/12] Clamp textbox position in window. --- dist/main/editor/draggable-text.js | 21 ++++++++++++++------- src/main/editor/draggable-text.ts | 24 +++++++++++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/dist/main/editor/draggable-text.js b/dist/main/editor/draggable-text.js index d229b94..8fe3e49 100644 --- a/dist/main/editor/draggable-text.js +++ b/dist/main/editor/draggable-text.js @@ -25,13 +25,21 @@ export class DraggableTextbox { }; const copyBtn = div.getElementsByClassName("draggable-copy-btn")[0]; copyBtn.onclick = () => navigator.clipboard.writeText(content); - let x, y; header.onmousedown = (e) => { e = e || window.event; e.preventDefault(); - x = e.clientX; - y = e.clientY; + let x = e.clientX; + let y = e.clientY; + let left, top; + const setPos = () => { + div.style.top = top.toString() + "px"; + div.style.left = left.toString() + "px"; + }; + const clamp = (x, a, b) => x < a ? a : x > b ? b : x; document.onmouseup = () => { + left = clamp(left, 0, window.innerWidth - div.offsetWidth); + top = clamp(top, 0, window.innerHeight - div.offsetHeight); + setPos(); document.onmouseup = null; document.onmousemove = null; }; @@ -42,10 +50,9 @@ export class DraggableTextbox { let dy = y - e.clientY; x = e.clientX; y = e.clientY; - let left = div.offsetLeft - dx; - let top = div.offsetTop - dy; - div.style.top = top.toString() + "px"; - div.style.left = left.toString() + "px"; + left = div.offsetLeft - dx; + top = div.offsetTop - dy; + setPos(); }; this.moveToFront(id); }; diff --git a/src/main/editor/draggable-text.ts b/src/main/editor/draggable-text.ts index 9ad0d0c..fba18f0 100644 --- a/src/main/editor/draggable-text.ts +++ b/src/main/editor/draggable-text.ts @@ -34,15 +34,26 @@ export class DraggableTextbox { const copyBtn = div.getElementsByClassName("draggable-copy-btn")[0] as HTMLButtonElement; copyBtn.onclick = () => navigator.clipboard.writeText(content); - let x: number, y: number; header.onmousedown = (e: MouseEvent) => { e = e || window.event; e.preventDefault(); - x = e.clientX; - y = e.clientY; + let x = e.clientX; + let y = e.clientY; + + let left: number, top: number; + const setPos = () => { + div.style.top = top.toString() + "px"; + div.style.left = left.toString() + "px"; + }; + + const clamp = (x:number, a:number, b:number) => x < a ? a : x > b ? b : x; document.onmouseup = () => { + left = clamp(left, 0, window.innerWidth - div.offsetWidth); + top = clamp(top, 0, window.innerHeight - div.offsetHeight); + setPos(); + document.onmouseup = null; document.onmousemove = null; }; @@ -56,10 +67,9 @@ export class DraggableTextbox { x = e.clientX; y = e.clientY; - let left = div.offsetLeft - dx; - let top = div.offsetTop - dy; - div.style.top = top.toString() + "px"; - div.style.left = left.toString() + "px"; + left = div.offsetLeft - dx; + top = div.offsetTop - dy; + setPos(); }; this.moveToFront(id); From 2703c6fb41fb9e4cd5b667bd1bff001017a1238c Mon Sep 17 00:00:00 2001 From: Krafpy Date: Tue, 3 Jan 2023 10:12:59 +0100 Subject: [PATCH 11/12] Clamp textbox header position in window. --- dist/main/editor/draggable-text.js | 4 ++-- src/main/editor/draggable-text.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/main/editor/draggable-text.js b/dist/main/editor/draggable-text.js index 8fe3e49..a0a4ea8 100644 --- a/dist/main/editor/draggable-text.js +++ b/dist/main/editor/draggable-text.js @@ -37,8 +37,8 @@ export class DraggableTextbox { }; const clamp = (x, a, b) => x < a ? a : x > b ? b : x; document.onmouseup = () => { - left = clamp(left, 0, window.innerWidth - div.offsetWidth); - top = clamp(top, 0, window.innerHeight - div.offsetHeight); + left = clamp(left, 0, window.innerWidth - header.offsetWidth); + top = clamp(top, 0, window.innerHeight - header.offsetHeight); setPos(); document.onmouseup = null; document.onmousemove = null; diff --git a/src/main/editor/draggable-text.ts b/src/main/editor/draggable-text.ts index fba18f0..2940a92 100644 --- a/src/main/editor/draggable-text.ts +++ b/src/main/editor/draggable-text.ts @@ -50,8 +50,8 @@ export class DraggableTextbox { const clamp = (x:number, a:number, b:number) => x < a ? a : x > b ? b : x; document.onmouseup = () => { - left = clamp(left, 0, window.innerWidth - div.offsetWidth); - top = clamp(top, 0, window.innerHeight - div.offsetHeight); + left = clamp(left, 0, window.innerWidth - header.offsetWidth); + top = clamp(top, 0, window.innerHeight - header.offsetHeight); setPos(); document.onmouseup = null; From 6b20969ad577a08f76e046542e250e541a77c659 Mon Sep 17 00:00:00 2001 From: Krafpy Date: Fri, 6 Jan 2023 22:56:30 +0100 Subject: [PATCH 12/12] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index f6c1271..8b05d33 100644 --- a/index.html +++ b/index.html @@ -242,7 +242,7 @@

Calculated trajectory