Not sure exactly what to call it, but I am looking for a way to create a dotted outline/selection box effect via javascript/svg when you click and drag over an area, and then goes away on mouseUp (that could be added if it wasn't an original part) .
A jQuery library would be nice if it exists. I've done some looking around, and haven't found exactly what I am looking for.
I guess the theory would be get the coord from the first click, track the mouse coord moment and adjust the box accordingly.
But not writing it from scratch would be nice.
Here's a demo I made just for you :)
You can use CSS to control the visual style of the marquee.
You can pass one or two functions to the trackMarquee
method; both will be called with four arguments: the x1,y1,x2,y2 bounds of the marquee. The first function will be called when the marquee is released. The second function (if present) will be called each time the marquee moves (so that you can, for example, calculate what items are within that bounding box).
When you start dragging on the SVG document (or whatever element you choose to track) it will create a <rect class="marquee" />
; during dragging it will adjust the size of the rectangle. Use CSS (as seen in the demo) to style this rectangle however you want. I'm using the stroke-dasharray
property to make the border dotted.
For Stack Overflow posterity, here's the code (on the off chance that JSFiddle is down):
(function createMarquee(global){
var svgNS = 'http://www.w3.org/2000/svg',
svg = document.createElementNS(svgNS,'svg'),
pt = svg.createSVGPoint();
// Usage: trackMarquee( mySVG, function(x1,y1,x2,y2){}, function(x1,y1,x2,y2){} );
// The first function (if present) will be called when the marquee is released
// The second function (if present) will be called as the marquee is changed
// Use the CSS selector `rect.marquee` to select the marquee for visual styling
global.trackMarquee = function(forElement,onRelease,onDrag){
forElement.addEventListener('mousedown',function(evt){
var point0 = getLocalCoordinatesFromMouseEvent(forElement,evt);
var marquee = document.createElementNS(svgNS,'rect');
marquee.setAttribute('class','marquee');
updateMarquee(marquee,point0,point0);
forElement.appendChild(marquee);
document.documentElement.addEventListener('mousemove',trackMouseMove,false);
document.documentElement.addEventListener('mouseup',stopTrackingMove,false);
function trackMouseMove(evt){
var point1 = getLocalCoordinatesFromMouseEvent(forElement,evt);
updateMarquee(marquee,point0,point1);
if (onDrag) callWithBBox(onDrag,marquee);
}
function stopTrackingMove(){
document.documentElement.removeEventListener('mousemove',trackMouseMove,false);
document.documentElement.removeEventListener('mouseup',stopTrackingMove,false);
forElement.removeChild(marquee);
if (onRelease) callWithBBox(onRelease,marquee);
}
},false);
};
function callWithBBox(func,rect){
var x = rect.getAttribute('x')*1,
y = rect.getAttribute('y')*1,
w = rect.getAttribute('width')*1,
h = rect.getAttribute('height')*1;
func(x,y,x+w,y+h);
}
function updateMarquee(rect,p0,p1){
var xs = [p0.x,p1.x].sort(sortByNumber),
ys = [p0.y,p1.y].sort(sortByNumber);
rect.setAttribute('x',xs[0]);
rect.setAttribute('y',ys[0]);
rect.setAttribute('width', xs[1]-xs[0]);
rect.setAttribute('height',ys[1]-ys[0]);
}
function getLocalCoordinatesFromMouseEvent(el,evt){
pt.x = evt.clientX; pt.y = evt.clientY;
return pt.matrixTransform(el.getScreenCTM().inverse());
}
function sortByNumber(a,b){ return a-b }
})(window);
You are lucky I just made this myself. I'm using jQuery SVG plugin ( http://keith-wood.name/svg.html )
$("#paper2").mousedown(function(ev) {
ev.preventDefault();
var pX= (ev.pageX - this.offsetLeft) * viewBox[2]/parseInt($("#paper2").css("width"));
var pY= (ev.pageY - this.offsetTop) * viewBox[3]/parseInt($("#paper2").css("height"));
var rect = svg2.rect(
pX, //X
pY, //Y
1,1, //width and height
{ //Settings, you can make the box dotted here
fill: 'black', "fill-opacity": 0.3, stroke: 'red', strokeWidth: 3, id:rect
}
)
$("#paper2").mousemove(function(ev) {
ev.preventDefault();
var rect= $('#rect');
var pX= (ev.pageX - this.offsetLeft) * viewBox[2]/parseInt($("#paper2").css("width")) - rect.attr("x");
var pY= (ev.pageY - this.offsetTop) * viewBox[3]/parseInt($("#paper2").css("height")) - rect.attr("y");
rect.attr("width", pX);
rect.attr("height", pY);
});
$("#paper2").mouseup(function(ev) {
ev.preventDefault();
var div= $("#paper2");
div.unbind('mousemove');
div.unbind('mouseup');
})
});
paper2 is a div in which I have an svg element (so the svg element and the div have the same height/width). This is how I created the svg2 element:
var svg2;
var root2;
$(document).ready(function() {
$("#paper2").svg({
onLoad: function() {
svg2= $("#paper2").svg('get');
svg2.configure({id: 'svg2'});
var div= $("#paper2");
root2= svg2.root();
$("#svg2").attr("viewBox", viewBox[0]+','+viewBox[1]+','+viewBox[2]+','+viewBox[3]);
},
settings: {}
});
}
If you not using viewbox on the svg element you don't need this on the calculations:
* viewBox[2]/parseInt($("#paper2").css("*****"));
viewbox[2] would be the viewbox width and viewbox[3] would be the viewbox height.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With