8000 Cartesian dropline support by rpaskowitz · Pull Request #1461 · plotly/plotly.js · GitHub
[go: up one dir, main page]

Skip to content

Cartesian dropline support #1461

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

Merged
merged 30 commits into from
Apr 18, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d9fab15
Cartesian dropline support
rpaskowitz Mar 10, 2017
5d39b53
Removed chart config for showDroplines
rpaskowitz Mar 11, 2017
be47533
Add spikecolor, spikethickness, spikedash and spikemode
rpaskowitz Apr 7, 2017
17d815c
Add cartesian spikeline modebar support
rpaskowitz Apr 7, 2017
162068e
Merge branch 'master' into dropline
rpaskowitz Apr 7, 2017
762b54a
Move dashStyle to Drawing
rpaskowitz Apr 7, 2017
d680bd4
Name back to showspikes
rpaskowitz Apr 7, 2017
2433d4c
Lint, test and implementation fixes
rpaskowitz Apr 7, 2017
75da2fe
add spikeline icon
etpinard Apr 7, 2017
7953488
Fix cartesian check and fine-tune marker placement
rpaskowitz Apr 7, 2017
55b17b2
Merge branch 'master' into dropline
etpinard Apr 10, 2017
b9f6ab1
Refactor dropline to spikeline
rpaskowitz Apr 10, 2017
7fe4363
Merge branch 'dropline' of github.com:rpaskowitz/plotly.js into dropline
rpaskowitz Apr 10, 2017
34a1562
Switch from getBoundingClientRect to offsetLeft and offsetTop.
rpaskowitz Apr 10, 2017
8c7ac76
Move spike setup from axis to layout.
rpaskowitz Apr 10, 2017
6e243de
Fix marker positioning and across rendering for top-side x-axes.
rpaskowitz Apr 11, 2017
c036bf7
Merge branch 'master' into dropline
alexcjohnson Apr 13, 2017
8000
08371c2
short-circuit redraw for spike attribute relayouts
alexcjohnson Apr 14, 2017
69dc781
fix manual-hover logic for event emitting
alexcjohnson Apr 14, 2017
37b77fe
don't make spike markers crisp
alexcjohnson Apr 14, 2017
710d2d6
alter logic for where spikes start and end
alexcjohnson Apr 14, 2017
e509fa7
lint
alexcjohnson Apr 14, 2017
75121d2
:hocho: spikemode: 'none'
alexcjohnson Apr 17, 2017
bd11567
make drawing/attributes.dash - and clean up some dashes that don't fi…
alexcjohnson Apr 17, 2017
3a9aa58
short-circuit spike properties when spikes are off
alexcjohnson Apr 17, 2017
052417b
test hover event response to manual and "real" events
alexcjohnson Apr 17, 2017
a3a0a4f
:hocho: fit
alexcjohnson Apr 17, 2017
f7b467e
fix scattermapbox defaults for omitted options
alexcjohnson Apr 18, 2017
7aa4359
lint
alexcjohnson Apr 18, 2017
5925049
:hocho: :hocho:
alexcjohnson Apr 18, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add spikecolor, spikethickness, spikedash and spikemode
Move 'dash' function to lib for re-use
Use dynamic contrast color based on same logic as hovertext contrast text
  • Loading branch information
rpaskowitz committed Apr 7, 2017
commit be4753358a18330c95fb8d1e2d90c48943b27ef5
15 changes: 2 additions & 13 deletions src/components/drawing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,8 @@ drawing.lineGroupStyle = function(s, lw, lc, ld) {

drawing.dashLine = function(s, dash, lineWidth) {
lineWidth = +lineWidth || 0;
var dlw = Math.max(lineWidth, 3);

if(dash === 'solid') dash = '';
else if(dash === 'dot') dash = dlw + 'px,' + dlw + 'px';
else if(dash === 'dash') dash = (3 * dlw) + 'px,' + (3 * dlw) + 'px';
else if(dash === 'longdash') dash = (5 * dlw) + 'px,' + (5 * dlw) + 'px';
else if(dash === 'dashdot') {
dash = (3 * dlw) + 'px,' + dlw + 'px,' + dlw + 'px,' + dlw + 'px';
}
else if(dash === 'longdashdot') {
dash = (5 * dlw) + 'px,' + (2 * dlw) + 'px,' + dlw + 'px,' + (2 * dlw) + 'px';
}
// otherwise user wrote the dasharray themselves - leave it be

dash = Lib.dash(dash, lineWidth);

s.style({
'stroke-dasharray': dash,
Expand Down
28 changes: 28 additions & 0 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -636,3 +636,31 @@ lib.numSeparate = function(value, separators, separatethousands) {

return x1 + x2;
};

/**
* Accepts a named dash style or stroke-dasharray string
* and returns a dasharray representing the named type.
*
* @param {string} dash named dash format, or dasharray
* @param {number} lineWidth width of the line, used to scale the dashes
*
* @returns {string} SVG stroke-dasharray formatted string
*/
lib.dash = function(dash, lineWidth) {
lineWidth = +lineWidth || 1;
var dlw = Math.max(lineWidth, 3);

if(dash === 'solid') dash = '';
else if(dash === 'dot') dash = dlw + 'px,' + dlw + 'px';
else if(dash === 'dash') dash = (3 * dlw) + 'px,' + (3 * dlw) + 'px';
else if(dash === 'longdash') dash = (5 * dlw) + 'px,' + (5 * dlw) + 'px';
else if(dash === 'dashdot') {
dash = (3 * dlw) + 'px,' + dlw + 'px,' + dlw + 'px,' + dlw + 'px';
}
else if(dash === 'longdashdot') {
dash = (5 * dlw) + 'px,' + (2 * dlw) + 'px,' + dlw + 'px,' + (2 * dlw) + 'px';
}
// otherwise user wrote the dasharray themselves - leave it be

return dash;
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of breaking this out - but lets keep it in drawing, it fits there thematically and lib is a bit overloaded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming in next commit.

4 changes: 4 additions & 0 deletions src/plots/cartesian/axis_defaults.js
8000
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
containerOut.cleanRange();

coerce('showspikes');
coerce('spikecolor');
coerce('spikethickness');
coerce('spikedash');
coerce('spikemode');

handleTickValueDefaults(containerIn, containerOut, coerce, axType);
handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options);
Expand Down
128 changes: 75 additions & 53 deletions src/plots/cartesian/graph_interact.js
Original file line number Diff line number Diff line change
Expand Up @@ -857,73 +857,95 @@ function createDroplines(hoverData, opts) {
yAnchoredBase = yEdge - outerBBox.top,
xBase = c0.ya.anchor === 'free' ? xFreeBase : xAnchoredBase,
yBase = c0.xa.anchor === 'free' ? yFreeBase : yAnchoredBase,
color = c0.color;
xColor = c0.xa.spikecolor ? c0.xa.spikecolor : c0.color,
yColor = c0.ya.spikecolor ? c0.ya.spikecolor : c0.color,
xContrastColor = tinycolor(xColor).getBrightness() > 128 ?
'#000' : Color.background,
yContrastColor = tinycolor(yColor).getBrightness() > 128 ?
'#000' : Color.background,
xThickness = c0.xa.spikethickness,
yThickness = c0.ya.spikethickness,
xDash = Lib.dash(c0.xa.spikedash, xThickness),
yDash = Lib.dash(c0.xa.spikedash, yThickness),
xMarker = c0.xa.spikemode.indexOf('marker') !== -1,
yMarker = c0.ya.spikemode.indexOf('marker') !== -1,
xSpikeLine = c0.xa.spikemode.indexOf('toaxis') !== -1 || c0.xa.spikemode.indexOf('across') !== -1,
ySpikeLine = c0.ya.spikemode.indexOf('toaxis') !== -1 || c0.ya.spikemode.indexOf('across') !== -1,
xEndSpike = c0.xa.spikemode.indexOf('across') !== -1 ? xBase + xLength : xPoint,
yEndSpike = c0.ya.spikemode.indexOf('across') !== -1 ? yBase - yLength : yPoint;

// Remove old dropline items
container.selectAll('line.dropline').remove();
container.selectAll('circle.dropline').remove();


if(c0.ya.showspikes) {
// Background horizontal Line (to y-axis)
container.append('line')
.attr('x1', xBase)
.attr('x2', xPoint)
.attr('y1', yPoint)
.attr('y2', yPoint)
.attr('stroke-width', 5)
.attr('stroke', '#fff')
.attr('class', 'dropline');

// Foreground horizontal line (to y-axis)
container.append('line')
.attr('x1', xBase)
.attr('x2', xPoint)
.attr('y1', yPoint)
.attr('y2', yPoint)
.attr('stroke-width', 3)
.attr('stroke', color)
.attr('stroke-dasharray', '5,5')
.attr('class', 'dropline');

if(ySpikeLine) {
// Background horizontal Line (to y-axis)
container.append('line')
.attr('x1', xBase)
.attr('x2', xEndSpike)
.attr('y1', yPoint)
.attr('y2', yPoint)
.attr('stroke-width', yThickness + 2)
.attr('stroke', yContrastColor)
.attr('class', 'dropline');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.attr can take an object ie .attr({x1: xBase, x2: xEndSpike ... })

also it's a bit nicer to use .classed('dropline', true) instead of .attr('class', 'dropline'), just because it makes things easier to extend later, if it turns out we need multiple classes or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both coming in next commit.


// Foreground horizontal line (to y-axis)
container.append('line')
.attr('x1', xBase)
.attr('x2', xEndSpike)
.attr('y1', yPoint)
.attr('y2', yPoint)
.attr('stroke-width', yThickness)
.attr('stroke', yColor)
.attr('stroke-dasharray', yDash)
.attr('class', 'dropline');
}
// Y axis marker
container.append('circle')
.attr('cx', xBase)
.attr('cy', yPoint)
.attr('r', 3)
.attr('fill', color)
.attr('class', 'dropline');
if(yMarker) {
container.append('circle')
.attr('cx', xAnchoredBase)
.attr('cy', yPoint)
.attr('r', yThickness)
.attr('fill', yColor)
.attr('class', 'dropline');
}
}

if(c0.xa.showspikes) {
if(xSpikeLine) {
// Background vertical line (to x-axis)
container.append('line')
.attr('x1', xPoint)
.attr('x2', xPoint)
.attr('y1', yPoint)
.attr('y2', yBase)
.attr('stroke-width', 5)
.attr('stroke', '#fff')
.attr('class', 'dropline');

// Foreground vertical line (to x-axis)
container.append('line')
.attr('x1', xPoint)
.attr('x2', xPoint)
.attr('y1', yPoint)
.attr('y2', yBase)
.attr('stroke-width', 3)
.attr('stroke', color)
.attr('stroke-dasharray', '5,5')
.attr('class', 'dropline');
container.append('line')
.attr('x1', xPoint)
.attr('x2', xPoint)
.attr('y1', yEndSpike)
.attr('y2', yBase)
.attr('stroke-width', xThickness + 2)
.attr('stroke', xContrastColor)
.attr('class', 'dropline');

// Foreground vertical line (to x-axis)
container.append('line')
.attr('x1', xPoint)
.attr('x2', xPoint)
.attr('y1', yEndSpike)
.attr('y2', yBase)
.attr('stroke-width', xThickness)
.attr('stroke', xColor)
.attr('stroke-dasharray', xDash)
.attr('class', 'dropline');
}

// X axis marker
container.append('circle')
.attr('cx', xPoint)
.attr('cy', yBase)
.attr('r', 3)
.attr('fill', color)
.attr('class', 'dropline');
if(xMarker) {
container.append('circle')
.attr('cx', xPoint)
.attr('cy', yAnchoredBase)
.attr('r', xThickness)
.attr('fill', xColor)
.attr('class', 'dropline');
}
}
}

Expand Down
46 changes: 45 additions & 1 deletion src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,57 @@ module.exports = {
},
showspikes: {
valType: 'boolean',
dflt: false,
dflt: true,
role: 'style',
description: [
'Determines whether or not spikes (aka droplines) are drawn for this axis.',
'Note: This only takes affect when hovermode = closest'
].join(' ')
},
spikecolor: {
valType: 'color',
dflt: null,
role: 'style',
description: 'Sets the spike color. If undefined, will use the series color'
},
spikethickness: {
valType: 'number',
dflt: 3,
role: 'style',
description: 'Sets the width (in px) of the zero line.'
},
spikedash: {
valType: 'string',
// string type usually doesn't take values... this one should really be
// a special type or at least a special coercion function, from the GUI
// you only get these values but elsewhere the user can supply a list of
// dash lengths in px, and it will be honored
values: ['solid', 'dot', 'dash', 'longdash', 'dashdot', 'longdashdot'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non- ⛔ , but It would be nice to reuse the list in traces/scatter/attributes.js

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cleaned up a bunch of things in bd11567
@etpinard can you take a look at this? I tried to turn it into a regular enumerated attribute in cases where the manual dasharray isn't allowed (gl) and removed it where it's not supported at all (mapbox). I don't think this syntax is tested anywhere though... I suppose in principle we should provide mocks that use it for all the places it's used in SVG.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Lear C281 n more.

Looking good 👍

dflt: 'dash',
role: 'style',
description: [
'Sets the style of the lines. Set to a dash string type',
'or a dash length in px.'
].join(' ')
},
spikemode: {
valType: 'flaglist',
flags: ['toaxis', 'across', 'marker'],
extras: ['none'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't spikemode: 'none' the same as showspikes: false?

role: 'style',
dflt: 'toaxis',
description: [
'Determines the drawing mode for the spike line',
'If *toaxis*, the line is drawn from the data point to the axis the ',
'series is plotted on.',

'If *across*, the line is drawn across the entire plot area, and',
'supercedes *toaxis*.',

'If *marker*, then a marker dot is drawn on the axis the series is',
'plotted on'
].join(' ')
},
tickfont: extendFlat({}, fontAttrs, {
description: 'Sets the tick font.'
}),
Expand Down
0