Визуализация данных представляет собой процесс преобразования числовой или категориальной информации в графические элементы. В контексте Snap.svg это означает работу с примитивами SVG — линиями, кругами, прямоугольниками и путями — для построения графиков, диаграмм и интерактивных схем.
SVG (Scalable Vector Graphics) обеспечивает масштабируемость и точность отображения, а Snap.svg предоставляет удобный API для манипуляции этими элементами.
Ключевые преимущества использования Snap.svg:
Перед визуализацией данные необходимо привести к удобному формату. Чаще всего используется массив объектов:
const data = [
{ label: "A", value: 30 },
{ label: "B", value: 80 },
{ label: "C", value: 45 },
{ label: "D", value: 60 }
];
Основные этапы подготовки:
Инициализация Snap.svg:
const s = Snap("#svg");
Создание рабочей области:
const width = 500;
const height = 300;
s.attr({
viewBox: `0 0 ${width} ${height}`
});
Добавление отступов:
const padding = 40;
const maxValue = Math.max(...data.map(d => d.value));
const barWidth = (width - padding * 2) / data.length;
data.forEach((d, i) => {
const barHeight = (d.value / maxValue) * (height - padding * 2);
const x = padding + i * barWidth;
const y = height - padding - barHeight;
s.rect(x, y, barWidth - 10, barHeight)
.attr({
fill: "#3498db"
});
});
data.forEach((d, i) => {
const x = padding + i * barWidth + (barWidth / 2);
s.text(x, height - 10, d.label)
.attr({
textAnchor: "middle"
});
});
const stepX = (width - padding * 2) / (data.length - 1);
const points = data.map((d, i) => {
const x = padding + i * stepX;
const y = height - padding - (d.value / maxValue) * (height - padding * 2);
return { x, y };
});
let pathString = `M ${points[0].x} ${points[0].y}`;
for (let i = 1; i < points.length; i++) {
pathString += ` L ${points[i].x} ${points[i].y}`;
}
s.path(pathString)
.attr({
fill: "none",
stroke: "#e74c3c",
strokeWidth: 2
});
points.forEach(p => {
s.circle(p.x, p.y, 4)
.attr({ fill: "#e74c3c" });
});
const total = data.reduce((sum, d) => sum + d.value, 0);
let startAngle = 0;
data.forEach(d => {
const angle = (d.value / total) * 360;
const endAngle = startAngle + angle;
const x1 = 250 + 100 * Math.cos(Math.PI * startAngle / 180);
const y1 = 150 + 100 * Math.sin(Math.PI * startAngle / 180);
const x2 = 250 + 100 * Math.cos(Math.PI * endAngle / 180);
const y2 = 150 + 100 * Math.sin(Math.PI * endAngle / 180);
const largeArc = angle > 180 ? 1 : 0;
const path = `
M 250 150
L ${x1} ${y1}
A 100 100 0 ${largeArc} 1 ${x2} ${y2}
Z
`;
s.path(path)
.attr({
fill: Snap.hsl(Math.random() * 360, 70, 50)
});
startAngle = endAngle;
});
s.line(padding, height - padding, width - padding, height - padding)
.attr({ stroke: "#000" });
s.line(padding, padding, padding, height - padding)
.attr({ stroke: "#000" });
const steps = 5;
for (let i = 0; i <= steps; i++) {
const y = height - padding - i * (height - padding * 2) / steps;
const value = (maxValue / steps) * i;
s.text(5, y, Math.round(value));
s.line(padding - 5, y, padding, y)
.attr({ stroke: "#000" });
}
Snap.svg предоставляет метод .animate():
rect.animate(
{ height: barHeight, y: y },
800,
mina.easeinout
);
Пример для линии:
path.attr({ strokeDasharray: pathLength, strokeDashoffset: pathLength });
path.animate(
{ strokeDashoffset: 0 },
1000
);
element.hover(
function () {
this.attr({ fill: "#2ecc71" });
},
function () {
this.attr({ fill: "#3498db" });
}
);
const tooltip = s.text(0, 0, "")
.attr({ opacity: 0 });
element.mousemove(function (e) {
tooltip.attr({
x: e.offsetX + 10,
y: e.offsetY - 10,
text: d.value,
opacity: 1
});
});
const group = s.group();
group.add(rect);
group.add(text);
group.transform("translate(10, 0)");
Преимущества:
Использование viewBox:
s.attr({
viewBox: "0 0 500 300",
width: "100%",
height: "auto"
});
Масштабирование без потери качества — ключевое преимущество SVG.
g)const gradient = s.gradient("L(0,0,1,1)#3498db-#9b59b6");
rect.attr({
fill: gradient
});
const mask = s.circle(250, 150, 80);
element.attr({
mask: mask
});
const clip = s.rect(100, 100, 200, 200);
element.attr({
clipPath: clip
});
Рекомендуемый подход:
Разделение ответственности упрощает поддержку и расширение визуализации.
Комбинирование различных типов графиков:
Snap.svg позволяет строить сложные визуализации через объединение простых примитивов.
function renderChart(data) {
const s = Snap("#svg");
const scales = calculateScales(data);
drawAxes(s, scales);
drawBars(s, data, scales);
addLabels(s, data, scales);
addInteractions(s);
}
Такой подход облегчает повторное использование и тестирование компонентов визуализации.