blob: d204a03dc1e75c235a70c8827b8b31de7e7d939b [file]
<!-- The <dots-sk> custom element declaration.
A custom element for displaying a dot chart of digests by trace, such as:
ooo-o-o-oo•••
Attributes:
withblame - Boolean attribute that controls whether to show blame
information, defaults to false.
Events:
commit-selected - Event generated when a dot is clicked.
e.detail contains a slice of commits that could have
made up that dot.
hover - Event generated when the mouse hovers over a trace.
e.detail is the trace id.
Methods:
setValue(value) - Where value is an object of the form:
{
tileSize: 50,
traces: [
{
label: "some:trace:id",
data: [
{
x: 2, // Commit index.
y: 0, // Trace index.
s: 0 // Color code.
},
{ x: 5, y: 0, s: 1 },
...
],
},
...
]
}
Where s is a color code, 0 is the target digest, while
1-6 indicate unique digests that are different from
the target digest. A code of 7 means that there are more
than 7 unique digests in the trace and all digests
after the first 7 unique digests are represented by
this code.
setCommits(commits) - Where commits is an array of commits:
[
{
author: "committer@example.org"
commit_time: 1428445634
hash: "c654e9016a15985ebeb24f94f819d113ad48a251"
},
...
]
-->
<polymer-element name="dots-sk" attributes="withblame">
<template>
<style type="text/css" media="screen">
g:hover circle {
fill: #E7298A;
stroke: #E7298A;
}
circle.status0 {
fill: #000000;
stroke: #000000;
}
circle.status1 {
fill: #ffffff;
stroke: #1B9E77;
}
circle.status2 {
fill: #ffffff;
stroke: #D95F02;
}
circle.status3 {
fill: #ffffff;
stroke: #7570B3;
}
circle.status4 {
fill: #ffffff;
stroke: #E7298A;
}
circle.status5 {
fill: #ffffff;
stroke: #66A61E;
}
circle.status6 {
fill: #ffffff;
stroke: #E6AB02;
}
circle.status7 {
fill: #ffffff;
stroke: #A6761D;
}
circle.status8 {
fill: #ffffff;
stroke: #999999;
}
.circHoverCommit {
fill: #E7298A !important;
stroke: #E7298A !important;
}
div.commitEntry:hover {
color: #E7298A;
}
div.commitEntry {
padding-left: 2em;
}
.blameHeader {
font-weight: bold;
padding-top: 1em;
}
.blameContainer {
padding-top: 1em;
padding-bottom: 1em;
}
.footNote {
padding-top: 1em;
}
</style>
<svg id=dots
width="{{(value.tileSize)*10+20}}"
height="{{(value.traces.length+2)*10}}"
viewBox="-1 -1 {{value.tileSize+1}} {{value.traces.length+1}}">
<template repeat="{{trace, i in value.traces}}">
<g data-id="{{trace.label}}" stroke="#999" fill="#999" stroke-width="0.2">
<line
x1="{{trace.data[0].x}}"
y1="{{trace.data[0].y}}"
x2="{{trace.data[trace.data.length-1].x}}"
y2="{{trace.data[0].y}}"/>
<template repeat="{{pt, j in trace.data}}">
<circle cx="{{pt.x}}" cy="{{pt.y}}" r="0.3"
id="{{'circ-' + i + '-' + j}}" class="status{{pt.s}}"/>
</template>
</g>
</template>
</svg>
<template if="{{withblame && value.blame.freq.length > 0}}">
<div class="blameContainer">
<div class="blameHeader">Blame</div>
<template repeat="{{b in value.blame.freq}}">
<div class="commitEntry" data-idx="{{b}}" on-mouseover="{{hoverCommits}}" on-mouseout="{{hoverCommits}}">
{{commits[b].commit_time | humanDiffDate}} - {{commits[b].author}}
</div>
</template>
<template if="{{value.blame.old}}">
<div class="footNote">
* Digest appeared before current range. Blame might be incorrect.
</div>
</template>
</div>
</template>
<template if="{{withblame && !(value.blame.freq.length > 0)}}">
<div class="blameContainer">
No blames available - Digest too old !
</div>
</template>
</template>
<script>
Polymer({
publish: {
withblame: {
value: false,
reflect: true
}
},
ready: function() {
// Keep track of the last element hovered over to reduce the number of
// events we generate.
this.hoverElement = null;
this.value = {};
this.commits = [];
var that = this;
this.$.dots.addEventListener('mouseover', function(e) {
if (e.target.nodeName == "circle" && that.hoverElement != e.target) {
that.hoverElement = e.target;
that.dispatchEvent(new CustomEvent('hover', {detail: e.target.parentElement.dataset.id}));
}
});
this.$.dots.addEventListener('click', function(e) {
if (e.target.nodeName == "circle") {
// The dots cx value is actually the offset into the list of commits.
// The cy is the offset into the list of traces.
var x = e.target.cx.baseVal.value;
var y = e.target.cy.baseVal.value;
// Look backwards in the trace for the previous commit with data.
var firstCommit = 0;
var trace = that.value.traces[y];
for (var i=trace.data.length-1; i>=0; i--) {
if (trace.data[i].x == x) {
if (i>0) {
firstCommit = trace.data[i-1].x+1;
break;
}
}
}
var commitinfo = that.value.commits.slice(firstCommit, x+1);
commitinfo.reverse();
that.dispatchEvent(new CustomEvent('commit-selected', {detail: commitinfo, "bubbles": true}));
}
});
},
setValue: function(value) {
this.value = value;
},
setCommits: function(commits) {
this.commits = commits;
},
hoverCommits: function(e) {
var commitIdx = parseInt(e.target.attributes['data-idx'].value);
var targetNodes = [];
for(var i=0, iLen=this.value.traces.length; i < iLen; i++) {
for(var j=0, jLen=this.value.traces[i].data.length; j < jLen; j++) {
if (this.value.traces[i].data[j].x >= commitIdx) {
targetNodes.push(this.shadowRoot.querySelector('#circ-' + i + '-' + j));
break;
}
}
}
if (e.type == 'mouseover') {
targetNodes.forEach(function(ele) {
ele.classList.add('circHoverCommit');
});
} else {
targetNodes.forEach(function(ele) {
ele.classList.remove('circHoverCommit');
});
}
},
humanDiffDate: function(s) {
return sk.human.diffDate(s*1000);
}
});
</script>
</polymer-element>