瀏覽代碼

Switch styles to LESS build, add inspector.html, update flot

Rashid Khan 12 年之前
父節點
當前提交
58256acb81

+ 15 - 1
Gruntfile.js

@@ -46,14 +46,28 @@ module.exports = function (grunt) {
           moment: false
         }
       }
+    },
+    less: {
+      production: {
+        options: {
+          paths: ["vendor/bootstrap/less"],
+          yuicompress:true
+        },
+        files: {
+          "common/css/bootstrap.dark.min.css": "vendor/bootstrap/less/bootstrap.dark.less",
+          "common/css/bootstrap.light.min.css": "vendor/bootstrap/less/bootstrap.light.less"
+        }
+      }
     }
   });
 
   // load plugins
   grunt.loadNpmTasks('grunt-contrib-jshint');
+  grunt.loadNpmTasks('assemble-less');
+
 
 
   // Default task.
-  grunt.registerTask('default', ['jshint']);
+  grunt.registerTask('default', ['jshint','less']);
 
 };

文件差異過大導致無法顯示
+ 2 - 7063
common/css/bootstrap.dark.min.css


文件差異過大導致無法顯示
+ 3 - 4744
common/css/bootstrap.light.min.css


+ 10 - 0
common/css/main.css

@@ -132,10 +132,20 @@
   max-width: 500px;
 }
 
+.modal {
+  width: 770px;
+  margin-left: -385px;
+  top: 10px !important;
+}
+
 .tiny {
   font-size: 50%;
 }
 
+.smaller {
+  font-size: 70%;
+}
+
 .small {
   font-size: 85%;
 }

文件差異過大導致無法顯示
+ 592 - 235
common/lib/panels/jquery.flot.js


+ 152 - 145
common/lib/panels/jquery.flot.pie.js

@@ -1,6 +1,6 @@
 /* Flot plugin for rendering pie charts.
 
-Copyright (c) 2007-2012 IOLA and Ole Laursen.
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
 Licensed under the MIT license.
 
 The plugin assumes that each series has a single data value, and that each
@@ -57,22 +57,22 @@ More detail and specific examples can be found in the included HTML file.
 
 (function($) {
 
+	// Maximum redraw attempts when fitting labels within the plot
+
+	var REDRAW_ATTEMPTS = 10;
+
+	// Factor by which to shrink the pie when fitting labels within the plot
+
+	var REDRAW_SHRINK = 0.95;
+
 	function init(plot) {
 
 		var canvas = null,
-			canvasWidth = 0,
-			canvasHeight = 0,
 			target = null,
 			maxRadius = null,
 			centerLeft = null,
 			centerTop = null,
-			total = 0,
-			redraw = true,
-			redrawAttempts = 10,
-			shrink = 0.95,
-			legendWidth = 0,
 			processed = false,
-			raw = false,
 			ctx = null;
 
 		// interactive variables
@@ -81,16 +81,9 @@ More detail and specific examples can be found in the included HTML file.
 
 		// add hook to determine if pie plugin in enabled, and then perform necessary operations
 
-		plot.hooks.processOptions.push(checkPieEnabled);
-		plot.hooks.bindEvents.push(bindEvents);
-
-		// check to see if the pie plugin is enabled
-
-		function checkPieEnabled(plot, options) {
+		plot.hooks.processOptions.push(function(plot, options) {
 			if (options.series.pie.show) {
 
-				//disable grid
-
 				options.grid.show = false;
 
 				// set labels.show
@@ -120,21 +113,10 @@ More detail and specific examples can be found in the included HTML file.
 				} else if (options.series.pie.tilt < 0) {
 					options.series.pie.tilt = 0;
 				}
-
-				// add processData hook to do transformations on the data
-
-				plot.hooks.processDatapoints.push(processDatapoints);
-				plot.hooks.drawOverlay.push(drawOverlay);
-
-				//  draw hook
-
-				plot.hooks.draw.push(draw);
 			}
-		}
+		});
 
-		// bind hoverable events
-
-		function bindEvents(plot, eventHolder) {
+		plot.hooks.bindEvents.push(function(plot, eventHolder) {
 			var options = plot.getOptions();
 			if (options.series.pie.show) {
 				if (options.grid.hoverable) {
@@ -144,47 +126,30 @@ More detail and specific examples can be found in the included HTML file.
 					eventHolder.unbind("click").click(onClick);
 				}
 			}
-		}
-
-		// debugging function that prints out an object
+		});
 
-		function alertObject(obj) {
-
-			var msg = "";
-
-			function traverse(obj, depth) {
-
-				if (!depth) {
-					depth = 0;
-				}
-
-				for (var i = 0; i < obj.length; ++i) {
-					for (var j = 0; j < depth; j++) {
-						msg += "\t";
-					}
-					if( typeof obj[i] == "object") {
-						msg += "" + i + ":\n";
-						traverse(obj[i], depth + 1);
-					} else {
-						msg += "" + i + ": " + obj[i] + "\n";
-					}
-				}
+		plot.hooks.processDatapoints.push(function(plot, series, data, datapoints) {
+			var options = plot.getOptions();
+			if (options.series.pie.show) {
+				processDatapoints(plot, series, data, datapoints);
 			}
+		});
 
-			traverse(obj);
-			alert(msg);
-		}
+		plot.hooks.drawOverlay.push(function(plot, octx) {
+			var options = plot.getOptions();
+			if (options.series.pie.show) {
+				drawOverlay(plot, octx);
+			}
+		});
 
-		function calcTotal(data) {
-			for (var i = 0; i < data.length; ++i) {
-				var item = parseFloat(data[i].data[0][1]);
-				if (item) {
-					total += item;
-				}
+		plot.hooks.draw.push(function(plot, newCtx) {
+			var options = plot.getOptions();
+			if (options.series.pie.show) {
+				draw(plot, newCtx);
 			}
-		}
+		});
 
-		function processDatapoints(plot, series, data, datapoints) {
+		function processDatapoints(plot, series, datapoints) {
 			if (!processed)	{
 				processed = true;
 				canvas = plot.getCanvas();
@@ -194,85 +159,81 @@ More detail and specific examples can be found in the included HTML file.
 			}
 		}
 
-		function setupPie() {
+		function combine(data) {
 
-			legendWidth = target.children().filter(".legend").children().width() || 0;
+			var total = 0,
+				combined = 0,
+				numCombined = 0,
+				color = options.series.pie.combine.color,
+				newdata = [];
 
-			// calculate maximum radius and center point
+			// Fix up the raw data from Flot, ensuring the data is numeric
 
-			maxRadius =  Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2;
-			centerTop = canvasHeight / 2 + options.series.pie.offset.top;
-			centerLeft = canvasWidth / 2;
+			for (var i = 0; i < data.length; ++i) {
 
-			if (options.series.pie.offset.left == "auto") {
-				if (options.legend.position.match("w")) {
-					centerLeft += legendWidth / 2;
-				} else {
-					centerLeft -= legendWidth / 2;
-				}
-			} else {
-				centerLeft += options.series.pie.offset.left;
-			}
+				var value = data[i].data;
 
-			if (centerLeft < maxRadius) {
-				centerLeft = maxRadius;
-			} else if (centerLeft > canvasWidth - maxRadius) {
-				centerLeft = canvasWidth - maxRadius;
-			}
-		}
+				// If the data is an array, we'll assume that it's a standard
+				// Flot x-y pair, and are concerned only with the second value.
 
-		function fixData(data) {
-			for (var i = 0; i < data.length; ++i) {
-				if (typeof(data[i].data) == "number") {
-					data[i].data = [[1, data[i].data]];
-				} else if (typeof(data[i].data) == "undefined" || typeof(data[i].data[0]) == "undefined") {
-					if (typeof(data[i].data) != "undefined" && typeof(data[i].data.label) != "undefined") {
-						data[i].label = data[i].data.label; // fix weirdness coming from flot
-					}
-					data[i].data = [[1, 0]];
+				// Note how we use the original array, rather than creating a
+				// new one; this is more efficient and preserves any extra data
+				// that the user may have stored in higher indexes.
+
+				if ($.isArray(value) && value.length == 1) {
+    				value = value[0];
 				}
-			}
-			return data;
-		}
 
-		function combine(data) {
+				if ($.isArray(value)) {
+					// Equivalent to $.isNumeric() but compatible with jQuery < 1.7
+					if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) {
+						value[1] = +value[1];
+					} else {
+						value[1] = 0;
+					}
+				} else if (!isNaN(parseFloat(value)) && isFinite(value)) {
+					value = [1, +value];
+				} else {
+					value = [1, 0];
+				}
 
-			data = fixData(data);
-			calcTotal(data);
+				data[i].data = [value];
+			}
 
-			var combined = 0;
-			var numCombined = 0;
-			var color = options.series.pie.combine.color;
-			var newdata = [];
+			// Sum up all the slices, so we can calculate percentages for each
 
 			for (var i = 0; i < data.length; ++i) {
+				total += data[i].data[0][1];
+			}
 
-				// make sure its a number
-
-				data[i].data[0][1] = parseFloat(data[i].data[0][1]);
-
-				if (!data[i].data[0][1]) {
-					data[i].data[0][1] = 0;
-				}
+			// Count the number of slices with percentages below the combine
+			// threshold; if it turns out to be just one, we won't combine.
 
-				if (data[i].data[0][1] / total <= options.series.pie.combine.threshold) {
-					combined += data[i].data[0][1];
+			for (var i = 0; i < data.length; ++i) {
+				var value = data[i].data[0][1];
+				if (value / total <= options.series.pie.combine.threshold) {
+					combined += value;
 					numCombined++;
 					if (!color) {
 						color = data[i].color;
 					}
-				} else {
+				}
+			}
+
+			for (var i = 0; i < data.length; ++i) {
+				var value = data[i].data[0][1];
+				if (numCombined < 2 || value / total > options.series.pie.combine.threshold) {
 					newdata.push({
-						data: [[1, data[i].data[0][1]]],
+						data: [[1, value]],
 						color: data[i].color,
 						label: data[i].label,
-						angle: data[i].data[0][1] * Math.PI * 2 / total,
-						percent: data[i].data[0][1] / (total / 100)
+						angle: value * Math.PI * 2 / total,
+						percent: value / (total / 100)
 					});
 				}
 			}
 
-			if (numCombined > 0) {
+			if (numCombined > 1) {
 				newdata.push({
 					data: [[1, combined]],
 					color: color,
@@ -291,39 +252,79 @@ More detail and specific examples can be found in the included HTML file.
 				return; // if no series were passed
 			}
 
-			canvasWidth = plot.getPlaceholder().width();
-			canvasHeight = plot.getPlaceholder().height();
+			var canvasWidth = plot.getPlaceholder().width(),
+				canvasHeight = plot.getPlaceholder().height(),
+				legendWidth = target.children().filter(".legend").children().width() || 0;
 
 			ctx = newCtx;
-			setupPie();
 
-			var slices = plot.getData();
-			var attempts = 0;
+			// WARNING: HACK! REWRITE THIS CODE AS SOON AS POSSIBLE!
+
+			// When combining smaller slices into an 'other' slice, we need to
+			// add a new series.  Since Flot gives plugins no way to modify the
+			// list of series, the pie plugin uses a hack where the first call
+			// to processDatapoints results in a call to setData with the new
+			// list of series, then subsequent processDatapoints do nothing.
+
+			// The plugin-global 'processed' flag is used to control this hack;
+			// it starts out false, and is set to true after the first call to
+			// processDatapoints.
 
-			while (redraw && attempts<redrawAttempts) {
-				redraw = false;
+			// Unfortunately this turns future setData calls into no-ops; they
+			// call processDatapoints, the flag is true, and nothing happens.
+
+			// To fix this we'll set the flag back to false here in draw, when
+			// all series have been processed, so the next sequence of calls to
+			// processDatapoints once again starts out with a slice-combine.
+			// This is really a hack; in 0.9 we need to give plugins a proper
+			// way to modify series before any processing begins.
+
+			processed = false;
+
+			// calculate maximum radius and center point
+
+			maxRadius =  Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2;
+			centerTop = canvasHeight / 2 + options.series.pie.offset.top;
+			centerLeft = canvasWidth / 2;
+
+			if (options.series.pie.offset.left == "auto") {
+				if (options.legend.position.match("w")) {
+					centerLeft += legendWidth / 2;
+				} else {
+					centerLeft -= legendWidth / 2;
+				}
+			} else {
+				centerLeft += options.series.pie.offset.left;
+			}
+
+			if (centerLeft < maxRadius) {
+				centerLeft = maxRadius;
+			} else if (centerLeft > canvasWidth - maxRadius) {
+				centerLeft = canvasWidth - maxRadius;
+			}
+
+			var slices = plot.getData(),
+				attempts = 0;
+
+			// Keep shrinking the pie's radius until drawPie returns true,
+			// indicating that all the labels fit, or we try too many times.
+
+			do {
 				if (attempts > 0) {
-					maxRadius *= shrink;
+					maxRadius *= REDRAW_SHRINK;
 				}
 				attempts += 1;
 				clear();
 				if (options.series.pie.tilt <= 0.8) {
 					drawShadow();
 				}
-				drawPie();
-			}
+			} while (!drawPie() && attempts < REDRAW_ATTEMPTS)
 
-			if (attempts >= redrawAttempts) {
+			if (attempts >= REDRAW_ATTEMPTS) {
 				clear();
 				target.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>");
 			}
 
-			// Reset the redraw flag on success, so the loop above can run
-			// again in the event of a resize or other update.
-			// TODO: We should remove this redraw system entirely!
-
-			redraw = true;
-
 			if (plot.setSeries && plot.insertLegend) {
 				plot.setSeries(slices);
 				plot.insertLegend();
@@ -408,14 +409,13 @@ More detail and specific examples can be found in the included HTML file.
 
 				drawDonutHole(ctx);
 
-				// draw labels
+				ctx.restore();
 
-				if (options.series.pie.label.show) {
-					drawLabels();
-				}
+				// Draw the labels, returning true if they fit within the plot
 
-				// restore to original state
-				ctx.restore();
+				if (options.series.pie.label.show) {
+					return drawLabels();
+				} else return true;
 
 				function drawSlice(angle, color, fill) {
 
@@ -456,14 +456,19 @@ More detail and specific examples can be found in the included HTML file.
 
 					for (var i = 0; i < slices.length; ++i) {
 						if (slices[i].percent >= options.series.pie.label.threshold * 100) {
-							drawLabel(slices[i], currentAngle, i);
+							if (!drawLabel(slices[i], currentAngle, i)) {
+								return false;
+							}
 						}
 						currentAngle += slices[i].angle;
 					}
 
+					return true;
+
 					function drawLabel(slice, startAngle, index) {
+
 						if (slice.data[0][1] == 0) {
-							return;
+							return true;
 						}
 
 						// format label text
@@ -497,7 +502,7 @@ More detail and specific examples can be found in the included HTML file.
 						// check to make sure that the label is not outside the canvas
 
 						if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) {
-							redraw = true;
+							return false;
 						}
 
 						if (options.series.pie.label.background.opacity != 0) {
@@ -515,6 +520,8 @@ More detail and specific examples can be found in the included HTML file.
 								.css("opacity", options.series.pie.label.background.opacity)
 								.insertBefore(label);
 						}
+
+						return true;
 					} // end individual label function
 				} // end drawLabels function
 			} // end drawPie function

+ 10 - 10
common/lib/panels/jquery.flot.selection.js

@@ -6,10 +6,10 @@ Licensed under the MIT license.
 The plugin supports these options:
 
 selection: {
-  mode: null or "x" or "y" or "xy",
-  color: color,
-  shape: "round" or "miter" or "bevel",
-  minSize: number of pixels
+	mode: null or "x" or "y" or "xy",
+	color: color,
+	shape: "round" or "miter" or "bevel",
+	minSize: number of pixels
 }
 
 Selection support is enabled by setting the mode to one of "x", "y" or "xy".
@@ -33,11 +33,11 @@ When selection support is enabled, a "plotselected" event will be emitted on
 the DOM element you passed into the plot function. The event handler gets a
 parameter with the ranges selected on the axes, like this:
 
-  placeholder.bind( "plotselected", function( event, ranges ) {
-    alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
-    // similar for yaxis - with multiple axes, the extra ones are in
-    // x2axis, x3axis, ...
-  });
+	placeholder.bind( "plotselected", function( event, ranges ) {
+		alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
+		// similar for yaxis - with multiple axes, the extra ones are in
+		// x2axis, x3axis, ...
+	});
 
 The "plotselected" event is only fired when the user has finished making the
 selection. A "plotselecting" event is fired during the process with the same
@@ -58,7 +58,7 @@ The plugin allso adds the following methods to the plot object:
   an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
   this:
 
-  setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
+	setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
 
   setSelection will trigger the "plotselected" event when called. If you don't
   want that to happen, e.g. if you're inside a "plotselected" handler, pass

+ 3 - 130
common/lib/panels/jquery.flot.stack.js

@@ -1,6 +1,6 @@
 /* Flot plugin for stacking data sets rather than overlyaing them.
 
-Copyright (c) 2007-2012 IOLA and Ole Laursen.
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
 Licensed under the MIT license.
 
 The plugin assumes the data is sorted on x (or y if stacking horizontally).
@@ -15,7 +15,7 @@ key (which can be any number or string or just "true"). To specify the default
 stack, you can set the stack option like this:
 
 	series: {
-		stack: null or true or key (number/string)
+		stack: null/false, true, or a key (number/string)
 	}
 
 You can also specify it for a single series, like this:
@@ -55,7 +55,7 @@ charts or filled areas).
         }
         
         function stackData(plot, s, datapoints) {
-            if (s.stack == null)
+            if (s.stack == null || s.stack === false)
                 return;
 
             var other = findMatchingSeries(s, plot.getData());
@@ -186,130 +186,3 @@ charts or filled areas).
         version: '1.2'
     });
 })(jQuery);
-
-(function ($) {
-    var options = {
-        series: {
-            stackpercent: null
-        } // or number/string
-    };
-
-    function init(plot) {
-
-        // will be built up dynamically as a hash from x-value, or y-value if horizontal
-        var stackBases = {};
-        var processed = false;
-        var stackSums = {};
-
-        //set percentage for stacked chart
-        function processRawData(plot, series, data, datapoints) {
-            if (!processed) {
-                processed = true;
-                stackSums = getStackSums(plot.getData());
-            }
-            if (series.stackpercent == true) {
-                var num = data.length;
-                series.percents = [];
-                var key_idx = 0;
-                var value_idx = 1;
-                if (series.bars && series.bars.horizontal && series.bars.horizontal === true) {
-                    key_idx = 1;
-                    value_idx = 0;
-                }
-                for (var j = 0; j < num; j++) {
-                    var sum = stackSums[data[j][key_idx] + ""];
-                    if (sum > 0) {
-                        series.percents.push(data[j][value_idx] * 100 / sum);
-                    } else {
-                        series.percents.push(0);
-                    }
-                }
-            }
-        }
-
-        //calculate summary
-        function getStackSums(_data) {
-            var data_len = _data.length;
-            var sums = {};
-            if (data_len > 0) {
-                //caculate summary
-                for (var i = 0; i < data_len; i++) {
-                    if (_data[i].stackpercent) {
-                        var key_idx = 0;
-                        var value_idx = 1;
-                        if (_data[i].bars && _data[i].bars.horizontal && _data[i].bars.horizontal === true) {
-                            key_idx = 1;
-                            value_idx = 0;
-                        }
-                        var num = _data[i].data.length;
-                        for (var j = 0; j < num; j++) {
-                            var value = 0;
-                            if (_data[i].data[j][1] != null) {
-                                value = _data[i].data[j][value_idx];
-                            }
-                            if (sums[_data[i].data[j][key_idx] + ""]) {
-                                sums[_data[i].data[j][key_idx] + ""] += value;
-                            } else {
-                                sums[_data[i].data[j][key_idx] + ""] = value;
-                            }
-
-                        }
-                    }
-                }
-            }
-            return sums;
-        }
-
-        function stackData(plot, s, datapoints) {
-            if (!s.stackpercent) return;
-            if (!processed) {
-                stackSums = getStackSums(plot.getData());
-            }
-            var newPoints = [];
-            
-            
-            var key_idx = 0;
-            var value_idx = 1;
-            if (s.bars && s.bars.horizontal && s.bars.horizontal === true) {
-                key_idx = 1;
-                value_idx = 0;
-            }
-
-            for (var i = 0; i < datapoints.points.length; i += 3) {
-                // note that the values need to be turned into absolute y-values.
-                // in other words, if you were to stack (x, y1), (x, y2), and (x, y3),
-                // (each from different series, which is where stackBases comes in),
-                // you'd want the new points to be (x, y1, 0), (x, y1+y2, y1), (x, y1+y2+y3, y1+y2)
-                // generally, (x, thisValue + (base up to this point), + (base up to this point))
-                if (!stackBases[datapoints.points[i + key_idx]]) {
-                    stackBases[datapoints.points[i + key_idx]] = 0;
-                }
-                newPoints[i + key_idx] = datapoints.points[i + key_idx];
-                newPoints[i + value_idx] = datapoints.points[i + value_idx] + stackBases[datapoints.points[i + key_idx]];
-                newPoints[i + 2] = stackBases[datapoints.points[i + key_idx]];
-                stackBases[datapoints.points[i + key_idx]] += datapoints.points[i + value_idx];
-                // change points to percentage values
-                // you may need to set yaxis:{ max = 100 }
-                if ( stackSums[newPoints[i+key_idx]+""] > 0 ){
-                    newPoints[i + value_idx] = newPoints[i + value_idx] * 100 / stackSums[newPoints[i + key_idx] + ""];
-                    newPoints[i + 2] = newPoints[i + 2] * 100 / stackSums[newPoints[i + key_idx] + ""];
-                } else {
-                    newPoints[i + value_idx] = 0;
-                    newPoints[i + 2] = 0;
-                }
-            }
-
-            datapoints.points = newPoints;
-        }
-
-        plot.hooks.processRawData.push(processRawData);
-        plot.hooks.processDatapoints.push(stackData);
-    }
-
-    $.plot.plugins.push({
-        init: init,
-        options: options,
-        name: 'stackpercent',
-        version: '0.1'
-    });
-})(jQuery);

+ 23 - 9
common/lib/panels/jquery.flot.time.js

@@ -1,6 +1,6 @@
 /* Pretty handling of time axes.
 
-Copyright (c) 2007-2012 IOLA and Ole Laursen.
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
 Licensed under the MIT license.
 
 Set axis.mode to "time" to enable. See the section "Time series data" in
@@ -10,7 +10,14 @@ API.txt for details.
 
 (function($) {
 
-	var options = {};
+	var options = {
+		xaxis: {
+			timezone: null,		// "browser" for local to the client or timezone for timezone-js
+			timeformat: null,	// format string to use
+			twelveHourClock: false,	// 12 or 24 time in time mode
+			monthNames: null	// list of names of months
+		}
+	};
 
 	// round to nearby lower multiple of base
 
@@ -66,6 +73,7 @@ API.txt for details.
 					case 'b': c = "" + monthNames[d.getMonth()]; break;
 					case 'd': c = leftPad(d.getDate()); break;
 					case 'e': c = leftPad(d.getDate(), " "); break;
+					case 'h':	// For back-compat with 0.7; remove in 1.0
 					case 'H': c = leftPad(hours); break;
 					case 'I': c = leftPad(hours12); break;
 					case 'l': c = leftPad(hours12, " "); break;
@@ -187,7 +195,7 @@ API.txt for details.
 		[1, "year"]]);
 
 	function init(plot) {
-		plot.hooks.processDatapoints.push(function (plot, series, datapoints) {
+		plot.hooks.processOptions.push(function (plot, options) {
 			$.each(plot.getAxes(), function(axisName, axis) {
 
 				var opts = axis.options;
@@ -287,17 +295,23 @@ API.txt for details.
 
 						if (step >= timeUnitSize.minute) {
 							d.setSeconds(0);
-						} else if (step >= timeUnitSize.hour) {
+						}
+						if (step >= timeUnitSize.hour) {
 							d.setMinutes(0);
-						} else if (step >= timeUnitSize.day) {
+						}
+						if (step >= timeUnitSize.day) {
 							d.setHours(0);
-						} else if (step >= timeUnitSize.day * 4) {
+						}
+						if (step >= timeUnitSize.day * 4) {
 							d.setDate(1);
-						} else if (step >= timeUnitSize.month * 2) {
+						}
+						if (step >= timeUnitSize.month * 2) {
 							d.setMonth(floorInBase(d.getMonth(), 3));
-						} else if (step >= timeUnitSize.quarter * 2) {
+						}
+						if (step >= timeUnitSize.quarter * 2) {
 							d.setMonth(floorInBase(d.getMonth(), 6));
-						} else if (step >= timeUnitSize.year) {
+						}
+						if (step >= timeUnitSize.year) {
 							d.setMonth(0);
 						}
 

+ 5 - 4
index.html

@@ -16,7 +16,6 @@
     <link rel="stylesheet" href="common/css/animate.min.css">
     <link rel="stylesheet" href="common/css/bootstrap-responsive.min.css">
     <link rel="stylesheet" href="common/css/font-awesome.min.css">
-    <link rel="stylesheet" href="common/css/main.css">
     <link rel="stylesheet" href="common/css/timepicker.css">
   
     <!-- project dependency libs -->
@@ -26,13 +25,15 @@
     <script src="config.js"></script>
     <script src="js/app.js"></script>
 
+    <style>
+    </style>
 
   </head>
 
   <body ng-controller="DashCtrl" ng-cloak>
-    <div ng-repeat='alert in global_alert' class="alert alert-{{alert.severity}} span12" style="position: fixed;top:2px;opacity:0.9;z-index:8000">
-      <button type="button" class="close" ng-click="clear_alert(alert)">&times;</button>
-      <strong>{{alert.title}}</strong> <span ng-bind-html-unsafe='alert.text'></span> <div class='pull-right small'> {{$index + 1}} alert(s) </div>
+    <div ng-repeat='alert in global_alert' class="alert-{{alert.severity}} dashboard-notice" ng-show="$last">
+      <button type="button" class="close" ng-click="clear_alert(alert)" style="padding-right:50px">&times;</button>
+      <strong>{{alert.title}}</strong> <span ng-bind-html-unsafe='alert.text'></span> <div style="padding-right:10px" class='pull-right small'> {{$index + 1}} alert(s) </div>
     </div>
     <div class="navbar navbar-static-top">
       <div class="navbar-inner">

+ 6 - 2
js/directives.js

@@ -7,11 +7,15 @@ angular.module('kibana.directives', [])
   return {
     restrict: 'E',
     link: function(scope, elem, attrs) {
-      var template = '<img src="common/img/load.gif" class="panel-loading" ng-show="panelMeta.loading == true">'+
+      var template = '<i class="icon-spinner small icon-spin icon-large panel-loading" '+
+        'ng-show="panelMeta.loading == true && !panel.title"></i>'+
         ' <span class="editlink panelextra pointer" style="right:15px;top:0px" ' + 
         'bs-modal="\'partials/paneleditor.html\'" ng-show="panel.editable != false">'+
         '<span class="small">{{panel.type}}</span> <i class="icon-cog pointer"></i> '+
-        '</span><h4>{{panel.title}}</h4>';
+        '</span><h4>'+
+        '{{panel.title}} '+
+        '<i class="icon-spinner smaller icon-spin icon-large" ng-show="panelMeta.loading == true && panel.title"></i>'+
+        '</h4>';
       elem.prepend($compile(angular.element(template))(scope));
     }
   };

+ 2 - 1
package.json

@@ -8,7 +8,8 @@
   "devDependencies": {
     "grunt": "~0.4.0",
     "grunt-contrib": "~0.7.0",
-    "grunt-contrib-jshint": "~0.6.0"
+    "grunt-contrib-jshint": "~0.6.0",
+    "assemble-less": "~0.4.8"
   },
   "license": "Apache License"
 }

+ 5 - 5
panels/histogram/module.js

@@ -165,6 +165,7 @@ angular.module('kibana.histogram', [])
             data = [];
             if(filterSrv.idsByType('time').length > 0) {
               data = [[_range.from.getTime(), null],[_range.to.getTime(), null]];
+              //data = [];
             }
             hits = 0;
           } else {
@@ -313,7 +314,7 @@ angular.module('kibana.histogram', [])
                   lineWidth: scope.panel.linewidth,
                   steps: false
                 },
-                bars:   { show: scope.panel.bars,  fill: 1, barWidth: barwidth/1.8 },
+                bars:   { show: scope.panel.bars,  fill: 1, barWidth: barwidth/1.8, zero: false },
                 points: { show: scope.panel.points, fill: 1, fillColor: false, radius: 5},
                 shadowSize: 1
               },
@@ -321,22 +322,21 @@ angular.module('kibana.histogram', [])
                 show: scope.panel['y-axis'], 
                 min: 0, 
                 max: scope.panel.percentage && scope.panel.stack ? 100 : null, 
-                color: "#c8c8c8" 
               },
               xaxis: {
                 timezone: scope.panel.timezone,
                 show: scope.panel['x-axis'],
                 mode: "time",
+                min: scope.range.from.getTime(),
+                max: scope.range.to.getTime(),
                 timeformat: time_format(scope.panel.interval),
                 label: "Datetime",
-                color: "#c8c8c8",
               },
               grid: {
                 backgroundColor: null,
                 borderWidth: 0,
-                borderColor: '#eee',
-                color: "#eee",
                 hoverable: true,
+                color: '#c8c8c8'
               }
             };
 

+ 1 - 1
panels/table/editor.html

@@ -8,7 +8,7 @@
     </div>
     <div class="span8">
       <h6>Columns <small>Click to remove</small></h6>
-      <span style="margin-left:3px" ng-click="toggle_field(field)" ng-repeat="field in $parent.panel.fields" class="label remove pointer">{{field}} </span>
+      <span style="margin-left:3px" ng-click="toggle_field(field)" ng-repeat="field in $parent.panel.fields" class="label pointer remove">{{field}} </span>
     </div>
   </div>
   <div class="row-fluid">    

+ 1 - 1
partials/inspector.html

@@ -7,7 +7,7 @@
   <div>
     <h5>Last Elasticsearch Query</h5>
     <pre>curl -XGET '{{config.elasticsearch}}/{{dashboard.indices|stringify}}/_search?pretty' -d '{{inspector}}'
-    </pre>"
+    </pre>
   </div>
   
 </div>

+ 13 - 0
vendor/bootstrap/less/overrides.less

@@ -190,3 +190,16 @@
 .faded {
   opacity: 0.2;
 }
+
+div.flot-text {
+  color: @textColor !important;
+}
+
+.dashboard-notice {
+  z-index:8000;
+  margin-left:0px;
+  padding:3px 0px 3px 0px;
+  width:100%;
+  color: @textColor;
+  padding-left:20px;
+}

+ 1 - 1
vendor/bootstrap/less/variables.light.less

@@ -32,7 +32,7 @@
 
 // Scaffolding
 // -------------------------
-@bodyBackground:        @white;
+@bodyBackground:        #ffffff;
 @textColor:             @grayDark;
 
 

部分文件因文件數量過多而無法顯示