0

I'm building a graph displaying events happening over time. Each of my event is an horizontal bar that is created using a <div> as shown below:

<div class="aaaa" style="margin-left: 0.00%; width:100.00%;">aaaa</div>
<div class="aaaa" style="margin-left: 5.00%; width: 20.00%;">bbbb</div>
<div class="aaaa" style="margin-left:25.00%; width: 50.00%;">cccc</div>
<div class="aaaa" style="margin-left:55.00%; width: 45.00%;">dddd</div>

At the top of this graph, I have a "ruler" which is a draggable and resizable <div>

<div id="draggable2" class="draggable ui-widget-content">
    <p>Ruler</p>
</div>

My intention is to drag this ruler horizontally and to use it to select all bars of my graphs that are below the ruler. When bars are selected, the background color should change.

So far I manage to drag and to resize my ruler as I want with the following code:

$(function () {
    $("#draggable2").draggable({
        axis: "x"
    });
});

$(function () {
    $("#draggable2").resizable({
        helper: "ui-resizable-helper",
        handles: "se, sw, e, w"
    });
});

I also manage to select the bars I want using the following code:

$(".fake").selectable({
    filter: "div"
});

You can see on the fiddle referenced below that when you do a "lasso selection", my bars become pink.

However, I would like to combine my ruler with this "lasso selection", or in other words, I would like that once my ruler is dragged, all <div> that are below become selected.

I've created a fiddle to illustrate my problem: http://jsfiddle.net/Lge93/

As I'm new to Javascript and Jquery, I would really appreciate any solution or suggestion.

Thanks for your time

Edit post answers: My final solution based on the code provided by Jtromans is available here: http://jsfiddle.net/Lge93/5/

  • It's a little buggy - it works fine on drag but not when you resize the ruler. You need to begin dragging it again for it to notice the resize has taken place. – jtromans Nov 13 '13 at 16:00

2 Answers2

1

Here's my solution:

$(function() {
  $( "#draggable2" ).draggable({ 
    axis: "x",
    drag: function(e) {
        var selectableElements = $(".fake").data().uiSelectable.selectees;
        var ruler = $(e.target);

        $.each(selectableElements, function(i, v) {
            if(ruler.offset().left >= $(v).offset().left) {
                $(v).addClass("ui-selected");
              }else {
                 $(v).hasClass("ui-selected") && $(v).removeClass("ui-selected");                    
            }
           });
        }

    });
});

$(function() {
  $( "#draggable2" ).resizable({
    helper: "ui-resizable-helper",
    handles: "se, sw, e, w"
  });
});

$(".fake").selectable({filter:"div"});

http://jsfiddle.net/Lge93/3/

silicakes
  • 6,364
  • 3
  • 28
  • 39
  • Thanks for this piece of code and the fiddle. As a newbie, I have to digest all this knew stuff and to adapt it but I know where to go ! – user2987076 Nov 13 '13 at 11:20
0

If I understand your question correctly, it sounds like you could solve the problem in the following way.

Upon interacting with the ruler, you will be able to calculate the new width, x- and y-coordinates. This is pretty straight forward and requires only a few lines of jQuery code in the callback after any form of interaction with your ruler.

You could then check for each item in your (gant?) chart to see whether it occupies any of the same area that the ruler does. This would be relative to the parent container.

The devil is in the detail for how you would like to handle whether the ruler is 'in' the Gant chart div item. And below is some code to get your started on working out whether the Ruler occupies the some of the same location as the other divs:

function checkOverlays (x, width, y, height) {
    $(".aaaa").each (function (i,e) {
        var thisWidth = $(this).width();
        var thisHeight = $(this).height();
        var offsetTop = $(this).offset().top - $(this).parent().offset().top;
        var offsetLeft = $(this).offset().left - $(this).parent().offset().left;
        console.log('x coverage: ' + offsetLeft + " to " + parseFloat(thisWidth + offsetLeft));
        console.log('y coverage: ' + offsetTop + " to " + parseFloat(thisHeight + offsetTop));

        if (offsetLeft > x && offsetLeft < parseFloat(x + width) ) {
            console.log("I'm in the same x space");
            $(this).css('background-color', 'red');
        }

        if (offsetTop > y && offsetTop < parseFloat(y + height) ) {
            console.log("I'm in the same y space");
            $(this).css('background-color', 'red');
        }
    })
}



$("#draggable2").on("resize drag", function () {
    var thisWidth = $(this).width();
    var thisHeight = $(this).height();
    var offsetTop = $(this).offset().top - $(this).parent().offset().top;
    var offsetLeft = $(this).offset().left - $(this).parent().offset().left;
    console.log('x coverage: ' + offsetLeft + " to " + parseFloat(thisWidth + offsetLeft));
    console.log('y coverage: ' + offsetTop + " to " + parseFloat(thisHeight + offsetTop));

    checkOverlays (offsetLeft, thisWidth, offsetTop, thisHeight)
});
jtromans
  • 4,183
  • 6
  • 35
  • 33
  • Thanks for your answer. I understand the logic and I will go in this direction unless I get an easier solution :-). To answer two of your comments: 1) yes, my graph is a kind of gant chart. 2) In my example, the resize is working on a div but I can't say if it works for any element. – user2987076 Nov 13 '13 at 10:55
  • I've just seen the update of your code, this is really useful especially the console.log information which allows to see exactly what's going on. I think I have enough material now to play with and to implement all possible cases (bar inside ruler, left or right side of ruler inside bar and so on). Thanks again for your help. – user2987076 Nov 13 '13 at 11:16
  • No problem, if you got Qs, just post back. – jtromans Nov 13 '13 at 11:20
  • I have it working fine now. The console.log was really helpful. – user2987076 Nov 13 '13 at 15:07