/static/scripts/helper_functions.js

https://bitbucket.org/cistrome/cistrome-harvard/ · JavaScript · 817 lines · 415 code · 38 blank · 364 comment · 108 complexity · 675341a4304fe144d75ebf35ba25a977 MD5 · raw file

  1. /**
  2. * @fileoverview
  3. *
  4. * ECMAScript <a href="http://www.carto.net/papers/svg/resources/helper_functions.html">helper functions</a>, main purpose is to serve in SVG mapping or other SVG based web applications
  5. *
  6. * This ECMA script library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library (http://www.carto.net/papers/svg/resources/lesser_gpl.txt); if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. * Please report bugs and send improvements to neumann@karto.baug.ethz.ch
  21. * If you use these scripts, please link to the original (http://www.carto.net/papers/svg/resources/helper_functions.html)
  22. * somewhere in the source-code-comment or the "about" of your project and give credits, thanks!
  23. *
  24. * See <a href="js_docs_out/overview-summary-helper_functions.js.html">documentation</a>.
  25. *
  26. * @author Andreas Neumann a.neumann@carto.net
  27. * @copyright LGPL 2.1 <a href="http://www.gnu.org/copyleft/lesser.txt">Gnu LGPL 2.1</a>
  28. * @credits Bruce Rindahl, numerous people on svgdevelopers@yahoogroups.com
  29. */
  30. //global variables necessary to create elements in these namespaces, do not delete them!!!!
  31. /**
  32. * This variable is a shortcut to the full URL of the SVG namespace
  33. * @final
  34. * @type String
  35. */
  36. var svgNS = "http://www.w3.org/2000/svg";
  37. /**
  38. * This variable is a shortcut to the full URL of the XLink namespace
  39. * @final
  40. * @type String
  41. */
  42. var xlinkNS = "http://www.w3.org/1999/xlink";
  43. /**
  44. * This variable is a shortcut to the full URL of the attrib namespace
  45. * @final
  46. * @type String
  47. */
  48. var cartoNS = "http://www.carto.net/attrib";
  49. /**
  50. * This variable is a alias to the full URL of the attrib namespace
  51. * @final
  52. * @type String
  53. */
  54. var attribNS = "http://www.carto.net/attrib";
  55. /**
  56. * This variable is a alias to the full URL of the Batik extension namespace
  57. * @final
  58. * @type String
  59. */
  60. var batikNS = "http://xml.apache.org/batik/ext";
  61. /**
  62. * Returns the polar direction from a given vector
  63. * @param {Number} xdiff the x-part of the vector
  64. * @param {Number} ydiff the y-part of the vector
  65. * @return direction the direction in radians
  66. * @type Number
  67. * @version 1.0 (2007-04-30)
  68. * @see #toPolarDist
  69. * @see #toRectX
  70. * @see #toRectY
  71. */
  72. function toPolarDir(xdiff,ydiff) {
  73. var direction = (Math.atan2(ydiff,xdiff));
  74. return(direction);
  75. }
  76. /**
  77. * Returns the polar distance from a given vector
  78. * @param {Number} xdiff the x-part of the vector
  79. * @param {Number} ydiff the y-part of the vector
  80. * @return distance the distance
  81. * @type Number
  82. * @version 1.0 (2007-04-30)
  83. * @see #toPolarDir
  84. * @see #toRectX
  85. * @see #toRectY
  86. */
  87. function toPolarDist(xdiff,ydiff) {
  88. var distance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
  89. return(distance);
  90. }
  91. /**
  92. * Returns the x-part of a vector from a given direction and distance
  93. * @param {Number} direction the direction (in radians)
  94. * @param {Number} distance the distance
  95. * @return x the x-part of the vector
  96. * @type Number
  97. * @version 1.0 (2007-04-30)
  98. * @see #toPolarDist
  99. * @see #toPolarDir
  100. * @see #toRectY
  101. */
  102. function toRectX(direction,distance) {
  103. var x = distance * Math.cos(direction);
  104. return(x);
  105. }
  106. /**
  107. * Returns the y-part of the vector from a given direction and distance
  108. * @param {Number} direction the direction (in radians)
  109. * @param {Number} distance the distance
  110. * @return y the y-part of the vector
  111. * @type Number
  112. * @version 1.0 (2007-04-30)
  113. * @see #toPolarDist
  114. * @see #toPolarDir
  115. * @see #toRectX
  116. */
  117. function toRectY(direction,distance) {
  118. y = distance * Math.sin(direction);
  119. return(y);
  120. }
  121. /**
  122. * Converts degrees to radians
  123. * @param {Number} deg the degree value
  124. * @return rad the radians value
  125. * @type Number
  126. * @version 1.0 (2007-04-30)
  127. * @see #RadToDeg
  128. */
  129. function DegToRad(deg) {
  130. return (deg / 180.0 * Math.PI);
  131. }
  132. /**
  133. * Converts radians to degrees
  134. * @param {Number} rad the radians value
  135. * @return deg the degree value
  136. * @type Number
  137. * @version 1.0 (2007-04-30)
  138. * @see #DegToRad
  139. */
  140. function RadToDeg(rad) {
  141. return (rad / Math.PI * 180.0);
  142. }
  143. /**
  144. * Converts decimal degrees to degrees, minutes, seconds
  145. * @param {Number} dd the decimal degree value
  146. * @return degrees the degree values in the following notation: {deg:degrees,min:minutes,sec:seconds}
  147. * @type literal
  148. * @version 1.0 (2007-04-30)
  149. * @see #dms2dd
  150. */
  151. function dd2dms(dd) {
  152. var minutes = (Math.abs(dd) - Math.floor(Math.abs(dd))) * 60;
  153. var seconds = (minutes - Math.floor(minutes)) * 60;
  154. var minutes = Math.floor(minutes);
  155. if (dd >= 0) {
  156. var degrees = Math.floor(dd);
  157. }
  158. else {
  159. var degrees = Math.ceil(dd);
  160. }
  161. return {deg:degrees,min:minutes,sec:seconds};
  162. }
  163. /**
  164. * Converts degrees, minutes and seconds to decimal degrees
  165. * @param {Number} deg the degree value
  166. * @param {Number} min the minute value
  167. * @param {Number} sec the second value
  168. * @return deg the decimal degree values
  169. * @type Number
  170. * @version 1.0 (2007-04-30)
  171. * @see #dd2dms
  172. */
  173. function dms2dd(deg,min,sec) {
  174. if (deg < 0) {
  175. return deg - (min / 60) - (sec / 3600);
  176. }
  177. else {
  178. return deg + (min / 60) + (sec / 3600);
  179. }
  180. }
  181. /**
  182. * log function, missing in the standard Math object
  183. * @param {Number} x the value where the log function should be applied to
  184. * @param {Number} b the base value for the log function
  185. * @return logResult the result of the log function
  186. * @type Number
  187. * @version 1.0 (2007-04-30)
  188. */
  189. function log(x,b) {
  190. if(b==null) b=Math.E;
  191. return Math.log(x)/Math.log(b);
  192. }
  193. /**
  194. * interpolates a value (e.g. elevation) bilinearly based on the position within a cell with 4 corner values
  195. * @param {Number} za the value at the upper left corner of the cell
  196. * @param {Number} zb the value at the upper right corner of the cell
  197. * @param {Number} zc the value at the lower right corner of the cell
  198. * @param {Number} zd the value at the lower left corner of the cell
  199. * @param {Number} xpos the x position of the point where a new value should be interpolated
  200. * @param {Number} ypos the y position of the point where a new value should be interpolated
  201. * @param {Number} ax the x position of the lower left corner of the cell
  202. * @param {Number} ay the y position of the lower left corner of the cell
  203. * @param {Number} cellsize the size of the cell
  204. * @return interpol_value the result of the bilinear interpolation function
  205. * @type Number
  206. * @version 1.0 (2007-04-30)
  207. */
  208. function intBilinear(za,zb,zc,zd,xpos,ypos,ax,ay,cellsize) { //bilinear interpolation function
  209. var e = (xpos - ax) / cellsize;
  210. var f = (ypos - ay) / cellsize;
  211. //calculation of weights
  212. var wa = (1 - e) * (1 - f);
  213. var wb = e * (1 - f);
  214. var wc = e * f;
  215. var wd = f * (1 - e);
  216. var interpol_value = wa * zc + wb * zd + wc * za + wd * zb;
  217. return interpol_value;
  218. }
  219. /**
  220. * tests if a given point is left or right of a given line
  221. * @param {Number} pointx the x position of the given point
  222. * @param {Number} pointy the y position of the given point
  223. * @param {Number} linex1 the x position of line's start point
  224. * @param {Number} liney1 the y position of line's start point
  225. * @param {Number} linex2 the x position of line's end point
  226. * @param {Number} liney2 the y position of line's end point
  227. * @return leftof the result of the leftOfTest, 1 means leftOf, 0 means rightOf
  228. * @type Number (integer, 0|1)
  229. * @version 1.0 (2007-04-30)
  230. */
  231. function leftOfTest(pointx,pointy,linex1,liney1,linex2,liney2) {
  232. var result = (liney1 - pointy) * (linex2 - linex1) - (linex1 - pointx) * (liney2 - liney1);
  233. if (result < 0) {
  234. var leftof = 1; //case left of
  235. }
  236. else {
  237. var leftof = 0; //case left of
  238. }
  239. return leftof;
  240. }
  241. /**
  242. * calculates the distance between a given point and a given line
  243. * @param {Number} pointx the x position of the given point
  244. * @param {Number} pointy the y position of the given point
  245. * @param {Number} linex1 the x position of line's start point
  246. * @param {Number} liney1 the y position of line's start point
  247. * @param {Number} linex2 the x position of line's end point
  248. * @param {Number} liney2 the y position of line's end point
  249. * @return distance the result of the leftOfTest, 1 means leftOf, 0 means rightOf
  250. * @type Number
  251. * @version 1.0 (2007-04-30)
  252. */
  253. function distFromLine(xpoint,ypoint,linex1,liney1,linex2,liney2) {
  254. var dx = linex2 - linex1;
  255. var dy = liney2 - liney1;
  256. var distance = (dy * (xpoint - linex1) - dx * (ypoint - liney1)) / Math.sqrt(Math.pow(dx,2) + Math.pow(dy,2));
  257. return distance;
  258. }
  259. /**
  260. * calculates the angle between two vectors (lines)
  261. * @param {Number} ax the x part of vector a
  262. * @param {Number} ay the y part of vector a
  263. * @param {Number} bx the x part of vector b
  264. * @param {Number} by the y part of vector b
  265. * @return angle the angle in radians
  266. * @type Number
  267. * @version 1.0 (2007-04-30)
  268. * @credits <a href="http://www.mathe-online.at/mathint/vect2/i.html#Winkel">Mathe Online (Winkel)</a>
  269. */
  270. function angleBetwTwoLines(ax,ay,bx,by) {
  271. var angle = Math.acos((ax * bx + ay * by) / (Math.sqrt(Math.pow(ax,2) + Math.pow(ay,2)) * Math.sqrt(Math.pow(bx,2) + Math.pow(by,2))));
  272. return angle;
  273. }
  274. /**
  275. * calculates the bisector vector for two given vectors
  276. * @param {Number} ax the x part of vector a
  277. * @param {Number} ay the y part of vector a
  278. * @param {Number} bx the x part of vector b
  279. * @param {Number} by the y part of vector b
  280. * @return c the resulting vector as an Array, c[0] is the x part of the vector, c[1] is the y part
  281. * @type Array
  282. * @version 1.0 (2007-04-30)
  283. * @credits <a href="http://www.mathe-online.at/mathint/vect1/i.html#Winkelsymmetrale">Mathe Online (Winkelsymmetrale)</a>
  284. * see #calcBisectorAngle
  285. * */
  286. function calcBisectorVector(ax,ay,bx,by) {
  287. var betraga = Math.sqrt(Math.pow(ax,2) + Math.pow(ay,2));
  288. var betragb = Math.sqrt(Math.pow(bx,2) + Math.pow(by,2));
  289. var c = new Array();
  290. c[0] = ax / betraga + bx / betragb;
  291. c[1] = ay / betraga + by / betragb;
  292. return c;
  293. }
  294. /**
  295. * calculates the bisector angle for two given vectors
  296. * @param {Number} ax the x part of vector a
  297. * @param {Number} ay the y part of vector a
  298. * @param {Number} bx the x part of vector b
  299. * @param {Number} by the y part of vector b
  300. * @return angle the bisector angle in radians
  301. * @type Number
  302. * @version 1.0 (2007-04-30)
  303. * @credits <a href="http://www.mathe-online.at/mathint/vect1/i.html#Winkelsymmetrale">Mathe Online (Winkelsymmetrale)</a>
  304. * see #calcBisectorVector
  305. * */
  306. function calcBisectorAngle(ax,ay,bx,by) {
  307. var betraga = Math.sqrt(Math.pow(ax,2) + Math.pow(ay,2));
  308. var betragb = Math.sqrt(Math.pow(bx,2) + Math.pow(by,2));
  309. var c1 = ax / betraga + bx / betragb;
  310. var c2 = ay / betraga + by / betragb;
  311. var angle = toPolarDir(c1,c2);
  312. return angle;
  313. }
  314. /**
  315. * calculates the intersection point of two given lines
  316. * @param {Number} line1x1 the x the start point of line 1
  317. * @param {Number} line1y1 the y the start point of line 1
  318. * @param {Number} line1x2 the x the end point of line 1
  319. * @param {Number} line1y2 the y the end point of line 1
  320. * @return interSectPoint the intersection point, interSectPoint.x contains x-part, interSectPoint.y the y-part of the resulting coordinate
  321. * @type Object
  322. * @version 1.0 (2007-04-30)
  323. * @credits <a href="http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/">P. Bourke</a>
  324. */
  325. function intersect2lines(line1x1,line1y1,line1x2,line1y2,line2x1,line2y1,line2x2,line2y2) {
  326. var interSectPoint = new Object();
  327. var denominator = (line2y2 - line2y1)*(line1x2 - line1x1) - (line2x2 - line2x1)*(line1y2 - line1y1);
  328. if (denominator == 0) {
  329. alert("lines are parallel");
  330. }
  331. else {
  332. var ua = ((line2x2 - line2x1)*(line1y1 - line2y1) - (line2y2 - line2y1)*(line1x1 - line2x1)) / denominator;
  333. var ub = ((line1x2 - line1x1)*(line1y1 - line2y1) - (line1y2 - line1y1)*(line1x1 - line2x1)) / denominator;
  334. }
  335. interSectPoint["x"] = line1x1 + ua * (line1x2 - line1x1);
  336. interSectPoint["y"] = line1y1 + ua * (line1y2 - line1y1);
  337. return interSectPoint;
  338. }
  339. /**
  340. * reformats a given number to a string by adding separators at every third digit
  341. * @param {String|Number} inputNumber the input number, can be of type number or string
  342. * @param {String} separator the separator, e.g. ' or ,
  343. * @return newString the intersection point, interSectPoint.x contains x-part, interSectPoint.y the y-part of the resulting coordinate
  344. * @type String
  345. * @version 1.0 (2007-04-30)
  346. */
  347. function formatNumberString(inputNumber,separator) {
  348. //check if of type string, if number, convert it to string
  349. if (typeof(inputNumber) == "Number") {
  350. var myTempString = inputNumber.toString();
  351. }
  352. else {
  353. var myTempString = inputNumber;
  354. }
  355. var newString="";
  356. //if it contains a comma, it will be split
  357. var splitResults = myTempString.split(".");
  358. var myCounter = splitResults[0].length;
  359. if (myCounter > 3) {
  360. while(myCounter > 0) {
  361. if (myCounter > 3) {
  362. newString = separator + splitResults[0].substr(myCounter - 3,3) + newString;
  363. }
  364. else {
  365. newString = splitResults[0].substr(0,myCounter) + newString;
  366. }
  367. myCounter -= 3;
  368. }
  369. }
  370. else {
  371. newString = splitResults[0];
  372. }
  373. //concatenate if it contains a comma
  374. if (splitResults[1]) {
  375. newString = newString + "." + splitResults[1];
  376. }
  377. return newString;
  378. }
  379. /**
  380. * writes a status text message out to a SVG text element's first child
  381. * @param {String} statusText the text message to be displayed
  382. * @version 1.0 (2007-04-30)
  383. */
  384. function statusChange(statusText) {
  385. document.getElementById("statusText").firstChild.nodeValue = "Statusbar: " + statusText;
  386. }
  387. /**
  388. * scales an SVG element, requires that the element has an x and y attribute (e.g. circle, ellipse, use element, etc.)
  389. * @param {dom::Event} evt the evt object that triggered the scaling
  390. * @param {Number} factor the scaling factor
  391. * @version 1.0 (2007-04-30)
  392. */
  393. function scaleObject(evt,factor) {
  394. //reference to the currently selected object
  395. var element = evt.currentTarget;
  396. var myX = element.getAttributeNS(null,"x");
  397. var myY = element.getAttributeNS(null,"y");
  398. var newtransform = "scale(" + factor + ") translate(" + (myX * 1 / factor - myX) + " " + (myY * 1 / factor - myY) +")";
  399. element.setAttributeNS(null,'transform', newtransform);
  400. }
  401. /**
  402. * returns the transformation matrix (ctm) for the given node up to the root element
  403. * the basic use case is to provide a wrapper function for the missing SVGLocatable.getTransformToElement method (missing in ASV3)
  404. * @param {svg::SVGTransformable} node the node reference for the SVGElement the ctm is queried
  405. * @return CTM the current transformation matrix from the given node to the root element
  406. * @type svg::SVGMatrix
  407. * @version 1.0 (2007-05-01)
  408. * @credits <a href="http://www.kevlindev.com/tutorials/basics/transformations/toUserSpace/index.htm">Kevin Lindsey (toUserSpace)</a>
  409. * @see #getTransformToElement
  410. */
  411. function getTransformToRootElement(node) {
  412. try {
  413. //this part is for fully conformant players (like Opera, Batik, Firefox, Safari ...)
  414. var CTM = node.getTransformToElement(document.documentElement);
  415. }
  416. catch (ex) {
  417. //this part is for ASV3 or other non-conformant players
  418. // Initialize our CTM the node's Current Transformation Matrix
  419. var CTM = node.getCTM();
  420. // Work our way through the ancestor nodes stopping at the SVG Document
  421. while ( ( node = node.parentNode ) != document ) {
  422. // Multiply the new CTM to the one with what we have accumulated so far
  423. CTM = node.getCTM().multiply(CTM);
  424. }
  425. }
  426. return CTM;
  427. }
  428. /**
  429. * returns the transformation matrix (ctm) for the given dom::Node up to a different dom::Node
  430. * the basic use case is to provide a wrapper function for the missing SVGLocatable.getTransformToElement method (missing in ASV3)
  431. * @param {svg::SVGTransformable} node the node reference for the element the where the ctm should be calculated from
  432. * @param {svg::SVGTransformable} targetNode the target node reference for the element the ctm should be calculated to
  433. * @return CTM the current transformation matrix from the given node to the target element
  434. * @type svg::SVGMatrix
  435. * @version 1.0 (2007-05-01)
  436. * @credits <a href="http://www.kevlindev.com/tutorials/basics/transformations/toUserSpace/index.htm">Kevin Lindsey (toUserSpace)</a>
  437. * @see #getTransformToRootElement
  438. */
  439. function getTransformToElement(node,targetNode) {
  440. try {
  441. //this part is for fully conformant players
  442. var CTM = node.getTransformToElement(targetNode);
  443. }
  444. catch (ex) {
  445. //this part is for ASV3 or other non-conformant players
  446. // Initialize our CTM the node's Current Transformation Matrix
  447. var CTM = node.getCTM();
  448. // Work our way through the ancestor nodes stopping at the SVG Document
  449. while ( ( node = node.parentNode ) != targetNode ) {
  450. // Multiply the new CTM to the one with what we have accumulated so far
  451. CTM = node.getCTM().multiply(CTM);
  452. }
  453. }
  454. return CTM;
  455. }
  456. /**
  457. * converts HSV to RGB values
  458. * @param {Number} hue the hue value (between 0 and 360)
  459. * @param {Number} sat the saturation value (between 0 and 1)
  460. * @param {Number} val the value value (between 0 and 1)
  461. * @return rgbArr the rgb values (associative array or object, the keys are: red,green,blue), all values are scaled between 0 and 255
  462. * @type Object
  463. * @version 1.0 (2007-05-01)
  464. * @see #rgb2hsv
  465. */
  466. function hsv2rgb(hue,sat,val) {
  467. var rgbArr = new Object();
  468. if ( sat == 0) {
  469. rgbArr["red"] = Math.round(val * 255);
  470. rgbArr["green"] = Math.round(val * 255);
  471. rgbArr["blue"] = Math.round(val * 255);
  472. }
  473. else {
  474. var h = hue / 60;
  475. var i = Math.floor(h);
  476. var f = h - i;
  477. if (i % 2 == 0) {
  478. f = 1 - f;
  479. }
  480. var m = val * (1 - sat);
  481. var n = val * (1 - sat * f);
  482. switch(i) {
  483. case 0:
  484. rgbArr["red"] = val;
  485. rgbArr["green"] = n;
  486. rgbArr["blue"] = m;
  487. break;
  488. case 1:
  489. rgbArr["red"] = n;
  490. rgbArr["green"] = val;
  491. rgbArr["blue"] = m;
  492. break;
  493. case 2:
  494. rgbArr["red"] = m;
  495. rgbArr["green"] = val;
  496. rgbArr["blue"] = n;
  497. break;
  498. case 3:
  499. rgbArr["red"] = m;
  500. rgbArr["green"] = n;
  501. rgbArr["blue"] = val;
  502. break;
  503. case 4:
  504. rgbArr["red"] = n;
  505. rgbArr["green"] = m;
  506. rgbArr["blue"] = val;
  507. break;
  508. case 5:
  509. rgbArr["red"] = val;
  510. rgbArr["green"] = m;
  511. rgbArr["blue"] = n;
  512. break;
  513. case 6:
  514. rgbArr["red"] = val;
  515. rgbArr["green"] = n;
  516. rgbArr["blue"] = m;
  517. break;
  518. }
  519. rgbArr["red"] = Math.round(rgbArr["red"] * 255);
  520. rgbArr["green"] = Math.round(rgbArr["green"] * 255);
  521. rgbArr["blue"] = Math.round(rgbArr["blue"] * 255);
  522. }
  523. return rgbArr;
  524. }
  525. /**
  526. * converts RGB to HSV values
  527. * @param {Number} red the hue value (between 0 and 255)
  528. * @param {Number} green the saturation value (between 0 and 255)
  529. * @param {Number} blue the value value (between 0 and 255)
  530. * @return hsvArr the hsv values (associative array or object, the keys are: hue (0-360),sat (0-1),val (0-1))
  531. * @type Object
  532. * @version 1.0 (2007-05-01)
  533. * @see #hsv2rgb
  534. */
  535. function rgb2hsv(red,green,blue) {
  536. var hsvArr = new Object();
  537. red = red / 255;
  538. green = green / 255;
  539. blue = blue / 255;
  540. myMax = Math.max(red, Math.max(green,blue));
  541. myMin = Math.min(red, Math.min(green,blue));
  542. v = myMax;
  543. if (myMax > 0) {
  544. s = (myMax - myMin) / myMax;
  545. }
  546. else {
  547. s = 0;
  548. }
  549. if (s > 0) {
  550. myDiff = myMax - myMin;
  551. rc = (myMax - red) / myDiff;
  552. gc = (myMax - green) / myDiff;
  553. bc = (myMax - blue) / myDiff;
  554. if (red == myMax) {
  555. h = (bc - gc) / 6;
  556. }
  557. if (green == myMax) {
  558. h = (2 + rc - bc) / 6;
  559. }
  560. if (blue == myMax) {
  561. h = (4 + gc - rc) / 6;
  562. }
  563. }
  564. else {
  565. h = 0;
  566. }
  567. if (h < 0) {
  568. h += 1;
  569. }
  570. hsvArr["hue"] = Math.round(h * 360);
  571. hsvArr["sat"] = s;
  572. hsvArr["val"] = v;
  573. return hsvArr;
  574. }
  575. /**
  576. * populates an array such that it can be addressed by both a key or an index nr,
  577. * note that both Arrays need to be of the same length
  578. * @param {Array} arrayKeys the array containing the keys
  579. * @param {Array} arrayValues the array containing the values
  580. * @return returnArray the resulting array containing both associative values and also a regular indexed array
  581. * @type Array
  582. * @version 1.0 (2007-05-01)
  583. */
  584. function arrayPopulate(arrayKeys,arrayValues) {
  585. var returnArray = new Array();
  586. if (arrayKeys.length != arrayValues.length) {
  587. alert("error: arrays do not have the same length!");
  588. }
  589. else {
  590. for (i=0;i<arrayKeys.length;i++) {
  591. returnArray[arrayKeys[i]] = arrayValues[i];
  592. }
  593. }
  594. return returnArray;
  595. }
  596. /**
  597. * Wrapper object for network requests, uses getURL or XMLHttpRequest depending on availability
  598. * The callBackFunction receives a XML or text node representing the rootElement
  599. * of the fragment received or the return text, depending on the returnFormat.
  600. * See also the following <a href="http://www.carto.net/papers/svg/network_requests/">documentation</a>.
  601. * @class this is a wrapper object to provide network request functionality (get|post)
  602. * @param {String} url the URL/IRI of the network resource to be called
  603. * @param {Function|Object} callBackFunction the callBack function or object that is called after the data was received, in case of an object, the method 'receiveData' is called; both the function and the object's 'receiveData' method get 2 return parameters: 'node.firstChild'|text (the root element of the XML or text resource), this.additionalParams (if defined)
  604. * @param {String} returnFormat the return format, either 'xml' or 'json' (or text)
  605. * @param {String} method the method of the network request, either 'get' or 'post'
  606. * @param {String|Undefined} postText the String containing the post text (optional) or Undefined (if not a 'post' request)
  607. * @param {Object|Array|String|Number|Undefined} additionalParams additional parameters that will be passed to the callBackFunction or object (optional) or Undefined
  608. * @return a new getData instance
  609. * @type getData
  610. * @constructor
  611. * @version 1.0 (2007-02-23)
  612. */
  613. function getData(url,callBackFunction,returnFormat,method,postText,additionalParams) {
  614. this.url = url;
  615. this.callBackFunction = callBackFunction;
  616. this.returnFormat = returnFormat;
  617. this.method = method;
  618. this.additionalParams = additionalParams;
  619. if (method != "get" && method != "post") {
  620. alert("Error in network request: parameter 'method' must be 'get' or 'post'");
  621. }
  622. this.postText = postText;
  623. this.xmlRequest = null; //@private reference to the XMLHttpRequest object
  624. }
  625. /**
  626. * triggers the network request defined in the constructor
  627. */
  628. getData.prototype.getData = function() {
  629. //call getURL() if available
  630. if (window.getURL) {
  631. if (this.method == "get") {
  632. getURL(this.url,this);
  633. }
  634. if (this.method == "post") {
  635. postURL(this.url,this.postText,this);
  636. }
  637. }
  638. //or call XMLHttpRequest() if available
  639. else if (window.XMLHttpRequest) {
  640. var _this = this;
  641. this.xmlRequest = new XMLHttpRequest();
  642. if (this.method == "get") {
  643. if (this.returnFormat == "xml") {
  644. this.xmlRequest.overrideMimeType("text/xml");
  645. }
  646. this.xmlRequest.open("GET",this.url,true);
  647. }
  648. if (this.method == "post") {
  649. this.xmlRequest.open("POST",this.url,true);
  650. }
  651. this.xmlRequest.onreadystatechange = function() {_this.handleEvent()};
  652. if (this.method == "get") {
  653. this.xmlRequest.send(null);
  654. }
  655. if (this.method == "post") {
  656. //test if postText exists and is of type string
  657. var reallyPost = true;
  658. if (!this.postText) {
  659. reallyPost = false;
  660. alert("Error in network post request: missing parameter 'postText'!");
  661. }
  662. if (typeof(this.postText) != "string") {
  663. reallyPost = false;
  664. alert("Error in network post request: parameter 'postText' has to be of type 'string')");
  665. }
  666. if (reallyPost) {
  667. this.xmlRequest.send(this.postText);
  668. }
  669. }
  670. }
  671. //write an error message if neither method is available
  672. else {
  673. alert("your browser/svg viewer neither supports window.getURL nor window.XMLHttpRequest!");
  674. }
  675. }
  676. /**
  677. * this is the callback method for the getURL() or postURL() case
  678. * @private
  679. */
  680. getData.prototype.operationComplete = function(data) {
  681. //check if data has a success property
  682. if (data.success) {
  683. //parse content of the XML format to the variable "node"
  684. if (this.returnFormat == "xml") {
  685. //convert the text information to an XML node and get the first child
  686. var node = parseXML(data.content,document);
  687. //distinguish between a callback function and an object
  688. if (typeof(this.callBackFunction) == "function") {
  689. this.callBackFunction(node.firstChild,this.additionalParams);
  690. }
  691. if (typeof(this.callBackFunction) == "object") {
  692. this.callBackFunction.receiveData(node.firstChild,this.additionalParams);
  693. }
  694. }
  695. if (this.returnFormat == "json") {
  696. if (typeof(this.callBackFunction) == "function") {
  697. this.callBackFunction(data.content,this.additionalParams);
  698. }
  699. if (typeof(this.callBackFunction) == "object") {
  700. this.callBackFunction.receiveData(data.content,this.additionalParams);
  701. }
  702. }
  703. }
  704. else {
  705. alert("something went wrong with dynamic loading of geometry!");
  706. }
  707. }
  708. /**
  709. * this is the callback method for the XMLHttpRequest case
  710. * @private
  711. */
  712. getData.prototype.handleEvent = function() {
  713. if (this.xmlRequest.readyState == 4) {
  714. if (this.returnFormat == "xml") {
  715. //we need to import the XML node first
  716. var importedNode = document.importNode(this.xmlRequest.responseXML.documentElement,true);
  717. if (typeof(this.callBackFunction) == "function") {
  718. this.callBackFunction(importedNode,this.additionalParams);
  719. }
  720. if (typeof(this.callBackFunction) == "object") {
  721. this.callBackFunction.receiveData(importedNode,this.additionalParams);
  722. }
  723. }
  724. if (this.returnFormat == "json") {
  725. if (typeof(this.callBackFunction) == "function") {
  726. this.callBackFunction(this.xmlRequest.responseText,this.additionalParams);
  727. }
  728. if (typeof(this.callBackFunction) == "object") {
  729. this.callBackFunction.receiveData(this.xmlRequest.responseText,this.additionalParams);
  730. }
  731. }
  732. }
  733. }
  734. /**
  735. * Serializes an XML node and returns a string representation. Wrapper function to hide implementation differences.
  736. * This can be used for debugging purposes or to post data to a server or network resource.
  737. * @param {dom::Node} node the DOM node reference
  738. * @return textRepresentation the String representation of the XML node
  739. * @type String
  740. * @version 1.0 (2007-05-01)
  741. * @see getData
  742. */
  743. function serializeNode(node) {
  744. if (typeof XMLSerializer != 'undefined') {
  745. return new XMLSerializer().serializeToString(node);
  746. }
  747. else if (typeof node.xml != 'undefined') {
  748. return node.xml;
  749. }
  750. else if (typeof printNode != 'undefined') {
  751. return printNode(node);
  752. }
  753. else if (typeof Packages != 'undefined') {
  754. try {
  755. var stringWriter = new java.io.StringWriter();
  756. Packages.org.apache.batik.dom.util.DOMUtilities.writeNode(node,stringWriter);
  757. return stringWriter.toString();
  758. }
  759. catch (e) {
  760. alert("Sorry, your SVG viewer does not support the printNode/serialize function.");
  761. return '';
  762. }
  763. }
  764. else {
  765. alert("Sorry, your SVG viewer does not support the printNode/serialize function.");
  766. return '';
  767. }
  768. }
  769. /**
  770. * Starts a SMIL animation element with the given id by triggering the '.beginElement()' method.
  771. * This is a convenience (shortcut) function.
  772. * @param {String} id a valid id of a valid SMIL animation element
  773. * @version 1.0 (2007-05-01)
  774. */
  775. //starts an animtion with the given id
  776. //this function is useful in combination with window.setTimeout()
  777. function startAnimation(id) {
  778. document.getElementById(id).beginElement();
  779. }