blob: ce3d83f0dbd0d210d976064f0041e55222ee1be0 [file] [log] [blame]
/*
Scripts to create interactive sliders in SVG using ECMA script
Copyright (C) <2006> <Andreas Neumann>
Version 1.0, 2006-08-04
neumann@karto.baug.ethz.ch
http://www.carto.net/
http://www.carto.net/neumann/
Credits:
* Kevin Lindsey for ideas how to implement such a slider
----
Documentation: http://www.carto.net/papers/svg/gui/slider/
----
current version: 1.0.
version history:
0.99 (not documented, somewhere around 2001)
1.0 (2006-08-04)
changed constructor parameters (added id, parentNode), removed parameter sliderGroupId, added documentation, added method .moveTo()
-------
This ECMA script library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library (lesser_gpl.txt); if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
----
original document site: http://www.carto.net/papers/svg/gui/slider/
Please contact the author in case you want to use code or ideas commercially.
If you use this code, please include this copyright header, the included full
LGPL 2.1 text and read the terms provided in the LGPL 2.1 license
(http://www.gnu.org/copyleft/lesser.txt)
-------------------------------
Please report bugs and send improvements to neumann@karto.baug.ethz.ch
If you use this control, please link to the original (http://www.carto.net/papers/svg/gui/slider/)
somewhere in the source-code-comment or the "about" of your project and give credits, thanks!
*/
//slider properties
function slider(id,parentNode,x1,y1,value1,x2,y2,value2,startVal,sliderStyles,invisSliderWidth,sliderSymb,functionToCall,mouseMoveBool) {
var nrArguments = 14;
var createSlider= true;
if (arguments.length == nrArguments) {
this.id = id; //an internal id, this id is not used in the SVG Dom tree
this.parentNode = parentNode; //the parentNode, string or nodeReference
this.x1 = x1; //the start point x of the slider
this.y1 = y1; //the start point y of the slider
this.value1 = value1; //the value at the start point, min slider value
this.x2 = x2; //the end point x of the slider
this.y2 = y2; //the end point y of the slider
this.value2 = value2; //the value at the end point, max slider value
this.startVal = startVal; //the initial value of the slider
this.value = startVal; //the current value of the slider
this.sliderStyles = sliderStyles; //the color of the slider line
this.invisSliderWidth = invisSliderWidth; //the width of invisible part of the slider
this.sliderSymb = sliderSymb; //the id for the movable symbol to be placed on the slider line
this.functionToCall = functionToCall; //the callback function
this.mouseMoveBool = mouseMoveBool; //boolean value to indicate if the slider gives immediate feedback or not
this.length = toPolarDist((this.x2 - this.x1),(this.y2 - this.y1));
this.direction = toPolarDir((this.x2 - this.x1),(this.y2 - this.y1));
this.invisSliderLine = null;
this.slideStatus = 0;
}
else {
createSlider = false;
alert("Error in slider ("+id+") constructor: wrong nr of arguments! You have to pass over "+nrArguments+" parameters.");
}
if (createSlider) {
this.createSlider();
}
else {
alert("Could not create slider with id '"+id+"' due to errors in the constructor parameters");
}
}
//create slider
slider.prototype.createSlider = function() {
var result = this.testParent();
if (result) {
this.invisSliderLine = document.createElementNS(svgNS,"line");
this.invisSliderLine.setAttributeNS(null,"x1",this.x1);
this.invisSliderLine.setAttributeNS(null,"y1",this.y1);
this.invisSliderLine.setAttributeNS(null,"x2",this.x2);
this.invisSliderLine.setAttributeNS(null,"y2",this.y2);
this.invisSliderLine.setAttributeNS(null,"stroke","black");
this.invisSliderLine.setAttributeNS(null,"stroke-width",this.invisSliderWidth);
//note that due to bugs in Opera9 and Firefox I can't use pointer-events here
this.invisSliderLine.setAttributeNS(null,"stroke-opacity","0");
this.invisSliderLine.setAttributeNS(null,"fill-opacity","0");
this.invisSliderLine.setAttributeNS(null,"stroke-linecap","square");
this.invisSliderLine.addEventListener("mousedown",this,false);
this.parentGroup.appendChild(this.invisSliderLine);
this.visSliderLine = document.createElementNS(svgNS,"line");
this.visSliderLine.setAttributeNS(null,"x1",this.x1);
this.visSliderLine.setAttributeNS(null,"y1",this.y1);
this.visSliderLine.setAttributeNS(null,"x2",this.x2);
this.visSliderLine.setAttributeNS(null,"y2",this.y2);
for (var attrib in this.sliderStyles) {
this.visSliderLine.setAttributeNS(null,attrib,this.sliderStyles[attrib]);
}
this.visSliderLine.setAttributeNS(null,"pointer-events","none");
this.parentGroup.appendChild(this.visSliderLine);
this.sliderSymbol = document.createElementNS(svgNS,"use");
this.sliderSymbol.setAttributeNS(xlinkNS,"xlink:href","#"+this.sliderSymb);
var myStartDistance = this.length - ((this.value2 - this.startVal) / (this.value2 - this.value1)) * this.length;
var myPosX = this.x1 + toRectX(this.direction,myStartDistance);
var myPosY = this.y1 + toRectY(this.direction,myStartDistance);
var myTransformString = "translate("+myPosX+","+myPosY+") rotate(" + Math.round(this.direction / Math.PI * 180) + ")";
this.sliderSymbol.setAttributeNS(null,"transform",myTransformString);
this.sliderSymbol.setAttributeNS(null,"pointer-events","none");
this.parentGroup.appendChild(this.sliderSymbol);
}
else {
alert("could not create or reference 'parentNode' of slider with id '"+this.id+"'");
}
}
//test if parent group exists
slider.prototype.testParent = function() {
//test if of type object
var nodeValid = false;
if (typeof(this.parentNode) == "object") {
if (this.parentNode.nodeName == "svg" || this.parentNode.nodeName == "g" || this.parentNode.nodeName == "svg:svg" || this.parentNode.nodeName == "svg:g") {
this.parentGroup = this.parentNode;
nodeValid = true;
}
}
else if (typeof(this.parentNode) == "string") {
//first test if button group exists
if (!document.getElementById(this.parentNode)) {
this.parentGroup = document.createElementNS(svgNS,"g");
this.parentGroup.setAttributeNS(null,"id",this.parentNode);
document.documentElement.appendChild(this.parentGroup);
nodeValid = true;
}
else {
this.parentGroup = document.getElementById(this.parentNode);
nodeValid = true;
}
}
return nodeValid;
}
//remove all slider elements
slider.prototype.removeSlider = function() {
this.parentGroup.removeChild(this.sliderSymbol);
this.parentGroup.removeChild(this.visSliderLine);
this.parentGroup.removeChild(this.invisSliderLine);
}
//handle events
slider.prototype.handleEvent = function(evt) {
this.drag(evt);
}
//drag slider
slider.prototype.drag = function(evt) {
if (evt.type == "mousedown" || (evt.type == "mousemove" && this.slideStatus == 1)) {
//get coordinate in slider coordinate system
var coordPoint = myMapApp.calcCoord(evt,this.invisSliderLine);
//draw normal line for first vertex
var ax = this.x2 - this.x1;
var ay = this.y2 - this.y1;
//normal vector 1
var px1 = parseFloat(this.x1) + ay * -1;
var py1 = parseFloat(this.y1) + ax;
//normal vector 2
var px2 = parseFloat(this.x2) + ay * -1;
var py2 = parseFloat(this.y2) + ax;
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) {
if (evt.type == "mousedown" && (evt.detail == 1 || evt.detail == 0)) {
this.slideStatus = 1;
document.documentElement.addEventListener("mousemove",this,false);
document.documentElement.addEventListener("mouseup",this,false);
}
myNewPos = intersect2lines(this.x1,this.y1,this.x2,this.y2,coordPoint.x,coordPoint.y,coordPoint.x + ay * -1,coordPoint.y + ax);
var myPercentage = toPolarDist(myNewPos['x'] - this.x1,myNewPos['y'] - this.y1) / this.length;
this.value = this.value1 + myPercentage * (this.value2 - this.value1);
}
else {
var myNewPos = new Array();
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) {
//more than max
this.value = this.value2;
myNewPos['x'] = this.x2;
myNewPos['y'] = this.y2;
}
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) {
//less than min
this.value = this.value1;
myNewPos['x'] = this.x1;
myNewPos['y'] = this.y1;
}
}
var myTransformString = "translate("+myNewPos['x']+","+myNewPos['y']+") rotate(" + Math.round(this.direction / Math.PI * 180) + ")";
this.sliderSymbol.setAttributeNS(null,"transform",myTransformString);
this.fireFunction();
}
if (evt.type == "mouseup" && (evt.detail == 1 || evt.detail == 0)) {
if (this.slideStatus == 1) {
this.slideStatus = 2;
document.documentElement.removeEventListener("mousemove",this,false);
document.documentElement.removeEventListener("mouseup",this,false);
this.fireFunction();
}
this.slideStatus = 0;
}
}
//this code is executed, after the slider is released
//you can use switch/if to detect which slider was used (use this.id) for that
slider.prototype.fireFunction = function() {
if (this.slideStatus == 1 && this.mouseMoveBool == true) {
if (typeof(this.functionToCall) == "function") {
this.functionToCall("change",this.id,this.value);
}
if (typeof(this.functionToCall) == "object") {
this.functionToCall.getSliderVal("change",this.id,this.value);
}
if (typeof(this.functionToCall) == undefined) {
return;
}
}
if (this.slideStatus == 2) {
if (typeof(this.functionToCall) == "function") {
this.functionToCall("release",this.id,this.value);
}
if (typeof(this.functionToCall) == "object") {
this.functionToCall.getSliderVal("release",this.id,this.value);
}
if (typeof(this.functionToCall) == undefined) {
return;
}
}
}
slider.prototype.getValue = function() {
return this.value;
}
//this is to set the value from other scripts
slider.prototype.setValue = function(value,fireFunction) {
this.value = value;
var myPercAlLine = (this.value - this.value1) / (this.value2 - this.value1);
var myPosX = this.x1 + toRectX(this.direction,this.length * myPercAlLine);
var myPosY = this.y1 + toRectY(this.direction,this.length * myPercAlLine);
var myTransformString = "translate("+myPosX+","+myPosY+") rotate(" + Math.round(this.direction / Math.PI * 180) + ")";
this.sliderSymbol.setAttributeNS(null,"transform",myTransformString);
if (fireFunction) {
//temporary set slideStatus
this.slideStatus = 2;
this.fireFunction();
this.slideStatus = 0;
}
}
slider.prototype.moveTo = function(x1,y1,x2,y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.invisSliderLine.setAttributeNS(null,"x1",this.x1);
this.invisSliderLine.setAttributeNS(null,"y1",this.y1);
this.invisSliderLine.setAttributeNS(null,"x2",this.x2);
this.invisSliderLine.setAttributeNS(null,"y2",this.y2);
this.visSliderLine.setAttributeNS(null,"x1",this.x1);
this.visSliderLine.setAttributeNS(null,"y1",this.y1);
this.visSliderLine.setAttributeNS(null,"x2",this.x2);
this.visSliderLine.setAttributeNS(null,"y2",this.y2);
//reset direction and length of the slider
this.length = toPolarDist((this.x2 - this.x1),(this.y2 - this.y1));
this.direction = toPolarDir((this.x2 - this.x1),(this.y2 - this.y1));
//reset the value to correctly reposition element
this.setValue(this.getValue(),false);
}