@@ -20,12 +20,15 @@ var ARROWPATHS = require('./arrow_paths');
20
20
*
21
21
* @param {d3.selection } el3: a d3-selected line or path element
22
22
*
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
24
24
*
25
25
* @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
29
32
* @param {number } options.arrowwidth: width of the arrow line
30
33
* @param {string } options.arrowcolor: color of the arrow line, for the head to match
31
34
* Note that the opacity of this color is ignored, as it's assumed the container
@@ -35,10 +38,13 @@ var ARROWPATHS = require('./arrow_paths');
35
38
module . exports = function drawArrowHead ( el3 , ends , options ) {
36
39
var el = el3 . node ( ) ;
37
40
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 ) ;
39
44
var doStart = ends . indexOf ( 'start' ) >= 0 ;
40
45
var doEnd = ends . indexOf ( 'end' ) >= 0 ;
41
46
var backOff = headStyle . backoff * scale + options . standoff ;
47
+ var startBackOff = startHeadStyle . backoff * startScale + options . startstandoff ;
42
48
43
49
var start , end , startRot , endRot ;
44
50
@@ -51,6 +57,13 @@ module.exports = function drawArrowHead(el3, ends, options) {
51
57
52
58
startRot = Math . atan2 ( dy , dx ) ;
53
59
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
+
54
67
if ( backOff ) {
55
68
if ( backOff * backOff > dx * dx + dy * dy ) {
56
69
hideLine ( ) ;
@@ -59,16 +72,24 @@ module.exports = function drawArrowHead(el3, ends, options) {
59
72
var backOffX = backOff * Math . cos ( startRot ) ,
60
73
backOffY = backOff * Math . sin ( startRot ) ;
61
74
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 ;
71
85
}
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
+
72
93
}
73
94
}
74
95
else if ( el . nodeName === 'path' ) {
@@ -79,59 +100,53 @@ module.exports = function drawArrowHead(el3, ends, options) {
79
100
// combine the two
80
101
dashArray = '' ;
81
102
82
- if ( pathlen < backOff ) {
103
+ if ( pathlen < backOff + startBackOff ) {
83
104
hideLine ( ) ;
84
105
return ;
85
106
}
86
107
87
- if ( doStart ) {
88
- var start0 = el . getPointAtLength ( 0 ) ;
89
- var dstart = el . getPointAtLength ( 0.1 ) ;
90
108
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 ) ;
93
111
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 ) ) ;
96
114
97
- if ( doEnd ) {
98
- var end0 = el . getPointAtLength ( pathlen ) ;
99
- var dend = el . getPointAtLength ( pathlen - 0.1 ) ;
115
+ dashArray = '0px,' + startBackOff + 'px,' ;
100
116
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 ) ;
103
119
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' ;
110
125
111
- if ( dashArray ) el3 . style ( 'stroke-dasharray' , dashArray ) ;
126
+ el3 . style ( 'stroke-dasharray' , dashArray ) ;
112
127
}
113
128
114
129
function hideLine ( ) { el3 . style ( 'stroke-dasharray' , '0px,100px' ) ; }
115
130
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 ;
119
134
120
135
d3 . select ( el . parentNode ) . append ( 'path' )
121
136
. attr ( {
122
137
'class' : el3 . attr ( 'class' ) ,
123
- d : headStyle . path ,
138
+ d : arrowHeadStyle . path ,
124
139
transform :
125
140
'translate(' + p . x + ',' + p . y + ')' +
126
141
( rot ? 'rotate(' + ( rot * 180 / Math . PI ) + ')' : '' ) +
127
- 'scale(' + scale + ')'
142
+ 'scale(' + arrowScale + ')'
128
143
} )
129
144
. style ( {
130
145
fill : Color . rgb ( options . arrowcolor ) ,
131
146
'stroke-width' : 0
132
147
} ) ;
133
148
}
134
149
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 ) ;
137
152
} ;
0 commit comments