add pinia
This commit is contained in:
parent
b17852280b
commit
6b59d4962c
|
@ -10,6 +10,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"html2canvas": "^1.4.1",
|
||||
"pinia": "^2.1.4",
|
||||
"vue": "3.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
110
src/App.vue
110
src/App.vue
|
@ -6,31 +6,25 @@ import Button from "./components/Button.vue";
|
|||
import Page from "./components/Page.vue";
|
||||
import Input from "./components/Input.vue";
|
||||
import Canvas from "./components/Canvas.vue";
|
||||
import { ref } from "vue";
|
||||
import {
|
||||
DEFAULT_HORIZONTAL_MARGIN,
|
||||
DEFAULT_IMAGE_HEIGHT,
|
||||
DEFAULT_IMAGE_WIDTH,
|
||||
DEFAULT_VERTICAL_MARGIN,
|
||||
DEFAULT_IMAGE_BACKGROUND_COLOR,
|
||||
DEFAULT_VERTICAL_ROTATION,
|
||||
DEFAULT_MARGIN_ENABLE,
|
||||
DEFAULT_MARGIN_BACKGROUND_COLOR,
|
||||
DEFAULT_MARGIN_LEFT_MARGIN,
|
||||
} from "./const";
|
||||
import { ButtonSize, InputType } from "./types";
|
||||
import { useStore } from "./store";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { VARIANTS_VERTICAL_ROTATION, VARIANTS_IMAGE_SIZE } from './const';
|
||||
|
||||
const vMargin = ref(DEFAULT_VERTICAL_MARGIN);
|
||||
const vRotation = ref(DEFAULT_VERTICAL_ROTATION);
|
||||
const hMargin = ref(DEFAULT_HORIZONTAL_MARGIN);
|
||||
const hMargin2 = ref(DEFAULT_HORIZONTAL_MARGIN);
|
||||
const imageWidth = ref(DEFAULT_IMAGE_WIDTH);
|
||||
const imageHeight = ref(DEFAULT_IMAGE_HEIGHT);
|
||||
const imageBackgroundColor = ref(DEFAULT_IMAGE_BACKGROUND_COLOR);
|
||||
const store = useStore();
|
||||
|
||||
const marginEnable = ref(DEFAULT_MARGIN_ENABLE);
|
||||
const marginColor = ref(DEFAULT_MARGIN_BACKGROUND_COLOR);
|
||||
const marginLeftMargin = ref(DEFAULT_MARGIN_LEFT_MARGIN);
|
||||
const {
|
||||
imageBackgroundColor,
|
||||
vMargin,
|
||||
vRotation,
|
||||
hMargin,
|
||||
hMargin2,
|
||||
marginEnable,
|
||||
marginColor,
|
||||
marginLeftMargin,
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
} = storeToRefs(store);
|
||||
|
||||
const savePng = async () => {
|
||||
const canvas = document.getElementById("canvas") as HTMLCanvasElement;
|
||||
|
@ -43,90 +37,60 @@ const savePng = async () => {
|
|||
link.click();
|
||||
}
|
||||
};
|
||||
|
||||
const rotatePage = () => {
|
||||
const tmp = imageHeight.value;
|
||||
imageHeight.value = imageWidth.value;
|
||||
imageWidth.value = tmp;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<Sidebar>
|
||||
<SidebarBlock title="Фон">
|
||||
<Input v-model="imageBackgroundColor" :type="InputType.Color">Цвет {{ imageBackgroundColor }}</Input>
|
||||
<Input v-model="imageBackgroundColor" :type="InputType.Color">Цвет {{ store.imageBackgroundColor }}</Input>
|
||||
</SidebarBlock>
|
||||
|
||||
<SidebarBlock title="Вертикальные линии">
|
||||
<Input v-model="vMargin" :min="1">Отступ, мм</Input>
|
||||
<Input v-model="vRotation" :min="0" :max="359">Поворот, градусы</Input>
|
||||
<ButtonsBar>
|
||||
<Button :size="ButtonSize.Small" :click="() => {
|
||||
vRotation = 45;
|
||||
}
|
||||
">
|
||||
45°
|
||||
</Button>
|
||||
<Button :size="ButtonSize.Small" :click="() => {
|
||||
vRotation = 60;
|
||||
}
|
||||
">
|
||||
60°
|
||||
</Button>
|
||||
<Button :size="ButtonSize.Small" :click="() => {
|
||||
vRotation = 65;
|
||||
}
|
||||
">
|
||||
65°
|
||||
</Button>
|
||||
<Button :size="ButtonSize.Small" :click="() => {
|
||||
vRotation = 90;
|
||||
}
|
||||
">
|
||||
90°
|
||||
<Button v-for="deg in VARIANTS_VERTICAL_ROTATION" :key="deg" :size="ButtonSize.Small" :click="() => store.setVRotation(deg)">
|
||||
{{ deg }}°
|
||||
</Button>
|
||||
</ButtonsBar>
|
||||
</SidebarBlock>
|
||||
|
||||
<SidebarBlock title="Горизонтальные линии">
|
||||
<Input v-model="hMargin" :min="1">Отступ, мм</Input>
|
||||
<Input v-model="hMargin2" :min="1">Дополнительный отступ, мм</Input>
|
||||
</SidebarBlock>
|
||||
|
||||
<SidebarBlock title="Поля">
|
||||
<label class="switch">
|
||||
<input v-model="marginEnable" type="checkbox">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
<Input v-model="marginColor" :type="InputType.Color">
|
||||
Цвет {{ marginColor }}
|
||||
</Input>
|
||||
<Input v-model="marginLeftMargin" :min="1">Отступ слева, мм</Input>
|
||||
<div v-if="marginEnable">
|
||||
<Input v-model="marginColor" :type="InputType.Color">
|
||||
Цвет {{ marginColor }}
|
||||
</Input>
|
||||
<Input v-model="marginLeftMargin" :min="1">Отступ слева, мм</Input>
|
||||
</div>
|
||||
</SidebarBlock>
|
||||
</Sidebar>
|
||||
<Page>
|
||||
<Canvas :imageBackgroundColor="imageBackgroundColor" :vMargin="vMargin" :vRotation="vRotation" :hMargin="hMargin"
|
||||
:hMargin2="hMargin2" :imageWidth="imageWidth" :marginEnable="marginEnable" :marginColor="marginColor"
|
||||
:marginLeftMargin="marginLeftMargin" :imageHeight="imageHeight" />
|
||||
<Canvas />
|
||||
</Page>
|
||||
<Sidebar horizontalPosition="right">
|
||||
<SidebarBlock title="Изображение">
|
||||
<Input v-model="imageHeight" :min="1">Высота, мм</Input>
|
||||
<Input v-model="imageWidth" :min="1">Ширина, мм</Input>
|
||||
<ButtonsBar>
|
||||
<Button :size="ButtonSize.Small" :click="() => {
|
||||
imageWidth = 148;
|
||||
imageHeight = 210;
|
||||
}
|
||||
">
|
||||
A5
|
||||
<Button
|
||||
v-for="size in VARIANTS_IMAGE_SIZE"
|
||||
:key="size.name"
|
||||
:size="ButtonSize.Small"
|
||||
:click="() => store.setImageSize(size)"
|
||||
>
|
||||
{{ size.name }}
|
||||
</Button>
|
||||
<Button :size="ButtonSize.Small" :click="() => {
|
||||
imageWidth = 210;
|
||||
imageHeight = 297;
|
||||
}
|
||||
">
|
||||
A4
|
||||
</Button>
|
||||
<Button :size="ButtonSize.Small" :click="rotatePage">
|
||||
<Button :size="ButtonSize.Small" :click="store.rotateImage">
|
||||
Повернуть
|
||||
</Button>
|
||||
</ButtonsBar>
|
||||
|
|
|
@ -1,54 +1,55 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, onUpdated, ref } from "vue";
|
||||
import { ONE_MM } from "../const";
|
||||
import { useStore } from "../store";
|
||||
import { storeToRefs } from "pinia";
|
||||
|
||||
const props = defineProps<{
|
||||
imageBackgroundColor: string;
|
||||
const store = useStore();
|
||||
const {
|
||||
imageBackgroundColor,
|
||||
|
||||
vMargin: number;
|
||||
vRotation: number;
|
||||
hMargin: number;
|
||||
hMargin2: number;
|
||||
vMargin,
|
||||
vRotation,
|
||||
|
||||
marginEnable: boolean;
|
||||
marginColor: string;
|
||||
marginLeftMargin: number;
|
||||
hMargin,
|
||||
hMargin2,
|
||||
|
||||
imageWidth: number;
|
||||
imageHeight: number;
|
||||
}>();
|
||||
marginEnable,
|
||||
marginColor,
|
||||
marginLeftMargin,
|
||||
|
||||
imageHeight,
|
||||
imageWidth,
|
||||
} = storeToRefs(store);
|
||||
|
||||
const ctx = ref<null | CanvasRenderingContext2D>(null);
|
||||
|
||||
const clearCanvas = () => {
|
||||
const { imageWidth, imageHeight, imageBackgroundColor } = props;
|
||||
|
||||
if (ctx.value) {
|
||||
ctx.value.shadowColor
|
||||
ctx.value.fillStyle = imageBackgroundColor;
|
||||
ctx.value.fillRect(0, 0, imageWidth * ONE_MM, imageHeight * ONE_MM);
|
||||
ctx.value.fillStyle = imageBackgroundColor.value;
|
||||
ctx.value.fillRect(0, 0, imageWidth.value * ONE_MM, imageHeight.value * ONE_MM);
|
||||
ctx.value.beginPath();
|
||||
}
|
||||
};
|
||||
|
||||
const render = () => {
|
||||
const { vMargin, vRotation, hMargin, hMargin2, imageWidth, imageHeight, marginEnable, marginColor, marginLeftMargin } = props;
|
||||
|
||||
if (vMargin < 1 || hMargin < 1 || hMargin2 < 1) {
|
||||
if (vMargin.value < 1 || hMargin.value < 1 || hMargin2.value < 1) {
|
||||
return
|
||||
}
|
||||
if (imageWidth < 1 || imageHeight < 1) {
|
||||
if (imageWidth.value < 1 || imageHeight.value < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
clearCanvas();
|
||||
|
||||
var hMargins = [hMargin, hMargin2];
|
||||
var hMargins = [hMargin.value, hMargin2.value];
|
||||
|
||||
var imageHeightPx = imageHeight * ONE_MM;
|
||||
var imageWidthPx = imageWidth * ONE_MM;
|
||||
var vMarginPx = vMargin * ONE_MM;
|
||||
var rotationDelta = imageHeightPx / Math.tan(vRotation / 180 * Math.PI);
|
||||
var imageHeightPx = imageHeight.value * ONE_MM;
|
||||
var imageWidthPx = imageWidth.value * ONE_MM;
|
||||
var vMarginPx = vMargin.value * ONE_MM;
|
||||
var rotationDelta = imageHeightPx / Math.tan(vRotation.value / 180 * Math.PI);
|
||||
|
||||
if (ctx.value) {
|
||||
ctx.value.strokeStyle = "#000000";
|
||||
|
@ -83,9 +84,9 @@ const render = () => {
|
|||
}
|
||||
|
||||
|
||||
x = marginLeftMargin * ONE_MM;
|
||||
if (marginEnable) {
|
||||
ctx.value.strokeStyle = marginColor;
|
||||
x = marginLeftMargin.value * ONE_MM;
|
||||
if (marginEnable.value) {
|
||||
ctx.value.strokeStyle = marginColor.value;
|
||||
ctx.value.lineWidth = 2;
|
||||
ctx.value.beginPath();
|
||||
ctx.value.moveTo(x, 0);
|
||||
|
@ -112,6 +113,10 @@ onUpdated(() => {
|
|||
|
||||
<template>
|
||||
<canvas id="canvas" :width="imageWidth * ONE_MM" :height="imageHeight * ONE_MM" />
|
||||
<!-- Костыль, чтобы обновлялся стейт, неужели vue не может красиво это делать -->
|
||||
<div style="display: none;">
|
||||
{{ store }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
19
src/const.ts
19
src/const.ts
|
@ -1,14 +1,31 @@
|
|||
import { Size } from "./types";
|
||||
|
||||
/** 1 миллиметр в пикселях */
|
||||
export const ONE_MM = 12;
|
||||
|
||||
export const DEFAULT_IMAGE_WIDTH = 100;
|
||||
export const DEFAULT_IMAGE_HEIGHT = 100;
|
||||
/** Стандартные варианты размера изображения */
|
||||
export const VARIANTS_IMAGE_SIZE: { [k: string]: Size } = {
|
||||
A4: {
|
||||
name: 'A4',
|
||||
width: 210,
|
||||
height: 297,
|
||||
},
|
||||
A5: {
|
||||
name: 'A5',
|
||||
width: 148,
|
||||
height: 210,
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_VERTICAL_MARGIN = 10;
|
||||
export const DEFAULT_HORIZONTAL_MARGIN = 10;
|
||||
export const DEFAULT_VERTICAL_ROTATION = 90;
|
||||
/** Стандартные варианты наклона вертикальных линий */
|
||||
export const VARIANTS_VERTICAL_ROTATION = [45, 60, 65, 90];
|
||||
|
||||
export const DEFAULT_IMAGE_BACKGROUND_COLOR = "#ffffff"
|
||||
export const DEFAULT_IMAGE_BACKGROUND_COLOR = "#ffffff";
|
||||
|
||||
export const DEFAULT_MARGIN_ENABLE = false;
|
||||
export const DEFAULT_MARGIN_BACKGROUND_COLOR = "#dd3333";
|
||||
|
|
|
@ -2,5 +2,10 @@ import { createApp } from 'vue'
|
|||
import './reset.css'
|
||||
import './style.css'
|
||||
import App from './App.vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
const pinia = createPinia()
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(pinia)
|
||||
app.mount('#app')
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import {
|
||||
DEFAULT_HORIZONTAL_MARGIN,
|
||||
DEFAULT_IMAGE_BACKGROUND_COLOR,
|
||||
DEFAULT_IMAGE_HEIGHT,
|
||||
DEFAULT_IMAGE_WIDTH,
|
||||
DEFAULT_MARGIN_BACKGROUND_COLOR,
|
||||
DEFAULT_MARGIN_ENABLE,
|
||||
DEFAULT_MARGIN_LEFT_MARGIN,
|
||||
DEFAULT_VERTICAL_MARGIN,
|
||||
DEFAULT_VERTICAL_ROTATION,
|
||||
} from "./const";
|
||||
import { Size } from "./types";
|
||||
|
||||
export const useStore = defineStore("store", () => {
|
||||
const imageBackgroundColor = ref(DEFAULT_IMAGE_BACKGROUND_COLOR);
|
||||
|
||||
const vMargin = ref(DEFAULT_VERTICAL_MARGIN);
|
||||
const vRotation = ref(DEFAULT_VERTICAL_ROTATION);
|
||||
const setVRotation = (newRotation: number) => (vRotation.value = newRotation);
|
||||
|
||||
const hMargin = ref(DEFAULT_HORIZONTAL_MARGIN);
|
||||
const hMargin2 = ref(DEFAULT_HORIZONTAL_MARGIN);
|
||||
|
||||
const marginEnable = ref(DEFAULT_MARGIN_ENABLE);
|
||||
const marginColor = ref(DEFAULT_MARGIN_BACKGROUND_COLOR);
|
||||
const marginLeftMargin = ref(DEFAULT_MARGIN_LEFT_MARGIN);
|
||||
|
||||
const imageWidth = ref(DEFAULT_IMAGE_WIDTH);
|
||||
const imageHeight = ref(DEFAULT_IMAGE_HEIGHT);
|
||||
const setImageSize = (size: Size) => {
|
||||
imageWidth.value = size.width;
|
||||
imageHeight.value = size.height;
|
||||
}
|
||||
const rotateImage = () => {
|
||||
const tmp = imageHeight.value;
|
||||
imageHeight.value = imageWidth.value;
|
||||
imageWidth.value = tmp;
|
||||
};
|
||||
|
||||
return {
|
||||
imageBackgroundColor,
|
||||
|
||||
vMargin,
|
||||
vRotation,
|
||||
setVRotation,
|
||||
|
||||
hMargin,
|
||||
hMargin2,
|
||||
|
||||
marginEnable,
|
||||
marginColor,
|
||||
marginLeftMargin,
|
||||
|
||||
imageWidth,
|
||||
imageHeight,
|
||||
setImageSize,
|
||||
rotateImage,
|
||||
};
|
||||
});
|
|
@ -7,3 +7,9 @@ export enum InputType {
|
|||
Number = 'number',
|
||||
Color = 'color',
|
||||
}
|
||||
|
||||
export interface Size {
|
||||
name: string;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
|
18
yarn.lock
18
yarn.lock
|
@ -190,6 +190,11 @@
|
|||
"@vue/compiler-dom" "3.3.4"
|
||||
"@vue/shared" "3.3.4"
|
||||
|
||||
"@vue/devtools-api@^6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
|
||||
integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
|
||||
|
||||
"@vue/language-core@1.8.0":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-1.8.0.tgz#3d106afdef859464435c90921fcce200a0b1d15c"
|
||||
|
@ -381,6 +386,14 @@ picocolors@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||
|
||||
pinia@^2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.1.4.tgz#a642adfe6208e10c36d3dc16184a91064788142a"
|
||||
integrity sha512-vYlnDu+Y/FXxv1ABo1vhjC+IbqvzUdiUC3sfDRrRyY2CQSrqqaa+iiHmqtARFxJVqWQMCJfXx1PBvFs9aJVLXQ==
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.5.0"
|
||||
vue-demi ">=0.14.5"
|
||||
|
||||
postcss@^8.1.10, postcss@^8.4.23:
|
||||
version "8.4.24"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df"
|
||||
|
@ -444,6 +457,11 @@ vscode-uri@^3.0.7:
|
|||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.7.tgz#6d19fef387ee6b46c479e5fb00870e15e58c1eb8"
|
||||
integrity sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==
|
||||
|
||||
vue-demi@>=0.14.5:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.5.tgz#676d0463d1a1266d5ab5cba932e043d8f5f2fbd9"
|
||||
integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==
|
||||
|
||||
vue-template-compiler@^2.7.14:
|
||||
version "2.7.14"
|
||||
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz#4545b7dfb88090744c1577ae5ac3f964e61634b1"
|
||||
|
|
Loading…
Reference in New Issue