Vue SVG. Приклад побудови живого параметричного креслення
Отже, на Vue можна робити параметричні креслення у форматі SVG, а потім зберегти як окремий SVG-файл. Що таке параметричне креслення і кому воно потрібно? Уявіть що Ви працюєте закрійником, всі викрійки типові, різні тільки розміри. Було б дуже зручно, якби Ви вбили основні розміри (параметри), а програма сама побудувала б креслення. Так само це стосується інших галузей, де треба завдати декілька параметрів і отримати креслення. Наприклад, Ви займаєтесь виготовленням коробок з картону, тощо. І, щоб скоротити час на креслення і вчасно виконати замовлення клієнта, Вам потрібна система для швидкої побудови креслення.
У цьому прикладі я буду "малювати" статор електричного двигуна.
Переглянути приклад SVG креслення на Vue
Основна компонента, яка займається саме кресленням drawing1 (дивись файл drawing1.js) створюється на базі mixins з назвою vuesvg (дивись файл app-mixins.js). Цей mixin містить (буде містити) всі властивості, методи, тощо, які необхідні всім компонентам - кресленням, які ми будемо створювати (поки-що у прикладі лише один drawing1).
Основна ідея побудови компоненти для SVG креслення така:
- data містить всі параметри, які можуть змінюватись;
- computed - містять всі необхідні розрахунки для побудови креслення. Основним є drawing. Він повертає набір об'єктів, які треба буде намалювати. В даному прикладі drawing повертає набір об'єктів: sectors, lines, circles, sizelines. Кожен з елементів має свої властивості, які використовуються для їх “малювання”.
- зображення креслення будується у шаблоні (template). Також template містить форму для зміни необхідних розмірів.
Зверніть увагу, що для sizelines створений окремий компонент size-lines (дивись файл app-components.js). Саме цей компонент дозволяє простіше встановлювати розмірні лінії на кресленні. Таким чином у template для побудови креслення ви можете використовувати не тільки стандартні SVG теги, але і свої компоненти.
Наприклад, якщо Вам потрібно буде малювати дуже багато гайок, ви можете створити компонент, назвати його, скажімо screw-nuts, який буде малювати гайку певного розміру у певних координатах. У computed властивість drawing додати набір об'єктів типу screw-nuts і заповнити його даними. А у template додати рядок, який буде виводити ваші гайки у SVG, як це зроблено у прикладі з розмірними лініями.
Скачати приклад SVG креслення на Vue
Код самої компоненти:
"use strict";
Vue.component('drawing1', {
mixins:[vuesvg],
data: function () {
return {
pageW: this.pageW,
pageH: this.pageH,
statorDiameter: this.statorDiameter,
statorCentralHoleDiameter: this.statorCentralHoleDiameter,
toothCount: this.toothCount,
toothHeight: this.toothHeight,
toothWidth: this.toothWidth,
toothHatHeight: this.toothHatHeight,
toothBetween: this.toothBetween,
}
},
computed: {
pageCenter: function () {
return {'x':this.pageW/2, 'y': this.pageH/2}
},
/* calculate limits for each parameters. optional */
limits: function () {
return {
statorDiameter: {
min: parseFloat(this.statorCentralHoleDiameter) + this.toothHeight*2,
max: this.pageW
},
statorCentralHoleDiameter: {
min: 0,
max: parseFloat(this.statorDiameter) - this.toothHeight*2
},
toothCount: {
min: 3,
max: 57
},
toothHeight: {
min: this.toothHatHeight * 3,
max: (this.statorDiameter - (this.toothWidth * this.toothCount / Math.PI)) / 2
},
toothWidth: {
min: 1,
max: (this.statorDiameter/2 - this.toothHeight)*2*Math.PI / this.toothCount
},
toothHatHeight: {
min: 1,
max: this.toothHeight/3
},
toothBetween: {
min: 1,
max: ((Math.PI*this.statorDiameter/this.toothCount - this.toothWidth)/2)
}
}
},
drawing: function () {
let result = {'sectors':[],'lines':[],'circles':[],'sizelines':[]}
let radius = this.statorDiameter/2
let sectorAngle = 2*Math.PI/this.toothCount;
let sectorAngleBetween = this.getSectorAngle(radius, this.toothBetween)
let radiusSmall = this.statorDiameter/2 - this.toothHeight
let toothWidthAngle = this.getSectorAngle(radiusSmall, this.toothWidth)
let radiusUnderHat = this.statorDiameter/2 - this.toothHatHeight
let toothWidthAngleHat = this.getSectorAngle(radiusUnderHat, this.toothWidth)
let so_interesting_size_line = {'x1':0,'y1':0,'x2':0,'y2':0}
for (let i = 0; i < this.toothCount; i++) {
let p1 = this.getPointOnCircle(radius, i*sectorAngle + sectorAngleBetween, this.pageCenter)
let p2 = this.getPointOnCircle(radius, (i+1)*sectorAngle - sectorAngleBetween, this.pageCenter)
let p3 = this.getPointOnCircle(radiusUnderHat, i*sectorAngle + sectorAngleBetween, this.pageCenter)
let p4 = this.getPointOnCircle(radiusUnderHat, i*sectorAngle + sectorAngle/2 - toothWidthAngleHat/2, this.pageCenter)
let p5 = this.getPointOnCircle(radiusUnderHat, (i+1)*sectorAngle - sectorAngle/2 + toothWidthAngleHat/2, this.pageCenter)
let p6 = this.getPointOnCircle(radiusUnderHat, (i+1)*sectorAngle - sectorAngleBetween, this.pageCenter)
let p7 = this.getPointOnCircle(radiusSmall, i*sectorAngle, this.pageCenter)
let p8 = this.getPointOnCircle(radiusSmall, i*sectorAngle + sectorAngle/2 - toothWidthAngle/2, this.pageCenter)
let p9 = this.getPointOnCircle(radiusSmall, (i+1)*sectorAngle - sectorAngle/2 + toothWidthAngle/2, this.pageCenter)
let p10 = this.getPointOnCircle(radiusSmall, (i+1)*sectorAngle, this.pageCenter)
result.sectors.push({'p1': p1, 'p2': p2, 'radius': radius})
result.sectors.push({'p1': p7, 'p2': p8, 'radius': radiusSmall})
result.sectors.push({'p1': p9, 'p2': p10, 'radius': radiusSmall})
result.sectors.push({'p1': p3, 'p2': p4, 'radius': radiusUnderHat})
result.sectors.push({'p1': p5, 'p2': p6, 'radius': radiusUnderHat})
result.lines.push({'p1': p1, 'p2': p3})
result.lines.push({'p1': p2, 'p2': p6})
result.lines.push({'p1': p4, 'p2': p8})
result.lines.push({'p1': p5, 'p2': p9})
if (i==this.toothCount-2) { // First tooth
so_interesting_size_line.x1 = p2.x
so_interesting_size_line.y1 = p2.y
}
if (i==this.toothCount-1) { // Last tooth
so_interesting_size_line.x2 = p1.x
so_interesting_size_line.y2 = p1.y
}
}
result.circles.push({'p': this.pageCenter, 'r': this.statorCentralHoleDiameter/2})
/* Size lines */
// Between tooths (so interesting size line)
result.sizelines.push({ 'x1': so_interesting_size_line.x1, 'y1': so_interesting_size_line.y1, 'x2': so_interesting_size_line.x2, 'y2': so_interesting_size_line.y2, 'offset': 5, 'text': this.toothBetween })
// Stator Diameter
result.sizelines.push({ 'x1':this.pageCenter.x - radius, 'y1': this.pageCenter.y, 'x2': this.pageCenter.x + radius, 'y2': this.pageCenter.y, 'offset': (radius * 1.1) + 7, 'text': this.statorDiameter })
// Central Hole Diameter
result.sizelines.push({ 'x1':this.pageCenter.x - this.statorCentralHoleDiameter/2, 'y1': this.pageCenter.y, 'x2': this.pageCenter.x + this.statorCentralHoleDiameter/2, 'y2': this.pageCenter.y, 'offset': 0, 'text': this.statorCentralHoleDiameter })
return result
}
},
mounted: function() {
/* Init values */
this.pageW = 210
this.pageH = 297
this.statorDiameter = 180
this.statorCentralHoleDiameter = 40
this.toothCount = 12
this.toothHeight = 40
this.toothWidth = 20
this.toothBetween = 5
this.toothHatHeight = 3
this.draw()
},
methods: {
getPointOnCircle: function (radius, angle, offset = {'x':0,'y':0}) {
return {'x': offset.x + radius*Math.cos(angle),'y': offset.y + radius*Math.sin(angle)}
},
getSectorAngle: function (radius, length) {
return length / radius
}
},
template: `
<div>
<v-style>
form div {
margin-bottom: 0.5em;
}
form label {
min-width: 15em;
display: inline-block;
}
.drawing {
border: 1px solid silver;
}
</v-style>
<h2>Form:</h2>
<div>
<form>
<div><label>Stator Diameter:</label><input v-model="statorDiameter" type="number" :min="limits.statorDiameter.min" :max="limits.statorDiameter.max"></div>
<div><label>Central Hole's Diameter:</label><input v-model="statorCentralHoleDiameter" type="number" :min="limits.statorCentralHoleDiameter.min" :max="limits.statorCentralHoleDiameter.max"></div>
<div><label>Tooth Count:</label><input v-model="toothCount" type="number" :min="limits.toothCount.min" :max="limits.toothCount.max"></div>
<div><label>Tooth Height:</label><input v-model="toothHeight" type="number" :min="limits.toothHeight.min" :max="limits.toothHeight.max"></div>
<div><label>Tooth Width:</label><input v-model="toothWidth" type="number" :min="limits.toothWidth.min" :max="limits.toothWidth.max"></div>
<div><label>Tooth's Hat Height:</label><input v-model="toothHatHeight" type="number" :min="limits.toothHatHeight.min" :max="limits.toothHatHeight.max"></div>
<div><label>Between Tooths:</label><input v-model="toothBetween" type="number" :min="limits.toothBetween.min" :max="limits.toothBetween.max"></div>
</form>
</div>
<h2>Drawing: <button type="button" @click="saveSvg('vue.svg')">Save SVG-file</button></h2>
<div>
<svg ref="svg" v-if="ready" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" :width="pageW+'mm'" :height="pageH+'mm'" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" :viewBox="'0 0 ' + pageW + ' ' + pageH" xmlns:xlink="http://www.w3.org/1999/xlink" class="drawing">
<defs>
<marker id="DimPoint1" viewBox="-2 -12 29 24" markerWidth="22" markerHeight="18" orient="auto">
<path fill="black" stroke="black" d="M0,0 L20,-4 16,0 20,4 z M0,-10 L0,10 M0,0 L27,0"/>
</marker>
<marker id="DimPoint2" viewBox="-27 -12 29 24" markerWidth="22" markerHeight="18" orient="auto">
<path fill="black" stroke="black" d="M0,0 L-20,-4 -16,0 -20,4 z M0,-10 L0,10 M0,0 L-27,0"/>
</marker>
<v-style type="text/css">
.sizeline { fill: none; stroke-width: 0.2; }
.sizetext { fill: black; stroke: none; font-weight:normal; font-family:'Arial'; font-size: 0.3em; }
</v-style>
</defs>
<g fill="none" stroke="black">
<path v-for="sector in drawing.sectors" :d="'M'+sector.p1.x+','+sector.p1.y+' A'+sector.radius+','+sector.radius+' 0 0,1 ' + sector.p2.x+','+sector.p2.y" />
<line v-for="line in drawing.lines" :x1="line.p1.x" :y1="line.p1.y" :x2="line.p2.x" :y2="line.p2.y" />
<circle v-for="circle in drawing.circles" :cx="circle.p.x" :cy="circle.p.y" :r="circle.r" />
</g>
<size-lines v-for="sizeline in drawing.sizelines" :sizeline="sizeline" />
</svg>
</div>
</div>`
})
Смотри также:
- Vue. Vue-router
- Vue. Свойство data. Основы компонент
- Vue. CRUD. Работа с данными
- Vue. Mixins (Примеси)
- Vue. computed свойства. Постраничный вывод данных
- Vue. Сортировка, поиск данных в таблицах
- Vue. Таблица - трансформер под настольные и мобильные версии
- Vue. Стандартная таблица. Минимизируем код
- Vue. Динамическая загрузка компонент
- Vue. Диалоги и Notifications
- Vue.Стандартный компонент для редактирования данных
- Vue. Разнообразие из кирпичиков
- Flask + Vue. Финальный пример
Додати коментар

Недавні записи
- Конструктор регуляторів моторів. Структура.
- Конструктор регуляторів моторів. Анонс.
- Golang + Vue + PostgreSQL #2
- Golang + Vue + SQLite #1
- FOC Position Control. Векторне управління - Стабілізація положення
- Flask & Vue. Завантаження файлів. Приклад № 2.10
- Рекуперація. FOC і цікаві досліди
- Flask & Vue. OAuth. Приклад№ 2.9
- Flask & Vue. Використання систем збірки проекту. Webpack. Приклад№ 2.8
- Flask & Vue. SQLAlchemy, Migrate, Marshmallow, JWT. Приклад№ 2.7
Tags
stm32 bkp soldering eeprom eb-500 led hih-4000 bme280 bmp280 3d-printer usb ethernet html git docker barometer raspberry-pi remap dc-dc rfid java-script nodemcu mpu-6050 rtc capture gpio avr brushless foc options flash flask atmega python displays rs-232 solar st-link ssd1331 dma adc bluetooth web ssd1306 wifi exti mpu-9250 pwm pmsm mongodb programmator i2c battery max1674 piezo css meteo watchdog books websocket servo dht11 ngnix mpx4115a lcd motor uart sensors nvic encoder usart sms smd bldc esp8266 tim timer gps examples
Архіви
