sdabet
sdabet

Reputation: 18670

Point dragging in Kendo UI line chart

I have a simple Kendo UI line chart, e.g:

    <div id="chart"></div>      
    <script>
        $("#chart").kendoChart({
            series: [{
                type: 'line',
                data: [200, 450, 300, 125]
            }]
        });
    </script>

How can I enable/implement point dragging ? (i.e I want the user to move points vertically with mouse dragging)

Upvotes: 1

Views: 2515

Answers (2)

SpaceDog
SpaceDog

Reputation: 3269

You have several problems to overcome -- one is the default behavior for click/drag/hover on the Kendo chart that I see. That should be easy enough to disable, but it depends if you want to combine some of that.

Second is refreshing the graph, Kendo's doesn't offer a 'nice' method of updating the graph without a full redraw. So we'll have to move the lines in the SVG as part of the drag. Unfortunately they're part of a path, so that's more complex.

You can definitely attach event handlers to the individual circles, you could use another framework like jQuery-UI (Draggable) to implement that. But that brings us to the third problem, you have to understand how the IDs for the different SVG elements relate to the actual data you're using. Internally it's created numerical IDs for the circles and paths on the graph -- you need to understand how those relate to the data points.

If you worked on that and had jQuery-UI accessible you try something like this (note, SVG draggable help adapted from this answer and MarmiK's fiddle).

$('circle')
    .draggable({ 
        axis: "y",
        containment: $('svg') 
     })
    .bind('mousedown', function(event, ui){
        // bring target to front
        $(event.target.parentElement).append( event.target );
    })
    .bind('drag', function(event, ui){
    // update coordinates manually, since top/left style props don't work on SVG          
    event.target.setAttribute('cy', ui.position.top + 2);

    // Update the path here, then update the data: 
    // $chart.options.series[?].data[?] = new position.
});

Fiddle

The containment needs to be just the plot area not the whole SVG, and you also need to update the PATH. You could just cheat and do the kendo .redraw() method when you drop the circle -- which will not be as slick as it could be but it will work.

Then to dynamically update the path, you can do

var path = $('#k10014').attr('d'); // Get Path
path = path.substr(1);             // Remove M 
p_array = path.split(" ");         // Split into array
p_array[7] = ui.position.top;      // Change one value (but which one?)
path = "M"+ p_array.join(" ")      // Combine back with M
$('#k10014').attr('d', path);      // Update SVG

Fiddle

So that's pretty close -- if you can work out how to relate each circle to a point in the path (and there's probably a pattern to the IDs) then you can almost certainly do it that way.

You could implement all the dragging stuff by hand if you want to avoid using jQuery-UI -- it's not that hard as the position update is already done above.

EDIT

OK, I've thought about this a bit more -- I can see that the graph itself is included inside two inner elements, so we can use jQuery to get that. Then it's easy to find the first path (which is the first line) and work out which circle we're dragging, I made a function:

// This only works for one path ... but if you know the number of points
// then you can expand this easily ... 
function movePathForPointId(element, pos) {
   // Update pos to account for the circle radius 
   pos = pos + 2;

   // The graph is in two nested <g> elements, we can use this ... 

   // First find the position of the circle,     
   var pointIndex = $('svg g g circle').index(element); 

   // Get the first path in the graph 
   var pathElement = $('svg g g path').first();

   var path = pathElement.attr('d');     // Get Path String
   path = path.substr(1);                // Remove M 
   p_array = path.split(" ");            // Split into array
   p_array[(pointIndex * 2) + 1] = pos;  // Change one value (but which one?)
   path = "M"+ p_array.join(" ")         // Combine back with M
   pathElement.attr('d', path);          // Write new path back to SVG
   element.setAttribute('cy', pos);      // Update circle position
   return pointIndex;                    // Might be useful to update the data table
}

Combining this with MarmiK's Kendo fiddle doesn't work -- the jQuery-UI events don't bind to the graph (back to problem 1 at the very start of my post). So I had to do this to get a graph I could move:

var chart = $("#chart").data("kendoChart");
var svg = chart.svg();
chart.destroy();
$("#chart").html(svg);

From there I've got a working fiddle, but it'll depend what you want to do with the data. You might need to work how to unbind the Kendo events and bind your own, or use the logic above to redo a different implementation of dragging.

But that should get you started ...

Upvotes: 2

MarmiK
MarmiK

Reputation: 5785

I have updated a fiddle for the working example of Kendo..

I have studied the parts of chart, that uses SVG to draw the chart,

I have updated the scratch model that draws chart, also have added small code that should drag,

A circle below chart. but its not dragging using kendoDraggable

Sample fiddle

Sample2 fiddle this works fine with jQuery UI for draggable, but now in graph due to SVG yet.

This should give you a good start.

Upvotes: 0

Related Questions