This commit is contained in:
Igor Zinken
2021-01-13 13:21:03 +01:00
7 changed files with 250 additions and 53 deletions

View File

@@ -1,8 +1,6 @@
{
"en-US": {
"resizeDocument": "Resize document",
"width": "Width",
"height": "Height",
"maintainAspectRatio": "Maintain aspect ratio",
"save": "Save",
"cancel": "Cancel"

View File

@@ -27,15 +27,6 @@
</template>
<template #content>
<div class="form" @keyup.enter="save()">
<div class="wrapper input">
<label v-t="'width'"></label>
<input
ref="first"
v-model.number="width"
type="number"
name="width"
/>
</div>
<div class="wrapper input">
<label v-t="'maintainAspectRatio'"></label>
<toggle-button
@@ -43,14 +34,9 @@
name="ratio"
/>
</div>
<div class="wrapper input">
<label v-t="'height'"></label>
<input
v-model.number="height"
type="number"
name="height"
/>
</div>
<dimensions-formatter
v-model="dimensions"
/>
</div>
</template>
<template #actions>
@@ -74,6 +60,7 @@
import { mapGetters, mapMutations } from "vuex";
import { ToggleButton } from "vue-js-toggle-button";
import Modal from "@/components/modal/modal";
import DimensionsFormatter from "@/components/ui/dimensions-formatter/dimensions-formatter";
import messages from "./messages.json";
export default {
@@ -81,10 +68,13 @@ export default {
components: {
Modal,
ToggleButton,
DimensionsFormatter,
},
data: () => ({
width: 0,
height: 0,
dimensions: {
width: 0,
height: 0,
},
ratio: 0,
syncLock: false,
maintainRatio: true,
@@ -93,18 +83,24 @@ export default {
...mapGetters([
"activeDocument",
]),
width() {
return this.dimensions.width;
},
height() {
return this.dimensions.height;
},
},
mounted() {
this.width = this.activeDocument.width;
this.height = this.activeDocument.height;
this.ratio = this.width / this.height;
created() {
this.dimensions.width = this.activeDocument.width;
this.dimensions.height = this.activeDocument.height;
this.ratio = this.dimensions.width / this.dimensions.height;
this.$watch( "width", function( value ) {
if ( !this.maintainRatio || this.syncLock ) {
return;
}
this.lockSync();
this.height = Math.round( value / this.ratio );
this.dimensions.height = Math.round( value / this.ratio );
});
this.$watch( "height", function( value ) {
@@ -112,9 +108,8 @@ export default {
return;
}
this.lockSync();
this.width = Math.round( value * this.ratio );
this.dimensions.width = Math.round( value * this.ratio );
});
this.$refs.first.focus();
},
methods: {
...mapMutations([
@@ -129,12 +124,12 @@ export default {
});
},
async save() {
const { width, height } = this;
const { width, height } = this.dimensions;
const scaleX = width / this.activeDocument.width;
const scaleY = height / this.activeDocument.height;
await this.resizeActiveDocumentContent({ scaleX, scaleY });
this.setActiveDocumentSize({ width, height });
this.setActiveDocumentSize({ width: Math.round( width ), height: Math.round( height ) });
this.closeModal();
},
}

View File

@@ -35,22 +35,9 @@
name="name"
/>
</div>
<div class="wrapper input">
<label v-t="'width'"></label>
<input
v-model.number="width"
type="number"
name="width"
/>
</div>
<div class="wrapper input">
<label v-t="'height'"></label>
<input
v-model.number="height"
type="number"
name="height"
/>
</div>
<dimensions-formatter
v-model="dimensions"
/>
</div>
</template>
<template #actions>
@@ -74,17 +61,21 @@
import { mapGetters, mapMutations } from "vuex";
import Modal from "@/components/modal/modal";
import DocumentFactory from "@/factories/document-factory";
import DimensionsFormatter from "@/components/ui/dimensions-formatter/dimensions-formatter";
import messages from "./messages.json";
export default {
i18n: { messages },
components: {
Modal,
DimensionsFormatter,
},
data: () => ({
name : "",
width : 1000,
height : 1000,
dimensions: {
width: 1000,
height: 1000,
},
}),
computed: {
...mapGetters([
@@ -102,9 +93,9 @@ export default {
]),
async save() {
this.addNewDocument( DocumentFactory.create({
name: this.name,
width: this.width,
height: this.height
name : this.name,
width : Math.round( this.dimensions.width ),
height : Math.round( this.dimensions.height ),
}));
this.closeModal();
},

View File

@@ -3,8 +3,6 @@
"newDocument": "New document",
"newDocumentNum": "New document #{num}",
"name": "Name",
"width": "Width",
"height": "Height",
"create": "Create",
"cancel": "Cancel"
}

View File

@@ -0,0 +1,171 @@
/**
* The MIT License (MIT)
*
* Igor Zinken 2021 - 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
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
<template>
<div>
<h3 v-t="'dimensions'" class="title"></h3>
<div class="wrapper input">
<label v-t="'unit'"></label>
<div class="select-combo">
<select-box :options="units"
v-model="unit"
/>
<select-box v-if="showDPI"
v-model="dpi"
:options="dpis"
/>
</div>
</div>
<div class="wrapper input">
<label v-t="'width'"></label>
<input
v-model.number="translatedWidth"
type="number"
name="width"
/>
</div>
<div class="wrapper input">
<label v-t="'height'"></label>
<input
v-model.number="translatedHeight"
type="number"
name="height"
/>
</div>
</div>
</template>
<script>
import SelectBox from "@/components/ui/select-box/select-box";
import { pixelsToInch, pixelsToCm, pixelsToMm, inchesToPixels, cmToPixels, mmToPixels, } from "@/math/unit-math";
import messages from "./messages.json";
const DPI = [ 72, 97, 150, 300, 600, 1200 ];
const UNITS = [ "px", "in", "cm", "mm" ];
const toFixedFloat = ( value, exp = 2 ) => parseFloat( value.toFixed( exp ));
export default {
i18n: { messages },
components: {
SelectBox,
},
props: {
value: {
type: Object,
required: true,
validator: ({ width, height }) => typeof width === "number" && typeof height === "number"
},
},
data: () => ({
unit: UNITS[ 0 ],
dpi: DPI[ 0 ].toString(),
internalValue: {},
}),
computed: {
showDPI() {
return this.unit !== "px";
},
dpis() {
return DPI.map( dpi => ({ text: `${dpi} DPI`, value: dpi.toString() }));
},
units() {
return UNITS.map( unit => ({ text: this.$t( unit ), value: unit }));
},
translatedWidth: {
get() {
return this.valueFromPx( this.internalValue.width );
},
set( value ) {
this.internalValue.width = this.valueToPx( value );
},
},
translatedHeight: {
get() {
return this.valueFromPx( this.internalValue.height );
},
set( value ) {
this.internalValue.height = this.valueToPx( value )
},
}
},
mounted() {
this.internalValue = { ...this.value };
},
watch: {
internalValue( value ) {
this.$emit( "input", value );
},
},
methods: {
valueFromPx( valueInPx ) {
const dpi = parseFloat( this.dpi );
switch ( this.unit ) {
default:
case "px":
return valueInPx;
case "in":
return toFixedFloat( pixelsToInch( valueInPx, dpi ));
case "cm":
return toFixedFloat( pixelsToCm( valueInPx, dpi ));
case "mm":
return toFixedFloat( pixelsToMm( valueInPx, dpi ));
}
},
valueToPx( value ) {
switch ( this.unit ) {
default:
case "px":
return value;
case "in":
return inchesToPixels( value, this.dpi );
break;
case "cm":
return cmToPixels( value, this.dpi );
break;
case "mm":
return mmToPixels( value, this.dpi );
break;
}
}
}
};
</script>
<style lang="scss" scoped>
@import "@/styles/_variables";
.title {
color: #FFF;
margin: $spacing-medium 0 $spacing-medium 50%;
}
.select-combo {
display: inline-flex;
width: 50%;
}
.select-combo .select {
flex: 1;
margin-right: $spacing-small;
}
</style>

View File

@@ -0,0 +1,13 @@
{
"en-US": {
"dimensions": "Dimensions",
"dpi": "DPI",
"width": "Width",
"height": "Height",
"unit": "Unit",
"px": "Pixels",
"in": "Inches",
"cm": "Centimeters",
"mm": "Millimeters"
}
}

31
src/math/unit-math.js Normal file
View File

@@ -0,0 +1,31 @@
/**
* The MIT License (MIT)
*
* Igor Zinken 2021 - 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
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
const CM_PER_INCH = 2.54;
const MM_PER_INCH = CM_PER_INCH * 10;
export const pixelsToInch = ( pixels, dpi = 72 ) => pixels / dpi;
export const pixelsToCm = ( pixels, dpi = 72 ) => pixelsToInch( pixels, dpi ) * CM_PER_INCH
export const pixelsToMm = ( pixels, dpi = 72 ) => pixelsToInch( pixels, dpi ) * MM_PER_INCH;
export const inchesToPixels = ( inches, dpi = 72 ) => inches * dpi;
export const cmToPixels = ( cms, dpi = 72 ) => inchesToPixels( cms / CM_PER_INCH );
export const mmToPixels = ( mms, dpi = 72 ) => inchesToPixels( mms / MM_PER_INCH );