-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add "arrowanchor" property to annotations #2164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
f598c92
c4a0f1f
19a06c6
42138e7
191d5d2
8e75b74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,12 +20,15 @@ var ARROWPATHS = require('./arrow_paths'); | |
* | ||
* @param {d3.selection} el3: a d3-selected line or path element | ||
* | ||
* @param {string} ends: 'start', 'end', or 'start+end' for which ends get arrowheads | ||
* @param {string} ends: 'none', 'start', 'end', or 'start+end' for which ends get arrowheads | ||
* | ||
* @param {object} options: style information. Must have all the following: | ||
* @param {number} options.arrowhead: head style - see ./arrow_paths | ||
* @param {number} options.arrowsize: relative size of the head vs line width | ||
* @param {number} options.standoff: distance in px to move the arrow point from its target | ||
* @param {number} options.arrowhead: end head style - see ./arrow_paths | ||
* @param {number} options.startarrowhead: start head style - see ./arrow_paths | ||
* @param {number} options.arrowsize: relative size of the end head vs line width | ||
* @param {number} options.startarrowsize: relative size of the start head vs line width | ||
* @param {number} options.standoff: distance in px to move the end arrow point from its target | ||
* @param {number} options.startstandoff: distance in px to move the start arrow point from its target | ||
* @param {number} options.arrowwidth: width of the arrow line | ||
* @param {string} options.arrowcolor: color of the arrow line, for the head to match | ||
* Note that the opacity of this color is ignored, as it's assumed the container | ||
|
@@ -35,10 +38,14 @@ var ARROWPATHS = require('./arrow_paths'); | |
module.exports = function drawArrowHead(el3, ends, options) { | ||
var el = el3.node(); | ||
var headStyle = ARROWPATHS[options.arrowhead || 0]; | ||
var startHeadStyle = ARROWPATHS[options.startarrowhead || 0]; | ||
var scale = (options.arrowwidth || 1) * options.arrowsize; | ||
var startScale = (options.arrowwidth || 1) * options.startarrowsize; | ||
var doStart = ends.indexOf('start') >= 0; | ||
var doEnd = ends.indexOf('end') >= 0; | ||
var doNone = ends.indexOf('none') >= 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That said, I'm a little confused by the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed these |
||
var backOff = headStyle.backoff * scale + options.standoff; | ||
var startBackOff = startHeadStyle.backoff * startScale + options.startstandoff; | ||
|
||
var start, end, startRot, endRot; | ||
|
||
|
@@ -51,6 +58,13 @@ module.exports = function drawArrowHead(el3, ends, options) { | |
|
||
startRot = Math.atan2(dy, dx); | ||
endRot = startRot + Math.PI; | ||
if(backOff && startBackOff) { | ||
if(backOff * backOff + startBackOff * startBackOff > dx * dx + dy * dy) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this condition is quite right... should be the square of the sum, not the sum of squares. Probably we should just compare lengths, not lengths squared, that was an optimization on my part but it's obviously not very intuitive or extensible! But also I think we can simplify and only do this whole check once, instead of once for both, then again for if(backOff || startBackOff) {
if(backOff + startBackOff > Math.sqrt(dx * dx + dy * dy) {
hideline();
return;
}
} |
||
hideLine(); | ||
return; | ||
} | ||
} | ||
|
||
if(backOff) { | ||
if(backOff * backOff > dx * dx + dy * dy) { | ||
hideLine(); | ||
|
@@ -59,17 +73,27 @@ module.exports = function drawArrowHead(el3, ends, options) { | |
var backOffX = backOff * Math.cos(startRot), | ||
backOffY = backOff * Math.sin(startRot); | ||
|
||
if(doStart) { | ||
start.x -= backOffX; | ||
start.y -= backOffY; | ||
el3.attr({x1: start.x, y1: start.y}); | ||
} | ||
if(doEnd) { | ||
if(doEnd || doNone) { | ||
end.x += backOffX; | ||
end.y += backOffY; | ||
el3.attr({x2: end.x, y2: end.y}); | ||
} | ||
} | ||
|
||
if(startBackOff) { | ||
if(startBackOff * startBackOff > dx * dx + dy * dy) { | ||
hideLine(); | ||
return; | ||
} | ||
var startBackOffX = startBackOff * Math.cos(startRot), | ||
startbackOffY = startBackOff * Math.sin(startRot); | ||
|
||
if(doStart || doNone) { | ||
start.x -= startBackOffX; | ||
start.y -= startbackOffY; | ||
el3.attr({x1: start.x, y1: start.y}); | ||
} | ||
} | ||
} | ||
else if(el.nodeName === 'path') { | ||
var pathlen = el.getTotalLength(), | ||
|
@@ -79,41 +103,35 @@ module.exports = function drawArrowHead(el3, ends, options) { | |
// combine the two | ||
dashArray = ''; | ||
|
||
if(pathlen < backOff) { | ||
if(pathlen < backOff || pathlen < startBackOff || pathlen < backOff + startBackOff) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. similarly, seems like only the last condition matters here? |
||
hideLine(); | ||
return; | ||
} | ||
|
||
if(doStart) { | ||
var start0 = el.getPointAtLength(0); | ||
var dstart = el.getPointAtLength(0.1); | ||
|
||
startRot = Math.atan2(start0.y - dstart.y, start0.x - dstart.x); | ||
start = el.getPointAtLength(Math.min(backOff, pathlen)); | ||
var start0 = el.getPointAtLength(0); | ||
var dstart = el.getPointAtLength(0.1); | ||
|
||
if(backOff) dashArray = '0px,' + backOff + 'px,'; | ||
} | ||
startRot = Math.atan2(start0.y - dstart.y, start0.x - dstart.x); | ||
start = el.getPointAtLength(Math.min(startBackOff, pathlen)); | ||
|
||
if(doEnd) { | ||
var end0 = el.getPointAtLength(pathlen); | ||
var dend = el.getPointAtLength(pathlen - 0.1); | ||
dashArray = '0px,' + startBackOff + 'px,'; | ||
|
||
endRot = Math.atan2(end0.y - dend.y, end0.x - dend.x); | ||
end = el.getPointAtLength(Math.max(0, pathlen - backOff)); | ||
var end0 = el.getPointAtLength(pathlen); | ||
var dend = el.getPointAtLength(pathlen - 0.1); | ||
|
||
if(backOff) { | ||
var shortening = dashArray ? 2 * backOff : backOff; | ||
dashArray += (pathlen - shortening) + 'px,' + pathlen + 'px'; | ||
} | ||
} | ||
else if(dashArray) dashArray += pathlen + 'px'; | ||
endRot = Math.atan2(end0.y - dend.y, end0.x - dend.x); | ||
end = el.getPointAtLength(Math.max(0, pathlen - backOff)); | ||
|
||
var shortening = dashArray ? startBackOff + backOff : backOff; | ||
dashArray += (pathlen - shortening) + 'px,' + pathlen + 'px'; | ||
|
||
if(dashArray) el3.style('stroke-dasharray', dashArray); | ||
el3.style('stroke-dasharray', dashArray); | ||
} | ||
|
||
function hideLine() { el3.style('stroke-dasharray', '0px,100px'); } | ||
|
||
function drawhead(p, rot) { | ||
function drawhead(headStyle, p, rot, scale) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will work, but it's a bit confusing to reuse the names from the outer scope - perhaps rename to something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed names to |
||
if(!headStyle.path) return; | ||
if(headStyle.noRotate) rot = 0; | ||
|
||
|
@@ -132,6 +150,6 @@ module.exports = function drawArrowHead(el3, ends, options) { | |
}); | ||
} | ||
|
||
if(doStart) drawhead(start, startRot); | ||
if(doEnd) drawhead(end, endRot); | ||
if(doStart) drawhead(startHeadStyle, start, startRot, startScale); | ||
if(doEnd) drawhead(headStyle, end, endRot, scale); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,9 +72,13 @@ module.exports = overrideAll({ | |
showarrow: annAtts.showarrow, | ||
arrowcolor: annAtts.arrowcolor, | ||
arrowhead: annAtts.arrowhead, | ||
startarrowhead: annAtts.startarrowhead, | ||
arrowside: annAtts.arrowside, | ||
arrowsize: annAtts.arrowsize, | ||
startarrowsize: annAtts.startarrowsize, | ||
arrowwidth: annAtts.arrowwidth, | ||
standoff: annAtts.standoff, | ||
startstandoff: annAtts.startstandoff, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this really work in 3D or are these attributes there just to make the supply-default function not error out? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it works fine There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great. Would you mind adding an annotations item showing off the new attributes to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
hovertext: annAtts.hovertext, | ||
hoverlabel: annAtts.hoverlabel, | ||
captureevents: annAtts.captureevents, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,8 @@ | |
"arrowcolor":"rgb(166, 28, 0)","borderpad":3,"textangle":50,"x":5,"y":1 | ||
}, | ||
{"text":"","showarrow":true,"borderwidth":1.2,"arrowhead":2,"axref":"x","ayref":"y","x":5,"y":3,"ax":4,"ay":5}, | ||
{"text":"","showarrow":true,"borderwidth":1.2,"arrowhead":3,"startarrowhead":6,"arrowsize":1.5,"startarrowsize":3,"standoff": 7,"startstandoff": 15,"arrowside":"start+end","axref":"x","ayref":"y","x":2,"y":4,"ax":3,"ay":4}, | ||
{"text":"","showarrow":true,"borderwidth":1.2,"startarrowhead":2,"startstandoff": 5,"arrowside":"start","axref":"x","ayref":"y","x":1,"y":5,"ax":2,"ay":4}, | ||
{"text":"","showarrow":true,"borderwidth":1.2,"arrowhead":2,"axref":"x","ayref":"y","x":6,"y":2,"ax":3,"ay":3}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice job here! Maybe we could add an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. Good idea, I will add it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since it depends on your answer here #2164 (comment), I will add it when you confirm expected behaviour. |
||
{ | ||
"text": "arrow ML<br>+standoff", "x": 2, "y": 2, "ax": 20, "ay": 20, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and
should be inside this block as well - as they have no effect w/o start arrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was possibility to use
standoff
witharrowhead: 0
(no arrow) before my changes and I decided to keep this functionality for ‘startstandoff’ -> when we havearrowside: none
, we still can set both properties of standoff and see the result.Please just confirm that it is not expected behaviour and I will apply suggested changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha good point. I think you have it right here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, so
(start)standoff
always needs to be coerced - but doesn'tstartarrowsize
go in here?Also if we have no
'end'
we don't needarrowhead
andarrowsize
do we?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like @apalchys posted and deleted a comment, so maybe he noticed what I'm about to say... (incidentally, if that's the case, let me encourage you to edit comments, using
strikethroughif necessary, rather than deleting them, as it makes the conversation flow clearer)(start)arrowhead
and(start)arrowsize
are not needed logically when we're not showing a head on that end, so that's a warning sign that providing them could lead to bugs. Indeed, I think there is a subtle one: if you choose an arrowhead that has abackoff
(including the defaultarrowhead: 1
!backoff
is how much you need to move the end of the line backward so the arrowhead can point to the right place without the line jutting through it) but you don't show that arrowhead, you'll get an excessive standoff.options.arrowhead || 0
ensures an un-coercedarrowhead
is treated as no arrow, and we may needoptions.arrowsize || 0
(this value probably doesn't matter as long as it's numeric) to make the math well-defined.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I recognized that my answer is wrong right after I submit it. I will commit an update soon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check my commit - 191d5d2
Is it what you expected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect, thanks! Looks like this tweaked one more test image (
gl2d_annotations
) but once that's fixed I think we're ready to go 🎉