1. 程式人生 > >SVG DOM常用屬性和方法介紹(1)

SVG DOM常用屬性和方法介紹(1)

12.2 SVG DOM常用屬性和方法介紹

將以Adobe SVG Viewer提供的屬性和方法為準,因為不同解析器對JavaScript以及相關的屬性和方法支援的程度不同,有些方法和屬性是某個解析器所特有的。SVG支援DOM2標準。

12.2.1 文件初始化相關

— evt屬性

evt表示事件本身,可以通過evt獲取與當前事件相關的資訊,使用者可以在script中定義響應函式,進行相應的處理。它與普通JavaScript指令碼中的event基本相同,只不過在普通JavaScript的指令碼中簡寫成“e”。

— ownerDocument屬性

通過引用該屬性獲得當前SVG檔案的文件物件,也就是得到SVG的DOM結構。

使用舉例:svgdoc = evt.target.ownerDocument

— getOwnerDocument()方法

通過呼叫該方法獲得當前SVG檔案的文件物件,也就是得到SVG的DOM結構。

使用舉例:svgdoc = evt.target.getOwnerDocument()

— target屬性

通過引用該屬性獲得事件產生於哪個SVG元素,有時可能是該元素的父元素。

使用舉例:object = evt.target

— getTarget()方法

通過呼叫該方法獲得事件產生於哪個SVG元素,有時可能是該元素的父元素。

使用舉例:object = evt.getTarget()

例程12-1 獲得SVG文件物件

<svg width="640" height="480" onload="init(evt)"> u

<script><![CDATA[

function init(evt)

{

svgDoc = evt.target.ownerDocument; v

svgRoot = svgDoc.rootElement;

alert(svgRoot.nodeName);

}

]]></script>

<rect x="100" y="100" width="100" height="50" fill="red" stroke-width= "2"/>

</svg>

該例展示瞭如何在SVG文件被載入後,呼叫初始化程式,以獲得SVG的DOM結構,為後續的程式設計做好準備。

例程12-1中,u 處表示在SVG文件載入時啟用的“onload”事件中執行“init”函式;“init”函式先是得到SVG Document物件,然後獲得該物件的根元素(也就是“SVG”元素),最後的效果是彈出一個訊息框,上面顯示“SVG”。

v 處的程式碼可以替換為“svgDoc = evt.getTarget().getOwnerDocument;”,得到的效果是一樣的。

12.2.2 DOM物件操作相關

前面我們已經介紹過,DOM物件是一個樹型的結構,並且經過載入後就放在記憶體中供我們讀寫。如何對這棵樹進行操作,也就成為發揮SVG互動性很關鍵的一步。下面所示的方法中,有些是文件物件(Document)的方法,有些是文件元素(Element)的方法,需要區別開來。DOM可以分為三大部分:文件基本元素、文件物件和各種型別的從文件基本元素派生出的文件元素。文件物件是文件物件模型的頂級物件,它包含了整個文件的內容。各種型別的文件元素派生自文件基本元素型別,用於描述文件中各種實際存在的元素。其中可以定義一種文件元素,它們可以容納其他的文件元素,這些元素就是容器元素,實際上文件物件就是最大的容器元素。由於文件物件模型中存在容器元素,因此所有的物件都組成一個樹狀結構,稱為文件物件樹或者DOM樹,其中根節點就是文件物件。

— getElementById(ID_Name)方法

通過元素的ID名獲得該元素。

使用舉例:object = svgdoc.getElementById("map")

— getElementsByTagName(Tag_Name)方法

通過元素名獲得一個或者一組元素,注意方法名中的“Elements”是複數,說明返回的元素可能有多個,是一個“NodeList”。

使用舉例:object = svgdoc.getElementsByTagName ("rect")

例程12-2 獲得SVG文件中的元素

<svg width="640" height="480" onload="init(evt)">

<script><![CDATA[

function init(evt)

{

svgDoc = evt.target.ownerDocument;

svgRoot = svgDoc.rootElement;

rect = svgRoot.getElementById("rect1");u

rects = svgRoot.getElementsByTagName("rect");v

alert(rect+","+rects);

}

]]></script>

<rect id="rect1" x="100" y="100" width="100" height="50" fill="red"/>

<rect id="rect2" x="100" y="200" width="100" height="50" fill="red"/>

<rect id="rect3" x="100" y="300" width="100" height="50" fill="red"/>

</svg>

開啟該文件後,彈出的訊息框上顯示“[object SVGRectElement],[object NodeList]”。

例程12-2中,u處使用“rect1”的ID名得到了“svgRoot”下屬的一個矩形元素(SVGRectElement)。v是為了獲得所有“svgRoot”下屬的“<rect>”元素,返回的是一個“NodeList”,本例中一共有三個符合條件的元素。

— getAttribute(ID_Name)方法

根據所提供的ID名來獲得元素的屬性值。

使用舉例:color = node.getAttribute ("fill")

— setAttribute(Attribute_Name,Value)方法

設定該元素屬性名為“Attribute_Name”屬性的值為“Value”。

使用舉例:color = node.getAttribute ("fill")

— setAttributeNS(NameSpace, Attribute_Name ,Value)方法

功能效果同setAttribute方法,區別就是增加了為屬性名加上名稱空間(NameSpace)。在ASV3.0中,屬性名都是預設SVG的名稱空間,所以不需要再特別註明,但是如果你要使用“xlink”中的屬性,就要加入相應的名稱空間“http://www.w3.org/2000 /xlink/namespace/”。

使用舉例:object = svgdoc.setAttributeNS ("http://www.w3.org/2000/xlink/namespace/", xlink:href, "index.html")

注意 絕對不要在同一個程式中混合使用DOM1非名稱空間API和DOM2名稱空間感知的API(例如,createElement和createElementNS)。如果使用名稱空間,請儘量在根元素位置宣告所有名稱空間,並且不要覆蓋名稱空間字首,否則情況會非常混亂。一般來說,只要按照慣例,就不會觸發使你陷入麻煩的臨界情況。

例程12-3 設定SVG元素的屬性

<svg width="640" height="480" onload="init(evt)">

<script><![CDATA[

function init(evt)

{

svgDoc = evt.target.ownerDocument;

svgRoot = svgDoc.rootElement;

rect1 = svgRoot.getElementById("rect1");

rect2 = svgRoot.getElementById("rect2");

}

function setSvgAttribute(evt,flag)

{

if ( flag == 1)

rect1.setAttribute("fill", "green");u

else

{

rect2.setAttributeNS(null, "fill", "green");v

}

}

function getSvgAttribute(evt)

{

alert(rect1.getAttribute("fill")+ "," + rect1.getAttribute("height"));w

}

]]></script>

<rect id="rect1" x="100" y="100" width="100" height="50" fill="red" onclick="getSvgAttribute(evt)" onmousemove="setSvgAttribute(evt,1) "/><rect id="rect2" x="100" y="200" width="100" height="50" fill="red" onclick="setSvgAttribute(evt,2)"/>

</svg>

這裡例子中我們接觸到了SVG中的事件,這跟HTML中的事件很相似,關於SVG的事件我們會在後面的章節中做詳細介紹。這裡用到了兩個事件:一個是滑鼠單擊事件“onclick”,一個是滑鼠移動到“<rect>”時觸發的“onmousemove”事件,注意它們的大小寫,全部是小寫,否則事件無法啟用,瀏覽器會報告指令碼錯誤。

我們想要實現的效果是,單擊ID為“rect1”的矩形時,能得到它的填充顏色值和矩形的高度值,並且滑鼠移動到該矩形的時候,矩形的填充顏色從紅色變成綠色;另外一個矩形,我們在單擊它的時候,它的填充顏色從紅色變成綠色。

例程12-3中,u處設定矩形“rect1”的“fill”屬性為“green”

v通過名稱空間來設定屬性值。不過名稱空間引數的值是“null”,因為ASV3.0已經內建了名稱空間,所以你再給這些SVG的屬性新增名稱空間的話就會出錯,所以填入“null”值。

w是為了彈出訊息框,顯示我們需要知道的那兩個屬性值。

— createElement(Element_Type)方法

在DOM物件內建立一個新的元素,可以指定建立哪一種型別的元素,並且返回對這個新元素的引用。

使用舉例:newnode = svgdoc.createElement("rect")

— appendChild(Element)方法

在該元素的最後追加一個孩子節點。

使用舉例:someElement.appendChild(node)

例程12-4 動態建立SVG的元素

<svg width="640" height="480" onload="init(evt)">

<script><![CDATA[

function alertMsg(evt)

{

objet=evt.target;

large=objet.getAttribute("width");

alert("Width of the rectangle is:" + evt.target.getAttribute ("width"));

}

function init(evt)

{

svgdoc=evt.target.ownerDocument;

node=svgdoc.createElement("rect");u

node.setAttribute("x","50");

node.setAttribute("y","50");

node.setAttribute("width","100");

node.setAttribute("height","50");

node.setAttribute("style","fill:red");

node.addEventListener("mousemove",alertMsg,false); v

group=svgdoc.getElementById("group");

group.appendChild(node); w

}

]]></script>

<g id="group">

<text x="100" y="20"

style="text-anchor:middle;font-size:15;fill:red">Click the rectangle </text>

</g>

</svg>

在上面這個SVG文件中,沒有看到對“rect”元素的定義,但是實際顯示的時候還是顯示了一個紅色的矩形,原因就在於例程12-4中u處,我們使用“createElement”方法動態生成了一個矩形元素,並且逐個設定了它的“x”、“y”、“width”、“height”及“fill”屬性,並且在v處為該元素添加了“mousemove”事件及事件相應的函式名。但是這樣生成的矩形元素依舊還是“流離失所”,無法顯示出來,需要使用appendChild、insertBefore、replaceChild等方法把生成的節點元素新增到其它其他元素下才能顯示。所以,執行w處的語句後,生成的新元素被加入到名為“group”的組中去,從而顯示出來。最終的DOM結構為:如圖12-1所示。

圖12-1 動態生成SVG元素後的DOM結構

從圖12-1中可以看出,新加入的“rect”元素與之前就存在的“text”元素位置並列。

— replaceChild(newElement, oldElement)方法

在某元素的子節點中,使用新元素替代舊元素。

使用舉例:someElement.replaceChild(newNode, oldNode)

例程12-5 replaceChild方法使用舉例

<svg width="640" height="480" onload="init(evt)">

<script><![CDATA[

function init(evt)

{

svgdoc = evt.target.ownerDocument;

root = svgdoc.rootElement;

}

function change(evt)

{

obj = evt.target; u

node=svgdoc.createElement("rect");

node.setAttribute("x",150);

node.setAttribute("y",150);

node.setAttribute("width","100");

node.setAttribute("height","50");

node.setAttribute("style","fill:blue");

root.replaceChild(node,obj); v

}

]]></script>

<rect x="50" y="50" width="100" height="50" onclick="change(evt)"/> w

</svg>

這個例子想要實現的效果是:單擊一個黑色的矩形後,使它移動到新的位置,並且填充顏色變成藍色。可以使用動畫的辦法來實現,但現在我們要用編寫動態指令碼的方法來實現。例程12-5中,w處已經存在一個黑色矩形了,單擊後觸發事件執行“change”函式。u的“obj”就是產生事件的“rect”元素,也就是此後要被替代掉的那個元素。然後建立一個新的“rect”元素,設定新的位置屬性和填充顏色值。在v處進行元素的替代,w處的矩形元素就被替換成新的矩形元素,舊的矩形元素不復存在,從而也在顯示區域內消失。

— removeChild(Element)方法

刪除某元素下的指定元素。

使用舉例:someElement.replaceChild(Node)

— insertBefore(newElement,refElement)方法

newElement是一個包含新子元素地址的物件,refElement是參照元素的地址,新子元素被插到參照元素之前。如果refElement引數沒有包含在內,或者refElement不是此集合的成員,新的子元素會被插到該元素子元素列表的末尾。

使用舉例:objDocumentElement =someElement.insertBefore(newNode, refNode)

— cloneNode(true/false)方法

複製一個新的元素,並且返回對這個元素的引用。

使用舉例:someElement.cloneNode(true)

例程12-6 刪除、插入、複製一個新元素

<svg width="640" height="480" onload="init(evt)">

<script><![CDATA[

function init(evt)

{

svgdoc = evt.target.ownerDocument;

root = svgdoc.rootElement;

}

function remove(evt) u

{

obj = evt.target;

root.removeChild(obj);

}

function insert(evt) v

{

obj = evt.target;

node=svgdoc.createElement("rect");

node.setAttribute("x",150);

node.setAttribute("y",150);

node.setAttribute("width","100");

node.setAttribute("height","50");

node.setAttribute("style","fill:blue");

root.insertBefore(node,obj);

}

function clone(evt) w

{

obj = evt.target;

var newNode = obj.cloneNode(true);

newNode.setAttribute("y", 300);

newNode.setAttribute("style", "fill:blue");

root.appendChild(newNode);

}

]]></script>

<rect x="50" y="50" width="100" height="50" onclick="remove(evt)"/>

<rect x="50" y="150" width="100" height="50" onclick="insert(evt)"/>

<rect x="50" y="250" width="100" height="50" onclick="clone(evt)"/>

</svg>

該例中有三個矩形元素,分別進行刪除、插入和複製操作。例程12-6中,函式u進行刪除元素的操作,直接呼叫“removeChild”方法,要刪除的是在root元素下的“rect”元素,執行後,“rect”元素被刪除,矩形也就消失了;函式v依舊是先在記憶體中生成一個新的“rect”元素,然後使用“insertBefore”方法把它插入到產生事件的那個“rect”元素的前面,兩者是並列的位置;函式w先是“克隆”了一個與產生事件的“rect”元素一模一樣的元素,並且返回給區域性變數“newNode”,我們再對這個區域性變數設定了屬性“y”和填充顏色,然後把這個元素追加到“root”元素內的最後的位置,使它顯示出來。

— firstChild屬性、getFirstChlid()方法

獲得某個元素的第一個子元素。

使用舉例:node = someElement.firstChild

或node = someElement.getFirstChild()

— childNodes屬性、getChildNodes()方法

獲得某個元素下面所有的子元素。

使用舉例:nodeList = someElement.childNodes

或nodeList = someElement.getChildNodes()

— item(n)方法

當獲得了一個元素集合的時候,需要使用該方法進行引用。

使用舉例:node = someElement.childNodes.items(1)

— NodeType屬性

節點型別,是一個列舉量。

使用舉例:i = someElement.NodeType

詳見下面的列12-1

表12-1 節點型別

返回的整數

節點型別常數

1

ELEMENT_NODE

2

ATTRIBUTE_NODE

3

TEXT_NODE

4

CDATA_SECTION_NODE

5

ENTITY_REFERENCE_NODE

6

ENTITY_NODE

7

PROCESSING_INSTRUCTION_NODE

8

COMMENT_NODE

9

DOCUMENT_NODE

10

DOCUMENT_TYPE_NODE

11

DOCUMENT_FRAGMENT_NODE

12

NOTATION_NODE

— NodeName屬性

節點名。

使用舉例:name = someElement.NodeName

詳見表12-2

表12-2 節點名稱

返回的字串

comment

這是一個註釋節點

#document

這是一個文件節點

Element.tagName

元素的標記名,同時也說明這是一個元素

Attri.name

屬性的名字,同時也說明這是一個元素

#text

這是一個文字節點

例程12-7 SVG節點操作

<svg width="640" height="480" onload="init(evt)">

<script><![CDATA[

function init(evt)

{

svgdoc = evt.target.ownerDocument;

root = svgdoc.rootElement;

alert("First node of root:" + root.firstChild.nodeName); u

alert("Seconde child node of root:"+root.getChildNodes().item(1). nodeName); v

var obj = svgdoc.getElementById("words");

alert("Third child node of text element:"+obj.childNodes.item(0). nodeName); w

}

]]>

</script>

<g>

<rect x="50" y="50" width="100" height="50"

fill="white" stroke="black" stroke-width="2" />

<text id="words" x="100" y="100" style="font-size:20">

<tspan style="font-size:30">W</tspan>

<tspan x="110" y="80"> orld!</tspan>

</text>

</g>

</svg>

這個例子幫助大家更加深刻理解SVG的DOM樹型結構。

例程12-7中,u 是為了取到“svg”元素下的第一個子元素,也就是“script”元素,所以執行後訊息框顯示“First node of root:script”

v 是使用“getChildNodes”方法取到“svg”下所有子元素,然後再引用第2個元素(索引值同陣列相同,從0開始),執行後訊息框顯示“First node of root:g”,也可以使用“root.firstChild. nextSibling.nodeName”語句獲得同樣的效果,這裡的“nextSibling”屬性指的是緊挨著某個元素的下一個元素

w 是取得“text”元素下的所有子元素,然後取得這些子元素的第一個元素也就是“tspan”元素,執行後顯示“Third child node of text element:tspan”。在使用這些取節點元素的方法或者屬性時,一定要小心地數好元素的排列順序,稍有不慎就會引起錯誤,所以應該儘可能減少引用層次。

— attributes

獲得某元素的屬性集合。

使用舉例:attributes = someElement.attributes

— length屬性、getLength()方法

獲得集合元素所含有元素的個數,如attributes、childNodes屬性有此屬性或方法。

使用舉例:len = attributes.length

或len = attributes.getLength()

例程12-8 SVG遍歷元素值操作

<svg width="640" height="480">

<script><![CDATA[

function information(evt)

{

obj=evt.target;

att=obj.attributes; u

str="Attributs:\nNumber: "+att.length;

for (i=0; i<att.length; i++)

{

str = str+"\n"+att.item(i).name+" : "+att.item(i).value;

}

alert(str);

}

]]></script>

<rect x="100" y="100" width="150" height="100" style="fill:blue; opacity:0.7" onclick="information(evt)"/>

</svg>

這個例子很好理解,就是遍歷矩形元素的所有屬性值,在u處,通過attributes獲得一個屬性值的集合,然後同“childNodes”屬性類似,可以使用“item()”方法進行引用,從而獲得相應的屬性值,如圖12-2所示。

圖12-1 2 遍歷屬性值的顯示結果

12.2.3 事件物件evt相關

— clientX屬性、getClientX()方法

滑鼠指標相對於瀏覽器視窗的客戶區的X座標。

使用舉例:cx = evt.clientX 或 cx = evt.getClientX()

— clientY屬性、getClientY()方法

滑鼠指標相對於瀏覽器視窗的客戶區的Y座標。

使用舉例:cx = evt.clientY 或 cx = evt.getClientY()

注意 這兩個座標並沒有計算文件的滾動高度或者寬度,如果事件發生在視窗的最上邊,不管這個文件已經向下滾動了多遠,clientX或clientY都是0

— screenX屬性、getScreenX()方法

滑鼠指標相對於使用者顯示器左上角的X座標

使用舉例:sx = evt.screenX 或 sx = evt.getScreenX()

— screenY屬性、getScreenY()方法

滑鼠指標相對於使用者顯示器左上角的Y座標

使用舉例:sx = evt.screenY 或 sx = evt.getScreenY()

例程12-9 SVG動態獲得和設定樣式操作

<svg width="400" height="400" onmousemove="mousePos(evt)">

<script><![CDATA[

function mousePos(evt)

{

cx=evt.clientX;cy=evt.clientY;

sx=evt.getScreenX();sy=evt.getScreenY();

root=evt.target.ownerDocument;

root.getElementById("pos1").firstChild.setData("Client: "+cx+" "+cy);

root.getElementById("pos2").firstChild.setData("Screen: "+sx+" "+sy)

}

]]></script>

<rect x="0" y="0" width="400" height="400"

style="stroke-width:1; stroke:black;fill:white"/>

<text id="pos1" x="5" y="20" style="font-size:15"></text>

<text id="pos2" x="5" y="40" style="font-size:15"></text>

</svg>

這個例子不復雜,就是獲得滑鼠當前的客戶區座標和螢幕座標,這兩個座標其實有著“相對座標”和“絕對座標”的味道。但是很奇怪的是,在這個例子中,不論滑鼠在什麼地方,瀏覽器視窗在什麼地方,兩個座標值總是相等的。

— getCharCode()方法

獲得鍵盤輸入的字元的ASCII碼。

使用舉例:key = evt.getCharCode()

例程12-10 SVG動態獲得鍵盤輸入字元

<svg width="500" height="500">

<script><![CDATA[

var phrase="";

function type(evt)

{

svgdoc=evt.target.ownerDocument;

key=evt.getCharCode();u

if (key==8)

{

if (phrase!="")

{

phrase=phrase.substring(0,phrase.length-1);

}

}

else

{

letter=String.fromCharCode(key); v

phrase=phrase+letter;

}

obj = svgdoc.getElementById("enter");

child = obj.firstChild.setData(phrase);

}

]]></script>

<g onkeypress="type(evt)">

<rect x="0" y="0" width="400" height="400" style="fill:white"/>

<text id="enter" x="150" y="50"

style="text-anchor:middle;font-size: 25; font-family:Arial;fill:red"> Display here</text>

</g>

</svg>

例程12-10很有趣,用來實時地顯示使用者在鍵盤上輸入的字元。首先使用u處的“getCharCode”方法獲得字元的ASCII碼,如果是控制鍵(如Ctrl、Alt、方向鍵等),則該方法自動過濾掉這些字元。v處的“String.fromCharCode”方法可以把獲得的ASCII碼轉換成相應的字元。

12.2.4 字串及文字相關

— createTextNode(TextContent)方法

動態生成文字節點的文字內容。

使用舉例:text = svgdoc.createTextNode("SVG")

例程12-11 SVG動態生成<text>節點

<svg width="400" height="400" onload="creatTextNode(evt)">

<script><![CDATA[

function creatTextNode(evt)

{

svgtarget = evt.getTarget();

svgdoc = svgtarget.ownerDocument;

node = svgdoc.createElement("text");u

node.setAttribute("x","50");

node.setAttribute("y","50");

node.setAttribute("style","text-anchor:middle;font-size:25; font-family:Arial;fill:red");

text = svgdoc.createTextNode("SVG");v

node.appendChild(text);

ou = evt.getTarget();

svgtarget.appendChild(node);

}

]]></script>

</svg>

例程12-11向我們展示瞭如何動態地生成一個文字節點,並新增這個節點文字內容。首先需要生成一個“text”元素,u處開始的程式碼就做了這樣一件事情,相信大家已經很熟悉這種動態生成元素的方法了,這裡不再贅述。v處的程式碼呼叫了“createTextNode”方法,引數就是“text”元素的文字內容,也就是要顯示出來的內容。然後使用“appendChild”方法新增到新建立的“text”元素中去。最後再把整個新建立好的元素加入到根元素中。例子中沒有任何實現定義好的“text”元素,完全通過指令碼程式動態生成。

— getNumberOfChars()方法

獲得<text>元素所包含的文字字元的個數(包括空格)。

使用舉例:number = someElement.getNumberOfChars()

— getComputedTextLength()方法

獲得<text>元素所包含的文字字元的顯示長度。

使用舉例:len = someElement.getComputedTextLength()

— selectSubString(i,j) 方法

高亮顯示<text>元素所包含的文字字串中第i個字元(不包括i)後的j個字元。

使用舉例:letter = someElement.selectSubString (2,3)

例程12-12 <text>元素文字字元相關方法

<svg width="400" height="400">

<script><![CDATA[

function detail(evt)

{

textdoc=evt.target.ownerDocument;

textNode=textdoc.getElementById("mtext");

number = textNode.getNumberOfChars();u

len = textNode.getComputedTextLength();v

textNode.selectSubString(2,3); w

alert("Total:" + number + "\n"+"Length:" + len);

}

]]></script>

<text onclick="detail(evt)" id="mtext" x="200" y="100"

style="text-anchor:middle;font-size:24;font-family:Arial;fill:red"> Welcome to SVG world!</text>

</svg>

上述三個方法是針對“text”元素的,只有“text”元素才能使用。

例程12-12中,u處程式碼計算了該文字元素所含的文字字元的數字,此例是計算“Welcome to SVG world!”這個字串的字元個數,一共有21個

v處程式碼計算字串的顯示長度,單位是畫素

w處程式碼執行後,“lco”這幾個字母呈現藍色背景高亮顯示,即第2個字母“l”後3個字母高亮顯示。