Спідометр на HTML5 Canvas

В мережі є кілька схожих прикладів створення спідометра, але я вирішив поділитися з вами своїм.

image

Для початку нам потрібно в DOM'е створити об'єкт canvas:

<canvas id="canvas" width="500px" height="500px"></canvas>

Прописувати стилі інлайн — це гріх, але якщо ширину і висоту канвасу задати за допомогою css, ми зіткнемося з масою проблем, а якщо бути точніше — це просто не буде працювати. Тепер переходимо безпосередньо до скрипта. Спочатку нам потрібно отримати 2d контекст, з яким ми і далі будемо працювати:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

Далі йде ряд налаштувань, які нам знадобляться в обчисленнях. Всі значення розмірів я вираховується відносно ширини кинувся. Таким чином, при зміні розмірів кинувся, пропорції спідометра не зміняться

// general settings
var middleX = canvas.width / 2;
var middleY = canvas.height / 2;
var radius = canvas.width / 2 - canvas.width / 10;
// beginning and ending of our arc. Sets by rad * pi
var startAngleIndex = 0.7;
var endAngleIndex = 2.3;

// zones settings
var zoneLineWidth = canvas.width / 30;
var counterClockwise = false;

// settings ticks
var tickWidth = canvas.width / 100;
var tickColor = "#746845";
var tickOffsetFromArc = canvas.width / 40;

// Center circle settings
var centerCircleRadius = canvas.width / 20;
var centerCircleColor = "#efe5cf";
var centerCircleBorderWidth = canvas.width / 100;

// Settings Arrow
var arrowValueIndex = 1.29;
var arrowColor = "#464646";
var arrowWidth = canvas.width / 50;

// Digits settings
var digits = [0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240];
var digitsColor = "#746845";
var digitsFont = "bold 20px Tahoma";
var digitsOffsetFromArc = canvas.width / 12;

var zonesCount = digits.length - 1;
var step = (endAngleIndex - startAngleIndex) / zonesCount;

Окремо хотів би зупинитися на змінних startAngleIndex та endAngleIndex . Щоб краще зрозуміти, звідки взялися такі значення, я покажу картинку, взяту з сайту www.html5canvastutorials.com

image

Далі реалізуємо декілька методів, які будуть перетворювати на канвасі елементи спідометра.

var DrawZones = function() {
var greenZonesCount = Math.ceil(zonesCount / 2);
var yellowZonesCount = Math.ceil((zonesCount - greenZonesCount) / 2);
var redZonesCount = zonesCount - greenZonesCount - yellowZonesCount;

var startAngle = (startAngleIndex - 0.02) * Math.PI;
var endGreenAngle = (startAngleIndex + greenZonesCount * step) * Math.PI;
var endYellowAngle = (startAngleIndex + (greenZonesCount + yellowZonesCount) * step) * Math.PI;
var endRedAngle = (endAngleIndex + 0.02) * Math.PI;

var sectionOptions = [
{
startAngle: startAngle,
endAngle: endGreenAngle,
color: "#090"
},
{
startAngle: endGreenAngle,
endAngle: endYellowAngle,
color: "#cc0"
},
{
startAngle: endYellowAngle,
endAngle: endRedAngle,
color: "#900"
}
];

this.DrawZone = function(options) {
ctx.beginPath();
ctx.arc(middleX, middleY, radius, options.startAngle, options.endAngle, counterClockwise);
ctx.lineWidth = zoneLineWidth;
ctx.strokeStyle = options.color;
ctx.lineCap = "butt";
ctx.stroke();
};

sectionOptions.forEach(function(options) {
DrawZone(options);
});
};

У цьому методі я розбираю масив digits і визначаю скільки повинно бути зелених, жовтих і червоних зон.

image
Метод DrawTicks малює зарубки на дузі з кроком, высчитанным раніше

var DrawTicks = function() {

this.DrawTick = function(angle) {
var fromX = middleX + (radius - tickOffsetFromArc) * Math.cos(angle);
var fromY = middleY + (radius - tickOffsetFromArc) * Math.sin(angle);
var toX = middleX + (radius + tickOffsetFromArc) * Math.cos(angle);
var toY = middleY + (radius + tickOffsetFromArc) * Math.sin(angle);

ctx.beginPath();
ctx.moveTo(fromX, fromY);
ctx.lineTo(toX, toY);
ctx.lineWidth = tickWidth;
ctx.lineCap = "round";
ctx.strokeStyle = tickColor;
ctx.stroke();
};

for (var i = startAngleIndex; i <= endAngleIndex; i += step) {
var angle = i * Math.PI;
this.DrawTick(angle);
}
};

image
Наступний метод отрисует нам цифри на майбутньому спідометрі

var DrawDigits = function() {
var angleIndex = startAngleIndex;

digits.forEach(function(digit) {
var angle = angleIndex * Math.PI;
angleIndex += step;
var x = middleX + (radius - digitsOffsetFromArc) * Math.cos(angle);
var y = middleY + (radius - digitsOffsetFromArc) * Math.sin(angle);

ctx.font = digitsFont;
ctx.fillStyle = digitsColor;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(digit, x, y);
});
};

image
Останні два методи призначені для відтворення центрального кола і, власне, стрілки. При бажанні метод DrawArrow можна навчити приймати нормальні значення і реалізувати логіку, яка буде визначати, куди стрілка буде показувати

var DrawArrow = function() {
var arrowAngle = arrowValueIndex * Math.PI;
var toX = middleX + (radius) * Math.cos(arrowAngle);
var toY = middleY + (radius) * Math.sin(arrowAngle);

ctx.beginPath();
ctx.moveTo(middleX, middleY);
ctx.lineTo(toX, toY);
ctx.strokeStyle = arrowColor;
ctx.lineWidth = arrowWidth;
ctx.stroke();
};

var DrawCenterCircle = function() {
ctx.beginPath();
ctx.arc(middleX, middleY, centerCircleRadius, 0, 2 * Math.PI, false);
ctx.fillStyle = centerCircleColor;
ctx.fill();
ctx.lineWidth = centerCircleBorderWidth;
ctx.strokeStyle = arrowColor;
ctx.stroke();
};

Залишилося викликати наші методи в потрібному порядку

DrawTicks();
DrawZones();
DrawDigits();
DrawArrow();
DrawCenterCircle();

Звичайно ж, порядок виклику має значення, так само, як і, наприклад, порядок шарів у фотошопі (тільки в зворотному порядку)
Результат:
image

Джерела:
<habracut/>
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.