summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/network/branch_graph.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/network/branch_graph.js')
-rw-r--r--app/assets/javascripts/network/branch_graph.js418
1 files changed, 418 insertions, 0 deletions
diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js
new file mode 100644
index 00000000000..74dbeb94741
--- /dev/null
+++ b/app/assets/javascripts/network/branch_graph.js
@@ -0,0 +1,418 @@
+/* eslint-disable */
+(function() {
+ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+
+ this.BranchGraph = (function() {
+ function BranchGraph(element1, options1) {
+ this.element = element1;
+ this.options = options1;
+ this.scrollTop = bind(this.scrollTop, this);
+ this.scrollBottom = bind(this.scrollBottom, this);
+ this.scrollRight = bind(this.scrollRight, this);
+ this.scrollLeft = bind(this.scrollLeft, this);
+ this.scrollUp = bind(this.scrollUp, this);
+ this.scrollDown = bind(this.scrollDown, this);
+ this.preparedCommits = {};
+ this.mtime = 0;
+ this.mspace = 0;
+ this.parents = {};
+ this.colors = ["#000"];
+ this.offsetX = 150;
+ this.offsetY = 20;
+ this.unitTime = 30;
+ this.unitSpace = 10;
+ this.prev_start = -1;
+ this.load();
+ }
+
+ BranchGraph.prototype.load = function() {
+ return $.ajax({
+ url: this.options.url,
+ method: "get",
+ dataType: "json",
+ success: $.proxy(function(data) {
+ $(".loading", this.element).hide();
+ this.prepareData(data.days, data.commits);
+ return this.buildGraph();
+ }, this)
+ });
+ };
+
+ BranchGraph.prototype.prepareData = function(days, commits) {
+ var c, ch, cw, j, len, ref;
+ this.days = days;
+ this.commits = commits;
+ this.collectParents();
+ this.graphHeight = $(this.element).height();
+ this.graphWidth = $(this.element).width();
+ ch = Math.max(this.graphHeight, this.offsetY + this.unitTime * this.mtime + 150);
+ cw = Math.max(this.graphWidth, this.offsetX + this.unitSpace * this.mspace + 300);
+ this.r = Raphael(this.element.get(0), cw, ch);
+ this.top = this.r.set();
+ this.barHeight = Math.max(this.graphHeight, this.unitTime * this.days.length + 320);
+ ref = this.commits;
+ for (j = 0, len = ref.length; j < len; j++) {
+ c = ref[j];
+ if (c.id in this.parents) {
+ c.isParent = true;
+ }
+ this.preparedCommits[c.id] = c;
+ this.markCommit(c);
+ }
+ return this.collectColors();
+ };
+
+ BranchGraph.prototype.collectParents = function() {
+ var c, j, len, p, ref, results;
+ ref = this.commits;
+ results = [];
+ for (j = 0, len = ref.length; j < len; j++) {
+ c = ref[j];
+ this.mtime = Math.max(this.mtime, c.time);
+ this.mspace = Math.max(this.mspace, c.space);
+ results.push((function() {
+ var l, len1, ref1, results1;
+ ref1 = c.parents;
+ results1 = [];
+ for (l = 0, len1 = ref1.length; l < len1; l++) {
+ p = ref1[l];
+ this.parents[p[0]] = true;
+ results1.push(this.mspace = Math.max(this.mspace, p[1]));
+ }
+ return results1;
+ }).call(this));
+ }
+ return results;
+ };
+
+ BranchGraph.prototype.collectColors = function() {
+ var k, results;
+ k = 0;
+ results = [];
+ while (k < this.mspace) {
+ this.colors.push(Raphael.getColor(.8));
+ // Skipping a few colors in the spectrum to get more contrast between colors
+ Raphael.getColor();
+ Raphael.getColor();
+ results.push(k++);
+ }
+ return results;
+ };
+
+ BranchGraph.prototype.buildGraph = function() {
+ var cuday, cumonth, day, j, len, mm, r, ref;
+ r = this.r;
+ cuday = 0;
+ cumonth = "";
+ r.rect(0, 0, 40, this.barHeight).attr({
+ fill: "#222"
+ });
+ r.rect(40, 0, 30, this.barHeight).attr({
+ fill: "#444"
+ });
+ ref = this.days;
+ for (mm = j = 0, len = ref.length; j < len; mm = ++j) {
+ day = ref[mm];
+ if (cuday !== day[0] || cumonth !== day[1]) {
+ // Dates
+ r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({
+ font: "12px Monaco, monospace",
+ fill: "#BBB"
+ });
+ cuday = day[0];
+ }
+ if (cumonth !== day[1]) {
+ // Months
+ r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({
+ font: "12px Monaco, monospace",
+ fill: "#EEE"
+ });
+ cumonth = day[1];
+ }
+ }
+ this.renderPartialGraph();
+ return this.bindEvents();
+ };
+
+ BranchGraph.prototype.renderPartialGraph = function() {
+ var commit, end, i, isGraphEdge, start, x, y;
+ start = Math.floor((this.element.scrollTop() - this.offsetY) / this.unitTime) - 10;
+ if (start < 0) {
+ isGraphEdge = true;
+ start = 0;
+ }
+ end = start + 40;
+ if (this.commits.length < end) {
+ isGraphEdge = true;
+ end = this.commits.length;
+ }
+ if (this.prev_start === -1 || Math.abs(this.prev_start - start) > 10 || isGraphEdge) {
+ i = start;
+ this.prev_start = start;
+ while (i < end) {
+ commit = this.commits[i];
+ i += 1;
+ if (commit.hasDrawn !== true) {
+ x = this.offsetX + this.unitSpace * (this.mspace - commit.space);
+ y = this.offsetY + this.unitTime * commit.time;
+ this.drawDot(x, y, commit);
+ this.drawLines(x, y, commit);
+ this.appendLabel(x, y, commit);
+ this.appendAnchor(x, y, commit);
+ commit.hasDrawn = true;
+ }
+ }
+ return this.top.toFront();
+ }
+ };
+
+ BranchGraph.prototype.bindEvents = function() {
+ var element;
+ element = this.element;
+ return $(element).scroll((function(_this) {
+ return function(event) {
+ return _this.renderPartialGraph();
+ };
+ })(this));
+ };
+
+ BranchGraph.prototype.scrollDown = function() {
+ this.element.scrollTop(this.element.scrollTop() + 50);
+ return this.renderPartialGraph();
+ };
+
+ BranchGraph.prototype.scrollUp = function() {
+ this.element.scrollTop(this.element.scrollTop() - 50);
+ return this.renderPartialGraph();
+ };
+
+ BranchGraph.prototype.scrollLeft = function() {
+ this.element.scrollLeft(this.element.scrollLeft() - 50);
+ return this.renderPartialGraph();
+ };
+
+ BranchGraph.prototype.scrollRight = function() {
+ this.element.scrollLeft(this.element.scrollLeft() + 50);
+ return this.renderPartialGraph();
+ };
+
+ BranchGraph.prototype.scrollBottom = function() {
+ return this.element.scrollTop(this.element.find('svg').height());
+ };
+
+ BranchGraph.prototype.scrollTop = function() {
+ return this.element.scrollTop(0);
+ };
+
+ BranchGraph.prototype.appendLabel = function(x, y, commit) {
+ var label, r, rect, shortrefs, text, textbox, triangle;
+ if (!commit.refs) {
+ return;
+ }
+ r = this.r;
+ shortrefs = commit.refs;
+ // Truncate if longer than 15 chars
+ if (shortrefs.length > 17) {
+ shortrefs = shortrefs.substr(0, 15) + "…";
+ }
+ text = r.text(x + 4, y, shortrefs).attr({
+ "text-anchor": "start",
+ font: "10px Monaco, monospace",
+ fill: "#FFF",
+ title: commit.refs
+ });
+ textbox = text.getBBox();
+ // Create rectangle based on the size of the textbox
+ rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({
+ fill: "#000",
+ "fill-opacity": .5,
+ stroke: "none"
+ });
+ triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr({
+ fill: "#000",
+ "fill-opacity": .5,
+ stroke: "none"
+ });
+ label = r.set(rect, text);
+ label.transform(["t", -rect.getBBox().width - 15, 0]);
+ // Set text to front
+ return text.toFront();
+ };
+
+ BranchGraph.prototype.appendAnchor = function(x, y, commit) {
+ var anchor, options, r, top;
+ r = this.r;
+ top = this.top;
+ options = this.options;
+ anchor = r.circle(x, y, 10).attr({
+ fill: "#000",
+ opacity: 0,
+ cursor: "pointer"
+ }).click(function() {
+ return window.open(options.commit_url.replace("%s", commit.id), "_blank");
+ }).hover(function() {
+ this.tooltip = r.commitTooltip(x + 5, y, commit);
+ return top.push(this.tooltip.insertBefore(this));
+ }, function() {
+ return this.tooltip && this.tooltip.remove() && delete this.tooltip;
+ });
+ return top.push(anchor);
+ };
+
+ BranchGraph.prototype.drawDot = function(x, y, commit) {
+ var avatar_box_x, avatar_box_y, r;
+ r = this.r;
+ r.circle(x, y, 3).attr({
+ fill: this.colors[commit.space],
+ stroke: "none"
+ });
+ avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10;
+ avatar_box_y = y - 10;
+ r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({
+ stroke: this.colors[commit.space],
+ "stroke-width": 2
+ });
+ r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20);
+ return r.text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split("\n")[0]).attr({
+ "text-anchor": "start",
+ font: "14px Monaco, monospace"
+ });
+ };
+
+ BranchGraph.prototype.drawLines = function(x, y, commit) {
+ var arrow, color, i, j, len, offset, parent, parentCommit, parentX1, parentX2, parentY, r, ref, results, route;
+ r = this.r;
+ ref = commit.parents;
+ results = [];
+ for (i = j = 0, len = ref.length; j < len; i = ++j) {
+ parent = ref[i];
+ parentCommit = this.preparedCommits[parent[0]];
+ parentY = this.offsetY + this.unitTime * parentCommit.time;
+ parentX1 = this.offsetX + this.unitSpace * (this.mspace - parentCommit.space);
+ parentX2 = this.offsetX + this.unitSpace * (this.mspace - parent[1]);
+ // Set line color
+ if (parentCommit.space <= commit.space) {
+ color = this.colors[commit.space];
+ } else {
+ color = this.colors[parentCommit.space];
+ }
+ // Build line shape
+ if (parent[1] === commit.space) {
+ offset = [0, 5];
+ arrow = "l-2,5,4,0,-2,-5,0,5";
+ } else if (parent[1] < commit.space) {
+ offset = [3, 3];
+ arrow = "l5,0,-2,4,-3,-4,4,2";
+ } else {
+ offset = [-3, 3];
+ arrow = "l-5,0,2,4,3,-4,-4,2";
+ }
+ // Start point
+ route = ["M", x + offset[0], y + offset[1]];
+ // Add arrow if not first parent
+ if (i > 0) {
+ route.push(arrow);
+ }
+ // Circumvent if overlap
+ if (commit.space !== parentCommit.space || commit.space !== parent[1]) {
+ route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5);
+ }
+ // End point
+ route.push("L", parentX1, parentY);
+ results.push(r.path(route).attr({
+ stroke: color,
+ "stroke-width": 2
+ }));
+ }
+ return results;
+ };
+
+ BranchGraph.prototype.markCommit = function(commit) {
+ var r, x, y;
+ if (commit.id === this.options.commit_id) {
+ r = this.r;
+ x = this.offsetX + this.unitSpace * (this.mspace - commit.space);
+ y = this.offsetY + this.unitTime * commit.time;
+ r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr({
+ fill: "#000",
+ "fill-opacity": .5,
+ stroke: "none"
+ });
+ // Displayed in the center
+ return this.element.scrollTop(y - this.graphHeight / 2);
+ }
+ };
+
+ return BranchGraph;
+
+ })();
+
+ Raphael.prototype.commitTooltip = function(x, y, commit) {
+ var boxHeight, boxWidth, icon, idText, messageText, nameText, rect, textSet, tooltip;
+ boxWidth = 300;
+ boxHeight = 200;
+ icon = this.image(gon.relative_url_root + commit.author.icon, x, y, 20, 20);
+ nameText = this.text(x + 25, y + 10, commit.author.name);
+ idText = this.text(x, y + 35, commit.id);
+ messageText = this.text(x, y + 50, commit.message);
+ textSet = this.set(icon, nameText, idText, messageText).attr({
+ "text-anchor": "start",
+ font: "12px Monaco, monospace"
+ });
+ nameText.attr({
+ font: "14px Arial",
+ "font-weight": "bold"
+ });
+ idText.attr({
+ fill: "#AAA"
+ });
+ this.textWrap(messageText, boxWidth - 50);
+ rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({
+ fill: "#FFF",
+ stroke: "#000",
+ "stroke-linecap": "round",
+ "stroke-width": 2
+ });
+ tooltip = this.set(rect, textSet);
+ rect.attr({
+ height: tooltip.getBBox().height + 10,
+ width: tooltip.getBBox().width + 10
+ });
+ tooltip.transform(["t", 20, 20]);
+ return tooltip;
+ };
+
+ Raphael.prototype.textWrap = function(t, width) {
+ var abc, b, content, h, j, len, letterWidth, s, word, words, x;
+ content = t.attr("text");
+ abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ t.attr({
+ text: abc
+ });
+ letterWidth = t.getBBox().width / abc.length;
+ t.attr({
+ text: content
+ });
+ words = content.split(" ");
+ x = 0;
+ s = [];
+ for (j = 0, len = words.length; j < len; j++) {
+ word = words[j];
+ if (x + (word.length * letterWidth) > width) {
+ s.push("\n");
+ x = 0;
+ }
+ x += word.length * letterWidth;
+ s.push(word + " ");
+ }
+ t.attr({
+ text: s.join("")
+ });
+ b = t.getBBox();
+ h = Math.abs(b.y2) - Math.abs(b.y) + 1;
+ return t.attr({
+ y: b.y + h
+ });
+ };
+
+}).call(this);