Implement interactive scaling/motion of rulers (#306) (#385)

* Update ruler origin

* Fix ruler text

* Handle zoom

* Remove log

* Fix origin
This commit is contained in:
0HyperCube 2021-10-25 10:03:14 +01:00 committed by Keavon Chambers
parent 5641f5d822
commit 029b8ff8b3
5 changed files with 78 additions and 12 deletions

View file

@ -111,11 +111,11 @@
</LayoutCol>
<LayoutCol :class="'viewport'">
<LayoutRow :class="'bar-area'">
<CanvasRuler :origin="0" :majorMarkSpacing="100" :direction="RulerDirection.Horizontal" :class="'top-ruler'" />
<CanvasRuler :origin="rulerOrigin.x" :majorMarkSpacing="rulerSpacing" :numberInterval="rulerInterval" :direction="RulerDirection.Horizontal" :class="'top-ruler'" />
</LayoutRow>
<LayoutRow :class="'canvas-area'">
<LayoutCol :class="'bar-area'">
<CanvasRuler :origin="0" :majorMarkSpacing="100" :direction="RulerDirection.Vertical" />
<CanvasRuler :origin="rulerOrigin.y" :majorMarkSpacing="rulerSpacing" :numberInterval="rulerInterval" :direction="RulerDirection.Vertical" />
</LayoutCol>
<LayoutCol :class="'canvas-area'">
<div class="canvas" ref="canvas">
@ -224,7 +224,7 @@
<script lang="ts">
import { defineComponent } from "vue";
import { ResponseType, registerResponseHandler, Response, UpdateCanvas, UpdateScrollbars, SetActiveTool, SetCanvasZoom, SetCanvasRotation } from "@/utilities/response-handler";
import { ResponseType, registerResponseHandler, Response, UpdateCanvas, UpdateScrollbars, UpdateRulers, SetActiveTool, SetCanvasZoom, SetCanvasRotation } from "@/utilities/response-handler";
import { SeparatorDirection, SeparatorType } from "@/components/widgets/widgets";
import { comingSoon } from "@/utilities/errors";
import { panicProxy } from "@/utilities/panic-proxy";
@ -329,6 +329,15 @@ export default defineComponent({
}
});
registerResponseHandler(ResponseType.UpdateRulers, (responseData: Response) => {
const updateData = responseData as UpdateRulers;
if (updateData) {
this.rulerOrigin = updateData.origin;
this.rulerSpacing = updateData.spacing;
this.rulerInterval = updateData.interval;
}
});
registerResponseHandler(ResponseType.SetActiveTool, (responseData: Response) => {
const toolData = responseData as SetActiveTool;
if (toolData) {
@ -374,6 +383,9 @@ export default defineComponent({
scrollbarPos: { x: 0.5, y: 0.5 },
scrollbarSize: { x: 0.5, y: 0.5 },
scrollbarMultiplier: { x: 0, y: 0 },
rulerOrigin: { x: 0, y: 0 },
rulerSpacing: 100,
rulerInterval: 100,
IncrementBehavior,
IncrementDirection,
MenuDirection,

View file

@ -55,10 +55,17 @@ export enum RulerDirection {
"Vertical" = "Vertical",
}
// Apparently the modulo operator in js does not work properly.
const mod = (n: number, m: number) => {
const remain = n % m;
return Math.floor(remain >= 0 ? remain : remain + m);
};
export default defineComponent({
props: {
direction: { type: String as PropType<RulerDirection>, default: RulerDirection.Vertical },
origin: { type: Number, required: true },
numberInterval: { type: Number, required: true },
majorMarkSpacing: { type: Number, required: true },
mediumDivisions: { type: Number, default: 5 },
minorDivisions: { type: Number, default: 2 },
@ -68,9 +75,8 @@ export default defineComponent({
const isVertical = this.direction === RulerDirection.Vertical;
const lineDirection = isVertical ? "H" : "V";
const offsetStart = this.origin % this.majorMarkSpacing;
const phasingShift = offsetStart < this.majorMarkSpacing ? this.majorMarkSpacing : 0;
const shiftedOffsetStart = offsetStart - phasingShift;
const offsetStart = mod(this.origin, this.majorMarkSpacing);
const shiftedOffsetStart = offsetStart - this.majorMarkSpacing;
const divisions = this.majorMarkSpacing / this.mediumDivisions / this.minorDivisions;
const majorMarksFrequency = this.mediumDivisions * this.minorDivisions;
@ -94,11 +100,13 @@ export default defineComponent({
svgTexts(): {} {
const isVertical = this.direction === RulerDirection.Vertical;
const offsetStart = this.origin % this.majorMarkSpacing;
const phasingShift = offsetStart < this.majorMarkSpacing ? this.majorMarkSpacing : 0;
const shiftedOffsetStart = offsetStart - phasingShift;
const offsetStart = mod(this.origin, this.majorMarkSpacing);
const shiftedOffsetStart = offsetStart - this.majorMarkSpacing;
const svgTextCoordinates = [];
let text = (Math.ceil(-this.origin / this.majorMarkSpacing) - 1) * this.numberInterval;
for (let location = shiftedOffsetStart; location < this.rulerLength; location += this.majorMarkSpacing) {
const destination = Math.round(location);
const x = isVertical ? 9 : destination + 2;
@ -107,7 +115,9 @@ export default defineComponent({
let transform = `translate(${x} ${y})`;
if (isVertical) transform += " rotate(270)";
svgTextCoordinates.push({ transform, text: location });
svgTextCoordinates.push({ transform, text });
text += this.numberInterval;
}
return svgTextCoordinates;

View file

@ -15,6 +15,7 @@ const state = reactive({
export enum ResponseType {
UpdateCanvas = "UpdateCanvas",
UpdateScrollbars = "UpdateScrollbars",
UpdateRulers = "UpdateRulers",
ExportDocument = "ExportDocument",
SaveDocument = "SaveDocument",
OpenDocumentBrowse = "OpenDocumentBrowse",
@ -67,6 +68,8 @@ function parseResponse(responseType: string, data: any): Response {
return newUpdateCanvas(data.UpdateCanvas);
case "UpdateScrollbars":
return newUpdateScrollbars(data.UpdateScrollbars);
case "UpdateRulers":
return newUpdateRulers(data.UpdateRulers);
case "UpdateLayer":
return newUpdateLayer(data.UpdateLayer);
case "SetCanvasZoom":
@ -94,7 +97,17 @@ function parseResponse(responseType: string, data: any): Response {
}
}
export type Response = SetActiveTool | UpdateCanvas | UpdateScrollbars | UpdateLayer | DocumentChanged | DisplayFolderTreeStructure | UpdateWorkingColors | SetCanvasZoom | SetCanvasRotation;
export type Response =
| SetActiveTool
| UpdateCanvas
| UpdateScrollbars
| UpdateRulers
| UpdateLayer
| DocumentChanged
| DisplayFolderTreeStructure
| UpdateWorkingColors
| SetCanvasZoom
| SetCanvasRotation;
export interface UpdateOpenDocumentsList {
open_documents: Array<string>;
@ -204,6 +217,19 @@ function newUpdateScrollbars(input: any): UpdateScrollbars {
};
}
export interface UpdateRulers {
origin: { x: number; y: number };
spacing: number;
interval: number;
}
function newUpdateRulers(input: any): UpdateRulers {
return {
origin: { x: input.origin[0], y: input.origin[1] },
spacing: input.spacing,
interval: input.interval,
};
}
export interface ExportDocument {
document: string;
name: string;