前段时间因项目需要实现一个能直观的表达出商品流向的功能。当初考虑了,SVG和VML以及生成图片来显示,因为系统一般在IE下使用,最后采用了VML实现,下面是实现后的几张贴图。
由于时间比较仓促只实现了基本功能没有细化,看起来比较粗糙。
下面主要简述下实现的思路及主要代码,废话不多说代码贴上。
线及长方形的显示主要是由几个DTO来描述:
//矩形DTO
public class RectangleDTO {
private double left;//矩形图左起点
private double top;//矩形图顶点
private double width;//矩形宽度
private String enterpriseName;//图形名称
private String rectangleColor;//矩形底色
private String characterColor;//字体颜色
private double lineX;//从矩形图引出线的X坐标
private double lineY;//从矩形图引出线的Y坐标
public double getLeft() {
return left;
}
public void setLeft(double left) {
this.left = left;
}
public double getTop() {
return top;
}
public void setTop(double top) {
this.top = top;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public String getEnterpriseName() {
return enterpriseName;
}
public void setEnterpriseName(String enterpriseName) {
this.enterpriseName = enterpriseName;
}
public String getRectangleColor() {
return rectangleColor;
}
public void setRectangleColor(String rectangleColor) {
this.rectangleColor = rectangleColor;
}
public String getCharacterColor() {
return characterColor;
}
public void setCharacterColor(String characterColor) {
this.characterColor = characterColor;
}
public double getLineX() {
return lineX;
}
public void setLineX(double lineX) {
this.lineX = lineX;
}
public double getLineY() {
return lineY;
}
public void setLineY(double lineY) {
this.lineY = lineY;
}
}
//细化下矩形的点,为线的起始点做准备
public class RectangleAllDTO extends RectangleDTO{
private double leftX;//矩形框左中点X坐标
private double leftY;//矩形框左中点Y坐标
private double rightX;//矩形框右中点X坐标
private double rightY;//矩形框右中点Y坐标
public double getLeftX() {
return leftX;
}
public void setLeftX(double leftX) {
this.leftX = leftX;
}
public double getLeftY() {
return leftY;
}
public void setLeftY(double leftY) {
this.leftY = leftY;
}
public double getRightX() {
return rightX;
}
public void setRightX(double rightX) {
this.rightX = rightX;
}
public double getRightY() {
return rightY;
}
public void setRightY(double rightY) {
this.rightY = rightY;
}
}
//连线的DTO
public class LineDTO {
private double startX;//起点X坐标
private double startY;//起点Y坐标
private double endX;//终点X坐标
private double endY;//终点Y坐标
private double controlX;//为绘曲线的控制点X坐标
private double controlY;//为绘曲线的控制点Y坐标
private double contentLeft;//内容文字左起点
private double contentTop;//内容文字顶点
private String content;//内容文字
private double contentWidth;//文字宽度
private double contentHeight;//文字高度
private String lineColor;//曲线颜色
private List contentList = new ArrayList();//文字内容列表
public void addContent(LineContentDTO object){
this.contentList.add(object);
}
public double getStartX() {
return startX;
}
public void setStartX(double startX) {
this.startX = startX;
}
public double getStartY() {
return startY;
}
public void setStartY(double startY) {
this.startY = startY;
}
public double getEndX() {
return endX;
}
public void setEndX(double endX) {
this.endX = endX;
}
public double getEndY() {
return endY;
}
public void setEndY(double endY) {
this.endY = endY;
}
public double getControlX() {
return controlX;
}
public void setControlX(double controlX) {
this.controlX = controlX;
}
public double getControlY() {
return controlY;
}
public void setControlY(double controlY) {
this.controlY = controlY;
}
public double getContentLeft() {
return contentLeft;
}
public void setContentLeft(double contentLeft) {
this.contentLeft = contentLeft;
}
public double getContentTop() {
return contentTop;
}
public void setContentTop(double contentTop) {
this.contentTop = contentTop;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public double getContentWidth() {
return contentWidth;
}
public void setContentWidth(double contentWidth) {
this.contentWidth = contentWidth;
}
public String getLineColor() {
return lineColor;
}
public void setLineColor(String lineColor) {
this.lineColor = lineColor;
}
public List getContentList() {
return contentList;
}
public void setContentList(List contentList) {
this.contentList = contentList;
}
public double getContentHeight() {
return contentHeight;
}
public void setContentHeight(double contentHeight) {
this.contentHeight = contentHeight;
}
}
//线上文字的DTO
public class LineContentDTO {
private double left;//文字内容左起点
private double top; //文字内容顶点
private double width;//文字内容在页面上所占宽度
private String content;//文字具体内容
public double getLeft() {
return left;
}
public void setLeft(double left) {
this.left = left;
}
public double getTop() {
return top;
}
public void setTop(double top) {
this.top = top;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
页面先生成矩形然后在生成连线,矩形的位置和连线的起始点根据自己的业务需求计算出来,这里就不在叙述。页面显示主要代码:
<div id="Graph_layer" style="position:absolute;z-index:1; left: 30px; top: 0px;">
<#list rectangleList as rectangle>
<v:RoundRect id="_x0000_s00201"
style="position:absolute;left:${rectangle.left?string('#.##')}px;top:${rectangle.top?string('#.##')}px;width:${rectangle.width?string('#.##')}px;height:20px;z-index:1"
fillcolor="${rectangle.rectangleColor}" strokeweight="1px" strokecolor="#5E80A4"
arcsize="0.1">
<v:shadow on="T" type="single" color="#b3b3b3" offset="3px,3px"/>
</v:RoundRect>
<v:shape inset="0px,0px,0px,0px" id="_x0000_s1025"
style="position:absolute;left:${rectangle.left?string('#.##')}px;top:${rectangle.top?string('#.##')}px;width:${rectangle.width?string('#.##')}px;height:30px;z-index:1;text-align:center">
<v:textbox><!-- <a οnclick="forward('${rectangle.url}')" href="#" title="点击查看详细信息">--><span
class="nameStyle"
style="color:${rectangle.characterColor}">${rectangle.enterpriseName}</span></a></v:textbox>
</v:shape>
</#list>
<#list lineList as line>
<v:rect id="_x0000_s1044"
style="position:absolute;left:${(line.startX-3)?string('#.##')}px;top:${(line.startY-3)?string('#.##')}px;width:6px;height:6px;z-index:1"
filled="f" strokecolor="#436589"></v:rect>
<v:rect id="_x0000_s1044"
style="position:absolute;left:${(line.endX-3)?string('#.##')}px;top:${(line.endY-3)?string('#.##')}px;width:6px;height:6px;z-index:1"
filled="f" strokecolor="#436589"></v:rect>
<v:curve style="position:absolute;left:0px;top:0px;z-index:1"
from="${line.startX?string('#.##')}px,${line.startY?string('#.##')}px"
to="${line.endX?string('#.##')}px,${line.endY?string('#.##')}px" filled="f"
control1="${line.controlX?string('#.##')}px,${line.controlY?string('#.##')}px"
οnclick="javascript:controlCase(this)"
strokecolor="${line.lineColor}" strokeweight="1.0px">
<v:stroke opacity="1" startarrow="none" endarrow="block" endarrowwidth="medium" endarrowlength="long"/>
</v:curve>
<v:rect id="_x0000_s1040"
style="position:absolute;left:${line.contentLeft?string('#.##')}px;top:${line.contentTop?string('#.##')}px;width:${line.contentWidth?string('#.##')}px;height:${line.contentHeight?string('#.##')}px;z-index:1"
fillcolor="#FFFFFF" stroked="f">
<v:fill type="frame" opacity="0.0"/>
</v:rect>
<v:shape inset="0px,0px,0px,0px" id="_x0000_s1025"
style="position:absolute;left:${line.contentLeft?string('#.##')}px;top:${line.contentTop?string('#.##')}px;width:${line.contentWidth?string('#.##')}px;height:${line.contentHeight?string('#.##')}px;z-index:1;text-align:left">
<v:textbox inset="0px,0px,0px,0px"><span class="lineContentStyle">${line.content}</span></v:textbox>
</v:shape>
</#list>
</div>
上面的是生成图形主要VML代码。在实现的过程中主要是参考了两个教程,下面也贴出来,喜欢的朋友拿去研究研究。
PS:在实现的过程中想把显示的数字放置到线的中点处,探究发现VML中的曲线是贝塞尔曲线,关于更多的贝塞尔曲线可以参考维基百科。