|
1 | 1 | /* ==========================================================
|
2 |
| - * GitGraph v1.1.3 |
| 2 | + * GitGraph v1.2.0 |
3 | 3 | * https://github.com/nicoespeon/gitgraph.js
|
4 | 4 | * ==========================================================
|
5 | 5 | * Copyright (c) 2016 Nicolas CARLO (@nicoespeon) ٩(^‿^)۶
|
|
68 | 68 | return scalingFactor;
|
69 | 69 | }
|
70 | 70 |
|
| 71 | + /** |
| 72 | + * Returns `true` if `graph` has a vertical orientation. |
| 73 | + * |
| 74 | + * @param {GitGraph} graph |
| 75 | + * @returns {boolean} |
| 76 | + * @private |
| 77 | + */ |
| 78 | + function _isVertical ( graph ) { |
| 79 | + return (graph.orientation === "vertical" || graph.orientation === "vertical-reverse"); |
| 80 | + } |
| 81 | + |
| 82 | + /** |
| 83 | + * Returns `true` if `graph` has an horizontal orientation. |
| 84 | + * |
| 85 | + * @param {GitGraph} graph |
| 86 | + * @returns {boolean} |
| 87 | + * @private |
| 88 | + */ |
| 89 | + function _isHorizontal ( graph ) { |
| 90 | + return (graph.orientation === "horizontal" || graph.orientation === "horizontal-reverse"); |
| 91 | + } |
| 92 | + |
71 | 93 | /**
|
72 | 94 | * GitGraph
|
73 | 95 | *
|
|
80 | 102 | * @param {String} [options.mode = (null|"compact")] - Display mode
|
81 | 103 | * @param {HTMLElement} [options.canvas] - DOM canvas (ex: document.getElementById("id"))
|
82 | 104 | * @param {String} [options.orientation = ("vertical-reverse"|"horizontal"|"horizontal-reverse")] - Graph orientation
|
| 105 | + * @param {Boolean} [options.reverseArrow = false] - Make arrows point to ancestors if true |
83 | 106 | *
|
84 | 107 | * @this GitGraph
|
85 | 108 | **/
|
|
88 | 111 | options = (typeof options === "object") ? options : {};
|
89 | 112 | this.elementId = (typeof options.elementId === "string") ? options.elementId : "gitGraph";
|
90 | 113 | this.author = (typeof options.author === "string") ? options.author : "Sergio Flores <[email protected]>";
|
| 114 | + this.reverseArrow = booleanOptionOr( options.reverseArrow, false ); |
91 | 115 |
|
92 | 116 | // Template management
|
93 | 117 | if ( (typeof options.template === "string")
|
94 | 118 | || (typeof options.template === "object") ) {
|
95 | 119 | this.template = this.newTemplate( options.template );
|
96 |
| - } |
97 |
| - else if ( options.template instanceof Template ) { |
| 120 | + } else if ( options.template instanceof Template ) { |
98 | 121 | this.template = options.template;
|
99 |
| - } |
100 |
| - else { |
| 122 | + } else { |
101 | 123 | this.template = this.newTemplate( "metro" );
|
102 | 124 | }
|
103 | 125 |
|
|
284 | 306 | * @this GitGraph
|
285 | 307 | **/
|
286 | 308 | GitGraph.prototype.render = function () {
|
287 |
| - var scalingFactor = _getScale( this.context ); |
| 309 | + this.scalingFactor = _getScale( this.context ); |
288 | 310 |
|
289 | 311 | // Resize canvas
|
290 | 312 | var unscaledResolution = {
|
|
305 | 327 | this.canvas.style.width = unscaledResolution.x + "px";
|
306 | 328 | this.canvas.style.height = unscaledResolution.y + "px";
|
307 | 329 |
|
308 |
| - this.canvas.width = unscaledResolution.x * scalingFactor; |
309 |
| - this.canvas.height = unscaledResolution.y * scalingFactor; |
| 330 | + this.canvas.width = unscaledResolution.x * this.scalingFactor; |
| 331 | + this.canvas.height = unscaledResolution.y * this.scalingFactor; |
310 | 332 |
|
311 | 333 | // Clear All
|
312 | 334 | this.context.clearRect( 0, 0, this.canvas.width, this.canvas.height );
|
|
325 | 347 | }
|
326 | 348 |
|
327 | 349 | // Scale the context when every transformations have been made.
|
328 |
| - this.context.scale( scalingFactor, scalingFactor ); |
| 350 | + this.context.scale( this.scalingFactor, this.scalingFactor ); |
329 | 351 |
|
330 | 352 | // Render branches
|
331 | 353 | for ( var i = this.branches.length - 1, branch; !!(branch = this.branches[ i ]); i-- ) {
|
|
338 | 360 | for ( var j = 0, commit; !!(commit = this.commits[ j ]); j++ ) {
|
339 | 361 | commit.render();
|
340 | 362 | }
|
| 363 | + |
| 364 | + _emitEvent( this.canvas, "graph:render", { id: this.elementId } ); |
341 | 365 | };
|
342 | 366 |
|
343 | 367 | /**
|
|
357 | 381 | * @this GitGraph
|
358 | 382 | **/
|
359 | 383 | GitGraph.prototype.applyCommits = function ( event, callbackFn ) {
|
360 |
| - var scalingFactor = _getScale( this.context ); |
361 |
| - |
362 | 384 | for ( var i = 0, commit; !!(commit = this.commits[ i ]); i++ ) {
|
363 |
| - var distanceX = (commit.x + (this.offsetX + this.marginX) / scalingFactor - event.offsetX); |
364 |
| - var distanceY = (commit.y + (this.offsetY + this.marginY) / scalingFactor - event.offsetY); |
| 385 | + var distanceX = (commit.x + (this.offsetX + this.marginX) / this.scalingFactor - event.offsetX); |
| 386 | + var distanceY = (commit.y + (this.offsetY + this.marginY) / this.scalingFactor - event.offsetY); |
365 | 387 | var distanceBetweenCommitCenterAndMouse = Math.sqrt( Math.pow( distanceX, 2 ) + Math.pow( distanceY, 2 ) );
|
366 | 388 | var isOverCommit = distanceBetweenCommitCenterAndMouse < this.template.commit.dot.size;
|
367 | 389 |
|
|
397 | 419 | self.tooltip.style.display = "block";
|
398 | 420 | }
|
399 | 421 |
|
400 |
| - function emitMouseoverEvent ( commit ) { |
401 |
| - var mouseoverEventOptions = { |
| 422 | + function emitCommitEvent ( commit, event ) { |
| 423 | + var mouseEventOptions = { |
402 | 424 | author: commit.author,
|
403 | 425 | message: commit.message,
|
404 | 426 | date: commit.date,
|
405 | 427 | sha1: commit.sha1
|
406 | 428 | };
|
407 | 429 |
|
408 |
| - _emitEvent( self.canvas, "commit:mouseover", mouseoverEventOptions ); |
| 430 | + _emitEvent( self.canvas, "commit:" + event, mouseEventOptions ); |
409 | 431 | }
|
410 | 432 |
|
411 | 433 | self.applyCommits( event, function ( commit, isOverCommit ) {
|
412 | 434 | if ( isOverCommit ) {
|
413 |
| - if ( !self.template.commit.message.display ) { |
| 435 | + if ( !self.template.commit.message.display && self.template.commit.shouldDisplayTooltipsInCompactMode ) { |
414 | 436 | showCommitTooltip( commit );
|
415 | 437 | }
|
416 | 438 |
|
417 |
| - if ( !commit.isMouseover ) { |
418 |
| - emitMouseoverEvent( commit ); |
| 439 | + // Don't emit event if we already were over a commit. |
| 440 | + if ( !commit.isMouseOver ) { |
| 441 | + emitCommitEvent( commit, "mouseover" ); |
419 | 442 | }
|
420 | 443 |
|
421 | 444 | isOut = false;
|
422 |
| - commit.isMouseover = true; |
| 445 | + commit.isMouseOver = true; |
423 | 446 | } else {
|
424 |
| - commit.isMouseover = false; |
| 447 | + // Don't emit event if we already were out of a commit. |
| 448 | + if ( commit.isMouseOver ) { |
| 449 | + emitCommitEvent( commit, "mouseout" ); |
| 450 | + } |
| 451 | + commit.isMouseOver = false; |
425 | 452 | }
|
426 | 453 | } );
|
427 | 454 |
|
|
587 | 614 | **/
|
588 | 615 | Branch.prototype.commit = function ( options ) {
|
589 | 616 | if ( typeof (options) === "string" ) {
|
590 |
| - var message = options; |
591 |
| - options = { message: message }; |
| 617 | + options = { message: options }; |
592 | 618 | } else if ( typeof (options) !== "object" ) {
|
593 | 619 | options = {};
|
594 | 620 | }
|
|
731 | 757 |
|
732 | 758 | // Check integrity of target
|
733 | 759 | if ( targetBranch instanceof Branch === false || targetBranch === this ) {
|
734 |
| - return; |
| 760 | + return this; |
735 | 761 | }
|
736 | 762 |
|
737 | 763 | // Merge commit
|
|
820 | 846 | * @param {String} [options.date] - Date of commit, default is now
|
821 | 847 | * @param {String} [options.detail] - DOM Element of detail part
|
822 | 848 | * @param {String} [options.sha1] - Sha1, default is a random short sha1
|
| 849 | + * @param {Commit} [options.parentCommit] - Parent commit |
| 850 | + * @param {String} [options.type = ("mergeCommit"|null)] - Type of commit |
| 851 | + * |
| 852 | + * @param {String} [options.tag] - Tag of the commit |
| 853 | + * @param {String} [options.tagColor = options.color] - Specific tag color |
| 854 | + * @param {String} [options.tagFont = this.template.commit.tag.font] - Font of the tag |
| 855 | + * |
823 | 856 | * @param {String} [options.dotColor = options.color] - Specific dot color
|
824 | 857 | * @param {Number} [options.dotSize = this.template.commit.dot.size] - Dot size
|
825 | 858 | * @param {Number} [options.dotStrokeWidth = this.template.commit.dot.strokeWidth] - Dot stroke width
|
826 | 859 | * @param {Number} [options.dotStrokeColor = this.template.commit.dot.strokeColor]
|
827 |
| - * @param {Commit} [options.parentCommit] - Parent commit |
| 860 | + * |
828 | 861 | * @param {String} [options.message = "He doesn't like George Michael! Boooo!"] - Commit message
|
829 | 862 | * @param {String} [options.messageColor = options.color] - Specific message color
|
| 863 | + * @param {String} [options.messageFont = this.template.commit.message.font] - Font of the message |
830 | 864 | * @param {Boolean} [options.messageDisplay = this.template.commit.message.display] - Commit message policy
|
831 | 865 | * @param {Boolean} [options.messageAuthorDisplay = this.template.commit.message.displayAuthor] - Commit message author policy
|
832 | 866 | * @param {Boolean} [options.messageBranchDisplay = this.template.commit.message.displayBranch] - Commit message author policy
|
833 | 867 | * @param {Boolean} [options.messageHashDisplay = this.template.commit.message.displayHash] - Commit message hash policy
|
834 |
| - * @param {String} [options.type = ("mergeCommit"|null)] - Type of commit |
| 868 | + * |
| 869 | + * @param {String} [options.labelColor = options.color] - Specific label color |
| 870 | + * @param {String} [options.labelFont = this.template.branch.labelFont] - Font used for labels |
| 871 | + * |
835 | 872 | * @param {commitCallback} [options.onClick] - OnClick event for the commit dot
|
836 | 873 | * @param {Object} [options.representedObject] - Any object which is related to this commit. Can be used in onClick or the formatter. Useful to bind the commit to external objects such as database id etc.
|
837 | 874 | *
|
|
970 | 1007 | // Options
|
971 | 1008 | var size = this.template.arrow.size;
|
972 | 1009 | var color = this.template.arrow.color || this.branch.color;
|
| 1010 | + var isReversed = this.parent.reverseArrow; |
| 1011 | + |
| 1012 | + function rotate ( y, x ) { |
| 1013 | + var direction = (isReversed) ? -1 : 1; |
| 1014 | + return Math.atan2( direction * y, direction * x ); |
| 1015 | + } |
973 | 1016 |
|
974 | 1017 | // Angles calculation
|
975 |
| - var alpha = Math.atan2( |
976 |
| - this.parentCommit.y - this.y, |
977 |
| - this.parentCommit.x - this.x |
978 |
| - ); |
| 1018 | + var alpha = rotate( this.parentCommit.y - this.y, this.parentCommit.x - this.x ); |
979 | 1019 |
|
980 | 1020 | // Merge & Fork case
|
981 | 1021 | if ( this.type === "mergeCommit" || this === this.branch.commits[ 0 ] /* First commit */ ) {
|
982 |
| - alpha = Math.atan2( |
983 |
| - this.template.branch.spacingY * (this.parentCommit.branch.column - this.branch.column) + this.template.commit.spacingY * (this.showLabel ? 2 : 1), |
984 |
| - this.template.branch.spacingX * (this.parentCommit.branch.column - this.branch.column) + this.template.commit.spacingX * (this.showLabel ? 2 : 1) |
| 1022 | + var deltaColumn = (this.parentCommit.branch.column - this.branch.column); |
| 1023 | + var commitSpaceDelta = (this.showLabel ? 2 : 1); |
| 1024 | + |
| 1025 | + var isArrowVertical = ( |
| 1026 | + isReversed |
| 1027 | + && _isVertical( this.parent ) |
| 1028 | + && Math.abs( this.y - this.parentCommit.y ) > Math.abs( this.template.commit.spacingY ) |
| 1029 | + ); |
| 1030 | + var alphaX = (isArrowVertical) |
| 1031 | + ? 0 |
| 1032 | + : this.template.branch.spacingX * deltaColumn + this.template.commit.spacingX * commitSpaceDelta; |
| 1033 | + |
| 1034 | + var isArrowHorizontal = ( |
| 1035 | + isReversed |
| 1036 | + && _isHorizontal( this.parent ) |
| 1037 | + && Math.abs( this.x - this.parentCommit.x ) > Math.abs( this.template.commit.spacingX ) |
985 | 1038 | );
|
| 1039 | + var alphaY = (isArrowHorizontal) |
| 1040 | + ? 0 |
| 1041 | + : this.template.branch.spacingY * deltaColumn + this.template.commit.spacingY * commitSpaceDelta; |
| 1042 | + |
| 1043 | + alpha = rotate( alphaY, alphaX ); |
986 | 1044 | color = this.parentCommit.branch.color;
|
987 | 1045 | }
|
988 | 1046 |
|
989 | 1047 | var delta = Math.PI / 7; // Delta between left & right (radian)
|
990 | 1048 |
|
| 1049 | + var arrowX = (isReversed) ? this.parentCommit.x : this.x; |
| 1050 | + var arrowY = (isReversed) ? this.parentCommit.y : this.y; |
| 1051 | + |
991 | 1052 | // Top
|
992 | 1053 | var h = this.template.commit.dot.size + this.template.arrow.offset;
|
993 |
| - var x1 = h * Math.cos( alpha ) + this.x; |
994 |
| - var y1 = h * Math.sin( alpha ) + this.y; |
| 1054 | + var x1 = h * Math.cos( alpha ) + arrowX; |
| 1055 | + var y1 = h * Math.sin( alpha ) + arrowY; |
995 | 1056 |
|
996 | 1057 | // Bottom left
|
997 |
| - var x2 = (h + size) * Math.cos( alpha - delta ) + this.x; |
998 |
| - var y2 = (h + size) * Math.sin( alpha - delta ) + this.y; |
| 1058 | + var x2 = (h + size) * Math.cos( alpha - delta ) + arrowX; |
| 1059 | + var y2 = (h + size) * Math.sin( alpha - delta ) + arrowY; |
999 | 1060 |
|
1000 | 1061 | // Bottom center
|
1001 |
| - var x3 = (h + size / 2) * Math.cos( alpha ) + this.x; |
1002 |
| - var y3 = (h + size / 2) * Math.sin( alpha ) + this.y; |
| 1062 | + var x3 = (h + size / 2) * Math.cos( alpha ) + arrowX; |
| 1063 | + var y3 = (h + size / 2) * Math.sin( alpha ) + arrowY; |
1003 | 1064 |
|
1004 | 1065 | // Bottom right
|
1005 |
| - var x4 = (h + size) * Math.cos( alpha + delta ) + this.x; |
1006 |
| - var y4 = (h + size) * Math.sin( alpha + delta ) + this.y; |
| 1066 | + var x4 = (h + size) * Math.cos( alpha + delta ) + arrowX; |
| 1067 | + var y4 = (h + size) * Math.sin( alpha + delta ) + arrowY; |
1007 | 1068 |
|
1008 | 1069 | this.context.beginPath();
|
1009 | 1070 | this.context.fillStyle = color;
|
|
1039 | 1100 | * @param {String} [options.commit.color] - Master commit color (dot & message)
|
1040 | 1101 | * @param {String} [options.commit.dot.color] - Commit dot color
|
1041 | 1102 | * @param {Number} [options.commit.dot.size] - Commit dot size
|
1042 |
| - * @param {Number} [options.commit.dot.strokewidth] - Commit dot stroke width |
| 1103 | + * @param {Number} [options.commit.dot.strokeWidth] - Commit dot stroke width |
1043 | 1104 | * @param {Number} [options.commit.dot.strokeColor] - Commit dot stroke color
|
1044 | 1105 | * @param {String} [options.commit.message.color] - Commit message color
|
1045 | 1106 | * @param {Boolean} [options.commit.message.display] - Commit display policy
|
1046 | 1107 | * @param {Boolean} [options.commit.message.displayAuthor] - Commit message author policy
|
1047 | 1108 | * @param {Boolean} [options.commit.message.displayBranch] - Commit message branch policy
|
1048 | 1109 | * @param {Boolean} [options.commit.message.displayHash] - Commit message hash policy
|
1049 | 1110 | * @param {String} [options.commit.message.font = "normal 12pt Calibri"] - Commit message font
|
1050 |
| - * @param {commitCallback} [options.commit.tooltipHTMLFormatter] - Formatter for the tooltip contents. |
| 1111 | + * @param {Boolean} [options.commit.shouldDisplayTooltipsInCompactMode] - Tooltips policy |
| 1112 | + * @param {commitCallback} [options.commit.tooltipHTMLFormatter=true] - Formatter for the tooltip contents. |
1051 | 1113 | *
|
1052 | 1114 | * @this Template
|
1053 | 1115 | **/
|
|
1094 | 1156 | this.commit.spacingY = (typeof options.commit.spacingY === "number") ? options.commit.spacingY : 25;
|
1095 | 1157 | this.commit.widthExtension = (typeof options.commit.widthExtension === "number") ? options.commit.widthExtension : 0;
|
1096 | 1158 | this.commit.tooltipHTMLFormatter = options.commit.tooltipHTMLFormatter || null;
|
| 1159 | + this.commit.shouldDisplayTooltipsInCompactMode = booleanOptionOr( options.commit.shouldDisplayTooltipsInCompactMode, true ); |
1097 | 1160 |
|
1098 | 1161 | // Only one color, if null message takes branch color (full commit)
|
1099 | 1162 | this.commit.color = options.commit.color || null;
|
|
0 commit comments