@@ -20,12 +20,15 @@ var ARROWPATHS = require('./arrow_paths');
2020 *
2121 * @param {d3.selection } el3: a d3-selected line or path element
2222 *
23- * @param {string } ends: 'start', 'end', or 'start+end' for which ends get arrowheads
23+ * @param {string } ends: 'none', ' start', 'end', or 'start+end' for which ends get arrowheads
2424 *
2525 * @param {object } options: style information. Must have all the following:
26- * @param {number } options.arrowhead: head style - see ./arrow_paths
27- * @param {number } options.arrowsize: relative size of the head vs line width
28- * @param {number } options.standoff: distance in px to move the arrow point from its target
26+ * @param {number } options.arrowhead: end head style - see ./arrow_paths
27+ * @param {number } options.startarrowhead: start head style - see ./arrow_paths
28+ * @param {number } options.arrowsize: relative size of the end head vs line width
29+ * @param {number } options.startarrowsize: relative size of the start head vs line width
30+ * @param {number } options.standoff: distance in px to move the end arrow point from its target
31+ * @param {number } options.startstandoff: distance in px to move the start arrow point from its target
2932 * @param {number } options.arrowwidth: width of the arrow line
3033 * @param {string } options.arrowcolor: color of the arrow line, for the head to match
3134 * Note that the opacity of this color is ignored, as it's assumed the container
@@ -35,10 +38,13 @@ var ARROWPATHS = require('./arrow_paths');
3538module . exports = function drawArrowHead ( el3 , ends , options ) {
3639 var el = el3 . node ( ) ;
3740 var headStyle = ARROWPATHS [ options . arrowhead || 0 ] ;
38- var scale = ( options . arrowwidth || 1 ) * options . arrowsize ;
41+ var startHeadStyle = ARROWPATHS [ options . startarrowhead || 0 ] ;
42+ var scale = ( options . arrowwidth || 1 ) * ( options . arrowsize || 1 ) ;
43+ var startScale = ( options . arrowwidth || 1 ) * ( options . startarrowsize || 1 ) ;
3944 var doStart = ends . indexOf ( 'start' ) >= 0 ;
4045 var doEnd = ends . indexOf ( 'end' ) >= 0 ;
4146 var backOff = headStyle . backoff * scale + options . standoff ;
47+ var startBackOff = startHeadStyle . backoff * startScale + options . startstandoff ;
4248
4349 var start , end , startRot , endRot ;
4450
@@ -51,6 +57,13 @@ module.exports = function drawArrowHead(el3, ends, options) {
5157
5258 startRot = Math . atan2 ( dy , dx ) ;
5359 endRot = startRot + Math . PI ;
60+ if ( backOff && startBackOff ) {
61+ if ( backOff + startBackOff > Math . sqrt ( dx * dx + dy * dy ) ) {
62+ hideLine ( ) ;
63+ return ;
64+ }
65+ }
66+
5467 if ( backOff ) {
5568 if ( backOff * backOff > dx * dx + dy * dy ) {
5669 hideLine ( ) ;
@@ -59,16 +72,24 @@ module.exports = function drawArrowHead(el3, ends, options) {
5972 var backOffX = backOff * Math . cos ( startRot ) ,
6073 backOffY = backOff * Math . sin ( startRot ) ;
6174
62- if ( doStart ) {
63- start . x -= backOffX ;
64- start . y -= backOffY ;
65- el3 . attr ( { x1 : start . x , y1 : start . y } ) ;
66- }
67- if ( doEnd ) {
68- end . x += backOffX ;
69- end . y += backOffY ;
70- el3 . attr ( { x2 : end . x , y2 : end . y } ) ;
75+ end . x += backOffX ;
76+ end . y += backOffY ;
77+ el3 . attr ( { x2 : end . x , y2 : end . y } ) ;
78+
79+ }
80+
81+ if ( startBackOff ) {
82+ if ( startBackOff * startBackOff > dx * dx + dy * dy ) {
83+ hideLine ( ) ;
84+ return ;
7185 }
86+ var startBackOffX = startBackOff * Math . cos ( startRot ) ,
87+ startbackOffY = startBackOff * Math . sin ( startRot ) ;
88+
89+ start . x -= startBackOffX ;
90+ start . y -= startbackOffY ;
91+ el3 . attr ( { x1 : start . x , y1 : start . y } ) ;
92+
7293 }
7394 }
7495 else if ( el . nodeName === 'path' ) {
@@ -79,59 +100,53 @@ module.exports = function drawArrowHead(el3, ends, options) {
79100 // combine the two
80101 dashArray = '' ;
81102
82- if ( pathlen < backOff ) {
103+ if ( pathlen < backOff + startBackOff ) {
83104 hideLine ( ) ;
84105 return ;
85106 }
86107
87- if ( doStart ) {
88- var start0 = el . getPointAtLength ( 0 ) ;
89- var dstart = el . getPointAtLength ( 0.1 ) ;
90108
91- startRot = Math . atan2 ( start0 . y - dstart . y , start0 . x - dstart . x ) ;
92- start = el . getPointAtLength ( Math . min ( backOff , pathlen ) ) ;
109+ var start0 = el . getPointAtLength ( 0 ) ;
110+ var dstart = el . getPointAtLength ( 0.1 ) ;
93111
94- if ( backOff ) dashArray = '0px,' + backOff + 'px,' ;
95- }
112+ startRot = Math . atan2 ( start0 . y - dstart . y , start0 . x - dstart . x ) ;
113+ start = el . getPointAtLength ( Math . min ( startBackOff , pathlen ) ) ;
96114
97- if ( doEnd ) {
98- var end0 = el . getPointAtLength ( pathlen ) ;
99- var dend = el . getPointAtLength ( pathlen - 0.1 ) ;
115+ dashArray = '0px,' + startBackOff + 'px,' ;
100116
101- endRot = Math . atan2 ( end0 . y - dend . y , end0 . x - dend . x ) ;
102- end = el . getPointAtLength ( Math . max ( 0 , pathlen - backOff ) ) ;
117+ var end0 = el . getPointAtLength ( pathlen ) ;
118+ var dend = el . getPointAtLength ( pathlen - 0.1 ) ;
103119
104- if ( backOff ) {
105- var shortening = dashArray ? 2 * backOff : backOff ;
106- dashArray += ( pathlen - shortening ) + 'px,' + pathlen + 'px' ;
107- }
108- }
109- else if ( dashArray ) dashArray += pathlen + 'px' ;
120+ endRot = Math . atan2 ( end0 . y - dend . y , end0 . x - dend . x ) ;
121+ end = el . getPointAtLength ( Math . max ( 0 , pathlen - backOff ) ) ;
122+
123+ var shortening = dashArray ? startBackOff + backOff : backOff ;
124+ dashArray += ( pathlen - shortening ) + 'px,' + pathlen + 'px' ;
110125
111- if ( dashArray ) el3 . style ( 'stroke-dasharray' , dashArray ) ;
126+ el3 . style ( 'stroke-dasharray' , dashArray ) ;
112127 }
113128
114129 function hideLine ( ) { el3 . style ( 'stroke-dasharray' , '0px,100px' ) ; }
115130
116- function drawhead ( p , rot ) {
117- if ( ! headStyle . path ) return ;
118- if ( headStyle . noRotate ) rot = 0 ;
131+ function drawhead ( arrowHeadStyle , p , rot , arrowScale ) {
132+ if ( ! arrowHeadStyle . path ) return ;
133+ if ( arrowHeadStyle . noRotate ) rot = 0 ;
119134
120135 d3 . select ( el . parentNode ) . append ( 'path' )
121136 . attr ( {
122137 'class' : el3 . attr ( 'class' ) ,
123- d : headStyle . path ,
138+ d : arrowHeadStyle . path ,
124139 transform :
125140 'translate(' + p . x + ',' + p . y + ')' +
126141 ( rot ? 'rotate(' + ( rot * 180 / Math . PI ) + ')' : '' ) +
127- 'scale(' + scale + ')'
142+ 'scale(' + arrowScale + ')'
128143 } )
129144 . style ( {
130145 fill : Color . rgb ( options . arrowcolor ) ,
131146 'stroke-width' : 0
132147 } ) ;
133148 }
134149
135- if ( doStart ) drawhead ( start , startRot ) ;
136- if ( doEnd ) drawhead ( end , endRot ) ;
150+ if ( doStart ) drawhead ( startHeadStyle , start , startRot , startScale ) ;
151+ if ( doEnd ) drawhead ( headStyle , end , endRot , scale ) ;
137152} ;
0 commit comments