d3_v7绘制折线图

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

生成折线图的源码需要实现以下几个步骤: 1. 读取Excel文件:使用JavaScript在HTML中引入Excel文件,并通过JavaScript的File API读取文件数据。 2. 解析Excel数据:将Excel文件中的数据解析为JavaScript对象,以便后续数据的处理和使用。 3. 绘制折线图:根据解析后的Excel数据,使用JavaScript的绘图API(例如D3.js、Chart.js等),绘制折线图。 4. 页面展示:将绘制好的折线图动态地添加到HTML页面中展示出来。 根据以上步骤,可以使用以下代码实现生成折线图的源码: ```html <!DOCTYPE html> <html> <head> <title>Excel数据折线图</title> <meta charset="utf-8"> <script src="https://d3js.org/d3.v7.min.js"></script><!--使用D3.js作为绘图API--> </head> <body> <input type="file" id="fileInput"> <div id="chart"></div> <script> var fileInput = document.getElementById("fileInput"); var chart = document.getElementById("chart"); fileInput.addEventListener("change", function(e) { var file = e.target.files[0]; var reader = new FileReader(); reader.onload = function(e) { var data = e.target.result; var workbook = XLSX.read(data, {type: &#39;binary&#39;});//使用XLSX库解析Excel文件 var sheetName = workbook.SheetNames[0]; var sheet = workbook.Sheets[sheetName]; var jsonData = XLSX.utils.sheet_to_json(sheet);//将数据解析为JavaScript对象 //绘制折线图 var margin = {top: 20, right: 20, bottom: 30, left: 50}; var width = chart.offsetWidth - margin.left - margin.right; var height = chart.offsetHeight - margin.top - margin.bottom; var svg = d3.select("#chart").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom); var g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var x = d3.scaleLinear().range([0, width]); var y = d3.scaleLinear().range([height, 0]); var line = d3.line().x(function(d) { return x(d.x); }).y(function(d) { return y(d.y); }); x.domain(d3.extent(jsonData, function(d) { return d.x; })); y.domain([0, d3.max(jsonData, function(d) { return d.y; })]); g.append("g").attr("transform", "translate(0," + height + ")").call(d3.axisBottom(x)).select(".domain").remove(); g.append("g").call(d3.axisLeft(y)).append("text").attr("fill", "#000").attr("transform", "rotate(-90)").attr("y", 6).attr("dy", "0.71em").attr("text-anchor", "end").text("Value"); g.append("path").datum(jsonData).attr("class", "line").attr("d", line); }; reader.readAsBinaryString(file); }); </script> </body> </html> ``` 以上代码中,`XLSX`库用于解析Excel文件,`d3.js`作为绘图API,输入框用于选择要读取的Excel文件,折线图会自动在页面中展示出来。在使用时需要注意,需先安装相关库并将相关库文件引入HTML文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

deyong1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值