本项目开发了一个基于 Electron 框架的二维散点图可视化工具,用于呈现和分析数据点的空间分布特征与相互关系。整个应用使用纯 JavaScript 构建,通过 Canvas API 实现图形绘制,具备高效渲染能力。支持多种数据生成模式,包括正态分布、均匀分布及完全随机分布,并集成了丰富的交互功能,如鼠标拖拽平移、滚轮缩放、悬停信息提示以及可调节的数据点尺寸等。在架构设计上,遵循 Electron 的主进程与渲染进程分离机制,利用 contextBridge 安全地暴露必要接口,保障了系统的安全性与运行效率。
应用采用标准的 Electron 主从进程模型:主进程负责管理窗口生命周期与系统级事件;渲染进程专注于界面展示与用户操作响应。通过 preload 脚本桥接两个环境,利用 contextBridge 向前端安全注入所需 API,避免直接暴露 Node.js 接口,提升安全性。该结构有效隔离了 UI 线程与系统资源访问,确保稳定性和性能表现。
内置多种数据分布算法,能够按需生成符合特定统计规律的数据集。其中正态分布采用 Box-Muller 变换方法生成高质量高斯随机数,保证数据自然聚集特性。同时构建了坐标映射系统,实现原始数据空间到画布像素坐标的精准转换,支持动态缩放和平移后的坐标还原。
提供完整的视图操控体验:通过鼠标按下拖动实现画布平移;使用滚轮进行缩放操作,并自动保持当前视野中心点不变;当鼠标悬停于某数据点时,显示其具体数值信息;此外还支持通过滑块实时调整所有数据点的显示大小,增强可视化的灵活性与可读性。
借助 Canvas 提供的低层级绘图能力,直接操作像素进行高效绘制。引入视图裁剪机制,仅渲染当前可见区域内的数据点,显著减少不必要的绘制开销。颜色方案根据数据点位置动态计算,提升视觉区分度。坐标轴与刻度标签也根据当前缩放级别智能调整密度与格式,确保不同尺度下均有良好可读性。
整体采用响应式设计原则,适配各种屏幕分辨率与窗口尺寸变化。控制面板布局清晰,集中管理数据生成参数与视图操作按钮,操作直观。实时更新并展示当前数据集的基本统计信息(如总数、范围等),帮助用户快速了解数据状态。所有交互操作均配有明确的状态反馈,提升使用流畅度与友好性。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>97-scatter-plot</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<!-- 应用头部 -->
<header class="app-header">
<h1>散点图数据可视化</h1>
</header>
<!-- 控制面板 -->
<div class="control-panel">
<div class="control-group">
<label for="data-count">数据点数量:</label>
<input type="number" id="data-count" min="10" max="1000" value="200">
</div>
<div class="control-group">
<label for="distribution">分布类型:</label>
<select id="distribution">
<option value="normal">正态分布</option>
<option value="uniform">均匀分布</option>
<option value="random">随机分布</option>
</select>
</div>
<div class="control-group">
<label for="point-size">点大小:</label>
<input type="range" id="point-size" min="5" max="20" value="10">
<span id="point-size-value">10</span>
</div>
<div class="button-group">
<button id="generate-btn">生成数据</button>
<button id="reset-btn">重置视图</button>
</div>
</div>
<!-- 散点图容器 -->
主进程代码实现如下:
const { app, BrowserWindow } = require('electron');
const path = require('path');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1000,
height: 700,
webPreferences: {
preload: path.join(__dirname, 'src', 'preload.js'),
nodeIntegration: false,
contextIsolation: true
},
title: '散点图'
});
mainWindow.loadFile(path.join(__dirname, 'src', 'index.html'));
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
散点图核心渲染功能由以下类实现:
/**
* 散点图渲染器类
*/
class ScatterPlotRenderer {
constructor() {
this.canvas = document.getElementById('scatter-chart');
this.ctx = this.canvas.getContext('2d');
this.data = [];
this.transform = { x: 0, y: 0, scale: 1 };
// 初始化其他配置和状态
}
/**
* 生成符合正态分布的数据点
*/
generateNormalData() {
const data = [];
const mean = 50;
const stdDev = 15;
for (let i = 0; i < this.config.dataCount; i++) {
const x = this.gaussianRandom(mean, stdDev);
const y = this.gaussianRandom(mean, stdDev);
data.push({
x: Math.max(0, Math.min(100, x)),
y: Math.max(0, Math.min(100, y))
});
}
return data;
}
/**
* 使用Box-Muller变换生成高斯分布随机数
*/
gaussianRandom(mean, stdDev) {
let u = 0, v = 0;
while(u === 0) u = Math.random();
while(v === 0) v = Math.random();
const z = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2 * Math.PI * v);
return mean + z * stdDev;
}
}
// 将数据坐标转换为画布坐标
dataToCanvas(dataX, dataY) {
const xRange = this.xRange.max - this.xRange.min;
const yRange = this.yRange.max - this.yRange.min;
// 计算在画布上的原始位置(考虑内边距)
const canvasX = this.config.padding +
((dataX - this.xRange.min) / xRange) * (this.canvas.width - 2 * this.config.padding);
const canvasY = this.canvas.height - this.config.padding -
((dataY - this.yRange.min) / yRange) * (this.canvas.height - 2 * this.config.padding);
// 应用当前的缩放与平移变换
return {
x: canvasX * this.transform.scale + this.transform.x,
y: canvasY * this.transform.scale + this.transform.y
};
}
/**
* 渲染散点图的主要方法
*/
render() {
// 清除整个画布内容
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 保存当前绘图状态,并应用变换矩阵
this.ctx.save();
this.ctx.translate(this.transform.x, this.transform.y);
this.ctx.scale(this.transform.scale, this.transform.scale);
// 绘制X轴和Y轴
this.drawAxes();
// 绘制所有数据点
this.drawPoints();
// 恢复之前保存的状态,避免影响其他绘制操作
this.ctx.restore();
}
/**
* 处理鼠标滚轮事件以实现缩放功能
*/
handleWheel(e) {
e.preventDefault();
// 根据滚轮方向确定缩放比例
const scaleFactor = e.deltaY > 0 ? 0.9 : 1.1;
const newScale = Math.max(0.1, Math.min(5, this.transform.scale * scaleFactor));
// 获取鼠标相对于画布的位置
const rect = this.canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
// 调整平移量,使缩放围绕鼠标位置进行
const scaleRatio = newScale / this.transform.scale;
this.transform.x = mouseX - (mouseX - this.transform.x) * scaleRatio;
this.transform.y = mouseY - (mouseY - this.transform.y) * scaleRatio;
this.transform.scale = newScale;
// 重新渲染视图
this.render();
}
安装项目所需依赖:
npm install
启动应用程序:
npm start
应用提供简洁直观的操作界面,用户可通过控制面板调节以下参数:
控制散点图中数据点的总数由“数据点数量”参数决定,用户可根据需要调节显示的数据规模。
“分布类型”用于设定数据点的排列模式,支持多种分布方式,如正态分布、均匀分布以及随机分布等。
通过“点大小”选项可以自定义散点图中各个数据点的视觉尺寸,提升图表可读性或突出重点区域。
点击“生成数据按钮”,系统将根据当前设置重新创建一组符合配置的散点数据。
若需恢复初始状态,可使用“重置视图按钮”将图表视角与参数设置还原至默认值。
用户可通过鼠标操作实现对散点图的交互式浏览:
应用底部区域展示当前散点图的关键统计信息,包括总数据点数、X轴与Y轴的数据范围,便于用户快速掌握整体数据分布特征。
操作系统:Windows 10 或 Windows 11;内存建议8GB以上;磁盘预留至少20GB可用空间。
需安装以下开发工具:
访问Electron鸿蒙官方仓库,下载Electron 34或更高版本的Release发布包(格式为.zip)。
将压缩包解压至项目根目录,并确保以下路径中包含必要的核心.so库文件:
electron/libs/arm64-v8a/
按照如下结构组织Electron应用源码:
web_engine/src/main/resources/resfile/resources/app/
├── main.js
├── package.json
└── src/
├── index.html
├── preload.js
├── renderer.js
└── style.css
打开项目:在DevEco Studio中加载 ohos_hap 目录作为工程主体。
配置签名:进入菜单 File → Project Structure → Signing Configs,可选择自动生成调试签名或导入已有签名文件。
连接设备:启用目标鸿蒙设备的开发者模式及USB调试功能,并通过Type-C数据线连接至主机。
编译运行:点击运行按钮或使用快捷键 Shift+F10 启动应用部署流程。
| 平台 | 适配策略 | 特殊处理 |
|---|---|---|
| Windows | 采用标准Electron运行环境 | 无需额外配置 |
| macOS | 采用标准Electron运行环境 | 保留Dock图标激活逻辑以维持用户体验一致性 |
| Linux | 采用标准Electron运行环境 | 确保系统依赖库完整安装 |
| 鸿蒙PC | 借助Electron鸿蒙适配层运行 | 关闭硬件加速功能,使用特定规定的目录结构 |
在DevEco Studio的Log面板中搜索关键词“Electron”,可精准定位应用运行日志及相关错误信息。
"SysCap不匹配"错误:检查 module.json5 文件中的 reqSysCapabilities 字段,仅保留实际所需的系统能力声明。
"找不到.so文件"错误:验证 arm64-v8a 目录下四个核心动态库文件是否齐全。
窗口不显示:在 main.js 文件中添加 app.disableHardwareAcceleration() 语句以禁用硬件加速。
动画卡顿:优化CSS动画逻辑,减少复杂效果,降低页面重绘频率以提升性能表现。
扫码加好友,拉您进群



收藏
