最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How would you create a JQuerysvg click-drag select outline effect? - Stack Overflow

programmeradmin3浏览0评论

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.

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.

Share Improve this question edited Jul 26, 2012 at 16:38 Phrogz 303k113 gold badges667 silver badges756 bronze badges asked Jul 26, 2012 at 16:15 jmheadjmhead 9072 gold badges13 silver badges26 bronze badges 2
  • The term you are looking for is "marquee" or possibly "marching ants". Do you want it to be animated while drawn, or just a dotted border? Does it need to be dotted? (Note that Windows 7 just uses a semi-opaque rectangle with more-opaque stroking for its drag selection.) – Phrogz Commented Jul 26, 2012 at 16:38
  • The selection box size just needs to change while being selected - animation isn't important - part of a user app interface – jmhead Commented Jul 26, 2012 at 21:20
Add a comment  | 

2 Answers 2

Reset to default 15

Here's a demo I made just for you :)

Demo (Static): http://jsfiddle.net/HNH2f/1/

Demo (Animated): http://jsfiddle.net/HNH2f/2/

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.

发布评论

评论列表(0)

  1. 暂无评论