| <!-- The <plot-sk> custom element declaration. |
| |
| Events: |
| selected - A point on a trace has been clicked on. |
| detail.begin, |
| detail.end - The indices of the point clicked and |
| the index of the previous data point, useful for looking |
| up the commits that correspond to the data points. Note that |
| detail.end can be undefined if there is no previous data point. |
| detail.id - The key of the trace clicked on. |
| detail.params - The params for the selected trace. |
| |
| highlighted - The mouse is hovering over a trace. |
| detail.id - The key of the trace clicked on. |
| detail.value - The value of the point we are near. |
| |
| Methods: |
| addTraces(traces) - Adds the given traces to the plot. |
| |
| clear() - Remove all traces. |
| |
| remove(id) - Remove a trace with the given id. |
| |
| only(id) - Remove all traces but the one with the given id. |
| |
| removeUnHighlighted() - Remove all traces currently unhighlighted. |
| |
| setBackgroundInfo(ticks, skps, lastCommitIndex) - Sets the tick marks, |
| the skp background banding, and the index of the last commit. |
| |
| highlightGroup(key, value) - Highlight all traces that have params |
| that match the given key and value. |
| |
| getKeys() - Return the keys of all the traces being displayed. |
| |
| Attributes: |
| - stepIndex |
| --> |
| <polymer-element name="plot-sk"> |
| <template> |
| <!-- The style must be inline, Because Flot. --> |
| <div id=plot style="width:100%; height:400px"></div> |
| </template> |
| <script> |
| Polymer({ |
| // We can't be in Shadow DOM, Because Flot. So force |
| // the template expansion to be in the Light DOM. |
| parseDeclaration: function(elementElement) { |
| var template = this.fetchTemplate(elementElement); |
| if (template != null) { |
| this.lightFromTemplate(template); |
| }; |
| }, |
| |
| ready: function() { |
| // Stores the keys of the currently selected lines, used in the drawSeries |
| // hook to highlight that line. |
| this.curHighlightedLines = []; |
| |
| // The index where alerting found a step. |
| this.stepIndex = -1; |
| |
| // The alternating background bands we draw for SKP updates. |
| this.skps = []; |
| |
| // The index of the last valid commit. |
| this.lastCommitIndex = 0; |
| |
| var that = this; |
| // The underlying Flot chart. |
| this.plotRef = jQuery(this.$.plot).plot([], |
| { |
| legend: { |
| show: false |
| }, |
| grid: { |
| hoverable: true, |
| autoHighlight: true, |
| mouseActiveRadius: 16, |
| clickable: true, |
| markings: function() { return that.skps; } |
| }, |
| xaxis: { |
| ticks: [], |
| zoomRange: false, |
| panRange: false, |
| }, |
| yaxis: { |
| }, |
| crosshair: { |
| mode: 'xy' |
| }, |
| zoom: { |
| interactive: true |
| }, |
| pan: { |
| interactive: false, |
| frameRate: 60 |
| }, |
| hooks: { |
| draw: [that.drawAnnotations_.bind(that)], |
| drawSeries: [that.drawHighlightedLine_.bind(that)] |
| }, |
| selection: { |
| mode: "xy", |
| color: "#ddd" |
| } |
| }).data('plot'); |
| |
| // Handle dragging out a rect and zooming into that selection. |
| jQuery(this.$.plot).bind('plotselected', function(event, ranges) { |
| that.plotRef.getOptions().xaxes[0].min = ranges.xaxis.from; |
| that.plotRef.getOptions().xaxes[0].max = ranges.xaxis.to; |
| that.plotRef.getOptions().yaxes[0].min = ranges.yaxis.from; |
| that.plotRef.getOptions().yaxes[0].max = ranges.yaxis.to; |
| that.plotRef.clearSelection(); |
| that.plotRef.setupGrid(); |
| that.plotRef.draw(); |
| }); |
| |
| // Generate an event when a trace is clicked on. |
| jQuery(this.$.plot).bind('plotclick', function(e, pos, item) { |
| if (!item) { |
| return; |
| } |
| var beginIndex = item.datapoint[0]; |
| var endIndex = undefined; |
| if (beginIndex > 0) { |
| endIndex = beginIndex; |
| beginIndex = item.series.data[item.dataIndex-1][0] |
| } |
| var detail = { |
| begin: beginIndex, |
| end: endIndex, |
| id: item.series.label, |
| params: item.series._params |
| }; |
| that.dispatchEvent(new CustomEvent('selected', {detail: detail})); |
| }); |
| |
| // Generate an event as the mouse hovers over a trace. |
| jQuery(this.$.plot).bind('plothover', function(e, pos, item) { |
| if (!item) { |
| return; |
| } |
| var detail = { |
| id: item.series.label, |
| value: item.datapoint[1] |
| }; |
| that.dispatchEvent(new CustomEvent('highlighted', {detail: detail})); |
| var lastHighlightedLines = that.curHighlightedLines.slice(0); |
| that.curHighlightedLines = [item.series.label]; |
| if (!sk.array.equal(lastHighlightedLines, that.curHighlightedLines)) { |
| that.plotRef.draw(); |
| } |
| }); |
| |
| }, |
| |
| // Returns the keys of all the traces being displayed. |
| getKeys: function() { |
| var keys = []; |
| this.plotRef.getData().forEach(function(s) { |
| keys.push(s.label); |
| }); |
| return keys; |
| }, |
| |
| // Clear the plot of all traces. |
| clear: function() { |
| this.plotRef.setData([]); |
| this.curHighlightedLines = []; |
| this.stepIndex = -1; |
| this.plotRef.setupGrid(); |
| this.plotRef.draw(); |
| }, |
| |
| // Reset the axes to the default extent. |
| resetAxes: function() { |
| var options = this.plotRef.getOptions(); |
| var cleanYAxes = function(axis) { |
| axis.max = null; |
| axis.min = null; |
| }; |
| var cleanXAxes = function(axis) { |
| axis.max = this.lastCommitIndex; |
| axis.min = 0; |
| }; |
| options.xaxes.forEach(cleanXAxes); |
| options.yaxes.forEach(cleanYAxes); |
| |
| this.plotRef.setupGrid(); |
| this.plotRef.draw(); |
| }, |
| |
| // Remove all traces currently not highlighted. |
| removeUnHighlighted: function() { |
| var that = this; |
| var series = this.plotRef.getData().filter(function(s) { |
| return -1 !== that.curHighlightedLines.indexOf(s.label); |
| }); |
| this.plotRef.setData(series); |
| this.plotRef.setupGrid(); |
| this.plotRef.draw(); |
| }, |
| |
| // Remove the trace with the given id. |
| remove: function(id) { |
| var that = this; |
| var series = this.plotRef.getData().filter(function(s) { |
| return s.label !== id; |
| }); |
| this.plotRef.setData(series); |
| this.plotRef.setupGrid(); |
| this.plotRef.draw(); |
| }, |
| |
| // Remove all traces except the one with the given id. |
| only: function(id) { |
| var that = this; |
| var series = this.plotRef.getData().filter(function(s) { |
| return s.label === id; |
| }); |
| this.plotRef.setData(series); |
| this.plotRef.setupGrid(); |
| this.plotRef.draw(); |
| }, |
| |
| // Highlight all traces that match the given param key and value. |
| highlightGroup: function(key, value) { |
| var series = this.plotRef.getData(); |
| this.curHighlightedLines = []; |
| for (var i = 0; i < series.length; ++i) { |
| if (series[i]._params[key] && series[i]._params[key] == value) { |
| this.curHighlightedLines.push(series[i].label); |
| } |
| } |
| this.plotRef.draw(); |
| }, |
| |
| // Add the given traces. The value for traces must be an array of |
| // objects that Flot can accept via setData(). |
| addTraces: function(traces) { |
| // TODO(jcgregorio) Only add a trace if it isn't already being displayed. |
| this.plotRef.setData([].concat(this.plotRef.getData(), traces)); |
| |
| var cleanXAxes = function(axis) { |
| axis.max = this.lastCommitIndex; |
| axis.min = 0; |
| }; |
| this.plotRef.getOptions().xaxes.forEach(cleanXAxes); |
| |
| this.plotRef.setupGrid(); |
| this.plotRef.draw(); |
| }, |
| |
| // Sets the ticks, the SKP banding info, and the index of the last |
| // commit. |
| setBackgroundInfo: function(ticks, skps, lastCommitIndex) { |
| this.skps = []; |
| for (var i = 2, len = skps.length; i < len; i+=2) { |
| this.skps.push({ xaxis: {from: skps[i], to: skps[i-1]}, color: '#eeeeee'}); |
| } |
| this.plotRef.getOptions().xaxes[0]["ticks"] = ticks; |
| this.lastCommitIndex = lastCommitIndex; |
| }, |
| |
| // Draws the big red line at where clustering found a step. |
| drawAnnotations_: function(plot, ctx) { |
| if (this.stepIndex == -1) { |
| return |
| } |
| var yaxes = plot.getAxes().yaxis; |
| var offsets = plot.getPlotOffset(); |
| var lineStart = plot.p2c({'x': this.stepIndex, 'y': yaxes.max}); |
| var lineEnd = plot.p2c({'x': this.stepIndex, 'y': yaxes.min}); |
| ctx.save(); |
| ctx.strokeStyle = 'red'; |
| ctx.lineWidth = 2; |
| ctx.beginPath(); |
| ctx.moveTo(lineStart.left + offsets.left, lineStart.top + offsets.top); |
| ctx.lineTo(lineEnd.left + offsets.left, lineEnd.top + offsets.top); |
| ctx.stroke(); |
| ctx.restore(); |
| }, |
| |
| // Highlights each trace that exists in curHighlightedLines. |
| drawHighlightedLine_: function(plot, canvascontext, series) { |
| if (!series.lines) { |
| series.lines = {}; |
| } |
| if (!series.points) { |
| series.points = {}; |
| } |
| if (-1 != this.curHighlightedLines.indexOf(series.label)) { |
| series.lines.lineWidth = 5; |
| series.points.show = true; |
| } else { |
| series.lines.lineWidth = 1; |
| series.points.show = false; |
| } |
| } |
| |
| }); |
| </script> |
| </polymer-element> |