本文介绍一种不依赖Canvas,而是通过操作DOM元素(如span标签)在网页中绘制几何图形的JavaScript方法。文章详细讲解了如何定义并渲染点、直线、折线、多边形及矩形,涵盖坐标计算、样式控制及闭合逻辑,为前端可视化提供轻量级实现思路。
JavaScript DOM绘图概述
关于使用JavaScript进行图形绘制的构思颇具趣味,因此进行了实际尝试。本系列文章旨在探讨如何使用JS绘制点、线和面等基础几何元素。
具体效果可参考示例:http://www.zhaojz.com.cn/demo/draw5.html
点的绘制实现
一、点的绘制
在此方案中,我们采用HTML的span标签来代表图形中的“点”。
具体实现代码如下:
// 绘制点函数,参数包含点的大小、颜色、坐标及标签;opts为一个配置对象
function drawPoint(opts){
document.write("<span id='"+opts.point[0]+""+opts.point[1]+"' style='display: inline-block; width: "+opts.pw+"px; height: "+opts.ph+"px; background-color: "+opts.color+"; position: absolute "+opts.point[0]+"px; top: "+opts.point[1]+"px;'>"+(opts.point[2]?("<div style='position: relative;'><span style='position: absolute; left: 5px; bottom: 1px; text-align: left; width: 100px;'>"+opts.point[2]+"</span></div>"):"")+"</span>");
}
该函数涉及的关键参数说明如下:
opts.pw:定义点的宽度
opts.ph:定义点的高度,通常与opts.pw保持一致
opts.color:定义点的背景颜色
opts.point:定义点的位置数组,其中point[0]为水平坐标,point[1]为垂直坐标,point[2]为可选的标签文本
注意:CSS中的position属性必须设置为absolute,以确保坐标定位准确。
直线的绘制算法
二、直线的绘制
直线在视觉上由无数个点组成,因此绘制直线的本质是在两个端点之间生成并渲染多个点。
具体实现代码如下:
// 绘制直线函数
// pstart:起点坐标
// pend:终点坐标
// opts:配置参数
function drawLine(pstart, pend, opts){
var ph = 1;
var pw = 1;
var color = "DarkRed";
if(opts){
color = opts.color ? opts.color: color;
}
var slope; // 斜率变量
var noSlope = false; // 标记是否无斜率
var hdist = pend[0] - pstart[0]; // 水平距离
var vdist = pend[1] - pstart[1]; // 垂直距离
if(hdist != 0){
slope = Math.abs(vdist/hdist); // 计算斜率
}else{
noSlope = true; // 当水平距离为0时,判定为无斜率(垂直线)
}
var gapp = pw > ph ? ph : pw; // 默认相邻点(像素点)间的间距
var diagonal = Math.sqrt(Math.pow(hdist,2) + Math.pow(vdist,2)); // 计算两点间直线距离(斜边)
var pn = parseInt(diagonal/gapp); // 计算两点间需要生成的点的数量
if(pn < 3){pn=pn*3+1}; // 若计算出的点数少于3个,则增加点数;加1是为了确保即使pn为0时也能至少生成一个点
var vgap = Math.abs(vdist)/pn; // 相邻两点间的垂直间距
var hgap = Math.abs(hdist)/pn; // 相邻两点间的水平间距
for(var i = 0; i< pn ; i++){
// 调用描点函数
// hgap:相邻点水平间距
// vgap:相邻点垂直间距
// hgap*i*(pend[0]<pstart[0]?-1:1)*(noSlope?0:1):计算相对于起点的水平偏移量
// vgap*i*(pend[1]<pstart[1]?-1:1):计算相对于起点的垂直偏移量
// (pend[0]<pstart[0]?-1:1):判断水平偏移方向
// (pend[1]<pstart[1]?-1:1):判断垂直偏移方向
// (noSlope?0:1):当为垂直线时,水平偏移量设为0
drawPoint({
pw: pw,
ph: ph,
color: color,
point: [(hgap*i*(pend[0]<pstart[0]?-1:1)*(noSlope?0:1)+pstart[0]),(vgap*i*(pend[1]<pstart[1]?-1:1)+pstart[1])]
});
}
}
折线与多边形绘制
基于直线绘制逻辑,可进一步扩展为折线和面的绘制:
折线绘制:
具体实现代码如下:
// 绘制折线函数
// ps:包含所有顶点坐标的一维数组
function drawPolyline(ps){
if(ps){
// 遍历数组绘制线段
for(var i = 0; i<ps.length-1; i++){
drawLine(ps[i], ps[i+1]);
}
// 绘制拐点(顶点)
for(var i = 0; i<ps.length; i++){
drawPoint({
pw: 3,
ph: 3,
color: 'RED',
point: ps[i]
});
}
}
}
多边形绘制:
具体实现代码如下:
// 绘制多边形函数
// ps:包含所有顶点坐标的一维数组
function drawPolygon(ps){
if(ps){
// 遍历数组绘制线段
for(var i = 0; i<ps.length-1; i++){
drawLine(ps[i], ps[i+1]);
}
// 实现图形闭合
if(ps.length > 2){
drawLine(ps[ps.length-1], ps[0])
}
// 绘制拐点(顶点)
for(var i = 0; i<ps.length; i++){
drawPoint({
pw: 3,
ph: 3,
color: 'RED',
point: ps[i]
});
}
}
}矩形:
矩形绘制示例
矩形绘制示例:
// 绘制矩形函数
// leftTop:左上角顶点坐标
// width:矩形宽度
// high:矩形高度
function drawRectangle(leftTop, width, high){
drawPolygon([
leftTop,
[leftTop[0], leftTop[1]+high],
[leftTop[0]+width, leftTop[1]+high],
[leftTop[0]+width, leftTop[1]]
]);
// 填充功能(注释状态)
// document.write("<span style='height: "+(high-1)+"px; width: "+(width-1)+"px; background-color: "+"Green"+"; position: absolute; left:"+(leftTop[0]+1)+"px; top: "+(leftTop[1]+1)+"'></span>");
}
通过JavaScript操作DOM元素实现图形绘制展现了前端开发的灵活性,值得深入研究与实践。