
<!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>