Can I draw a line using jQuery?
Asked Answered
P

5

9

I have a web app where I would like the user to draw a line in the following way: When he clicks on Point1 and he moves the mouse, draw the line from Point1 to the current mouse position and, when clicks to Point2 draw the final line from Point1 to Point2.

How can I do it using jQuery and/or one of its plugins?

Prophesy answered 31/7, 2012 at 15:17 Comment(2)
Using html5 canvas you should be able to do this with just an onclick event but I have no experience with canvas myself. All jQuery will do for you is the event binding and getting the mouse position.Eulogia
Google is your friend: amaslo.com/2012/06/drawing-diagonal-line-in-htmlcssjs-with.htmlStirpiculture
C
6

Challenge accepted.

I tried to do it with CSS transforms and a bunch of Math in Javascript - after half an hour I have this:

http://jsfiddle.net/VnDrb/2/

Make 2 clicks into the gray square and a line should be drawn. There is still a small bug that draws the line wrong when the angle is > 45 degree. Maybe someone else knows how to fix that. Maybe instead of using Math.asin (arcsinus), use a other trigonometrical function, but I'm really not good at it. I thought I'd post it even there is a small bug, I think it's a good start for you.

Concertize answered 31/7, 2012 at 16:14 Comment(2)
Doesn't work so well, but it's fun! And well done for a good try!Mathieu
Oh, Great man! This is really good, and you spent time to make it. This gave me ideaCerebro
W
4

I've tried a number of different approaches this weekend and the solution that worked best for me is from Adam Sanderson: http://monkeyandcrow.com/blog/drawing_lines_with_css3/

His demo is here: http://monkeyandcrow.com/samples/css_lines/

The core of it is very simple, which is always good.

div.line{
  transform-origin: 0 100%;
  height: 3px; /* Line width of 3 */
  background: #000; /* Black fill */
}


function createLine(x1,y1, x2,y2){
  var length = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
  var angle  = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
  var transform = 'rotate('+angle+'deg)';

    var line = $('<div>')
      .appendTo('#page')
      .addClass('line')
      .css({
        'position': 'absolute',
        'transform': transform
      })
      .width(length)
      .offset({left: x1, top: y1});

  return line;
}
Wamsley answered 15/6, 2014 at 0:4 Comment(0)
S
2

You can not do it with jQuery and classic HTML.

  1. You can do it using SVG (+svgweb for IE8- http://code.google.com/p/svgweb/ ) SVG can be dynamically created. jQuery + svgweb are working perfectly, you just need to know how to create SVG nodes and you need only jquerify this nodes. After jquerifiing in most cases used only one method attr()

  2. You can do it using Raphael http://raphaeljs.com/ (based on SVG and VML)

  3. You can do it using Canvas ( http://flashcanvas.net/ for IE8- )


For SVG programming will be this way:

  1. Moment of creating first point: you create empty line var Line (also this points coordinates will be x1 and y1)

  2. Then you bind on mousemove repaint of x2, y2 properties of Line

  3. On mousedown after mousemove you freeze last line position.


UPDATE

You can do it with CSS/JS, but main problem is in calculations for IE8-, that has only Matrix filter for transformations.

Snubnosed answered 31/7, 2012 at 15:20 Comment(4)
Hate to be that guy, but you could do it with only JS and HTML. I'm just not good enough at trigonometry to whip up a quick answer. You would need one element with a CSS rotation and a single border.Mathieu
And how many problems you will get from filters in IE? It has only Matrix filter for transformations, that have many problems with calculations.Snubnosed
Also it will be not best performance to animate (I mean change on every mousemove) IE filterSnubnosed
There are a whole bunch of ways to approach this problem, and I think your answer is good so I upvoted it. I just don't agree with you when you say “You can not do it with jQuery and classic HTML.”Mathieu
C
0

Been using a modified version of this for a while now. Works well.

http://www.ofdream.com/code/css/xline2.php

So on first click, drop and object there as a placeholder div, maybe a little circle, then either keep redrawing a line as they move their mouse, or draw it when they click the second time, using the original placeholder as a guide.

I recently made another helper function for this, because my tool involves moving lines around:

function setLinePos(x1, y1, x2, y2, id) {
    if (x2 < x1) {
        var temp = x1;
        x1 = x2;
        x2 = temp;
        temp = y1;
        y1 = y2;
        y2 = temp;
    }
    var line = $('#line' + id);
    var length = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    line.css('width', length + "px");
    var angle = Math.atan((y2 - y1) / (x2 - x1));
    line.css('top', y1 + 0.5 * length * Math.sin(angle) + "px");
    line.css('left', x1 - 0.5 * length * (1 - Math.cos(angle)) + "px");
    line.css('-moz-transform', "rotate(" + angle + "rad)");
    line.css('-webkit-transform', "rotate(" + angle + "rad)");
    line.css('-o-transform', "rotate(" + angle + "rad)");

 }

That is the jquery version, and in this iteration I have no IE requirement so I ignore it. I could be adapted from the original function pretty easily.

Clough answered 28/6, 2013 at 16:51 Comment(0)
K
0

The class

function getXY(evt, element) {
    var rect = element.getBoundingClientRect();
    var scrollTop = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft;
    var elementLeft = rect.left + scrollLeft;
    var elementTop = rect.top + scrollTop;

    x = evt.pageX - elementLeft;
    y = evt.pageY - elementTop;
    return { x: x, y: y };
}
var LineDrawer = {
    LineHTML: `<div style="cursor: pointer;transform-origin:center; position:absolute;width:200px;height:2px; background-color:blue"></div>`,
    isDown: false,
    pStart: {},
    pCurrent :{},
    containerID: "",
    JLine: {},
    angle: 0,
    afterLineCallback: null,
    Init: function (containerID, afterLineCallback) {
        LineDrawer.containerID = containerID;
        LineDrawer.afterLineCallback = afterLineCallback;
        LineDrawer.JLine = $(LineDrawer.LineHTML).appendTo("#" + LineDrawer.containerID);
        LineDrawer.JLine.css("transform-origin", "top left");
        LineDrawer.JLine.hide();
        //LineDrawer.JLine.draggable({ containment: "#" + LineDrawer.containerID });
        $("#" + LineDrawer.containerID).mousedown(LineDrawer.LineDrawer_mousedown);
        $("#" + LineDrawer.containerID).mousemove(LineDrawer.LineDrawer_mousemove);
        $("#" + LineDrawer.containerID).mouseup(LineDrawer.LineDrawer_mouseup);
    },
    LineDrawer_mousedown: function (e) {
        if (e.target === LineDrawer.JLine[0]) return false;
        LineDrawer.isDown = true;
        let p = LineDrawer.pStart = getXY(e, e.target);
        LineDrawer.JLine.css({ "left": p.x, "top": p.y, "width": 1});
        LineDrawer.JLine.show();
    },
    LineDrawer_mousemove: function (e) {
        if (!LineDrawer.isDown) return;
        LineDrawer.pCurrent = getXY(e, document.getElementById("jim"));
        let w = Math.sqrt(((LineDrawer.pStart.x - LineDrawer.pCurrent.x) * (LineDrawer.pStart.x - LineDrawer.pCurrent.x)) + ((LineDrawer.pStart.y - LineDrawer.pCurrent.y) * (LineDrawer.pStart.y - LineDrawer.pCurrent.y)));
        LineDrawer.JLine.css("width", w - 2);
        LineDrawer.angle = Math.atan2((LineDrawer.pStart.y - LineDrawer.pCurrent.y), (LineDrawer.pStart.x - LineDrawer.pCurrent.x)) * (180.0 / Math.PI);
        //the below ensures that angle moves from 0 to -360
        if (LineDrawer.angle < 0) {
            LineDrawer.angle *= -1;
            LineDrawer.angle += 180;
        }
        else LineDrawer.angle = 180 - LineDrawer.angle;
        LineDrawer.angle *= -1;

        LineDrawer.JLine.css("transform", "rotate(" + LineDrawer.angle + "deg");

    },
    LineDrawer_mouseup: function (e) {
        LineDrawer.isDown = false;
        if (LineDrawer.afterLineCallback == null || LineDrawer.afterLineCallback == undefined) return;
        LineDrawer.afterLine(LineDrawer.angle, LineDrawer.pStart, LineDrawer.pCurrent);
    },
};

Usage:

var ECApp = {
    start_action: function () {
        LineDrawer.Init("jim", ECApp.afterLine);            
    },
    afterLine(angle, pStart, pEnd) {
        //$("#angle").text("angle : " + angle);
        let disp = "angle = " + angle;
        disp += " Start = " + JSON.stringify(pStart) + " End = " + JSON.stringify(pEnd);
        //alert(disp);
        $("#angle").text("angle : " + disp);
    }
}
$(document).ready(ECApp.start_action);

HTML

<div class="row">
<div class="col">
    <div id="jim" style="position:relative;width:1200px;height:800px;background-color:lightblue;">            
    </div>
</div>

Kierakieran answered 31/1, 2020 at 7:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.