在现代网页设计中,动态图表的实现越来越受到重视。SVG(Scalable Vector Graphics)作为一种基于XML的图形格式,因其可伸缩性和交互性而成为动态图表绘制的首选技术。本文将介绍如何利用JavaScript和DOM Level 3标准动态地在网页上绘制SVG图表,包括对图表参数的动态修改和图表渲染的详细过程。
首先,需要了解SVG图表的背景。SVG图表在不同的浏览器上可能存在兼容性问题。例如,某些SVG示例在Chrome和Opera浏览器中可以正常工作,但在Firefox中却无法显示。这可能是由于Firefox和Chrome在处理SVG时存在一些限制,例如不支持修改根元素,只支持修改子元素。然而,Opera浏览器则支持JavaScript动态地添加大量元素。
在实现动态SVG图表时,通常会创建一个包含表单的HTML页面。用户可以通过这个表单输入图表的参数,如函数表达式、坐标轴范围等。页面分为左右两个框架,左侧框架用于输入参数,右侧框架用于显示图表。左侧框架中的JavaScript代码在验证用户输入后,会将参数提交到右侧框架的表单中。然后,右侧框架的JavaScript代码会根据提交的参数动态地渲染图表。
在渲染图表之前,需要将XY坐标系转换为SVG坐标系。SVG坐标系的原点位于屏幕的左上角,而XY坐标系的原点通常位于屏幕的中心。因此,需要对图表进行适当的平移。例如,可以将图表的Y轴向上平移25像素,X轴向左平移50像素。所有的图形元素都使用白色填充,因为SVG主要由线条和形状组成。
function yCoordinateToScreen(y, minY, maxY) {
var ySpace = yMinCoord - yMaxCoord;
var yCoords = maxY - minY;
var svgIndex = (y - minY) * ySpace / yCoords;
return yMinCoord - svgIndex;
}
在渲染图表的过程中,首先需要创建一个SVG文档,并获取图表的根元素。然后,可以通过JavaScript代码动态地创建和修改SVG元素,如线条、形状等。例如,可以通过以下代码创建Y轴的刻度:
var tick = svgDoc.createElementNS(svgns, "line");
tick.setAttributeNS(svgns, "id", "yTickRight" + i);
tick.setAttributeNS(svgns, "x1", xMaxCoord + 4);
tick.setAttributeNS(svgns, "y1", yPos);
tick.setAttributeNS(svgns, "x2", xMaxCoord);
tick.setAttributeNS(svgns, "y2", yPos);
tick.setAttributeNS(svgns, "stroke-width", 2);
tick.setAttributeNS(svgns, "stroke", "black");
svgRoot.appendChild(tick);
接下来,需要根据用户提交的参数动态地渲染图表。对于二次函数,可以使用路径(path)元素来绘制。首先,需要计算二次函数在X轴范围内的Y值,并将其转换为SVG坐标系中的坐标。然后,可以通过以下代码创建路径元素,并将其添加到SVG文档中:
var y_val = y2(xMin);
var xScreenCoord = 0;
var yScreenCoord = 0;
var data = "";
if (y_val <= yMax && y_val >= yMin) {
xScreenCoord = xCoordinateToScreen(xMin, xMin, xMax);
yScreenCoord = yCoordinateToScreen(y_val, yMin, yMax);
data = "M" + xScreenCoord + "," + yScreenCoord + "Q";
}
for (var j = xMin + 1; j <= xMax; j++) {
y_val = y2(j);
if (y_val <= yMax && y_val >= yMin) {
xScreenCoord = xCoordinateToScreen(j, xMin, xMax);
yScreenCoord = yCoordinateToScreen(y_val, yMin, yMax);
if (data == "") {
data = "M" + xScreenCoord + "," + yScreenCoord + "Q";
} else {
data += xScreenCoord + "," + yScreenCoord + " ";
}
}
}
drawing3.setAttributeNS(svgns, "d", data);
drawing3.setAttributeNS(svgns, "stroke-width", 1);
drawing3.setAttributeNS(svgns, "stroke", "#00F");
drawing3.setAttributeNS(svgns, "fill", "#FFF");
svgRoot.appendChild(drawing3);