Blob Blame History Raw
/*
 * $Id: gnuplot_mouse.js,v 1.27 2017/02/17 20:42:17 sfeam Exp $
 */
    gnuplot.mouse_version = " 17 February 2017";

// Mousing code for use with gnuplot's 'canvas' terminal driver.
// The functions defined here assume that the javascript plot produced by
// gnuplot initializes the plot boundary and scaling parameters.

    gnuplot.mousex = 0;
    gnuplot.mousey = 0;
    gnuplot.plotx = 0;
    gnuplot.ploty = 0;
    gnuplot.scaled_x = 0;
    gnuplot.scaled_y = 0;

// These will be initialized by the gnuplot canvas-drawing function
    gnuplot.plot_xmin = 0;
    gnuplot.plot_xmax = 0;
    gnuplot.plot_ybot = 0;
    gnuplot.plot_ytop = 0;
    gnuplot.plot_width  = 0
    gnuplot.plot_height = 0
    gnuplot.plot_term_ymax = 0;
    gnuplot.plot_axis_xmin = 0;
    gnuplot.plot_axis_xmax = 0;
    gnuplot.plot_axis_width  = 0;
    gnuplot.plot_axis_height = 0;
    gnuplot.plot_axis_ymin = 0;
    gnuplot.plot_axis_ymax = 0;
    gnuplot.plot_axis_x2min = "none";
    gnuplot.plot_axis_y2min = "none";
    gnuplot.plot_logaxis_x = 0;
    gnuplot.plot_logaxis_y = 0;
    gnuplot.grid_lines = true;
    gnuplot.zoom_text = false;
    gnuplot.display_is_uptodate = false;

// These are the equivalent parameters while zooming
    gnuplot.zoom_axis_xmin = 0;
    gnuplot.zoom_axis_xmax = 0;
    gnuplot.zoom_axis_ymin = 0;
    gnuplot.zoom_axis_ymax = 0;
    gnuplot.zoom_axis_x2min = 0;
    gnuplot.zoom_axis_x2max = 0;
    gnuplot.zoom_axis_y2min = 0;
    gnuplot.zoom_axis_y2max = 0;
    gnuplot.zoom_axis_width = 0;
    gnuplot.zoom_axis_height = 0;
    gnuplot.zoom_temp_xmin = 0;
    gnuplot.zoom_temp_ymin = 0;
    gnuplot.zoom_temp_x2min = 0;
    gnuplot.zoom_temp_y2min = 0;
    gnuplot.zoom_in_progress = false;

    gnuplot.full_canvas_image = null;
    gnuplot.axisdate = new Date();

gnuplot.init = function ()
{
  if (document.getElementById("gnuplot_canvas"))
      document.getElementById("gnuplot_canvas").onmousemove = gnuplot.mouse_update;
  if (document.getElementById("gnuplot_canvas"))
      document.getElementById("gnuplot_canvas").onmouseup = gnuplot.zoom_in;
  if (document.getElementById("gnuplot_canvas"))
      document.getElementById("gnuplot_canvas").onmousedown = gnuplot.saveclick;
  if (document.getElementById("gnuplot_canvas"))
      document.getElementById("gnuplot_canvas").onkeydown = gnuplot.do_hotkey;
  if (document.getElementById("gnuplot_grid_icon"))
      document.getElementById("gnuplot_grid_icon").onmouseup = gnuplot.toggle_grid;
  if (document.getElementById("gnuplot_textzoom_icon"))
      document.getElementById("gnuplot_textzoom_icon").onmouseup = gnuplot.toggle_zoom_text;
  if (document.getElementById("gnuplot_rezoom_icon"))
      document.getElementById("gnuplot_rezoom_icon").onmouseup = gnuplot.rezoom;
  if (document.getElementById("gnuplot_unzoom_icon"))
      document.getElementById("gnuplot_unzoom_icon").onmouseup = gnuplot.unzoom;
  gnuplot.mouse_update();
}

gnuplot.getMouseCoordsWithinTarget = function(event)
{
	var coords = { x: 0, y: 0};

	if(!event) // then we're in a non-DOM (probably IE) browser
	{
		event = window.event;
		if (event) {
			coords.x = event.offsetX;
			coords.y = event.offsetY;
		}
	}
	else		// we assume DOM modeled javascript
	{
		var Element = event.target ;
		var CalculatedTotalOffsetLeft = 0;
		var CalculatedTotalOffsetTop = 0 ;

		while (Element.offsetParent)
 		{
 			CalculatedTotalOffsetLeft += Element.offsetLeft ;     
			CalculatedTotalOffsetTop += Element.offsetTop ;
 			Element = Element.offsetParent ;
 		}

		coords.x = event.pageX - CalculatedTotalOffsetLeft ;
		coords.y = event.pageY - CalculatedTotalOffsetTop ;
	}

	gnuplot.mousex = coords.x;
	gnuplot.mousey = coords.y;
}


gnuplot.mouse_update = function(e)
{
  gnuplot.getMouseCoordsWithinTarget(e);

  gnuplot.plotx = gnuplot.mousex - gnuplot.plot_xmin;
  gnuplot.ploty = -(gnuplot.mousey - gnuplot.plot_ybot);

  // Limit tracking to the interior of the plot
  if (gnuplot.plotx < 0 || gnuplot.ploty < 0){
      if (gnuplot.hypertext_list != "undefined" && gnuplot.hypertext_list.length > 0) {
	  gnuplot.check_hypertext();
      } 
      return;
  }
  if (gnuplot.mousex > gnuplot.plot_xmax || gnuplot.mousey < gnuplot.plot_ytop){
      if (gnuplot.hypertext_list != "undefined" && gnuplot.hypertext_list.length > 0) {
	  gnuplot.check_hypertext();
      } 
      return;
  }

  var axis_xmin = (gnuplot.zoomed) ? gnuplot.zoom_axis_xmin : gnuplot.plot_axis_xmin;
  var axis_xmax = (gnuplot.zoomed) ? gnuplot.zoom_axis_xmax : gnuplot.plot_axis_xmax;
  var axis_ymin = (gnuplot.zoomed) ? gnuplot.zoom_axis_ymin : gnuplot.plot_axis_ymin;
  var axis_ymax = (gnuplot.zoomed) ? gnuplot.zoom_axis_ymax : gnuplot.plot_axis_ymax;

    if (gnuplot.plot_logaxis_x != 0) {
	x = Math.log(axis_xmax) - Math.log(axis_xmin);
	x = x * (gnuplot.plotx / (gnuplot.plot_xmax-gnuplot.plot_xmin)) + Math.log(axis_xmin);
	x = Math.exp(x);
    } else {
	x =  axis_xmin + (gnuplot.plotx / (gnuplot.plot_xmax-gnuplot.plot_xmin)) * (axis_xmax - axis_xmin);
    }

    if (gnuplot.plot_logaxis_y != 0) {
	y = Math.log(axis_ymax) - Math.log(axis_ymin);
	y = y * (-gnuplot.ploty / (gnuplot.plot_ytop-gnuplot.plot_ybot)) + Math.log(axis_ymin);
	y = Math.exp(y);
    } else {
	y =  axis_ymin - (gnuplot.ploty / (gnuplot.plot_ytop-gnuplot.plot_ybot)) * (axis_ymax - axis_ymin);
    }

    if (gnuplot.plot_axis_x2min != "none") {
	gnuplot.axis_x2min = (gnuplot.zoomed) ? gnuplot.zoom_axis_x2min : gnuplot.plot_axis_x2min;
	gnuplot.axis_x2max = (gnuplot.zoomed) ? gnuplot.zoom_axis_x2max : gnuplot.plot_axis_x2max;
	if (gnuplot.x2_mapping != undefined)
	    x2 = gnuplot.x2_mapping(x);
	else
	    x2 =  gnuplot.axis_x2min + (gnuplot.plotx / (gnuplot.plot_xmax-gnuplot.plot_xmin)) * (gnuplot.axis_x2max - gnuplot.axis_x2min);
	if (document.getElementById(gnuplot.active_plot_name + "_x2"))
	    document.getElementById(gnuplot.active_plot_name + "_x2").innerHTML = x2.toPrecision(4);
    }
    if (gnuplot.plot_axis_y2min != "none") {
	gnuplot.axis_y2min = (gnuplot.zoomed) ? gnuplot.zoom_axis_y2min : gnuplot.plot_axis_y2min;
	gnuplot.axis_y2max = (gnuplot.zoomed) ? gnuplot.zoom_axis_y2max : gnuplot.plot_axis_y2max;
	if (gnuplot.y2_mapping != undefined)
	    y2 = gnuplot.y2_mapping(y);
	else
	    y2 = gnuplot.axis_y2min - (gnuplot.ploty / (gnuplot.plot_ytop-gnuplot.plot_ybot)) * (gnuplot.axis_y2max - gnuplot.axis_y2min);
	if (document.getElementById(gnuplot.active_plot_name + "_y2"))
	    document.getElementById(gnuplot.active_plot_name + "_y2").innerHTML = y2.toPrecision(4);
    }
  
  var label_x, label_y;
  if (gnuplot.polar_mode) {
    var polar = gnuplot.convert_to_polar(x,y);
    label_x = "ang= " + polar.ang.toPrecision(4);
    label_y = "R= " + polar.r.toPrecision(4);
  } else {
    if (typeof(gnuplot.plot_timeaxis_x) == "string" && gnuplot.plot_timeaxis_x != "")
      label_x = gnuplot.datafmt(x);
    else
      label_x = x.toPrecision(4);
    if (typeof(gnuplot.plot_timeaxis_y) == "string" && gnuplot.plot_timeaxis_y != "")
      label_y = gnuplot.datafmt(y);
    else
      label_y = y.toPrecision(4);
  }

  if (document.getElementById(gnuplot.active_plot_name + "_x"))
      document.getElementById(gnuplot.active_plot_name + "_x").innerHTML = label_x;
  if (document.getElementById(gnuplot.active_plot_name + "_y"))
      document.getElementById(gnuplot.active_plot_name + "_y").innerHTML = label_y;

  // Echo the zoom box interactively
  if (gnuplot.zoom_in_progress) {
    // Clear previous box before drawing a new one
    if (gnuplot.full_canvas_image == null) {
      gnuplot.full_canvas_image = ctx.getImageData(0,0,canvas.width,canvas.height);
    } else {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.putImageData(gnuplot.full_canvas_image,0,0);
    }
    ctx.strokeStyle="rgba(128,128,128,0.60)";
    var x0 = gnuplot.plot_xmin + gnuplot.zoom_temp_plotx;
    var y0 = gnuplot.plot_ybot - gnuplot.zoom_temp_ploty;
    var w = gnuplot.plotx - gnuplot.zoom_temp_plotx;
    var h = -(gnuplot.ploty - gnuplot.zoom_temp_ploty);
    if (w<0) {x0 = x0 + w; w = -w;}
    if (h<0) {y0 = y0 + h; h = -h;}
    ctx.strokeRect(x0,y0,w,h);
  }

  // See if we are over a hypertext anchor point
  if (gnuplot.hypertext_list != "undefined" && gnuplot.hypertext_list.length > 0) {
    gnuplot.check_hypertext();
  }
}

gnuplot.check_hypertext = function()
{
  var nitems = gnuplot.hypertext_list.length;
  for (var i=0; i<nitems; i++) {
    var linkx = gnuplot.hypertext_list[i].x / 10.;
    var linky = gnuplot.hypertext_list[i].y / 10.;
    if (gnuplot.zoomed) {
      var zoom = gnuplot.zoomXY(linkx,linky);
      linkx = zoom.x; linky = zoom.y;
    }
    var delx = Math.abs(gnuplot.mousex - linkx);
    var dely = Math.abs(gnuplot.mousey - linky);
    var w = gnuplot.hypertext_list[i].w / 20.;
    if (delx < w && dely < w) {
	if (i == gnuplot.on_hypertext)
	    break;
	gnuplot.on_hypertext = i;
	var text = gnuplot.hypertext_list[i].text;
	var lines = text.split('\v');
	var len = 0;
	if (lines.length <= 1) {
	    len = ctx.measureText("sans", 10, text);
	} else {
	    for (var l=0; l<lines.length; l++) {
		var ll = ctx.measureText("sans", 10, lines[l]);
		if (len < ll) len = ll;
	    }
	}

	// text shift (so it is not covered by cursor)
	var shiftx = 14;

	if (linkx > gnuplot.plot_term_xmax-(len+8) ){
	    // position text left of cursor if we are to far in the right hemisphere
	    // else we might print over the border
	    linkx = linkx - len;
	    shiftx = -shiftx;
	}
	if (linky > 14*lines.length ){
	    // position text top of cursor if we are low enough in the plot
	    // else we might print over the border
	    linky = linky - 14*lines.length;
	}

	ctx.fillStyle = "rgba(238,238,238,0.8)"
	ctx.fillRect(linkx+shiftx, linky+4, len+8, 14*lines.length);
	for (var l=0; l<lines.length; l++) {
	    ctx.drawText("sans", 10, linkx+shiftx+4, linky+14+l*14, lines[l]);
	}
	break;
    }
  } 
  if (i == nitems && gnuplot.on_hypertext >= 0) {
    gnuplot.on_hypertext = -1;
    ctx.clearRect(0,0,gnuplot.plot_term_xmax,gnuplot.plot_term_ymax);
    gnuplot.display_is_uptodate = false;
    gnuplot_canvas();
  }
}

gnuplot.datafmt = function (x)
{
  if (gnuplot.plot_timeaxis_x == "DMS") {
    return gnuplot.convert_to_DMS(x);
  }

  // gnuplot 4.6 used (x + 946684800)
  gnuplot.axisdate.setTime(1000. * x);

  if (gnuplot.plot_timeaxis_x == "DateTime") {
    return gnuplot.axisdate.toUTCString();
  } 
  if (gnuplot.plot_timeaxis_x == "Date") {
    var year = gnuplot.axisdate.getUTCFullYear();
    var month = gnuplot.axisdate.getUTCMonth();
    var date = gnuplot.axisdate.getUTCDate();
    return (" " + date).slice (-2) + "/"
         + ("0" + (month+1)).slice (-2) + "/"
	 + year;
  } 
  if (gnuplot.plot_timeaxis_x == "Time") {
    var hour = gnuplot.axisdate.getUTCHours();
    var minute = gnuplot.axisdate.getUTCMinutes();
    var second = gnuplot.axisdate.getUTCSeconds();
    return ("0" + hour).slice (-2) + ":"
         + ("0" + minute).slice (-2) + ":"
         + ("0" + second).slice (-2);
  }
}

gnuplot.convert_to_DMS = function (x)
{
    var dms = {d:0, m:0, s:0};
    var deg = Math.abs(x);
    dms.d = Math.floor(deg);
    dms.m = Math.floor((deg - dms.d) * 60.);
    dms.s = Math.floor((deg - dms.d) * 3600. - dms.m * 60.);
    fmt = ((x<0)?"-":" ")
        + dms.d.toFixed(0) + "°"
	+ dms.m.toFixed(0) + "\""
	+ dms.s.toFixed(0) + "'";
    return fmt;
}

gnuplot.convert_to_polar = function (x,y)
{
    var polar = new Object;
    var phi, r;
    phi = Math.atan2(y,x);
    if (gnuplot.plot_logaxis_r) 
        r = Math.exp( (x/Math.cos(phi) + Math.log(gnuplot.plot_axis_rmin)/Math.LN10) * Math.LN10);
    else if (gnuplot.plot_axis_rmin > gnuplot.plot_axis_rmax)
	r = gnuplot.plot_axis_rmin - x/Math.cos(phi);
    else
        r = gnuplot.plot_axis_rmin + x/Math.cos(phi);
    phi = phi * (180./Math.PI);
    if (gnuplot.polar_sense < 0)
	phi = -phi;
    if (gnuplot.polar_theta0 != undefined)
	phi = phi + gnuplot.polar_theta0;
    if (phi > 180.)
	phi = phi - 360.;
    polar.r = r;
    polar.ang = phi;
    return polar;
}

gnuplot.saveclick = function (event)
{
  gnuplot.mouse_update(event);
  var button, label_x, label_y;
  
  // Limit tracking to the interior of the plot
  if (gnuplot.plotx < 0 || gnuplot.ploty < 0) return;
  if (gnuplot.mousex > gnuplot.plot_xmax || gnuplot.mousey < gnuplot.plot_ytop) return;

  if (event.which == null) 	/* IE case */
    button= (event.button < 2) ? "LEFT" : ((event.button == 4) ? "MIDDLE" : "RIGHT");
  else				/* All others */
    button= (event.which < 2) ? "LEFT" : ((event.which == 2) ? "MIDDLE" : "RIGHT");

  if (button == "LEFT") {
    ctx.strokeStyle="black";
    ctx.strokeRect(gnuplot.mousex, gnuplot.mousey, 1, 1);
    if (typeof(gnuplot.plot_timeaxis_x) == "string" && gnuplot.plot_timeaxis_x != "")
      label_x = gnuplot.datafmt(x);
    else
      label_x = x.toPrecision(4);
    if (typeof(gnuplot.plot_timeaxis_y) == "string" && gnuplot.plot_timeaxis_y != "")
      label_y = gnuplot.datafmt(y);
    else
      label_y = y.toPrecision(4);
    click = " " + label_x + ", " + label_y;

    var len = ctx.measureText("sans", 9, click);
    if (gnuplot.mousex > gnuplot.plot_term_xmax-(len) ){
	// draw left of cursor when we are near the right side of the plot
	len += ctx.measureText("sans", 9, " ");
	ctx.drawText("sans", 9, gnuplot.mousex-len, gnuplot.mousey, click);
    } else {
	ctx.drawText("sans", 9, gnuplot.mousex, gnuplot.mousey, click);
    }
  }

  // Save starting corner of zoom box
  else {
    gnuplot.zoom_temp_xmin = x;
    gnuplot.zoom_temp_ymin = y;
    if (gnuplot.plot_axis_x2min != "none") gnuplot.zoom_temp_x2min = x2;
    if (gnuplot.plot_axis_y2min != "none") gnuplot.zoom_temp_y2min = y2;
    // Only used to echo the zoom box interactively
    gnuplot.zoom_temp_plotx = gnuplot.plotx;
    gnuplot.zoom_temp_ploty = gnuplot.ploty;
    gnuplot.zoom_in_progress = true;
    gnuplot.full_canvas_image = null;
  }
  return false; // Nobody else should respond to this event
}

gnuplot.zoom_in = function (event)
{
  if (!gnuplot.zoom_in_progress)
    return false;

  gnuplot.mouse_update(event);
 
  var button;

  if (event.which == null) 	/* IE case */
    button= (event.button < 2) ? "LEFT" : ((event.button == 4) ? "MIDDLE" : "RIGHT");
  else				/* All others */
    button= (event.which < 2) ? "LEFT" : ((event.which == 2) ? "MIDDLE" : "RIGHT");

  // Save ending corner of zoom box
  if (button != "LEFT") {
    if (x > gnuplot.zoom_temp_xmin) {
        gnuplot.zoom_axis_xmin = gnuplot.zoom_temp_xmin;
	gnuplot.zoom_axis_xmax = x;
	if (gnuplot.plot_axis_x2min != "none") {
            gnuplot.zoom_axis_x2min = gnuplot.zoom_temp_x2min;
	    gnuplot.zoom_axis_x2max = x2;
	}
    } else {
        gnuplot.zoom_axis_xmin = x;
	gnuplot.zoom_axis_xmax = gnuplot.zoom_temp_xmin;
	if (gnuplot.plot_axis_x2min != "none") {
            gnuplot.zoom_axis_x2min = x2;
	    gnuplot.zoom_axis_x2max = gnuplot.zoom_temp_x2min;
	}
    }
    if (y > gnuplot.zoom_temp_ymin) {
        gnuplot.zoom_axis_ymin = gnuplot.zoom_temp_ymin;
	gnuplot.zoom_axis_ymax = y;
	if (gnuplot.plot_axis_y2min != "none") {
            gnuplot.zoom_axis_y2min = gnuplot.zoom_temp_y2min;
	    gnuplot.zoom_axis_y2max = y2;
	}
    } else {
        gnuplot.zoom_axis_ymin = y;
	gnuplot.zoom_axis_ymax = gnuplot.zoom_temp_ymin;
	if (gnuplot.plot_axis_y2min != "none") {
            gnuplot.zoom_axis_y2min = y2;
	    gnuplot.zoom_axis_y2max = gnuplot.zoom_temp_y2min;
	}
    }
    gnuplot.zoom_axis_width = gnuplot.zoom_axis_xmax - gnuplot.zoom_axis_xmin;
    gnuplot.zoom_axis_height = gnuplot.zoom_axis_ymax - gnuplot.zoom_axis_ymin;
    gnuplot.zoom_in_progress = false;
    gnuplot.rezoom(event);
  }
  return false; // Nobody else should respond to this event
}

gnuplot.toggle_grid = function (e)
{
  if (!gnuplot.grid_lines) gnuplot.grid_lines = true;
  else gnuplot.grid_lines = false;
  ctx.clearRect(0,0,gnuplot.plot_term_xmax,gnuplot.plot_term_ymax);
  gnuplot.display_is_uptodate = false;
  gnuplot_canvas();
}

gnuplot.toggle_zoom_text = function (e)
{
  if (!gnuplot.zoom_text) gnuplot.zoom_text = true;
  else gnuplot.zoom_text = false;
  ctx.clearRect(0,0,gnuplot.plot_term_xmax,gnuplot.plot_term_ymax);
  gnuplot.display_is_uptodate = false;
  gnuplot_canvas();
}

gnuplot.rezoom = function (e)
{
  if (gnuplot.zoom_axis_width > 0)
    gnuplot.zoomed = true;
  ctx.clearRect(0,0,gnuplot.plot_term_xmax,gnuplot.plot_term_ymax);
  gnuplot.display_is_uptodate = false;
  gnuplot_canvas();
}

gnuplot.unzoom = function (e)
{
  gnuplot.zoomed = false;
  ctx.clearRect(0,0,gnuplot.plot_term_xmax,gnuplot.plot_term_ymax);
  gnuplot.display_is_uptodate = false;
  gnuplot_canvas();
}

gnuplot.zoomXY = function(x,y)
{
  var zoom = new Object;
  var xreal, yreal;

  zoom.x = x; zoom.y = y; zoom.clip = false;

  if (gnuplot.plot_logaxis_x != 0) {
	xreal = Math.log(gnuplot.plot_axis_xmax) - Math.log(gnuplot.plot_axis_xmin);
	xreal = Math.log(gnuplot.plot_axis_xmin) + (x - gnuplot.plot_xmin) * xreal/gnuplot.plot_width;
	zoom.x = Math.log(gnuplot.zoom_axis_xmax) - Math.log(gnuplot.zoom_axis_xmin);
	zoom.x = gnuplot.plot_xmin + (xreal - Math.log(gnuplot.zoom_axis_xmin)) * gnuplot.plot_width/zoom.x;
  } else {
	xreal = gnuplot.plot_axis_xmin + (x - gnuplot.plot_xmin) * (gnuplot.plot_axis_width/gnuplot.plot_width);
	zoom.x = gnuplot.plot_xmin + (xreal - gnuplot.zoom_axis_xmin) * (gnuplot.plot_width/gnuplot.zoom_axis_width);
  }
  if (gnuplot.plot_logaxis_y != 0) {
	yreal = Math.log(gnuplot.plot_axis_ymax) - Math.log(gnuplot.plot_axis_ymin);
	yreal = Math.log(gnuplot.plot_axis_ymin) + (gnuplot.plot_ybot - y) * yreal/gnuplot.plot_height;
	zoom.y = Math.log(gnuplot.zoom_axis_ymax) - Math.log(gnuplot.zoom_axis_ymin);
	zoom.y = gnuplot.plot_ybot - (yreal - Math.log(gnuplot.zoom_axis_ymin)) * gnuplot.plot_height/zoom.y;
  } else {
	yreal = gnuplot.plot_axis_ymin + (gnuplot.plot_ybot - y) * (gnuplot.plot_axis_height/gnuplot.plot_height);
	zoom.y = gnuplot.plot_ybot - (yreal - gnuplot.zoom_axis_ymin) * (gnuplot.plot_height/gnuplot.zoom_axis_height);
  }

  // Report unclipped coords also
  zoom.xraw = zoom.x; zoom.yraw = zoom.y;

  // Limit the zoomed plot to the original plot area
  if (x > gnuplot.plot_xmax) {
    zoom.x = x;
    if (gnuplot.plot_axis_y2min == "none") {
      zoom.y = y;
      return zoom;
    }
    if (gnuplot.plot_ybot <= y && y <= gnuplot.plot_ybot + 15)
      zoom.clip = true;
  }

  else if (x < gnuplot.plot_xmin)
    zoom.x = x;
  else if (zoom.x < gnuplot.plot_xmin)
    { zoom.x = gnuplot.plot_xmin; zoom.clip = true; }
  else if (zoom.x > gnuplot.plot_xmax)
    { zoom.x = gnuplot.plot_xmax; zoom.clip = true; }

  if (y < gnuplot.plot_ytop) {
    zoom.y = y;
    if (gnuplot.plot_axis_x2min == "none") {
      zoom.x = x; zoom.clip = false;
      return zoom;
    }
  }

  else if (y > gnuplot.plot_ybot)
    zoom.y = y;
  else if (zoom.y > gnuplot.plot_ybot)
    { zoom.y = gnuplot.plot_ybot; zoom.clip = true; }
  else if (zoom.y < gnuplot.plot_ytop)
    { zoom.y = gnuplot.plot_ytop; zoom.clip = true; }

  return zoom;
}

gnuplot.zoomW = function (w) { return (w*gnuplot.plot_axis_width/gnuplot.zoom_axis_width); }
gnuplot.zoomH = function (h) { return (h*gnuplot.plot_axis_height/gnuplot.zoom_axis_height); }

gnuplot.popup_help = function(URL) {
    if (typeof(URL) != "string") {
	if (typeof(gnuplot.help_URL) == "string") 
	    URL = gnuplot.help_URL;
	else
	    return;
    }
    // FIXME: Placeholder for useful action
    if (URL != "")
	window.open (URL,"gnuplot help");
}

gnuplot.toggle_plot = function(plotid) {
    if (typeof(gnuplot["hide_"+plotid]) == "unknown")
    	gnuplot["hide_"+plotid] = false;
    gnuplot["hide_"+plotid] = !gnuplot["hide_"+plotid];
    ctx.clearRect(0,0,gnuplot.plot_term_xmax,gnuplot.plot_term_ymax);
    gnuplot.display_is_uptodate = false;
    gnuplot_canvas();
}

gnuplot.do_hotkey = function(event) {
    keychar = String.fromCharCode(event.charCode ? event.charCode : event.keyCode);
    switch (keychar) {
    case 'e':	ctx.clearRect(0,0,gnuplot.plot_term_xmax,gnuplot.plot_term_ymax);
		gnuplot.display_is_uptodate = false;
		gnuplot_canvas();
		break;
    case 'g':	gnuplot.toggle_grid();
		break;
    case 'n':	gnuplot.rezoom();
		break;
    case 'r':
		ctx.lineWidth = 0.5;
		ctx.strokeStyle="rgba(128,128,128,0.50)";
		ctx.moveTo(gnuplot.plot_xmin, gnuplot.mousey); ctx.lineTo(gnuplot.plot_xmax, gnuplot.mousey);
		ctx.moveTo(gnuplot.mousex, gnuplot.plot_ybot); ctx.lineTo(gnuplot.mousex, gnuplot.plot_ytop);
		ctx.stroke();
		break;
    case 'p':
    case 'u':	gnuplot.unzoom();
		break;
    case '':	zoom_in_progress = false;
		break;

// Arrow keys
    case '%':	// ctx.drawText("sans", 10, gnuplot.mousex, gnuplot.mousey, "<");
		break;
    case '\'':	// ctx.drawText("sans", 10, gnuplot.mousex, gnuplot.mousey, ">");
		break;
    case '&':	// ctx.drawText("sans", 10, gnuplot.mousex, gnuplot.mousey, "^");
		break;
    case '(':	// ctx.drawText("sans", 10, gnuplot.mousex, gnuplot.mousey, "v");
		break;

    default:	ctx.drawText("sans", 10, gnuplot.mousex, gnuplot.mousey, keychar);
		return true; // Let someone else handle it
		break;
    }
    return false; // Nobody else should respond to this keypress
}