plotly.js
Version:
The open source javascript graphing library that powers plotly
237 lines (194 loc) • 8.49 kB
JavaScript
/**
* Copyright 2012-2020, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var Lib = require('../../lib');
var Color = require('../../components/color');
var Template = require('../../plot_api/plot_template');
var handleSubplotDefaults = require('../subplot_defaults');
var getSubplotData = require('../get_data').getSubplotData;
var handleTickValueDefaults = require('../cartesian/tick_value_defaults');
var handleTickMarkDefaults = require('../cartesian/tick_mark_defaults');
var handleTickLabelDefaults = require('../cartesian/tick_label_defaults');
var handleCategoryOrderDefaults = require('../cartesian/category_order_defaults');
var handleLineGridDefaults = require('../cartesian/line_grid_defaults');
var autoType = require('../cartesian/axis_autotype');
var layoutAttributes = require('./layout_attributes');
var setConvert = require('./set_convert');
var constants = require('./constants');
var axisNames = constants.axisNames;
function handleDefaults(contIn, contOut, coerce, opts) {
var bgColor = coerce('bgcolor');
opts.bgColor = Color.combine(bgColor, opts.paper_bgcolor);
var sector = coerce('sector');
coerce('hole');
// could optimize, subplotData is not always needed!
var subplotData = getSubplotData(opts.fullData, constants.name, opts.id);
var layoutOut = opts.layoutOut;
var axName;
function coerceAxis(attr, dflt) {
return coerce(axName + '.' + attr, dflt);
}
for(var i = 0; i < axisNames.length; i++) {
axName = axisNames[i];
if(!Lib.isPlainObject(contIn[axName])) {
contIn[axName] = {};
}
var axIn = contIn[axName];
var axOut = Template.newContainer(contOut, axName);
axOut._id = axOut._name = axName;
axOut._attr = opts.id + '.' + axName;
axOut._traceIndices = subplotData.map(function(t) { return t._expandedIndex; });
var dataAttr = constants.axisName2dataArray[axName];
var axType = handleAxisTypeDefaults(axIn, axOut, coerceAxis, subplotData, dataAttr, opts);
handleCategoryOrderDefaults(axIn, axOut, coerceAxis, {
axData: subplotData,
dataAttr: dataAttr
});
var visible = coerceAxis('visible');
setConvert(axOut, contOut, layoutOut);
coerceAxis('uirevision', contOut.uirevision);
var dfltColor;
var dfltFontColor;
if(visible) {
dfltColor = coerceAxis('color');
dfltFontColor = (dfltColor === axIn.color) ? dfltColor : opts.font.color;
}
// We don't want to make downstream code call ax.setScale,
// as both radial and angular axes don't have a set domain.
// Furthermore, angular axes don't have a set range.
//
// Mocked domains and ranges are set by the polar subplot instances,
// but Axes.findExtremes uses the sign of _m to determine which padding value
// to use.
//
// By setting, _m to 1 here, we make Axes.findExtremes think that
// range[1] > range[0], and vice-versa for `autorange: 'reversed'` below.
axOut._m = 1;
switch(axName) {
case 'radialaxis':
var autoRange = coerceAxis('autorange', !axOut.isValidRange(axIn.range));
axIn.autorange = autoRange;
if(autoRange && (axType === 'linear' || axType === '-')) coerceAxis('rangemode');
if(autoRange === 'reversed') axOut._m = -1;
coerceAxis('range');
axOut.cleanRange('range', {dfltRange: [0, 1]});
if(visible) {
coerceAxis('side');
coerceAxis('angle', sector[0]);
coerceAxis('title.text');
Lib.coerceFont(coerceAxis, 'title.font', {
family: opts.font.family,
size: Math.round(opts.font.size * 1.2),
color: dfltFontColor
});
}
break;
case 'angularaxis':
// We do not support 'true' date angular axes yet,
// users can still plot dates on angular axes by setting
// `angularaxis.type: 'category'`.
//
// Here, if a date angular axes is detected, we make
// all its corresponding traces invisible, so that
// when we do add support for data angular axes, the new
// behavior won't conflict with existing behavior
if(axType === 'date') {
Lib.log('Polar plots do not support date angular axes yet.');
for(var j = 0; j < subplotData.length; j++) {
subplotData[j].visible = false;
}
// turn this into a 'dummy' linear axis so that
// the subplot still renders ok
axType = axIn.type = axOut.type = 'linear';
}
if(axType === 'linear') {
coerceAxis('thetaunit');
} else {
coerceAxis('period');
}
var direction = coerceAxis('direction');
coerceAxis('rotation', {counterclockwise: 0, clockwise: 90}[direction]);
break;
}
if(visible) {
handleTickValueDefaults(axIn, axOut, coerceAxis, axOut.type);
handleTickLabelDefaults(axIn, axOut, coerceAxis, axOut.type, {
tickSuffixDflt: axOut.thetaunit === 'degrees' ? '°' : undefined
});
handleTickMarkDefaults(axIn, axOut, coerceAxis, {outerTicks: true});
var showTickLabels = coerceAxis('showticklabels');
if(showTickLabels) {
Lib.coerceFont(coerceAxis, 'tickfont', {
family: opts.font.family,
size: opts.font.size,
color: dfltFontColor
});
coerceAxis('tickangle');
coerceAxis('tickformat');
}
handleLineGridDefaults(axIn, axOut, coerceAxis, {
dfltColor: dfltColor,
bgColor: opts.bgColor,
// default grid color is darker here (60%, vs cartesian default ~91%)
// because the grid is not square so the eye needs heavier cues to follow
blend: 60,
showLine: true,
showGrid: true,
noZeroLine: true,
attributes: layoutAttributes[axName]
});
coerceAxis('layer');
}
if(axType !== 'category') coerceAxis('hoverformat');
axOut._input = axIn;
}
if(contOut.angularaxis.type === 'category') {
coerce('gridshape');
}
}
function handleAxisTypeDefaults(axIn, axOut, coerce, subplotData, dataAttr, options) {
var autotypenumbers = coerce('autotypenumbers', options.autotypenumbersDflt);
var axType = coerce('type');
if(axType === '-') {
var trace;
for(var i = 0; i < subplotData.length; i++) {
if(subplotData[i].visible) {
trace = subplotData[i];
break;
}
}
if(trace && trace[dataAttr]) {
axOut.type = autoType(trace[dataAttr], 'gregorian', {
noMultiCategory: true,
autotypenumbers: autotypenumbers
});
}
if(axOut.type === '-') {
axOut.type = 'linear';
} else {
// copy autoType back to input axis
// note that if this object didn't exist
// in the input layout, we have to put it in
// this happens in the main supplyDefaults function
axIn.type = axOut.type;
}
}
return axOut.type;
}
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
handleSubplotDefaults(layoutIn, layoutOut, fullData, {
type: constants.name,
attributes: layoutAttributes,
handleDefaults: handleDefaults,
font: layoutOut.font,
autotypenumbersDflt: layoutOut.autotypenumbers,
paper_bgcolor: layoutOut.paper_bgcolor,
fullData: fullData,
layoutOut: layoutOut
});
};