Вопрос или проблема
Я экспериментирую с различными стилями для графиков и хочу узнать, как создать такой затененный полупрозрачный многоплощадный график с отображением индикатора при наведении мыши.
Моя текущая версия — обычные многолинейные графики
https://codesandbox.io/p/sandbox/magical-wiles-forked-wnzkfk
Пример базового графика площадей
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Загружаем d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Создаем див, где будет располагаться график -->
<div id="my_dataviz"></div>
<script>
// устанавливаем размеры и отступы графика
var margin = {top: 10, right: 30, bottom: 30, left: 50},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// добавляем объект svg в тело страницы
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Читаем данные
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered_comma.csv",
// При чтении csv я должен отформатировать переменные:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Теперь я могу использовать этот набор данных:
function(data) {
// Добавляем ось X --> это формат даты
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Добавляем ось Y
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) { return +d.value; })])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));
// Добавляем площадь
svg.append("path")
.datum(data)
.attr("fill", "#cce5df")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.area()
.x(function(d) { return x(d.date) })
.y0(y(0))
.y1(function(d) { return y(d.value) })
)
})
</script>
Ответ или решение
Чтобы создать многослойный полупрозрачный график области с индикацией на наведение, используя D3.js, мы можем начать с базового примера графика области и затем добавить несколько слоев областей и информацию для отображения при наведении.
Ниже приведен обновленный пример кода на JavaScript, который реализует такие функции:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Многослойный полупрозрачный график области</title>
<script src="https://d3js.org/d3.v6.min.js"></script>
<style>
.tooltip {
position: absolute;
text-align: center;
padding: 6px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
</head>
<body>
<div id="my_dataviz"></div>
<script>
// Устанавливаем размеры и отступы графика
var margin = {top: 10, right: 30, bottom: 30, left: 50},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// Создаем SVG элемент
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Чтение данных
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered_comma.csv").then(function(data) {
// Форматирование данных
data.forEach(function(d) {
d.date = d3.timeParse("%Y-%m-%d")(d.date);
d.value = +d.value;
});
// Установка шкалы оси X
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Установка шкалы оси Y
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) { return d.value; })])
.range([height, 0]);
svg.append("g").call(d3.axisLeft(y));
// Создаем массив данных для нескольких областей
var areaData = [
{ color: "#cce5df", name: "Area 1" },
{ color: "#69b3a2", name: "Area 2" }
];
areaData.forEach(function(area, index) {
// Добавляем область
svg.append("path")
.datum(data)
.attr("fill", area.color)
.attr("opacity", 0.5)
.attr("d", d3.area()
.x(function(d) { return x(d.date); })
.y0(y(0) + index * 20) // Сдвиг области вниз
.y1(function(d) { return y(d.value); })
);
// Добавление события наведения для отображения значений
svg.selectAll(".dot" + index)
.data(data)
.enter().append("circle")
.attr("class", "dot" + index)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.value); })
.attr("r", 5)
.attr("fill", area.color)
.on('mouseover', function(event, d) {
tooltip.style("display", "block")
.html(area.name + ": " + d.value)
.style("left", (event.pageX + 5) + "px")
.style("top", (event.pageY - 28) + "px");
})
.on('mouseout', function() {
tooltip.style("display", "none");
});
});
// Создаем подложку для инструментальной подсказки
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("display", "none");
});
</script>
</body>
</html>
Объяснение кода:
- SVG и размеры: Код создает SVG-элемент и задает его размеры и отступы.
- Чтение данных: Данные загружаются из CSV-файла и содержимое столбцов преобразуется в формат, подходящий для D3.js.
- Установка осей: X и Y оси настроены для отображения значений.
- Области: Создаются две области с различными цветами и полупрозрачностями. Скрипт добавляет сдвиг для каждой области, чтобы они не накладывались друг на друга.
- Инструментальная подсказка: При наведении на точки данных отображается подсказка с названием области и соответствующим значением.
Этот пример можно адаптировать для добавления большего числа областей и настройки стилей по вашему усмотрению.