1

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)

sdabet
  • 18,360
  • 11
  • 89
  • 158
  • Please post some of own work or a fiddle for better understanding, yes it is possible. – MarmiK Sep 20 '13 at 06:59
  • I updated my question. But the point is I have no idea where to start with. – sdabet Sep 20 '13 at 08:04
  • I was studying that part in detail you need to start with SVG commands, as Kendo it self uses SVG in the back-end of chart see the source of generated chart http://jsfiddle.net/MarmeeK/kHp5G/1/ – MarmiK Sep 20 '13 at 08:07
  • Yep, I guess we could get inspiration from this highcharts plugin which obviously uses SVG too: http://jsfiddle.net/highcharts/AyUbx/ – sdabet Sep 20 '13 at 08:51
  • Yup, its ready to use function, but if the constraint is Kendo, we have too many work to do. drag and drop is supported by kendo but not in Charts. So we need to manually define each event and its functions. – MarmiK Sep 20 '13 at 09:01
  • Don't you think the plugin's code could be adapted to Kendo chart? https://rawgithub.com/highslide-software/draggable-points/master/draggable-points.js – sdabet Sep 20 '13 at 09:04
  • NO it can't be it handles many thing within function.. – MarmiK Sep 20 '13 at 09:39

2 Answers2

2

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 ...

Community
  • 1
  • 1
SpaceDog
  • 3,249
  • 1
  • 17
  • 25
  • Thanks a lot for this in-depth answer. Your fiddle looks great. I will take some time to fully understand it and definitely validate this answer if I succeed in using it. – sdabet Sep 20 '13 at 13:06
  • Thank you for Finding a way to convert SVG to HTML(SVG) :), that does to trick :) – MarmiK Sep 23 '13 at 10:05
  • @SpaceDog Do you have any idea on how to convert mouse event's Y coordinate to chart value? – sdabet Sep 24 '13 at 15:24
  • 1
    @fiddler, heh -- I didn't do that part because I couldn't see an easy way. What you need to get is the bounding box of the plot area -- this is all contained in the first inner `g` element in SVG, it also looks like the second path in the SVG defines the box of the gridlines. So you could grab the path string `$(svg path).next().attr('d')` and then process it to get the min/max of the x/y values. That gives you the corners -- so you should be able to extrapolate the y position relative to that `(((maxY - minY)/(mouseY - plotAreaTopY)) * (maxScaleY - minScaleY)) + minScaleY)`. I think ;) – SpaceDog Sep 25 '13 at 01:19
0

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.

MarmiK
  • 5,639
  • 6
  • 40
  • 49