This commit is contained in:
2023-07-01 18:15:43 +07:00
commit a25b0adb09
20 changed files with 930 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
<script setup lang="ts">
import Sidebar from './components/Sidebar.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 } from './const';
const vMargin = ref(DEFAULT_VERTICAL_MARGIN)
const hMargin = ref(DEFAULT_HORIZONTAL_MARGIN)
const imageWidth = ref(DEFAULT_IMAGE_WIDTH)
const imageHeight = ref(DEFAULT_IMAGE_HEIGHT)
const savePng = async () => {
const canvas = document.getElementById("canvas") as HTMLCanvasElement;
if (canvas) {
const image = canvas.toDataURL("image/png")
const link = document.createElement("a");
link.setAttribute("download", "image.png");
link.href = image
link.click();
}
}
</script>
<template>
<div class="container">
<Sidebar>
<Input v-model="hMargin">Отступ для горизонтальных линий, мм</Input>
<Input v-model="vMargin">Отступ для вертикальных линии, мм</Input>
<Input v-model="imageWidth">Высота изображения, мм</Input>
<Input v-model="imageHeight">Ширина изображения, мм</Input>
<button @click="savePng">Сохранить png</button>
</Sidebar>
<Page>
<Canvas :vMargin="vMargin" :hMargin="hMargin" :imageWidth="imageWidth" :imageHeight="imageHeight" />
</Page>
</div>
</template>
<style scoped>
#app,
body,
html {
height: 100vh;
width: 100vw;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
}
body {
background-color: aqua;
}
</style>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

+73
View File
@@ -0,0 +1,73 @@
<script setup lang="ts">
import { onMounted, onUpdated, ref } from "vue";
import { ONE_MM } from "../const";
const props = defineProps<{
vMargin: number;
hMargin: number;
imageWidth: number;
imageHeight: number;
}>();
const ctx = ref<null | CanvasRenderingContext2D>(null);
const clearCanvas = () => {
const { imageWidth, imageHeight } = props;
if (ctx.value) {
ctx.value.clearRect(0, 0, imageWidth * ONE_MM, imageHeight * ONE_MM);
}
};
const render = () => {
const { vMargin, hMargin, imageWidth, imageHeight } = props;
clearCanvas();
if (ctx.value) {
for (let i = 1; i < 100; i++) {
const y = i * hMargin * ONE_MM;
ctx.value.moveTo(0, y);
ctx.value.lineTo(imageWidth * ONE_MM, y);
ctx.value.stroke();
}
for (let i = 1; i < 100; i++) {
const x = i * vMargin * ONE_MM;
ctx.value.moveTo(x, 0);
ctx.value.lineTo(x, imageHeight * ONE_MM);
ctx.value.stroke();
}
}
};
onMounted(() => {
const canvas = document.getElementById("canvas") as HTMLCanvasElement;
if (canvas) {
ctx.value = canvas.getContext("2d");
}
render();
});
onUpdated(() => {
render();
});
</script>
<template>
<canvas
id="canvas"
:width="imageWidth * ONE_MM"
:height="imageHeight * ONE_MM"
/>
</template>
<style scoped>
canvas {
border: 1px solid black;
margin: 20px;
height: calc(100vh - 40px);
}
</style>
+23
View File
@@ -0,0 +1,23 @@
<script setup lang="ts">
const modelValue = defineModel();
</script>
<template>
<div class="input">
<label>
<slot></slot>
</label>
<input type="number" v-model="modelValue" />
</div>
</template>
<style scoped>
.input {
margin: 10px;
}
input {
border: #333 1px solid;
}
</style>
+12
View File
@@ -0,0 +1,12 @@
<script setup lang="ts">
</script>
<template>
<slot></slot>
</template>
<style scoped>
.page {
position: relative;
}
</style>
+22
View File
@@ -0,0 +1,22 @@
<template>
<div class="sidebar">
<slot></slot>
</div>
</template>
<style scoped>
.sidebar {
position: fixed;
top: 0;
left: 0;
width: 330px;
background-color: white;
margin: 10px;
padding: 10px;
z-index: 2;
border-radius: 10px;
border: 1px solid #333;
}
</style>
+8
View File
@@ -0,0 +1,8 @@
/** 1 миллиметр в пикселях */
export const ONE_MM = 12;
export const DEFAULT_IMAGE_WIDTH = 210;
export const DEFAULT_IMAGE_HEIGHT = 297;
export const DEFAULT_VERTICAL_MARGIN = 10;
export const DEFAULT_HORIZONTAL_MARGIN = 10;
+5
View File
@@ -0,0 +1,5 @@
import { createApp } from 'vue'
import './reset.css'
import App from './App.vue'
createApp(App).mount('#app')
+93
View File
@@ -0,0 +1,93 @@
/* Reset and base styles */
* {
padding: 0px;
margin: 0px;
border: none;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Links */
a, a:link, a:visited {
text-decoration: none;
}
a:hover {
text-decoration: none;
}
/* Common */
aside, nav, footer, header, section, main {
display: block;
}
h1, h2, h3, h4, h5, h6, p {
font-size: inherit;
font-weight: inherit;
}
ul, ul li {
list-style: none;
}
img {
vertical-align: top;
}
img, svg {
max-width: 100%;
height: auto;
}
address {
font-style: normal;
}
/* Form */
input, textarea, button, select {
font-family: inherit;
font-size: inherit;
color: inherit;
background-color: transparent;
}
input::-ms-clear {
display: none;
}
button, input[type="submit"] {
display: inline-block;
box-shadow: none;
background-color: transparent;
background: none;
cursor: pointer;
}
input:focus, input:active,
button:focus, button:active {
outline: none;
}
button::-moz-focus-inner {
padding: 0;
border: 0;
}
label {
cursor: pointer;
}
legend {
display: block;
}
#app {
width: 100vh;
}
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />