Dom Manipulation of SVG embeded inside XHTML

It’s been awhile now since the W3C proposed the XHTML + SVG + MAthML document type declaration and a certain level of support has been available for a while. I’ve been testing XHTML + MathML lately (see http://www.metonymie.com/apuntes/2008/05/14/probabilidad-formulas-basicas.html). Now Firefox 3 is out, and supposedly it has support not only for embedded SVG but also for Dom manipulation the SVG nodes ( Correction: Jeff Schiller has pointed out that SVG support has been available in Firefox since version 1.5 ). So this is a series of tests of the basics of working with SVG from Javascript.

Getting the content to be recognized by the browser.

While testing this on my machine, I found out that for the svg to be accepted inside the html I had to name the file with an .xhtml extension. Since the same document with a .html extension just wasn´t recognized by firefox (IE 7 didn´t recognize the embedded SVG one way or the other). An example: SVG embedded inline inside XHTML.

So that was fine for local tests, but what about a dynamically generated document?.

Well first we need to define the type declaration, and the appropiate namespaces:

	<?xml version="1.0"?>
	<!DOCTYPE html PUBLIC    “-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN”
	“http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd”><html xmlns=”http://www.w3.org/1999/xhtml” xml:lang=”en”>
<html xmlns=”http://www.w3.org/1999/xhtml”
      xmlns:svg=”http://www.w3.org/2000/svg”
      xmlns:xlink=”http://www.w3.org/1999/xlink”
	  xmlns:mathml=”http://www.w3.org/1998/Math/MathML”>

Note: Declaring the namespace on the document level saves us from having to declare it in each and every instance of an SVG element. So out of laziness, I prefer to do it on the top of the document.

But this is not enough if we want the document to be recognized as XHTML, we need to either use the .xhtml extension or to use a header when serving the document with content type=”text/xml”. In php we can do it like this:

	header("content-type:text/xml");

An example: SVG embedded inline inside XHTML in a file with a non .xhtml extension.

You can also set the content type to a more specific definition, for example (inside the head of the document):

	<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>

Using SVG inside XHTML

Now we’ll get into a little (just a little) more complex svg example that we’ll use for the rest of the post: Dom Manipulations of SVG Inside XHTML Examples

Defining the SVG elements

First we´ll create some basic SVG elements inside our document. Basically a Rectangle and a Circle inside a div.

	<div id="svg-content">
	<svg:svg height="300" width="700" is="svg-container">
	<svg:rect fill="#ff5500" height="50" width="200" y="100" x="300" stroke="#000000" stroke-width="2px"/>
    <svg:circle cx="150px" cy="100px" r="50px" fill="#ff0000" stroke="#000000" stroke-width="5px" id="circle"/>

	</svg:svg></div>

Accesing the SVG Objects Properties with Javascript

Getting the value of an SVG Object attribute

It is as simple as retrieving the element by ID and getting the attribute as we would for any other DOM object. In the example page, this is the code on the first button:

	alert( document.getElementById('circle').getAttribute('fill') );

Changing the value of an SVG Object Attribute

Again this is done as we would normally do with any other DOM Object.

	document.getElementById('circle').setAttribute('fill', '#ffdd22');

Creating and adding a new SVG Object

This is a little more complex since we have to create a document node with the SVG Namespace defined.

	function add_new_rectangle () {
		var atts = {"stroke-width":"1", "stroke":"blue", "fill":"yellow", "height":"20", "width":"40", "y":"100", "x":"220"};
		//Defining the SVG Namespace
		var svgNS = "http://www.w3.org/2000/svg";
		//Creating a Document by Namespace
		var node = document.createElementNS(svgNS, "rect");
		//Setting attributes by namespace
		node.setAttributeNS(null, "id", "new-rect");
		for(name in atts) {
			node.setAttributeNS(null, name, atts[name]);
		}
		var cont = document.getElementById(”svg-container”);
		//Appending the new node
		cont.appendChild(node);
	}

Using innerHTML with SVG

Now, a very simple way to deal with elements in HTML with the dom, is to use the innerHTML property. Luckily we can do the same with Divs containing SVG. Code for the fourth button in the example:

	alert(document.getElementById('svg-content').innerHTML);

And of course we can manipulate and change it with a new SVG element declaration. The function that calls the fifth button:

	function change_innerHTML_to_a_new_SVG() {
		var svg_str='‘;
		for(var x=1; x<10; x++) {
			svg_str += '<svg:circle cx="' + (x*30) + 'px" cy="100" r="' + (x*5) + 'px" fill="#ff' + (x*10) +  '00" stroke="#000000" stroke-width="3px"/>';
		}
		svg_str += '</svg:svg>';
		var cont = document.getElementById("svg-content");
		cont.innerHTML = svg_str;
	}

Javascript Global Variables Weirdness

This is a simple test of the use of Global variables in Javascript. Now suppose the following code writing outside of any function, class or whatever.


k = "k";

var t = "t";

alert("gl: " + k);

alert("gl: " + t);

Will alert us of both variables with those nice little javascript alerts

Now suppose we add this function to the code above


function test() {

	alert("t: " + k);

	alert("t: " + t);

	j = "J";

	var l = "l";

	alert("t: " + j);

	alert("t: " + l);

	k = "2k";

	t = "2t";

}

Now we run the test.


test();

which Alerts all the variables.

But now if we try the following:


alert("gl after test: " + k +" - " + "gl after test: " + t);

Alerts us with the following line gl after test: 2k - gl after test: 2t. So Globals can be modified from within functions. But what happens to the variables that were defined within the function?


 alert("gl: " + j);

//alert(”gl: ” + l); //This won’t run, l was scoped within test and can’t be accessed outside of test.

Conclusions: Variables initialized outside a function are global whether you use var or not. Variables initialized inside a function are not global if they are initialized with var, else they are global.

Simple “Days Iteration” Algorithm with a twist

Yet another one of this date iterations algorithms, due to the particulars of the script I was running I had to redo the date iteration to start on one date and iterate through all the days till another one. This is the new version, (that I’m blogging for not having to go through this again in the future):



begA = 2001;
begM = 3;
begD = 1;
endA = 2007;
endM = 1;
endD = 1;

itA = begA;
itM = begM;
itD = begD;
while( ((itA!=endA) || (itM!=endM) || (itD!=endD)) ) {
	//Print
	document.write(itA + '-' + itM + '-' + itD + '');
	if(itM==12 && itD==31) {
		//End of Year
		itA++;
		itM=01;
		itD=01;
	} else if(
		//End of Month
	( (itM==1 || itM==3 || itM==5 || itM==7 || itM==8 || itM==10 ) && itD==31)
 	//Months with 31 days
	|| ( (itM==4 || itM==6 || itM==9 || itM==11 ) && itD==30)
	//Months with 30 days
	|| (itM==2 && itD==28 && (itA%4!=0))
	//February not leap
	|| (itM==2 && itD==29 && (itA%4==0))
	//February leap
	) {
		itM++;
		itD=01;
	} else {
		itD++;
	}
}

Simple “Days Iteration” algorithm

I had to do a script for iterating through a set of MySQL fields of type Datetime. Since I’ve run through this before, I’m blogging the litle thing for rememberance in the future. Here is the a version in Javascript.



for(var a=2001; a <2007; a++) {

 for(var m=1; m<13; m++) {

 	var monthdays = 31;

 	if(m==4 || m==6 || m==9 || m==11) {

 		monthdays = 30;

 	}

 i	f(m==2) {

 		if( a%4 == 0 ) {

 			monthdays = 29;

 		} else {

 			monthdays = 28;

 		}

 	}

 	for(var d=1; d< (monthdays+1); d++) {

 		document.write(a + ' ' + m + ' ' + d + '<br/>');

 	}

 }

}

Preventing event bubble propagation in Javascript

This post is basically a bunch of tests on the information provided on chapter 9 of the book Professional Javascript for Web Developers.

I’ve been working with some javascript events behaviour and I needed to explore the Event Bubbling model in a variety of browsers. I created a simple test page for testing how js events bubble. I added a simple on click event to the different elements on a page and associated it with a function that simply alerts the name of the element. This is very usefull to see how events propagate. Go test them and see for yourself.

Results on Windows XP

 IE 6.0.2900 Firefox 1.5.07 Opera 9.0.1
Clicking outside the Body Document Document - Window Window - Document
Clicking Inside the Body Body - Document Body - Document - Window Body - Window - Document
Clicking Inside the Element Element - Body - Document Element - Body - Document - Window Element - Body - Window - Document

Now this works pretty fine and is very straightforward. But if you want to prevent an event fired by an element to bubble all the way up the bubble chain, the code is the following:


function al_p(e) { alert('Element'); if((navigator.userAgent.indexOf("MSIE")>-1 && navigator.userAgent.indexOf("compatible")>1 && !(navigator.userAgent.indexOf("opera")>-1))) { //IE
if(!e) e = window.event; e.cancelBubble = true;
} else {
//Other Browsers
e.stopPropagation(); } }; 

You can test the results here: Javascript Event Bubbling Prevention Test

Dynamic Array Sorting in Javascript

Well this is my first post at codewerks, so let’s go…

Introduction

During the development of version 3.4 ( coming soon! ) of TTIW, I needed a simple function for sorting an array whose length was dynamic. Meaning that it starts with 0 elements and it grows to a maximum number of elements. The array needed to be sorted as elements where added. Once the maximum number of elements was reached, the function should behave as it would for a fixed length array.

Now, there is a very simple way to acomplish this in Javascript by using the JavaScript Array sort() Method. However due to some particulars of the case involved ( more below ), this method was of no use, so I had to develop my own little function. Truth is, I think it’s quite a nice algorithm for the task and though I doubt it will get into Knuth’s Bible Vol.3 ( BTW, I have not read this volume, though, I only have volume one. So, who knows, maybe some variation of this is already there.. ), I thought it was nice to write a post about this. So here we go..

The first version. Sorting the array while it is being created.

Now the first version can be accessed here. The function is the following ( It’s ultra commented, so that it’s inner workings are made clear. ):


function dynamicArraySort(val, arr, maxarrlen) {
	//Check if arr already has some value.
	if(arr.length==0) return [val]; //It doesn’t return an arr with val as it’s only element
	//Determine how big the next loop will be. If array’s Maximum length has not been reached, then add one more,
	//so that if there is nothing filled it will be filled by this value ( or the ones that come after it ).
	var till = maxarrlen;
	if(arr.length<maxarrlen) till = arr.length+1;
	//Iterate through the elements on the array
	for(var i=0; i<till; i++) {
		//evaluate value against the array in that position.
		if(val>= arr[i]) {
			//It is bigger or the same.. swap every element after this one with the following one.
			for(var j=(till-1); j>=i; j–) {
				arr[j]=arr[j-1];
			}
		//change this element to val
		arr[i]=val;
		//Done for this value, stop execution, (since we have found an element smaller than value and we have changed it and all the subsequent elements)
		return arr;
		}
		//Test if there is allready an element filled on this position.
		if(!arr[i]) {
			//There is not, add this value to this position, stop execution and return array
			arr[i] = val;
			return arr;
		}
	}
	//Return array (will only happen if the array allready had a length of maxarrlen and val was not bigger than any element on the array)
	return arr;
}

You can test the function here, and it will show execution by a very helpfull ( but annoying ) alert() window on every new value added and evaluated into the array.

Another test of the function can be accessed here, this one feeds the function a set of random values ( and it doesn´t have the annoying alert ).

Now, I’m pretty sure that there are plenty of other different algorithms to do the same thing.. but this one seems fairly well suited for this particular task. Now let’s get a little more into my actual problem.

The second version. Do the same on an array of arrays, and sort by the value of the first element in the array.

Actually part of my problem was that I needed to sort an array of arrays by the value of one of the elements in the array. So I had to modify the function to do the evaluation based on this. The new version was:


function dynamicArraySort(narr, arr, maxarrlen) {
	//Check if arr has allready some value.
	if(arr.length==0) return [narr]; //It doesn’t return an arr with val as it’s only element
	//Determine how big the next loop will be. If array’s Maximum length has not been reached, then add one more,
	//so that if there is nothing filled it will be filled by this value ( or the ones that come after it ).
	var till = maxarrlen;
	if(arr.length<maxarrlen) till = arr.length+1;
	//Iterate through the elements on the array
	for(var i=0; i < till; i++) {
		//Test if there is allready an element filled on this position.
		if(!arr[i]) {
		//There is not, add this value to this position, stop execution and return array
		arr[i] = narr;
		return arr;
		}
		//evaluate value against the array in that position.
		if(narr[0] >= arr[i][0]) {
			//It is bigger or the same.. swap every element after this one with it’s following one
			for(var j=(till-1); j > =i; j–) {
				arr[j]=arr[j-1];
			}
			//change this element to val
			arr[i]=narr;
			//Done for this value, stop execution, (since we have found an element smaller than value and we have changed it and all the subsequent elements)
			return arr;
		}
	}
	//Return array (will only happen if the array allready had a length of maxarrlen and val was not bigger than any element on the array)
	return arr;
}

There is no real variations bettween this function and the other, except that we are dealing with an array of arrays. The evaluation is done against the element in postion [0] of the array. ( I had to move the test of wether an element has a value to the top of the loop, since javascript will throw an error if you try to access the elements of an array that does not exist. )

You can test it here and here.

Now, notice how when using the examples above, the second element of the array has a number on the left ( something like a-24 ). This was done just for testing purposes, but, and this is the interesting part and the problem I actually had to solve. The number represents the actual step in which the new array was evaluated into the function. As you can see in the second test, the last added element of the same value will be stored before the ones that came before it. Now this was my problem. I needed to sort the array by the value of the first element in the array, but if an element with the same value was added, it needed to be placed after and not before the elements with this same value. So it’s on to version 3…

Version 3, Recursiveness…

Well to solve this problem I had to use recursion. Here is the new version:


function dynamicArraySort(narr, arr, maxarrlen, start) {
	//Check if arr has allready some value.
	if(arr.length==0) return [narr]; //It doesn’t return an arr with val as it’s only element
	//Determine how big the next loop will be. If array’s Maximum length has not been reached, then add one more,
	//so that if there is nothing filled it will be filled by this value ( or the ones that come after it ).
	var till = maxarrlen;
	if(arr.length<maxarrlen) till = arr.length+1;
	//Iterate through the elements on the array
	for(var i=start; i<till; i++) {
		//Test if there is allready an element filled on this position.
		if(!arr[i]) {
			//There is not, add this value to this position, stop execution and return array
			arr[i] = narr;
			return arr;
		}
		//evaluate value against the array in that position.
		if(narr[0]== arr[i][0]) {
			//It is the same.. do a recursive call to this same function starting on the next element.
			return dynamicArraySort(narr, arr, maxarrlen, i+1);
		} else if(narr[0] > arr[i][0]) {
			//It is bigger swap every element after this one with it’s following one
			for(var j=(till-1); j>=i; j–) {
				arr[j]=arr[j-1];
			}
			//change this element to val
			arr[i]=narr;
			//Done for this value, stop execution, (since we have found an element smaller than value and we have changed it and all the subsequent elements)
			return arr;
		}
	}
	//Return array (will only happen if the array allready had a length of maxarrlen and val was not bigger than any element on the array)
	return arr;
}

Now, the big difference here is that if an element is of the same value as one before, the function calls itself but starting the loop on the next element of the array (of arrays). That’s the reason of the start paramenter on this new version. Neat!!!

Well, that solved the problem, you can test the final version here and here

Prologue

The function is pretty sweet, the only thing that I would like to add is that I needed to do this on an array that will store a maximum of 5 values out of something from 3 to 120 different values. For solving this, the algorithm is very good, of course if the array had to store a bigger amount of values, the algorithm can ( and should ) be refined.. but I’m leaving that for another time.

Post Archive

Post Categories

Search Posts