Index: /issm/trunk-jpl/src/m/plot/applyoptions.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/applyoptions.js	(revision 20400)
+++ /issm/trunk-jpl/src/m/plot/applyoptions.js	(revision 20401)
@@ -11,4 +11,8 @@
 		if (options.getfieldvalue('colorbar')==1) {
 			//Handle movie data {{{
+			if (typeof data == 'string') {
+				//throw Error('plot error message: data of type string');
+				return;
+			}
 			var	dataresults = processdata(md,data,options);
 			var	data2 = dataresults[0]; 
Index: /issm/trunk-jpl/src/m/plot/plot_manager.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_manager.js	(revision 20400)
+++ /issm/trunk-jpl/src/m/plot/plot_manager.js	(revision 20401)
@@ -12,26 +12,31 @@
 	var data=options.getfieldvalue('data');
 	
-	//standard plot: initialize open Gl for each canvas, if needed: 
-	var canvas = $('<div><canvas id="'+options.getfieldvalue('canvasid')+'" width="'+options.getfieldvalue('canvassize',480)+'" height="'+options.getfieldvalue('canvassize',480)+'"></canvas></div>)')
-	canvas.css({'height':String(options.getfieldvalue('canvassize',480)+'px')});
-	if ($('#'+options.getfieldvalue('canvasid')).length == 0) {
-		canvas.appendTo('body');
-	}
-	canvas=document.getElementById(options.getfieldvalue('canvasid'));
-	//Initialize the buffer structure when first data is drawn to mesh:
-	var requestDrawing = false;
-	var gl = canvas.gl;
-	if (!canvas.hasOwnProperty("nodes")) {
-		canvas.nodes = {};
-		canvas.datalength = 0;
-		requestDrawing = true;
-		//Initialize the GL context: 
-		gl = initWebGL(canvas,options);
-		if (!gl) {
-			throw Error("plotmodel error message: could not initialize open Gl!");
+	//TODO: Move into webgl.js? 
+	function initCanvas() {
+		//standard plot: initialize open Gl for each canvas, if needed: 
+		var canvas = $('<div><canvas id="'+options.getfieldvalue('canvasid')+'" width="'+options.getfieldvalue('canvassize',480)+'" height="'+options.getfieldvalue('canvassize',480)+'"></canvas></div>)')
+		canvas.css({'height':String(options.getfieldvalue('canvassize',480)+'px')});
+		if ($('#'+options.getfieldvalue('canvasid')).length == 0) {
+			canvas.appendTo('body');
 		}
-		canvas.gl = gl;
-	}
-	canvas.nodes["data"+String(++canvas.datalength)] = Node(gl,options);
+		canvas=document.getElementById(options.getfieldvalue('canvasid'));
+		//Initialize the buffer structure when first data is drawn to mesh:
+		canvas.requestDrawing = false;
+		var gl = canvas.gl;
+		if (!canvas.hasOwnProperty("nodes")) {
+			canvas.nodes = {};
+			canvas.datalength = 0;
+			canvas.requestDrawing = true;
+			//Initialize the GL context: 
+			gl = initWebGL(canvas,options);
+			if (!gl) {
+				throw Error("plotmodel error message: could not initialize open Gl!");
+			}
+			canvas.gl = gl;
+		}
+		canvas.nodes["data"+String(++canvas.datalength)] = Node(gl,options);
+		return canvas;
+	}
+	var canvas = initCanvas();
 
 	//figure out if this is a special plot
@@ -42,109 +47,109 @@
 			case 'boundaries':
 				plot_boundaries(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'BC':
 				plot_BC(md,options,subplotwidth,i,data);
-				break;
+				return;
 			case 'edges':
 				plot_edges(md,options,subplotwidth,i,data);
-				break;
+				return;
 			case 'elementnumbering':
 				plot_elementnumbering(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'highlightelements':
 				plot_highlightelements(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'qmumean':
 				plot_qmumean(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'qmustddev':
 				plot_qmustddev(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'qmuhistnorm':
 				plot_qmuhistnorm(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'qmu_mass_flux_segments':
 				plot_qmu_mass_flux_segments(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'part_hist':
 				plot_parthist(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'part_hist_n':
 				plot_parthistn(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'part_hist_w':
 				plot_parthistw(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'elements_type':
 				plot_elementstype(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'vertexnumbering':
 				plot_vertexnumbering(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'highlightvertices':
 				plot_highlightvertices(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'basal_drag':
 				plot_basaldrag(md,options,subplotwidth,i,data);
-				break;
+				return;
 			case 'basal_dragx':
 				plot_basaldrag(md,options,subplotwidth,i,data);
-				break;
+				return;
 			case 'basal_dragy':
 				plot_basaldrag(md,options,subplotwidth,i,data);
-				break;
+				return;
 			case 'driving_stress':
 				plot_drivingstress(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'mesh':
 				plot_mesh(md,options,canvas,gl,canvas.nodes["data"+String(canvas.datalength)]);
-				break;
+				return;
 			case 'none':
 				if (!(options.exist('overlay'))){
 					plot_none(md,options,nlines,ncols,i);
 				}
-				break;
+				return;
 			case 'penalties':
 				plot_penalties(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'partition':
 				plot_partition(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'referential':
 				plot_referential(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'riftvel':
 				plot_riftvel(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'riftnumbering':
 				plot_riftnumbering(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'rifts':
 				plot_rifts(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'riftrelvel':
 				plot_riftrelvel(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'riftpenetration':
 				plot_riftpenetration(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'riftfraction':
 				plot_riftfraction(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'sarpwr':
 				plot_sarpwr(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'time_dependant':
 				plot_vstime(md,options,nlines,ncols,i);
-				break;
+				return;
 			case 'icefront':
 				plot_icefront(md,options,subplotwidth,i,data);
-				break;
+				return;
 			case 'segments':
 				plot_segments(md,options,subplotwidth,i,data);
-				break;
+				return;
 			case 'quiver':
-				data=[md.initialization.vx, md.initialization.vy]; //Go ahead and try plot_unit
-
+				plot_quiver(md,options,canvas,gl,canvas.nodes["data"+String(canvas.datalength)]);
+				return;
 			case 'strainrate_tensor':
 			case 'strainrate':
@@ -166,17 +171,17 @@
 			case 'deviatoricstress_principalaxis3':
 				plot_tensor(md,options,subplotwidth,i,data);
-				break;
+				return;
 			case 'thermaltransient_results':
 				plot_thermaltransient_results(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'transient_movie':
 				plot_transient_movie(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'transient_results':
 				plot_transient_results(md,options,subplotwidth,i);
-				break;
+				return;
 			case 'transient_field':
 				plot_transient_field(md,options,subplotwidth,i);
-				break;
+				return;
 			default:
 				if (data in md){
@@ -218,5 +223,5 @@
 		return;
 	}
-
+	
 	if (typeof data !== 'string'){
 		//plot unit
@@ -225,6 +230,3 @@
 
 	applyoptions(md,data,options,canvas,gl,canvas.nodes["data"+String(canvas.datalength)]);
-	
-	//Draw into the canvas if needed:
-	if (requestDrawing)	draw(gl,options,canvas);
 }
Index: /issm/trunk-jpl/src/m/plot/plot_mesh.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_mesh.js	(revision 20400)
+++ /issm/trunk-jpl/src/m/plot/plot_mesh.js	(revision 20401)
@@ -62,5 +62,4 @@
 	node["modelMatrix"] = recalculateModelMatrix(node);
 	node["drawMode"] = gl.LINES;
-	node["overlay"] = false;
 	node["drawOrder"] = 0;
 	node["maskEnabled"] = options.exist('mask');
@@ -109,3 +108,4 @@
 	node["arrays"] = [vertices, colors, indices];
 	node["buffers"] = initBuffers(gl, node["arrays"]);
+	if (canvas.requestDrawing)	draw(gl,options,canvas);
 }
Index: /issm/trunk-jpl/src/m/plot/plot_overlay.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_overlay.js	(revision 20400)
+++ /issm/trunk-jpl/src/m/plot/plot_overlay.js	(revision 20401)
@@ -65,5 +65,4 @@
 	node["texture"] = initTexture(gl,options.getfieldvalue('image'));
 	node["alpha"] = options.getfieldvalue('outeralpha',1.0);
-	node["overlay"] = false;
 	node["drawOrder"] = 1;
 	node["maskEnabled"] = options.getfieldvalue('outermask','off') == 'on';
@@ -127,3 +126,4 @@
 	node["arrays"] = [vertices, texcoords, indices];
 	node["buffers"] = initBuffers(gl,node["arrays"]);
+	if (canvas.requestDrawing)	draw(gl,options,canvas);
 }
Index: /issm/trunk-jpl/src/m/plot/plot_quiver.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_quiver.js	(revision 20401)
+++ /issm/trunk-jpl/src/m/plot/plot_quiver.js	(revision 20401)
@@ -0,0 +1,117 @@
+function plot_quiver(md,options,canvas,gl,node) {
+	//PLOT_QUIVER - quiver plot with colors
+	//
+	//   Usage:
+	//      plot_quiver(md,options,canvas,gl,node)
+	//
+
+	//declare variables:  {{{
+	var vertices = [];
+	var indices = [];
+	var colors = [];
+	var rgbcolor = [];
+	var xmin,xmax;
+	var ymin,ymax;
+	var zmin,zmax;
+	var scale,zscale,surfacescale;
+	
+	//Process data and model
+	var meshresults = processmesh(md,[],options);
+	var x = meshresults[0]; 
+	var y = meshresults[1]; 
+	var z = meshresults[2]; 
+	var elements = meshresults[3]; 
+	var is2d = meshresults[4]; 
+	var isplanet = meshresults[5];
+	var vx = md.initialization.vx; 
+	var vy = md.initialization.vy; 
+		
+	if (!md.geometry.surface) {
+		md.geometry.surface=NewArrayFill(md.mesh.x.length,0);
+	}
+	if (md.mesh.classname() == 'mesh3dsurface') {
+		zscale = 1;
+		surfacescale = options.getfieldvalue('heightscale',1);
+	}
+	else {
+		if (md.geometry.surface) {
+			z=md.geometry.surface;
+		}	
+		zscale = options.getfieldvalue('heightscale',1);
+		surfacescale = 0;
+	}
+	//}}}
+
+	//Compute coordinates and data range:
+	var modelxlim = [ArrayMin(x),ArrayMax(x)];
+	var modelylim = [ArrayMin(y),ArrayMax(y)];
+	var modelzlim = [ArrayMin(z),ArrayMax(z)];
+	var xlim = options.getfieldvalue('xlim',modelxlim);
+	var ylim = options.getfieldvalue('ylim',modelylim);
+	var zlim = options.getfieldvalue('zlim',modelzlim);
+	xmin = xlim[0];
+	xmax = xlim[1];
+	ymin = ylim[0];
+	ymax = ylim[1];
+	zmin = zlim[0];
+	zmax = zlim[1];
+
+	//Compute scaling: 
+	var scale = 1 / (xmax - xmin);
+	node["shaderName"] = "colored";
+	node["shader"] = gl["shaders"][node["shaderName"]]["program"];
+	node["scale"] = [scale, scale, scale * zscale];
+	node["translation"] = [(xmin + xmax) / (-2 / scale), (ymin + ymax) / (-2 / scale), (zmin + zmax) / (2 / scale)];
+	node["modelMatrix"] = recalculateModelMatrix(node);
+	node["drawMode"] = gl.LINES;
+	node["useIndexBuffer"] = false;
+	node["drawOrder"] = 0;
+	node["maskEnabled"] = options.exist('mask');
+	node["maskHeight"] = options.getfieldvalue('maskheight',150.0)*options.getfieldvalue('heightscale',1);
+	node["maskColor"] = options.getfieldvalue('maskcolor',[0.0,0.0,1.0,1.0]);
+				
+	//some defaults:
+	colors.itemSize = 4;
+
+	//retrieve some options
+	var linewidth=options.getfieldvalue('linewidth',1);
+	var edgecolor=options.getfieldvalue('edgecolor',[0.0,0.0,0.0,1.0]); //have RGBColor switch with array color?
+	//var edgecolor=options.getfieldvalue('edgecolor','black'); //have RGBColor switch with array color?
+
+	//node plot {{{
+	if (elements[0].length==6){ //prisms
+	}
+	else if (elements[0].length==4){ //tetras
+	}
+	else{ //2D triangular elements
+		vertices.itemSize = 3;
+		var xyz = vec3.create();
+		var direction = vec3.create();
+		var vertex = vec3.create();
+		var magnitude;
+		var color = edgecolor;
+		for(var i = 0; i < x.length; i++){
+			xyz1 = vec3.fromValues(x[i], y[i], z[i]);
+			magnitude = vec3.length(xyz1) + md.geometry.surface[i] * surfacescale;
+			vec3.normalize(direction, xyz1);
+			vec3.scale(vertex, direction, magnitude);
+			vertices.push.apply(vertices, vertex);
+			
+			xyz2 = vec3.fromValues(vx[i], vy[i], 0.0);
+			magnitude = 100.0; //mesh resolution
+			vec3.normalize(direction, xyz2);
+			vec3.scale(direction, direction, magnitude);
+			vec3.add(vertex, direction, vertex);
+			vertices.push.apply(vertices, vertex);
+			
+			colors.push.apply(colors, color);
+			colors.push.apply(colors, color);
+		}
+	}
+	//}}}
+
+	/*Initalize buffers: */
+	node["arrays"] = [vertices, colors];
+	node["buffers"] = initBuffers(gl, node["arrays"]);
+	if (canvas.requestDrawing)	draw(gl,options,canvas);
+}
Index: /issm/trunk-jpl/src/m/plot/plot_unit.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_unit.js	(revision 20400)
+++ /issm/trunk-jpl/src/m/plot/plot_unit.js	(revision 20401)
@@ -70,5 +70,4 @@
 	node["modelMatrix"] = recalculateModelMatrix(node);
 	node["alpha"] = options.getfieldvalue('alpha',1.0);
-	node["overlay"] = options.getfieldvalue('overlay','off') == 'on';
 	node["drawOrder"] = 0;
 	node["maskEnabled"] = options.getfieldvalue('innermask','off') == 'on';
@@ -200,10 +199,32 @@
 				node["movieFrame"] = 0;
 				node["movieHandler"] = function () {
-						node["movieFrame"] = (node["movieFrame"] + 1) % (node["movieLength"]);
-						var array = [node["arrays"][0],node["arrays"][1][node["movieFrame"]],node["arrays"][2]];
-						node["buffers"] = initBuffers(gl,array);
+						if (canvas["moviePlay"]) {
+							node["movieFrame"] = canvas["movieFrame"];
+							if (canvas["movieIncrement"]) {
+								if (canvas["movieReverse"]) {
+									node["movieFrame"] = (((node["movieFrame"] - 1) % node["movieLength"]) + node["movieLength"]) % node["movieLength"]; //Handle negative modulus
+								}
+								else {
+									node["movieFrame"] = (((node["movieFrame"] + 1) % node["movieLength"]) + node["movieLength"]) % node["movieLength"]; //Handle negative modulus
+								}
+							}
+							if (canvas["timeLabel"]) {
+								canvas["timeLabel"].html(String(node["movieFrame"]) + "/" +  String(node["movieLength"] - 1));
+							}
+							if (canvas["progressBar"]) {
+								canvas["progressBar"].slider("value", node["movieFrame"]);
+							}
+							var array = [node["arrays"][0],node["arrays"][1][node["movieFrame"]],node["arrays"][2]];
+							node["buffers"] = initBuffers(gl,array);
+							canvas["movieFrame"] = node["movieFrame"];
+						}
 						setTimeout(node["movieHandler"], node["movieInterval"]);
 					};
 				setTimeout(node["movieHandler"], node["movieInterval"]);
+				if (canvas["progressBar"]) {
+					canvas["movieFrame"] = 0;
+					canvas["progressBar"].slider("value", 0);
+					canvas["progressBar"].slider("option", {max: node["movieLength"]-1});
+				}
 			}
 			
@@ -216,3 +237,4 @@
 			throw Error(sprintf("%s%i%s\n",'case ',datatype,' not supported'));
 	}
+	if (canvas.requestDrawing) draw(gl,options,canvas);
 }
Index: /issm/trunk-jpl/src/m/plot/slider.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/slider.js	(revision 20400)
+++ /issm/trunk-jpl/src/m/plot/slider.js	(revision 20401)
@@ -23,8 +23,8 @@
 
 	$('#'+slidersdiv).css({width:width});
-	$('<div class="slider'+name+'"></div>').appendTo('#'+slidersdiv);
+	$('<div class="'+name+'-slider"></div>').appendTo('#'+slidersdiv);
 	$('<div class="info'+name+'">'+startmessage[0]+value.toString()+startmessage[1]+'</div>').appendTo('#'+slidersdiv);
 	var info=$('.info'+name);
-	$('.slider'+name).slider({
+	$('.'+name+'-slider').slider({
 		range:'min',
 		value:value,
@@ -37,7 +37,7 @@
 		stop:function(event,ui){
 			stopSlide(event,ui,info,callback,middlemessage,endmessage,precision);
-		},
+		}
 	});
-	$('.ui-slider').css({
+	$('.'+name+'-slider.ui-slider').css({
 		width:'auto',
 		height:height,
@@ -45,12 +45,11 @@
 		margin:'8px'
 	});
-	$('.ui-slider-handle').css({
+	$('.'+name+'-slider .ui-slider-handle').css({
 		background:color,
 		height:parseInt(height)+8
 	});
-	$('.ui-slider-range').css({
+	$('.'+name+'-slider .ui-slider-range').css({
 		background:color
 	});
-
 }
 
@@ -66,2 +65,92 @@
 	info.text(endmessage[0]+val.toPrecision(precision).toString()+endmessage[1]);
 }
+
+function progress(){
+	//Convert arguments to options
+	var args = Array.prototype.slice.call(arguments);
+	var  options = new pairoptions(args.slice());
+	
+	var value = options.getfieldvalue('value',0);
+	var name = options.getfieldvalue('name','hma');
+	var min = options.getfieldvalue('min',0.6*value);
+	var max = options.getfieldvalue('max',1.4*value);
+	var width = options.getfieldvalue('width','auto');
+	var height = options.getfieldvalue('height',32);
+	var color = options.getfieldvalue('color','#bbbbbb');
+	var progressdiv = options.getfieldvalue('progressdiv','progressdiv');
+	
+	var canvas = $('#'+name)[0];
+	var progressbar = $('#'+name+'-progressbar');
+	var playbutton = $('#'+name+'-playbutton');
+	var reversebutton = $('#'+name+'-reversebutton');
+	var timelabel = $('#'+name+'-timelabel');
+
+	
+	playbutton.click(function() {
+		canvas.moviePlay = !canvas.moviePlay;
+		if (canvas.moviePlay) {
+			$("#playButton").html("&#10074&#10074");
+		}
+		else {
+			$("#playButton").html("&#9654");
+		}
+	});
+	reversebutton.click(function() {
+		canvas.movieReverse = !canvas.movieReverse;
+		if (canvas.movieReverse) {
+			reversebutton.html("&#9664&#9664");
+		}
+		else {
+			reversebutton.html("&#9654&#9654");
+		}
+	});
+	canvas.timeLabel = timelabel;
+	
+	$('#'+progressdiv).css({width:width});
+	$('<div class="'+name+'-progressbar"></div>').prependTo('#'+progressdiv);
+	$('.'+name+'-progressbar').slider({
+		range:'min',
+		value:0,
+		min:0,
+		max:1,
+		step:1,
+		start:function(event,ui){
+			startProgress(event,ui,canvas);
+		},
+		slide:function(event,ui){
+			moveProgress(event,ui,canvas);
+		},
+		stop:function(event,ui){
+			stopProgress(event,ui,canvas);
+		}
+	});
+	$('.'+name+'-progressbar.ui-slider').css({
+		width:'auto',
+		height:height,
+		background:color,
+		margin:'8px'
+	});
+	$('.'+name+'-progressbar .ui-slider-handle').css({
+		background:color,
+		height:parseInt(height)+8
+	});
+	$('.'+name+'-progressbar .ui-slider-range').css({
+		background:'red'
+	});
+	
+	canvas.progressBar = $('.'+name+'-progressbar');
+}
+
+function startProgress(event,ui,canvas){
+	canvas.movieFrame = ui.value;
+	canvas.movieIncrement = false;
+}
+
+function moveProgress(event,ui,canvas){
+	canvas.movieFrame = ui.value;
+}
+
+function stopProgress(event,ui,canvas){
+	canvas.movieFrame = ui.value;
+	canvas.movieIncrement = true;
+}
Index: /issm/trunk-jpl/src/m/plot/webgl.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/webgl.js	(revision 20400)
+++ /issm/trunk-jpl/src/m/plot/webgl.js	(revision 20401)
@@ -45,4 +45,7 @@
 	canvas.controlsensitivity = 1;
 	canvas.twod = options.getfieldvalue('2d','off') == 'on';
+	canvas.moviePlay = true;
+	canvas.movieReverse = false;
+	canvas.movieIncrement = true;
 
 	if (canvas.twod) {
