自动选择SVG和VML的WEB页面

来源:互联网 发布:孤岛惊魂3视频优化 编辑:程序博客网 时间:2024/05/22 10:54
 
自动选择SVG和VML的WEB页面
问题
       在WEB上使用二维图形编程的人员现在面临者一个两难的选择,是使用SVG,还是VML?二者的功能相似,可以满足大多数WEB二维图形应用的需求,但目前的情况是:VML只能在IE中使用,SVG被firefox,opera等浏览器的最新版本支持,并且是W3C制定的开放标准,但目前IE不内置支持SVG,只能通过ADOBE的SVG插件显示。
对于有特定用户的应用,可能选择哪一种技术都可以,软件提供方可以要求用户安装和配置所需的环境。但对于面向INTERNET用户的应用,例如网上地图等,这个问题就比较明显了。IE无疑是最广泛使用的浏览器,而且大多数用户在不了解网站内容的情况下,不会选择下载并安装一个4M多的SVG插件。而在技术上,SVG无疑前景更光明,而且被其它浏览器支持,可以被非WINDOWS平台用户使用。
      
思路
能否通过用户浏览器的类型,自动在SVG和VML之间切换,以在浏览器上显示同样(或基本相似)的图形?(下面提到的SVG都是SVG1.1标准)
 
解决方法
1, 根据用户浏览器情况,设置显示标志
 
//设置使用SVG显示标志,缺省为使用
var useSVG = true;
 
//如果为IE则使用VML
if (navigator.appName == "Microsoft Internet Explorer")
              useSVG = false;
//如果为其它浏览器,则使用SVG,这里用Opera
       if (navigator.userAgent.search("Opera")>=0)
              useSVG = true;
 
2, 在HTML初始化时,加载SVG或VML对象
if(useSVG)
              {
                     var elem = document.createElement("embed");
                 
                         elem.id = "svgCanvas";
                         elem.width = 500;
                         elem.height = 500;
                         elem.name = "svgCanvas";
                         elem.src = "canvas.svg";
                         elem.wmode = "transparent";
                         elem.type = "image/svg+xml";
                        
                         document.body.insertBefore(elem,null);
              }
              else
              {
                     var elem = document.createElement("v:group");
                        
                         elem.id = "vmlCanvas";
                         elem.style.width = 500 + "px";
                         elem.style.height = 500 + "px";
                         elem.coordsize = "200,200";
                                          
                         document.body.insertBefore(elem,null);
            }
       之后,我们就可以分别在SVG或VML画布上进行操作了。当然最好是定义一个与显示无关的图形对象。
 
3, 图形对象,此处为一个简单的圆
function Bubble(id, cx, cy, r, stroke, fill)
       {
              this.id = id;
              this.cx   = cx;
              this.cy = cy;
              this.r = r;
      
              this.stroke = stroke;
              this.fill = fill;
                           
              this.draw = draw;
              this.move = move;
       }
 
其显示和移动实现为:
function draw()
       {
              if(useSVG)
              {
                     //alert("svg");
                    
                     var svgDocument = GetSvgDocument();
                     if(svgDocument == null)
                            return;
                           
                     var elem = svgDocument.createElementNS(svgns, "circle" );
                     elem.setAttributeNS(null, "id", this.id);
                     elem.setAttributeNS(null, "cx", this.cx);
                     elem.setAttributeNS(null, "cy", this.cy);
                     elem.setAttributeNS(null, "r", this.r);
                     elem.setAttributeNS(null,"stroke",this.stroke);
                     elem.setAttributeNS(null,"fill",this.fill);
                                         
                     var svgCanvas = GetSvgCanvas();
                     if(svgCanvas == null)
                            return;
                           
                     svgCanvas.appendChild(elem);
              }
              else
              {
                     //alert("vml");
                    
                     var elem = document.createElement("v:oval");
                         with (elem.style)
                         {
                                position="absolute";
                                top=this.cy - this.r;
                                left=this.cx - this.r;
                                width=parseInt(this.r*2);
                                height=parseInt(this.r*2);
                         }
                         elem.coordorigin = "0,0";
                        
                         elem.strokecolor=this.stroke;
                         elem.FillColor = this.fill;
                        
                         vmlCanvas.insertBefore(elem,null);
            }
             
       }
      
       function move(x, y)
       {
               this.cx = x;
               this.cy = y;
       }
 
4, 使用
var bubble1 = new Bubble("b1", 100, 100, 30, "purple", "green");
              bubble1.draw();
             
              var bubble2 = new Bubble("b2", 30, 20, 20, "red", "yellow");
              bubble2.draw();    
VML显示:
 
SVG显示
5,注意事项:
l         通过上面的图可以看出,尽管比较相似,但还是有所不同,例如圆的边线由于使用的是缺省属性,SVG和VML使用的笔画粗细是不同。因此要显示完全相同的图形要付出很大的工作量。
l         尽管SVG和VML在大多数情况下可以互相替换,但还是有一些对方不支持的特性和属性。例如SVG中的动画(animate)等,这些要在VML-SVG混合时尽量避免使用,实在不行就只能使用脚本模拟实现了。
l         SVG为独立的嵌入对象,因此要使用embedded列表取得,而VML可以直接使用HTML的文档对象。在SVG动态嵌入时,要判断加载情况,在加载完成后才可以操作。
 
在SVG中加载事件中通知HTML
function OnLoadEvent(evt)
       {
              window.parent.svgLoadFlag = true;
       }
 
在HTML初始化时,等待SVG加载完成标志
if(useSVG)
              {
                     //Wait svg load event
                     if ( svgLoadFlag == false )
                         {
                                setTimeout("renderObjects()",100);
                               return;
                         } 
              }
 
l         如果使用交互事件,例如鼠标操作等,SVG和VML的事件对象结构是不同的,传递方式也不相同,应分别处理,不过一般在得到事件对象的属性,例如坐标位置,产生事件对象ID后,就可以使用相同的处理函数了。例如:
//SVG的事件处理
function svgClick(evt)
       {
              var choiceId = evt.target.getAttributeNS(null,"id");
              selectChoice(choiceId);
       }
      
//VML事件处理
       function vmlClick()
       {
var choiceId = event.srcElement.name;
              selectChoice(choiceId);
}
因此在VML/SVG混合编程时,采用MODEL-VIEW-CONTROL方式是比较好的一种模式。
 
附:SVG和VML元素对应表(不全)
名称
SVG
VML
描述
矩形
rect
rect
 
圆角矩形
 
roundrect
SVG中通过rect属性实现
直线
line
line
 
circle
oval
 
椭圆
ellipse
oval
 
折线
polyline
polyline
 
多边形
polygon
shape
 
曲线
 
arc
SVG中可以使用circle或path实现
路径
path
path
 
文本
text
textbox
 
文本段
tpan
 
 
路径文本
textPath
textPath
 
 
 
 
 
标题
title
 
 
描述
desc
 
 
 
 
 
 
group
group
 
预定义图形
defs
vmlframe
 
 
 
 
 
滤镜
filter
 
 
线性渐变
linearGradient
 
 
圆形渐变
radialGradient
 
 
图案
pattern
 
 
箭头
marker
 
在stroke的属性StartArrow和EndArrow实现
剪裁
clippath
 
 
遮盖
mask
 
 
链接
a
 
 
 
 
 
 
重用
use
vmlframe
 
图形
symbol
shape
 
光栅图像
image
image
 
 
 完整代码
HTML
<html xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<title>VML-SVG-DEMO</title>
<STYLE>
 v:* 
{ BEHAVIOR: url(#default#VML) }
</STYLE>
<script src="objects.js" language="JavaScript" type="text/javascript"></script>
<script src="initial.js" language="JavaScript" type="text/javascript"></script>
</head>

<body onload="init()"></body>
</html>

 

          SVG

 

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 200"  onload="OnLoadEvent(evt)">
<id="Canvas"></g>
<script type="text/ecmascript">
<![CDATA[
    
function OnLoadEvent(evt)
    

        window.parent.svgLoadFlag 
= true;
    }

]]
>
</script>
</svg>

 

初始化脚本

 

    //useSVG = true;    //you can also change this by hand

    
function renderObjects()
    
{
        
if(useSVG)
        
{
            
//Wait svg load event
            if ( svgLoadFlag == false )
                

                    setTimeout(
"renderObjects()",100);
                      
return;
                }
  
        }

        
        
//alert(svgLoadFlag);
        var bubble1 = new Bubble("b1"10010030"purple""green");
        bubble1.draw();
        
        
var bubble2 = new Bubble("b2"302020"red""yellow");
        bubble2.draw();    
    }

    
    
function init()
    
{
    
// Write svg embed object or vml group into html body
    //    
    //<embed width='500' height='500' name='svgCanvas' src='canvas.svg' wmode='transparent' type='image/svg+xml' />
    //<v:group id='vmlCanvas' style='WIDTH:500px;HEIGHT:500px;' coordsize = '200,200'/>;

        
if(useSVG)
        
{
            
var elem = document.createElement("embed");
            
                elem.id 
= "svgCanvas";
                elem.width 
= 500
                elem.height 
= 500
                elem.name 
= "svgCanvas";
                elem.src 
= "canvas.svg";
                elem.wmode 
= "transparent";
                elem.type 
= "image/svg+xml";
                
                document.body.insertBefore(elem,
null);
        }

        
else
        
{
            
var elem = document.createElement("v:group");
                
                elem.id 
= "vmlCanvas";
                elem.style.width 
= 500 + "px";
                elem.style.height 
= 500 + "px";
                elem.coordsize 
= "200,200";
                            
                document.body.insertBefore(elem,
null);
           }

           
           
//Create graphic object and draw
           renderObjects();
    }



    
    
    
    

 

对象脚本

 

    
    
var useSVG = true;
    
var svgLoadFlag = false;
    
    
if (navigator.appName == "Microsoft Internet Explorer"
        useSVG 
= false;
        
    
if (navigator.userAgent.search("Opera")>=0
        useSVG 
= true;
    
    
//alert(useSVG);
    
    
var svgns = "http://www.w3.org/2000/svg";
    
var xlinkNS = "http://www.w3.org/1999/xlink";
        
    
function GetSvgDocument()
    

        
return(document.embeds[0].getSVGDocument());
    }

    
function GetSvgCanvas()
    

        
return(document.embeds[0].getSVGDocument().getElementById("Canvas"));
    }

        
    
///
    ///  Bubble class
    ///
    function Bubble(id, cx, cy, r, stroke, fill)
    
{
        
this.id = id;
        
this.cx   = cx;
        
this.cy = cy;
        
this.r = r;
    
        
this.stroke = stroke;
        
this.fill = fill;
                
        
this.draw = draw;
        
this.move = move;
    }

    
    
function draw()
    
{
        
if(useSVG)
        
{
            
//alert("svg");
            
            
var svgDocument = GetSvgDocument();
            
if(svgDocument == null)
                
return;
                
            
var elem = svgDocument.createElementNS(svgns, "circle" );
            elem.setAttributeNS(
null"id"this.id);
            elem.setAttributeNS(
null"cx"this.cx);
            elem.setAttributeNS(
null"cy"this.cy);
            elem.setAttributeNS(
null"r"this.r);
            elem.setAttributeNS(
null,"stroke",this.stroke);
            elem.setAttributeNS(
null,"fill",this.fill);
                        
            
var svgCanvas = GetSvgCanvas();
            
if(svgCanvas == null)
                
return;
                
            svgCanvas.appendChild(elem);
        }

        
else
        
{
            
//alert("vml");
            
            
var elem = document.createElement("v:oval");
                
with (elem.style)
                

                    position
="absolute"
                    top
=this.cy - this.r; 
                    left
=this.cx - this.r; 
                    width
=parseInt(this.r*2); 
                    height
=parseInt(this.r*2);
                }

                elem.coordorigin 
= "0,0";
                
                elem.strokecolor
=this.stroke;
                elem.FillColor 
= this.fill;
                
                vmlCanvas.insertBefore(elem,
null);
           }

        
    }

    
    
function move(x, y)
    
{
            
this.cx = x;
            
this.cy = y;
    }
 
    
    
///
    ///  Bubble class finish
    ///