Fix Issue 28: Use spinners instead of pulldowns for stroke-width and rect radius. Add spinbtn jquery plugin

git-svn-id: http://svg-edit.googlecode.com/svn/trunk@278 eee81c28-f429-11dd-99c0-75d572ba1ddd
master
Jeff Schiller 2009-07-07 01:21:19 +00:00
parent e4af0eb261
commit 5f8016a839
5 changed files with 295 additions and 32 deletions

View File

@ -0,0 +1,41 @@
/*
Styles to make ordinary <INPUT type="text"/> look like a spinbutton/spinbox control.
Use with JQuerySpinBtn.js to provide the spin functionality by reacting to mouse etc.
(Requires a reference to the JQuery library found at http://jquery.com/src/latest/)
(Hats-off to John Resig for creating the excellent JQuery library. It is fab.)
This control is achieved with no extra html markup whatsoever and uses unobtrusive javascript.
Written by George Adamson, Software Unity (george.jquery@softwareunity.com) September 2006.
Big improvements added by Mark Gibson, (mgibson@designlinks.net) September 2006.
Do contact me with comments and suggestions but please don't ask for support.
As much as I'd love to help with specific problems I have plenty to get on with already!
Go ahead and use it in your own projects. This code is provided 'as is'.
Sure I've tested in heaps of ways. Its good for me, but you use it at your own risk.
SoftwareUnity and I are certainly not responsible if your computer sets fire to the sofa,
hacks into the pentagon, hijacks a plane or gives you any kind of hassle whatsoever.
If you'd like your spin-button image in a different place then you'll need to alter both
the CSS below and the javascript isMouseOverUpDn() function to accommodate the new position.
You could even have left and right buttons either side of the textbox.
*/
INPUT.spin-button {
/* explicitly put padding for top/bottom/left in here so that Opera displays it better */
padding: 2px 20px 2px 2px;
background-repeat:no-repeat; /* Warning: Img may disappear in Firefox if you use 'background-attachment:fixed' ! */
background-position:100% 0%;
background-image:url(spinbtn_updn.gif);
background-color:white; /* Needed for Opera */
}
INPUT.spin-button.up { /* Change button img when mouse is over the UP-arrow */
cursor:pointer;
background-position:100% -18px; /* 18px matches height of 2 visible buttons */
}
INPUT.spin-button.down { /* Change button img when mouse is over the DOWN-arrow */
cursor:pointer;
background-position:100% -36px; /* 36px matches height of 2x2 visible buttons */
}

View File

@ -0,0 +1,234 @@
/* SpinButton control
*
* Adds bells and whistles to any ordinary textbox to
* make it look and feel like a SpinButton Control.
*
* Originally written by George Adamson, Software Unity (george.jquery@softwareunity.com) August 2006.
* - Added min/max options
* - Added step size option
* - Added bigStep (page up/down) option
*
* Modifications made by Mark Gibson, (mgibson@designlinks.net) September 2006:
* - Converted to jQuery plugin
* - Allow limited or unlimited min/max values
* - Allow custom class names, and add class to input element
* - Removed global vars
* - Reset (to original or through config) when invalid value entered
* - Repeat whilst holding mouse button down (with initial pause, like keyboard repeat)
* - Support mouse wheel in Firefox
* - Fix double click in IE
* - Refactored some code and renamed some vars
*
* Modifications by Jeff Schiller, June 2009:
* - provide callback function for when the value changes based on the following
* http://www.mail-archive.com/jquery-en@googlegroups.com/msg36070.html
* Modifications by Jeff Schiller, July 2009:
* - improve styling for widget in Opera
* - consistent key-repeat handling cross-browser
*
* Tested in IE6, Opera9, Firefox 1.5
* v1.0 11 Aug 2006 - George Adamson - First release
* v1.1 Aug 2006 - George Adamson - Minor enhancements
* v1.2 27 Sep 2006 - Mark Gibson - Major enhancements
* v1.3a 28 Sep 2006 - George Adamson - Minor enhancements
* v1.4 18 Jun 2009 - Jeff Schiller - Added callback function
* v1.5 06 Jul 2009 - Jeff Schiller - Fixes for Opera.
* Fast-repeat for keys and live updating as you type.
Sample usage:
// Create group of settings to initialise spinbutton(s). (Optional)
var myOptions = {
min: 0, // Set lower limit.
max: 100, // Set upper limit.
step: 1, // Set increment size.
spinClass: mySpinBtnClass, // CSS class to style the spinbutton. (Class also specifies url of the up/down button image.)
upClass: mySpinUpClass, // CSS class for style when mouse over up button.
downClass: mySpinDnClass // CSS class for style when mouse over down button.
}
$(document).ready(function(){
// Initialise INPUT element(s) as SpinButtons: (passing options if desired)
$("#myInputElement").SpinButton(myOptions);
});
*/
$.fn.SpinButton = function(cfg){
return this.each(function(){
this.repeating = false;
// Apply specified options or defaults:
// (Ought to refactor this some day to use $.extend() instead)
this.spinCfg = {
//min: cfg && cfg.min ? Number(cfg.min) : null,
//max: cfg && cfg.max ? Number(cfg.max) : null,
min: cfg && !isNaN(parseFloat(cfg.min)) ? Number(cfg.min) : null, // Fixes bug with min:0
max: cfg && !isNaN(parseFloat(cfg.max)) ? Number(cfg.max) : null,
step: cfg && cfg.step ? Number(cfg.step) : 1,
page: cfg && cfg.page ? Number(cfg.page) : 10,
upClass: cfg && cfg.upClass ? cfg.upClass : 'up',
downClass: cfg && cfg.downClass ? cfg.downClass : 'down',
reset: cfg && cfg.reset ? cfg.reset : this.value,
delay: cfg && cfg.delay ? Number(cfg.delay) : 500,
interval: cfg && cfg.interval ? Number(cfg.interval) : 100,
_btn_width: 20,
_btn_height: 12,
_direction: null,
_delay: null,
_repeat: null,
callback: cfg && cfg.callback ? cfg.callback : null,
};
this.adjustValue = function(i){
var v = (isNaN(this.value) ? this.spinCfg.reset : Number(this.value)) + Number(i);
if (this.spinCfg.min !== null) v = Math.max(v, this.spinCfg.min);
if (this.spinCfg.max !== null) v = Math.min(v, this.spinCfg.max);
this.value = v;
if ($.isFunction(this.spinCfg.callback)) this.spinCfg.callback(this);
};
$(this)
.addClass(cfg && cfg.spinClass ? cfg.spinClass : 'spin-button')
.mousemove(function(e){
// Determine which button mouse is over, or not (spin direction):
var x = e.pageX || e.x;
var y = e.pageY || e.y;
var el = e.target || e.srcElement;
var direction =
(x > coord(el,'offsetLeft') + el.offsetWidth - this.spinCfg._btn_width)
? ((y < coord(el,'offsetTop') + this.spinCfg._btn_height) ? 1 : -1) : 0;
if (direction !== this.spinCfg._direction) {
// Style up/down buttons:
switch(direction){
case 1: // Up arrow:
$(this).removeClass(this.spinCfg.downClass).addClass(this.spinCfg.upClass);
break;
case -1: // Down arrow:
$(this).removeClass(this.spinCfg.upClass).addClass(this.spinCfg.downClass);
break;
default: // Mouse is elsewhere in the textbox
$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);
}
// Set spin direction:
this.spinCfg._direction = direction;
}
})
.mouseout(function(){
// Reset up/down buttons to their normal appearance when mouse moves away:
$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);
this.spinCfg._direction = null;
})
.mousedown(function(e){
if (this.spinCfg._direction != 0) {
// Respond to click on one of the buttons:
var self = this;
var adjust = function() {
self.adjustValue(self.spinCfg._direction * self.spinCfg.step);
};
adjust();
// Initial delay before repeating adjustment
self.spinCfg._delay = window.setTimeout(function() {
adjust();
// Repeat adjust at regular intervals
self.spinCfg._repeat = window.setInterval(adjust, self.spinCfg.interval);
}, self.spinCfg.delay);
}
})
.mouseup(function(e){
// Cancel repeating adjustment
window.clearInterval(this.spinCfg._repeat);
window.clearTimeout(this.spinCfg._delay);
})
.dblclick(function(e) {
if ($.browser.msie)
this.adjustValue(this.spinCfg._direction * this.spinCfg.step);
})
.keydown(function(e){
// Respond to up/down arrow keys.
switch(e.keyCode){
case 38: this.adjustValue(this.spinCfg.step); break; // Up
case 40: this.adjustValue(-this.spinCfg.step); break; // Down
case 33: this.adjustValue(this.spinCfg.page); break; // PageUp
case 34: this.adjustValue(-this.spinCfg.page); break; // PageDown
}
})
/*
http://unixpapa.com/js/key.html describes the current state-of-affairs for
key repeat events:
- Safari 3.1 changed their model so that keydown is reliably repeated going forward
- Firefox and Opera still only repeat the keypress event, not the keydown
*/
.keypress(function(e){
if (this.repeating) {
// Respond to up/down arrow keys.
switch(e.keyCode){
case 38: this.adjustValue(this.spinCfg.step); break; // Up
case 40: this.adjustValue(-this.spinCfg.step); break; // Down
case 33: this.adjustValue(this.spinCfg.page); break; // PageUp
case 34: this.adjustValue(-this.spinCfg.page); break; // PageDown
}
}
// we always ignore the first keypress event (use the keydown instead)
else {
this.repeating = true;
}
})
// clear the 'repeating' flag
.keyup(function(e) {
this.repeating = false;
this.adjustValue(0);
})
.bind("mousewheel", function(e){
// Respond to mouse wheel in IE. (It returns up/dn motion in multiples of 120)
if (e.wheelDelta >= 120)
this.adjustValue(this.spinCfg.step);
else if (e.wheelDelta <= -120)
this.adjustValue(-this.spinCfg.step);
e.preventDefault();
})
.change(function(e){
this.adjustValue(0);
});
if (this.addEventListener) {
// Respond to mouse wheel in Firefox
this.addEventListener('DOMMouseScroll', function(e) {
if (e.detail > 0)
this.adjustValue(-this.spinCfg.step);
else if (e.detail < 0)
this.adjustValue(this.spinCfg.step);
e.preventDefault();
}, false);
}
});
function coord(el,prop) {
var c = el[prop], b = document.body;
while ((el = el.offsetParent) && (el != b)) {
if (!$.browser.msie || (el.currentStyle.position != 'relative'))
c += el[prop];
}
return c;
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -3,9 +3,11 @@
<head>
<link rel="stylesheet" href="jpicker/jpicker.css" type="text/css"/>
<link rel="stylesheet" href="svg-editor.css" type="text/css"/>
<link rel="stylesheet" href="spinbtn/JQuerySpinBtn.css" type="text/css"/>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<script type="text/javascript" src="js-hotkeys/jquery.hotkeys.min.js"></script>
<script type="text/javascript" src="jpicker/jpicker.js"></script>
<script type="text/javascript" src="spinbtn/JQuerySpinBtn.js"></script>
<script type="text/javascript" src="svgcanvas.js"></script>
<script type="text/javascript" src="svg-editor.js"></script>
<title>SVG-edit demo</title>
@ -70,18 +72,7 @@
<label class="rect_tool">height:</label>
<input id="rect_h" class="rect_tool attr_changer" title="Change rectangle height" alt="height" size="3"/>
<label class="rect_tool">Corner Radius:</label>
<!-- TODO: turn this into a spinner control! -->
<select id="rect_radius" class="rect_tool" title="Change rectangle corner radius" alt="Corner Radius">
<option selected="selected" value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="5">5</option>
<option value="7">7</option>
<option value="10">10</option>
<option value="15">15</option>
<option value="20">20</option>
</select>
<input id="rect_radius" size="3" value="0" class="rect_tool" type="text" title="Change Rectangle Corner Radius" alt="Corner Radius"/>
</div>
<div id="circle_panel">
@ -182,22 +173,16 @@
<td><div id="stroke_color" class="color_block" title="Change stroke color"></div></td>
<td><div id="stroke_opacity">100 %</div></td>
<td>
<select id="stroke_width" title="Change stroke width">
<option selected="selected" value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="5">5</option>
<option value="7">7</option>
</select>
<input id="stroke_width" title="Change stroke width" alt="Stroke Width" size="2" value="1" type="text"/>
</td>
<td>
<select id="stroke_style" title="Change stroke dash style">
<option selected="selected" value="none">---</option>
<option value="2,2">...</option>
<option value="5,5">- -</option>
<option value="5,2,2,2">- .</option>
<option value="5,2,2,2,2,2">- ..</option>
</select>
<option selected="selected" value="none">---</option>
<option value="2,2">...</option>
<option value="5,5">- -</option>
<option value="5,2,2,2">- .</option>
<option value="5,2,2,2,2,2">- ..</option>
</select>
</td>
</tr>
</table>

View File

@ -193,9 +193,9 @@ function svg_edit_setup() {
pos = $('#tools_ellipse_show').position();
$('#tools_ellipse').css({'left': pos.left+4, 'top': pos.top+70});
$('#stroke_width').change(function(){
svgCanvas.setStrokeWidth(this.options[this.selectedIndex].value);
});
function changeStrokeWidth(ctl) {
svgCanvas.setStrokeWidth(ctl.value);
}
$('#stroke_style').change(function(){
svgCanvas.setStrokeStyle(this.options[this.selectedIndex].value);
@ -217,10 +217,10 @@ function svg_edit_setup() {
svgCanvas.setTextContent(this.value);
});
$('#rect_radius').change(function(){
svgCanvas.setRectRadius(this.options[this.selectedIndex].value);
});
function changeRectRadius(ctl) {
svgCanvas.setRectRadius(ctl.value);
}
$('.attr_changer').change(function() {
svgCanvas.changeSelectedAttribute(this.getAttribute("alt"), this.value);
});
@ -618,5 +618,8 @@ function svg_edit_setup() {
svgCanvas.setResolution(x,y);
});
$('#rect_radius').SpinButton({ min: 0, max: 1000, step: 1, callback: changeRectRadius });
$('#stroke_width').SpinButton({ min: 1, max: 99, step: 1, callback: changeStrokeWidth });
return svgCanvas;
};