<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>需求</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
#graph-container {
width: 50%;
height: 30%;
position: relative;
display: flex;
flex-direction: column;
/*一定要加position: relative*/
}
#graph{
width: 100%;
flex: 1;
}
.chart-title {
text-align: center;
color: #333;
margin-bottom: 20px;
}
#zhe-xian-tooltip {
position: absolute;
padding: 12px;
background: rgba(0, 0, 0, 0.85);
color: white;
border-radius: 6px;
pointer-events: none;
font-size: 14px;
font-family: sans-serif;
opacity: 0;
}
.zhe-xian-circle{
fill: #e63946;
stroke: white;
stroke-width: 2;
transition: r 0.2s;
}
.zhe-xian-line {
fill: none;
stroke: #e63946;
stroke-width: 3;
stroke-linejoin: round;
}
</style>
</head>
<body>
<button id="myButton" style="margin-right: 40px">数据变更</button>
<div id="graph-container">
<h2 class="chart-title">标题</h2>
<div id="graph">
<div id="zhe-xian-tooltip">
</div>
</div>
</div>
<script>
const generateData = () => {
return Array.from({length: Math.floor(Math.random() * 12) + 5}, (_, index) => ({
time: index + 1,
count: Math.floor(Math.random() * 100) // 生成0-99的随机整数
}));
}
const drawZheXianGraph = (dataset, container, update) => {
dataset.sort((a, b) => a.time - b.time);//按照月份排序
console.log("绘制图形数据", dataset);
const element = document.getElementById(container);
const width = element.offsetWidth; // 宽度(含 padding + border)
const height = element.offsetHeight; // 高度(含 padding + border)
const margin = {
left: 50,
right: 30,
top: 30,
bottom: 50
}
if (!update) {
d3.select(`#${container}`).append('svg').attr('width', width).attr('height', height);
}
const svg = d3.select(`#${container}`).select('svg');
//定义x轴比例尺
const xScale = d3
.scaleBand()
.domain(dataset.map(item => item.time))
.range([margin.left, width - margin.right])
.padding(0) // 设置柱子之间的间隙
.paddingInner(1); // 设置柱子内部的间隙
console.log(xScale(1), xScale(2));
// 获取所有count值组成的数组
const counts = dataset.map(item => item.count);
const maxCount = Math.max(...counts);
//定义y轴比例尺
const yScale = d3
.scaleLinear()
.domain([0, maxCount])
.range([height - margin.bottom, margin.top]);
//定义绘制折线的函数
const line = d3
.line()
.x(function (d) {
return xScale(d.time) + xScale.bandwidth() / 2;
})
.y(function (d) {
return yScale(d.count);
})
// .curve(d3.curveCardinal) //曲线
.curve(d3.curveLinear) //直线
const xAxis = d3
.axisBottom(xScale)
.tickFormat(function (d, i) {
return dataset[i].time;
});
const yAxis = d3.axisLeft(yScale);
// 每个区域绘制一个矩形用于触发事件
const _w = (width - margin.left - margin.right) / (dataset.length - 1);
const tooltip = d3.select('#zhe-xian-tooltip');
function showTooltip(event, d) {
tooltip.transition()
.duration(200)
.style("opacity", 0.9);
tooltip.html(`
time: ${d.time}<br>
count: ${d.count}
`)
.style("left", (xScale(d.time) + xScale.bandwidth() / 2 + 10) + "px")
.style("top", (yScale(d.count) - 10) + "px");
}
function hideTooltip() {
tooltip.transition()
.duration(500)
.style("opacity", 0);
}
if (update) {
//更新x轴和y轴
svg.select(".zhe-xian-x-axis")
.transition()
.duration(500)
.call(xAxis);
svg.select(".zhe-xian-y-axis")
.transition()
.duration(500)
.call(yAxis)
svg.selectAll(".zhe-xian-line")
.datum(dataset)
.join("path")
.attr("class", "zhe-xian-line")
.transition()
.duration(500)
.attr("d", line)
svg.selectAll('.zhe-xian-circle')
.data(dataset)
.join("circle")
.attr("class", "zhe-xian-circle")
.attr("r", 5)
.style('cursor', 'pointer')
.on('mouseover', showTooltip)
.on('mouseout', hideTooltip)
.transition()
.duration(500)
.attr('cx', function (d) {
return xScale(d.time) + xScale.bandwidth() / 2;
})
.attr('cy', function (d) {
return yScale(d.count);
})
} else {
svg
.append('path')
.datum(dataset)
.attr('class', 'zhe-xian-line')
.attr('d', line)
svg
.append('g')
.attr('class', 'zhe-xian-x-axis')
.attr('transform', 'translate(0,' + (height - margin.bottom) + ')')
.call(xAxis);
svg
.append('g')
.attr('class', 'zhe-xian-y-axis')
.attr('transform', 'translate(' + margin.left + ',0)')
.call(yAxis);
// 绘制圆点
svg
.selectAll('.zhe-xian-circle')
.data(dataset)
.enter()
.append('circle')
.attr('class', 'zhe-xian-circle')
.attr('cx', function (d) {
return xScale(d.time) + xScale.bandwidth() / 2;
})
.attr('cy', function (d) {
return yScale(d.count);
})
.attr('r', 5) //修改圆点大小
.style('cursor', 'pointer')
.on('mouseover', showTooltip)
.on('mouseout', hideTooltip);
svg.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("x", -height/2)
.attr("y", margin.left-30)
.style("text-anchor", "middle")
.text("数量");
svg.append("text")
.attr("class", "axis-label")
.attr("x", width / 2)
.attr("y", height-10)
.style("text-anchor", "middle")
.text("月份");
}
}
drawZheXianGraph(generateData(), "graph", false)
// 绑定点击事件
document.getElementById('myButton').addEventListener('click', function () {
console.log("我被点击了")
drawZheXianGraph(generateData(), "graph", true)
// 这里可以添加更多自定义逻辑
});
</script>
</body>
</html>
d3_v7绘制折线图
最新推荐文章于 2025-05-06 09:59:37 发布