Как сделать Canvas спидометр на VUE?
Недавно взял заказ на игровой Hud, для одного проекта. Проблема в том, что я раньше не сталкивался с Canvas, да и не до конца понимаю как его использовать во VUE реактивно.
Сам принцип работы: -- Спидометр должен считывать значения из стейта, а именно значения state.speed и state.maxSpeed и подставляться в данный Canvas.
Хотел бы попросить помощи у тех, кто разбирается лучше меня. Помощь в виде направления на чтение материала или же помощь кодом с объяснением действий. Всем кто не останется равнодушными и не пройдет мимо, спасибо.
Figma: https://www.figma.com/file/d0I6yGnc90yFGxq4yQw1qS/...
Ответы (1 шт):
Вы можете использовать пользовательскую директиву, которая даст вам возможность делать низкоуровневые операции с DOM(отрисовку canvas).
Первым аргументом в директиве v-draw будет элемент, к которому привязана ваша директива - canvasElement, вторым binding - объект, в свойстве value которого будут данные(в примере state).
Привожу пример для наглядности данного подхода:
new Vue({
el: '#app',
data: {
state: {
speed: 0,
maxSpeed: 200,
},
},
directives: {
draw: function(canvasElement, binding) {
const {
speed,
maxSpeed
} = binding.value
const r = 50
const x = 100
const y = 100
const koof = speed / maxSpeed + 0.8
var ctx = canvasElement.getContext("2d");
ctx.clearRect(0, 0, 300, 300);
ctx.fillStyle = "green";
ctx.font = "20px Arial";
ctx.fillText(speed, x - 10, y);
ctx.fillStyle = "silver";
ctx.font = "15px Arial";
ctx.fillText('км/ч', x - 10, y + 10);
ctx.beginPath();
ctx.lineWidth = 10;
ctx.strokeStyle = "#dddddd50"
ctx.arc(x, y, r, 0.8 * Math.PI, 1.8 * Math.PI, false)
ctx.stroke();
ctx.moveTo(x, y)
ctx.beginPath();
ctx.strokeStyle = "green"
ctx.arc(x, y, r, 0.8 * Math.PI, koof * Math.PI, false)
ctx.stroke();
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<body>
<div id="app">
<canvas width="150" height="150" v-draw="state"></canvas>
<br>
<input type="range" v-model="state.speed" :max="state.maxSpeed" step="1" />
<span>< Акселератор </span>
</div>
</body>
