Added 'Fit to window' option to zoom tool

This commit is contained in:
Igor Zinken
2022-01-22 22:44:10 +01:00
parent 21c88af8f0
commit e688fd42be
6 changed files with 110 additions and 38 deletions

View File

@@ -109,9 +109,9 @@ export default {
"activeTool",
"activeToolOptions",
"antiAlias",
"canvasDimensions",
"snapAlign",
"zoomOptions",
"zCanvasBaseDimensions",
]),
documentTitle() {
const { name } = this.activeDocument;
@@ -151,6 +151,7 @@ export default {
renderState.reset();
layerPool.clear();
this.calcIdealDimensions();
this.setToolOptionValue({ tool: ToolTypes.ZOOM, option: "level", value: 1 }); // reset zoom
this.$nextTick( async () => {
// previously active tool needs to update to new document ref
const tool = this.activeTool;
@@ -262,10 +263,11 @@ export default {
},
methods: {
...mapMutations([
"setZCanvasBaseDimensions",
"setCanvasDimensions",
"setActiveTool",
"setPanMode",
"setSelectMode",
"setToolOptionValue",
]),
...mapActions([
"requestDocumentClose",
@@ -309,20 +311,30 @@ export default {
if ( calculateBestFit ) {
const { width, height } = this.activeDocument;
const scaledSize = scaleToRatio( width, height, containerSize.width, containerSize.height );
this.setZCanvasBaseDimensions( scaledSize );
xScale = scaledSize.width / this.activeDocument.width;
yScale = scaledSize.height / this.activeDocument.height;
const maxScaling = calculateMaxScaling( scaledSize.width, scaledSize.height, width, containerSize.width );
maxInScale = maxScaling.in;
maxOutScale = maxScaling.out;
this.setCanvasDimensions({
...scaledSize,
visibleWidth : containerSize.width,
visibleHeight : containerSize.height,
maxInScale,
maxOutScale
});
xScale = scaledSize.width / this.activeDocument.width;
yScale = scaledSize.height / this.activeDocument.height;
this.viewportWidth = containerSize.width;
this.viewportHeight = containerSize.height;
zCanvas.setViewport( this.viewportWidth, this.viewportHeight );
}
this.scaleWrapper();
// replace below with updated zCanvas lib to not multiply by zoom
this.cvsWidth = this.zCanvasBaseDimensions.width * zoom;
this.cvsHeight = this.zCanvasBaseDimensions.height * zoom;
this.cvsWidth = this.canvasDimensions.width * zoom;
this.cvsHeight = this.canvasDimensions.height * zoom;
zCanvas.setDocumentScale( this.cvsWidth, this.cvsHeight, xScale, zoom, this.activeDocument );
this.centerCanvas = zCanvas.getWidth() < containerSize.width || zCanvas.getHeight() < containerSize.height ;
},

View File

@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
* Igor Zinken 2020-2021 - https://www.igorski.nl
* Igor Zinken 2020-2022 - https://www.igorski.nl
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@@ -22,15 +22,17 @@
*/
<template>
<div class="form">
<label v-t="'importLocalFile'"
for="file"
class="file-label button button--block"
<label
v-t="'importLocalFile'"
for="file"
class="file-label button button--block"
></label>
<input type="file"
id="file"
multiple
:accept="acceptedImageTypes"
@change="handleFileSelect"
<input
type="file"
id="file"
multiple
:accept="acceptedFileTypes"
@change="handleFileSelect"
/>
</div>
</template>

View File

@@ -2,6 +2,7 @@
"en-US": {
"zoomLevel": "Zoom level",
"bestFit": "Best fit",
"fitWindow": "Fit window",
"original": "Original"
}
}

View File

@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
* Igor Zinken 2020-2021 - https://www.igorski.nl
* Igor Zinken 2020-2022 - https://www.igorski.nl
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@@ -38,6 +38,12 @@
class="button button--small"
@click="setBestFit()"
></button>
<button
v-t="'fitWindow'"
type="button"
class="button button--small"
@click="setFitWindow()"
></button>
<button
v-t="'original'"
type="button"
@@ -51,8 +57,9 @@
<script>
import { mapGetters, mapMutations } from "vuex";
import ToolTypes, { MIN_ZOOM, MAX_ZOOM } from "@/definitions/tool-types";
import Slider from "@/components/ui/slider/slider";
import messages from "./messages.json";
import { scaleValue, isPortrait, isLandscape } from "@/math/image-math";
import Slider from "@/components/ui/slider/slider";
import messages from "./messages.json";
export default {
i18n: { messages },
@@ -67,7 +74,7 @@ export default {
...mapGetters([
"activeDocument",
"zoomOptions",
"zCanvasBaseDimensions",
"canvasDimensions",
]),
zoomLevel: {
get() {
@@ -89,8 +96,38 @@ export default {
setBestFit() {
this.zoomLevel = 0;
},
setFitWindow() {
const { width, height } = this.activeDocument;
const { visibleWidth, visibleHeight, maxOutScale } = this.canvasDimensions;
const isWidthDominantSide = isLandscape( width, height );
if ( isWidthDominantSide ) {
// width is dominant, meaning zoom level 0 has image occupying full visibleHeight
const minZoomHeight = visibleHeight / maxOutScale;
const minZoomWidth = minZoomHeight * ( width / height );
const heightAtZeroZoom = visibleHeight;
const widthAtZeroZoom = ( width / height ) * heightAtZeroZoom;
const pixelsPerZoomUnit = ( widthAtZeroZoom - minZoomWidth ) / MIN_ZOOM;
this.setZoomLevel(( widthAtZeroZoom - visibleWidth ) / pixelsPerZoomUnit );
}
else {
// height is dominant, meaning zoom level 0 has image occupying full visibleWidth
const minZoomWidth = visibleWidth / maxOutScale;
const minZoomHeight = minZoomWidth * ( height / width );
const widthAtZeroZoom = visibleWidth;
const heightAtZeroZoom = ( height / width ) * widthAtZeroZoom;
const pixelsPerZoomUnit = ( widthAtZeroZoom - minZoomWidth ) / MIN_ZOOM;
this.setZoomLevel(( heightAtZeroZoom - visibleHeight ) / pixelsPerZoomUnit );
}
},
setOriginalSize() {
this.zoomLevel = ( this.activeDocument.width / this.zCanvasBaseDimensions.width ) * window.devicePixelRatio;
this.zoomLevel = ( this.activeDocument.width / this.canvasDimensions.width ) * window.devicePixelRatio;
},
setZoomLevel( level ) {
this.zoomLevel = Math.max( MIN_ZOOM, Math.min( MAX_ZOOM, level ));
},
},
};

View File

@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
* Igor Zinken 2020 - https://www.igorski.nl
* Igor Zinken 2020-2022 - https://www.igorski.nl
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@@ -24,20 +24,28 @@ import Vue from "vue";
export default {
state: {
// the base dimensions describe the "best fit" scale to represent
// the currently active document at the current window size, this
// is basically the base line used for the unzoomed document view
zCanvasBaseDimensions: {
width: 0,
height: 0,
canvasDimensions: {
// the base dimensions describe the "best fit" scale to represent
// the currently active document at the current window size, this
// is basically the baseline used for the unzoomed document view
width : 0,
height : 0,
// the visible area of the canvas (as it is positioned inside a container
// that offers scrollable overflow)
visibleWidth : 0,
visibleHeight : 0,
// the maximum in- and out zoom level supported for the currently
// open document at the current available screen dimensions
maxInScale : 1,
maxOutScale : 1,
},
},
getters: {
zCanvasBaseDimensions: state => state.zCanvasBaseDimensions,
canvasDimensions: state => state.canvasDimensions,
},
mutations: {
setZCanvasBaseDimensions( state, { width, height }) {
Vue.set( state, "zCanvasBaseDimensions", { width, height });
setCanvasDimensions( state, { width, height, visibleWidth, visibleHeight, maxInScale, maxOutScale }) {
Vue.set( state, "canvasDimensions", { width, height, visibleWidth, visibleHeight, maxInScale, maxOutScale });
},
},
};

View File

@@ -4,17 +4,29 @@ const { getters, mutations } = storeModule;
describe( "Vuex canvas module", () => {
describe( "getters", () => {
it( "should be able to retrieve the zCanvas instance base dimensions", () => {
const state = { zCanvasBaseDimensions: { width: 10, height: 5 } };
expect( getters.zCanvasBaseDimensions( state )).toEqual( state.zCanvasBaseDimensions );
it( "should be able to retrieve the zCanvas instance dimensions", () => {
const state = {
canvasDimensions: {
width: 10, height: 5, visibleWidth: 7, visibleHeight: 3, maxInScale: 1, maxOutScale: 1
}
};
expect( getters.canvasDimensions( state )).toEqual( state.canvasDimensions );
});
});
describe( "mutations", () => {
it( "should be able to set the zCanvas instance base dimensions", () => {
const state = { zCanvasBaseDimensions: { width: 10, height: 5 } };
mutations.setZCanvasBaseDimensions( state, { width: 50, height: 40 } );
expect( state.zCanvasBaseDimensions ).toEqual({ width: 50, height: 40 });
it( "should be able to set the zCanvas instance dimensions", () => {
const state = {
canvasDimensions: {
width: 10, height: 5, visibleWidth: 7, visibleHeight: 3, maxInScale: 1, maxOutScale: 1
}
};
mutations.setCanvasDimensions( state, {
width: 50, height: 40, visibleWidth: 40, visibleHeight: 20, maxInScale: 5, maxOutScale: 10
});
expect( state.canvasDimensions ).toEqual({
width: 50, height: 40, visibleWidth: 40, visibleHeight: 20, maxInScale: 5, maxOutScale: 10
});
});
});
});