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個字母高亮顯示。