Skip to content

modeBar styling #3068

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 24 commits into from
Oct 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1b7c126
add config option modeBarStyle, update logo
antoinerg Oct 2, 2018
947eaf2
fix margins and alignments of modeBar buttons
antoinerg Oct 2, 2018
212612b
specify default style in modebar tests
antoinerg Oct 2, 2018
3795223
increase sizeo of plot.ly logo
antoinerg Oct 2, 2018
e870e34
fix rendering of logo in IE
antoinerg Oct 2, 2018
a4d3948
fix no-multiple-empty-lines
antoinerg Oct 2, 2018
61d1c7b
slurp entire SVG, uses DOMParser instead of innerHTML
antoinerg Oct 2, 2018
1d4ac7e
add build artefact for icons
antoinerg Oct 2, 2018
ff9d801
move plot.ly logo on top for vertical modebar
antoinerg Oct 3, 2018
397a6de
move modeBarStyle from config to layout options
antoinerg Oct 3, 2018
baeb1bc
update modebar tests with modeBarStyle in layout instead of config
antoinerg Oct 3, 2018
254f158
set proper editType on layout attribute modeBar
antoinerg Oct 3, 2018
f9e8777
modeBarStyle managed in css, new layout attribute activeIconColor
antoinerg Oct 3, 2018
fc47c72
remove 🐫 in modebar layout attributes
antoinerg Oct 3, 2018
0046f12
more robust test for modeBar.destroy
antoinerg Oct 4, 2018
b7c2355
place tooltips on the left of vertical modebars
antoinerg Oct 4, 2018
31d6fb2
in modebar plotly logo has same position in both orientations (v|h)
antoinerg Oct 4, 2018
97f25e2
fix to change modebar style on relayout
antoinerg Oct 4, 2018
dc7877b
trim whitespace in plotly logo's svg
antoinerg Oct 4, 2018
f5cc0e9
🔒 down modebar styling option
antoinerg Oct 4, 2018
452f9bc
by default modebar colors contrasts with paper_bgcolor
antoinerg Oct 5, 2018
266d63b
fix default modebar colors
antoinerg Oct 5, 2018
ff3f9f6
improve default modebar colors
antoinerg Oct 5, 2018
db9edd1
improve default modebar color
antoinerg Oct 5, 2018
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
14 changes: 7 additions & 7 deletions build/plotcss.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ var rules = {
"X .cursor-n-resize": "cursor:n-resize;",
"X .cursor-ne-resize": "cursor:ne-resize;",
"X .cursor-grab": "cursor:-webkit-grab;cursor:grab;",
"X .modebar": "position:absolute;top:2px;right:2px;z-index:1001;background:rgba(255,255,255,0.7);",
"X .modebar": "position:absolute;top:2px;right:2px;z-index:1001;",
"X .modebar--hover": "opacity:0;-webkit-transition:opacity 0.3s ease 0s;-moz-transition:opacity 0.3s ease 0s;-ms-transition:opacity 0.3s ease 0s;-o-transition:opacity 0.3s ease 0s;transition:opacity 0.3s ease 0s;",
"X:hover .modebar--hover": "opacity:1;",
"X .modebar-group": "float:left;display:inline-block;box-sizing:border-box;margin-left:8px;position:relative;vertical-align:middle;white-space:nowrap;",
"X .modebar-group:first-child": "margin-left:0px;",
"X .modebar-btn": "position:relative;font-size:16px;padding:3px 4px;cursor:pointer;line-height:normal;box-sizing:border-box;",
"X .modebar-btn": "position:relative;font-size:16px;padding:3px 4px;height:22px;cursor:pointer;line-height:normal;box-sizing:border-box;",
"X .modebar-btn svg": "position:relative;top:2px;",
"X .modebar-btn path": "fill:rgba(0,31,95,0.3);",
"X .modebar-btn.active path,X .modebar-btn:hover path": "fill:rgba(0,22,72,0.5);",
"X .modebar-btn.modebar-btn--logo": "padding:3px 1px;",
"X .modebar-btn.modebar-btn--logo path": "fill:#447adb !important;",
"X .modebar.vertical": "top:-1px;",
"X .modebar.vertical .modebar-group": "display:block;float:none;margin-left:0px;margin-bottom:8px;",
"X .modebar.vertical .modebar-group .modebar-btn": "display:block;text-align:center;",
"X [data-title]:before,X [data-title]:after": "position:absolute;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);-ms-transform:translate3d(0, 0, 0);-o-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);display:none;opacity:0;z-index:1001;pointer-events:none;top:110%;right:50%;",
"X [data-title]:hover:before,X [data-title]:hover:after": "display:block;opacity:1;",
"X [data-title]:before": "content:'';position:absolute;background:transparent;border:6px solid transparent;z-index:1002;margin-top:-12px;border-bottom-color:#69738a;margin-right:-6px;",
"X [data-title]:after": "content:attr(data-title);background:#69738a;color:white;padding:8px 10px;font-size:12px;line-height:12px;white-space:nowrap;margin-right:-18px;border-radius:2px;",
"X .vertical [data-title]:before,X .vertical [data-title]:after": "top:0%;right:200%;",
"X .vertical [data-title]:before": "border:6px solid transparent;border-left-color:#69738a;margin-top:8px;margin-right:-30px;",
"X .select-outline": "fill:none;stroke-width:1;shape-rendering:crispEdges;",
"X .select-outline-1": "stroke:white;",
"X .select-outline-2": "stroke:black;stroke-dasharray:2px 2px;",
Expand Down
8 changes: 6 additions & 2 deletions build/ploticon.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ module.exports = {
'transform': 'matrix(1 0 0 -1 0 850)'
},
'zoom_plus': {
'width': 1000,
'width': 875,
'height': 1000,
'path': 'm1 787l0-875 875 0 0 875-875 0z m687-500l-187 0 0-187-125 0 0 187-188 0 0 125 188 0 0 187 125 0 0-187 187 0 0-125z',
'transform': 'matrix(1 0 0 -1 0 850)'
},
'zoom_minus': {
'width': 1000,
'width': 875,
'height': 1000,
'path': 'm0 788l0-876 875 0 0 876-875 0z m688-500l-500 0 0 125 500 0 0-125z',
'transform': 'matrix(1 0 0 -1 0 850)'
Expand Down Expand Up @@ -120,5 +120,9 @@ module.exports = {
'height': 1000,
'path': 'M512 409c0-57-46-104-103-104-57 0-104 47-104 104 0 57 47 103 104 103 57 0 103-46 103-103z m-327-39l92 0 0 92-92 0z m-185 0l92 0 0 92-92 0z m370-186l92 0 0 93-92 0z m0-184l92 0 0 92-92 0z',
'transform': 'matrix(1.5 0 0 -1.5 0 850)'
},
'newplotlylogo': {
'name': 'newplotlylogo',
'svg': '<svg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 132 132\'><defs><style>.cls-1 {fill: #119dff;} .cls-2 {fill: #25fefd;} .cls-3 {fill: #fff;}</style></defs><title>plotly-logomark</title><g id=\'symbol\'><rect class=\'cls-1\' width=\'132\' height=\'132\' rx=\'6\' ry=\'6\'/><circle class=\'cls-2\' cx=\'78\' cy=\'54\' r=\'6\'/><circle class=\'cls-2\' cx=\'102\' cy=\'30\' r=\'6\'/><circle class=\'cls-2\' cx=\'78\' cy=\'30\' r=\'6\'/><circle class=\'cls-2\' cx=\'54\' cy=\'30\' r=\'6\'/><circle class=\'cls-2\' cx=\'30\' cy=\'30\' r=\'6\'/><circle class=\'cls-2\' cx=\'30\' cy=\'54\' r=\'6\'/><path class=\'cls-3\' d=\'M30,72a6,6,0,0,0-6,6v24a6,6,0,0,0,12,0V78A6,6,0,0,0,30,72Z\'/><path class=\'cls-3\' d=\'M78,72a6,6,0,0,0-6,6v24a6,6,0,0,0,12,0V78A6,6,0,0,0,78,72Z\'/><path class=\'cls-3\' d=\'M54,48a6,6,0,0,0-6,6v48a6,6,0,0,0,12,0V54A6,6,0,0,0,54,48Z\'/><path class=\'cls-3\' d=\'M102,48a6,6,0,0,0-6,6v48a6,6,0,0,0,12,0V54A6,6,0,0,0,102,48Z\'/></g></svg>'
}
};
65 changes: 49 additions & 16 deletions src/components/modebar/modebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var isNumeric = require('fast-isnumeric');

var Lib = require('../../lib');
var Icons = require('../../../build/ploticon');

var Parser = new DOMParser();

/**
* UI controller for interactive plots
Expand Down Expand Up @@ -45,13 +45,29 @@ var proto = ModeBar.prototype;
proto.update = function(graphInfo, buttons) {
this.graphInfo = graphInfo;

var context = this.graphInfo._context;
var context = this.graphInfo._context,
fullLayout = this.graphInfo._fullLayout,
modeBarId = 'modebar-' + fullLayout._uid;

this.element.setAttribute('id', modeBarId);
this._uid = modeBarId;

if(context.displayModeBar === 'hover') {
this.element.className = 'modebar modebar--hover';
}
else this.element.className = 'modebar';

if(fullLayout.modebar.orientation === 'v') {
this.element.className += ' vertical';
buttons = buttons.reverse();
}

Lib.deleteRelatedStyleRule(modeBarId);
Lib.addRelatedStyleRule(modeBarId, '#' + modeBarId, 'background-color: ' + fullLayout.modebar.bgcolor);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have to use CSS here? Could we instead add mouseover / mouseout handlers to the modebar buttons, similar to how we handle updatemenu buttons:

header.on('mouseover', function() {
header.call(styleOnMouseOver);
});

function styleOnMouseOver(item) {
item.select('rect.' + constants.itemRectClassName)
.call(Color.fill, constants.hoverColor);
}

that way we wouldn't have to hijack the <style> dynamically.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could use mouseover / mouseout for hover but I wasn't sure how to handle the active state. Since we already add/remove class name active to the icons, I thought it made sense to just style those in CSS. @alexcjohnson wasn't against the idea but we can consider another strategy.

Copy link
Contributor

Choose a reason for hiding this comment

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

Since we already add/remove class name active to the icons

Right, getting "active" to work would require some work. The modebar button click handlers would need to update their style attribute instead of appending/removing the "active" class name.

Consider my comment non-blocking.

Lib.addRelatedStyleRule(modeBarId, '#' + modeBarId + ' .modebar-btn .icon path', 'fill: ' + fullLayout.modebar.color);
Lib.addRelatedStyleRule(modeBarId, '#' + modeBarId + ' .modebar-btn:hover .icon path', 'fill: ' + fullLayout.modebar.activecolor);
Lib.addRelatedStyleRule(modeBarId, '#' + modeBarId + ' .modebar-btn.active .icon path', 'fill: ' + fullLayout.modebar.activecolor);
Copy link
Contributor

Choose a reason for hiding this comment

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

These don't appear to update properly on relayout e.g. Plotly.relayout(gd, 'modebar.bgcolor', 'blue')

Copy link
Contributor

Choose a reason for hiding this comment

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

peek 2018-10-04 13-54

moreover, modebar.color doesn't seem to work on some icons.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me investigate relayout!

As for the screen capture: the gray icons are the ones that are currently active (gray being the default activecolor). It does look like a bug the first time you try it but it's not. Maybe I should implement what @nicolaskruchten suggested over here: #3063 (comment). This shouldn't be a problem in Dash however since they usually explicitly style everything.

Copy link
Contributor

Choose a reason for hiding this comment

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

the gray icons are the ones that are currently active (gray being the default activecolor).

Ha I see. My mistake!

Copy link
Contributor Author

@antoinerg antoinerg Oct 4, 2018

Choose a reason for hiding this comment

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

Commit 97f25e2 fixes the issue with relayout.

The new style rules were just appended to the same style element and would have less priority than previous rules. This is fixed by starting with a fresh style element each time.

Copy link
Contributor

Choose a reason for hiding this comment

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

Cool. Let's 🔒 this down in a jasmine test though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In commit f5cc0e9, we test each new layout attributes and make sure they behave properly when using relayout!

Copy link
Contributor

Choose a reason for hiding this comment

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

Great tests. Thanks 🎉


// if buttons or logo have changed, redraw modebar interior
var needsNewButtons = !this.hasButtons(buttons);
var needsNewLogo = (this.hasLogo !== context.displaylogo);
Expand All @@ -65,7 +81,12 @@ proto.update = function(graphInfo, buttons) {
this.updateButtons(buttons);

if(context.displaylogo) {
this.element.appendChild(this.getLogo());
if(fullLayout.modebar.orientation === 'v') {
this.element.prepend(this.getLogo());
} else {
this.element.appendChild(this.getLogo());
}

this.hasLogo = true;
}
}
Expand Down Expand Up @@ -173,31 +194,42 @@ proto.createButton = function(config) {
* @Param {object} thisIcon
* @Param {number} thisIcon.width
* @Param {string} thisIcon.path
* @Param {string} thisIcon.color
* @Return {HTMLelement}
*/
proto.createIcon = function(thisIcon) {
var iconHeight = isNumeric(thisIcon.height) ?
Number(thisIcon.height) :
thisIcon.ascent - thisIcon.descent,
svgNS = 'http://www.w3.org/2000/svg',
icon = document.createElementNS(svgNS, 'svg'),
path = document.createElementNS(svgNS, 'path');
icon;

icon.setAttribute('height', '1em');
icon.setAttribute('width', (thisIcon.width / iconHeight) + 'em');
icon.setAttribute('viewBox', [0, 0, thisIcon.width, iconHeight].join(' '));
if(thisIcon.path) {
icon = document.createElementNS(svgNS, 'svg');
icon.setAttribute('viewBox', [0, 0, thisIcon.width, iconHeight].join(' '));
icon.setAttribute('class', 'icon');

var path = document.createElementNS(svgNS, 'path');
path.setAttribute('d', thisIcon.path);

path.setAttribute('d', thisIcon.path);
if(thisIcon.transform) {
path.setAttribute('transform', thisIcon.transform);
}
else if(thisIcon.ascent !== undefined) {
// Legacy icon transform calculation
path.setAttribute('transform', 'matrix(1 0 0 -1 0 ' + thisIcon.ascent + ')');
}

if(thisIcon.transform) {
path.setAttribute('transform', thisIcon.transform);
icon.appendChild(path);
}
else if(thisIcon.ascent !== undefined) {
// Legacy icon transform calculation
path.setAttribute('transform', 'matrix(1 0 0 -1 0 ' + thisIcon.ascent + ')');

if(thisIcon.svg) {
var svgDoc = Parser.parseFromString(thisIcon.svg, 'application/xml');
icon = svgDoc.childNodes[0];
}

icon.appendChild(path);
icon.setAttribute('height', '1em');
icon.setAttribute('width', '1em');

return icon;
};
Expand Down Expand Up @@ -272,7 +304,7 @@ proto.getLogo = function() {
a.setAttribute('data-title', Lib._(this.graphInfo, 'Produced with Plotly'));
a.className = 'modebar-btn plotlyjsicon modebar-btn--logo';

a.appendChild(this.createIcon(Icons.plotlylogo));
a.appendChild(this.createIcon(Icons.newplotlylogo));

group.appendChild(a);
return group;
Expand All @@ -288,6 +320,7 @@ proto.removeAllButtons = function() {

proto.destroy = function() {
Lib.removeElement(this.container.querySelector('.modebar'));
Lib.deleteRelatedStyleRule(this._uid);
};

function createModeBar(gd, buttons) {
Expand Down
28 changes: 13 additions & 15 deletions src/css/_modebar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
top: 2px;
right: 2px;
z-index: 1001;
background: rgba(255,255,255,0.7);
}

.modebar--hover {
Expand All @@ -23,17 +22,13 @@
position: relative;
vertical-align: middle;
white-space: nowrap;

&:first-child {
margin-left: 0px;
}
}


.modebar-btn {
position: relative;
font-size: 16px;
padding: 3px 4px;
height: 22px;
/* display: inline-block; including this breaks 3d interaction in .embed mode. Chrome bug? */
cursor: pointer;
line-height: normal;
Expand All @@ -44,19 +39,22 @@
top: 2px;
}

path {
fill: rgba(0,31,95,0.3);
}
&.modebar-btn--logo {

&.active path, &:hover path {
fill: rgba(0,22,72,0.5);
}
}

&.modebar-btn--logo {
padding: 3px 1px;
.modebar.vertical {
top: -1px;
.modebar-group {
display: block;
float: none;
margin-left: 0px;
margin-bottom: 8px;

path {
fill: $color-brand-primary !important;
.modebar-btn {
display: block;
text-align: center;
}
}
}
17 changes: 16 additions & 1 deletion src/css/_tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ $successColor: hsl(121, 32%, 40%) !default;
opacity: 1;
}

// Arrow
// Top arrow
&:before {
content: '';
position: absolute;
Expand All @@ -78,3 +78,18 @@ $successColor: hsl(121, 32%, 40%) !default;
border-radius: 2px;
}
}

.vertical [data-title] {
&:before, &:after {
top: 0%;
right: 200%;
}

// Right arrow
&:before {
border: $arrowBorderWidth solid transparent;
border-left-color: $defaultColor;
margin-top: $verticalPadding;
margin-right: -1 * ($arrowOffsetX + 2 * $arrowBorderWidth);
}
}
24 changes: 22 additions & 2 deletions src/fonts/ploticon/ploticon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 23 additions & 4 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -679,14 +679,24 @@ lib.removeElement = function(el) {
* by all calls to this function
*/
lib.addStyleRule = function(selector, styleString) {
if(!lib.styleSheet) {
var style = document.createElement('style');
lib.addRelatedStyleRule('global', selector, styleString);
};

/**
* for dynamically adding style rules
* to a stylesheet uniquely identified by a uid
*/
lib.addRelatedStyleRule = function(uid, selector, styleString) {
var id = 'plotly.js-style-' + uid,
style = document.getElementById(id);
if(!style) {
style = document.createElement('style');
style.setAttribute('id', id);
// WebKit hack :(
style.appendChild(document.createTextNode(''));
document.head.appendChild(style);
lib.styleSheet = style.sheet;
}
var styleSheet = lib.styleSheet;
var styleSheet = style.sheet;

if(styleSheet.insertRule) {
styleSheet.insertRule(selector + '{' + styleString + '}', 0);
Expand All @@ -697,6 +707,15 @@ lib.addStyleRule = function(selector, styleString) {
else lib.warn('addStyleRule failed');
};

/**
* to remove from the page a stylesheet identified by a given uid
*/
lib.deleteRelatedStyleRule = function(uid) {
var id = 'plotly.js-style-' + uid,
style = document.getElementById(id);
if(style) style.remove();
};

lib.isIE = function() {
return typeof window.navigator.msSaveBlob !== 'undefined';
};
Expand Down
29 changes: 29 additions & 0 deletions src/plots/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,5 +224,34 @@ module.exports = {
'or a logo image, for example. To omit one of these items on the plot,',
'make an item with matching `templateitemname` and `visible: false`.'
].join(' ')
},
modebar: {
orientation: {
valType: 'enumerated',
values: ['v', 'h'],
dflt: 'h',
role: 'info',
editType: 'modebar',
description: 'Sets the orientation of the modebar.'
},
bgcolor: {
valType: 'color',
role: 'style',
editType: 'modebar',
description: 'Sets the background color of the modebar.'
},
color: {
valType: 'color',
role: 'style',
editType: 'modebar',
description: 'Sets the color of the icons in the modebar.'
},
activecolor: {
valType: 'color',
role: 'style',
editType: 'modebar',
description: 'Sets the color of the active or hovered on icons in the modebar.'
},
editType: 'modebar'
}
};
6 changes: 6 additions & 0 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,12 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) {

coerce('datarevision');

coerce('modebar.orientation');
coerce('modebar.bgcolor', Color.addOpacity(layoutOut.paper_bgcolor, 0.5));
var modebarDefaultColor = Color.contrast(Color.rgb(layoutOut.modebar.bgcolor));
coerce('modebar.color', Color.addOpacity(modebarDefaultColor, 0.3));
coerce('modebar.activecolor', Color.addOpacity(modebarDefaultColor, 0.7));

Registry.getComponentMethod(
'calendars',
'handleDefaults'
Expand Down
Loading