如何实现D3雷达图按固定间隔或数据变更重绘?附代码及报错
Hey Tony, let's fix this radar chart update issue step by step. Here's what we need to adjust to get your chart refreshing with new data every 5 seconds and resolve that pesky TypeError:
First, let's break down the core issues:
- Your AJAX call is successfully pulling data, but it wasn't feeding that new data into the radar chart
- The modified radar chart invocation you tried uses incorrect syntax for most custom D3 radar chart implementations (like the one from VisualCinnamon), causing the
Cannot read property 'apply' of undefinederror
1. Fix the Backend to Return Pure JSON
Your current phpmysqlconnect.php outputs script tags, which makes it hard for AJAX to process cleanly. Let's adjust it to return pure JSON data:
<?php require_once 'dbconfig.php'; header('Content-Type: application/json'); // Declare we're returning JSON try { $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password); $sql = 'SELECT cast(avg(field_18) as unsigned) AS field_18, cast(avg(field_19) as unsigned) AS field_19, cast(avg(field_20) as unsigned) AS field_20, cast(avg(field_21) as unsigned) AS field_21, cast(avg(field_22) as unsigned) AS field_22, cast(avg(field_23) as unsigned) AS field_23 FROM rstutdmkgk.craft_freeform_submissions WHERE formId =1'; $row = $pdo->prepare($sql); $row->execute(); $data=array(); foreach($row as $rec) { $json_array['field_18']=$rec['field_18']; $json_array['field_19']=$rec['field_19']; $json_array['field_20']=$rec['field_20']; $json_array['field_21']=$rec['field_21']; $json_array['field_22']=$rec['field_22']; $json_array['field_23']=$rec['field_23']; array_push($data,$json_array); } echo json_encode($data); // Output raw JSON } catch (PDOException $pe) { die(json_encode(['error' => "无法连接到数据库 $dbname :" . $pe->getMessage()])); } ?>
2. Rewrite Frontend Logic for Chart Updates
We'll encapsulate the radar chart drawing logic into reusable functions, so we can clear the old chart and redraw it with new data every time AJAX pulls fresh values:
<?php include 'phpmysqlconnect.php' ?> <script> function fetchdata(){ $.ajax({ url: 'phpmysqlconnect.php', type: 'post', dataType: 'json', // Tell jQuery to expect JSON success: function(newData){ updateRadarChart(newData); // Optional: Show raw data in the result div $('#my-result').html(JSON.stringify(newData, null, 2)); }, error: function(xhr, status, error){ console.error('Failed to fetch data:', error); } }); } $(document).ready(function(){ // Initialize chart with initial PHP-rendered data initRadarChart(<?php echo json_encode($data) ?>); // Start auto-refresh every 5 seconds setInterval(fetchdata, 5000); }); ////////////////////////////////////////////////////////////// //////////////////// Radar Chart Core Logic ////////////////// ////////////////////////////////////////////////////////////// var margin = {top: 100, right: 100, bottom: 100, left: 100}, width = Math.min(700, window.innerWidth - 10) - margin.left - margin.right, height = Math.min(width, window.innerHeight - margin.top - margin.bottom - 20); var color = d3.scale.ordinal() .range(["#EDC951","#CC333F","#00A0B0"]); var radarChartOptions = { w: width, h: height, margin: margin, maxValue: 5, levels: 5, roundStrokes: false, color: color }; // Initialize the chart on page load function initRadarChart(initialData) { var radarData = formatDataForRadar(initialData); RadarChart(".radarChart", radarData, radarChartOptions); } // Update chart with new data function updateRadarChart(newData) { // Clear old chart elements first d3.select(".radarChart").selectAll("*").remove(); // Format new data to match radar chart structure var radarData = formatDataForRadar(newData); // Redraw chart with fresh data RadarChart(".radarChart", radarData, radarChartOptions); } // Convert database data to radar chart-compatible structure function formatDataForRadar(dbData) { return [ [ {axis:"Battery Life",value: dbData[0]['field_18']}, {axis:"Brand",value: dbData[0]['field_19']}, {axis:"Contract Cost",value: dbData[0]['field_20']}, {axis:"Design And Quality",value: dbData[0]['field_21']}, {axis:"Have Internet Connectivity",value: dbData[0]['field_22']}, {axis:"Large Screen",value: dbData[0]['field_23']}, {axis:"Price Of Device",value:1}, {axis:"To Be A Smartphone",value:2} ] ]; } </script> <!-- 展示结果 --> <div id="my-result"></div> <div class="radarChart"></div> <script src="radarChart.js"></script>
3. Why Your Previous Code Broke
The error happened because the RadarChart function from the VisualCinnamon implementation doesn't return a callable object with update() or options() methods. Your line d3.select("#radarChart").call(radarChart) tried to invoke a non-function value, which triggered the Cannot read property 'apply' of undefined error.
Our solution uses a simpler, more reliable approach: clear the old chart entirely, then redraw it with fresh data every time we get an AJAX response.
4. Test It Out
- Start your server and load the page – no more console errors
- Watch the console for successful AJAX requests every 5 seconds
- Update the field values in your database, wait 5 seconds, and see the radar chart refresh automatically
内容的提问来源于stack exchange,提问作者Tony Clemmey

