faqts : Computers : Internet : Web : SVG : ...with Javascript

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

7 of 7 people (100%) answered Yes
Recently 7 of 7 people (100%) answered Yes

Entry

How do I assign an event handler to an object?
How do I attach an object's method as an event handler?

Nov 10th, 2003 06:05
Gavin Kistner,


Most SVG elements inherit from the DOM 2 Events EventTarget interface, 
which enables you to dynamically assign one or more event handlers to 
the object (for each event type).
This entry shows first how to attach a simple global function as an 
event handler, then how to attach an object's method (so that the 
method still has proper object scope, with 'this' referring to the 
object in question).
All examples assume that you have an object in your SVG file with an 
ID of 'myObjID', e.g.
	<g id="myObjID">...</g>
and a reference to the global SVG document called 'document'.
ATTACHING A GLOBAL FUNCTION
===========================
<script type="text/ecmascript"><![CDATA[
	function SayHello(){
		alert('hello world');
	}
	var myObj = document.getElementById('myObjID');
	myObj.addEventListener('click',SayHello,false);
]]></script>
In the above, note that:
* the event type is 'click', not 'onclick'
* the function name is used without parentheses
* the third parameter is false
  (this is almost always what you'll want)
Other event types of interest to the fledgling SVG developer are 
'mouseover','mouseout','mousedown','mouseup'...but that's not a 
complete list. For a complete list, see
http://www.w3.org/TR/SVG11/interact.html#SVGEvents
ATTACHING AN OBJECT'S METHOD
============================
If you used the above to attach the method of an object instance, you 
would not get what you expect. For example:
<script type="text/ecmascript"><![CDATA[
	function MyClass(name){
		this.name=name;
	}
	MyClass.prototype.sayMyName=function(){
		alert(this.name+' says "Hello"');
	}
	var bob = new MyClass('Bob Villa');
	var myObj = document.getElementById('myObjID');
	myObj.addEventListener('click',bob.sayMyName,false);
	//THE ABOVE WON'T DO WHAT YOU WANT	
]]></script>
In the above, the sayMyName() function will be run in global scope, 
and 'this' will refer to the global window object, not 'bob'.
There are two ways to do what you want properly:
1) Define a handleEvent method of your object
---------------------------------------------
<script type="text/ecmascript"><![CDATA[
	function MyClass(name){
		this.name=name;
	}
	MyClass.prototype.handleEvent=function(evt){
		switch(evt.type){
			case 'click':
				this.sayMyName(evt);
				break;
		}
	}
	MyClass.prototype.sayMyName=function(){
		alert(this.name+' says "Hello"');
	}
	var bob = new MyClass('Bob Villa');
	var myObj = document.getElementById('myObjID');
	myObj.addEventListener('click',bob,false);
	//NOTE THAT THE OBJECT ITSELF IS PASSED
]]></script>
Unfortunately the above does not work with Corel's SVG Viewer v2.1; 
the alternative method (below) may cause memory leaks in some SVG UAs, 
and also may not work all the time, as some UAs will (under 
circumstance I don't fully understand) 'clean' up the SVG element and 
destroy the custom 'ownerJSObj' property we use to associate the 
element with its JS object.
2) Assign a custom property on the SVG element
----------------------------------------------
<script type="text/ecmascript"><![CDATA[
	function HandleEventWithObject(evt){
		var svgEl = evt.currentTarget;
		var jsObj = svgEl.ownerJSObj;
		if (jsObj!=null) jsObj.handleEvent(evt);
	}
	function MyClass(name){
		alert(this.name+' says "Hello"');
	}
	MyClass.prototype.handleEvent=function(evt){
		switch(evt.type){
			case 'click':
				this.sayMyName(evt);
				break;
		}
	}
	MyClass.prototype.sayMyName=function(){
		alert(this.name);
	}
	var bob = new MyClass('Bob Villa');
	var myObj = document.getElementById('myObjID');
	myObj.ownerJSObj = bob;
	myObj.addEventListener('click',HandleEventWithObject,false);
]]></script>