2 Scripts to create interactive sliders in SVG using ECMA script
3 Copyright (C) <2006> <Andreas Neumann>
4 Version 1.0, 2006-08-04
5 neumann@karto.baug.ethz.ch
7 http://www.carto.net/neumann/
10 * Kevin Lindsey for ideas how to implement such a slider
14 Documentation: http://www.carto.net/papers/svg/gui/slider/
21 0.99 (not documented, somewhere around 2001)
24 changed constructor parameters (added id, parentNode), removed parameter sliderGroupId, added documentation, added method .moveTo()
28 This ECMA script library is free software; you can redistribute it and/or
29 modify it under the terms of the GNU Lesser General Public
30 License as published by the Free Software Foundation; either
31 version 2.1 of the License, or (at your option) any later version.
33 This library is distributed in the hope that it will be useful,
34 but WITHOUT ANY WARRANTY; without even the implied warranty of
35 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 Lesser General Public License for more details.
38 You should have received a copy of the GNU Lesser General Public
39 License along with this library (lesser_gpl.txt); if not, write to the Free Software
40 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
44 original document site: http://www.carto.net/papers/svg/gui/slider/
45 Please contact the author in case you want to use code or ideas commercially.
46 If you use this code, please include this copyright header, the included full
47 LGPL 2.1 text and read the terms provided in the LGPL 2.1 license
48 (http://www.gnu.org/copyleft/lesser.txt)
50 -------------------------------
52 Please report bugs and send improvements to neumann@karto.baug.ethz.ch
53 If you use this control, please link to the original (http://www.carto.net/papers/svg/gui/slider/)
54 somewhere in the source-code-comment or the "about" of your project and give credits, thanks!
59 function slider(id,parentNode,x1,y1,value1,x2,y2,value2,startVal,sliderStyles,invisSliderWidth,sliderSymb,functionToCall,mouseMoveBool) {
61 var createSlider= true;
62 if (arguments.length == nrArguments) {
63 this.id = id; //an internal id, this id is not used in the SVG Dom tree
64 this.parentNode = parentNode; //the parentNode, string or nodeReference
65 this.x1 = x1; //the start point x of the slider
66 this.y1 = y1; //the start point y of the slider
67 this.value1 = value1; //the value at the start point, min slider value
68 this.x2 = x2; //the end point x of the slider
69 this.y2 = y2; //the end point y of the slider
70 this.value2 = value2; //the value at the end point, max slider value
71 this.startVal = startVal; //the initial value of the slider
72 this.value = startVal; //the current value of the slider
73 this.sliderStyles = sliderStyles; //the color of the slider line
74 this.invisSliderWidth = invisSliderWidth; //the width of invisible part of the slider
75 this.sliderSymb = sliderSymb; //the id for the movable symbol to be placed on the slider line
76 this.functionToCall = functionToCall; //the callback function
77 this.mouseMoveBool = mouseMoveBool; //boolean value to indicate if the slider gives immediate feedback or not
78 this.length = toPolarDist((this.x2 - this.x1),(this.y2 - this.y1));
79 this.direction = toPolarDir((this.x2 - this.x1),(this.y2 - this.y1));
80 this.invisSliderLine = null;
85 alert("Error in slider ("+id+") constructor: wrong nr of arguments! You have to pass over "+nrArguments+" parameters.");
91 alert("Could not create slider with id '"+id+"' due to errors in the constructor parameters");
96 slider.prototype.createSlider = function() {
97 var result = this.testParent();
99 this.invisSliderLine = document.createElementNS(svgNS,"line");
100 this.invisSliderLine.setAttributeNS(null,"x1",this.x1);
101 this.invisSliderLine.setAttributeNS(null,"y1",this.y1);
102 this.invisSliderLine.setAttributeNS(null,"x2",this.x2);
103 this.invisSliderLine.setAttributeNS(null,"y2",this.y2);
104 this.invisSliderLine.setAttributeNS(null,"stroke","black");
105 this.invisSliderLine.setAttributeNS(null,"stroke-width",this.invisSliderWidth);
106 //note that due to bugs in Opera9 and Firefox I can't use pointer-events here
107 this.invisSliderLine.setAttributeNS(null,"stroke-opacity","0");
108 this.invisSliderLine.setAttributeNS(null,"fill-opacity","0");
109 this.invisSliderLine.setAttributeNS(null,"stroke-linecap","square");
110 this.invisSliderLine.addEventListener("mousedown",this,false);
111 this.parentGroup.appendChild(this.invisSliderLine);
112 this.visSliderLine = document.createElementNS(svgNS,"line");
113 this.visSliderLine.setAttributeNS(null,"x1",this.x1);
114 this.visSliderLine.setAttributeNS(null,"y1",this.y1);
115 this.visSliderLine.setAttributeNS(null,"x2",this.x2);
116 this.visSliderLine.setAttributeNS(null,"y2",this.y2);
117 for (var attrib in this.sliderStyles) {
118 this.visSliderLine.setAttributeNS(null,attrib,this.sliderStyles[attrib]);
120 this.visSliderLine.setAttributeNS(null,"pointer-events","none");
121 this.parentGroup.appendChild(this.visSliderLine);
122 this.sliderSymbol = document.createElementNS(svgNS,"use");
123 this.sliderSymbol.setAttributeNS(xlinkNS,"xlink:href","#"+this.sliderSymb);
124 var myStartDistance = this.length - ((this.value2 - this.startVal) / (this.value2 - this.value1)) * this.length;
125 var myPosX = this.x1 + toRectX(this.direction,myStartDistance);
126 var myPosY = this.y1 + toRectY(this.direction,myStartDistance);
127 var myTransformString = "translate("+myPosX+","+myPosY+") rotate(" + Math.round(this.direction / Math.PI * 180) + ")";
128 this.sliderSymbol.setAttributeNS(null,"transform",myTransformString);
129 this.sliderSymbol.setAttributeNS(null,"pointer-events","none");
130 this.parentGroup.appendChild(this.sliderSymbol);
133 alert("could not create or reference 'parentNode' of slider with id '"+this.id+"'");
137 //test if parent group exists
138 slider.prototype.testParent = function() {
139 //test if of type object
140 var nodeValid = false;
141 if (typeof(this.parentNode) == "object") {
142 if (this.parentNode.nodeName == "svg" || this.parentNode.nodeName == "g" || this.parentNode.nodeName == "svg:svg" || this.parentNode.nodeName == "svg:g") {
143 this.parentGroup = this.parentNode;
147 else if (typeof(this.parentNode) == "string") {
148 //first test if button group exists
149 if (!document.getElementById(this.parentNode)) {
150 this.parentGroup = document.createElementNS(svgNS,"g");
151 this.parentGroup.setAttributeNS(null,"id",this.parentNode);
152 document.documentElement.appendChild(this.parentGroup);
156 this.parentGroup = document.getElementById(this.parentNode);
163 //remove all slider elements
164 slider.prototype.removeSlider = function() {
165 this.parentGroup.removeChild(this.sliderSymbol);
166 this.parentGroup.removeChild(this.visSliderLine);
167 this.parentGroup.removeChild(this.invisSliderLine);
171 slider.prototype.handleEvent = function(evt) {
176 slider.prototype.drag = function(evt) {
177 if (evt.type == "mousedown" || (evt.type == "mousemove" && this.slideStatus == 1)) {
178 //get coordinate in slider coordinate system
179 var coordPoint = myMapApp.calcCoord(evt,this.invisSliderLine);
180 //draw normal line for first vertex
181 var ax = this.x2 - this.x1;
182 var ay = this.y2 - this.y1;
184 var px1 = parseFloat(this.x1) + ay * -1;
185 var py1 = parseFloat(this.y1) + ax;
187 var px2 = parseFloat(this.x2) + ay * -1;
188 var py2 = parseFloat(this.y2) + ax;
190 if (leftOfTest(coordPoint.x,coordPoint.y,this.x1,this.y1,px1,py1) == 0 && leftOfTest(coordPoint.x,coordPoint.y,this.x2,this.y2,px2,py2) == 1) {
191 if (evt.type == "mousedown" && (evt.detail == 1 || evt.detail == 0)) {
192 this.slideStatus = 1;
193 document.documentElement.addEventListener("mousemove",this,false);
194 document.documentElement.addEventListener("mouseup",this,false);
196 myNewPos = intersect2lines(this.x1,this.y1,this.x2,this.y2,coordPoint.x,coordPoint.y,coordPoint.x + ay * -1,coordPoint.y + ax);
197 var myPercentage = toPolarDist(myNewPos['x'] - this.x1,myNewPos['y'] - this.y1) / this.length;
198 this.value = this.value1 + myPercentage * (this.value2 - this.value1);
201 var myNewPos = new Array();
202 if (leftOfTest(coordPoint.x,coordPoint.y,this.x1,this.y1,px1,py1) == 0 && leftOfTest(coordPoint.x,coordPoint.y,this.x2,this.y2,px2,py2) == 0) {
204 this.value = this.value2;
205 myNewPos['x'] = this.x2;
206 myNewPos['y'] = this.y2;
208 if (leftOfTest(coordPoint.x,coordPoint.y,this.x1,this.y1,px1,py1) == 1 && leftOfTest(coordPoint.x,coordPoint.y,this.x2,this.y2,px2,py2) == 1) {
210 this.value = this.value1;
211 myNewPos['x'] = this.x1;
212 myNewPos['y'] = this.y1;
215 var myTransformString = "translate("+myNewPos['x']+","+myNewPos['y']+") rotate(" + Math.round(this.direction / Math.PI * 180) + ")";
216 this.sliderSymbol.setAttributeNS(null,"transform",myTransformString);
219 if (evt.type == "mouseup" && (evt.detail == 1 || evt.detail == 0)) {
220 if (this.slideStatus == 1) {
221 this.slideStatus = 2;
222 document.documentElement.removeEventListener("mousemove",this,false);
223 document.documentElement.removeEventListener("mouseup",this,false);
226 this.slideStatus = 0;
230 //this code is executed, after the slider is released
231 //you can use switch/if to detect which slider was used (use this.id) for that
232 slider.prototype.fireFunction = function() {
233 if (this.slideStatus == 1 && this.mouseMoveBool == true) {
234 if (typeof(this.functionToCall) == "function") {
235 this.functionToCall("change",this.id,this.value);
237 if (typeof(this.functionToCall) == "object") {
238 this.functionToCall.getSliderVal("change",this.id,this.value);
240 if (typeof(this.functionToCall) == undefined) {
244 if (this.slideStatus == 2) {
245 if (typeof(this.functionToCall) == "function") {
246 this.functionToCall("release",this.id,this.value);
248 if (typeof(this.functionToCall) == "object") {
249 this.functionToCall.getSliderVal("release",this.id,this.value);
251 if (typeof(this.functionToCall) == undefined) {
257 slider.prototype.getValue = function() {
261 //this is to set the value from other scripts
262 slider.prototype.setValue = function(value,fireFunction) {
264 var myPercAlLine = (this.value - this.value1) / (this.value2 - this.value1);
265 var myPosX = this.x1 + toRectX(this.direction,this.length * myPercAlLine);
266 var myPosY = this.y1 + toRectY(this.direction,this.length * myPercAlLine);
267 var myTransformString = "translate("+myPosX+","+myPosY+") rotate(" + Math.round(this.direction / Math.PI * 180) + ")";
268 this.sliderSymbol.setAttributeNS(null,"transform",myTransformString);
270 //temporary set slideStatus
271 this.slideStatus = 2;
273 this.slideStatus = 0;
277 slider.prototype.moveTo = function(x1,y1,x2,y2) {
282 this.invisSliderLine.setAttributeNS(null,"x1",this.x1);
283 this.invisSliderLine.setAttributeNS(null,"y1",this.y1);
284 this.invisSliderLine.setAttributeNS(null,"x2",this.x2);
285 this.invisSliderLine.setAttributeNS(null,"y2",this.y2);
286 this.visSliderLine.setAttributeNS(null,"x1",this.x1);
287 this.visSliderLine.setAttributeNS(null,"y1",this.y1);
288 this.visSliderLine.setAttributeNS(null,"x2",this.x2);
289 this.visSliderLine.setAttributeNS(null,"y2",this.y2);
290 //reset direction and length of the slider
291 this.length = toPolarDist((this.x2 - this.x1),(this.y2 - this.y1));
292 this.direction = toPolarDir((this.x2 - this.x1),(this.y2 - this.y1));
293 //reset the value to correctly reposition element
294 this.setValue(this.getValue(),false);