You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:基于HTML/CSS/Chart.js实现指定动态交互式图表

求助:实现指定样式的动态交互图表

我是开发新手,急需用HTML、CSS和JavaScript(或Chart.js)实现符合以下要求的动态图表,但自己写的代码无法达到效果,没时间系统学习,恳请协助:

图表要求

  • 坐标轴参数:X轴刻度从左到右为0,10,20,...,200;Y轴刻度从下到上为0,10,20,...,100
  • 背景使用指定棋盘格图片
  • 可根据输入的X、Y轴数据,在对应位置放置指定标记图
  • 交互功能:点击空心黑圆点时,该点变为橙色实心点,原选中点恢复为空心黑圆,且橙色点旁显示对应Y轴数值

我尝试的代码如下:

<!DOCTYPE html>
<html>
<head>
<title>Dynamic Break Linear Graph</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
</head>
<body>
<canvas id="myChart" width="400" height="200"></canvas>
<input type="number" id="x" value="10">
<input type="number" id="y" value="10">
<script>
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "line",
data: {
labels: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
datasets: [{
label: "Break Linear",
data: Array.from(Array(10), function(_, i) {
var xValue = i * x / 10;
var yValue = i * y / 10;
return Math.min(xValue, yValue);
}),
borderColor: "#000",
backgroundColor: "#ccc"
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
min: 0,
max: 10
}],
xAxes: [{
ticks: {
beginAtZero: true
},
min: 0,
max: 10
}],
breaks: [{
position: 5,
direction: "up"
}]
}
}
});
var xInput = document.getElementById("x");
var yInput = document.getElementById("y");
xInput.addEventListener("change", function() {
var x = parseInt(xInput.value);
var y = parseInt(yInput.value);
myChart.data.datasets[0].data = Array.from(Array(10), function(_, i) {
var xValue = i * x / 10;
var yValue = i * y / 10;
return Math.min(xValue, yValue);
});
myChart.update();
});
yInput.addEventListener("change", function() {
var x = parseInt(xInput.value);
var y = parseInt(yInput.value);
myChart.data.datasets[0].data = Array.from(Array(10), function(_, i) {
var xValue = i * x / 10;
var yValue = i * y / 10;
return Math.min(xValue, yValue);
});
myChart.update();
});
</script>
</body>
</html>

解决方案代码

以下是满足所有要求的完整实现:

<!DOCTYPE html>
<html>
<head>
    <title>Dynamic Interactive Chart</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
    <style>
        #myChart {
            background-image: url('https://i.sstatic.net/2OMgi.png');
            background-repeat: repeat;
        }
        .input-group {
            margin: 10px 0;
        }
        input {
            width: 80px;
            padding: 5px;
            margin-right: 10px;
        }
    </style>
</head>
<body>
    <canvas id="myChart" width="800" height="400"></canvas>
    <div class="input-group">
        <label>X值:</label>
        <input type="number" id="xInput" value="50" min="0" max="200">
        <label>Y值:</label>
        <input type="number" id="yInput" value="30" min="0" max="100">
        <button onclick="updateChart()">更新数据</button>
    </div>

    <script>
        // 预加载标记图片
        const markerImg = new Image();
        markerImg.src = 'https://i.sstatic.net/xmgyz.png';
        
        let selectedPointIndex = -1;

        // 初始化图表
        const ctx = document.getElementById("myChart").getContext("2d");
        const myChart = new Chart(ctx, {
            type: 'scatter',
            data: {
                datasets: [{
                    label: '数据点',
                    data: [{x: 50, y: 30}],
                    pointStyle: markerImg,
                    pointRadius: 15,
                    pointHoverRadius: 18,
                    backgroundColor: '#000',
                    borderColor: '#000',
                    borderWidth: 2
                }]
            },
            options: {
                responsive: true,
                scales: {
                    xAxes: [{
                        type: 'linear',
                        ticks: {
                            min: 0,
                            max: 200,
                            stepSize: 10,
                            // 每20显示一次刻度,避免过于拥挤
                            callback: function(value) {
                                return value % 20 === 0 ? value : '';
                            }
                        },
                        gridLines: {
                            color: 'rgba(0,0,0,0.1)'
                        }
                    }],
                    yAxes: [{
                        type: 'linear',
                        ticks: {
                            min: 0,
                            max: 100,
                            stepSize: 10
                        },
                        gridLines: {
                            color: 'rgba(0,0,0,0.1)'
                        }
                    }]
                },
                tooltips: {
                    enabled: false // 禁用默认提示框,自定义显示
                },
                onClick: function(e, elements) {
                    if (elements.length > 0) {
                        const clickedIndex = elements[0]._index;
                        
                        // 重置之前选中的点样式
                        if (selectedPointIndex !== -1) {
                            myChart.data.datasets[0].backgroundColor[selectedPointIndex] = '#000';
                            myChart.data.datasets[0].pointStyle[selectedPointIndex] = markerImg;
                        }
                        
                        // 设置当前选中点为橙色实心圆
                        selectedPointIndex = clickedIndex;
                        myChart.data.datasets[0].backgroundColor[clickedIndex] = '#ff8c00';
                        myChart.data.datasets[0].pointStyle[clickedIndex] = 'circle';
                        
                        myChart.update();
                    }
                },
                animation: {
                    duration: 300
                }
            },
            // 自定义绘制选中点的Y值
            plugins: [{
                afterDraw: function(chart) {
                    if (selectedPointIndex !== -1) {
                        const point = chart.data.datasets[0].data[selectedPointIndex];
                        const meta = chart.getDatasetMeta(0);
                        const pointPos = meta.data[selectedPointIndex].getCenterPoint();
                        
                        chart.ctx.font = '14px Arial';
                        chart.ctx.fillStyle = '#ff8c00';
                        chart.ctx.textAlign = 'center';
                        chart.ctx.fillText(`Y: ${point.y}`, pointPos.x, pointPos.y - 25);
                    }
                }
            }]
        });

        // 更新图表数据函数
        function updateChart() {
            const xVal = parseInt(document.getElementById('xInput').value);
            const yVal = parseInt(document.getElementById('yInput').value);
            
            // 确保输入值在坐标轴范围内
            const validX = Math.max(0, Math.min(200, isNaN(xVal) ? 0 : xVal));
            const validY = Math.max(0, Math.min(100, isNaN(yVal) ? 0 : yVal));
            
            document.getElementById('xInput').value = validX;
            document.getElementById('yInput').value = validY;
            
            // 更新数据点并重置选中状态
            myChart.data.datasets[0].data = [{x: validX, y: validY}];
            selectedPointIndex = -1;
            myChart.data.datasets[0].backgroundColor = '#000';
            myChart.data.datasets[0].pointStyle = markerImg;
            
            myChart.update();
        }

        // 输入框回车触发更新
        document.getElementById('xInput').addEventListener('keypress', e => {
            if (e.key === 'Enter') updateChart();
        });
        document.getElementById('yInput').addEventListener('keypress', e => {
            if (e.key === 'Enter') updateChart();
        });
    </script>
</body>
</html>

实现要点说明

  1. 坐标轴配置:使用线性坐标轴,严格设置X轴范围0-200、步长10,Y轴范围0-100、步长10,优化刻度显示避免拥挤。
  2. 背景设置:通过CSS为canvas添加指定棋盘格背景并设置重复平铺。
  3. 标记点实现:预加载指定标记图片,设置为图表点的样式,调整点大小保证显示清晰。
  4. 交互逻辑:
    • 监听图表点击事件,切换选中点的样式,同时重置之前选中的点
    • 通过Chart.js的afterDraw插件,在选中点上方绘制对应的Y轴数值
    • 输入框添加范围验证,确保数据始终在坐标轴有效范围内

内容的提问来源于stack exchange,提问作者MeriJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:17:09