Commit 1ad1cdba authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'remove-vendored-raphael-library' into 'master'

Refactor network graph bundle to ES module syntax

See merge request !9696
parents 34f3d899 536be744
/* eslint-disable func-names, space-before-function-paren */
/*= require raphael */
/*= require g.raphael */
/*= require g.bar */
(function() {
}).call(window);
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-mixed-operators, new-cap, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len */
/* global Raphael */
/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-mixed-operators, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len */
(function() {
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
import Raphael from './raphael';
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)
});
};
export default (function() {
function BranchGraph(element1, options1) {
this.element = element1;
this.options = options1;
this.scrollTop = this.scrollTop.bind(this);
this.scrollBottom = this.scrollBottom.bind(this);
this.scrollRight = this.scrollRight.bind(this);
this.scrollLeft = this.scrollLeft.bind(this);
this.scrollUp = this.scrollUp.bind(this);
this.scrollDown = this.scrollDown.bind(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.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 += 1) {
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 += 1) {
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 += 1) {
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.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.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 += 1);
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 += 1) {
c = ref[j];
if (c.id in this.parents) {
c.isParent = true;
}
return results;
};
this.preparedCommits[c.id] = c;
this.markCommit(c);
}
return this.collectColors();
};
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 += 1)) {
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];
BranchGraph.prototype.collectParents = function() {
var c, j, len, p, ref, results;
ref = this.commits;
results = [];
for (j = 0, len = ref.length; j < len; j += 1) {
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 += 1) {
p = ref1[l];
this.parents[p[0]] = true;
results1.push(this.mspace = Math.max(this.mspace, p[1]));
}
}
this.renderPartialGraph();
return this.bindEvents();
};
return results1;
}).call(this));
}
return results;
};
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;
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 += 1);
}
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 += 1)) {
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];
}
end = start + 40;
if (this.commits.length < end) {
isGraphEdge = true;
end = this.commits.length;
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];
}
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;
}
}
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());
};
return this.top.toFront();
}
};
BranchGraph.prototype.scrollTop = function() {
return this.element.scrollTop(0);
};
BranchGraph.prototype.bindEvents = function() {
var element;
element = this.element;
return $(element).scroll((function(_this) {
return function(event) {
return _this.renderPartialGraph();
};
})(this));
};
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.scrollDown = function() {
this.element.scrollTop(this.element.scrollTop() + 50);
return this.renderPartialGraph();
};
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.scrollUp = function() {
this.element.scrollTop(this.element.scrollTop() - 50);
return this.renderPartialGraph();
};
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.scrollLeft = function() {
this.element.scrollLeft(this.element.scrollLeft() - 50);
return this.renderPartialGraph();
};
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 += 1)) {
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.scrollRight = function() {
this.element.scrollLeft(this.element.scrollLeft() + 50);
return this.renderPartialGraph();
};
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);
}
};
BranchGraph.prototype.scrollBottom = function() {
return this.element.scrollTop(this.element.find('svg').height());
};
return BranchGraph;
})();
BranchGraph.prototype.scrollTop = function() {
return this.element.scrollTop(0);
};
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.replace(/\r?\n/g, " \n "));
textSet = this.set(icon, nameText, idText, messageText).attr({
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: "12px Monaco, monospace"
});
nameText.attr({
font: "14px Arial",
"font-weight": "bold"
font: "10px Monaco, monospace",
fill: "#FFF",
title: commit.refs
});
idText.attr({
fill: "#AAA"
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"
});
messageText.node.style["white-space"] = "pre";
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
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"
});
tooltip = this.set(rect, textSet);
rect.attr({
height: tooltip.getBBox().height + 10,
width: tooltip.getBBox().width + 10
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;
});
tooltip.transform(["t", 20, 20]);
return tooltip;
return top.push(anchor);
};
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
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"
});
letterWidth = t.getBBox().width / abc.length;
t.attr({
text: content
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
});
words = content.split(" ");
x = 0;
s = [];
for (j = 0, len = words.length; j < len; j += 1) {
word = words[j];
if (x + (word.length * letterWidth) > width) {
s.push("\n");
x = 0;
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 += 1)) {
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];
}
if (word === "\n") {
s.push("\n");
x = 0;
// 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 {
s.push(word + " ");
x += word.length * letterWidth;
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);
}
t.attr({
text: s.join("").trim()
});
b = t.getBBox();
h = Math.abs(b.y2) + 1;
return t.attr({
y: h
});
};
}).call(window);
return BranchGraph;
})();
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, quote-props, prefer-template, comma-dangle, max-len */
/* global BranchGraph */
(function() {
this.Network = (function() {
function Network(opts) {
var vph;
$("#filter_ref").click(function() {
return $(this).closest('form').submit();
});
this.branch_graph = new BranchGraph($(".network-graph"), opts);
vph = $(window).height() - 250;
$('.network-graph').css({
'height': vph + 'px'
});
}
import BranchGraph from './branch_graph';
return Network;
})();
}).call(window);
export default (function() {
function Network(opts) {
var vph;
$("#filter_ref").click(function() {
return $(this).closest('form').submit();
});
this.branch_graph = new BranchGraph($(".network-graph"), opts);
vph = $(window).height() - 250;
$('.network-graph').css({
'height': vph + 'px'
});
}
return Network;
})();
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, quotes, no-var, vars-on-top, camelcase, comma-dangle, consistent-return, max-len */
/* global Network */
/* global ShortcutsNetwork */
require('./branch_graph');
require('./network');
import Network from './network';
(function() {
$(function() {
if (!$(".network-graph").length) return;
$(function() {
if (!$(".network-graph").length) return;
var network_graph;
network_graph = new Network({
url: $(".network-graph").attr('data-url'),
commit_url: $(".network-graph").attr('data-commit-url'),
ref: $(".network-graph").attr('data-ref'),
commit_id: $(".network-graph").attr('data-commit-id')
});
return new ShortcutsNetwork(network_graph.branch_graph);
var network_graph;
network_graph = new Network({
url: $(".network-graph").attr('data-url'),
commit_url: $(".network-graph").attr('data-commit-url'),
ref: $(".network-graph").attr('data-ref'),
commit_id: $(".network-graph").attr('data-commit-id')
});
}).call(window);
return new ShortcutsNetwork(network_graph.branch_graph);
});
import Raphael from 'raphael/raphael';
Raphael.prototype.commitTooltip = function commitTooltip(x, y, commit) {
const boxWidth = 300;
const icon = this.image(gon.relative_url_root + commit.author.icon, x, y, 20, 20);
const nameText = this.text(x + 25, y + 10, commit.author.name);
const idText = this.text(x, y + 35, commit.id);
const messageText = this.text(x, y + 50, commit.message.replace(/\r?\n/g, ' \n '));
const 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',
});
messageText.node.style['white-space'] = 'pre';
this.textWrap(messageText, boxWidth - 50);
const rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({
fill: '#FFF',
stroke: '#000',
'stroke-linecap': 'round',
'stroke-width': 2,
});
const 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 testWrap(t, width) {
const content = t.attr('text');
const abc = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
t.attr({
text: abc,
});
const letterWidth = t.getBBox().width / abc.length;
t.attr({
text: content,
});
const words = content.split(' ');
let x = 0;
const s = [];
for (let j = 0, len = words.length; j < len; j += 1) {
const word = words[j];
if (x + (word.length * letterWidth) > width) {
s.push('\n');
x = 0;
}
if (word === '\n') {
s.push('\n');
x = 0;
} else {
s.push(`${word} `);
x += word.length * letterWidth;
}
}
t.attr({
text: s.join('').trim(),
});
const b = t.getBBox();
const h = Math.abs(b.y2) + 1;
return t.attr({
y: h,
});
};
export default Raphael;
- page_title "Graph", @ref
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/raphael.js')
= page_specific_javascript_bundle_tag('network')
= render "projects/commits/head"
= render "head"
......
......@@ -101,7 +101,6 @@ module Gitlab
config.assets.precompile << "katex.js"
config.assets.precompile << "xterm/xterm.css"
config.assets.precompile << "lib/ace.js"
config.assets.precompile << "lib/raphael.js"
config.assets.precompile << "u2f.js"
config.assets.precompile << "vendor/assets/fonts/*"
......
/*!
* g.Raphael 0.51 - Charting library, based on Raphaël
*
* Copyright (c) 2009-2012 Dmitry Baranovskiy (http://g.raphaeljs.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*/
(function () {
var mmin = Math.min,
mmax = Math.max;
function finger(x, y, width, height, dir, ending, isPath, paper) {
var path,
ends = { round: 'round', sharp: 'sharp', soft: 'soft', square: 'square' };
// dir 0 for horizontal and 1 for vertical
if ((dir && !height) || (!dir && !width)) {
return isPath ? "" : paper.path();
}
ending = ends[ending] || "square";
height = Math.round(height);
width = Math.round(width);
x = Math.round(x);
y = Math.round(y);
switch (ending) {
case "round":
if (!dir) {
var r = ~~(height / 2);
if (width < r) {
r = width;
path = [
"M", x + .5, y + .5 - ~~(height / 2),
"l", 0, 0,
"a", r, ~~(height / 2), 0, 0, 1, 0, height,
"l", 0, 0,
"z"
];
} else {
path = [
"M", x + .5, y + .5 - r,
"l", width - r, 0,
"a", r, r, 0, 1, 1, 0, height,
"l", r - width, 0,
"z"
];
}
} else {
r = ~~(width / 2);
if (height < r) {
r = height;
path = [
"M", x - ~~(width / 2), y,
"l", 0, 0,
"a", ~~(width / 2), r, 0, 0, 1, width, 0,
"l", 0, 0,
"z"
];
} else {
path = [
"M", x - r, y,
"l", 0, r - height,
"a", r, r, 0, 1, 1, width, 0,
"l", 0, height - r,
"z"
];
}
}
break;
case "sharp":
if (!dir) {
var half = ~~(height / 2);
path = [
"M", x, y + half,
"l", 0, -height, mmax(width - half, 0), 0, mmin(half, width), half, -mmin(half, width), half + (half * 2 < height),
"z"
];
} else {
half = ~~(width / 2);
path = [
"M", x + half, y,
"l", -width, 0, 0, -mmax(height - half, 0), half, -mmin(half, height), half, mmin(half, height), half,
"z"
];
}
break;
case "square":
if (!dir) {
path = [
"M", x, y + ~~(height / 2),
"l", 0, -height, width, 0, 0, height,
"z"
];
} else {
path = [
"M", x + ~~(width / 2), y,
"l", 1 - width, 0, 0, -height, width - 1, 0,
"z"
];
}
break;
case "soft":
if (!dir) {
r = mmin(width, Math.round(height / 5));
path = [
"M", x + .5, y + .5 - ~~(height / 2),
"l", width - r, 0,
"a", r, r, 0, 0, 1, r, r,
"l", 0, height - r * 2,
"a", r, r, 0, 0, 1, -r, r,
"l", r - width, 0,
"z"
];
} else {
r = mmin(Math.round(width / 5), height);
path = [
"M", x - ~~(width / 2), y,
"l", 0, r - height,
"a", r, r, 0, 0, 1, r, -r,
"l", width - 2 * r, 0,
"a", r, r, 0, 0, 1, r, r,
"l", 0, height - r,
"z"
];
}
}
if (isPath) {
return path.join(",");
} else {
return paper.path(path);
}
}
/*\
* Paper.vbarchart
[ method ]
**
* Creates a vertical bar chart
**
> Parameters
**
- x (number) x coordinate of the chart
- y (number) y coordinate of the chart
- width (number) width of the chart (respected by all elements in the set)
- height (number) height of the chart (respected by all elements in the set)
- values (array) values
- opts (object) options for the chart
o {
o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
o vgutter (number)
o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
o stacked (boolean) whether or not to tread values as in a stacked bar chart
o to
o stretch (boolean)
o }
**
= (object) path element of the popup
> Usage
| r.vbarchart(0, 0, 620, 260, [76, 70, 67, 71, 69], {})
\*/
function VBarchart(paper, x, y, width, height, values, opts) {
opts = opts || {};
var chartinst = this,
type = opts.type || "square",
gutter = parseFloat(opts.gutter || "20%"),
chart = paper.set(),
bars = paper.set(),
covers = paper.set(),
covers2 = paper.set(),
total = Math.max.apply(Math, values),
stacktotal = [],
multi = 0,
colors = opts.colors || chartinst.colors,
len = values.length;
if (Raphael.is(values[0], "array")) {
total = [];
multi = len;
len = 0;
for (var i = values.length; i--;) {
bars.push(paper.set());
total.push(Math.max.apply(Math, values[i]));
len = Math.max(len, values[i].length);
}
if (opts.stacked) {
for (var i = len; i--;) {
var tot = 0;
for (var j = values.length; j--;) {
tot +=+ values[j][i] || 0;
}
stacktotal.push(tot);
}
}
for (var i = values.length; i--;) {
if (values[i].length < len) {
for (var j = len; j--;) {
values[i].push(0);
}
}
}
total = Math.max.apply(Math, opts.stacked ? stacktotal : total);
}
total = (opts.to) || total;
var barwidth = width / (len * (100 + gutter) + gutter) * 100,
barhgutter = barwidth * gutter / 100,
barvgutter = opts.vgutter == null ? 20 : opts.vgutter,
stack = [],
X = x + barhgutter,
Y = (height - 2 * barvgutter) / total;
if (!opts.stretch) {
barhgutter = Math.round(barhgutter);
barwidth = Math.floor(barwidth);
}
!opts.stacked && (barwidth /= multi || 1);
for (var i = 0; i < len; i++) {
stack = [];
for (var j = 0; j < (multi || 1); j++) {
var h = Math.round((multi ? values[j][i] : values[i]) * Y),
top = y + height - barvgutter - h,
bar = finger(Math.round(X + barwidth / 2), top + h, barwidth, h, true, type, null, paper).attr({ stroke: "none", fill: colors[multi ? j : i] });
if (multi) {
bars[j].push(bar);
} else {
bars.push(bar);
}
bar.y = top;
bar.x = Math.round(X + barwidth / 2);
bar.w = barwidth;
bar.h = h;
bar.value = multi ? values[j][i] : values[i];
if (!opts.stacked) {
X += barwidth;
} else {
stack.push(bar);
}
}
if (opts.stacked) {
var cvr;
covers2.push(cvr = paper.rect(stack[0].x - stack[0].w / 2, y, barwidth, height).attr(chartinst.shim));
cvr.bars = paper.set();
var size = 0;
for (var s = stack.length; s--;) {
stack[s].toFront();
}
for (var s = 0, ss = stack.length; s < ss; s++) {
var bar = stack[s],
cover,
h = (size + bar.value) * Y,
path = finger(bar.x, y + height - barvgutter - !!size * .5, barwidth, h, true, type, 1, paper);
cvr.bars.push(bar);
size && bar.attr({path: path});
bar.h = h;
bar.y = y + height - barvgutter - !!size * .5 - h;
covers.push(cover = paper.rect(bar.x - bar.w / 2, bar.y, barwidth, bar.value * Y).attr(chartinst.shim));
cover.bar = bar;
cover.value = bar.value;
size += bar.value;
}
X += barwidth;
}
X += barhgutter;
}
covers2.toFront();
X = x + barhgutter;
if (!opts.stacked) {
for (var i = 0; i < len; i++) {
for (var j = 0; j < (multi || 1); j++) {
var cover;
covers.push(cover = paper.rect(Math.round(X), y + barvgutter, barwidth, height - barvgutter).attr(chartinst.shim));
cover.bar = multi ? bars[j][i] : bars[i];
cover.value = cover.bar.value;
X += barwidth;
}
X += barhgutter;
}
}
chart.label = function (labels, isBottom) {
labels = labels || [];
this.labels = paper.set();
var L, l = -Infinity;
if (opts.stacked) {
for (var i = 0; i < len; i++) {
var tot = 0;
for (var j = 0; j < (multi || 1); j++) {
tot += multi ? values[j][i] : values[i];
if (j == multi - 1) {
var label = paper.labelise(labels[i], tot, total);
L = paper.text(bars[i * (multi || 1) + j].x, y + height - barvgutter / 2, label).attr(txtattr).insertBefore(covers[i * (multi || 1) + j]);
var bb = L.getBBox();
if (bb.x - 7 < l) {
L.remove();
} else {
this.labels.push(L);
l = bb.x + bb.width;
}
}
}
}
} else {
for (var i = 0; i < len; i++) {
for (var j = 0; j < (multi || 1); j++) {
var label = paper.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total);
L = paper.text(bars[i * (multi || 1) + j].x, isBottom ? y + height - barvgutter / 2 : bars[i * (multi || 1) + j].y - 10, label).attr(txtattr).insertBefore(covers[i * (multi || 1) + j]);
var bb = L.getBBox();
if (bb.x - 7 < l) {
L.remove();
} else {
this.labels.push(L);
l = bb.x + bb.width;
}
}
}
}
return this;
};
chart.hover = function (fin, fout) {
covers2.hide();
covers.show();
covers.mouseover(fin).mouseout(fout);
return this;
};
chart.hoverColumn = function (fin, fout) {
covers.hide();
covers2.show();
fout = fout || function () {};
covers2.mouseover(fin).mouseout(fout);
return this;
};
chart.click = function (f) {
covers2.hide();
covers.show();
covers.click(f);
return this;
};
chart.each = function (f) {
if (!Raphael.is(f, "function")) {
return this;
}
for (var i = covers.length; i--;) {
f.call(covers[i]);
}
return this;
};
chart.eachColumn = function (f) {
if (!Raphael.is(f, "function")) {
return this;
}
for (var i = covers2.length; i--;) {
f.call(covers2[i]);
}
return this;
};
chart.clickColumn = function (f) {
covers.hide();
covers2.show();
covers2.click(f);
return this;
};
chart.push(bars, covers, covers2);
chart.bars = bars;
chart.covers = covers;
return chart;
};
//inheritance
var F = function() {};
F.prototype = Raphael.g;
HBarchart.prototype = VBarchart.prototype = new F; //prototype reused by hbarchart
Raphael.fn.barchart = function(x, y, width, height, values, opts) {
return new VBarchart(this, x, y, width, height, values, opts);
};
/*\
* Paper.barchart
[ method ]
**
* Creates a horizontal bar chart
**
> Parameters
**
- x (number) x coordinate of the chart
- y (number) y coordinate of the chart
- width (number) width of the chart (respected by all elements in the set)
- height (number) height of the chart (respected by all elements in the set)
- values (array) values
- opts (object) options for the chart
o {
o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
o vgutter (number)
o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
o stacked (boolean) whether or not to tread values as in a stacked bar chart
o to
o stretch (boolean)
o }
**
= (object) path element of the popup
> Usage
| r.barchart(0, 0, 620, 260, [76, 70, 67, 71, 69], {})
\*/
function HBarchart(paper, x, y, width, height, values, opts) {
opts = opts || {};
var chartinst = this,
type = opts.type || "square",
gutter = parseFloat(opts.gutter || "20%"),
chart = paper.set(),
bars = paper.set(),
covers = paper.set(),
covers2 = paper.set(),
total = Math.max.apply(Math, values),
stacktotal = [],
multi = 0,
colors = opts.colors || chartinst.colors,
len = values.length;
if (Raphael.is(values[0], "array")) {
total = [];
multi = len;
len = 0;
for (var i = values.length; i--;) {
bars.push(paper.set());
total.push(Math.max.apply(Math, values[i]));
len = Math.max(len, values[i].length);
}
if (opts.stacked) {
for (var i = len; i--;) {
var tot = 0;
for (var j = values.length; j--;) {
tot +=+ values[j][i] || 0;
}
stacktotal.push(tot);
}
}
for (var i = values.length; i--;) {
if (values[i].length < len) {
for (var j = len; j--;) {
values[i].push(0);
}
}
}
total = Math.max.apply(Math, opts.stacked ? stacktotal : total);
}
total = (opts.to) || total;
var barheight = Math.floor(height / (len * (100 + gutter) + gutter) * 100),
bargutter = Math.floor(barheight * gutter / 100),
stack = [],
Y = y + bargutter,
X = (width - 1) / total;
!opts.stacked && (barheight /= multi || 1);
for (var i = 0; i < len; i++) {
stack = [];
for (var j = 0; j < (multi || 1); j++) {
var val = multi ? values[j][i] : values[i],
bar = finger(x, Y + barheight / 2, Math.round(val * X), barheight - 1, false, type, null, paper).attr({stroke: "none", fill: colors[multi ? j : i]});
if (multi) {
bars[j].push(bar);
} else {
bars.push(bar);
}
bar.x = x + Math.round(val * X);
bar.y = Y + barheight / 2;
bar.w = Math.round(val * X);
bar.h = barheight;
bar.value = +val;
if (!opts.stacked) {
Y += barheight;
} else {
stack.push(bar);
}
}
if (opts.stacked) {
var cvr = paper.rect(x, stack[0].y - stack[0].h / 2, width, barheight).attr(chartinst.shim);
covers2.push(cvr);
cvr.bars = paper.set();
var size = 0;
for (var s = stack.length; s--;) {
stack[s].toFront();
}
for (var s = 0, ss = stack.length; s < ss; s++) {
var bar = stack[s],
cover,
val = Math.round((size + bar.value) * X),
path = finger(x, bar.y, val, barheight - 1, false, type, 1, paper);
cvr.bars.push(bar);
size && bar.attr({ path: path });
bar.w = val;
bar.x = x + val;
covers.push(cover = paper.rect(x + size * X, bar.y - bar.h / 2, bar.value * X, barheight).attr(chartinst.shim));
cover.bar = bar;
size += bar.value;
}
Y += barheight;
}
Y += bargutter;
}
covers2.toFront();
Y = y + bargutter;
if (!opts.stacked) {
for (var i = 0; i < len; i++) {
for (var j = 0; j < (multi || 1); j++) {
var cover = paper.rect(x, Y, width, barheight).attr(chartinst.shim);
covers.push(cover);
cover.bar = multi ? bars[j][i] : bars[i];
cover.value = cover.bar.value;
Y += barheight;
}
Y += bargutter;
}
}
chart.label = function (labels, isRight) {
labels = labels || [];
this.labels = paper.set();
for (var i = 0; i < len; i++) {
for (var j = 0; j < multi; j++) {
var label = paper.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total),
X = isRight ? bars[i * (multi || 1) + j].x - barheight / 2 + 3 : x + 5,
A = isRight ? "end" : "start",
L;
this.labels.push(L = paper.text(X, bars[i * (multi || 1) + j].y, label).attr(txtattr).attr({ "text-anchor": A }).insertBefore(covers[0]));
if (L.getBBox().x < x + 5) {
L.attr({x: x + 5, "text-anchor": "start"});
} else {
bars[i * (multi || 1) + j].label = L;
}
}
}
return this;
};
chart.hover = function (fin, fout) {
covers2.hide();
covers.show();
fout = fout || function () {};
covers.mouseover(fin).mouseout(fout);
return this;
};
chart.hoverColumn = function (fin, fout) {
covers.hide();
covers2.show();
fout = fout || function () {};
covers2.mouseover(fin).mouseout(fout);
return this;
};
chart.each = function (f) {
if (!Raphael.is(f, "function")) {
return this;
}
for (var i = covers.length; i--;) {
f.call(covers[i]);
}
return this;
};
chart.eachColumn = function (f) {
if (!Raphael.is(f, "function")) {
return this;
}
for (var i = covers2.length; i--;) {
f.call(covers2[i]);
}
return this;
};
chart.click = function (f) {
covers2.hide();
covers.show();
covers.click(f);
return this;
};
chart.clickColumn = function (f) {
covers.hide();
covers2.show();
covers2.click(f);
return this;
};
chart.push(bars, covers, covers2);
chart.bars = bars;
chart.covers = covers;
return chart;
};
Raphael.fn.hbarchart = function(x, y, width, height, values, opts) {
return new HBarchart(this, x, y, width, height, values, opts);
};
})();
/*!
* g.Raphael 0.51 - Charting library, based on Raphaël
*
* Copyright (c) 2009-2012 Dmitry Baranovskiy (http://g.raphaeljs.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*/
/*
* Tooltips on Element prototype
*/
/*\
* Element.popup
[ method ]
**
* Puts the context Element in a 'popup' tooltip. Can also be used on sets.
**
> Parameters
**
- dir (string) location of Element relative to the tail: `'down'`, `'left'`, `'up'` [default], or `'right'`.
- size (number) amount of bevel/padding around the Element, as well as half the width and height of the tail [default: `5`]
- x (number) x coordinate of the popup's tail [default: Element's `x` or `cx`]
- y (number) y coordinate of the popup's tail [default: Element's `y` or `cy`]
**
= (object) path element of the popup
\*/
Raphael.el.popup = function (dir, size, x, y) {
var paper = this.paper || this[0].paper,
bb, xy, center, cw, ch;
if (!paper) return;
switch (this.type) {
case 'text':
case 'circle':
case 'ellipse': center = true; break;
default: center = false;
}
dir = dir == null ? 'up' : dir;
size = size || 5;
bb = this.getBBox();
x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y);
cw = Math.max(bb.width / 2 - size, 0);
ch = Math.max(bb.height / 2 - size, 0);
this.translate(x - bb.x - (center ? bb.width / 2 : 0), y - bb.y - (center ? bb.height / 2 : 0));
bb = this.getBBox();
var paths = {
up: [
'M', x, y,
'l', -size, -size, -cw, 0,
'a', size, size, 0, 0, 1, -size, -size,
'l', 0, -bb.height,
'a', size, size, 0, 0, 1, size, -size,
'l', size * 2 + cw * 2, 0,
'a', size, size, 0, 0, 1, size, size,
'l', 0, bb.height,
'a', size, size, 0, 0, 1, -size, size,
'l', -cw, 0,
'z'
].join(','),
down: [
'M', x, y,
'l', size, size, cw, 0,
'a', size, size, 0, 0, 1, size, size,
'l', 0, bb.height,
'a', size, size, 0, 0, 1, -size, size,
'l', -(size * 2 + cw * 2), 0,
'a', size, size, 0, 0, 1, -size, -size,
'l', 0, -bb.height,
'a', size, size, 0, 0, 1, size, -size,
'l', cw, 0,
'z'
].join(','),
left: [
'M', x, y,
'l', -size, size, 0, ch,
'a', size, size, 0, 0, 1, -size, size,
'l', -bb.width, 0,
'a', size, size, 0, 0, 1, -size, -size,
'l', 0, -(size * 2 + ch * 2),
'a', size, size, 0, 0, 1, size, -size,
'l', bb.width, 0,
'a', size, size, 0, 0, 1, size, size,
'l', 0, ch,
'z'
].join(','),
right: [
'M', x, y,
'l', size, -size, 0, -ch,
'a', size, size, 0, 0, 1, size, -size,
'l', bb.width, 0,
'a', size, size, 0, 0, 1, size, size,
'l', 0, size * 2 + ch * 2,
'a', size, size, 0, 0, 1, -size, size,
'l', -bb.width, 0,
'a', size, size, 0, 0, 1, -size, -size,
'l', 0, -ch,
'z'
].join(',')
};
xy = {
up: { x: -!center * (bb.width / 2), y: -size * 2 - (center ? bb.height / 2 : bb.height) },
down: { x: -!center * (bb.width / 2), y: size * 2 + (center ? bb.height / 2 : bb.height) },
left: { x: -size * 2 - (center ? bb.width / 2 : bb.width), y: -!center * (bb.height / 2) },
right: { x: size * 2 + (center ? bb.width / 2 : bb.width), y: -!center * (bb.height / 2) }
}[dir];
this.translate(xy.x, xy.y);
return paper.path(paths[dir]).attr({ fill: "#000", stroke: "none" }).insertBefore(this.node ? this : this[0]);
};
/*\
* Element.tag
[ method ]
**
* Puts the context Element in a 'tag' tooltip. Can also be used on sets.
**
> Parameters
**
- angle (number) angle of orientation in degrees [default: `0`]
- r (number) radius of the loop [default: `5`]
- x (number) x coordinate of the center of the tag loop [default: Element's `x` or `cx`]
- y (number) y coordinate of the center of the tag loop [default: Element's `x` or `cx`]
**
= (object) path element of the tag
\*/
Raphael.el.tag = function (angle, r, x, y) {
var d = 3,
paper = this.paper || this[0].paper;
if (!paper) return;
var p = paper.path().attr({ fill: '#000', stroke: '#000' }),
bb = this.getBBox(),
dx, R, center, tmp;
switch (this.type) {
case 'text':
case 'circle':
case 'ellipse': center = true; break;
default: center = false;
}
angle = angle || 0;
x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y);
r = r == null ? 5 : r;
R = .5522 * r;
if (bb.height >= r * 2) {
p.attr({
path: [
"M", x, y + r,
"a", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2,
"m", 0, -r * 2 -d,
"a", r + d, r + d, 0, 1, 0, 0, (r + d) * 2,
"L", x + r + d, y + bb.height / 2 + d,
"l", bb.width + 2 * d, 0, 0, -bb.height - 2 * d, -bb.width - 2 * d, 0,
"L", x, y - r - d
].join(",")
});
} else {
dx = Math.sqrt(Math.pow(r + d, 2) - Math.pow(bb.height / 2 + d, 2));
p.attr({
path: [
"M", x, y + r,
"c", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r,
"M", x + dx, y - bb.height / 2 - d,
"a", r + d, r + d, 0, 1, 0, 0, bb.height + 2 * d,
"l", r + d - dx + bb.width + 2 * d, 0, 0, -bb.height - 2 * d,
"L", x + dx, y - bb.height / 2 - d
].join(",")
});
}
angle = 360 - angle;
p.rotate(angle, x, y);
if (this.attrs) {
//elements
this.attr(this.attrs.x ? 'x' : 'cx', x + r + d + (!center ? this.type == 'text' ? bb.width : 0 : bb.width / 2)).attr('y', center ? y : y - bb.height / 2);
this.rotate(angle, x, y);
angle > 90 && angle < 270 && this.attr(this.attrs.x ? 'x' : 'cx', x - r - d - (!center ? bb.width : bb.width / 2)).rotate(180, x, y);
} else {
//sets
if (angle > 90 && angle < 270) {
this.translate(x - bb.x - bb.width - r - d, y - bb.y - bb.height / 2);
this.rotate(angle - 180, bb.x + bb.width + r + d, bb.y + bb.height / 2);
} else {
this.translate(x - bb.x + r + d, y - bb.y - bb.height / 2);
this.rotate(angle, bb.x - r - d, bb.y + bb.height / 2);
}
}
return p.insertBefore(this.node ? this : this[0]);
};
/*\
* Element.drop
[ method ]
**
* Puts the context Element in a 'drop' tooltip. Can also be used on sets.
**
> Parameters
**
- angle (number) angle of orientation in degrees [default: `0`]
- x (number) x coordinate of the drop's point [default: Element's `x` or `cx`]
- y (number) y coordinate of the drop's point [default: Element's `x` or `cx`]
**
= (object) path element of the drop
\*/
Raphael.el.drop = function (angle, x, y) {
var bb = this.getBBox(),
paper = this.paper || this[0].paper,
center, size, p, dx, dy;
if (!paper) return;
switch (this.type) {
case 'text':
case 'circle':
case 'ellipse': center = true; break;
default: center = false;
}
angle = angle || 0;
x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y);
size = Math.max(bb.width, bb.height) + Math.min(bb.width, bb.height);
p = paper.path([
"M", x, y,
"l", size, 0,
"A", size * .4, size * .4, 0, 1, 0, x + size * .7, y - size * .7,
"z"
]).attr({fill: "#000", stroke: "none"}).rotate(22.5 - angle, x, y);
angle = (angle + 90) * Math.PI / 180;
dx = (x + size * Math.sin(angle)) - (center ? 0 : bb.width / 2);
dy = (y + size * Math.cos(angle)) - (center ? 0 : bb.height / 2);
this.attrs ?
this.attr(this.attrs.x ? 'x' : 'cx', dx).attr(this.attrs.y ? 'y' : 'cy', dy) :
this.translate(dx - bb.x, dy - bb.y);
return p.insertBefore(this.node ? this : this[0]);
};
/*\
* Element.flag
[ method ]
**
* Puts the context Element in a 'flag' tooltip. Can also be used on sets.
**
> Parameters
**
- angle (number) angle of orientation in degrees [default: `0`]
- x (number) x coordinate of the flag's point [default: Element's `x` or `cx`]
- y (number) y coordinate of the flag's point [default: Element's `x` or `cx`]
**
= (object) path element of the flag
\*/
Raphael.el.flag = function (angle, x, y) {
var d = 3,
paper = this.paper || this[0].paper;
if (!paper) return;
var p = paper.path().attr({ fill: '#000', stroke: '#000' }),
bb = this.getBBox(),
h = bb.height / 2,
center;
switch (this.type) {
case 'text':
case 'circle':
case 'ellipse': center = true; break;
default: center = false;
}
angle = angle || 0;
x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2: bb.y);
p.attr({
path: [
"M", x, y,
"l", h + d, -h - d, bb.width + 2 * d, 0, 0, bb.height + 2 * d, -bb.width - 2 * d, 0,
"z"
].join(",")
});
angle = 360 - angle;
p.rotate(angle, x, y);
if (this.attrs) {
//elements
this.attr(this.attrs.x ? 'x' : 'cx', x + h + d + (!center ? this.type == 'text' ? bb.width : 0 : bb.width / 2)).attr('y', center ? y : y - bb.height / 2);
this.rotate(angle, x, y);
angle > 90 && angle < 270 && this.attr(this.attrs.x ? 'x' : 'cx', x - h - d - (!center ? bb.width : bb.width / 2)).rotate(180, x, y);
} else {
//sets
if (angle > 90 && angle < 270) {
this.translate(x - bb.x - bb.width - h - d, y - bb.y - bb.height / 2);
this.rotate(angle - 180, bb.x + bb.width + h + d, bb.y + bb.height / 2);
} else {
this.translate(x - bb.x + h + d, y - bb.y - bb.height / 2);
this.rotate(angle, bb.x - h - d, bb.y + bb.height / 2);
}
}
return p.insertBefore(this.node ? this : this[0]);
};
/*\
* Element.label
[ method ]
**
* Puts the context Element in a 'label' tooltip. Can also be used on sets.
**
= (object) path element of the label.
\*/
Raphael.el.label = function () {
var bb = this.getBBox(),
paper = this.paper || this[0].paper,
r = Math.min(20, bb.width + 10, bb.height + 10) / 2;
if (!paper) return;
return paper.rect(bb.x - r / 2, bb.y - r / 2, bb.width + r, bb.height + r, r).attr({ stroke: 'none', fill: '#000' }).insertBefore(this.node ? this : this[0]);
};
/*\
* Element.blob
[ method ]
**
* Puts the context Element in a 'blob' tooltip. Can also be used on sets.
**
> Parameters
**
- angle (number) angle of orientation in degrees [default: `0`]
- x (number) x coordinate of the blob's tail [default: Element's `x` or `cx`]
- y (number) y coordinate of the blob's tail [default: Element's `x` or `cx`]
**
= (object) path element of the blob
\*/
Raphael.el.blob = function (angle, x, y) {
var bb = this.getBBox(),
rad = Math.PI / 180,
paper = this.paper || this[0].paper,
p, center, size;
if (!paper) return;
switch (this.type) {
case 'text':
case 'circle':
case 'ellipse': center = true; break;
default: center = false;
}
p = paper.path().attr({ fill: "#000", stroke: "none" });
angle = (+angle + 1 ? angle : 45) + 90;
size = Math.min(bb.height, bb.width);
x = typeof x == 'number' ? x : (center ? bb.x + bb.width / 2 : bb.x);
y = typeof y == 'number' ? y : (center ? bb.y + bb.height / 2 : bb.y);
var w = Math.max(bb.width + size, size * 25 / 12),
h = Math.max(bb.height + size, size * 25 / 12),
x2 = x + size * Math.sin((angle - 22.5) * rad),
y2 = y + size * Math.cos((angle - 22.5) * rad),
x1 = x + size * Math.sin((angle + 22.5) * rad),
y1 = y + size * Math.cos((angle + 22.5) * rad),
dx = (x1 - x2) / 2,
dy = (y1 - y2) / 2,
rx = w / 2,
ry = h / 2,
k = -Math.sqrt(Math.abs(rx * rx * ry * ry - rx * rx * dy * dy - ry * ry * dx * dx) / (rx * rx * dy * dy + ry * ry * dx * dx)),
cx = k * rx * dy / ry + (x1 + x2) / 2,
cy = k * -ry * dx / rx + (y1 + y2) / 2;
p.attr({
x: cx,
y: cy,
path: [
"M", x, y,
"L", x1, y1,
"A", rx, ry, 0, 1, 1, x2, y2,
"z"
].join(",")
});
this.translate(cx - bb.x - bb.width / 2, cy - bb.y - bb.height / 2);
return p.insertBefore(this.node ? this : this[0]);
};
/*
* Tooltips on Paper prototype
*/
/*\
* Paper.label
[ method ]
**
* Puts the given `text` into a 'label' tooltip. The text is given a default style according to @g.txtattr. See @Element.label
**
> Parameters
**
- x (number) x coordinate of the center of the label
- y (number) y coordinate of the center of the label
- text (string) text to place inside the label
**
= (object) set containing the label path and the text element
> Usage
| paper.label(50, 50, "$9.99");
\*/
Raphael.fn.label = function (x, y, text) {
var set = this.set();
text = this.text(x, y, text).attr(Raphael.g.txtattr);
return set.push(text.label(), text);
};
/*\
* Paper.popup
[ method ]
**
* Puts the given `text` into a 'popup' tooltip. The text is given a default style according to @g.txtattr. See @Element.popup
*
* Note: The `dir` parameter has changed from g.Raphael 0.4.1 to 0.5. The options `0`, `1`, `2`, and `3` has been changed to `'down'`, `'left'`, `'up'`, and `'right'` respectively.
**
> Parameters
**
- x (number) x coordinate of the popup's tail
- y (number) y coordinate of the popup's tail
- text (string) text to place inside the popup
- dir (string) location of the text relative to the tail: `'down'`, `'left'`, `'up'` [default], or `'right'`.
- size (number) amount of padding around the Element [default: `5`]
**
= (object) set containing the popup path and the text element
> Usage
| paper.popup(50, 50, "$9.99", 'down');
\*/
Raphael.fn.popup = function (x, y, text, dir, size) {
var set = this.set();
text = this.text(x, y, text).attr(Raphael.g.txtattr);
return set.push(text.popup(dir, size), text);
};
/*\
* Paper.tag
[ method ]
**
* Puts the given text into a 'tag' tooltip. The text is given a default style according to @g.txtattr. See @Element.tag
**
> Parameters
**
- x (number) x coordinate of the center of the tag loop
- y (number) y coordinate of the center of the tag loop
- text (string) text to place inside the tag
- angle (number) angle of orientation in degrees [default: `0`]
- r (number) radius of the loop [default: `5`]
**
= (object) set containing the tag path and the text element
> Usage
| paper.tag(50, 50, "$9.99", 60);
\*/
Raphael.fn.tag = function (x, y, text, angle, r) {
var set = this.set();
text = this.text(x, y, text).attr(Raphael.g.txtattr);
return set.push(text.tag(angle, r), text);
};
/*\
* Paper.flag
[ method ]
**
* Puts the given `text` into a 'flag' tooltip. The text is given a default style according to @g.txtattr. See @Element.flag
**
> Parameters
**
- x (number) x coordinate of the flag's point
- y (number) y coordinate of the flag's point
- text (string) text to place inside the flag
- angle (number) angle of orientation in degrees [default: `0`]
**
= (object) set containing the flag path and the text element
> Usage
| paper.flag(50, 50, "$9.99", 60);
\*/
Raphael.fn.flag = function (x, y, text, angle) {
var set = this.set();
text = this.text(x, y, text).attr(Raphael.g.txtattr);
return set.push(text.flag(angle), text);
};
/*\
* Paper.drop
[ method ]
**
* Puts the given text into a 'drop' tooltip. The text is given a default style according to @g.txtattr. See @Element.drop
**
> Parameters
**
- x (number) x coordinate of the drop's point
- y (number) y coordinate of the drop's point
- text (string) text to place inside the drop
- angle (number) angle of orientation in degrees [default: `0`]
**
= (object) set containing the drop path and the text element
> Usage
| paper.drop(50, 50, "$9.99", 60);
\*/
Raphael.fn.drop = function (x, y, text, angle) {
var set = this.set();
text = this.text(x, y, text).attr(Raphael.g.txtattr);
return set.push(text.drop(angle), text);
};
/*\
* Paper.blob
[ method ]
**
* Puts the given text into a 'blob' tooltip. The text is given a default style according to @g.txtattr. See @Element.blob
**
> Parameters
**
- x (number) x coordinate of the blob's tail
- y (number) y coordinate of the blob's tail
- text (string) text to place inside the blob
- angle (number) angle of orientation in degrees [default: `0`]
**
= (object) set containing the blob path and the text element
> Usage
| paper.blob(50, 50, "$9.99", 60);
\*/
Raphael.fn.blob = function (x, y, text, angle) {
var set = this.set();
text = this.text(x, y, text).attr(Raphael.g.txtattr);
return set.push(text.blob(angle), text);
};
/**
* Brightness functions on the Element prototype
*/
/*\
* Element.lighter
[ method ]
**
* Makes the context element lighter by increasing the brightness and reducing the saturation by a given factor. Can be called on Sets.
**
> Parameters
**
- times (number) adjustment factor [default: `2`]
**
= (object) Element
> Usage
| paper.circle(50, 50, 20).attr({
| fill: "#ff0000",
| stroke: "#fff",
| "stroke-width": 2
| }).lighter(6);
\*/
Raphael.el.lighter = function (times) {
times = times || 2;
var fs = [this.attrs.fill, this.attrs.stroke];
this.fs = this.fs || [fs[0], fs[1]];
fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex);
fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex);
fs[0].b = Math.min(fs[0].b * times, 1);
fs[0].s = fs[0].s / times;
fs[1].b = Math.min(fs[1].b * times, 1);
fs[1].s = fs[1].s / times;
this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"});
return this;
};
/*\
* Element.darker
[ method ]
**
* Makes the context element darker by decreasing the brightness and increasing the saturation by a given factor. Can be called on Sets.
**
> Parameters
**
- times (number) adjustment factor [default: `2`]
**
= (object) Element
> Usage
| paper.circle(50, 50, 20).attr({
| fill: "#ff0000",
| stroke: "#fff",
| "stroke-width": 2
| }).darker(6);
\*/
Raphael.el.darker = function (times) {
times = times || 2;
var fs = [this.attrs.fill, this.attrs.stroke];
this.fs = this.fs || [fs[0], fs[1]];
fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex);
fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex);
fs[0].s = Math.min(fs[0].s * times, 1);
fs[0].b = fs[0].b / times;
fs[1].s = Math.min(fs[1].s * times, 1);
fs[1].b = fs[1].b / times;
this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"});
return this;
};
/*\
* Element.resetBrightness
[ method ]
**
* Resets brightness and saturation levels to their original values. See @Element.lighter and @Element.darker. Can be called on Sets.
**
= (object) Element
> Usage
| paper.circle(50, 50, 20).attr({
| fill: "#ff0000",
| stroke: "#fff",
| "stroke-width": 2
| }).lighter(6).resetBrightness();
\*/
Raphael.el.resetBrightness = function () {
if (this.fs) {
this.attr({ fill: this.fs[0], stroke: this.fs[1] });
delete this.fs;
}
return this;
};
//alias to set prototype
(function () {
var brightness = ['lighter', 'darker', 'resetBrightness'],
tooltips = ['popup', 'tag', 'flag', 'label', 'drop', 'blob'];
for (var f in tooltips) (function (name) {
Raphael.st[name] = function () {
return Raphael.el[name].apply(this, arguments);
};
})(tooltips[f]);
for (var f in brightness) (function (name) {
Raphael.st[name] = function () {
for (var i = 0; i < this.length; i++) {
this[i][name].apply(this[i], arguments);
}
return this;
};
})(brightness[f]);
})();
//chart prototype for storing common functions
Raphael.g = {
/*\
* g.shim
[ object ]
**
* An attribute object that charts will set on all generated shims (shims being the invisible objects that mouse events are bound to)
**
> Default value
| { stroke: 'none', fill: '#000', 'fill-opacity': 0 }
\*/
shim: { stroke: 'none', fill: '#000', 'fill-opacity': 0 },
/*\
* g.txtattr
[ object ]
**
* An attribute object that charts and tooltips will set on any generated text
**
> Default value
| { font: '12px Arial, sans-serif', fill: '#fff' }
\*/
txtattr: { font: '12px Arial, sans-serif', fill: '#fff' },
/*\
* g.colors
[ array ]
**
* An array of color values that charts will iterate through when drawing chart data values.
**
\*/
colors: (function () {
var hues = [.6, .2, .05, .1333, .75, 0],
colors = [];
for (var i = 0; i < 10; i++) {
if (i < hues.length) {
colors.push('hsb(' + hues[i] + ',.75, .75)');
} else {
colors.push('hsb(' + hues[i - hues.length] + ', 1, .5)');
}
}
return colors;
})(),
snapEnds: function(from, to, steps) {
var f = from,
t = to;
if (f == t) {
return {from: f, to: t, power: 0};
}
function round(a) {
return Math.abs(a - .5) < .25 ? ~~(a) + .5 : Math.round(a);
}
var d = (t - f) / steps,
r = ~~(d),
R = r,
i = 0;
if (r) {
while (R) {
i--;
R = ~~(d * Math.pow(10, i)) / Math.pow(10, i);
}
i ++;
} else {
if(d == 0 || !isFinite(d)) {
i = 1;
} else {
while (!r) {
i = i || 1;
r = ~~(d * Math.pow(10, i)) / Math.pow(10, i);
i++;
}
}
i && i--;
}
t = round(to * Math.pow(10, i)) / Math.pow(10, i);
if (t < to) {
t = round((to + .5) * Math.pow(10, i)) / Math.pow(10, i);
}
f = round((from - (i > 0 ? 0 : .5)) * Math.pow(10, i)) / Math.pow(10, i);
return { from: f, to: t, power: i };
},
axis: function (x, y, length, from, to, steps, orientation, labels, type, dashsize, paper) {
dashsize = dashsize == null ? 2 : dashsize;
type = type || "t";
steps = steps || 10;
paper = arguments[arguments.length-1] //paper is always last argument
var path = type == "|" || type == " " ? ["M", x + .5, y, "l", 0, .001] : orientation == 1 || orientation == 3 ? ["M", x + .5, y, "l", 0, -length] : ["M", x, y + .5, "l", length, 0],
ends = this.snapEnds(from, to, steps),
f = ends.from,
t = ends.to,
i = ends.power,
j = 0,
txtattr = { font: "11px 'Fontin Sans', Fontin-Sans, sans-serif" },
text = paper.set(),
d;
d = (t - f) / steps;
var label = f,
rnd = i > 0 ? i : 0;
dx = length / steps;
if (+orientation == 1 || +orientation == 3) {
var Y = y,
addon = (orientation - 1 ? 1 : -1) * (dashsize + 3 + !!(orientation - 1));
while (Y >= y - length) {
type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), Y + .5, "l", dashsize * 2 + 1, 0]));
text.push(paper.text(x + addon, Y, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr).attr({ "text-anchor": orientation - 1 ? "start" : "end" }));
label += d;
Y -= dx;
}
if (Math.round(Y + dx - (y - length))) {
type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), y - length + .5, "l", dashsize * 2 + 1, 0]));
text.push(paper.text(x + addon, y - length, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr).attr({ "text-anchor": orientation - 1 ? "start" : "end" }));
}
} else {
label = f;
rnd = (i > 0) * i;
addon = (orientation ? -1 : 1) * (dashsize + 9 + !orientation);
var X = x,
dx = length / steps,
txt = 0,
prev = 0;
while (X <= x + length) {
type != "-" && type != " " && (path = path.concat(["M", X + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1]));
text.push(txt = paper.text(X, y + addon, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr));
var bb = txt.getBBox();
if (prev >= bb.x - 5) {
text.pop(text.length - 1).remove();
} else {
prev = bb.x + bb.width;
}
label += d;
X += dx;
}
if (Math.round(X - dx - x - length)) {
type != "-" && type != " " && (path = path.concat(["M", x + length + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1]));
text.push(paper.text(x + length, y + addon, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(txtattr));
}
}
var res = paper.path(path);
res.text = text;
res.all = paper.set([res, text]);
res.remove = function () {
this.text.remove();
this.constructor.prototype.remove.call(this);
};
return res;
},
labelise: function(label, val, total) {
if (label) {
return (label + "").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g, function (all, value, percent) {
if (value) {
return (+val).toFixed(value.replace(/^#+\.?/g, "").length);
}
if (percent) {
return (val * 100 / total).toFixed(percent.replace(/^%+\.?/g, "").length) + "%";
}
});
} else {
return (+val).toFixed(0);
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -1746,6 +1746,10 @@ etag@~1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8"
eve-raphael@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/eve-raphael/-/eve-raphael-0.5.0.tgz#17c754b792beef3fa6684d79cf5a47c63c4cda30"
event-emitter@~0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5"
......@@ -3554,6 +3558,12 @@ range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
raphael@^2.2.7:
version "2.2.7"
resolved "https://registry.yarnpkg.com/raphael/-/raphael-2.2.7.tgz#231b19141f8d086986d8faceb66f8b562ee2c810"
dependencies:
eve-raphael "0.5.0"
raw-body@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment