svg渲染_在SVG中渲染动态图

本文探讨了如何使用SVG动态渲染条形图、折线图和散点图,重点在于如何根据数据自动调整图形比例因子,确保无论数据如何变化,图形都能适配并清晰展示。通过示例代码,展示了如何计算比例因子和绘制图形,并提供了进一步改进图形的建议。
摘要由CSDN通过智能技术生成

svg渲染

这是我在英国Hursley UK测试和开发期间遇到的确切问题。 我已经编写了可以很好地在SVG中绘制条形图,折线图和散点图的代码。 但是我在每次测试中处理的数据都在几个数量级上变化。 在每张图上使用相同的比例是没有用的,因为许多图太小或太大,并且所有值要么在一个角上缩小,要么在页面上绘制。

我需要的是一种自动确定用于每组数据的最佳规模的方法。

注意:要查看本文中的SVG文件,您需要一个SVG查看器,您可以在参考资料中找到它(以及包含所有相关文件的.zip文件)。

一点高中数学

着眼于这个问题,我发现自动缩放图形的最佳方法是查看需要绘图的数据集,确定数据集中包含的最大值,然后使用该值作为其他所有值的比例值将被绘制。

通过一个有效的示例可以更好地说明我的技术。 假设您有一个生成三个值的测试:A,B和C。每次测试运行之后,您都需要将这些值绘制到条形图上,但是每次测试运行时,值的范围都会发生巨大变化。

从第一次测试运行开始,生成的值为:

  • A = 100
  • B = 50
  • C = 25

因此,对于此测试运行,A的读数最高,为100。第一个(也是最重要的)任务是计算图形的比例因子 。 这就是绘制每个值时值得多少个高度的像素。 通过将图形轴的高度除以数据中的最大值来获得比例因子。 因此,当我通过本例研究数学时,这一点将变得更加清楚。

  • 为了清楚起见,Y轴始终设置为1000像素高。 这只是使理解数学变得更加容易。
  • 数据集中的最大值是100(对于A)。
  • 对于此图。 比例因子将是: 1000/100 = 10
  • 因此,对于此条形图,每个值的高度都值得10像素。
  • 要获取每个条形的高度,请将比例因子乘以数据集值。 这意味着每个条的高度将为:
    图1.使用比例因子,最大值是100(对于A)
    使用比例因子,最大值为100(对于A)

现在,假设在下一次测试运行中生成了以下值:

  • A = 2000
  • B = 5000
  • C = 800

请记住,Y轴仍为1000像素高。 这次的最高值为B列,值为5000。因此缩放比例为1000/5000 = 0.2

所以这一次每个条的高度将是:

图2.使用比例因子,最大值是5000(对于B)
使用比例因子,最大值为5000(对于B)

如您所见,由于这些条的高度是相对于最大值计算的,因此这些条的高度不会超过1000个像素,并且最终不会绘制得太高。 正是这个缩放因子是SVG动态缩放的关键。 请记住,它是根据最大值计算的; 所有其他值将相应缩放。

既然我已经介绍了比例因子的关键概念,那么我将向您展示如何使用它。 以下示例实现是一个小型Java语言程序,该程序在命令行上采用一组值并以上述示例中所述的方式绘制SVG条形图。 尽管是用Java代码编写的,但重要的是数学。 如有必要,您只需看一下Java代码就可以用您希望的任何语言重写它。

除了只在本文中重现整个代码之外,我仅介绍要点。 我建议您下载示例(请参阅参考资料 ),并在具有行编号功能的编辑器中打开SVG_barchart.java文件。

首先,在第38-48行中确定传入值的最大值。

最重要的行是第51行,其中计算了Y轴比例因子:

清单1.计算Y轴比例因子
51.	YAxisScalingFactor = 1000/(double)largestNumber;

在第58和59行上创建了SVG输出文件。使用SVGout.write(-SVG-)将SVG写入该文件。 请注意,必须使用各种转义字符,例如\"作为双引号。这可能使SVG有时难以阅读,但是这是必需的,因为否则Java编译器会错误地解释它,并且代码将无法编译。另外,请注意每条SVG文本行均以\n开头-这使得在使用SVG查看器的“查看源代码”功能时,更易于阅读SVG。

第70-79行画出X和Y轴。 X轴是一条从[x = 0,y = 1000]到[x = 1000,y = 1000]的简单线,Y轴从[x = 0,y = 0]到[x = 0 ,y = 1000]。 这提供了一组简单的笛卡尔坐标轴。

线82和83在Y轴的顶部和中点画一条虚线。 这只是使图形更易于阅读。

在第86和第87行上,Y轴标记在顶部,而在中途标记。 请注意,您正在使用之前计算出的最大值来标记Y轴。

清单2.标记Y轴
86.	SVGout.write("\n <text style=\"fill:black; stroke:none\" 
	x=\"-10\" y=\"0\" >" + largestNumber + "</text>");
87.	SVGout.write("\n <text style=\"fill:black; stroke:none\" 
	x=\"-10\" y=\"500\" >" + (largestNumber/2) + "</text>");

请注意,这些值是动态的,因为它使用largestNumber值来标记轴。 如有必要,可以通过除以其他值来轻松添加额外的准则和标签。

条的实际绘制从第90行开始:

清单3.绘制条
90.// The graph is ready to be rendered with the values.
91.for(i=0;i<barChartValues.length;i++){
92.  
93. // Calculate the Y position. First work out how high the bar 
94. // will be by multiplying the value by the scaling factor.
94. // calculated earlier
95. double barHeight = 
96.    Integer.parseInt(barChartValues[i]) * YAxisScalingFactor;
97.		
98. System.out.println("Bar Height is =" + barHeight);
99.    
100. // You now have the height that the bar will be. Need to work 
101. // out now where to place the bar. With Y values running 
102. // positively down, and the Y-axis being 1000 pixels tall, 
103. // simply subtract the  bar height from 1000 to get the position
104. // of where to place the bar.
105. 
106. double YStart = 1000 - barHeight;
107.                
108. // Each of the bars is 100 pixels wide. So to space them out 
109. //(with a 10-pixel gap between them), multiply the readings position
110. // in the array by 110.
111.	 
112. double XPosition = (i*110);
113.    
114. // Generate some random numbers for your bar colours
115. int randomRed = random.nextInt(255);
116. int randomGreen = random.nextInt(255);
117. int randomBlue = random.nextInt(255);
118.    
119. // You now have all your values ready. Draw the rectangle. 
120. SVGout.write("\n<rect x=\""+XPosition+"\" y=\""+
121.  YStart+"\" width =\""+ 100 +"\" height=\""+barHeight+
122.  "\" style=\"fill:rgb("+randomRed+"
123.  ,"+randomGreen+","+randomBlue+");\" /> ");
124.    	                             
125.}

尝试自己下载并运行该绘图仪。 传递跨不同数量级的各种值,并查看图形如何随值变化和缩放。 图3显示了一些示例输出。

图3.示例动态生成的SVG条形图
样本动态生成的SVG条形图

折线图

到目前为止,我已经向您展示了如何动态缩放条形图。 但是,这些并不是唯一的图形类型。 某些形式的数据,尤其是诸如股价或地震数据之类的基于时间的数据,最好在线图中绘制。 您也可以使用类似于条形图的方法缩放线形图。

假设您正在监视数据库中的行数。 每30秒读取一次行数,并将其记录在数组中。 在测试运行结束时,您将获得一个包含10个值的数组:

10,20,30,50,90,25,45,60,70,10

再一次,您需要为每次测试运行计算比例因子。 但是,您不希望自己受到限制,以便仅在具有精确读数的情况下才能绘制图表。 这次,您将不得不在X轴和Y轴上缩放。

绘制折线图的最佳方法是使用称为折线的SVG元素。 折线将成对的值作为X和Y点,并在这些点之间绘制一条连接线。 例如:

<polyline points="0 0, 10 10, 20 20">

在[X = 0,Y = 0],[X = 10,Y = 10]和[X = 20,Y = 20]处绘制3点的线。 这些是您需要根据数据集进行缩放和计算的点。

和以前一样,提供了一个可运行的Java示例程序,该程序可以根据提供的数据缩放和渲染折线图(请参阅参考资料 )。

同样,我将只介绍代码的要点。

首先,计算X轴比例因子。 这取决于您渲染的读数数量,因此需要将X轴上的像素数量除以读数数量。 例如,如果您获取了50个读数,则X轴比例因子将为1000/50 =20。因此,每个读数均沿X轴以20像素的间隔绘制。 当读数作为数组传递时,您只需要将1000除以数组中的元素数即可。

清单4.计算X轴缩放因子
40. XAxisScalingFactor = 1000/(double)valuesToPlot.length;

第41-49行找到传入数组中的最大值。

第54-100行准备好输出文件并绘制X和Y轴,以便可以进行绘制。

Y轴比例因子是在104行上以与条形图示例中完全相同的方式计算的(请参见清单2 )。

第108到125行是渲染该行的位置:

清单5.绘制折线
108. // Render the line
109. SVGout.write("\n<polyline points=\"0 1000,");
110.    	    
111. for(i=0;i<valuesToPlot.length;i++){
112.    
113.  // Calculate the X position by determining which 
114.  //value in the array you are dealing with.
115.  XValue = ((i+1)*XAxisScalingFactor);
116.
117.  YValue = Integer.parseInt(valuesToPlot[i]);
118.  YValue = YValue*YAxisScalingFactor;
119.  YValue = 1000-YValue;
120.    
121.  // You now have your polyline point.
122.  SVGout.write(" " + XValue + " " + YValue +",\n");
123.                
124. }           	           
125. // Close off the polyline.
126. SVGout.write("\" style=\"stroke:red; stroke-width: 3; fill : 
127. none;\"/>");

在线109中,启动折线元素,并在轴的原点绘制一个初始点。

接下来,通过数组中的值开始工作。 首先,计算X值。 这是元素在数组中的位置乘以X轴缩放因子。 例如,如果您的数组中有50个元素,则X轴比例因子将为:

  • XAxisScalingFactor = 1000/(double)valuesToPlot.length;
  • XAxisScalingFactor = 1000/(double)50;
  • XAxisScalingFactor = 20

因此,每个值以20像素的间隔绘制,因此遍历数组:

  • 第一点:x = 20,<第一值>
  • 第二点:x = 40,<第二值>
  • 第三点:x = 60,<第三值>
  • ...
  • ...
  • 49点:x = 980,<49值>
  • 第50点:x = 1000,<第50个值>

请注意,您使用(i+1)是因为在数组中,第一个元素的计数器值为零; 如要从第一个元素开始,将添加1

接下来,计算Y值:

  1. 第117行从数组中提取值并将其转换为整数。
  2. 线118将其乘以Y轴比例因子以确定其位置。
  3. 最后,从1000中减去它。之所以这样做,是因为Y值在页面的正下方运行。 X轴以1000像素的Y高度水平绘制,因此,要确定此计算的Y位置在X轴上方的高度,请从1000中减去它。

现在您已经有了计算出的X和Y位置,因此可以将此点添加到多段线内联中。

处理完数组中的所有值后,将关闭折线并将样式应用于该线。

尝试运行示例,并以不同的数量级传递各种数字列表。 再次,您将看到图形如何根据传入的最大值进行缩放。此外,请尝试传入不同数量的值,例如10甚至1000。X轴将根据值的数量进行缩放传入。图4显示了一些示例输出。

图4.示例动态生成的SVG线图
样本动态生成的SVG线图

散点图

这里涵盖的图形的最终类型是散点图。 这些图非常适合在两个维度上变化的数据。 在这里,您将使用与前面的示例完全相同的方法,尽管这次您有一组要绘制的X和Y轴值。

在示例中,数据以(X-value),(Y-value)的形式传递。 例如,[1,1],[3,5],[50,2]和[10,34]。

我再次提供了一个Java示例程序,您可以下载该程序(请参阅参考资料 )。 这是代码。

第31-57行确定X值和Y值的最大值。

60-61行计算X和Y轴的比例因子。

67-119行画出了轴。 请注意,这一次您将在图形上绘制四个虚线指导线,并相应地对其进行标记。

第124-157行绘制数据:

清单6.计算并绘制散点图点
122. // The axis and the guide lines are ready; now draw the data.
123. SVGout.write("\n    <g style=\"fill:none; 
124. stroke:red; stroke-width:3\">");
125.
126. for(i=0;i<dataToPlot.length;i++){
127.                 
128.    // Get the value out of the array.
129.	String value = dataToPlot[i];
130.                
131.	// The data is in the form (X-Value),(Y-Value), so find
132.	// the comma and get the values on either side of it.
133.	index = value.indexOf (',');
134.	String X_Pos = value.substring(0,index);
135.	String Y_Pos = value.substring(index+1);
136.
137.	// Change them to numbers
138.	XValue = Integer.parseInt(X_Pos);
139.	YValue = Integer.parseInt(Y_Pos);
140.
141.	// Calculate the point's position by using the scaling 
142.	// factor calculated earlier
143.	XValue = XValue*XAxisScalingFactor;     
144.	YValue = YValue*YAxisScalingFactor;
145.	YValue = 1000-YValue;
146.
147.	// You now have your point. As it's a scatter plot, it 
148.	// would look nice with an X, so use the point to draw 
149	// a line from the top left to the bottom right, and from
150.	// the top right to the bottom left.
151. 
152.	SVGout.write("\n  <line x1=\""+ (int)(XValue-5) + 
153		"\" y1=\""+(int)(YValue+5)+ "\" x2=\""+(int)(XValue+5)+
154.	"\" y2=\""+(int)(YValue-5)+"\" />"); 
155.	SVGout.write("\n  <line x1=\""+ (int)(XValue+5) + 
156.	"\" y1=\""+(int)(YValue+5)+ "\" x2=\""+(int)(XValue-5)+
157.	"\" y2=\""+(int)(YValue-5)+"\" />");    
158.}

首先,为该组定义样式(第123行)。

然后,开始处理数据。 在第129行中,您将获得该值。

接下来,通过查找逗号分隔符(第133-135行)将X和Y值分离出来,并将这些值转换为数字(第138-139行)。

然后计算该点的位置(线143-145)。

现在可以绘制该点了。 这次不只是绘制单个点,而是尝试用X标记该点。这是绘制两条线的一种简单情况,一条线从左侧开始5个像素,向上方5个像素,从右侧开始5个像素,向下5个像素。 ,另一个从右5个像素开始,向上5个像素,向左5个像素,向下5个像素结束。 这将导致以计算点为中心的X。

下载并运行示例中包含的散点图绘图仪。

图5.示例动态生成的散点图
样本动态生成的散点图

进一步改进

为简单起见,并使代码尽可能易读,在此处显示的示例中,我使用了最少的Java代码并生成了SVG。 当然,您可以采用这些示例,并通过添加其他颜色,效果和信息来进一步改进它们。 样本中包括两个条形图绘图仪,其中一个绘制了如前所述的简单矩形(参见图3 )。 另一种稍微复杂些,并使用渐变和阴影,但是计算钢筋高度的方法保持不变。 图6显示了一个示例。

图6.改进的条形图
改进的条形图

您可以在图7中看到我自己的一个折线图的示例。 此图显示了我在其上进行测试的数据库中的消息数,这些消息数是随时间变化的。 我添加了徽标,阴影效果和测试运行的统计信息表。

图7.改进的SVG折线图
改进的SVG折线图

图8显示了我的一个散点图的示例。 在此测试运行期间,我想比较从数据库删除消息的性能时间。 一组数据基于使用JDBC进行操作,另一组数据基于使用准备好的语句。 同样,它具有徽标,阴影和统计信息表。

图8.改进的SVG散点图
改进的SVG散点图

这些图的完整SVG版本均包含在样本中。

摘要

本文通过示例演示了如何根据数据动态缩放SVG图。 通过这些技术以及示例代码,您现在可以呈现自己的图形,并根据自己的需求进行调整。


翻译自: https://www.ibm.com/developerworks/xml/library/x-svggrph/index.html

svg渲染

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值