'use strict'; var d3 = require('@plotly/d3'); var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); var Lib = require('../../lib'); var Registry = require('../../registry'); var resizeText = require('./uniform_text').resizeText; var attributes = require('./attributes'); var attributeTextFont = attributes.textfont; var attributeInsideTextFont = attributes.insidetextfont; var attributeOutsideTextFont = attributes.outsidetextfont; var helpers = require('./helpers'); function style(gd) { var s = d3.select(gd).selectAll('g[class^="barlayer"]').selectAll('g.trace'); resizeText(gd, s, 'bar'); var barcount = s.size(); var fullLayout = gd._fullLayout; // trace styling s.style('opacity', function(d) { return d[0].trace.opacity; }) // for gapless (either stacked or neighboring grouped) bars use // crispEdges to turn off antialiasing so an artificial gap // isn't introduced. .each(function(d) { if((fullLayout.barmode === 'stack' && barcount > 1) || (fullLayout.bargap === 0 && fullLayout.bargroupgap === 0 && !d[0].trace.marker.line.width)) { d3.select(this).attr('shape-rendering', 'crispEdges'); } }); s.selectAll('g.points').each(function(d) { var sel = d3.select(this); var trace = d[0].trace; stylePoints(sel, trace, gd); }); Registry.getComponentMethod('errorbars', 'style')(s); } function stylePoints(sel, trace, gd) { Drawing.pointStyle(sel.selectAll('path'), trace, gd); styleTextPoints(sel, trace, gd); } function styleTextPoints(sel, trace, gd) { sel.selectAll('text').each(function(d) { var tx = d3.select(this); var font = Lib.ensureUniformFontSize(gd, determineFont(tx, d, trace, gd)); Drawing.font(tx, font); }); } function styleOnSelect(gd, cd, sel) { var trace = cd[0].trace; if(trace.selectedpoints) { stylePointsInSelectionMode(sel, trace, gd); } else { stylePoints(sel, trace, gd); Registry.getComponentMethod('errorbars', 'style')(sel); } } function stylePointsInSelectionMode(s, trace, gd) { Drawing.selectedPointStyle(s.selectAll('path'), trace); styleTextInSelectionMode(s.selectAll('text'), trace, gd); } function styleTextInSelectionMode(txs, trace, gd) { txs.each(function(d) { var tx = d3.select(this); var font; if(d.selected) { font = Lib.ensureUniformFontSize(gd, determineFont(tx, d, trace, gd)); var selectedFontColor = trace.selected.textfont && trace.selected.textfont.color; if(selectedFontColor) { font.color = selectedFontColor; } Drawing.font(tx, font); } else { Drawing.selectedTextStyle(tx, trace); } }); } function determineFont(tx, d, trace, gd) { var layoutFont = gd._fullLayout.font; var textFont = trace.textfont; if(tx.classed('bartext-inside')) { var barColor = getBarColor(d, trace); textFont = getInsideTextFont(trace, d.i, layoutFont, barColor); } else if(tx.classed('bartext-outside')) { textFont = getOutsideTextFont(trace, d.i, layoutFont); } return textFont; } function getTextFont(trace, index, defaultValue) { return getFontValue( attributeTextFont, trace.textfont, index, defaultValue); } function getInsideTextFont(trace, index, layoutFont, barColor) { var defaultFont = getTextFont(trace, index, layoutFont); var wouldFallBackToLayoutFont = (trace._input.textfont === undefined || trace._input.textfont.color === undefined) || (Array.isArray(trace.textfont.color) && trace.textfont.color[index] === undefined); if(wouldFallBackToLayoutFont) { defaultFont = { color: Color.contrast(barColor), family: defaultFont.family, size: defaultFont.size, weight: defaultFont.weight, style: defaultFont.style, variant: defaultFont.variant, textcase: defaultFont.textcase, lineposition: defaultFont.lineposition, shadow: defaultFont.shadow, }; } return getFontValue( attributeInsideTextFont, trace.insidetextfont, index, defaultFont); } function getOutsideTextFont(trace, index, layoutFont) { var defaultFont = getTextFont(trace, index, layoutFont); return getFontValue( attributeOutsideTextFont, trace.outsidetextfont, index, defaultFont); } function getFontValue(attributeDefinition, attributeValue, index, defaultValue) { attributeValue = attributeValue || {}; var familyValue = helpers.getValue(attributeValue.family, index); var sizeValue = helpers.getValue(attributeValue.size, index); var colorValue = helpers.getValue(attributeValue.color, index); var weightValue = helpers.getValue(attributeValue.weight, index); var styleValue = helpers.getValue(attributeValue.style, index); var variantValue = helpers.getValue(attributeValue.variant, index); var textcaseValue = helpers.getValue(attributeValue.textcase, index); var linepositionValue = helpers.getValue(attributeValue.lineposition, index); var shadowValue = helpers.getValue(attributeValue.shadow, index); return { family: helpers.coerceString( attributeDefinition.family, familyValue, defaultValue.family), size: helpers.coerceNumber( attributeDefinition.size, sizeValue, defaultValue.size), color: helpers.coerceColor( attributeDefinition.color, colorValue, defaultValue.color), weight: helpers.coerceString( attributeDefinition.weight, weightValue, defaultValue.weight), style: helpers.coerceString( attributeDefinition.style, styleValue, defaultValue.style), variant: helpers.coerceString( attributeDefinition.variant, variantValue, defaultValue.variant), textcase: helpers.coerceString( attributeDefinition.variant, textcaseValue, defaultValue.textcase), lineposition: helpers.coerceString( attributeDefinition.variant, linepositionValue, defaultValue.lineposition), shadow: helpers.coerceString( attributeDefinition.variant, shadowValue, defaultValue.shadow), }; } function getBarColor(cd, trace) { if(trace.type === 'waterfall') { return trace[cd.dir].marker.color; } return cd.mcc || cd.mc || trace.marker.color; } module.exports = { style: style, styleTextPoints: styleTextPoints, styleOnSelect: styleOnSelect, getInsideTextFont: getInsideTextFont, getOutsideTextFont: getOutsideTextFont, getBarColor: getBarColor, resizeText: resizeText };