How to setup Flot for iOS retina display
flot, ios, ipad, retina-display
Solution
I have modified jquery.flot.js like this:
In the top I have added
retinaMode = (window.devicePixelRatio > 1),
I have extended these functions
function makeCanvas(skipPositioning, cls) {
var c = document.createElement('canvas');
c.className = cls;
c.width = canvasWidth;
c.height = canvasHeight;
if (!skipPositioning)
$(c).css({ position: 'absolute', left: 0, top: 0 });
$(c).appendTo(placeholder);
if(retinaMode) {
c.width = canvasWidth * 2;
c.height = canvasHeight * 2;
c.style.width = '' + canvasWidth + 'px';
c.style.height = '' + canvasHeight + 'px';
}
if (!c.getContext) // excanvas hack
c = window.G_vmlCanvasManager.initElement(c);
// used for resetting in case we get replotted
c.getContext("2d").save();
if (retinaMode) {
c.getContext("2d").scale(2,2);
}
return c;
}
function getCanvasDimensions() {
canvasWidth = placeholder.width();
canvasHeight = placeholder.height();
if (canvasWidth <= 0 || canvasHeight <= 0)
throw "Invalid dimensions for plot, width = " + canvasWidth + ", height = " + canvasHeight;
}
function resizeCanvas(c) {
// resizing should reset the state (excanvas seems to be
// buggy though)
if (c.width != canvasWidth) {
c.width = canvasWidth;
if(retinaMode) {
c.width = canvasWidth * 2;
}
c.style.width = '' + canvasWidth + 'px';
}
if (c.height != canvasHeight) {
c.height = canvasHeight;
if(retinaMode) {
c.height = canvasHeight * 2;
}
c.style.height = '' + canvasHeight + 'px';
}
// so try to get back to the initial state (even if it's
// gone now, this should be safe according to the spec)
var cctx = c.getContext("2d");
cctx.restore();
// and save again
cctx.save();
if(retinaMode) {
cctx.scale(2, 2);
}
}
Problem
I have tested this on an iPad (3 generation). The line chart appears perfectly smooth. http://justindarc.github.com/flot.touch/example/index.html I have tried diffing the code with my flot code and cannot see any significant difference that would cause it to run in retina mode. My flot is version 0.7, same as his code. No matter what I try my own chart runs in non-retina mode. What is the trick in running retina mode? My setup code is rather long. ``` function setup_chart0(setup_options) { var point_data = []; if(setup_options.use_sample_data_for_chart0) { point_data = generate_dummy_data( setup_options.timestamp_generate_min, setup_options.timestamp_generate_max ); } var average_data = henderson23(point_data); var datasets = make_chart0_datasets(point_data, average_data); if(is_dualaxis_detail_mode) { datasets = make_chart0_dual_datasets( [], [], [], [] ); } var options = default_plot_options(); options.xaxis.min = setup_options.timestamp_visible_min; options.xaxis.max = setup_options.timestamp_visible_max; options.xaxis.panRange = [setup_options.timestamp_pan_min, setup_options.timestamp_pan_max]; options.yaxis.min = -0.025; options.yaxis.max = 1.025; options.yaxis.panRange = [-0.025, 1.025]; options.legend = { container: '#legend0', noColumns: 2 }; options.grid.markings = compute_markings_with_alertlevels; if(is_dualaxis_detail_mode) { options.y2axis = {}; options.y2axis.position = "right"; options.y2axis.min = -0.025; options.y2axis.max = 1.025; options.y2axis.panRange = [-0.025, 1.025]; options.legend = { container: '#legend_hidden', noColumns: 2 }; } //save_as_file({ samples: point_data, average: average_data }); var el_placeholder0 = $("#placeholder0"); if(el_placeholder0.length){ //console.log('plotting chart 0'); var fade = false; var el = el_placeholder0; var el_outer = $("#placeholder0_outer"); var original_offset = el_outer.offset(); if(fade) { el_outer.offset({ top: -5000, left: 0 }); // move plot container off screen } chart0 = $.plot(el, datasets, options); if(fade) { el.hide(); // hide plot - must do *after* creation el_outer.offset(original_offset); // put plot back where it belongs el.fadeIn('slow'); // fade in } /*var s = ' width: ' + chart0.width() + ' height: ' + chart0.height(); $('#label0').append(s);*/ if(solo_pan_mode) { el.bind('plotpan', function (event, plot) { set_data_should_redraw_chart0 = true; set_data_should_redraw_chart1 = false; set_data_should_redraw_chart2 = false; fetch_data_for_chart(chart0, setup_options.timestamp); show_loading_empty('#loader1'); show_loading_empty('#loader2'); }); el.bind('plotpanend', function (event, plot) { set_data_should_redraw_chart0 = true; set_data_should_redraw_chart1 = true; set_data_should_redraw_chart2 = true; copy_min_max(chart0, chart1, '#placeholder1'); copy_min_max(chart0, chart2, '#placeholder2'); hack_hide_loading_wheels = true; maybe_hide_loading_wheels(); }); } else { el.bind('plotpan', function (event, plot) { fetch_data_for_chart(chart0, setup_options.timestamp); sync_with_chart0(); }); } } } ```