blob: 695c4e259ff1879799553f4b2e12eed1257c9453 [file] [log] [blame]
<!-- 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>