From d8805ae4d7b5abec84a0a93e179d88d27f9eb516 Mon Sep 17 00:00:00 2001 From: Raghu Rajagopalan Date: Fri, 1 Apr 2016 12:05:59 +0530 Subject: [PATCH] WIP - prettier curves. --- dist/www/javascripts/lib/mermaid.js | 441 +++++++++++++--------- src/diagrams/gitGraph/gitGraphRenderer.js | 147 +++++--- 2 files changed, 358 insertions(+), 230 deletions(-) diff --git a/dist/www/javascripts/lib/mermaid.js b/dist/www/javascripts/lib/mermaid.js index 320833c12..71efe818c 100644 --- a/dist/www/javascripts/lib/mermaid.js +++ b/dist/www/javascripts/lib/mermaid.js @@ -324,7 +324,7 @@ process.umask = function() { return 0; }; },{}],4:[function(require,module,exports){ !function() { var d3 = { - version: "3.5.6" + version: "3.5.16" }; var d3_arraySlice = [].slice, d3_array = function(list) { return d3_arraySlice.call(list); @@ -544,20 +544,20 @@ process.umask = function() { return 0; }; while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ]; return pairs; }; - d3.zip = function() { - if (!(n = arguments.length)) return []; - for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { - for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { - zip[j] = arguments[j][i]; + d3.transpose = function(matrix) { + if (!(n = matrix.length)) return []; + for (var i = -1, m = d3.min(matrix, d3_transposeLength), transpose = new Array(m); ++i < m; ) { + for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n; ) { + row[j] = matrix[j][i]; } } - return zips; + return transpose; }; - function d3_zipLength(d) { + function d3_transposeLength(d) { return d.length; } - d3.transpose = function(matrix) { - return d3.zip.apply(d3, matrix); + d3.zip = function() { + return d3.transpose(arguments); }; d3.keys = function(map) { var keys = []; @@ -944,9 +944,10 @@ process.umask = function() { return 0; }; return d3_selectAll(selector, this); }; } + var d3_nsXhtml = "http://www.w3.org/1999/xhtml"; var d3_nsPrefix = { svg: "http://www.w3.org/2000/svg", - xhtml: "http://www.w3.org/1999/xhtml", + xhtml: d3_nsXhtml, xlink: "http://www.w3.org/1999/xlink", xml: "http://www.w3.org/XML/1998/namespace", xmlns: "http://www.w3.org/2000/xmlns/" @@ -955,10 +956,7 @@ process.umask = function() { return 0; }; prefix: d3_nsPrefix, qualify: function(name) { var i = name.indexOf(":"), prefix = name; - if (i >= 0) { - prefix = name.slice(0, i); - name = name.slice(i + 1); - } + if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); return d3_nsPrefix.hasOwnProperty(prefix) ? { space: d3_nsPrefix[prefix], local: name @@ -1132,7 +1130,7 @@ process.umask = function() { return 0; }; function d3_selection_creator(name) { function create() { var document = this.ownerDocument, namespace = this.namespaceURI; - return namespace ? document.createElementNS(namespace, name) : document.createElement(name); + return namespace === d3_nsXhtml && document.documentElement.namespaceURI === d3_nsXhtml ? document.createElement(name) : document.createElementNS(namespace, name); } function createNS() { return this.ownerDocument.createElementNS(name.space, name.local); @@ -1169,12 +1167,14 @@ process.umask = function() { return 0; }; if (key) { var nodeByKeyValue = new d3_Map(), keyValues = new Array(n), keyValue; for (i = -1; ++i < n; ) { - if (nodeByKeyValue.has(keyValue = key.call(node = group[i], node.__data__, i))) { - exitNodes[i] = node; - } else { - nodeByKeyValue.set(keyValue, node); + if (node = group[i]) { + if (nodeByKeyValue.has(keyValue = key.call(node, node.__data__, i))) { + exitNodes[i] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + keyValues[i] = keyValue; } - keyValues[i] = keyValue; } for (i = -1; ++i < m; ) { if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) { @@ -1186,7 +1186,7 @@ process.umask = function() { return 0; }; nodeByKeyValue.set(keyValue, true); } for (i = -1; ++i < n; ) { - if (nodeByKeyValue.get(keyValues[i]) !== true) { + if (i in keyValues && nodeByKeyValue.get(keyValues[i]) !== true) { exitNodes[i] = group[i]; } } @@ -1378,7 +1378,7 @@ process.umask = function() { return 0; }; group = d3_array(d3_selectAll(nodes, d3_document)); group.parentNode = d3_document.documentElement; } else { - group = nodes; + group = d3_array(nodes); group.parentNode = null; } return d3_selection([ group ]); @@ -1529,7 +1529,7 @@ process.umask = function() { return 0; }; } function dragstart(id, position, subject, move, end) { return function() { - var that = this, target = d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject(target)).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(target), position0 = position(parent, dragId); + var that = this, target = d3.event.target.correspondingElement || d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject(target)).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(target), position0 = position(parent, dragId); if (origin) { dragOffset = origin.apply(that, arguments); dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ]; @@ -1557,7 +1557,7 @@ process.umask = function() { return 0; }; function ended() { if (!position(parent, dragId)) return; dragSubject.on(move + dragName, null).on(end + dragName, null); - dragRestore(dragged && d3.event.target === target); + dragRestore(dragged); dispatch({ type: "dragend" }); @@ -1609,18 +1609,22 @@ process.umask = function() { return 0; }; } var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4; d3.interpolateZoom = function(p0, p1) { - var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2]; - var dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1), dr = r1 - r0, S = (dr || Math.log(w1 / w0)) / ρ; - function interpolate(t) { - var s = t * S; - if (dr) { - var coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0)); + var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i, S; + if (d2 < ε2) { + S = Math.log(w1 / w0) / ρ; + i = function(t) { + return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * t * S) ]; + }; + } else { + var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1); + S = (r1 - r0) / ρ; + i = function(t) { + var s = t * S, coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0)); return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ]; - } - return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * s) ]; + }; } - interpolate.duration = S * 1e3; - return interpolate; + i.duration = S * 1e3; + return i; }; d3.behavior.zoom = function() { var view = { @@ -1690,8 +1694,9 @@ process.umask = function() { return 0; }; view = { x: view.x, y: view.y, - k: +_ + k: null }; + scaleTo(+_); rescale(); return zoom; }; @@ -1790,7 +1795,7 @@ process.umask = function() { return 0; }; }), center0 = null; } function mousedowned() { - var that = this, target = d3.event.target, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress(that); + var that = this, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress(that); d3_selection_interrupt.call(that); zoomstarted(dispatch); function moved() { @@ -1800,7 +1805,7 @@ process.umask = function() { return 0; }; } function ended() { subject.on(mousemove, null).on(mouseup, null); - dragRestore(dragged && d3.event.target === target); + dragRestore(dragged); zoomended(dispatch); } } @@ -2022,9 +2027,8 @@ process.umask = function() { return 0; }; return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); } function d3_rgb_parse(format, rgb, hsl) { - format = format.toLowerCase(); var r = 0, g = 0, b = 0, m1, m2, color; - m1 = /([a-z]+)\((.*)\)/.exec(format); + m1 = /([a-z]+)\((.*)\)/.exec(format = format.toLowerCase()); if (m1) { m2 = m1[2].split(","); switch (m1[1]) { @@ -2439,17 +2443,19 @@ process.umask = function() { return 0; }; }; d3.csv = d3.dsv(",", "text/csv"); d3.tsv = d3.dsv(" ", "text/tab-separated-values"); - var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) { + var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) { setTimeout(callback, 17); }; - d3.timer = function(callback, delay, then) { + d3.timer = function() { + d3_timer.apply(this, arguments); + }; + function d3_timer(callback, delay, then) { var n = arguments.length; if (n < 2) delay = 0; if (n < 3) then = Date.now(); var time = then + delay, timer = { c: callback, t: time, - f: false, n: null }; if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer; @@ -2459,7 +2465,8 @@ process.umask = function() { return 0; }; d3_timer_interval = 1; d3_timer_frame(d3_timer_step); } - }; + return timer; + } function d3_timer_step() { var now = d3_timer_mark(), delay = d3_timer_sweep() - now; if (delay > 24) { @@ -2478,22 +2485,21 @@ process.umask = function() { return 0; }; d3_timer_sweep(); }; function d3_timer_mark() { - var now = Date.now(); - d3_timer_active = d3_timer_queueHead; - while (d3_timer_active) { - if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t); - d3_timer_active = d3_timer_active.n; + var now = Date.now(), timer = d3_timer_queueHead; + while (timer) { + if (now >= timer.t && timer.c(now - timer.t)) timer.c = null; + timer = timer.n; } return now; } function d3_timer_sweep() { var t0, t1 = d3_timer_queueHead, time = Infinity; while (t1) { - if (t1.f) { - t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n; - } else { + if (t1.c) { if (t1.t < time) time = t1.t; t1 = (t0 = t1).n; + } else { + t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n; } } d3_timer_queueTail = t0; @@ -2508,7 +2514,7 @@ process.umask = function() { return 0; }; var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); d3.formatPrefix = function(value, precision) { var i = 0; - if (value) { + if (value = +value) { if (value < 0) value *= -1; if (precision) value = d3.round(value, d3_format_precision(value, precision)); i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); @@ -2858,7 +2864,8 @@ process.umask = function() { return 0; }; if (i != string.length) return null; if ("p" in d) d.H = d.H % 12 + d.p * 12; var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)(); - if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { + if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("W" in d || "U" in d) { + if (!("w" in d)) d.w = "W" in d ? 1 : 0; date.setFullYear(d.y, 0, 1); date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); } else date.setFullYear(d.y, d.m, d.d); @@ -6310,54 +6317,68 @@ process.umask = function() { return 0; }; f: 0 }; d3.interpolateTransform = d3_interpolateTransform; - function d3_interpolateTransform(a, b) { - var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; - if (ta[0] != tb[0] || ta[1] != tb[1]) { - s.push("translate(", null, ",", null, ")"); + function d3_interpolateTransformPop(s) { + return s.length ? s.pop() + "," : ""; + } + function d3_interpolateTranslate(ta, tb, s, q) { + if (ta[0] !== tb[0] || ta[1] !== tb[1]) { + var i = s.push("translate(", null, ",", null, ")"); q.push({ - i: 1, + i: i - 4, x: d3_interpolateNumber(ta[0], tb[0]) }, { - i: 3, + i: i - 2, x: d3_interpolateNumber(ta[1], tb[1]) }); } else if (tb[0] || tb[1]) { s.push("translate(" + tb + ")"); - } else { - s.push(""); } - if (ra != rb) { + } + function d3_interpolateRotate(ra, rb, s, q) { + if (ra !== rb) { if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; q.push({ - i: s.push(s.pop() + "rotate(", null, ")") - 2, + i: s.push(d3_interpolateTransformPop(s) + "rotate(", null, ")") - 2, x: d3_interpolateNumber(ra, rb) }); } else if (rb) { - s.push(s.pop() + "rotate(" + rb + ")"); + s.push(d3_interpolateTransformPop(s) + "rotate(" + rb + ")"); } - if (wa != wb) { + } + function d3_interpolateSkew(wa, wb, s, q) { + if (wa !== wb) { q.push({ - i: s.push(s.pop() + "skewX(", null, ")") - 2, + i: s.push(d3_interpolateTransformPop(s) + "skewX(", null, ")") - 2, x: d3_interpolateNumber(wa, wb) }); } else if (wb) { - s.push(s.pop() + "skewX(" + wb + ")"); + s.push(d3_interpolateTransformPop(s) + "skewX(" + wb + ")"); } - if (ka[0] != kb[0] || ka[1] != kb[1]) { - n = s.push(s.pop() + "scale(", null, ",", null, ")"); + } + function d3_interpolateScale(ka, kb, s, q) { + if (ka[0] !== kb[0] || ka[1] !== kb[1]) { + var i = s.push(d3_interpolateTransformPop(s) + "scale(", null, ",", null, ")"); q.push({ - i: n - 4, + i: i - 4, x: d3_interpolateNumber(ka[0], kb[0]) }, { - i: n - 2, + i: i - 2, x: d3_interpolateNumber(ka[1], kb[1]) }); - } else if (kb[0] != 1 || kb[1] != 1) { - s.push(s.pop() + "scale(" + kb + ")"); + } else if (kb[0] !== 1 || kb[1] !== 1) { + s.push(d3_interpolateTransformPop(s) + "scale(" + kb + ")"); } - n = q.length; + } + function d3_interpolateTransform(a, b) { + var s = [], q = []; + a = d3.transform(a), b = d3.transform(b); + d3_interpolateTranslate(a.translate, b.translate, s, q); + d3_interpolateRotate(a.rotate, b.rotate, s, q); + d3_interpolateSkew(a.skew, b.skew, s, q); + d3_interpolateScale(a.scale, b.scale, s, q); + a = b = null; return function(t) { - var i = -1, o; + var i = -1, n = q.length, o; while (++i < n) s[(o = q[i]).i] = o.x(t); return s.join(""); }; @@ -6461,7 +6482,7 @@ process.umask = function() { return 0; }; index: di, startAngle: x0, endAngle: x, - value: (x - x0) / k + value: groupSums[di] }; x += padding; } @@ -6529,7 +6550,7 @@ process.umask = function() { return 0; }; return chord; }; d3.layout.force = function() { - var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges; + var force = {}, event = d3.dispatch("start", "tick", "end"), timer, size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges; function repulse(node) { return function(quad, x1, _, x2) { if (quad.point !== node) { @@ -6553,6 +6574,7 @@ process.umask = function() { return 0; }; } force.tick = function() { if ((alpha *= .99) < .005) { + timer = null; event.end({ type: "end", alpha: alpha = 0 @@ -6570,7 +6592,7 @@ process.umask = function() { return 0; }; l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; x *= l; y *= l; - t.x -= x * (k = s.weight / (t.weight + s.weight)); + t.x -= x * (k = s.weight + t.weight ? s.weight / (s.weight + t.weight) : .5); t.y -= y * k; s.x += x * (k = 1 - k); s.y += y * k; @@ -6666,13 +6688,21 @@ process.umask = function() { return 0; }; if (!arguments.length) return alpha; x = +x; if (alpha) { - if (x > 0) alpha = x; else alpha = 0; + if (x > 0) { + alpha = x; + } else { + timer.c = null, timer.t = NaN, timer = null; + event.end({ + type: "end", + alpha: alpha = 0 + }); + } } else if (x > 0) { event.start({ type: "start", alpha: alpha = x }); - d3.timer(force.tick); + timer = d3_timer(force.tick); } return force; }; @@ -6926,7 +6956,7 @@ process.umask = function() { return 0; }; function pie(data) { var n = data.length, values = data.map(function(d, i) { return +value.call(pie, d, i); - }), a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle), da = (typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a, p = Math.min(Math.abs(da) / n, +(typeof padAngle === "function" ? padAngle.apply(this, arguments) : padAngle)), pa = p * (da < 0 ? -1 : 1), k = (da - n * pa) / d3.sum(values), index = d3.range(n), arcs = [], v; + }), a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle), da = (typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a, p = Math.min(Math.abs(da) / n, +(typeof padAngle === "function" ? padAngle.apply(this, arguments) : padAngle)), pa = p * (da < 0 ? -1 : 1), sum = d3.sum(values), k = sum ? (da - n * pa) / sum : 0, index = d3.range(n), arcs = [], v; if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { return values[j] - values[i]; } : function(i, j) { @@ -7639,10 +7669,8 @@ process.umask = function() { return 0; }; } function treemap(d) { var nodes = stickies || hierarchy(d), root = nodes[0]; - root.x = 0; - root.y = 0; - root.dx = size[0]; - root.dy = size[1]; + root.x = root.y = 0; + if (root.value) root.dx = size[0], root.dy = size[1]; else root.dx = root.dy = 0; if (stickies) hierarchy.revalue(root); scale([ root ], root.dx * root.dy / root.value); (stickies ? stickify : squarify)(root); @@ -7862,7 +7890,9 @@ process.umask = function() { return 0; }; return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); } function d3_scale_linearNice(domain, m) { - return d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); + d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); + d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2])); + return domain; } function d3_scale_linearTickRange(domain, m) { if (m == null) m = 10; @@ -7964,10 +7994,11 @@ process.umask = function() { return 0; }; scale.tickFormat = function(n, format) { if (!arguments.length) return d3_scale_logFormat; if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); - var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, - Math.floor), e; + var k = Math.max(1, base * n / scale.ticks().length); return function(d) { - return d / pow(f(log(d) + e)) <= k ? format(d) : ""; + var i = d / pow(Math.round(log(d))); + if (i * base < base - .5) i *= base; + return i <= k ? format(d) : ""; }; }; scale.copy = function() { @@ -8306,11 +8337,16 @@ process.umask = function() { return 0; }; } else { x2 = y2 = 0; } - if ((rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) { + if (da > ε && (rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) { cr = r0 < r1 ^ cw ? 0 : 1; - var oc = x3 == null ? [ x2, y2 ] : x1 == null ? [ x0, y0 ] : d3_geom_polygonIntersect([ x0, y0 ], [ x3, y3 ], [ x1, y1 ], [ x2, y2 ]), ax = x0 - oc[0], ay = y0 - oc[1], bx = x1 - oc[0], by = y1 - oc[1], kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2), lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]); + var rc1 = rc, rc0 = rc; + if (da < π) { + var oc = x3 == null ? [ x2, y2 ] : x1 == null ? [ x0, y0 ] : d3_geom_polygonIntersect([ x0, y0 ], [ x3, y3 ], [ x1, y1 ], [ x2, y2 ]), ax = x0 - oc[0], ay = y0 - oc[1], bx = x1 - oc[0], by = y1 - oc[1], kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2), lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]); + rc0 = Math.min(rc, (r0 - lc) / (kc - 1)); + rc1 = Math.min(rc, (r1 - lc) / (kc + 1)); + } if (x1 != null) { - var rc1 = Math.min(rc, (r1 - lc) / (kc + 1)), t30 = d3_svg_arcCornerTangents(x3 == null ? [ x2, y2 ] : [ x3, y3 ], [ x0, y0 ], r1, rc1, cw), t12 = d3_svg_arcCornerTangents([ x1, y1 ], [ x2, y2 ], r1, rc1, cw); + var t30 = d3_svg_arcCornerTangents(x3 == null ? [ x2, y2 ] : [ x3, y3 ], [ x0, y0 ], r1, rc1, cw), t12 = d3_svg_arcCornerTangents([ x1, y1 ], [ x2, y2 ], r1, rc1, cw); if (rc === rc1) { path.push("M", t30[0], "A", rc1, ",", rc1, " 0 0,", cr, " ", t30[1], "A", r1, ",", r1, " 0 ", 1 - cw ^ d3_svg_arcSweep(t30[1][0], t30[1][1], t12[1][0], t12[1][1]), ",", cw, " ", t12[1], "A", rc1, ",", rc1, " 0 0,", cr, " ", t12[0]); } else { @@ -8320,7 +8356,7 @@ process.umask = function() { return 0; }; path.push("M", x0, ",", y0); } if (x3 != null) { - var rc0 = Math.min(rc, (r0 - lc) / (kc - 1)), t03 = d3_svg_arcCornerTangents([ x0, y0 ], [ x3, y3 ], r0, -rc0, cw), t21 = d3_svg_arcCornerTangents([ x2, y2 ], x1 == null ? [ x0, y0 ] : [ x1, y1 ], r0, -rc0, cw); + var t03 = d3_svg_arcCornerTangents([ x0, y0 ], [ x3, y3 ], r0, -rc0, cw), t21 = d3_svg_arcCornerTangents([ x2, y2 ], x1 == null ? [ x0, y0 ] : [ x1, y1 ], r0, -rc0, cw); if (rc === rc0) { path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t21[1], "A", r0, ",", r0, " 0 ", cw ^ d3_svg_arcSweep(t21[1][0], t21[1][1], t03[1][0], t03[1][1]), ",", 1 - cw, " ", t03[1], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]); } else { @@ -8402,7 +8438,7 @@ process.umask = function() { return 0; }; return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1; } function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) { - var x01 = p0[0] - p1[0], y01 = p0[1] - p1[1], lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x1 = p0[0] + ox, y1 = p0[1] + oy, x2 = p1[0] + ox, y2 = p1[1] + oy, x3 = (x1 + x2) / 2, y3 = (y1 + y2) / 2, dx = x2 - x1, dy = y2 - y1, d2 = dx * dx + dy * dy, r = r1 - rc, D = x1 * y2 - x2 * y1, d = (dy < 0 ? -1 : 1) * Math.sqrt(r * r * d2 - D * D), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x3, dy0 = cy0 - y3, dx1 = cx1 - x3, dy1 = cy1 - y3; + var x01 = p0[0] - p1[0], y01 = p0[1] - p1[1], lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x1 = p0[0] + ox, y1 = p0[1] + oy, x2 = p1[0] + ox, y2 = p1[1] + oy, x3 = (x1 + x2) / 2, y3 = (y1 + y2) / 2, dx = x2 - x1, dy = y2 - y1, d2 = dx * dx + dy * dy, r = r1 - rc, D = x1 * y2 - x2 * y1, d = (dy < 0 ? -1 : 1) * Math.sqrt(Math.max(0, r * r * d2 - D * D)), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x3, dy0 = cy0 - y3, dx1 = cx1 - x3, dy1 = cy1 - y3; if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1; return [ [ cx0 - ox, cy0 - oy ], [ cx0 * r1 / r, cy0 * r1 / r ] ]; } @@ -8474,10 +8510,10 @@ process.umask = function() { return 0; }; value.closed = /-closed$/.test(key); }); function d3_svg_lineLinear(points) { - return points.join("L"); + return points.length > 1 ? points.join("L") : points + "Z"; } function d3_svg_lineLinearClosed(points) { - return d3_svg_lineLinear(points) + "Z"; + return points.join("L") + "Z"; } function d3_svg_lineStep(points) { var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; @@ -8499,7 +8535,7 @@ process.umask = function() { return 0; }; return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, -1), d3_svg_lineCardinalTangents(points, tension)); } function d3_svg_lineCardinalClosed(points, tension) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), + return points.length < 3 ? d3_svg_lineLinearClosed(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); } function d3_svg_lineCardinal(points, tension) { @@ -8935,9 +8971,11 @@ process.umask = function() { return 0; }; var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace()); function d3_selection_interruptNS(ns) { return function() { - var lock, active; - if ((lock = this[ns]) && (active = lock[lock.active])) { - if (--lock.count) delete lock[lock.active]; else delete this[ns]; + var lock, activeId, active; + if ((lock = this[ns]) && (active = lock[activeId = lock.active])) { + active.timer.c = null; + active.timer.t = NaN; + if (--lock.count) delete lock[activeId]; else delete this[ns]; lock.active += .5; active.event && active.event.interrupt.call(this, this.__data__, active.index); } @@ -9192,12 +9230,68 @@ process.umask = function() { return 0; }; var lock = node[ns] || (node[ns] = { active: 0, count: 0 - }), transition = lock[id]; + }), transition = lock[id], time, timer, duration, ease, tweens; + function schedule(elapsed) { + var delay = transition.delay; + timer.t = delay + time; + if (delay <= elapsed) return start(elapsed - delay); + timer.c = start; + } + function start(elapsed) { + var activeId = lock.active, active = lock[activeId]; + if (active) { + active.timer.c = null; + active.timer.t = NaN; + --lock.count; + delete lock[activeId]; + active.event && active.event.interrupt.call(node, node.__data__, active.index); + } + for (var cancelId in lock) { + if (+cancelId < id) { + var cancel = lock[cancelId]; + cancel.timer.c = null; + cancel.timer.t = NaN; + --lock.count; + delete lock[cancelId]; + } + } + timer.c = tick; + d3_timer(function() { + if (timer.c && tick(elapsed || 1)) { + timer.c = null; + timer.t = NaN; + } + return 1; + }, 0, time); + lock.active = id; + transition.event && transition.event.start.call(node, node.__data__, i); + tweens = []; + transition.tween.forEach(function(key, value) { + if (value = value.call(node, node.__data__, i)) { + tweens.push(value); + } + }); + ease = transition.ease; + duration = transition.duration; + } + function tick(elapsed) { + var t = elapsed / duration, e = ease(t), n = tweens.length; + while (n > 0) { + tweens[--n].call(node, e); + } + if (t >= 1) { + transition.event && transition.event.end.call(node, node.__data__, i); + if (--lock.count) delete lock[id]; else delete node[ns]; + return 1; + } + } if (!transition) { - var time = inherit.time; + time = inherit.time; + timer = d3_timer(schedule, 0, time); transition = lock[id] = { tween: new d3_Map(), time: time, + timer: timer, delay: inherit.delay, duration: inherit.duration, ease: inherit.ease, @@ -9205,49 +9299,6 @@ process.umask = function() { return 0; }; }; inherit = null; ++lock.count; - d3.timer(function(elapsed) { - var delay = transition.delay, duration, ease, timer = d3_timer_active, tweened = []; - timer.t = delay + time; - if (delay <= elapsed) return start(elapsed - delay); - timer.c = start; - function start(elapsed) { - if (lock.active > id) return stop(); - var active = lock[lock.active]; - if (active) { - --lock.count; - delete lock[lock.active]; - active.event && active.event.interrupt.call(node, node.__data__, active.index); - } - lock.active = id; - transition.event && transition.event.start.call(node, node.__data__, i); - transition.tween.forEach(function(key, value) { - if (value = value.call(node, node.__data__, i)) { - tweened.push(value); - } - }); - ease = transition.ease; - duration = transition.duration; - d3.timer(function() { - timer.c = tick(elapsed || 1) ? d3_true : tick; - return 1; - }, 0, time); - } - function tick(elapsed) { - if (lock.active !== id) return 1; - var t = elapsed / duration, e = ease(t), n = tweened.length; - while (n > 0) { - tweened[--n].call(node, e); - } - if (t >= 1) { - transition.event && transition.event.end.call(node, node.__data__, i); - return stop(); - } - } - function stop() { - if (--lock.count) delete lock[id]; else delete node[ns]; - return 1; - } - }, 0, time); } } d3.svg.axis = function() { @@ -9301,7 +9352,7 @@ process.umask = function() { return 0; }; }; axis.ticks = function() { if (!arguments.length) return tickArguments_; - tickArguments_ = arguments; + tickArguments_ = d3_array(arguments); return axis; }; axis.tickValues = function(x) { @@ -9823,8 +9874,7 @@ process.umask = function() { return 0; }; d3.xml = d3_xhrType(function(request) { return request.responseXML; }); - if (typeof define === "function" && define.amd) define(d3); else if (typeof module === "object" && module.exports) module.exports = d3; - this.d3 = d3; + if (typeof define === "function" && define.amd) this.d3 = d3, define(d3); else if (typeof module === "object" && module.exports) module.exports = d3; else this.d3 = d3; }(); },{}],5:[function(require,module,exports){ /** @@ -53585,41 +53635,74 @@ var allCommitsDict = {}; exports.setConf = function (config) {}; function svgCreateDefs(svg) { - svg.append("defs").append("circle").attr("id", "def-commit").attr("r", 15).attr("cx", 0).attr("cy", 0); - svg.select("defs").append("line").attr("id", "def-arrow-rl").attr("x1", 25).attr("y1", 0).attr("x2", -25).attr("y2", 0).attr("marker-end", "url(#triangle)"); -} -function svgAddArrowMarker(svg) { - svg.append("marker").attr({ - "id": "triangle", - "refX": "5", - "refY": "5", - "markerUnits": "strokeWidth", - "fill": "#666", - "markerWidth": "4", - "markerHeight": "3", - "orient": "auto", - "viewBox": "0,0,10,10" - }).append("svg:path").attr("d", "M 0 0 L 10 5 L 0 10 z"); + svg.append("defs").append("g").attr("id", "def-commit").append("circle").attr("r", 15).attr("cx", 0).attr("cy", 0); + svg.select("#def-commit").append('foreignObject').attr('width', 100).attr('height', 100).attr('x', 50).attr('y', 50).attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility').append('xhtml:p').text("a big chunk of text that should wrap"); + //.attr("requiredExtensions", "http://www.w3.org/1999/xhtml") + //.attr("width", 50) + //.attr("height", 30) + //.attr("x", 30) + //.attr("y", 30) + //.append("xhtml:body") + //.append("xhtml:p") + //.text("something") } -function svgDrawLine(svg, points) { - +function svgDrawLine(svg, points, interpolate) { + interpolate = interpolate || "basis"; var lineGen = d3.svg.line().x(function (d) { - return d.x; + return Math.round(d.x); }).y(function (d) { - return d.y; - }).interpolate("basis"); + return Math.round(d.y); + }).interpolate(interpolate); svg.append("svg:path").attr("d", lineGen(points)).style("stroke", "grey").style("stroke-width", "4").style("fill", "none"); } +// Pass in the element and its pre-transform coords +function getElementCoords(element, coords) { + coords = coords || element.node().getBBox(); + var ctm = element.node().getCTM(), + xn = ctm.e + coords.x * ctm.a, + yn = ctm.f + coords.y * ctm.d; + //log.debug(ctm, coords); + return { + left: xn, + top: yn, + width: coords.width, + height: coords.height + }; +}; function svgDrawLineForCommits(svg, fromId, toId) { log.debug("svgDrawLineForCommits: ", fromId, toId); - var fromBbox = svg.select("#node-" + fromId).node().getBBox(); - var toBbox = svg.select("#node-" + toId).node().getBBox(); + var fromBbox = getElementCoords(svg.select("#node-" + fromId + " circle")); + var toBbox = getElementCoords(svg.select("#node-" + toId + " circle")); //log.debug("svgDrawLineForCommits: ", fromBbox, toBbox); - svgDrawLine(svg, [{ "x": fromBbox.x, "y": fromBbox.y + fromBbox.height / 2 }, { "x": toBbox.x + (fromBbox.x - toBbox.x) / 2, "y": fromBbox.y + fromBbox.height / 2 }, { "x": toBbox.x + (fromBbox.x - toBbox.x) / 2, "y": toBbox.y + toBbox.height / 2 }, { "x": toBbox.x + toBbox.width, "y": toBbox.y + toBbox.height / 2 }]); + if (fromBbox.left - toBbox.left > 100) { + var lineStart = { x: fromBbox.left - 100, y: toBbox.top + toBbox.height / 2 }; + var lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 }; + svgDrawLine(svg, [lineStart, lineEnd], "linear"); + svgDrawLine(svg, [{ x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2 }, { x: fromBbox.left - 50, y: fromBbox.top + fromBbox.height / 2 }, { x: fromBbox.left - 50, y: lineStart.y }, lineStart]); + } else { + svgDrawLine(svg, [{ + "x": fromBbox.left, + "y": fromBbox.top + fromBbox.height / 2 + }, { + "x": fromBbox.left - 50, + "y": fromBbox.top + fromBbox.height / 2 + }, { + "x": fromBbox.left - 50, + "y": toBbox.top + toBbox.height / 2 + }, { + "x": toBbox.left + toBbox.width, + "y": toBbox.top + toBbox.height / 2 + }]); + } } + +function cloneNode(svg, selector) { + return svg.select(selector).node().cloneNode(true); +} + function renderCommitHistory(svg, commitid, branches, direction, branchNum) { var commit; branchNum = branchNum || 1; @@ -53628,11 +53711,17 @@ function renderCommitHistory(svg, commitid, branches, direction, branchNum) { commit = allCommitsDict[commitid]; log.debug("in renderCommitHistory", commit.id, commit.seq); if (svg.select("#node-" + commitid).size() > 0) return; - svg.append("g").attr("class", "commit").attr("id", function () { + svg.append(function () { + return cloneNode(svg, "#def-commit"); + }).attr("class", "commit").attr("id", function () { return "node-" + commit.id; - }).append("use").attr("transform", function () { + }) + //.append("use") + .attr("transform", function () { return "translate(" + (commit.seq * 100 + 50) + ", " + branchNum * 50 + ")"; - }).attr("xlink:href", "#def-commit").attr("fill", "yellow").attr("stroke", "grey").attr("stroke-width", "2"); + }) + //.attr("xlink:href", "#def-commit") + .attr("fill", "yellow").attr("stroke", "grey").attr("stroke-width", "2"); commitid = commit.parent; } while (commitid && allCommitsDict[commitid]); @@ -53674,7 +53763,7 @@ exports.draw = function (txt, id, ver) { var svg = d3.select('#' + id); svgAddArrowMarker(svg); svgCreateDefs(svg); - var branchNum = 0; + var branchNum = 1; _.each(branches, function (v, k) { renderCommitHistory(svg, v.commit.id, branches, direction, branchNum); renderLines(svg, v.commit); diff --git a/src/diagrams/gitGraph/gitGraphRenderer.js b/src/diagrams/gitGraph/gitGraphRenderer.js index 27ce26be2..511a2ae9b 100644 --- a/src/diagrams/gitGraph/gitGraphRenderer.js +++ b/src/diagrams/gitGraph/gitGraphRenderer.js @@ -6,70 +6,106 @@ var Logger = require('../../logger'); var log = new Logger.Log(); var allCommitsDict = {}; -exports.setConf = function (config) { +exports.setConf = function(config) { } function svgCreateDefs(svg) { svg.append("defs") - .append("circle") + .append("g") .attr("id", "def-commit") + .append("circle") .attr("r", 15) .attr("cx", 0) .attr("cy", 0); - svg.select("defs") - .append("line") - .attr("id", "def-arrow-rl") - .attr("x1", 25) - .attr("y1", 0) - .attr("x2", -25) - .attr("y2", 0) - .attr("marker-end", "url(#triangle)"); -} -function svgAddArrowMarker(svg) { - svg.append("marker") - .attr({ - "id": "triangle", - "refX": "5", - "refY": "5", - "markerUnits": "strokeWidth", - "fill": "#666", - "markerWidth": "4", - "markerHeight": "3", - "orient": "auto", - "viewBox": "0,0,10,10" - }) - .append("svg:path") - .attr("d", "M 0 0 L 10 5 L 0 10 z"); + svg.select("#def-commit") + .append('foreignObject') + .attr('width', 100) + .attr('height', 100) + .attr('x', 50) + .attr('y', 50) + .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility') + .append('xhtml:p') + .text("a big chunk of text that should wrap"); + //.attr("requiredExtensions", "http://www.w3.org/1999/xhtml") + //.attr("width", 50) + //.attr("height", 30) + //.attr("x", 30) + //.attr("y", 30) + //.append("xhtml:body") + //.append("xhtml:p") + //.text("something") } -function svgDrawLine(svg, points) { +function svgDrawLine(svg, points, interpolate) { + interpolate = interpolate || "basis"; var lineGen = d3.svg.line() - .x(function(d) { return d.x }) - .y(function(d) {return d.y}) - .interpolate("basis"); + .x(function(d) { + return Math.round(d.x) + }) + .y(function(d) { + return Math.round(d.y) + }) + .interpolate(interpolate); svg - .append("svg:path") - .attr("d", lineGen(points)) - .style("stroke", "grey") - .style("stroke-width", "4") - .style("fill", "none"); + .append("svg:path") + .attr("d", lineGen(points)) + .style("stroke", "grey") + .style("stroke-width", "4") + .style("fill", "none"); } +// Pass in the element and its pre-transform coords +function getElementCoords(element, coords) { + coords = coords || element.node().getBBox(); + var ctm = element.node().getCTM(), + xn = ctm.e + coords.x * ctm.a, + yn = ctm.f + coords.y * ctm.d; + //log.debug(ctm, coords); + return { + left: xn, + top: yn, + width: coords.width, + height: coords.height + }; +}; function svgDrawLineForCommits(svg, fromId, toId) { log.debug("svgDrawLineForCommits: ", fromId, toId); - var fromBbox = svg.select("#node-" + fromId).node().getBBox(); - var toBbox = svg.select("#node-" + toId).node().getBBox(); + var fromBbox = getElementCoords(svg.select("#node-" + fromId + " circle")); + var toBbox = getElementCoords(svg.select("#node-" + toId + " circle")); //log.debug("svgDrawLineForCommits: ", fromBbox, toBbox); - svgDrawLine(svg, [ - {"x": fromBbox.x, "y": fromBbox.y + fromBbox.height/2 }, - {"x": toBbox.x + (fromBbox.x - toBbox.x)/2, "y": fromBbox.y + fromBbox.height/2 }, - {"x": toBbox.x + (fromBbox.x - toBbox.x)/2, "y": toBbox.y + toBbox.height/2 }, - {"x": toBbox.x + toBbox.width, "y": toBbox.y + toBbox.height/2 } - ]); + if (fromBbox.left - toBbox.left > 100) { + var lineStart = { x: fromBbox.left - 100, y: toBbox.top + toBbox.height/2}; + var lineEnd ={ x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height/2 }; + svgDrawLine(svg, [lineStart , lineEnd], "linear") + svgDrawLine(svg, [ + {x: fromBbox.left, y: fromBbox.top + fromBbox.height/2}, + {x: fromBbox.left - 50, y: fromBbox.top + fromBbox.height/2}, + {x: fromBbox.left - 50, y: lineStart.y}, + lineStart]); + } else { + svgDrawLine(svg, [{ + "x": fromBbox.left, + "y": fromBbox.top + fromBbox.height / 2 + }, { + "x": fromBbox.left - 50, + "y": fromBbox.top + fromBbox.height / 2 + }, { + "x": fromBbox.left - 50, + "y": toBbox.top + toBbox.height / 2 + }, { + "x": toBbox.left + toBbox.width, + "y": toBbox.top + toBbox.height / 2 + }]); + } } + +function cloneNode(svg, selector) { + return svg.select(selector).node().cloneNode(true); +} + function renderCommitHistory(svg, commitid, branches, direction, branchNum) { var commit; branchNum = branchNum || 1; @@ -77,16 +113,20 @@ function renderCommitHistory(svg, commitid, branches, direction, branchNum) { do { commit = allCommitsDict[commitid]; log.debug("in renderCommitHistory", commit.id, commit.seq); - if (svg.select("#node-" + commitid).size() > 0) return; + if (svg.select("#node-" + commitid).size() > 0) return; svg - .append("g") - .attr("class", "commit") - .attr("id", function() { return "node-" + commit.id; }) - .append("use") - .attr("transform", function() { - return "translate(" + (commit.seq * 100 + 50 )+ ", " + (branchNum * 50)+")"; + .append(function() { + return cloneNode(svg, "#def-commit"); }) - .attr("xlink:href", "#def-commit") + .attr("class", "commit") + .attr("id", function() { + return "node-" + commit.id; + }) + //.append("use") + .attr("transform", function() { + return "translate(" + (commit.seq * 100 + 50) + ", " + (branchNum * 50) + ")"; + }) + //.attr("xlink:href", "#def-commit") .attr("fill", "yellow") .attr("stroke", "grey") .attr("stroke-width", "2"); @@ -116,7 +156,7 @@ function renderLines(svg, commit) { } } -exports.draw = function (txt, id, ver) { +exports.draw = function(txt, id, ver) { try { var parser; parser = gitGraphParser.parser; @@ -129,9 +169,8 @@ exports.draw = function (txt, id, ver) { allCommitsDict = db.getCommits(); var branches = db.getBranchesAsObjArray(); var svg = d3.select('#' + id); - svgAddArrowMarker(svg); svgCreateDefs(svg); - var branchNum = 0; + var branchNum = 1; _.each(branches, function(v, k) { renderCommitHistory(svg, v.commit.id, branches, direction, branchNum); renderLines(svg, v.commit);