数据可视化:php+echarts实现数据可视化
一、实现效果
实现动态时间,多列柱状图,单列柱状图,普通表格,表格动画等效果
二、实现
1、动态时间显示
通过php获取当前时间
设置计时器来动态显示时间秒数
<!-- 时间动画 -->
<script>// 动态更新时间中的秒数function updateTime() {const now = new Date();const hours = String(now.getHours()).padStart(2, '0');const minutes = String(now.getMinutes()).padStart(2, '0');const seconds = String(now.getSeconds()).padStart(2, '0');const formattedTime = `${hours}:${minutes}:${seconds}`;// 更新时间显示document.getElementById('current-time').textContent = formattedTime;}// 每秒更新一次时间setInterval(updateTime, 1000);// 页面加载时立即更新时间updateTime();
</script>
2、非图表数据获取
第一行的标题,第二行的第一列,第二列,第三行的第三列均使用普通数据
①主页面展示框架
例如,线别的获取,写入div框架,内部的内容由ajax获取
②ajax请求
请求数据同时设置刷新时间,保证数据的及时更新
function fetchData() {fetch('echarts/get_base_data.php').then(response => response.json()).then(data => {console.log(data);// 线别const lineTitle = document.querySelector('.line1_title');if (lineTitle && data.linebody && data.linebody.linebody) {lineTitle.textContent = data.linebody.linebody;}// 清空旧工单信息const wipContainer = document.querySelector('.line2_item1');if (wipContainer) {wipContainer.innerHTML = ''; // 清空之前的内容if (data.wip) {const wipHtml = `<div class="line2_1_block flex flex-between"><div class="line2_1_title">工单号</div><div class="line2_1_content">${data.wip.wip_entity_name || ''}</div></div><div class="line2_1_block flex flex-between"><div class="line2_1_title">机种料号</div><div class="line2_1_content">${data.wip.item_no || ''}</div></div><div class="line2_1_block flex flex-between"><div class="line2_1_title">机种名称</div><div class="line2_1_content">${data.wip.item_name || ''}</div></div><div class="line2_1_block flex flex-between"><div class="line2_1_title">规格型号</div><div class="line2_1_content">${data.wip.item_desc || ''}</div></div><div class="line2_1_block flex flex-between"><div class="line2_1_title">在岗人数</div><div class="line2_1_content">${data.linebody.atwork_qty || ''}</div></div><div class="line2_1_block flex flex-between"><div class="line2_1_title">加工面别</div><div class="line2_1_content">${data.linebody.surface || ''}</div></div>`;wipContainer.innerHTML = wipHtml;} else {wipContainer.innerHTML = '<div class="no-data flex flex-center">暂未查到线别对应工单信息</div>';}}.....}).catch(error => console.error('Error fetching data:', error));
}
// 每隔一定时间自动刷新数据(例如每1秒刷新一次)
setInterval(fetchData, 5000);
// 页面加载后立即加载一次
document.addEventListener("DOMContentLoaded", fetchData);
③php获取基本数据
根据php去获取基本数据,并返回
<?php
header('Content-Type: application/json');
require_once '../get_db_conn.php';
$conn = db_connect();
mysqli_set_charset($conn, 'utf8');// 查询线别信息
$sql_linebody = "SELECT * FROM linebody_board_front WHERE 1=1";
$result_linebody = mysqli_query($conn, $sql_linebody);
$linebody_data = [];if ($result_linebody && mysqli_num_rows($result_linebody) > 0) {while ($row = mysqli_fetch_assoc($result_linebody)) {$linebody_data[] = $row;}
}// 查询工单机种信息
$wip_data = [];
if (!empty($linebody_data)) {$linebody = $linebody_data[0]['linebody'];$sql_wip = "SELECT wc.wip_entity_name AS wip_entity_name,wj.primary_item AS item_no,si.item_desc AS item_desc,si.item_name AS item_nameFROM wip_capacity wcLEFT JOIN wip_jobs_all wj ON wc.wip_entity_name = wj.wip_entity_nameLEFT JOIN sf_item_no si ON wj.primary_item = si.item_noWHERE wc.linebody = '" . mysqli_real_escape_string($conn, $linebody) . "'ORDER BY wc.creation_date ASCLIMIT 1";$result_wip = mysqli_query($conn, $sql_wip);if ($result_wip) {while ($row = mysqli_fetch_assoc($result_wip)) {$wip_data[] = $row;}}
}
.....// 返回 JSON 数据
echo json_encode(['linebody' => !empty($linebody_data) ? $linebody_data[0] : null,'wip' => !empty($wip_data) ? $wip_data[0] : null,'line_post' => $line_post_data,'abnormal' => $abnormal_data
]);?>
3、图表数据获取
①引入方法
引入使用jquery和echarts图表
引入写入linebody.js方法(封装的图表js)
②主页面写入图表的框架
③写入图表样式
根据echarts官网示例,引入echarts模板,再写入ajax去获取动态的数据,并且设置数据刷新
document.addEventListener("DOMContentLoaded", function () {// 全局刷新间隔时间(毫秒)const REFRESH_INTERVAL = 3000;let refreshTimer = null;// ============ 计划产能与实际达成 图表 ====================function initCapacityChart() {const chartDom = document.getElementById("capacity");if (!chartDom) {console.error("未找到 ID 为 capacity 的图表容器");return;}// 创建提示信息的 DOM 元素const noDataText = document.createElement('div');noDataText.innerText = '暂无计划产能与实际达成数据';noDataText.style.color = '#ffffff';noDataText.style.fontSize = '16px';noDataText.style.textAlign = 'center';noDataText.style.marginTop = '20px';noDataText.style.display = 'none';chartDom.parentNode.appendChild(noDataText);const myChart = echarts.init(chartDom);let autoPlayInterval = null;let currentIndex = -1;// 默认配置const option = {title: {text: '计划产能与实际达成',left: 'center',textStyle: { color: '#ffffff', fontSize: 16 }},tooltip: {trigger: 'axis',axisPointer: { type: 'shadow' },show: true,textStyle: { color: 'black' }},legend: {data: ['计划量', '实际产出'],bottom: '0',textStyle: { color: '#ffffff' }},xAxis: {type: 'category',data: [],axisLabel: { color: '#ffffff' },axisLine: { lineStyle: { color: '#ffffff' } }},yAxis: {type: 'value',name: '',axisLabel: { color: '#ffffff' },axisLine: { lineStyle: { color: '#ffffff' } }},series: [{name: '计划量',type: 'bar',data: [],itemStyle: { color: '#ff6d00' },label: {show: true,position: 'top',valueAnimation: true,formatter: '{c}',color: '#fff'}},{name: '实际产出',type: 'bar',data: [],itemStyle: { color: '#00ddfd' },label: {show: true,position: 'top',valueAnimation: true,formatter: '{c}',color: '#fff'}}]};// 获取数据并更新图表function fetchData() {fetch("echarts/get_data.php?type=capacity").then(response => response.json()).then(jsonData => {if (!jsonData || jsonData.length === 0) {chartDom.style.display = 'none';noDataText.style.display = 'block';return;}chartDom.style.display = 'block';noDataText.style.display = 'none';// 提取数据const xAxisData = jsonData.map(item => item.time_slot);const planValues = jsonData.map(item => item.plan_qty);const actualValues = jsonData.map(item => item.real_qty);// 更新配置项option.xAxis.data = xAxisData;option.series[0].data = planValues;option.series[1].data = actualValues;// 渲染图表myChart.setOption(option);// 启动自动提示startAutoShowTooltip(myChart, xAxisData.length);}).catch(error => {console.error("加载数据失败:", error);chartDom.style.display = 'none';noDataText.innerText = '加载数据失败,请检查网络或后端接口';noDataText.style.display = 'block';});}// 初始加载数据fetchData();// 动态展示提示信息function startAutoShowTooltip(myChart, dataLength) {stopAutoShowTooltip(); // 防止重复启动autoPlayInterval = setInterval(() => {if (dataLength === 0) return;currentIndex = (currentIndex + 1) % dataLength;myChart.dispatchAction({type: 'highlight',dataIndex: currentIndex,seriesIndex: 0});myChart.dispatchAction({type: 'showTip',seriesIndex: 0,dataIndex: currentIndex});}, 2000);}// 停止动画function stopAutoShowTooltip() {if (autoPlayInterval) clearInterval(autoPlayInterval);}// 鼠标悬停/离开控制自动播放myChart.on('mouseover', () => stopAutoShowTooltip());myChart.on('mouseout', () => startAutoShowTooltip(myChart, option.xAxis.data.length));// 返回fetchData函数以便全局刷新调用return fetchData;}// 初始化图表并获取各自的刷新函数const refreshFunctions = [];const capacityRefresh = initCapacityChart();if (capacityRefresh) refreshFunctions.push(capacityRefresh);// 设置全局定时刷新function startAutoRefresh() {stopAutoRefresh(); // 防止重复启动refreshTimer = setInterval(() => {refreshFunctions.forEach(fn => fn());}, REFRESH_INTERVAL);}function stopAutoRefresh() {if (refreshTimer) clearInterval(refreshTimer);}// 启动自动刷新startAutoRefresh();// 当页面失去焦点时停止刷新,获得焦点时重新开始document.addEventListener('visibilitychange', function () {if (document.hidden) {stopAutoRefresh();} else {startAutoRefresh();}});
});
④图表数据获取
直接使用php查询需要获取的数据,并返回,使用switch case进行条件查询,满足多个图表查询数据问题
<?php
// 设置响应头为 JSON 格式
header("Content-Type: application/json");// 引入数据库连接函数
require_once '../get_db_conn.php';
$conn = db_connect();
mysqli_set_charset($conn, 'utf8');
date_default_timezone_set('Asia/Shanghai');// 获取请求类型参数
$type = isset($_GET['type']) ? $_GET['type'] : '';
//获取当前页面的线别
$linebody_sql = "select linebody from linebody_board_front where id = 1";
$linebody_result = mysqli_query($conn, $linebody_sql);
while ($row = mysqli_fetch_assoc($linebody_result)) {$linebody = $row['linebody'];
}
//查找当前的工单
$sql_wip = "SELECT wc.wip_entity_name AS wip_entity_nameFROM wip_capacity wcWHERE wc.linebody = '" . $linebody . "'ORDER BY wc.creation_date ASClimit 1
";
$result_wip = mysqli_query($conn, $sql_wip);
if ($row = mysqli_fetch_assoc($result_wip)) {$wip_entity_name = $row['wip_entity_name'];
} else {$wip_entity_name = '';
}
// 获取今天的开始和结束时间戳(查询的是开始时间在今天内的数据)
$todayStart = strtotime(date("Y-m-d")); // 今天 00:00:00 的时间戳(不包含时区)
$todayEnd = $todayStart + 86400; // 明天 00:00:00 的时间戳(不包含)
switch ($type) {case 'capacity': // 计划产能与实际达成$sql = "SELECT * FROM wip_capacity WHERE linebody = '" . $linebody . "' AND startTime >= '" . $todayStart . "' AND startTime < '" . $todayEnd . "' order by startTime ASC";$result = mysqli_query($conn, $sql);$data = [];// echo json_encode(['sql' => $sql]);if ($result && mysqli_num_rows($result) > 0) {while ($row = mysqli_fetch_assoc($result)) {$data[] = ['time_slot' => date("H", $row['startTime']) . '-' . date("H", $row['endTime']),'plan_qty' => (int)$row['plan_qty'],'real_qty' => (int)$row['real_qty']];}}echo json_encode($data);break;...... default:echo json_encode(['error' => '未知的请求类型']);
}
$conn->close();