chart.redraw() not working after setting event-line
Asked Answered
L

1

9

I'm using the morris.js chart along with the bootstrap slider.

What I want to do:
If the slider is moved, I want to insert an event-line into the chart at the position of the sliders value. Nothing special.

The problem:
The chart isn't redrawing after setting the event. When inserting new data, the chart will be redrawn automatically. So I tried refreshing (to check for correct syntax) by passing the existing data to the chart again like this:

chart.setData(chart.options.data);

This is working! The new event gets drawn into the chart. Unfortunately this has a bad performance as the chart is redrawing all the data.

The documentation says there is chart.redraw(). It's just not working for me. Maybe someone of you can find out why.

Just run the snippet and switch the radio-buttons to test both methods and you'll see the problem.

// Chart creation - not interesting
var chart = new Morris.Line({
  element: 'chart',
  ymin: 0,
  ymax: 100,
  gridIntegers: true,
  parseTime:false,
  // Will be set below
  data: [  ],
  xkey: 'position',
  ykeys: ['value'],
  labels: ['Value'],
  hideHover: "always",
  pointSize: 0,
  continuousLine: false,
  goalStrokeWidth: 3,
  axes: true,
  grid: true,
  numLines: 6,
  eventLineColors: [ "red" ],
  smooth: true
});

// Inserting some values
var values = [101]
for(i = 1; i <= 100; i += 1) {
    var x = 100/(Math.pow((i-50), 2)+4);
    values.push({ position: i, value: x });
}
chart.setData(values);

// Create slider
$('#slider').slider({
  tooltip: 'never',
  tooltip_position:'left',
  height: 300,
  length: 300,
});

// If the slider moves, I want to set its value as an event-line
$("#slider").on("slideStop", function(slideEvt) {
    chart.options.events = [ slideEvt.value ];

    // Check inserting-data VS chart.redraw()
    // Both should work... chart.redraw() isnt.
    if(document.getElementById('insert').checked)
        chart.setData(chart.options.data);
    else if(document.getElementById('redraw').checked)
        chart.redraw();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="http://cdn.oesmith.co.uk/morris-0.5.1.min.js"></script>
<link href="http://cdn.oesmith.co.uk/morris-0.5.1.css" rel="stylesheet"/>

<!-- Bootstrap slider -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.2/bootstrap-slider.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.2/css/bootstrap-slider.min.css">

<div id="chart" style="height: 150px;width:500px;"></div>
<form action="">
    <input checked="true" id="insert" type="radio" name="refreshMethod"> Insert (working)<br>
    <input id="redraw" type="radio" name="refreshMethod"> Redraw (not working)<br>
</form>
<input id="slider" type="text" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="50"/>

I appreciate every help in here. Thank you very much!

Important edit:
As soon as I can set a bounty (+1 hour) I'll do so. A very important additional part of this question is how to bind the slider to the single chart-event without lagging around. Currently the performance is very low when using the slide event instead of slideStop.

Longdrawnout answered 3/4, 2017 at 12:33 Comment(1)
"The documentation says there is chart.redraw(). " - could you point out where/which document you are making reference to? I could not find it (see links in my answer)Permeability
U
2

It's not working because internally chart.events is not being set when you call chart.redraw(). This property is set inside setData with the line this.events = this.options.events.

To correct for this: In your code use chart.events = [val] rather than chart.options.events = [val];

Personally, I'd set them both in case setData is called again, but that's up to you.

So in your demo:

...
else if(document.getElementById('redraw').checked) {
    chart.events = [ slideEvt.value ];
    chart.redraw();
}

EDIT:

Added a chart.quickRedraw function. This removes unnecessary recalculations from the redraw function (refer to the commented out code for what is now excluded):

chart.quickRedraw = function() {
      this.raphael.clear();
      //this._calc();
      this.drawGrid();
      //this.drawGoals();
      this.drawEvents();
      this.draw();      
};

Demo has been updated with the third option.

// Chart creation - not interesting
var chart = new Morris.Line({
  element: 'chart',
  ymin: 0,
  ymax: 100,
  gridIntegers: true,
  parseTime:false,
  // Will be set below
  data: [  ],
  xkey: 'position',
  ykeys: ['value'],
  labels: ['Value'],
  hideHover: "always",
  pointSize: 0,
  continuousLine: false,
  goalStrokeWidth: 3,
  axes: true,
  grid: true,
  numLines: 6,
  eventLineColors: [ "red" ],
  smooth: true
});

// Inserting some values
var values = [101]
for(i = 1; i <= 100; i += 1) {
    var x = 100/(Math.pow((i-50), 2)+4);
    values.push({ position: i, value: x });
}
chart.setData(values);

// Create slider
$('#slider').slider({
  tooltip: 'never',
  tooltip_position:'left',
  height: 300,
  length: 300,
});

// If the slider moves, I want to set its value as an event-line
$("#slider").on("slideStop", function(slideEvt) {
    chart.options.events = [ slideEvt.value ];

    // Check inserting-data VS chart.redraw()
    // Both should work... chart.redraw() isnt.
    if(document.getElementById('insert').checked)
        chart.setData(chart.options.data);
    else if(document.getElementById('redraw').checked) {
        chart.events = [ slideEvt.value ];
        chart.redraw();
    } else if(document.getElementById('quickerRedraw').checked) {
        chart.events = [ slideEvt.value ];
        chart.quickRedraw();
    }
});

chart.quickRedraw = function() {
      this.raphael.clear();
      //this._calc();
      this.drawGrid();
      //this.drawGoals();
      this.drawEvents();
      this.draw();
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="http://cdn.oesmith.co.uk/morris-0.5.1.min.js"></script>
<link href="http://cdn.oesmith.co.uk/morris-0.5.1.css" rel="stylesheet"/>

<!-- Bootstrap slider -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.2/bootstrap-slider.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.2/css/bootstrap-slider.min.css">

<div id="chart" style="height: 150px;width:500px;"></div>
<form action="">
    <input checked="true" id="insert" type="radio" name="refreshMethod"> Insert (working)<br>
    <input id="redraw" type="radio" name="refreshMethod"> Redraw (working)<br>
    <input id="quickerRedraw" type="radio" name="refreshMethod"> Quicker Redraw<br>
</form>
<input id="slider" type="text" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="50"/>
Undersell answered 6/4, 2017 at 11:59 Comment(1)
I've updated the answer to include an alternative faster redraw function, by removing some of the unneeded redraw code. Refer to the edit for detailsUndersell

© 2022 - 2024 — McMap. All rights reserved.