* @param {object} opts (see Plotly.toImage in ../plot_api/to_image)
* @return {promise}
*/
function downloadImage(gd, opts) {
var _gd;
if (!Lib.isPlainObject(gd)) _gd = Lib.getGraphDiv(gd);
opts = opts || {};
opts.format = opts.format || 'png';
opts.width = opts.width || null;
opts.height = opts.height || null;
opts.imageDataOnly = true;
return new Promise(function (resolve, reject) {
if (_gd && _gd._snapshotInProgress) {
reject(new Error('Snapshotting already in progress.'));
}
// see comments within svgtoimg for additional
// discussion of problems with IE
// can now draw to canvas, but CORS tainted canvas
// does not allow toDataURL
// svg format will work though
if (Lib.isIE() && opts.format !== 'svg') {
reject(new Error(helpers.MSG_IE_BAD_FORMAT));
}
if (_gd) _gd._snapshotInProgress = true;
var promise = toImage(gd, opts);
var filename = opts.filename || gd.fn || 'newplot';
filename += '.' + opts.format.replace('-', '.');
promise.then(function (result) {
if (_gd) _gd._snapshotInProgress = false;
return fileSaver(result, filename, opts.format);
}).then(function (name) {
resolve(name);
}).catch(function (err) {
if (_gd) _gd._snapshotInProgress = false;
reject(err);
});
});
}
module.exports = downloadImage;
/***/ }),
/***/ 72780:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var helpers = __webpack_require__(48688);
/*
* substantial portions of this code from FileSaver.js
* https://github.com/eligrey/FileSaver.js
* License: https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
* FileSaver.js
* A saveAs() FileSaver implementation.
* 1.1.20160328
*
* By Eli Grey, http://eligrey.com
* License: MIT
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
*/
function fileSaver(url, name, format) {
var saveLink = document.createElement('a');
var canUseSaveLink = ('download' in saveLink);
var promise = new Promise(function (resolve, reject) {
var blob;
var objectUrl;
// IE 10+ (native saveAs)
if (Lib.isIE()) {
// At this point we are only dealing with a decoded SVG as
// a data URL (since IE only supports SVG)
blob = helpers.createBlob(url, 'svg');
window.navigator.msSaveBlob(blob, name);
blob = null;
return resolve(name);
}
if (canUseSaveLink) {
blob = helpers.createBlob(url, format);
objectUrl = helpers.createObjectURL(blob);
saveLink.href = objectUrl;
saveLink.download = name;
document.body.appendChild(saveLink);
saveLink.click();
document.body.removeChild(saveLink);
helpers.revokeObjectURL(objectUrl);
blob = null;
return resolve(name);
}
// Older versions of Safari did not allow downloading of blob urls
if (Lib.isSafari()) {
var prefix = format === 'svg' ? ',' : ';base64,';
helpers.octetStream(prefix + encodeURIComponent(url));
return resolve(name);
}
reject(new Error('download error'));
});
return promise;
}
module.exports = fileSaver;
/***/ }),
/***/ 48688:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
exports.getDelay = function (fullLayout) {
if (!fullLayout._has) return 0;
return fullLayout._has('gl3d') || fullLayout._has('gl2d') || fullLayout._has('mapbox') ? 500 : 0;
};
exports.getRedrawFunc = function (gd) {
return function () {
Registry.getComponentMethod('colorbar', 'draw')(gd);
};
};
exports.encodeSVG = function (svg) {
return 'data:image/svg+xml,' + encodeURIComponent(svg);
};
exports.encodeJSON = function (json) {
return 'data:application/json,' + encodeURIComponent(json);
};
var DOM_URL = window.URL || window.webkitURL;
exports.createObjectURL = function (blob) {
return DOM_URL.createObjectURL(blob);
};
exports.revokeObjectURL = function (url) {
return DOM_URL.revokeObjectURL(url);
};
exports.createBlob = function (url, format) {
if (format === 'svg') {
return new window.Blob([url], {
type: 'image/svg+xml;charset=utf-8'
});
} else if (format === 'full-json') {
return new window.Blob([url], {
type: 'application/json;charset=utf-8'
});
} else {
var binary = fixBinary(window.atob(url));
return new window.Blob([binary], {
type: 'image/' + format
});
}
};
exports.octetStream = function (s) {
document.location.href = 'data:application/octet-stream' + s;
};
// Taken from https://bl.ocks.org/nolanlawson/0eac306e4dac2114c752
function fixBinary(b) {
var len = b.length;
var buf = new ArrayBuffer(len);
var arr = new Uint8Array(buf);
for (var i = 0; i < len; i++) {
arr[i] = b.charCodeAt(i);
}
return buf;
}
exports.IMAGE_URL_PREFIX = /^data:image\/\w+;base64,/;
exports.MSG_IE_BAD_FORMAT = 'Sorry IE does not support downloading from canvas. Try {format:\'svg\'} instead.';
/***/ }),
/***/ 43976:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var helpers = __webpack_require__(48688);
var Snapshot = {
getDelay: helpers.getDelay,
getRedrawFunc: helpers.getRedrawFunc,
clone: __webpack_require__(2352),
toSVG: __webpack_require__(18424),
svgToImg: __webpack_require__(49864),
toImage: __webpack_require__(26272),
downloadImage: __webpack_require__(808)
};
module.exports = Snapshot;
/***/ }),
/***/ 49864:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var EventEmitter = (__webpack_require__(91984).EventEmitter);
var helpers = __webpack_require__(48688);
function svgToImg(opts) {
var ev = opts.emitter || new EventEmitter();
var promise = new Promise(function (resolve, reject) {
var Image = window.Image;
var svg = opts.svg;
var format = opts.format || 'png';
// IE only support svg
if (Lib.isIE() && format !== 'svg') {
var ieSvgError = new Error(helpers.MSG_IE_BAD_FORMAT);
reject(ieSvgError);
// eventually remove the ev
// in favor of promises
if (!opts.promise) {
return ev.emit('error', ieSvgError);
} else {
return promise;
}
}
var canvas = opts.canvas;
var scale = opts.scale || 1;
var w0 = opts.width || 300;
var h0 = opts.height || 150;
var w1 = scale * w0;
var h1 = scale * h0;
var ctx = canvas.getContext('2d', {
willReadFrequently: true
});
var img = new Image();
var svgBlob, url;
if (format === 'svg' || Lib.isSafari()) {
url = helpers.encodeSVG(svg);
} else {
svgBlob = helpers.createBlob(svg, 'svg');
url = helpers.createObjectURL(svgBlob);
}
canvas.width = w1;
canvas.height = h1;
img.onload = function () {
var imgData;
svgBlob = null;
helpers.revokeObjectURL(url);
// don't need to draw to canvas if svg
// save some time and also avoid failure on IE
if (format !== 'svg') {
ctx.drawImage(img, 0, 0, w1, h1);
}
switch (format) {
case 'jpeg':
imgData = canvas.toDataURL('image/jpeg');
break;
case 'png':
imgData = canvas.toDataURL('image/png');
break;
case 'webp':
imgData = canvas.toDataURL('image/webp');
break;
case 'svg':
imgData = url;
break;
default:
var errorMsg = 'Image format is not jpeg, png, svg or webp.';
reject(new Error(errorMsg));
// eventually remove the ev
// in favor of promises
if (!opts.promise) {
return ev.emit('error', errorMsg);
}
}
resolve(imgData);
// eventually remove the ev
// in favor of promises
if (!opts.promise) {
ev.emit('success', imgData);
}
};
img.onerror = function (err) {
svgBlob = null;
helpers.revokeObjectURL(url);
reject(err);
// eventually remove the ev
// in favor of promises
if (!opts.promise) {
return ev.emit('error', err);
}
};
img.src = url;
});
// temporary for backward compatibility
// move to only Promise in 2.0.0
// and eliminate the EventEmitter
if (opts.promise) {
return promise;
}
return ev;
}
module.exports = svgToImg;
/***/ }),
/***/ 26272:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var EventEmitter = (__webpack_require__(91984).EventEmitter);
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var helpers = __webpack_require__(48688);
var clonePlot = __webpack_require__(2352);
var toSVG = __webpack_require__(18424);
var svgToImg = __webpack_require__(49864);
/**
* @param {object} gd figure Object
* @param {object} opts option object
* @param opts.format 'jpeg' | 'png' | 'webp' | 'svg'
*/
function toImage(gd, opts) {
// first clone the GD so we can operate in a clean environment
var ev = new EventEmitter();
var clone = clonePlot(gd, {
format: 'png'
});
var clonedGd = clone.gd;
// put the cloned div somewhere off screen before attaching to DOM
clonedGd.style.position = 'absolute';
clonedGd.style.left = '-5000px';
document.body.appendChild(clonedGd);
function wait() {
var delay = helpers.getDelay(clonedGd._fullLayout);
setTimeout(function () {
var svg = toSVG(clonedGd);
var canvas = document.createElement('canvas');
canvas.id = Lib.randstr();
ev = svgToImg({
format: opts.format,
width: clonedGd._fullLayout.width,
height: clonedGd._fullLayout.height,
canvas: canvas,
emitter: ev,
svg: svg
});
ev.clean = function () {
if (clonedGd) document.body.removeChild(clonedGd);
};
}, delay);
}
var redrawFunc = helpers.getRedrawFunc(clonedGd);
Registry.call('_doPlot', clonedGd, clone.data, clone.layout, clone.config).then(redrawFunc).then(wait).catch(function (err) {
ev.emit('error', err);
});
return ev;
}
module.exports = toImage;
/***/ }),
/***/ 18424:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var Color = __webpack_require__(9240);
var xmlnsNamespaces = __webpack_require__(51608);
var DOUBLEQUOTE_REGEX = /"/g;
var DUMMY_SUB = 'TOBESTRIPPED';
var DUMMY_REGEX = new RegExp('("' + DUMMY_SUB + ')|(' + DUMMY_SUB + '")', 'g');
function htmlEntityDecode(s) {
var hiddenDiv = d3.select('body').append('div').style({
display: 'none'
}).html('');
var replaced = s.replace(/(&[^;]*;)/gi, function (d) {
if (d === '<') {
return '<';
} // special handling for brackets
if (d === '&rt;') {
return '>';
}
if (d.indexOf('<') !== -1 || d.indexOf('>') !== -1) {
return '';
}
return hiddenDiv.html(d).text(); // everything else, let the browser decode it to unicode
});
hiddenDiv.remove();
return replaced;
}
function xmlEntityEncode(str) {
return str.replace(/&(?!\w+;|\#[0-9]+;| \#x[0-9A-F]+;)/g, '&');
}
module.exports = function toSVG(gd, format, scale) {
var fullLayout = gd._fullLayout;
var svg = fullLayout._paper;
var toppaper = fullLayout._toppaper;
var width = fullLayout.width;
var height = fullLayout.height;
var i;
// make background color a rect in the svg, then revert after scraping
// all other alterations have been dealt with by properly preparing the svg
// in the first place... like setting cursors with css classes so we don't
// have to remove them, and providing the right namespaces in the svg to
// begin with
svg.insert('rect', ':first-child').call(Drawing.setRect, 0, 0, width, height).call(Color.fill, fullLayout.paper_bgcolor);
// subplot-specific to-SVG methods
// which notably add the contents of the gl-container
// into the main svg node
var basePlotModules = fullLayout._basePlotModules || [];
for (i = 0; i < basePlotModules.length; i++) {
var _module = basePlotModules[i];
if (_module.toSVG) _module.toSVG(gd);
}
// add top items above them assumes everything in toppaper is either
// a group or a defs, and if it's empty (like hoverlayer) we can ignore it.
if (toppaper) {
var nodes = toppaper.node().childNodes;
// make copy of nodes as childNodes prop gets mutated in loop below
var topGroups = Array.prototype.slice.call(nodes);
for (i = 0; i < topGroups.length; i++) {
var topGroup = topGroups[i];
if (topGroup.childNodes.length) svg.node().appendChild(topGroup);
}
}
// remove draglayer for Adobe Illustrator compatibility
if (fullLayout._draggers) {
fullLayout._draggers.remove();
}
// in case the svg element had an explicit background color, remove this
// we want the rect to get the color so it's the right size; svg bg will
// fill whatever container it's displayed in regardless of plot size.
svg.node().style.background = '';
svg.selectAll('text').attr({
'data-unformatted': null,
'data-math': null
}).each(function () {
var txt = d3.select(this);
// hidden text is pre-formatting mathjax, the browser ignores it
// but in a static plot it's useless and it can confuse batik
// we've tried to standardize on display:none but make sure we still
// catch visibility:hidden if it ever arises
if (this.style.visibility === 'hidden' || this.style.display === 'none') {
txt.remove();
return;
} else {
// clear other visibility/display values to default
// to not potentially confuse non-browser SVG implementations
txt.style({
visibility: null,
display: null
});
}
// Font family styles break things because of quotation marks,
// so we must remove them *after* the SVG DOM has been serialized
// to a string (browsers convert singles back)
var ff = this.style.fontFamily;
if (ff && ff.indexOf('"') !== -1) {
txt.style('font-family', ff.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
}
});
svg.selectAll('.gradient_filled,.pattern_filled').each(function () {
var pt = d3.select(this);
// similar to font family styles above,
// we must remove " after the SVG DOM has been serialized
var fill = this.style.fill;
if (fill && fill.indexOf('url(') !== -1) {
pt.style('fill', fill.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
}
var stroke = this.style.stroke;
if (stroke && stroke.indexOf('url(') !== -1) {
pt.style('stroke', stroke.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
}
});
if (format === 'pdf' || format === 'eps') {
// these formats make the extra line MathJax adds around symbols look super thick in some cases
// it looks better if this is removed entirely.
svg.selectAll('#MathJax_SVG_glyphs path').attr('stroke-width', 0);
}
// fix for IE namespacing quirk?
// http://stackoverflow.com/questions/19610089/unwanted-namespaces-on-svg-markup-when-using-xmlserializer-in-javascript-with-ie
svg.node().setAttributeNS(xmlnsNamespaces.xmlns, 'xmlns', xmlnsNamespaces.svg);
svg.node().setAttributeNS(xmlnsNamespaces.xmlns, 'xmlns:xlink', xmlnsNamespaces.xlink);
if (format === 'svg' && scale) {
svg.attr('width', scale * width);
svg.attr('height', scale * height);
svg.attr('viewBox', '0 0 ' + width + ' ' + height);
}
var s = new window.XMLSerializer().serializeToString(svg.node());
s = htmlEntityDecode(s);
s = xmlEntityEncode(s);
// Fix quotations around font strings and gradient URLs
s = s.replace(DUMMY_REGEX, '\'');
// Do we need this process now that IE9 and IE10 are not supported?
// IE is very strict, so we will need to clean
// svg with the following regex
// yes this is messy, but do not know a better way
// Even with this IE will not work due to tainted canvas
// see https://github.com/kangax/fabric.js/issues/1957
// http://stackoverflow.com/questions/18112047/canvas-todataurl-working-in-all-browsers-except-ie10
// Leave here just in case the CORS/tainted IE issue gets resolved
if (Lib.isIE()) {
// replace double quote with single quote
s = s.replace(/"/gi, '\'');
// url in svg are single quoted
// since we changed double to single
// we'll need to change these to double-quoted
s = s.replace(/(\('#)([^']*)('\))/gi, '(\"#$2\")');
// font names with spaces will be escaped single-quoted
// we'll need to change these to double-quoted
s = s.replace(/(\\')/gi, '\"');
}
return s;
};
/***/ }),
/***/ 79224:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
// arrayOk attributes, merge them into calcdata array
module.exports = function arraysToCalcdata(cd, trace) {
for (var i = 0; i < cd.length; i++) cd[i].i = i;
Lib.mergeArray(trace.text, cd, 'tx');
Lib.mergeArray(trace.hovertext, cd, 'htx');
var marker = trace.marker;
if (marker) {
Lib.mergeArray(marker.opacity, cd, 'mo', true);
Lib.mergeArray(marker.color, cd, 'mc');
var markerLine = marker.line;
if (markerLine) {
Lib.mergeArray(markerLine.color, cd, 'mlc');
Lib.mergeArrayCastPositive(markerLine.width, cd, 'mlw');
}
}
};
/***/ }),
/***/ 39788:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterAttrs = __webpack_require__(49992);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var colorScaleAttrs = __webpack_require__(99732);
var fontAttrs = __webpack_require__(71936);
var constants = __webpack_require__(77216);
var pattern = (__webpack_require__(9392)/* .pattern */ .c);
var extendFlat = (__webpack_require__(55016).extendFlat);
var textFontAttrs = fontAttrs({
editType: 'calc',
arrayOk: true,
colorEditType: 'style',
description: ''
});
var scatterMarkerAttrs = scatterAttrs.marker;
var scatterMarkerLineAttrs = scatterMarkerAttrs.line;
var markerLineWidth = extendFlat({}, scatterMarkerLineAttrs.width, {
dflt: 0
});
var markerLine = extendFlat({
width: markerLineWidth,
editType: 'calc'
}, colorScaleAttrs('marker.line'));
var marker = extendFlat({
line: markerLine,
editType: 'calc'
}, colorScaleAttrs('marker'), {
opacity: {
valType: 'number',
arrayOk: true,
dflt: 1,
min: 0,
max: 1,
editType: 'style',
description: 'Sets the opacity of the bars.'
},
pattern: pattern,
cornerradius: {
valType: 'any',
editType: 'calc',
description: ['Sets the rounding of corners. May be an integer number of pixels,', 'or a percentage of bar width (as a string ending in %). Defaults to `layout.barcornerradius`.', 'In stack or relative barmode, the first trace to set cornerradius is used for the whole stack.'].join(' ')
}
});
module.exports = {
x: scatterAttrs.x,
x0: scatterAttrs.x0,
dx: scatterAttrs.dx,
y: scatterAttrs.y,
y0: scatterAttrs.y0,
dy: scatterAttrs.dy,
xperiod: scatterAttrs.xperiod,
yperiod: scatterAttrs.yperiod,
xperiod0: scatterAttrs.xperiod0,
yperiod0: scatterAttrs.yperiod0,
xperiodalignment: scatterAttrs.xperiodalignment,
yperiodalignment: scatterAttrs.yperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
text: scatterAttrs.text,
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: constants.eventDataKeys
}),
hovertext: scatterAttrs.hovertext,
hovertemplate: hovertemplateAttrs({}, {
keys: constants.eventDataKeys
}),
textposition: {
valType: 'enumerated',
values: ['inside', 'outside', 'auto', 'none'],
dflt: 'auto',
arrayOk: true,
editType: 'calc',
description: ['Specifies the location of the `text`.', '*inside* positions `text` inside, next to the bar end', '(rotated and scaled if needed).', '*outside* positions `text` outside, next to the bar end', '(scaled if needed), unless there is another bar stacked on', 'this one, then the text gets pushed inside.', '*auto* tries to position `text` inside the bar, but if', 'the bar is too small and no bar is stacked on this one', 'the text is moved outside.', 'If *none*, no text appears.'].join(' ')
},
insidetextanchor: {
valType: 'enumerated',
values: ['end', 'middle', 'start'],
dflt: 'end',
editType: 'plot',
description: ['Determines if texts are kept at center or start/end points in `textposition` *inside* mode.'].join(' ')
},
textangle: {
valType: 'angle',
dflt: 'auto',
editType: 'plot',
description: ['Sets the angle of the tick labels with respect to the bar.', 'For example, a `tickangle` of -90 draws the tick labels', 'vertically. With *auto* the texts may automatically be', 'rotated to fit with the maximum size in bars.'].join(' ')
},
textfont: extendFlat({}, textFontAttrs, {
description: 'Sets the font used for `text`.'
}),
insidetextfont: extendFlat({}, textFontAttrs, {
description: 'Sets the font used for `text` lying inside the bar.'
}),
outsidetextfont: extendFlat({}, textFontAttrs, {
description: 'Sets the font used for `text` lying outside the bar.'
}),
constraintext: {
valType: 'enumerated',
values: ['inside', 'outside', 'both', 'none'],
dflt: 'both',
editType: 'calc',
description: ['Constrain the size of text inside or outside a bar to be no', 'larger than the bar itself.'].join(' ')
},
cliponaxis: extendFlat({}, scatterAttrs.cliponaxis, {
description: ['Determines whether the text nodes', 'are clipped about the subplot axes.', 'To show the text nodes above axis lines and tick labels,', 'make sure to set `xaxis.layer` and `yaxis.layer` to *below traces*.'].join(' ')
}),
orientation: {
valType: 'enumerated',
values: ['v', 'h'],
editType: 'calc+clearAxisTypes',
description: ['Sets the orientation of the bars.', 'With *v* (*h*), the value of the each bar spans', 'along the vertical (horizontal).'].join(' ')
},
base: {
valType: 'any',
dflt: null,
arrayOk: true,
editType: 'calc',
description: ['Sets where the bar base is drawn (in position axis units).', 'In *stack* or *relative* barmode,', 'traces that set *base* will be excluded', 'and drawn in *overlay* mode instead.'].join(' ')
},
offset: {
valType: 'number',
dflt: null,
arrayOk: true,
editType: 'calc',
description: ['Shifts the position where the bar is drawn', '(in position axis units).', 'In *group* barmode,', 'traces that set *offset* will be excluded', 'and drawn in *overlay* mode instead.'].join(' ')
},
width: {
valType: 'number',
dflt: null,
min: 0,
arrayOk: true,
editType: 'calc',
description: ['Sets the bar width (in position axis units).'].join(' ')
},
marker: marker,
offsetgroup: scatterAttrs.offsetgroup,
alignmentgroup: scatterAttrs.alignmentgroup,
selected: {
marker: {
opacity: scatterAttrs.selected.marker.opacity,
color: scatterAttrs.selected.marker.color,
editType: 'style'
},
textfont: scatterAttrs.selected.textfont,
editType: 'style'
},
unselected: {
marker: {
opacity: scatterAttrs.unselected.marker.opacity,
color: scatterAttrs.unselected.marker.color,
editType: 'style'
},
textfont: scatterAttrs.unselected.textfont,
editType: 'style'
},
zorder: scatterAttrs.zorder,
_deprecated: {
bardir: {
valType: 'enumerated',
editType: 'calc',
values: ['v', 'h'],
description: 'Renamed to `orientation`.'
}
}
};
/***/ }),
/***/ 97292:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var alignPeriod = __webpack_require__(82260);
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var colorscaleCalc = __webpack_require__(60416);
var arraysToCalcdata = __webpack_require__(79224);
var calcSelection = __webpack_require__(62496);
module.exports = function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var size, pos, origPos, pObj, hasPeriod, pLetter;
var sizeOpts = {
msUTC: !!(trace.base || trace.base === 0)
};
if (trace.orientation === 'h') {
size = xa.makeCalcdata(trace, 'x', sizeOpts);
origPos = ya.makeCalcdata(trace, 'y');
pObj = alignPeriod(trace, ya, 'y', origPos);
hasPeriod = !!trace.yperiodalignment;
pLetter = 'y';
} else {
size = ya.makeCalcdata(trace, 'y', sizeOpts);
origPos = xa.makeCalcdata(trace, 'x');
pObj = alignPeriod(trace, xa, 'x', origPos);
hasPeriod = !!trace.xperiodalignment;
pLetter = 'x';
}
pos = pObj.vals;
// create the "calculated data" to plot
var serieslen = Math.min(pos.length, size.length);
var cd = new Array(serieslen);
// set position and size
for (var i = 0; i < serieslen; i++) {
cd[i] = {
p: pos[i],
s: size[i]
};
if (hasPeriod) {
cd[i].orig_p = origPos[i]; // used by hover
cd[i][pLetter + 'End'] = pObj.ends[i];
cd[i][pLetter + 'Start'] = pObj.starts[i];
}
if (trace.ids) {
cd[i].id = String(trace.ids[i]);
}
}
// auto-z and autocolorscale if applicable
if (hasColorscale(trace, 'marker')) {
colorscaleCalc(gd, trace, {
vals: trace.marker.color,
containerStr: 'marker',
cLetter: 'c'
});
}
if (hasColorscale(trace, 'marker.line')) {
colorscaleCalc(gd, trace, {
vals: trace.marker.line.color,
containerStr: 'marker.line',
cLetter: 'c'
});
}
arraysToCalcdata(cd, trace);
calcSelection(cd, trace);
return cd;
};
/***/ }),
/***/ 77216:
/***/ (function(module) {
"use strict";
module.exports = {
// padding in pixels around text
TEXTPAD: 3,
// 'value' and 'label' are not really necessary for bar traces,
// but they were made available to `texttemplate` (maybe by accident)
// via tokens `%{value}` and `%{label}` starting in 1.50.0,
// so let's include them in the event data also.
eventDataKeys: ['value', 'label']
};
/***/ }),
/***/ 2616:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var BADNUM = (__webpack_require__(41752).BADNUM);
var Registry = __webpack_require__(30364);
var Axes = __webpack_require__(81536);
var getAxisGroup = (__webpack_require__(76908).getAxisGroup);
var Sieve = __webpack_require__(28788);
/*
* Bar chart stacking/grouping positioning and autoscaling calculations
* for each direction separately calculate the ranges and positions
* note that this handles histograms too
* now doing this one subplot at a time
*/
function crossTraceCalc(gd, plotinfo) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var fullLayout = gd._fullLayout;
var fullTraces = gd._fullData;
var calcTraces = gd.calcdata;
var calcTracesHorz = [];
var calcTracesVert = [];
for (var i = 0; i < fullTraces.length; i++) {
var fullTrace = fullTraces[i];
if (fullTrace.visible === true && Registry.traceIs(fullTrace, 'bar') && fullTrace.xaxis === xa._id && fullTrace.yaxis === ya._id) {
if (fullTrace.orientation === 'h') {
calcTracesHorz.push(calcTraces[i]);
} else {
calcTracesVert.push(calcTraces[i]);
}
if (fullTrace._computePh) {
var cd = gd.calcdata[i];
for (var j = 0; j < cd.length; j++) {
if (typeof cd[j].ph0 === 'function') cd[j].ph0 = cd[j].ph0();
if (typeof cd[j].ph1 === 'function') cd[j].ph1 = cd[j].ph1();
}
}
}
}
var opts = {
xCat: xa.type === 'category' || xa.type === 'multicategory',
yCat: ya.type === 'category' || ya.type === 'multicategory',
mode: fullLayout.barmode,
norm: fullLayout.barnorm,
gap: fullLayout.bargap,
groupgap: fullLayout.bargroupgap
};
setGroupPositions(gd, xa, ya, calcTracesVert, opts);
setGroupPositions(gd, ya, xa, calcTracesHorz, opts);
}
function setGroupPositions(gd, pa, sa, calcTraces, opts) {
if (!calcTraces.length) return;
var excluded;
var included;
var i, calcTrace, fullTrace;
initBase(sa, calcTraces);
switch (opts.mode) {
case 'overlay':
setGroupPositionsInOverlayMode(pa, sa, calcTraces, opts);
break;
case 'group':
// exclude from the group those traces for which the user set an offset
excluded = [];
included = [];
for (i = 0; i < calcTraces.length; i++) {
calcTrace = calcTraces[i];
fullTrace = calcTrace[0].trace;
if (fullTrace.offset === undefined) included.push(calcTrace);else excluded.push(calcTrace);
}
if (included.length) {
setGroupPositionsInGroupMode(gd, pa, sa, included, opts);
}
if (excluded.length) {
setGroupPositionsInOverlayMode(pa, sa, excluded, opts);
}
break;
case 'stack':
case 'relative':
// exclude from the stack those traces for which the user set a base
excluded = [];
included = [];
for (i = 0; i < calcTraces.length; i++) {
calcTrace = calcTraces[i];
fullTrace = calcTrace[0].trace;
if (fullTrace.base === undefined) included.push(calcTrace);else excluded.push(calcTrace);
}
// If any trace in `included` has a cornerradius, set cornerradius of all bars
// in `included` to match the first trace which has a cornerradius
standardizeCornerradius(included);
if (included.length) {
setGroupPositionsInStackOrRelativeMode(gd, pa, sa, included, opts);
}
if (excluded.length) {
setGroupPositionsInOverlayMode(pa, sa, excluded, opts);
}
break;
}
setCornerradius(calcTraces);
collectExtents(calcTraces, pa);
}
// Set cornerradiusvalue and cornerradiusform in calcTraces[0].t
function setCornerradius(calcTraces) {
var i, calcTrace, fullTrace, t, cr, crValue, crForm;
for (i = 0; i < calcTraces.length; i++) {
calcTrace = calcTraces[i];
fullTrace = calcTrace[0].trace;
t = calcTrace[0].t;
if (t.cornerradiusvalue === undefined) {
cr = fullTrace.marker ? fullTrace.marker.cornerradius : undefined;
if (cr !== undefined) {
crValue = isNumeric(cr) ? +cr : +cr.slice(0, -1);
crForm = isNumeric(cr) ? 'px' : '%';
t.cornerradiusvalue = crValue;
t.cornerradiusform = crForm;
}
}
}
}
// Make sure all traces in a stack use the same cornerradius
function standardizeCornerradius(calcTraces) {
if (calcTraces.length < 2) return;
var i, calcTrace, fullTrace, t;
var cr, crValue, crForm;
for (i = 0; i < calcTraces.length; i++) {
calcTrace = calcTraces[i];
fullTrace = calcTrace[0].trace;
cr = fullTrace.marker ? fullTrace.marker.cornerradius : undefined;
if (cr !== undefined) break;
}
// If any trace has cornerradius, store first cornerradius
// in calcTrace[0].t so that all traces in stack use same cornerradius
if (cr !== undefined) {
crValue = isNumeric(cr) ? +cr : +cr.slice(0, -1);
crForm = isNumeric(cr) ? 'px' : '%';
for (i = 0; i < calcTraces.length; i++) {
calcTrace = calcTraces[i];
t = calcTrace[0].t;
t.cornerradiusvalue = crValue;
t.cornerradiusform = crForm;
}
}
}
function initBase(sa, calcTraces) {
var i, j;
for (i = 0; i < calcTraces.length; i++) {
var cd = calcTraces[i];
var trace = cd[0].trace;
var base = trace.type === 'funnel' ? trace._base : trace.base;
var b;
// not sure if it really makes sense to have dates for bar size data...
// ideally if we want to make gantt charts or something we'd treat
// the actual size (trace.x or y) as time delta but base as absolute
// time. But included here for completeness.
var scalendar = trace.orientation === 'h' ? trace.xcalendar : trace.ycalendar;
// 'base' on categorical axes makes no sense
var d2c = sa.type === 'category' || sa.type === 'multicategory' ? function () {
return null;
} : sa.d2c;
if (isArrayOrTypedArray(base)) {
for (j = 0; j < Math.min(base.length, cd.length); j++) {
b = d2c(base[j], 0, scalendar);
if (isNumeric(b)) {
cd[j].b = +b;
cd[j].hasB = 1;
} else cd[j].b = 0;
}
for (; j < cd.length; j++) {
cd[j].b = 0;
}
} else {
b = d2c(base, 0, scalendar);
var hasBase = isNumeric(b);
b = hasBase ? b : 0;
for (j = 0; j < cd.length; j++) {
cd[j].b = b;
if (hasBase) cd[j].hasB = 1;
}
}
}
}
function setGroupPositionsInOverlayMode(pa, sa, calcTraces, opts) {
// update position axis and set bar offsets and widths
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var sieve = new Sieve([calcTrace], {
posAxis: pa,
sepNegVal: false,
overlapNoMerge: !opts.norm
});
// set bar offsets and widths, and update position axis
setOffsetAndWidth(pa, sieve, opts);
// set bar bases and sizes, and update size axis
//
// (note that `setGroupPositionsInOverlayMode` handles the case barnorm
// is defined, because this function is also invoked for traces that
// can't be grouped or stacked)
if (opts.norm) {
sieveBars(sieve);
normalizeBars(sa, sieve, opts);
} else {
setBaseAndTop(sa, sieve);
}
}
}
function setGroupPositionsInGroupMode(gd, pa, sa, calcTraces, opts) {
var sieve = new Sieve(calcTraces, {
posAxis: pa,
sepNegVal: false,
overlapNoMerge: !opts.norm
});
// set bar offsets and widths, and update position axis
setOffsetAndWidthInGroupMode(gd, pa, sieve, opts);
// relative-stack bars within the same trace that would otherwise
// be hidden
unhideBarsWithinTrace(sieve, pa);
// set bar bases and sizes, and update size axis
if (opts.norm) {
sieveBars(sieve);
normalizeBars(sa, sieve, opts);
} else {
setBaseAndTop(sa, sieve);
}
}
function setGroupPositionsInStackOrRelativeMode(gd, pa, sa, calcTraces, opts) {
var sieve = new Sieve(calcTraces, {
posAxis: pa,
sepNegVal: opts.mode === 'relative',
overlapNoMerge: !(opts.norm || opts.mode === 'stack' || opts.mode === 'relative')
});
// set bar offsets and widths, and update position axis
setOffsetAndWidth(pa, sieve, opts);
// set bar bases and sizes, and update size axis
stackBars(sa, sieve, opts);
// flag the outmost bar (for text display purposes)
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
for (var j = 0; j < calcTrace.length; j++) {
var bar = calcTrace[j];
if (bar.s !== BADNUM) {
var isOutmostBar = bar.b + bar.s === sieve.get(bar.p, bar.s);
if (isOutmostBar) bar._outmost = true;
}
}
}
// Note that marking the outmost bars has to be done
// before `normalizeBars` changes `bar.b` and `bar.s`.
if (opts.norm) normalizeBars(sa, sieve, opts);
}
function setOffsetAndWidth(pa, sieve, opts) {
var minDiff = sieve.minDiff;
var calcTraces = sieve.traces;
// set bar offsets and widths
var barGroupWidth = minDiff * (1 - opts.gap);
var barWidthPlusGap = barGroupWidth;
var barWidth = barWidthPlusGap * (1 - (opts.groupgap || 0));
// computer bar group center and bar offset
var offsetFromCenter = -barWidth / 2;
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var t = calcTrace[0].t;
// store bar width and offset for this trace
t.barwidth = barWidth;
t.poffset = offsetFromCenter;
t.bargroupwidth = barGroupWidth;
t.bardelta = minDiff;
}
// stack bars that only differ by rounding
sieve.binWidth = calcTraces[0][0].t.barwidth / 100;
// if defined, apply trace offset and width
applyAttributes(sieve);
// store the bar center in each calcdata item
setBarCenterAndWidth(pa, sieve);
// update position axes
updatePositionAxis(pa, sieve);
}
function setOffsetAndWidthInGroupMode(gd, pa, sieve, opts) {
var fullLayout = gd._fullLayout;
var positions = sieve.positions;
var distinctPositions = sieve.distinctPositions;
var minDiff = sieve.minDiff;
var calcTraces = sieve.traces;
var nTraces = calcTraces.length;
// if there aren't any overlapping positions,
// let them have full width even if mode is group
var overlap = positions.length !== distinctPositions.length;
var barGroupWidth = minDiff * (1 - opts.gap);
var groupId = getAxisGroup(fullLayout, pa._id) + calcTraces[0][0].trace.orientation;
var alignmentGroups = fullLayout._alignmentOpts[groupId] || {};
for (var i = 0; i < nTraces; i++) {
var calcTrace = calcTraces[i];
var trace = calcTrace[0].trace;
var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {};
var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length;
var barWidthPlusGap;
if (nOffsetGroups) {
barWidthPlusGap = barGroupWidth / nOffsetGroups;
} else {
barWidthPlusGap = overlap ? barGroupWidth / nTraces : barGroupWidth;
}
var barWidth = barWidthPlusGap * (1 - (opts.groupgap || 0));
var offsetFromCenter;
if (nOffsetGroups) {
offsetFromCenter = ((2 * trace._offsetIndex + 1 - nOffsetGroups) * barWidthPlusGap - barWidth) / 2;
} else {
offsetFromCenter = overlap ? ((2 * i + 1 - nTraces) * barWidthPlusGap - barWidth) / 2 : -barWidth / 2;
}
var t = calcTrace[0].t;
t.barwidth = barWidth;
t.poffset = offsetFromCenter;
t.bargroupwidth = barGroupWidth;
t.bardelta = minDiff;
}
// stack bars that only differ by rounding
sieve.binWidth = calcTraces[0][0].t.barwidth / 100;
// if defined, apply trace width
applyAttributes(sieve);
// store the bar center in each calcdata item
setBarCenterAndWidth(pa, sieve);
// update position axes
updatePositionAxis(pa, sieve, overlap);
}
function applyAttributes(sieve) {
var calcTraces = sieve.traces;
var i, j;
for (i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var calcTrace0 = calcTrace[0];
var fullTrace = calcTrace0.trace;
var t = calcTrace0.t;
var offset = fullTrace._offset || fullTrace.offset;
var initialPoffset = t.poffset;
var newPoffset;
if (isArrayOrTypedArray(offset)) {
// if offset is an array, then clone it into t.poffset.
newPoffset = Array.prototype.slice.call(offset, 0, calcTrace.length);
// guard against non-numeric items
for (j = 0; j < newPoffset.length; j++) {
if (!isNumeric(newPoffset[j])) {
newPoffset[j] = initialPoffset;
}
}
// if the length of the array is too short,
// then extend it with the initial value of t.poffset
for (j = newPoffset.length; j < calcTrace.length; j++) {
newPoffset.push(initialPoffset);
}
t.poffset = newPoffset;
} else if (offset !== undefined) {
t.poffset = offset;
}
var width = fullTrace._width || fullTrace.width;
var initialBarwidth = t.barwidth;
if (isArrayOrTypedArray(width)) {
// if width is an array, then clone it into t.barwidth.
var newBarwidth = Array.prototype.slice.call(width, 0, calcTrace.length);
// guard against non-numeric items
for (j = 0; j < newBarwidth.length; j++) {
if (!isNumeric(newBarwidth[j])) newBarwidth[j] = initialBarwidth;
}
// if the length of the array is too short,
// then extend it with the initial value of t.barwidth
for (j = newBarwidth.length; j < calcTrace.length; j++) {
newBarwidth.push(initialBarwidth);
}
t.barwidth = newBarwidth;
// if user didn't set offset,
// then correct t.poffset to ensure bars remain centered
if (offset === undefined) {
newPoffset = [];
for (j = 0; j < calcTrace.length; j++) {
newPoffset.push(initialPoffset + (initialBarwidth - newBarwidth[j]) / 2);
}
t.poffset = newPoffset;
}
} else if (width !== undefined) {
t.barwidth = width;
// if user didn't set offset,
// then correct t.poffset to ensure bars remain centered
if (offset === undefined) {
t.poffset = initialPoffset + (initialBarwidth - width) / 2;
}
}
}
}
function setBarCenterAndWidth(pa, sieve) {
var calcTraces = sieve.traces;
var pLetter = getAxisLetter(pa);
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var t = calcTrace[0].t;
var poffset = t.poffset;
var poffsetIsArray = isArrayOrTypedArray(poffset);
var barwidth = t.barwidth;
var barwidthIsArray = isArrayOrTypedArray(barwidth);
for (var j = 0; j < calcTrace.length; j++) {
var calcBar = calcTrace[j];
// store the actual bar width and position, for use by hover
var width = calcBar.w = barwidthIsArray ? barwidth[j] : barwidth;
if (calcBar.p === undefined) {
calcBar.p = calcBar[pLetter];
calcBar['orig_' + pLetter] = calcBar[pLetter];
}
var delta = (poffsetIsArray ? poffset[j] : poffset) + width / 2;
calcBar[pLetter] = calcBar.p + delta;
}
}
}
function updatePositionAxis(pa, sieve, allowMinDtick) {
var calcTraces = sieve.traces;
var minDiff = sieve.minDiff;
var vpad = minDiff / 2;
Axes.minDtick(pa, sieve.minDiff, sieve.distinctPositions[0], allowMinDtick);
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var calcTrace0 = calcTrace[0];
var fullTrace = calcTrace0.trace;
var pts = [];
var bar, l, r, j;
for (j = 0; j < calcTrace.length; j++) {
bar = calcTrace[j];
l = bar.p - vpad;
r = bar.p + vpad;
pts.push(l, r);
}
if (fullTrace.width || fullTrace.offset) {
var t = calcTrace0.t;
var poffset = t.poffset;
var barwidth = t.barwidth;
var poffsetIsArray = isArrayOrTypedArray(poffset);
var barwidthIsArray = isArrayOrTypedArray(barwidth);
for (j = 0; j < calcTrace.length; j++) {
bar = calcTrace[j];
var calcBarOffset = poffsetIsArray ? poffset[j] : poffset;
var calcBarWidth = barwidthIsArray ? barwidth[j] : barwidth;
l = bar.p + calcBarOffset;
r = l + calcBarWidth;
pts.push(l, r);
}
}
fullTrace._extremes[pa._id] = Axes.findExtremes(pa, pts, {
padded: false
});
}
}
// store these bar bases and tops in calcdata
// and make sure the size axis includes zero,
// along with the bases and tops of each bar.
function setBaseAndTop(sa, sieve) {
var calcTraces = sieve.traces;
var sLetter = getAxisLetter(sa);
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var fullTrace = calcTrace[0].trace;
var isScatter = fullTrace.type === 'scatter';
var isVertical = fullTrace.orientation === 'v';
var pts = [];
var tozero = false;
for (var j = 0; j < calcTrace.length; j++) {
var bar = calcTrace[j];
var base = isScatter ? 0 : bar.b;
var top = isScatter ? isVertical ? bar.y : bar.x : base + bar.s;
bar[sLetter] = top;
pts.push(top);
if (bar.hasB) pts.push(base);
if (!bar.hasB || !bar.b) {
tozero = true;
}
}
fullTrace._extremes[sa._id] = Axes.findExtremes(sa, pts, {
tozero: tozero,
padded: true
});
}
}
function stackBars(sa, sieve, opts) {
var sLetter = getAxisLetter(sa);
var calcTraces = sieve.traces;
var calcTrace;
var fullTrace;
var isFunnel;
var i, j;
var bar;
for (i = 0; i < calcTraces.length; i++) {
calcTrace = calcTraces[i];
fullTrace = calcTrace[0].trace;
if (fullTrace.type === 'funnel') {
for (j = 0; j < calcTrace.length; j++) {
bar = calcTrace[j];
if (bar.s !== BADNUM) {
// create base of funnels
sieve.put(bar.p, -0.5 * bar.s);
}
}
}
}
for (i = 0; i < calcTraces.length; i++) {
calcTrace = calcTraces[i];
fullTrace = calcTrace[0].trace;
isFunnel = fullTrace.type === 'funnel';
var pts = [];
for (j = 0; j < calcTrace.length; j++) {
bar = calcTrace[j];
if (bar.s !== BADNUM) {
// stack current bar and get previous sum
var value;
if (isFunnel) {
value = bar.s;
} else {
value = bar.s + bar.b;
}
var base = sieve.put(bar.p, value);
var top = base + value;
// store the bar base and top in each calcdata item
bar.b = base;
bar[sLetter] = top;
if (!opts.norm) {
pts.push(top);
if (bar.hasB) {
pts.push(base);
}
}
}
}
// if barnorm is set, let normalizeBars update the axis range
if (!opts.norm) {
fullTrace._extremes[sa._id] = Axes.findExtremes(sa, pts, {
// N.B. we don't stack base with 'base',
// so set tozero:true always!
tozero: true,
padded: true
});
}
}
}
function sieveBars(sieve) {
var calcTraces = sieve.traces;
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
for (var j = 0; j < calcTrace.length; j++) {
var bar = calcTrace[j];
if (bar.s !== BADNUM) {
sieve.put(bar.p, bar.b + bar.s);
}
}
}
}
function unhideBarsWithinTrace(sieve, pa) {
var calcTraces = sieve.traces;
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var fullTrace = calcTrace[0].trace;
if (fullTrace.base === undefined) {
var inTraceSieve = new Sieve([calcTrace], {
posAxis: pa,
sepNegVal: true,
overlapNoMerge: true
});
for (var j = 0; j < calcTrace.length; j++) {
var bar = calcTrace[j];
if (bar.p !== BADNUM) {
// stack current bar and get previous sum
var base = inTraceSieve.put(bar.p, bar.b + bar.s);
// if previous sum if non-zero, this means:
// multiple bars have same starting point are potentially hidden,
// shift them vertically so that all bars are visible by default
if (base) bar.b = base;
}
}
}
}
}
// Note:
//
// normalizeBars requires that either sieveBars or stackBars has been
// previously invoked.
function normalizeBars(sa, sieve, opts) {
var calcTraces = sieve.traces;
var sLetter = getAxisLetter(sa);
var sTop = opts.norm === 'fraction' ? 1 : 100;
var sTiny = sTop / 1e9; // in case of rounding error in sum
var sMin = sa.l2c(sa.c2l(0));
var sMax = opts.mode === 'stack' ? sTop : sMin;
function needsPadding(v) {
return isNumeric(sa.c2l(v)) && (v < sMin - sTiny || v > sMax + sTiny || !isNumeric(sMin));
}
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
var fullTrace = calcTrace[0].trace;
var pts = [];
var tozero = false;
var padded = false;
for (var j = 0; j < calcTrace.length; j++) {
var bar = calcTrace[j];
if (bar.s !== BADNUM) {
var scale = Math.abs(sTop / sieve.get(bar.p, bar.s));
bar.b *= scale;
bar.s *= scale;
var base = bar.b;
var top = base + bar.s;
bar[sLetter] = top;
pts.push(top);
padded = padded || needsPadding(top);
if (bar.hasB) {
pts.push(base);
padded = padded || needsPadding(base);
}
if (!bar.hasB || !bar.b) {
tozero = true;
}
}
}
fullTrace._extremes[sa._id] = Axes.findExtremes(sa, pts, {
tozero: tozero,
padded: padded
});
}
}
// Add an `_sMin` and `_sMax` value for each bar representing the min and max size value
// across all bars sharing the same position as that bar. These values are used for rounded
// bar corners, to carry rounding down to lower bars in the stack as needed.
function setHelperValuesForRoundedCorners(calcTraces, sMinByPos, sMaxByPos, pa) {
var pLetter = getAxisLetter(pa);
// Set `_sMin` and `_sMax` value for each bar
for (var i = 0; i < calcTraces.length; i++) {
var calcTrace = calcTraces[i];
for (var j = 0; j < calcTrace.length; j++) {
var bar = calcTrace[j];
var pos = bar[pLetter];
bar._sMin = sMinByPos[pos];
bar._sMax = sMaxByPos[pos];
}
}
}
// find the full position span of bars at each position
// for use by hover, to ensure labels move in if bars are
// narrower than the space they're in.
// run once per trace group (subplot & direction) and
// the same mapping is attached to all calcdata traces
function collectExtents(calcTraces, pa) {
var pLetter = getAxisLetter(pa);
var extents = {};
var i, j, cd;
var pMin = Infinity;
var pMax = -Infinity;
for (i = 0; i < calcTraces.length; i++) {
cd = calcTraces[i];
for (j = 0; j < cd.length; j++) {
var p = cd[j].p;
if (isNumeric(p)) {
pMin = Math.min(pMin, p);
pMax = Math.max(pMax, p);
}
}
}
// this is just for positioning of hover labels, and nobody will care if
// the label is 1px too far out; so round positions to 1/10K in case
// position values don't exactly match from trace to trace
var roundFactor = 10000 / (pMax - pMin);
var round = extents.round = function (p) {
return String(Math.round(roundFactor * (p - pMin)));
};
// Find min and max size axis extent for each position
// This is used for rounded bar corners, to carry rounding
// down to lower bars in the case of stacked bars
var sMinByPos = {};
var sMaxByPos = {};
// Check whether any trace has rounded corners
var anyTraceHasCornerradius = calcTraces.some(function (x) {
var trace = x[0].trace;
return 'marker' in trace && trace.marker.cornerradius;
});
for (i = 0; i < calcTraces.length; i++) {
cd = calcTraces[i];
cd[0].t.extents = extents;
var poffset = cd[0].t.poffset;
var poffsetIsArray = isArrayOrTypedArray(poffset);
for (j = 0; j < cd.length; j++) {
var di = cd[j];
var p0 = di[pLetter] - di.w / 2;
if (isNumeric(p0)) {
var p1 = di[pLetter] + di.w / 2;
var pVal = round(di.p);
if (extents[pVal]) {
extents[pVal] = [Math.min(p0, extents[pVal][0]), Math.max(p1, extents[pVal][1])];
} else {
extents[pVal] = [p0, p1];
}
}
di.p0 = di.p + (poffsetIsArray ? poffset[j] : poffset);
di.p1 = di.p0 + di.w;
di.s0 = di.b;
di.s1 = di.s0 + di.s;
if (anyTraceHasCornerradius) {
var sMin = Math.min(di.s0, di.s1) || 0;
var sMax = Math.max(di.s0, di.s1) || 0;
var pos = di[pLetter];
sMinByPos[pos] = pos in sMinByPos ? Math.min(sMinByPos[pos], sMin) : sMin;
sMaxByPos[pos] = pos in sMaxByPos ? Math.max(sMaxByPos[pos], sMax) : sMax;
}
}
}
if (anyTraceHasCornerradius) {
setHelperValuesForRoundedCorners(calcTraces, sMinByPos, sMaxByPos, pa);
}
}
function getAxisLetter(ax) {
return ax._id.charAt(0);
}
module.exports = {
crossTraceCalc: crossTraceCalc,
setGroupPositions: setGroupPositions
};
/***/ }),
/***/ 49520:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var Color = __webpack_require__(9240);
var Registry = __webpack_require__(30364);
var handleXYDefaults = __webpack_require__(88376);
var handlePeriodDefaults = __webpack_require__(98632);
var handleStyleDefaults = __webpack_require__(37408);
var handleGroupingDefaults = __webpack_require__(8584);
var attributes = __webpack_require__(39788);
var coerceFont = Lib.coerceFont;
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleXYDefaults(traceIn, traceOut, layout, coerce);
if (!len) {
traceOut.visible = false;
return;
}
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');
coerce('zorder');
coerce('orientation', traceOut.x && !traceOut.y ? 'h' : 'v');
coerce('base');
coerce('offset');
coerce('width');
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
var textposition = coerce('textposition');
handleText(traceIn, traceOut, layout, coerce, textposition, {
moduleHasSelected: true,
moduleHasUnselected: true,
moduleHasConstrain: true,
moduleHasCliponaxis: true,
moduleHasTextangle: true,
moduleHasInsideanchor: true
});
handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout);
var lineColor = (traceOut.marker.line || {}).color;
// override defaultColor for error bars with defaultLine
var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults');
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || Color.defaultLine, {
axis: 'y'
});
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || Color.defaultLine, {
axis: 'x',
inherit: 'y'
});
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
}
function crossTraceDefaults(fullData, fullLayout) {
var traceIn, traceOut;
function coerce(attr, dflt) {
return Lib.coerce(traceOut._input, traceOut, attributes, attr, dflt);
}
for (var i = 0; i < fullData.length; i++) {
traceOut = fullData[i];
if (traceOut.type === 'bar') {
traceIn = traceOut._input;
// `marker.cornerradius` needs to be coerced here rather than in handleStyleDefaults()
// because it needs to happen after `layout.barcornerradius` has been coerced
var r = coerce('marker.cornerradius', fullLayout.barcornerradius);
if (traceOut.marker) {
traceOut.marker.cornerradius = validateCornerradius(r);
}
if (fullLayout.barmode === 'group') {
handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce);
}
}
}
}
// Returns a value equivalent to the given cornerradius value, if valid;
// otherwise returns`undefined`.
// Valid cornerradius values must be either:
// - a numeric value (string or number) >= 0, or
// - a string consisting of a number >= 0 followed by a % sign
// If the given cornerradius value is a numeric string, it will be converted
// to a number.
function validateCornerradius(r) {
if (isNumeric(r)) {
r = +r;
if (r >= 0) return r;
} else if (typeof r === 'string') {
r = r.trim();
if (r.slice(-1) === '%' && isNumeric(r.slice(0, -1))) {
r = +r.slice(0, -1);
if (r >= 0) return r + '%';
}
}
return undefined;
}
function handleText(traceIn, traceOut, layout, coerce, textposition, opts) {
opts = opts || {};
var moduleHasSelected = !(opts.moduleHasSelected === false);
var moduleHasUnselected = !(opts.moduleHasUnselected === false);
var moduleHasConstrain = !(opts.moduleHasConstrain === false);
var moduleHasCliponaxis = !(opts.moduleHasCliponaxis === false);
var moduleHasTextangle = !(opts.moduleHasTextangle === false);
var moduleHasInsideanchor = !(opts.moduleHasInsideanchor === false);
var hasPathbar = !!opts.hasPathbar;
var hasBoth = Array.isArray(textposition) || textposition === 'auto';
var hasInside = hasBoth || textposition === 'inside';
var hasOutside = hasBoth || textposition === 'outside';
if (hasInside || hasOutside) {
var dfltFont = coerceFont(coerce, 'textfont', layout.font);
// Note that coercing `insidetextfont` is always needed –
// even if `textposition` is `outside` for each trace – since
// an outside label can become an inside one, for example because
// of a bar being stacked on top of it.
var insideTextFontDefault = Lib.extendFlat({}, dfltFont);
var isTraceTextfontColorSet = traceIn.textfont && traceIn.textfont.color;
var isColorInheritedFromLayoutFont = !isTraceTextfontColorSet;
if (isColorInheritedFromLayoutFont) {
delete insideTextFontDefault.color;
}
coerceFont(coerce, 'insidetextfont', insideTextFontDefault);
if (hasPathbar) {
var pathbarTextFontDefault = Lib.extendFlat({}, dfltFont);
if (isColorInheritedFromLayoutFont) {
delete pathbarTextFontDefault.color;
}
coerceFont(coerce, 'pathbar.textfont', pathbarTextFontDefault);
}
if (hasOutside) coerceFont(coerce, 'outsidetextfont', dfltFont);
if (moduleHasSelected) coerce('selected.textfont.color');
if (moduleHasUnselected) coerce('unselected.textfont.color');
if (moduleHasConstrain) coerce('constraintext');
if (moduleHasCliponaxis) coerce('cliponaxis');
if (moduleHasTextangle) coerce('textangle');
coerce('texttemplate');
}
if (hasInside) {
if (moduleHasInsideanchor) coerce('insidetextanchor');
}
}
module.exports = {
supplyDefaults: supplyDefaults,
crossTraceDefaults: crossTraceDefaults,
handleText: handleText,
validateCornerradius: validateCornerradius
};
/***/ }),
/***/ 99332:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt, trace) {
// standard cartesian event data
out.x = 'xVal' in pt ? pt.xVal : pt.x;
out.y = 'yVal' in pt ? pt.yVal : pt.y;
if (pt.xa) out.xaxis = pt.xa;
if (pt.ya) out.yaxis = pt.ya;
if (trace.orientation === 'h') {
out.label = out.y;
out.value = out.x;
} else {
out.label = out.x;
out.value = out.y;
}
return out;
};
/***/ }),
/***/ 17700:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var tinycolor = __webpack_require__(70336);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
exports.coerceString = function (attributeDefinition, value, defaultValue) {
if (typeof value === 'string') {
if (value || !attributeDefinition.noBlank) return value;
} else if (typeof value === 'number' || value === true) {
if (!attributeDefinition.strict) return String(value);
}
return defaultValue !== undefined ? defaultValue : attributeDefinition.dflt;
};
exports.coerceNumber = function (attributeDefinition, value, defaultValue) {
if (isNumeric(value)) {
value = +value;
var min = attributeDefinition.min;
var max = attributeDefinition.max;
var isOutOfBounds = min !== undefined && value < min || max !== undefined && value > max;
if (!isOutOfBounds) return value;
}
return defaultValue !== undefined ? defaultValue : attributeDefinition.dflt;
};
exports.coerceColor = function (attributeDefinition, value, defaultValue) {
if (tinycolor(value).isValid()) return value;
return defaultValue !== undefined ? defaultValue : attributeDefinition.dflt;
};
exports.coerceEnumerated = function (attributeDefinition, value, defaultValue) {
if (attributeDefinition.coerceNumber) value = +value;
if (attributeDefinition.values.indexOf(value) !== -1) return value;
return defaultValue !== undefined ? defaultValue : attributeDefinition.dflt;
};
exports.getValue = function (arrayOrScalar, index) {
var value;
if (!isArrayOrTypedArray(arrayOrScalar)) value = arrayOrScalar;else if (index < arrayOrScalar.length) value = arrayOrScalar[index];
return value;
};
exports.getLineWidth = function (trace, di) {
var w = 0 < di.mlw ? di.mlw : !isArrayOrTypedArray(trace.marker.line.width) ? trace.marker.line.width : 0;
return w;
};
/***/ }),
/***/ 30284:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Fx = __webpack_require__(39184);
var Registry = __webpack_require__(30364);
var Color = __webpack_require__(9240);
var fillText = (__webpack_require__(10923).fillText);
var getLineWidth = (__webpack_require__(17700).getLineWidth);
var hoverLabelText = (__webpack_require__(81536).hoverLabelText);
var BADNUM = (__webpack_require__(41752).BADNUM);
function hoverPoints(pointData, xval, yval, hovermode, opts) {
var barPointData = hoverOnBars(pointData, xval, yval, hovermode, opts);
if (barPointData) {
var cd = barPointData.cd;
var trace = cd[0].trace;
var di = cd[barPointData.index];
barPointData.color = getTraceColor(trace, di);
Registry.getComponentMethod('errorbars', 'hoverInfo')(di, trace, barPointData);
return [barPointData];
}
}
function hoverOnBars(pointData, xval, yval, hovermode, opts) {
var cd = pointData.cd;
var trace = cd[0].trace;
var t = cd[0].t;
var isClosest = hovermode === 'closest';
var isWaterfall = trace.type === 'waterfall';
var maxHoverDistance = pointData.maxHoverDistance;
var maxSpikeDistance = pointData.maxSpikeDistance;
var posVal, sizeVal, posLetter, sizeLetter, dx, dy, pRangeCalc;
if (trace.orientation === 'h') {
posVal = yval;
sizeVal = xval;
posLetter = 'y';
sizeLetter = 'x';
dx = sizeFn;
dy = positionFn;
} else {
posVal = xval;
sizeVal = yval;
posLetter = 'x';
sizeLetter = 'y';
dy = sizeFn;
dx = positionFn;
}
var period = trace[posLetter + 'period'];
var isClosestOrPeriod = isClosest || period;
function thisBarMinPos(di) {
return thisBarExtPos(di, -1);
}
function thisBarMaxPos(di) {
return thisBarExtPos(di, 1);
}
function thisBarExtPos(di, sgn) {
var w = di.w;
return di[posLetter] + sgn * w / 2;
}
function periodLength(di) {
return di[posLetter + 'End'] - di[posLetter + 'Start'];
}
var minPos = isClosest ? thisBarMinPos : period ? function (di) {
return di.p - periodLength(di) / 2;
} : function (di) {
/*
* In compare mode, accept a bar if you're on it *or* its group.
* Nearly always it's the group that matters, but in case the bar
* was explicitly set wider than its group we'd better accept the
* whole bar.
*
* use `bardelta` instead of `bargroupwidth` so we accept hover
* in the gap. That way hover doesn't flash on and off as you
* mouse over the plot in compare modes.
* In 'closest' mode though the flashing seems inevitable,
* without far more complex logic
*/
return Math.min(thisBarMinPos(di), di.p - t.bardelta / 2);
};
var maxPos = isClosest ? thisBarMaxPos : period ? function (di) {
return di.p + periodLength(di) / 2;
} : function (di) {
return Math.max(thisBarMaxPos(di), di.p + t.bardelta / 2);
};
function inbox(_minPos, _maxPos, maxDistance) {
if (opts.finiteRange) maxDistance = 0;
// add a little to the pseudo-distance for wider bars, so that like scatter,
// if you are over two overlapping bars, the narrower one wins.
return Fx.inbox(_minPos - posVal, _maxPos - posVal, maxDistance + Math.min(1, Math.abs(_maxPos - _minPos) / pRangeCalc) - 1);
}
function positionFn(di) {
return inbox(minPos(di), maxPos(di), maxHoverDistance);
}
function thisBarPositionFn(di) {
return inbox(thisBarMinPos(di), thisBarMaxPos(di), maxSpikeDistance);
}
function getSize(di) {
var s = di[sizeLetter];
if (isWaterfall) {
var rawS = Math.abs(di.rawS) || 0;
if (sizeVal > 0) {
s += rawS;
} else if (sizeVal < 0) {
s -= rawS;
}
}
return s;
}
function sizeFn(di) {
var v = sizeVal;
var b = di.b;
var s = getSize(di);
// add a gradient so hovering near the end of a
// bar makes it a little closer match
return Fx.inbox(b - v, s - v, maxHoverDistance + (s - v) / (s - b) - 1);
}
function thisBarSizeFn(di) {
var v = sizeVal;
var b = di.b;
var s = getSize(di);
// add a gradient so hovering near the end of a
// bar makes it a little closer match
return Fx.inbox(b - v, s - v, maxSpikeDistance + (s - v) / (s - b) - 1);
}
var pa = pointData[posLetter + 'a'];
var sa = pointData[sizeLetter + 'a'];
pRangeCalc = Math.abs(pa.r2c(pa.range[1]) - pa.r2c(pa.range[0]));
function dxy(di) {
return (dx(di) + dy(di)) / 2;
}
var distfn = Fx.getDistanceFunction(hovermode, dx, dy, dxy);
Fx.getClosest(cd, distfn, pointData);
// skip the rest (for this trace) if we didn't find a close point
if (pointData.index === false) return;
// skip points inside axis rangebreaks
if (cd[pointData.index].p === BADNUM) return;
// if we get here and we're not in 'closest' mode, push min/max pos back
// onto the group - even though that means occasionally the mouse will be
// over the hover label.
if (!isClosestOrPeriod) {
minPos = function (di) {
return Math.min(thisBarMinPos(di), di.p - t.bargroupwidth / 2);
};
maxPos = function (di) {
return Math.max(thisBarMaxPos(di), di.p + t.bargroupwidth / 2);
};
}
// the closest data point
var index = pointData.index;
var di = cd[index];
var size = trace.base ? di.b + di.s : di.s;
pointData[sizeLetter + '0'] = pointData[sizeLetter + '1'] = sa.c2p(di[sizeLetter], true);
pointData[sizeLetter + 'LabelVal'] = size;
var extent = t.extents[t.extents.round(di.p)];
pointData[posLetter + '0'] = pa.c2p(isClosest ? minPos(di) : extent[0], true);
pointData[posLetter + '1'] = pa.c2p(isClosest ? maxPos(di) : extent[1], true);
var hasPeriod = di.orig_p !== undefined;
pointData[posLetter + 'LabelVal'] = hasPeriod ? di.orig_p : di.p;
pointData.labelLabel = hoverLabelText(pa, pointData[posLetter + 'LabelVal'], trace[posLetter + 'hoverformat']);
pointData.valueLabel = hoverLabelText(sa, pointData[sizeLetter + 'LabelVal'], trace[sizeLetter + 'hoverformat']);
pointData.baseLabel = hoverLabelText(sa, di.b, trace[sizeLetter + 'hoverformat']);
// spikelines always want "closest" distance regardless of hovermode
pointData.spikeDistance = (thisBarSizeFn(di) + thisBarPositionFn(di)) / 2;
// they also want to point to the data value, regardless of where the label goes
// in case of bars shifted within groups
pointData[posLetter + 'Spike'] = pa.c2p(di.p, true);
fillText(di, trace, pointData);
pointData.hovertemplate = trace.hovertemplate;
return pointData;
}
function getTraceColor(trace, di) {
var mc = di.mcc || trace.marker.color;
var mlc = di.mlcc || trace.marker.line.color;
var mlw = getLineWidth(trace, di);
if (Color.opacity(mc)) return mc;else if (Color.opacity(mlc) && mlw) return mlc;
}
module.exports = {
hoverPoints: hoverPoints,
hoverOnBars: hoverOnBars,
getTraceColor: getTraceColor
};
/***/ }),
/***/ 61040:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(39788),
layoutAttributes: __webpack_require__(90192),
supplyDefaults: (__webpack_require__(49520).supplyDefaults),
crossTraceDefaults: (__webpack_require__(49520).crossTraceDefaults),
supplyLayoutDefaults: __webpack_require__(38700),
calc: __webpack_require__(97292),
crossTraceCalc: (__webpack_require__(2616).crossTraceCalc),
colorbar: __webpack_require__(71416),
arraysToCalcdata: __webpack_require__(79224),
plot: (__webpack_require__(39176).plot),
style: (__webpack_require__(21212).style),
styleOnSelect: (__webpack_require__(21212).styleOnSelect),
hoverPoints: (__webpack_require__(30284).hoverPoints),
eventData: __webpack_require__(99332),
selectPoints: __webpack_require__(10512),
moduleType: 'trace',
name: 'bar',
basePlotModule: __webpack_require__(34316),
categories: ['bar-like', 'cartesian', 'svg', 'bar', 'oriented', 'errorBarsOK', 'showLegend', 'zoomScale'],
animatable: true,
meta: {
description: ['The data visualized by the span of the bars is set in `y`', 'if `orientation` is set to *v* (the default)', 'and the labels are set in `x`.', 'By setting `orientation` to *h*, the roles are interchanged.'].join(' ')
}
};
/***/ }),
/***/ 90192:
/***/ (function(module) {
"use strict";
module.exports = {
barmode: {
valType: 'enumerated',
values: ['stack', 'group', 'overlay', 'relative'],
dflt: 'group',
editType: 'calc',
description: ['Determines how bars at the same location coordinate', 'are displayed on the graph.', 'With *stack*, the bars are stacked on top of one another', 'With *relative*, the bars are stacked on top of one another,', 'with negative values below the axis, positive values above', 'With *group*, the bars are plotted next to one another', 'centered around the shared location.', 'With *overlay*, the bars are plotted over one another,', 'you might need to reduce *opacity* to see multiple bars.'].join(' ')
},
barnorm: {
valType: 'enumerated',
values: ['', 'fraction', 'percent'],
dflt: '',
editType: 'calc',
description: ['Sets the normalization for bar traces on the graph.', 'With *fraction*, the value of each bar is divided by the sum of all', 'values at that location coordinate.', '*percent* is the same but multiplied by 100 to show percentages.'].join(' ')
},
bargap: {
valType: 'number',
min: 0,
max: 1,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between bars of', 'adjacent location coordinates.'].join(' ')
},
bargroupgap: {
valType: 'number',
min: 0,
max: 1,
dflt: 0,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between bars of', 'the same location coordinate.'].join(' ')
},
barcornerradius: {
valType: 'any',
editType: 'calc',
description: ['Sets the rounding of bar corners. May be an integer number of pixels,', 'or a percentage of bar width (as a string ending in %).'].join(' ')
}
};
/***/ }),
/***/ 38700:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Axes = __webpack_require__(81536);
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(90192);
var validateCornerradius = (__webpack_require__(49520).validateCornerradius);
module.exports = function (layoutIn, layoutOut, fullData) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
var hasBars = false;
var shouldBeGapless = false;
var gappedAnyway = false;
var usedSubplots = {};
var mode = coerce('barmode');
for (var i = 0; i < fullData.length; i++) {
var trace = fullData[i];
if (Registry.traceIs(trace, 'bar') && trace.visible) hasBars = true;else continue;
// if we have at least 2 grouped bar traces on the same subplot,
// we should default to a gap anyway, even if the data is histograms
if (mode === 'group') {
var subploti = trace.xaxis + trace.yaxis;
if (usedSubplots[subploti]) gappedAnyway = true;
usedSubplots[subploti] = true;
}
if (trace.visible && trace.type === 'histogram') {
var pa = Axes.getFromId({
_fullLayout: layoutOut
}, trace[trace.orientation === 'v' ? 'xaxis' : 'yaxis']);
if (pa.type !== 'category') shouldBeGapless = true;
}
}
if (!hasBars) {
delete layoutOut.barmode;
return;
}
if (mode !== 'overlay') coerce('barnorm');
coerce('bargap', shouldBeGapless && !gappedAnyway ? 0 : 0.2);
coerce('bargroupgap');
var r = coerce('barcornerradius');
layoutOut.barcornerradius = validateCornerradius(r);
};
/***/ }),
/***/ 39176:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var svgTextUtils = __webpack_require__(41536);
var Color = __webpack_require__(9240);
var Drawing = __webpack_require__(49348);
var Registry = __webpack_require__(30364);
var tickText = (__webpack_require__(81536).tickText);
var uniformText = __webpack_require__(4096);
var recordMinTextSize = uniformText.recordMinTextSize;
var clearMinTextSize = uniformText.clearMinTextSize;
var style = __webpack_require__(21212);
var helpers = __webpack_require__(17700);
var constants = __webpack_require__(77216);
var attributes = __webpack_require__(39788);
var attributeText = attributes.text;
var attributeTextPosition = attributes.textposition;
var appendArrayPointValue = (__webpack_require__(12228).appendArrayPointValue);
var TEXTPAD = constants.TEXTPAD;
function keyFunc(d) {
return d.id;
}
function getKeyFunc(trace) {
if (trace.ids) {
return keyFunc;
}
}
// Returns -1 if v < 0, 1 if v > 0, and 0 if v == 0
function sign(v) {
return (v > 0) - (v < 0);
}
// Returns 1 if a < b and -1 otherwise
// (For the purposes of this module we don't care about the case where a == b)
function dirSign(a, b) {
return a < b ? 1 : -1;
}
function getXY(di, xa, ya, isHorizontal) {
var s = [];
var p = [];
var sAxis = isHorizontal ? xa : ya;
var pAxis = isHorizontal ? ya : xa;
s[0] = sAxis.c2p(di.s0, true);
p[0] = pAxis.c2p(di.p0, true);
s[1] = sAxis.c2p(di.s1, true);
p[1] = pAxis.c2p(di.p1, true);
return isHorizontal ? [s, p] : [p, s];
}
function transition(selection, fullLayout, opts, makeOnCompleteCallback) {
if (!fullLayout.uniformtext.mode && hasTransition(opts)) {
var onComplete;
if (makeOnCompleteCallback) {
onComplete = makeOnCompleteCallback();
}
return selection.transition().duration(opts.duration).ease(opts.easing).each('end', function () {
onComplete && onComplete();
}).each('interrupt', function () {
onComplete && onComplete();
});
} else {
return selection;
}
}
function hasTransition(transitionOpts) {
return transitionOpts && transitionOpts.duration > 0;
}
function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var fullLayout = gd._fullLayout;
var isStatic = gd._context.staticPlot;
if (!opts) {
opts = {
mode: fullLayout.barmode,
norm: fullLayout.barmode,
gap: fullLayout.bargap,
groupgap: fullLayout.bargroupgap
};
// don't clear bar when this is called from waterfall or funnel
clearMinTextSize('bar', fullLayout);
}
var bartraces = Lib.makeTraceGroups(traceLayer, cdModule, 'trace bars').each(function (cd) {
var plotGroup = d3.select(this);
var trace = cd[0].trace;
var t = cd[0].t;
var isWaterfall = trace.type === 'waterfall';
var isFunnel = trace.type === 'funnel';
var isHistogram = trace.type === 'histogram';
var isBar = trace.type === 'bar';
var shouldDisplayZeros = isBar || isFunnel;
var adjustPixel = 0;
if (isWaterfall && trace.connector.visible && trace.connector.mode === 'between') {
adjustPixel = trace.connector.line.width / 2;
}
var isHorizontal = trace.orientation === 'h';
var withTransition = hasTransition(opts);
var pointGroup = Lib.ensureSingle(plotGroup, 'g', 'points');
var keyFunc = getKeyFunc(trace);
var bars = pointGroup.selectAll('g.point').data(Lib.identity, keyFunc);
bars.enter().append('g').classed('point', true);
bars.exit().remove();
bars.each(function (di, i) {
var bar = d3.select(this);
// now display the bar
// clipped xf/yf (2nd arg true): non-positive
// log values go off-screen by plotwidth
// so you see them continue if you drag the plot
var xy = getXY(di, xa, ya, isHorizontal);
var x0 = xy[0][0];
var x1 = xy[0][1];
var y0 = xy[1][0];
var y1 = xy[1][1];
// empty bars
var isBlank = (isHorizontal ? x1 - x0 : y1 - y0) === 0;
// display zeros if line.width > 0
if (isBlank && shouldDisplayZeros && helpers.getLineWidth(trace, di)) {
isBlank = false;
}
// skip nulls
if (!isBlank) {
isBlank = !isNumeric(x0) || !isNumeric(x1) || !isNumeric(y0) || !isNumeric(y1);
}
// record isBlank
di.isBlank = isBlank;
// for blank bars, ensure start and end positions are equal - important for smooth transitions
if (isBlank) {
if (isHorizontal) {
x1 = x0;
} else {
y1 = y0;
}
}
// in waterfall mode `between` we need to adjust bar end points to match the connector width
if (adjustPixel && !isBlank) {
if (isHorizontal) {
x0 -= dirSign(x0, x1) * adjustPixel;
x1 += dirSign(x0, x1) * adjustPixel;
} else {
y0 -= dirSign(y0, y1) * adjustPixel;
y1 += dirSign(y0, y1) * adjustPixel;
}
}
var lw;
var mc;
if (trace.type === 'waterfall') {
if (!isBlank) {
var cont = trace[di.dir].marker;
lw = cont.line.width;
mc = cont.color;
}
} else {
lw = helpers.getLineWidth(trace, di);
mc = di.mc || trace.marker.color;
}
function roundWithLine(v) {
var offset = d3.round(lw / 2 % 1, 2);
// if there are explicit gaps, don't round,
// it can make the gaps look crappy
return opts.gap === 0 && opts.groupgap === 0 ? d3.round(Math.round(v) - offset, 2) : v;
}
function expandToVisible(v, vc, hideZeroSpan) {
if (hideZeroSpan && v === vc) {
// should not expand zero span bars
// when start and end positions are identical
// i.e. for vertical when y0 === y1
// and for horizontal when x0 === x1
return v;
}
// if it's not in danger of disappearing entirely,
// round more precisely
return Math.abs(v - vc) >= 2 ? roundWithLine(v) :
// but if it's very thin, expand it so it's
// necessarily visible, even if it might overlap
// its neighbor
v > vc ? Math.ceil(v) : Math.floor(v);
}
var op = Color.opacity(mc);
var fixpx = op < 1 || lw > 0.01 ? roundWithLine : expandToVisible;
if (!gd._context.staticPlot) {
// if bars are not fully opaque or they have a line
// around them, round to integer pixels, mainly for
// safari so we prevent overlaps from its expansive
// pixelation. if the bars ARE fully opaque and have
// no line, expand to a full pixel to make sure we
// can see them
x0 = fixpx(x0, x1, isHorizontal);
x1 = fixpx(x1, x0, isHorizontal);
y0 = fixpx(y0, y1, !isHorizontal);
y1 = fixpx(y1, y0, !isHorizontal);
}
// Function to convert from size axis values to pixels
var c2p = isHorizontal ? xa.c2p : ya.c2p;
// Decide whether to use upper or lower bound of current bar stack
// as reference point for rounding
var outerBound;
if (di.s0 > 0) {
outerBound = di._sMax;
} else if (di.s0 < 0) {
outerBound = di._sMin;
} else {
outerBound = di.s1 > 0 ? di._sMax : di._sMin;
}
// Calculate corner radius of bar in pixels
function calcCornerRadius(crValue, crForm) {
if (!crValue) return 0;
var barWidth = isHorizontal ? Math.abs(y1 - y0) : Math.abs(x1 - x0);
var barLength = isHorizontal ? Math.abs(x1 - x0) : Math.abs(y1 - y0);
var stackedBarTotalLength = fixpx(Math.abs(c2p(outerBound, true) - c2p(0, true)));
var maxRadius = di.hasB ? Math.min(barWidth / 2, barLength / 2) : Math.min(barWidth / 2, stackedBarTotalLength);
var crPx;
if (crForm === '%') {
// If radius is given as a % string, convert to number of pixels
var crPercent = Math.min(50, crValue);
crPx = barWidth * (crPercent / 100);
} else {
// Otherwise, it's already a number of pixels, use the given value
crPx = crValue;
}
return fixpx(Math.max(Math.min(crPx, maxRadius), 0));
}
// Exclude anything which is not explicitly a bar or histogram chart from rounding
var r = isBar || isHistogram ? calcCornerRadius(t.cornerradiusvalue, t.cornerradiusform) : 0;
// Construct path string for bar
var path, h;
// Default rectangular path (used if no rounding)
var rectanglePath = 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z';
var overhead = 0;
if (r && di.s) {
// Bar has cornerradius, and nonzero size
// Check amount of 'overhead' (bars stacked above this one)
// to see whether we need to round or not
var refPoint = sign(di.s0) === 0 || sign(di.s) === sign(di.s0) ? di.s1 : di.s0;
overhead = fixpx(!di.hasB ? Math.abs(c2p(outerBound, true) - c2p(refPoint, true)) : 0);
if (overhead < r) {
// Calculate parameters for rounded corners
var xdir = dirSign(x0, x1);
var ydir = dirSign(y0, y1);
// Sweep direction for rounded corner arcs
var cornersweep = xdir === -ydir ? 1 : 0;
if (isHorizontal) {
// Horizontal bars
if (di.hasB) {
// Floating base: Round 1st & 2nd, and 3rd & 4th corners
path = 'M' + (x0 + r * xdir) + ',' + y0 + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + x0 + ',' + (y0 + r * ydir) + 'V' + (y1 - r * ydir) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x0 + r * xdir) + ',' + y1 + 'H' + (x1 - r * xdir) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + x1 + ',' + (y1 - r * ydir) + 'V' + (y0 + r * ydir) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x1 - r * xdir) + ',' + y0 + 'Z';
} else {
// Base on axis: Round 3rd and 4th corners
// Helper variables to help with extending rounding down to lower bars
h = Math.abs(x1 - x0) + overhead;
var dy1 = h < r ? r - Math.sqrt(h * (2 * r - h)) : 0;
var dy2 = overhead > 0 ? Math.sqrt(overhead * (2 * r - overhead)) : 0;
var xminfunc = xdir > 0 ? Math.max : Math.min;
path = 'M' + x0 + ',' + y0 + 'V' + (y1 - dy1 * ydir) + 'H' + xminfunc(x1 - (r - overhead) * xdir, x0) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + x1 + ',' + (y1 - r * ydir - dy2) + 'V' + (y0 + r * ydir + dy2) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + xminfunc(x1 - (r - overhead) * xdir, x0) + ',' + (y0 + dy1 * ydir) + 'Z';
}
} else {
// Vertical bars
if (di.hasB) {
// Floating base: Round 1st & 4th, and 2nd & 3rd corners
path = 'M' + (x0 + r * xdir) + ',' + y0 + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + x0 + ',' + (y0 + r * ydir) + 'V' + (y1 - r * ydir) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x0 + r * xdir) + ',' + y1 + 'H' + (x1 - r * xdir) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + x1 + ',' + (y1 - r * ydir) + 'V' + (y0 + r * ydir) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x1 - r * xdir) + ',' + y0 + 'Z';
} else {
// Base on axis: Round 2nd and 3rd corners
// Helper variables to help with extending rounding down to lower bars
h = Math.abs(y1 - y0) + overhead;
var dx1 = h < r ? r - Math.sqrt(h * (2 * r - h)) : 0;
var dx2 = overhead > 0 ? Math.sqrt(overhead * (2 * r - overhead)) : 0;
var yminfunc = ydir > 0 ? Math.max : Math.min;
path = 'M' + (x0 + dx1 * xdir) + ',' + y0 + 'V' + yminfunc(y1 - (r - overhead) * ydir, y0) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x0 + r * xdir - dx2) + ',' + y1 + 'H' + (x1 - r * xdir + dx2) + 'A ' + r + ',' + r + ' 0 0 ' + cornersweep + ' ' + (x1 - dx1 * xdir) + ',' + yminfunc(y1 - (r - overhead) * ydir, y0) + 'V' + y0 + 'Z';
}
}
} else {
// There is a cornerradius, but bar is too far down the stack to be rounded; just draw a rectangle
path = rectanglePath;
}
} else {
// No cornerradius, just draw a rectangle
path = rectanglePath;
}
var sel = transition(Lib.ensureSingle(bar, 'path'), fullLayout, opts, makeOnCompleteCallback);
sel.style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke').attr('d', isNaN((x1 - x0) * (y1 - y0)) || isBlank && gd._context.staticPlot ? 'M0,0Z' : path).call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
if (!fullLayout.uniformtext.mode && withTransition) {
var styleFns = Drawing.makePointStyleFns(trace);
Drawing.singlePointStyle(di, sel, trace, styleFns, gd);
}
appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, r, overhead, opts, makeOnCompleteCallback);
if (plotinfo.layerClipId) {
Drawing.hideOutsideRangePoint(di, bar.select('text'), xa, ya, trace.xcalendar, trace.ycalendar);
}
});
// lastly, clip points groups of `cliponaxis !== false` traces
// on `plotinfo._hasClipOnAxisFalse === true` subplots
var hasClipOnAxisFalse = trace.cliponaxis === false;
Drawing.setClipUrl(plotGroup, hasClipOnAxisFalse ? null : plotinfo.layerClipId, gd);
});
// error bars are on the top
Registry.getComponentMethod('errorbars', 'plot')(gd, bartraces, plotinfo, opts);
}
function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, r, overhead, opts, makeOnCompleteCallback) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var fullLayout = gd._fullLayout;
var textPosition;
function appendTextNode(bar, text, font) {
var textSelection = Lib.ensureSingle(bar, 'text').text(text).attr({
class: 'bartext bartext-' + textPosition,
'text-anchor': 'middle',
// prohibit tex interpretation until we can handle
// tex and regular text together
'data-notex': 1
}).call(Drawing.font, font).call(svgTextUtils.convertToTspans, gd);
return textSelection;
}
// get trace attributes
var trace = cd[0].trace;
var isHorizontal = trace.orientation === 'h';
var text = getText(fullLayout, cd, i, xa, ya);
textPosition = getTextPosition(trace, i);
// compute text position
var inStackOrRelativeMode = opts.mode === 'stack' || opts.mode === 'relative';
var calcBar = cd[i];
var isOutmostBar = !inStackOrRelativeMode || calcBar._outmost;
var hasB = calcBar.hasB;
var barIsRounded = r && r - overhead > TEXTPAD;
if (!text || textPosition === 'none' || (calcBar.isBlank || x0 === x1 || y0 === y1) && (textPosition === 'auto' || textPosition === 'inside')) {
bar.select('text').remove();
return;
}
var layoutFont = fullLayout.font;
var barColor = style.getBarColor(cd[i], trace);
var insideTextFont = style.getInsideTextFont(trace, i, layoutFont, barColor);
var outsideTextFont = style.getOutsideTextFont(trace, i, layoutFont);
var insidetextanchor = trace.insidetextanchor || 'end';
// Special case: don't use the c2p(v, true) value on log size axes,
// so that we can get correctly inside text scaling
var di = bar.datum();
if (isHorizontal) {
if (xa.type === 'log' && di.s0 <= 0) {
if (xa.range[0] < xa.range[1]) {
x0 = 0;
} else {
x0 = xa._length;
}
}
} else {
if (ya.type === 'log' && di.s0 <= 0) {
if (ya.range[0] < ya.range[1]) {
y0 = ya._length;
} else {
y0 = 0;
}
}
}
// Compute width and height of bar
var lx = Math.abs(x1 - x0);
var ly = Math.abs(y1 - y0);
// padding excluded
var barWidth = lx - 2 * TEXTPAD;
var barHeight = ly - 2 * TEXTPAD;
var textSelection;
var textBB;
var textWidth;
var textHeight;
var font;
if (textPosition === 'outside') {
if (!isOutmostBar && !calcBar.hasB) textPosition = 'inside';
}
if (textPosition === 'auto') {
if (isOutmostBar) {
// draw text using insideTextFont and check if it fits inside bar
textPosition = 'inside';
font = Lib.ensureUniformFontSize(gd, insideTextFont);
textSelection = appendTextNode(bar, text, font);
textBB = Drawing.bBox(textSelection.node());
textWidth = textBB.width;
textHeight = textBB.height;
var textHasSize = textWidth > 0 && textHeight > 0;
var fitsInside;
if (barIsRounded) {
// If bar is rounded, check if text fits between rounded corners
if (hasB) {
fitsInside = textfitsInsideBar(barWidth - 2 * r, barHeight, textWidth, textHeight, isHorizontal) || textfitsInsideBar(barWidth, barHeight - 2 * r, textWidth, textHeight, isHorizontal);
} else if (isHorizontal) {
fitsInside = textfitsInsideBar(barWidth - (r - overhead), barHeight, textWidth, textHeight, isHorizontal) || textfitsInsideBar(barWidth, barHeight - 2 * (r - overhead), textWidth, textHeight, isHorizontal);
} else {
fitsInside = textfitsInsideBar(barWidth, barHeight - (r - overhead), textWidth, textHeight, isHorizontal) || textfitsInsideBar(barWidth - 2 * (r - overhead), barHeight, textWidth, textHeight, isHorizontal);
}
} else {
fitsInside = textfitsInsideBar(barWidth, barHeight, textWidth, textHeight, isHorizontal);
}
if (textHasSize && fitsInside) {
textPosition = 'inside';
} else {
textPosition = 'outside';
textSelection.remove();
textSelection = null;
}
} else {
textPosition = 'inside';
}
}
if (!textSelection) {
font = Lib.ensureUniformFontSize(gd, textPosition === 'outside' ? outsideTextFont : insideTextFont);
textSelection = appendTextNode(bar, text, font);
var currentTransform = textSelection.attr('transform');
textSelection.attr('transform', '');
textBB = Drawing.bBox(textSelection.node()), textWidth = textBB.width, textHeight = textBB.height;
textSelection.attr('transform', currentTransform);
if (textWidth <= 0 || textHeight <= 0) {
textSelection.remove();
return;
}
}
var angle = trace.textangle;
// compute text transform
var transform, constrained;
if (textPosition === 'outside') {
constrained = trace.constraintext === 'both' || trace.constraintext === 'outside';
transform = toMoveOutsideBar(x0, x1, y0, y1, textBB, {
isHorizontal: isHorizontal,
constrained: constrained,
angle: angle
});
} else {
constrained = trace.constraintext === 'both' || trace.constraintext === 'inside';
transform = toMoveInsideBar(x0, x1, y0, y1, textBB, {
isHorizontal: isHorizontal,
constrained: constrained,
angle: angle,
anchor: insidetextanchor,
hasB: hasB,
r: r,
overhead: overhead
});
}
transform.fontSize = font.size;
recordMinTextSize(trace.type === 'histogram' ? 'bar' : trace.type, transform, fullLayout);
calcBar.transform = transform;
var s = transition(textSelection, fullLayout, opts, makeOnCompleteCallback);
Lib.setTransormAndDisplay(s, transform);
}
function textfitsInsideBar(barWidth, barHeight, textWidth, textHeight, isHorizontal) {
if (barWidth < 0 || barHeight < 0) return false;
var fitsInside = textWidth <= barWidth && textHeight <= barHeight;
var fitsInsideIfRotated = textWidth <= barHeight && textHeight <= barWidth;
var fitsInsideIfShrunk = isHorizontal ? barWidth >= textWidth * (barHeight / textHeight) : barHeight >= textHeight * (barWidth / textWidth);
return fitsInside || fitsInsideIfRotated || fitsInsideIfShrunk;
}
function getRotateFromAngle(angle) {
return angle === 'auto' ? 0 : angle;
}
function getRotatedTextSize(textBB, rotate) {
var a = Math.PI / 180 * rotate;
var absSin = Math.abs(Math.sin(a));
var absCos = Math.abs(Math.cos(a));
return {
x: textBB.width * absCos + textBB.height * absSin,
y: textBB.width * absSin + textBB.height * absCos
};
}
function toMoveInsideBar(x0, x1, y0, y1, textBB, opts) {
var isHorizontal = !!opts.isHorizontal;
var constrained = !!opts.constrained;
var angle = opts.angle || 0;
var anchor = opts.anchor;
var isEnd = anchor === 'end';
var isStart = anchor === 'start';
var leftToRight = opts.leftToRight || 0; // left: -1, center: 0, right: 1
var toRight = (leftToRight + 1) / 2;
var toLeft = 1 - toRight;
var hasB = opts.hasB;
var r = opts.r;
var overhead = opts.overhead;
var textWidth = textBB.width;
var textHeight = textBB.height;
var lx = Math.abs(x1 - x0);
var ly = Math.abs(y1 - y0);
// compute remaining space
var textpad = lx > 2 * TEXTPAD && ly > 2 * TEXTPAD ? TEXTPAD : 0;
lx -= 2 * textpad;
ly -= 2 * textpad;
var rotate = getRotateFromAngle(angle);
if (angle === 'auto' && !(textWidth <= lx && textHeight <= ly) && (textWidth > lx || textHeight > ly) && (!(textWidth > ly || textHeight > lx) || textWidth < textHeight !== lx < ly)) {
rotate += 90;
}
var t = getRotatedTextSize(textBB, rotate);
var scale, padForRounding;
// Scale text for rounded bars
if (r && r - overhead > TEXTPAD) {
var scaleAndPad = scaleTextForRoundedBar(x0, x1, y0, y1, t, r, overhead, isHorizontal, hasB);
scale = scaleAndPad.scale;
padForRounding = scaleAndPad.pad;
// Scale text for non-rounded bars
} else {
scale = 1;
if (constrained) {
scale = Math.min(1, lx / t.x, ly / t.y);
}
padForRounding = 0;
}
// compute text and target positions
var textX = textBB.left * toLeft + textBB.right * toRight;
var textY = (textBB.top + textBB.bottom) / 2;
var targetX = (x0 + TEXTPAD) * toLeft + (x1 - TEXTPAD) * toRight;
var targetY = (y0 + y1) / 2;
var anchorX = 0;
var anchorY = 0;
if (isStart || isEnd) {
var extrapad = (isHorizontal ? t.x : t.y) / 2;
if (r && (isEnd || hasB)) {
textpad += padForRounding;
}
var dir = isHorizontal ? dirSign(x0, x1) : dirSign(y0, y1);
if (isHorizontal) {
if (isStart) {
targetX = x0 + dir * textpad;
anchorX = -dir * extrapad;
} else {
targetX = x1 - dir * textpad;
anchorX = dir * extrapad;
}
} else {
if (isStart) {
targetY = y0 + dir * textpad;
anchorY = -dir * extrapad;
} else {
targetY = y1 - dir * textpad;
anchorY = dir * extrapad;
}
}
}
return {
textX: textX,
textY: textY,
targetX: targetX,
targetY: targetY,
anchorX: anchorX,
anchorY: anchorY,
scale: scale,
rotate: rotate
};
}
function scaleTextForRoundedBar(x0, x1, y0, y1, t, r, overhead, isHorizontal, hasB) {
var barWidth = Math.max(0, Math.abs(x1 - x0) - 2 * TEXTPAD);
var barHeight = Math.max(0, Math.abs(y1 - y0) - 2 * TEXTPAD);
var R = r - TEXTPAD;
var clippedR = overhead ? R - Math.sqrt(R * R - (R - overhead) * (R - overhead)) : R;
var rX = hasB ? R * 2 : isHorizontal ? R - overhead : 2 * clippedR;
var rY = hasB ? R * 2 : isHorizontal ? 2 * clippedR : R - overhead;
var a, b, c;
var scale, pad;
if (t.y / t.x >= barHeight / (barWidth - rX)) {
// Case 1 (Tall text)
scale = barHeight / t.y;
} else if (t.y / t.x <= (barHeight - rY) / barWidth) {
// Case 2 (Wide text)
scale = barWidth / t.x;
} else if (!hasB && isHorizontal) {
// Case 3a (Quadratic case, two side corners are rounded)
a = t.x * t.x + t.y * t.y / 4;
b = -2 * t.x * (barWidth - R) - t.y * (barHeight / 2 - R);
c = (barWidth - R) * (barWidth - R) + (barHeight / 2 - R) * (barHeight / 2 - R) - R * R;
scale = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
} else if (!hasB) {
// Case 3b (Quadratic case, two top/bottom corners are rounded)
a = t.x * t.x / 4 + t.y * t.y;
b = -t.x * (barWidth / 2 - R) - 2 * t.y * (barHeight - R);
c = (barWidth / 2 - R) * (barWidth / 2 - R) + (barHeight - R) * (barHeight - R) - R * R;
scale = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
} else {
// Case 4 (Quadratic case, all four corners are rounded)
a = (t.x * t.x + t.y * t.y) / 4;
b = -t.x * (barWidth / 2 - R) - t.y * (barHeight / 2 - R);
c = (barWidth / 2 - R) * (barWidth / 2 - R) + (barHeight / 2 - R) * (barHeight / 2 - R) - R * R;
scale = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
}
// Scale should not be larger than 1
scale = Math.min(1, scale);
if (isHorizontal) {
pad = Math.max(0, R - Math.sqrt(Math.max(0, R * R - (R - (barHeight - t.y * scale) / 2) * (R - (barHeight - t.y * scale) / 2))) - overhead);
} else {
pad = Math.max(0, R - Math.sqrt(Math.max(0, R * R - (R - (barWidth - t.x * scale) / 2) * (R - (barWidth - t.x * scale) / 2))) - overhead);
}
return {
scale: scale,
pad: pad
};
}
function toMoveOutsideBar(x0, x1, y0, y1, textBB, opts) {
var isHorizontal = !!opts.isHorizontal;
var constrained = !!opts.constrained;
var angle = opts.angle || 0;
var textWidth = textBB.width;
var textHeight = textBB.height;
var lx = Math.abs(x1 - x0);
var ly = Math.abs(y1 - y0);
var textpad;
// Keep the padding so the text doesn't sit right against
// the bars, but don't factor it into barWidth
if (isHorizontal) {
textpad = ly > 2 * TEXTPAD ? TEXTPAD : 0;
} else {
textpad = lx > 2 * TEXTPAD ? TEXTPAD : 0;
}
// compute rotate and scale
var scale = 1;
if (constrained) {
scale = isHorizontal ? Math.min(1, ly / textHeight) : Math.min(1, lx / textWidth);
}
var rotate = getRotateFromAngle(angle);
var t = getRotatedTextSize(textBB, rotate);
// compute text and target positions
var extrapad = (isHorizontal ? t.x : t.y) / 2;
var textX = (textBB.left + textBB.right) / 2;
var textY = (textBB.top + textBB.bottom) / 2;
var targetX = (x0 + x1) / 2;
var targetY = (y0 + y1) / 2;
var anchorX = 0;
var anchorY = 0;
var dir = isHorizontal ? dirSign(x1, x0) : dirSign(y0, y1);
if (isHorizontal) {
targetX = x1 - dir * textpad;
anchorX = dir * extrapad;
} else {
targetY = y1 + dir * textpad;
anchorY = -dir * extrapad;
}
return {
textX: textX,
textY: textY,
targetX: targetX,
targetY: targetY,
anchorX: anchorX,
anchorY: anchorY,
scale: scale,
rotate: rotate
};
}
function getText(fullLayout, cd, index, xa, ya) {
var trace = cd[0].trace;
var texttemplate = trace.texttemplate;
var value;
if (texttemplate) {
value = calcTexttemplate(fullLayout, cd, index, xa, ya);
} else if (trace.textinfo) {
value = calcTextinfo(cd, index, xa, ya);
} else {
value = helpers.getValue(trace.text, index);
}
return helpers.coerceString(attributeText, value);
}
function getTextPosition(trace, index) {
var value = helpers.getValue(trace.textposition, index);
return helpers.coerceEnumerated(attributeTextPosition, value);
}
function calcTexttemplate(fullLayout, cd, index, xa, ya) {
var trace = cd[0].trace;
var texttemplate = Lib.castOption(trace, index, 'texttemplate');
if (!texttemplate) return '';
var isHistogram = trace.type === 'histogram';
var isWaterfall = trace.type === 'waterfall';
var isFunnel = trace.type === 'funnel';
var isHorizontal = trace.orientation === 'h';
var pLetter, pAxis;
var vLetter, vAxis;
if (isHorizontal) {
pLetter = 'y';
pAxis = ya;
vLetter = 'x';
vAxis = xa;
} else {
pLetter = 'x';
pAxis = xa;
vLetter = 'y';
vAxis = ya;
}
function formatLabel(u) {
return tickText(pAxis, pAxis.c2l(u), true).text;
}
function formatNumber(v) {
return tickText(vAxis, vAxis.c2l(v), true).text;
}
var cdi = cd[index];
var obj = {};
obj.label = cdi.p;
obj.labelLabel = obj[pLetter + 'Label'] = formatLabel(cdi.p);
var tx = Lib.castOption(trace, cdi.i, 'text');
if (tx === 0 || tx) obj.text = tx;
obj.value = cdi.s;
obj.valueLabel = obj[vLetter + 'Label'] = formatNumber(cdi.s);
var pt = {};
appendArrayPointValue(pt, trace, cdi.i);
if (isHistogram || pt.x === undefined) pt.x = isHorizontal ? obj.value : obj.label;
if (isHistogram || pt.y === undefined) pt.y = isHorizontal ? obj.label : obj.value;
if (isHistogram || pt.xLabel === undefined) pt.xLabel = isHorizontal ? obj.valueLabel : obj.labelLabel;
if (isHistogram || pt.yLabel === undefined) pt.yLabel = isHorizontal ? obj.labelLabel : obj.valueLabel;
if (isWaterfall) {
obj.delta = +cdi.rawS || cdi.s;
obj.deltaLabel = formatNumber(obj.delta);
obj.final = cdi.v;
obj.finalLabel = formatNumber(obj.final);
obj.initial = obj.final - obj.delta;
obj.initialLabel = formatNumber(obj.initial);
}
if (isFunnel) {
obj.value = cdi.s;
obj.valueLabel = formatNumber(obj.value);
obj.percentInitial = cdi.begR;
obj.percentInitialLabel = Lib.formatPercent(cdi.begR);
obj.percentPrevious = cdi.difR;
obj.percentPreviousLabel = Lib.formatPercent(cdi.difR);
obj.percentTotal = cdi.sumR;
obj.percenTotalLabel = Lib.formatPercent(cdi.sumR);
}
var customdata = Lib.castOption(trace, cdi.i, 'customdata');
if (customdata) obj.customdata = customdata;
return Lib.texttemplateString(texttemplate, obj, fullLayout._d3locale, pt, obj, trace._meta || {});
}
function calcTextinfo(cd, index, xa, ya) {
var trace = cd[0].trace;
var isHorizontal = trace.orientation === 'h';
var isWaterfall = trace.type === 'waterfall';
var isFunnel = trace.type === 'funnel';
function formatLabel(u) {
var pAxis = isHorizontal ? ya : xa;
return tickText(pAxis, u, true).text;
}
function formatNumber(v) {
var sAxis = isHorizontal ? xa : ya;
return tickText(sAxis, +v, true).text;
}
var textinfo = trace.textinfo;
var cdi = cd[index];
var parts = textinfo.split('+');
var text = [];
var tx;
var hasFlag = function (flag) {
return parts.indexOf(flag) !== -1;
};
if (hasFlag('label')) {
text.push(formatLabel(cd[index].p));
}
if (hasFlag('text')) {
tx = Lib.castOption(trace, cdi.i, 'text');
if (tx === 0 || tx) text.push(tx);
}
if (isWaterfall) {
var delta = +cdi.rawS || cdi.s;
var final = cdi.v;
var initial = final - delta;
if (hasFlag('initial')) text.push(formatNumber(initial));
if (hasFlag('delta')) text.push(formatNumber(delta));
if (hasFlag('final')) text.push(formatNumber(final));
}
if (isFunnel) {
if (hasFlag('value')) text.push(formatNumber(cdi.s));
var nPercent = 0;
if (hasFlag('percent initial')) nPercent++;
if (hasFlag('percent previous')) nPercent++;
if (hasFlag('percent total')) nPercent++;
var hasMultiplePercents = nPercent > 1;
if (hasFlag('percent initial')) {
tx = Lib.formatPercent(cdi.begR);
if (hasMultiplePercents) tx += ' of initial';
text.push(tx);
}
if (hasFlag('percent previous')) {
tx = Lib.formatPercent(cdi.difR);
if (hasMultiplePercents) tx += ' of previous';
text.push(tx);
}
if (hasFlag('percent total')) {
tx = Lib.formatPercent(cdi.sumR);
if (hasMultiplePercents) tx += ' of total';
text.push(tx);
}
}
return text.join('
');
}
module.exports = {
plot: plot,
toMoveInsideBar: toMoveInsideBar
};
/***/ }),
/***/ 10512:
/***/ (function(module) {
"use strict";
module.exports = function selectPoints(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var trace = cd[0].trace;
var isFunnel = trace.type === 'funnel';
var isHorizontal = trace.orientation === 'h';
var selection = [];
var i;
if (selectionTester === false) {
// clear selection
for (i = 0; i < cd.length; i++) {
cd[i].selected = 0;
}
} else {
for (i = 0; i < cd.length; i++) {
var di = cd[i];
var ct = 'ct' in di ? di.ct : getCentroid(di, xa, ya, isHorizontal, isFunnel);
if (selectionTester.contains(ct, false, i, searchInfo)) {
selection.push({
pointNumber: i,
x: xa.c2d(di.x),
y: ya.c2d(di.y)
});
di.selected = 1;
} else {
di.selected = 0;
}
}
}
return selection;
};
function getCentroid(d, xa, ya, isHorizontal, isFunnel) {
var x0 = xa.c2p(isHorizontal ? d.s0 : d.p0, true);
var x1 = xa.c2p(isHorizontal ? d.s1 : d.p1, true);
var y0 = ya.c2p(isHorizontal ? d.p0 : d.s0, true);
var y1 = ya.c2p(isHorizontal ? d.p1 : d.s1, true);
if (isFunnel) {
return [(x0 + x1) / 2, (y0 + y1) / 2];
} else {
if (isHorizontal) {
return [x1, (y0 + y1) / 2];
} else {
return [(x0 + x1) / 2, y1];
}
}
}
/***/ }),
/***/ 28788:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = Sieve;
var distinctVals = (__webpack_require__(10923).distinctVals);
/**
* Helper class to sieve data from traces into bins
*
* @class
*
* @param {Array} traces
* Array of calculated traces
* @param {object} opts
* - @param {boolean} [sepNegVal]
* If true, then split data at the same position into a bar
* for positive values and another for negative values
* - @param {boolean} [overlapNoMerge]
* If true, then don't merge overlapping bars into a single bar
*/
function Sieve(traces, opts) {
this.traces = traces;
this.sepNegVal = opts.sepNegVal;
this.overlapNoMerge = opts.overlapNoMerge;
// for single-bin histograms - see histogram/calc
var width1 = Infinity;
var axLetter = opts.posAxis._id.charAt(0);
var positions = [];
for (var i = 0; i < traces.length; i++) {
var trace = traces[i];
for (var j = 0; j < trace.length; j++) {
var bar = trace[j];
var pos = bar.p;
if (pos === undefined) {
pos = bar[axLetter];
}
if (pos !== undefined) positions.push(pos);
}
if (trace[0] && trace[0].width1) {
width1 = Math.min(trace[0].width1, width1);
}
}
this.positions = positions;
var dv = distinctVals(positions);
this.distinctPositions = dv.vals;
if (dv.vals.length === 1 && width1 !== Infinity) this.minDiff = width1;else this.minDiff = Math.min(dv.minDiff, width1);
var type = (opts.posAxis || {}).type;
if (type === 'category' || type === 'multicategory') {
this.minDiff = 1;
}
this.binWidth = this.minDiff;
this.bins = {};
}
/**
* Sieve datum
*
* @method
* @param {number} position
* @param {number} value
* @returns {number} Previous bin value
*/
Sieve.prototype.put = function put(position, value) {
var label = this.getLabel(position, value);
var oldValue = this.bins[label] || 0;
this.bins[label] = oldValue + value;
return oldValue;
};
/**
* Get current bin value for a given datum
*
* @method
* @param {number} position Position of datum
* @param {number} [value] Value of datum
* (required if this.sepNegVal is true)
* @returns {number} Current bin value
*/
Sieve.prototype.get = function get(position, value) {
var label = this.getLabel(position, value);
return this.bins[label] || 0;
};
/**
* Get bin label for a given datum
*
* @method
* @param {number} position Position of datum
* @param {number} [value] Value of datum
* (required if this.sepNegVal is true)
* @returns {string} Bin label
* (prefixed with a 'v' if value is negative and this.sepNegVal is
* true; otherwise prefixed with '^')
*/
Sieve.prototype.getLabel = function getLabel(position, value) {
var prefix = value < 0 && this.sepNegVal ? 'v' : '^';
var label = this.overlapNoMerge ? position : Math.round(position / this.binWidth);
return prefix + label;
};
/***/ }),
/***/ 21212:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Color = __webpack_require__(9240);
var Drawing = __webpack_require__(49348);
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
var resizeText = (__webpack_require__(4096).resizeText);
var attributes = __webpack_require__(39788);
var attributeTextFont = attributes.textfont;
var attributeInsideTextFont = attributes.insidetextfont;
var attributeOutsideTextFont = attributes.outsidetextfont;
var helpers = __webpack_require__(17700);
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
};
}
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);
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)
};
}
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
};
/***/ }),
/***/ 37408:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Color = __webpack_require__(9240);
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var colorscaleDefaults = __webpack_require__(47280);
var coercePattern = (__webpack_require__(10923).coercePattern);
module.exports = function handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout) {
var markerColor = coerce('marker.color', defaultColor);
var hasMarkerColorscale = hasColorscale(traceIn, 'marker');
if (hasMarkerColorscale) {
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'marker.',
cLetter: 'c'
});
}
coerce('marker.line.color', Color.defaultLine);
if (hasColorscale(traceIn, 'marker.line')) {
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'marker.line.',
cLetter: 'c'
});
}
coerce('marker.line.width');
coerce('marker.opacity');
coercePattern(coerce, 'marker.pattern', markerColor, hasMarkerColorscale);
coerce('selected.marker.color');
coerce('unselected.marker.color');
};
/***/ }),
/***/ 4096:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
function resizeText(gd, gTrace, traceType) {
var fullLayout = gd._fullLayout;
var minSize = fullLayout['_' + traceType + 'Text_minsize'];
if (minSize) {
var shouldHide = fullLayout.uniformtext.mode === 'hide';
var selector;
switch (traceType) {
case 'funnelarea':
case 'pie':
case 'sunburst':
selector = 'g.slice';
break;
case 'treemap':
case 'icicle':
selector = 'g.slice, g.pathbar';
break;
default:
selector = 'g.points > g.point';
}
gTrace.selectAll(selector).each(function (d) {
var transform = d.transform;
if (transform) {
transform.scale = shouldHide && transform.hide ? 0 : minSize / transform.fontSize;
var el = d3.select(this).select('text');
Lib.setTransormAndDisplay(el, transform);
}
});
}
}
function recordMinTextSize(traceType,
// in
transform,
// inout
fullLayout // inout
) {
if (fullLayout.uniformtext.mode) {
var minKey = getMinKey(traceType);
var minSize = fullLayout.uniformtext.minsize;
var size = transform.scale * transform.fontSize;
transform.hide = size < minSize;
fullLayout[minKey] = fullLayout[minKey] || Infinity;
if (!transform.hide) {
fullLayout[minKey] = Math.min(fullLayout[minKey], Math.max(size, minSize));
}
}
}
function clearMinTextSize(traceType,
// in
fullLayout // inout
) {
var minKey = getMinKey(traceType);
fullLayout[minKey] = undefined;
}
function getMinKey(traceType) {
return '_' + traceType + 'Text_minsize';
}
module.exports = {
recordMinTextSize: recordMinTextSize,
clearMinTextSize: clearMinTextSize,
resizeText: resizeText
};
/***/ }),
/***/ 87024:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var extendFlat = (__webpack_require__(55016).extendFlat);
var scatterPolarAttrs = __webpack_require__(97736);
var barAttrs = __webpack_require__(39788);
module.exports = {
r: scatterPolarAttrs.r,
theta: scatterPolarAttrs.theta,
r0: scatterPolarAttrs.r0,
dr: scatterPolarAttrs.dr,
theta0: scatterPolarAttrs.theta0,
dtheta: scatterPolarAttrs.dtheta,
thetaunit: scatterPolarAttrs.thetaunit,
// orientation: {
// valType: 'enumerated',
// values: ['radial', 'angular'],
// editType: 'calc+clearAxisTypes',
// description: 'Sets the orientation of the bars.'
// },
base: extendFlat({}, barAttrs.base, {
description: ['Sets where the bar base is drawn (in radial axis units).', 'In *stack* barmode,', 'traces that set *base* will be excluded', 'and drawn in *overlay* mode instead.'].join(' ')
}),
offset: extendFlat({}, barAttrs.offset, {
description: ['Shifts the angular position where the bar is drawn', '(in *thetatunit* units).'].join(' ')
}),
width: extendFlat({}, barAttrs.width, {
description: ['Sets the bar angular width (in *thetaunit* units).'].join(' ')
}),
text: extendFlat({}, barAttrs.text, {
description: ['Sets hover text elements associated with each bar.', 'If a single string, the same string appears over all bars.', 'If an array of string, the items are mapped in order to the', 'this trace\'s coordinates.'].join(' ')
}),
hovertext: extendFlat({}, barAttrs.hovertext, {
description: 'Same as `text`.'
}),
// textposition: {},
// textfont: {},
// insidetextfont: {},
// outsidetextfont: {},
// constraintext: {},
// cliponaxis: extendFlat({}, barAttrs.cliponaxis, {dflt: false}),
marker: barPolarMarker(),
hoverinfo: scatterPolarAttrs.hoverinfo,
hovertemplate: hovertemplateAttrs(),
selected: barAttrs.selected,
unselected: barAttrs.unselected
// error_x (error_r, error_theta)
// error_y
};
function barPolarMarker() {
var marker = extendFlat({}, barAttrs.marker);
delete marker.cornerradius;
return marker;
}
/***/ }),
/***/ 3488:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var colorscaleCalc = __webpack_require__(60416);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var arraysToCalcdata = __webpack_require__(79224);
var setGroupPositions = (__webpack_require__(2616).setGroupPositions);
var calcSelection = __webpack_require__(62496);
var traceIs = (__webpack_require__(30364).traceIs);
var extendFlat = (__webpack_require__(10923).extendFlat);
function calc(gd, trace) {
var fullLayout = gd._fullLayout;
var subplotId = trace.subplot;
var radialAxis = fullLayout[subplotId].radialaxis;
var angularAxis = fullLayout[subplotId].angularaxis;
var rArray = radialAxis.makeCalcdata(trace, 'r');
var thetaArray = angularAxis.makeCalcdata(trace, 'theta');
var len = trace._length;
var cd = new Array(len);
// 'size' axis variables
var sArray = rArray;
// 'pos' axis variables
var pArray = thetaArray;
for (var i = 0; i < len; i++) {
cd[i] = {
p: pArray[i],
s: sArray[i]
};
}
// convert width and offset in 'c' coordinate,
// set 'c' value(s) in trace._width and trace._offset,
// to make Bar.crossTraceCalc "just work"
function d2c(attr) {
var val = trace[attr];
if (val !== undefined) {
trace['_' + attr] = isArrayOrTypedArray(val) ? angularAxis.makeCalcdata(trace, attr) : angularAxis.d2c(val, trace.thetaunit);
}
}
if (angularAxis.type === 'linear') {
d2c('width');
d2c('offset');
}
if (hasColorscale(trace, 'marker')) {
colorscaleCalc(gd, trace, {
vals: trace.marker.color,
containerStr: 'marker',
cLetter: 'c'
});
}
if (hasColorscale(trace, 'marker.line')) {
colorscaleCalc(gd, trace, {
vals: trace.marker.line.color,
containerStr: 'marker.line',
cLetter: 'c'
});
}
arraysToCalcdata(cd, trace);
calcSelection(cd, trace);
return cd;
}
function crossTraceCalc(gd, polarLayout, subplotId) {
var calcdata = gd.calcdata;
var barPolarCd = [];
for (var i = 0; i < calcdata.length; i++) {
var cdi = calcdata[i];
var trace = cdi[0].trace;
if (trace.visible === true && traceIs(trace, 'bar') && trace.subplot === subplotId) {
barPolarCd.push(cdi);
}
}
// to make _extremes is filled in correctly so that
// polar._subplot.radialAxis can get auotrange'd
// TODO clean up!
// I think we want to call getAutorange on polar.radialaxis
// NOT on polar._subplot.radialAxis
var rAxis = extendFlat({}, polarLayout.radialaxis, {
_id: 'x'
});
var aAxis = polarLayout.angularaxis;
setGroupPositions(gd, aAxis, rAxis, barPolarCd, {
mode: polarLayout.barmode,
norm: polarLayout.barnorm,
gap: polarLayout.bargap,
groupgap: polarLayout.bargroupgap
});
}
module.exports = {
calc: calc,
crossTraceCalc: crossTraceCalc
};
/***/ }),
/***/ 88272:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleRThetaDefaults = (__webpack_require__(36392).handleRThetaDefaults);
var handleStyleDefaults = __webpack_require__(37408);
var attributes = __webpack_require__(87024);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleRThetaDefaults(traceIn, traceOut, layout, coerce);
if (!len) {
traceOut.visible = false;
return;
}
// coerce('orientation', (traceOut.theta && !traceOut.r) ? 'angular' : 'radial');
coerce('thetaunit');
coerce('base');
coerce('offset');
coerce('width');
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
// var textPosition = coerce('textposition');
// var hasBoth = Array.isArray(textPosition) || textPosition === 'auto';
// var hasInside = hasBoth || textPosition === 'inside';
// var hasOutside = hasBoth || textPosition === 'outside';
// if(hasInside || hasOutside) {
// var textFont = coerceFont(coerce, 'textfont', layout.font);
// if(hasInside) coerceFont(coerce, 'insidetextfont', textFont);
// if(hasOutside) coerceFont(coerce, 'outsidetextfont', textFont);
// coerce('constraintext');
// coerce('selected.textfont.color');
// coerce('unselected.textfont.color');
// coerce('cliponaxis');
// }
handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout);
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 29916:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Fx = __webpack_require__(39184);
var Lib = __webpack_require__(10923);
var getTraceColor = (__webpack_require__(30284).getTraceColor);
var fillText = Lib.fillText;
var makeHoverPointText = (__webpack_require__(87116).makeHoverPointText);
var isPtInsidePolygon = (__webpack_require__(98852).isPtInsidePolygon);
module.exports = function hoverPoints(pointData, xval, yval) {
var cd = pointData.cd;
var trace = cd[0].trace;
var subplot = pointData.subplot;
var radialAxis = subplot.radialAxis;
var angularAxis = subplot.angularAxis;
var vangles = subplot.vangles;
var inboxFn = vangles ? isPtInsidePolygon : Lib.isPtInsideSector;
var maxHoverDistance = pointData.maxHoverDistance;
var period = angularAxis._period || 2 * Math.PI;
var rVal = Math.abs(radialAxis.g2p(Math.sqrt(xval * xval + yval * yval)));
var thetaVal = Math.atan2(yval, xval);
// polar.(x|y)axis.p2c doesn't get the reversed radial axis range case right
if (radialAxis.range[0] > radialAxis.range[1]) {
thetaVal += Math.PI;
}
var distFn = function (di) {
if (inboxFn(rVal, thetaVal, [di.rp0, di.rp1], [di.thetag0, di.thetag1], vangles)) {
return maxHoverDistance +
// add a little to the pseudo-distance for wider bars, so that like scatter,
// if you are over two overlapping bars, the narrower one wins.
Math.min(1, Math.abs(di.thetag1 - di.thetag0) / period) - 1 +
// add a gradient so hovering near the end of a
// bar makes it a little closer match
(di.rp1 - rVal) / (di.rp1 - di.rp0) - 1;
} else {
return Infinity;
}
};
Fx.getClosest(cd, distFn, pointData);
if (pointData.index === false) return;
var index = pointData.index;
var cdi = cd[index];
pointData.x0 = pointData.x1 = cdi.ct[0];
pointData.y0 = pointData.y1 = cdi.ct[1];
var _cdi = Lib.extendFlat({}, cdi, {
r: cdi.s,
theta: cdi.p
});
fillText(cdi, trace, pointData);
makeHoverPointText(_cdi, trace, subplot, pointData);
pointData.hovertemplate = trace.hovertemplate;
pointData.color = getTraceColor(trace, cdi);
pointData.xLabelVal = pointData.yLabelVal = undefined;
if (cdi.s < 0) {
pointData.idealAlign = 'left';
}
return [pointData];
};
/***/ }),
/***/ 11467:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'barpolar',
basePlotModule: __webpack_require__(18176),
categories: ['polar', 'bar', 'showLegend'],
attributes: __webpack_require__(87024),
layoutAttributes: __webpack_require__(69508),
supplyDefaults: __webpack_require__(88272),
supplyLayoutDefaults: __webpack_require__(8044),
calc: (__webpack_require__(3488).calc),
crossTraceCalc: (__webpack_require__(3488).crossTraceCalc),
plot: __webpack_require__(80696),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(94944),
style: (__webpack_require__(21212).style),
styleOnSelect: (__webpack_require__(21212).styleOnSelect),
hoverPoints: __webpack_require__(29916),
selectPoints: __webpack_require__(10512),
meta: {
hrName: 'bar_polar',
description: ['The data visualized by the radial span of the bars is set in `r`'
// 'if `orientation` is set to *radial* (the default)',
// 'and the labels are set in `theta`.',
// 'By setting `orientation` to *angular*, the roles are interchanged.'
].join(' ')
}
};
/***/ }),
/***/ 69508:
/***/ (function(module) {
"use strict";
module.exports = {
barmode: {
valType: 'enumerated',
values: ['stack', 'overlay'],
dflt: 'stack',
editType: 'calc',
description: ['Determines how bars at the same location coordinate', 'are displayed on the graph.', 'With *stack*, the bars are stacked on top of one another', 'With *overlay*, the bars are plotted over one another,', 'you might need to reduce *opacity* to see multiple bars.'].join(' ')
},
bargap: {
valType: 'number',
dflt: 0.1,
min: 0,
max: 1,
editType: 'calc',
description: ['Sets the gap between bars of', 'adjacent location coordinates.', 'Values are unitless, they represent fractions of the minimum difference', 'in bar positions in the data.'].join(' ')
}
};
/***/ }),
/***/ 8044:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attrs = __webpack_require__(69508);
module.exports = function (layoutIn, layoutOut, fullData) {
var subplotsDone = {};
var sp;
function coerce(attr, dflt) {
return Lib.coerce(layoutIn[sp] || {}, layoutOut[sp], attrs, attr, dflt);
}
for (var i = 0; i < fullData.length; i++) {
var trace = fullData[i];
if (trace.type === 'barpolar' && trace.visible === true) {
sp = trace.subplot;
if (!subplotsDone[sp]) {
coerce('barmode');
coerce('bargap');
subplotsDone[sp] = 1;
}
}
}
};
/***/ }),
/***/ 80696:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var helpers = __webpack_require__(98852);
module.exports = function plot(gd, subplot, cdbar) {
var isStatic = gd._context.staticPlot;
var xa = subplot.xaxis;
var ya = subplot.yaxis;
var radialAxis = subplot.radialAxis;
var angularAxis = subplot.angularAxis;
var pathFn = makePathFn(subplot);
var barLayer = subplot.layers.frontplot.select('g.barlayer');
Lib.makeTraceGroups(barLayer, cdbar, 'trace bars').each(function () {
var plotGroup = d3.select(this);
var pointGroup = Lib.ensureSingle(plotGroup, 'g', 'points');
var bars = pointGroup.selectAll('g.point').data(Lib.identity);
bars.enter().append('g').style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke').style('stroke-miterlimit', 2).classed('point', true);
bars.exit().remove();
bars.each(function (di) {
var bar = d3.select(this);
var rp0 = di.rp0 = radialAxis.c2p(di.s0);
var rp1 = di.rp1 = radialAxis.c2p(di.s1);
var thetag0 = di.thetag0 = angularAxis.c2g(di.p0);
var thetag1 = di.thetag1 = angularAxis.c2g(di.p1);
var dPath;
if (!isNumeric(rp0) || !isNumeric(rp1) || !isNumeric(thetag0) || !isNumeric(thetag1) || rp0 === rp1 || thetag0 === thetag1) {
// do not remove blank bars, to keep data-to-node
// mapping intact during radial drag, that we
// can skip calling _module.style during interactions
dPath = 'M0,0Z';
} else {
// this 'center' pt is used for selections and hover labels
var rg1 = radialAxis.c2g(di.s1);
var thetagMid = (thetag0 + thetag1) / 2;
di.ct = [xa.c2p(rg1 * Math.cos(thetagMid)), ya.c2p(rg1 * Math.sin(thetagMid))];
dPath = pathFn(rp0, rp1, thetag0, thetag1);
}
Lib.ensureSingle(bar, 'path').attr('d', dPath);
});
// clip plotGroup, when trace layer isn't clipped
Drawing.setClipUrl(plotGroup, subplot._hasClipOnAxisFalse ? subplot.clipIds.forTraces : null, gd);
});
};
function makePathFn(subplot) {
var cxx = subplot.cxx;
var cyy = subplot.cyy;
if (subplot.vangles) {
return function (r0, r1, _a0, _a1) {
var a0, a1;
if (Lib.angleDelta(_a0, _a1) > 0) {
a0 = _a0;
a1 = _a1;
} else {
a0 = _a1;
a1 = _a0;
}
var va0 = helpers.findEnclosingVertexAngles(a0, subplot.vangles)[0];
var va1 = helpers.findEnclosingVertexAngles(a1, subplot.vangles)[1];
var vaBar = [va0, (a0 + a1) / 2, va1];
return helpers.pathPolygonAnnulus(r0, r1, a0, a1, vaBar, cxx, cyy);
};
}
return function (r0, r1, a0, a1) {
return Lib.pathAnnulus(r0, r1, a0, a1, cxx, cyy);
};
}
/***/ }),
/***/ 12292:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var makeFillcolorAttr = __webpack_require__(94352);
var scatterAttrs = __webpack_require__(49992);
var barAttrs = __webpack_require__(39788);
var colorAttrs = __webpack_require__(51468);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var extendFlat = (__webpack_require__(55016).extendFlat);
var scatterMarkerAttrs = scatterAttrs.marker;
var scatterMarkerLineAttrs = scatterMarkerAttrs.line;
module.exports = {
y: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the y sample data or coordinates.', 'See overview for more info.'].join(' ')
},
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the x sample data or coordinates.', 'See overview for more info.'].join(' ')
},
x0: {
valType: 'any',
editType: 'calc+clearAxisTypes',
description: ['Sets the x coordinate for single-box traces', 'or the starting coordinate for multi-box traces', 'set using q1/median/q3.', 'See overview for more info.'].join(' ')
},
y0: {
valType: 'any',
editType: 'calc+clearAxisTypes',
description: ['Sets the y coordinate for single-box traces', 'or the starting coordinate for multi-box traces', 'set using q1/median/q3.', 'See overview for more info.'].join(' ')
},
dx: {
valType: 'number',
editType: 'calc',
description: ['Sets the x coordinate step for multi-box traces', 'set using q1/median/q3.'].join(' ')
},
dy: {
valType: 'number',
editType: 'calc',
description: ['Sets the y coordinate step for multi-box traces', 'set using q1/median/q3.'].join(' ')
},
xperiod: scatterAttrs.xperiod,
yperiod: scatterAttrs.yperiod,
xperiod0: scatterAttrs.xperiod0,
yperiod0: scatterAttrs.yperiod0,
xperiodalignment: scatterAttrs.xperiodalignment,
yperiodalignment: scatterAttrs.yperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
name: {
valType: 'string',
editType: 'calc+clearAxisTypes',
description: ['Sets the trace name.', 'The trace name appears as the legend item and on hover.', 'For box traces, the name will also be used for the position', 'coordinate, if `x` and `x0` (`y` and `y0` if horizontal) are', 'missing and the position axis is categorical'].join(' ')
},
q1: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the Quartile 1 values.', 'There should be as many items as the number of boxes desired.'].join(' ')
},
median: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the median values.', 'There should be as many items as the number of boxes desired.'].join(' ')
},
q3: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the Quartile 3 values.', 'There should be as many items as the number of boxes desired.'].join(' ')
},
lowerfence: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the lower fence values.', 'There should be as many items as the number of boxes desired.', 'This attribute has effect only under the q1/median/q3 signature.', 'If `lowerfence` is not provided but a sample (in `y` or `x`) is set,', 'we compute the lower as the last sample point below 1.5 times the IQR.'].join(' ')
},
upperfence: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the upper fence values.', 'There should be as many items as the number of boxes desired.', 'This attribute has effect only under the q1/median/q3 signature.', 'If `upperfence` is not provided but a sample (in `y` or `x`) is set,', 'we compute the upper as the last sample point above 1.5 times the IQR.'].join(' ')
},
notched: {
valType: 'boolean',
editType: 'calc',
description: ['Determines whether or not notches are drawn.', 'Notches displays a confidence interval around the median.', 'We compute the confidence interval as median +/- 1.57 * IQR / sqrt(N),', 'where IQR is the interquartile range and N is the sample size.', 'If two boxes\' notches do not overlap there is 95% confidence their medians differ.', 'See https://sites.google.com/site/davidsstatistics/home/notched-box-plots for more info.', 'Defaults to *false* unless `notchwidth` or `notchspan` is set.'].join(' ')
},
notchwidth: {
valType: 'number',
min: 0,
max: 0.5,
dflt: 0.25,
editType: 'calc',
description: ['Sets the width of the notches relative to', 'the box\' width.', 'For example, with 0, the notches are as wide as the box(es).'].join(' ')
},
notchspan: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the notch span from the boxes\' `median` values.', 'There should be as many items as the number of boxes desired.', 'This attribute has effect only under the q1/median/q3 signature.', 'If `notchspan` is not provided but a sample (in `y` or `x`) is set,', 'we compute it as 1.57 * IQR / sqrt(N),', 'where N is the sample size.'].join(' ')
},
// TODO
// maybe add
// - loweroutlierbound / upperoutlierbound
// - lowersuspectedoutlierbound / uppersuspectedoutlierbound
boxpoints: {
valType: 'enumerated',
values: ['all', 'outliers', 'suspectedoutliers', false],
editType: 'calc',
description: ['If *outliers*, only the sample points lying outside the whiskers', 'are shown', 'If *suspectedoutliers*, the outlier points are shown and', 'points either less than 4*Q1-3*Q3 or greater than 4*Q3-3*Q1', 'are highlighted (see `outliercolor`)', 'If *all*, all sample points are shown', 'If *false*, only the box(es) are shown with no sample points', 'Defaults to *suspectedoutliers* when `marker.outliercolor` or', '`marker.line.outliercolor` is set.', 'Defaults to *all* under the q1/median/q3 signature.', 'Otherwise defaults to *outliers*.'].join(' ')
},
jitter: {
valType: 'number',
min: 0,
max: 1,
editType: 'calc',
description: ['Sets the amount of jitter in the sample points drawn.', 'If *0*, the sample points align along the distribution axis.', 'If *1*, the sample points are drawn in a random jitter of width', 'equal to the width of the box(es).'].join(' ')
},
pointpos: {
valType: 'number',
min: -2,
max: 2,
editType: 'calc',
description: ['Sets the position of the sample points in relation to the box(es).', 'If *0*, the sample points are places over the center of the box(es).', 'Positive (negative) values correspond to positions to the', 'right (left) for vertical boxes and above (below) for horizontal boxes'].join(' ')
},
sdmultiple: {
valType: 'number',
min: 0,
editType: 'calc',
dflt: 1,
description: ['Scales the box size when sizemode=sd', 'Allowing boxes to be drawn across any stddev range', 'For example 1-stddev, 3-stddev, 5-stddev'].join(' ')
},
sizemode: {
valType: 'enumerated',
values: ['quartiles', 'sd'],
editType: 'calc',
dflt: 'quartiles',
description: ['Sets the upper and lower bound for the boxes', 'quartiles means box is drawn between Q1 and Q3', 'SD means the box is drawn between Mean +- Standard Deviation', 'Argument sdmultiple (default 1) to scale the box size', 'So it could be drawn 1-stddev, 3-stddev etc'].join(' ')
},
boxmean: {
valType: 'enumerated',
values: [true, 'sd', false],
editType: 'calc',
description: ['If *true*, the mean of the box(es)\' underlying distribution is', 'drawn as a dashed line inside the box(es).', 'If *sd* the standard deviation is also drawn.', 'Defaults to *true* when `mean` is set.', 'Defaults to *sd* when `sd` is set', 'Otherwise defaults to *false*.'].join(' ')
},
mean: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the mean values.', 'There should be as many items as the number of boxes desired.', 'This attribute has effect only under the q1/median/q3 signature.', 'If `mean` is not provided but a sample (in `y` or `x`) is set,', 'we compute the mean for each box using the sample values.'].join(' ')
},
sd: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the standard deviation values.', 'There should be as many items as the number of boxes desired.', 'This attribute has effect only under the q1/median/q3 signature.', 'If `sd` is not provided but a sample (in `y` or `x`) is set,', 'we compute the standard deviation for each box using the sample values.'].join(' ')
},
orientation: {
valType: 'enumerated',
values: ['v', 'h'],
editType: 'calc+clearAxisTypes',
description: ['Sets the orientation of the box(es).', 'If *v* (*h*), the distribution is visualized along', 'the vertical (horizontal).'].join(' ')
},
quartilemethod: {
valType: 'enumerated',
values: ['linear', 'exclusive', 'inclusive'],
dflt: 'linear',
editType: 'calc',
description: ['Sets the method used to compute the sample\'s Q1 and Q3 quartiles.', 'The *linear* method uses the 25th percentile for Q1 and 75th percentile for Q3', 'as computed using method #10 (listed on http://jse.amstat.org/v14n3/langford.html).', 'The *exclusive* method uses the median to divide the ordered dataset into two halves', 'if the sample is odd, it does not include the median in either half -', 'Q1 is then the median of the lower half and', 'Q3 the median of the upper half.', 'The *inclusive* method also uses the median to divide the ordered dataset into two halves', 'but if the sample is odd, it includes the median in both halves -', 'Q1 is then the median of the lower half and', 'Q3 the median of the upper half.'].join(' ')
},
width: {
valType: 'number',
min: 0,
dflt: 0,
editType: 'calc',
description: ['Sets the width of the box in data coordinate', 'If *0* (default value) the width is automatically selected based on the positions', 'of other box traces in the same subplot.'].join(' ')
},
marker: {
outliercolor: {
valType: 'color',
dflt: 'rgba(0, 0, 0, 0)',
editType: 'style',
description: 'Sets the color of the outlier sample points.'
},
symbol: extendFlat({}, scatterMarkerAttrs.symbol, {
arrayOk: false,
editType: 'plot'
}),
opacity: extendFlat({}, scatterMarkerAttrs.opacity, {
arrayOk: false,
dflt: 1,
editType: 'style'
}),
angle: extendFlat({}, scatterMarkerAttrs.angle, {
arrayOk: false,
editType: 'calc'
}),
size: extendFlat({}, scatterMarkerAttrs.size, {
arrayOk: false,
editType: 'calc'
}),
color: extendFlat({}, scatterMarkerAttrs.color, {
arrayOk: false,
editType: 'style'
}),
line: {
color: extendFlat({}, scatterMarkerLineAttrs.color, {
arrayOk: false,
dflt: colorAttrs.defaultLine,
editType: 'style'
}),
width: extendFlat({}, scatterMarkerLineAttrs.width, {
arrayOk: false,
dflt: 0,
editType: 'style'
}),
outliercolor: {
valType: 'color',
editType: 'style',
description: ['Sets the border line color of the outlier sample points.', 'Defaults to marker.color'].join(' ')
},
outlierwidth: {
valType: 'number',
min: 0,
dflt: 1,
editType: 'style',
description: ['Sets the border line width (in px) of the outlier sample points.'].join(' ')
},
editType: 'style'
},
editType: 'plot'
},
line: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the color of line bounding the box(es).'
},
width: {
valType: 'number',
min: 0,
dflt: 2,
editType: 'style',
description: 'Sets the width (in px) of line bounding the box(es).'
},
editType: 'plot'
},
fillcolor: makeFillcolorAttr(),
whiskerwidth: {
valType: 'number',
min: 0,
max: 1,
dflt: 0.5,
editType: 'calc',
description: ['Sets the width of the whiskers relative to', 'the box\' width.', 'For example, with 1, the whiskers are as wide as the box(es).'].join(' ')
},
showwhiskers: {
valType: 'boolean',
editType: 'calc',
description: ['Determines whether or not whiskers are visible.', 'Defaults to true for `sizemode` *quartiles*, false for *sd*.'].join(' ')
},
offsetgroup: barAttrs.offsetgroup,
alignmentgroup: barAttrs.alignmentgroup,
selected: {
marker: scatterAttrs.selected.marker,
editType: 'style'
},
unselected: {
marker: scatterAttrs.unselected.marker,
editType: 'style'
},
text: extendFlat({}, scatterAttrs.text, {
description: ['Sets the text elements associated with each sample value.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (x,y) coordinates.', 'To be seen, trace `hoverinfo` must contain a *text* flag.'].join(' ')
}),
hovertext: extendFlat({}, scatterAttrs.hovertext, {
description: 'Same as `text`.'
}),
hovertemplate: hovertemplateAttrs({
description: ['N.B. This only has an effect when hovering on points.'].join(' ')
}),
hoveron: {
valType: 'flaglist',
flags: ['boxes', 'points'],
dflt: 'boxes+points',
editType: 'style',
description: ['Do the hover effects highlight individual boxes ', 'or sample points or both?'].join(' ')
},
zorder: scatterAttrs.zorder
};
/***/ }),
/***/ 75816:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Axes = __webpack_require__(81536);
var alignPeriod = __webpack_require__(82260);
var Lib = __webpack_require__(10923);
var BADNUM = (__webpack_require__(41752).BADNUM);
var _ = Lib._;
module.exports = function calc(gd, trace) {
var fullLayout = gd._fullLayout;
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var cd = [];
// N.B. violin reuses same Box.calc
var numKey = trace.type === 'violin' ? '_numViolins' : '_numBoxes';
var i, j;
var valAxis, valLetter;
var posAxis, posLetter;
var hasPeriod;
if (trace.orientation === 'h') {
valAxis = xa;
valLetter = 'x';
posAxis = ya;
posLetter = 'y';
hasPeriod = !!trace.yperiodalignment;
} else {
valAxis = ya;
valLetter = 'y';
posAxis = xa;
posLetter = 'x';
hasPeriod = !!trace.xperiodalignment;
}
var allPosArrays = getPosArrays(trace, posLetter, posAxis, fullLayout[numKey]);
var posArray = allPosArrays[0];
var origPos = allPosArrays[1];
var dv = Lib.distinctVals(posArray, posAxis);
var posDistinct = dv.vals;
var dPos = dv.minDiff / 2;
// item in trace calcdata
var cdi;
// array of {v: v, i, i} sample pts
var pts;
// values of the `pts` array of objects
var boxVals;
// length of sample
var N;
// single sample point
var pt;
// single sample value
var v;
// filter function for outlier pts
// outlier definition based on http://www.physics.csbsju.edu/stats/box2.html
var ptFilterFn = (trace.boxpoints || trace.points) === 'all' ? Lib.identity : function (pt) {
return pt.v < cdi.lf || pt.v > cdi.uf;
};
if (trace._hasPreCompStats) {
var valArrayRaw = trace[valLetter];
var d2c = function (k) {
return valAxis.d2c((trace[k] || [])[i]);
};
var minVal = Infinity;
var maxVal = -Infinity;
for (i = 0; i < trace._length; i++) {
var posi = posArray[i];
if (!isNumeric(posi)) continue;
cdi = {};
cdi.pos = cdi[posLetter] = posi;
if (hasPeriod && origPos) {
cdi.orig_p = origPos[i]; // used by hover
}
cdi.q1 = d2c('q1');
cdi.med = d2c('median');
cdi.q3 = d2c('q3');
pts = [];
if (valArrayRaw && Lib.isArrayOrTypedArray(valArrayRaw[i])) {
for (j = 0; j < valArrayRaw[i].length; j++) {
v = valAxis.d2c(valArrayRaw[i][j]);
if (v !== BADNUM) {
pt = {
v: v,
i: [i, j]
};
arraysToCalcdata(pt, trace, [i, j]);
pts.push(pt);
}
}
}
cdi.pts = pts.sort(sortByVal);
boxVals = cdi[valLetter] = pts.map(extractVal);
N = boxVals.length;
if (cdi.med !== BADNUM && cdi.q1 !== BADNUM && cdi.q3 !== BADNUM && cdi.med >= cdi.q1 && cdi.q3 >= cdi.med) {
var lf = d2c('lowerfence');
cdi.lf = lf !== BADNUM && lf <= cdi.q1 ? lf : computeLowerFence(cdi, boxVals, N);
var uf = d2c('upperfence');
cdi.uf = uf !== BADNUM && uf >= cdi.q3 ? uf : computeUpperFence(cdi, boxVals, N);
var mean = d2c('mean');
cdi.mean = mean !== BADNUM ? mean : N ? Lib.mean(boxVals, N) : (cdi.q1 + cdi.q3) / 2;
var sd = d2c('sd');
cdi.sd = mean !== BADNUM && sd >= 0 ? sd : N ? Lib.stdev(boxVals, N, cdi.mean) : cdi.q3 - cdi.q1;
cdi.lo = computeLowerOutlierBound(cdi);
cdi.uo = computeUpperOutlierBound(cdi);
var ns = d2c('notchspan');
ns = ns !== BADNUM && ns > 0 ? ns : computeNotchSpan(cdi, N);
cdi.ln = cdi.med - ns;
cdi.un = cdi.med + ns;
var imin = cdi.lf;
var imax = cdi.uf;
if (trace.boxpoints && boxVals.length) {
imin = Math.min(imin, boxVals[0]);
imax = Math.max(imax, boxVals[N - 1]);
}
if (trace.notched) {
imin = Math.min(imin, cdi.ln);
imax = Math.max(imax, cdi.un);
}
cdi.min = imin;
cdi.max = imax;
} else {
Lib.warn(['Invalid input - make sure that q1 <= median <= q3', 'q1 = ' + cdi.q1, 'median = ' + cdi.med, 'q3 = ' + cdi.q3].join('\n'));
var v0;
if (cdi.med !== BADNUM) {
v0 = cdi.med;
} else if (cdi.q1 !== BADNUM) {
if (cdi.q3 !== BADNUM) v0 = (cdi.q1 + cdi.q3) / 2;else v0 = cdi.q1;
} else if (cdi.q3 !== BADNUM) {
v0 = cdi.q3;
} else {
v0 = 0;
}
// draw box as line segment
cdi.med = v0;
cdi.q1 = cdi.q3 = v0;
cdi.lf = cdi.uf = v0;
cdi.mean = cdi.sd = v0;
cdi.ln = cdi.un = v0;
cdi.min = cdi.max = v0;
}
minVal = Math.min(minVal, cdi.min);
maxVal = Math.max(maxVal, cdi.max);
cdi.pts2 = pts.filter(ptFilterFn);
cd.push(cdi);
}
trace._extremes[valAxis._id] = Axes.findExtremes(valAxis, [minVal, maxVal], {
padded: true
});
} else {
var valArray = valAxis.makeCalcdata(trace, valLetter);
var posBins = makeBins(posDistinct, dPos);
var pLen = posDistinct.length;
var ptsPerBin = initNestedArray(pLen);
// bin pts info per position bins
for (i = 0; i < trace._length; i++) {
v = valArray[i];
if (!isNumeric(v)) continue;
var n = Lib.findBin(posArray[i], posBins);
if (n >= 0 && n < pLen) {
pt = {
v: v,
i: i
};
arraysToCalcdata(pt, trace, i);
ptsPerBin[n].push(pt);
}
}
var minLowerNotch = Infinity;
var maxUpperNotch = -Infinity;
var quartilemethod = trace.quartilemethod;
var usesExclusive = quartilemethod === 'exclusive';
var usesInclusive = quartilemethod === 'inclusive';
// build calcdata trace items, one item per distinct position
for (i = 0; i < pLen; i++) {
if (ptsPerBin[i].length > 0) {
cdi = {};
cdi.pos = cdi[posLetter] = posDistinct[i];
pts = cdi.pts = ptsPerBin[i].sort(sortByVal);
boxVals = cdi[valLetter] = pts.map(extractVal);
N = boxVals.length;
cdi.min = boxVals[0];
cdi.max = boxVals[N - 1];
cdi.mean = Lib.mean(boxVals, N);
cdi.sd = Lib.stdev(boxVals, N, cdi.mean) * trace.sdmultiple;
cdi.med = Lib.interp(boxVals, 0.5);
if (N % 2 && (usesExclusive || usesInclusive)) {
var lower;
var upper;
if (usesExclusive) {
// do NOT include the median in either half
lower = boxVals.slice(0, N / 2);
upper = boxVals.slice(N / 2 + 1);
} else if (usesInclusive) {
// include the median in either half
lower = boxVals.slice(0, N / 2 + 1);
upper = boxVals.slice(N / 2);
}
cdi.q1 = Lib.interp(lower, 0.5);
cdi.q3 = Lib.interp(upper, 0.5);
} else {
cdi.q1 = Lib.interp(boxVals, 0.25);
cdi.q3 = Lib.interp(boxVals, 0.75);
}
// lower and upper fences
cdi.lf = computeLowerFence(cdi, boxVals, N);
cdi.uf = computeUpperFence(cdi, boxVals, N);
// lower and upper outliers bounds
cdi.lo = computeLowerOutlierBound(cdi);
cdi.uo = computeUpperOutlierBound(cdi);
// lower and upper notches
var mci = computeNotchSpan(cdi, N);
cdi.ln = cdi.med - mci;
cdi.un = cdi.med + mci;
minLowerNotch = Math.min(minLowerNotch, cdi.ln);
maxUpperNotch = Math.max(maxUpperNotch, cdi.un);
cdi.pts2 = pts.filter(ptFilterFn);
cd.push(cdi);
}
}
if (trace.notched && Lib.isTypedArray(valArray)) valArray = Array.from(valArray);
trace._extremes[valAxis._id] = Axes.findExtremes(valAxis, trace.notched ? valArray.concat([minLowerNotch, maxUpperNotch]) : valArray, {
padded: true
});
}
calcSelection(cd, trace);
if (cd.length > 0) {
cd[0].t = {
num: fullLayout[numKey],
dPos: dPos,
posLetter: posLetter,
valLetter: valLetter,
labels: {
med: _(gd, 'median:'),
min: _(gd, 'min:'),
q1: _(gd, 'q1:'),
q3: _(gd, 'q3:'),
max: _(gd, 'max:'),
mean: trace.boxmean === 'sd' || trace.sizemode === 'sd' ? _(gd, 'mean ± σ:').replace('σ', trace.sdmultiple === 1 ? 'σ' : trace.sdmultiple + 'σ') :
// displaying mean +- Nσ whilst supporting translations
_(gd, 'mean:'),
lf: _(gd, 'lower fence:'),
uf: _(gd, 'upper fence:')
}
};
fullLayout[numKey]++;
return cd;
} else {
return [{
t: {
empty: true
}
}];
}
};
// In vertical (horizontal) box plots:
// if no x (y) data, use x0 (y0), or name
// so if you want one box
// per trace, set x0 (y0) to the x (y) value or category for this trace
// (or set x (y) to a constant array matching y (x))
function getPosArrays(trace, posLetter, posAxis, num) {
var hasPosArray = (posLetter in trace);
var hasPos0 = (posLetter + '0' in trace);
var hasPosStep = ('d' + posLetter in trace);
if (hasPosArray || hasPos0 && hasPosStep) {
var origPos = posAxis.makeCalcdata(trace, posLetter);
var pos = alignPeriod(trace, posAxis, posLetter, origPos).vals;
return [pos, origPos];
}
var pos0;
if (hasPos0) {
pos0 = trace[posLetter + '0'];
} else if ('name' in trace && (posAxis.type === 'category' || isNumeric(trace.name) && ['linear', 'log'].indexOf(posAxis.type) !== -1 || Lib.isDateTime(trace.name) && posAxis.type === 'date')) {
pos0 = trace.name;
} else {
pos0 = num;
}
var pos0c = posAxis.type === 'multicategory' ? posAxis.r2c_just_indices(pos0) : posAxis.d2c(pos0, 0, trace[posLetter + 'calendar']);
var len = trace._length;
var out = new Array(len);
for (var i = 0; i < len; i++) out[i] = pos0c;
return [out];
}
function makeBins(x, dx) {
var len = x.length;
var bins = new Array(len + 1);
for (var i = 0; i < len; i++) {
bins[i] = x[i] - dx;
}
bins[len] = x[len - 1] + dx;
return bins;
}
function initNestedArray(len) {
var arr = new Array(len);
for (var i = 0; i < len; i++) {
arr[i] = [];
}
return arr;
}
var TRACE_TO_CALC = {
text: 'tx',
hovertext: 'htx'
};
function arraysToCalcdata(pt, trace, ptNumber) {
for (var k in TRACE_TO_CALC) {
if (Lib.isArrayOrTypedArray(trace[k])) {
if (Array.isArray(ptNumber)) {
if (Lib.isArrayOrTypedArray(trace[k][ptNumber[0]])) {
pt[TRACE_TO_CALC[k]] = trace[k][ptNumber[0]][ptNumber[1]];
}
} else {
pt[TRACE_TO_CALC[k]] = trace[k][ptNumber];
}
}
}
}
function calcSelection(cd, trace) {
if (Lib.isArrayOrTypedArray(trace.selectedpoints)) {
for (var i = 0; i < cd.length; i++) {
var pts = cd[i].pts || [];
var ptNumber2cdIndex = {};
for (var j = 0; j < pts.length; j++) {
ptNumber2cdIndex[pts[j].i] = j;
}
Lib.tagSelected(pts, trace, ptNumber2cdIndex);
}
}
}
function sortByVal(a, b) {
return a.v - b.v;
}
function extractVal(o) {
return o.v;
}
// last point below 1.5 * IQR
function computeLowerFence(cdi, boxVals, N) {
if (N === 0) return cdi.q1;
return Math.min(cdi.q1, boxVals[Math.min(Lib.findBin(2.5 * cdi.q1 - 1.5 * cdi.q3, boxVals, true) + 1, N - 1)]);
}
// last point above 1.5 * IQR
function computeUpperFence(cdi, boxVals, N) {
if (N === 0) return cdi.q3;
return Math.max(cdi.q3, boxVals[Math.max(Lib.findBin(2.5 * cdi.q3 - 1.5 * cdi.q1, boxVals), 0)]);
}
// 3 IQR below (don't clip to max/min,
// this is only for discriminating suspected & far outliers)
function computeLowerOutlierBound(cdi) {
return 4 * cdi.q1 - 3 * cdi.q3;
}
// 3 IQR above (don't clip to max/min,
// this is only for discriminating suspected & far outliers)
function computeUpperOutlierBound(cdi) {
return 4 * cdi.q3 - 3 * cdi.q1;
}
// 95% confidence intervals for median
function computeNotchSpan(cdi, N) {
if (N === 0) return 0;
return 1.57 * (cdi.q3 - cdi.q1) / Math.sqrt(N);
}
/***/ }),
/***/ 67872:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var Lib = __webpack_require__(10923);
var getAxisGroup = (__webpack_require__(76908).getAxisGroup);
var orientations = ['v', 'h'];
function crossTraceCalc(gd, plotinfo) {
var calcdata = gd.calcdata;
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
for (var i = 0; i < orientations.length; i++) {
var orientation = orientations[i];
var posAxis = orientation === 'h' ? ya : xa;
var boxList = [];
// make list of boxes / candlesticks
// For backward compatibility, candlesticks are treated as if they *are* box traces here
for (var j = 0; j < calcdata.length; j++) {
var cd = calcdata[j];
var t = cd[0].t;
var trace = cd[0].trace;
if (trace.visible === true && (trace.type === 'box' || trace.type === 'candlestick') && !t.empty && (trace.orientation || 'v') === orientation && trace.xaxis === xa._id && trace.yaxis === ya._id) {
boxList.push(j);
}
}
setPositionOffset('box', gd, boxList, posAxis);
}
}
function setPositionOffset(traceType, gd, boxList, posAxis) {
var calcdata = gd.calcdata;
var fullLayout = gd._fullLayout;
var axId = posAxis._id;
var axLetter = axId.charAt(0);
var i, j, calcTrace;
var pointList = [];
var shownPts = 0;
// make list of box points
for (i = 0; i < boxList.length; i++) {
calcTrace = calcdata[boxList[i]];
for (j = 0; j < calcTrace.length; j++) {
pointList.push(posAxis.c2l(calcTrace[j].pos, true));
shownPts += (calcTrace[j].pts2 || []).length;
}
}
if (!pointList.length) return;
// box plots - update dPos based on multiple traces
var boxdv = Lib.distinctVals(pointList);
if (posAxis.type === 'category' || posAxis.type === 'multicategory') {
boxdv.minDiff = 1;
}
var dPos0 = boxdv.minDiff / 2;
// check for forced minimum dtick
Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true);
var numKey = traceType === 'violin' ? '_numViolins' : '_numBoxes';
var numTotal = fullLayout[numKey];
var group = fullLayout[traceType + 'mode'] === 'group' && numTotal > 1;
var groupFraction = 1 - fullLayout[traceType + 'gap'];
var groupGapFraction = 1 - fullLayout[traceType + 'groupgap'];
for (i = 0; i < boxList.length; i++) {
calcTrace = calcdata[boxList[i]];
var trace = calcTrace[0].trace;
var t = calcTrace[0].t;
var width = trace.width;
var side = trace.side;
// position coordinate delta
var dPos;
// box half width;
var bdPos;
// box center offset
var bPos;
// half-width within which to accept hover for this box/violin
// always split the distance to the closest box/violin
var wHover;
if (width) {
dPos = bdPos = wHover = width / 2;
bPos = 0;
} else {
dPos = dPos0;
if (group) {
var groupId = getAxisGroup(fullLayout, posAxis._id) + trace.orientation;
var alignmentGroups = fullLayout._alignmentOpts[groupId] || {};
var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {};
var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length;
var num = nOffsetGroups || numTotal;
var shift = nOffsetGroups ? trace._offsetIndex : t.num;
bdPos = dPos * groupFraction * groupGapFraction / num;
bPos = 2 * dPos * (-0.5 + (shift + 0.5) / num) * groupFraction;
wHover = dPos * groupFraction / num;
} else {
bdPos = dPos * groupFraction * groupGapFraction;
bPos = 0;
wHover = dPos;
}
}
t.dPos = dPos;
t.bPos = bPos;
t.bdPos = bdPos;
t.wHover = wHover;
// box/violin-only value-space push value
var pushplus;
var pushminus;
// edge of box/violin
var edge = bPos + bdPos;
var edgeplus;
var edgeminus;
// value-space padding
var vpadplus;
var vpadminus;
// pixel-space padding
var ppadplus;
var ppadminus;
// do we add 5% of both sides (more logic for points beyond box/violin below)
var padded = Boolean(width);
// does this trace show points?
var hasPts = (trace.boxpoints || trace.points) && shownPts > 0;
if (side === 'positive') {
pushplus = dPos * (width ? 1 : 0.5);
edgeplus = edge;
pushminus = edgeplus = bPos;
} else if (side === 'negative') {
pushplus = edgeplus = bPos;
pushminus = dPos * (width ? 1 : 0.5);
edgeminus = edge;
} else {
pushplus = pushminus = dPos;
edgeplus = edgeminus = edge;
}
if (hasPts) {
var pointpos = trace.pointpos;
var jitter = trace.jitter;
var ms = trace.marker.size / 2;
var pp = 0;
if (pointpos + jitter >= 0) {
pp = edge * (pointpos + jitter);
if (pp > pushplus) {
// (++) beyond plus-value, use pp
padded = true;
ppadplus = ms;
vpadplus = pp;
} else if (pp > edgeplus) {
// (+), use push-value (it's bigger), but add px-pad
ppadplus = ms;
vpadplus = pushplus;
}
}
if (pp <= pushplus) {
// (->) fallback to push value
vpadplus = pushplus;
}
var pm = 0;
if (pointpos - jitter <= 0) {
pm = -edge * (pointpos - jitter);
if (pm > pushminus) {
// (--) beyond plus-value, use pp
padded = true;
ppadminus = ms;
vpadminus = pm;
} else if (pm > edgeminus) {
// (-), use push-value (it's bigger), but add px-pad
ppadminus = ms;
vpadminus = pushminus;
}
}
if (pm <= pushminus) {
// (<-) fallback to push value
vpadminus = pushminus;
}
} else {
vpadplus = pushplus;
vpadminus = pushminus;
}
var pos = new Array(calcTrace.length);
for (j = 0; j < calcTrace.length; j++) {
pos[j] = calcTrace[j].pos;
}
trace._extremes[axId] = Axes.findExtremes(posAxis, pos, {
padded: padded,
vpadminus: vpadminus,
vpadplus: vpadplus,
vpadLinearized: true,
// N.B. SVG px-space positive/negative
ppadminus: {
x: ppadminus,
y: ppadplus
}[axLetter],
ppadplus: {
x: ppadplus,
y: ppadminus
}[axLetter]
});
}
}
module.exports = {
crossTraceCalc: crossTraceCalc,
setPositionOffset: setPositionOffset
};
/***/ }),
/***/ 18024:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
var Color = __webpack_require__(9240);
var handlePeriodDefaults = __webpack_require__(98632);
var handleGroupingDefaults = __webpack_require__(8584);
var autoType = __webpack_require__(30948);
var attributes = __webpack_require__(12292);
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
handleSampleDefaults(traceIn, traceOut, coerce, layout);
if (traceOut.visible === false) return;
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');
var hasPreCompStats = traceOut._hasPreCompStats;
if (hasPreCompStats) {
coerce('lowerfence');
coerce('upperfence');
}
coerce('line.color', (traceIn.marker || {}).color || defaultColor);
coerce('line.width');
coerce('fillcolor', Color.addOpacity(traceOut.line.color, 0.5));
var boxmeanDflt = false;
if (hasPreCompStats) {
var mean = coerce('mean');
var sd = coerce('sd');
if (mean && mean.length) {
boxmeanDflt = true;
if (sd && sd.length) boxmeanDflt = 'sd';
}
}
coerce('whiskerwidth');
var sizemode = coerce('sizemode');
var boxmean;
if (sizemode === 'quartiles') {
boxmean = coerce('boxmean', boxmeanDflt);
}
coerce('showwhiskers', sizemode === 'quartiles');
if (sizemode === 'sd' || boxmean === 'sd') {
coerce('sdmultiple');
}
coerce('width');
coerce('quartilemethod');
var notchedDflt = false;
if (hasPreCompStats) {
var notchspan = coerce('notchspan');
if (notchspan && notchspan.length) {
notchedDflt = true;
}
} else if (Lib.validate(traceIn.notchwidth, attributes.notchwidth)) {
notchedDflt = true;
}
var notched = coerce('notched', notchedDflt);
if (notched) coerce('notchwidth');
handlePointsDefaults(traceIn, traceOut, coerce, {
prefix: 'box'
});
coerce('zorder');
}
function handleSampleDefaults(traceIn, traceOut, coerce, layout) {
function getDims(arr) {
var dims = 0;
if (arr && arr.length) {
dims += 1;
if (Lib.isArrayOrTypedArray(arr[0]) && arr[0].length) {
dims += 1;
}
}
return dims;
}
function valid(astr) {
return Lib.validate(traceIn[astr], attributes[astr]);
}
var y = coerce('y');
var x = coerce('x');
var sLen;
if (traceOut.type === 'box') {
var q1 = coerce('q1');
var median = coerce('median');
var q3 = coerce('q3');
traceOut._hasPreCompStats = q1 && q1.length && median && median.length && q3 && q3.length;
sLen = Math.min(Lib.minRowLength(q1), Lib.minRowLength(median), Lib.minRowLength(q3));
}
var yDims = getDims(y);
var xDims = getDims(x);
var yLen = yDims && Lib.minRowLength(y);
var xLen = xDims && Lib.minRowLength(x);
var calendar = layout.calendar;
var opts = {
autotypenumbers: layout.autotypenumbers
};
var defaultOrientation, len;
if (traceOut._hasPreCompStats) {
switch (String(xDims) + String(yDims)) {
// no x / no y
case '00':
var setInX = valid('x0') || valid('dx');
var setInY = valid('y0') || valid('dy');
if (setInY && !setInX) {
defaultOrientation = 'h';
} else {
defaultOrientation = 'v';
}
len = sLen;
break;
// just x
case '10':
defaultOrientation = 'v';
len = Math.min(sLen, xLen);
break;
case '20':
defaultOrientation = 'h';
len = Math.min(sLen, x.length);
break;
// just y
case '01':
defaultOrientation = 'h';
len = Math.min(sLen, yLen);
break;
case '02':
defaultOrientation = 'v';
len = Math.min(sLen, y.length);
break;
// both
case '12':
defaultOrientation = 'v';
len = Math.min(sLen, xLen, y.length);
break;
case '21':
defaultOrientation = 'h';
len = Math.min(sLen, x.length, yLen);
break;
case '11':
// this one is ill-defined
len = 0;
break;
case '22':
var hasCategories = false;
var i;
for (i = 0; i < x.length; i++) {
if (autoType(x[i], calendar, opts) === 'category') {
hasCategories = true;
break;
}
}
if (hasCategories) {
defaultOrientation = 'v';
len = Math.min(sLen, xLen, y.length);
} else {
for (i = 0; i < y.length; i++) {
if (autoType(y[i], calendar, opts) === 'category') {
hasCategories = true;
break;
}
}
if (hasCategories) {
defaultOrientation = 'h';
len = Math.min(sLen, x.length, yLen);
} else {
defaultOrientation = 'v';
len = Math.min(sLen, xLen, y.length);
}
}
break;
}
} else if (yDims > 0) {
defaultOrientation = 'v';
if (xDims > 0) {
len = Math.min(xLen, yLen);
} else {
len = Math.min(yLen);
}
} else if (xDims > 0) {
defaultOrientation = 'h';
len = Math.min(xLen);
} else {
len = 0;
}
if (!len) {
traceOut.visible = false;
return;
}
traceOut._length = len;
var orientation = coerce('orientation', defaultOrientation);
// these are just used for positioning, they never define the sample
if (traceOut._hasPreCompStats) {
if (orientation === 'v' && xDims === 0) {
coerce('x0', 0);
coerce('dx', 1);
} else if (orientation === 'h' && yDims === 0) {
coerce('y0', 0);
coerce('dy', 1);
}
} else {
if (orientation === 'v' && xDims === 0) {
coerce('x0');
} else if (orientation === 'h' && yDims === 0) {
coerce('y0');
}
}
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x', 'y'], layout);
}
function handlePointsDefaults(traceIn, traceOut, coerce, opts) {
var prefix = opts.prefix;
var outlierColorDflt = Lib.coerce2(traceIn, traceOut, attributes, 'marker.outliercolor');
var lineoutliercolor = coerce('marker.line.outliercolor');
var modeDflt = 'outliers';
if (traceOut._hasPreCompStats) {
modeDflt = 'all';
} else if (outlierColorDflt || lineoutliercolor) {
modeDflt = 'suspectedoutliers';
}
var mode = coerce(prefix + 'points', modeDflt);
if (mode) {
coerce('jitter', mode === 'all' ? 0.3 : 0);
coerce('pointpos', mode === 'all' ? -1.5 : 0);
coerce('marker.symbol');
coerce('marker.opacity');
coerce('marker.size');
coerce('marker.angle');
coerce('marker.color', traceOut.line.color);
coerce('marker.line.color');
coerce('marker.line.width');
if (mode === 'suspectedoutliers') {
coerce('marker.line.outliercolor', traceOut.marker.color);
coerce('marker.line.outlierwidth');
}
coerce('selected.marker.color');
coerce('unselected.marker.color');
coerce('selected.marker.size');
coerce('unselected.marker.size');
coerce('text');
coerce('hovertext');
} else {
delete traceOut.marker;
}
var hoveron = coerce('hoveron');
if (hoveron === 'all' || hoveron.indexOf('points') !== -1) {
coerce('hovertemplate');
}
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
}
function crossTraceDefaults(fullData, fullLayout) {
var traceIn, traceOut;
function coerce(attr) {
return Lib.coerce(traceOut._input, traceOut, attributes, attr);
}
for (var i = 0; i < fullData.length; i++) {
traceOut = fullData[i];
var traceType = traceOut.type;
if (traceType === 'box' || traceType === 'violin') {
traceIn = traceOut._input;
if (fullLayout[traceType + 'mode'] === 'group') {
handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce);
}
}
}
}
module.exports = {
supplyDefaults: supplyDefaults,
crossTraceDefaults: crossTraceDefaults,
handleSampleDefaults: handleSampleDefaults,
handlePointsDefaults: handlePointsDefaults
};
/***/ }),
/***/ 56456:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt) {
// Note: hoverOnBox property is needed for click-to-select
// to ignore when a box was clicked. This is the reason box
// implements this custom eventData function.
if (pt.hoverOnBox) out.hoverOnBox = pt.hoverOnBox;
if ('xVal' in pt) out.x = pt.xVal;
if ('yVal' in pt) out.y = pt.yVal;
if (pt.xa) out.xaxis = pt.xa;
if (pt.ya) out.yaxis = pt.ya;
return out;
};
/***/ }),
/***/ 69616:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var Lib = __webpack_require__(10923);
var Fx = __webpack_require__(39184);
var Color = __webpack_require__(9240);
var fillText = Lib.fillText;
function hoverPoints(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var trace = cd[0].trace;
var hoveron = trace.hoveron;
var closeBoxData = [];
var closePtData;
if (hoveron.indexOf('boxes') !== -1) {
closeBoxData = closeBoxData.concat(hoverOnBoxes(pointData, xval, yval, hovermode));
}
if (hoveron.indexOf('points') !== -1) {
closePtData = hoverOnPoints(pointData, xval, yval);
}
// If there's a point in range and hoveron has points, show the best single point only.
// If hoveron has boxes and there's no point in range (or hoveron doesn't have points), show the box stats.
if (hovermode === 'closest') {
if (closePtData) return [closePtData];
return closeBoxData;
}
// Otherwise in compare mode, allow a point AND the box stats to be labeled
// If there are multiple boxes in range (ie boxmode = 'overlay') we'll see stats for all of them.
if (closePtData) {
closeBoxData.push(closePtData);
return closeBoxData;
}
return closeBoxData;
}
function hoverOnBoxes(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var xa = pointData.xa;
var ya = pointData.ya;
var trace = cd[0].trace;
var t = cd[0].t;
var isViolin = trace.type === 'violin';
var pLetter, vLetter, pAxis, vAxis, vVal, pVal, dx, dy, dPos, hoverPseudoDistance, spikePseudoDistance;
var boxDelta = t.bdPos;
var boxDeltaPos, boxDeltaNeg;
var posAcceptance = t.wHover;
var shiftPos = function (di) {
return pAxis.c2l(di.pos) + t.bPos - pAxis.c2l(pVal);
};
if (isViolin && trace.side !== 'both') {
if (trace.side === 'positive') {
dPos = function (di) {
var pos = shiftPos(di);
return Fx.inbox(pos, pos + posAcceptance, hoverPseudoDistance);
};
boxDeltaPos = boxDelta;
boxDeltaNeg = 0;
}
if (trace.side === 'negative') {
dPos = function (di) {
var pos = shiftPos(di);
return Fx.inbox(pos - posAcceptance, pos, hoverPseudoDistance);
};
boxDeltaPos = 0;
boxDeltaNeg = boxDelta;
}
} else {
dPos = function (di) {
var pos = shiftPos(di);
return Fx.inbox(pos - posAcceptance, pos + posAcceptance, hoverPseudoDistance);
};
boxDeltaPos = boxDeltaNeg = boxDelta;
}
var dVal;
if (isViolin) {
dVal = function (di) {
return Fx.inbox(di.span[0] - vVal, di.span[1] - vVal, hoverPseudoDistance);
};
} else {
dVal = function (di) {
return Fx.inbox(di.min - vVal, di.max - vVal, hoverPseudoDistance);
};
}
if (trace.orientation === 'h') {
vVal = xval;
pVal = yval;
dx = dVal;
dy = dPos;
pLetter = 'y';
pAxis = ya;
vLetter = 'x';
vAxis = xa;
} else {
vVal = yval;
pVal = xval;
dx = dPos;
dy = dVal;
pLetter = 'x';
pAxis = xa;
vLetter = 'y';
vAxis = ya;
}
// if two boxes are overlaying, let the narrowest one win
var pseudoDistance = Math.min(1, boxDelta / Math.abs(pAxis.r2c(pAxis.range[1]) - pAxis.r2c(pAxis.range[0])));
hoverPseudoDistance = pointData.maxHoverDistance - pseudoDistance;
spikePseudoDistance = pointData.maxSpikeDistance - pseudoDistance;
function dxy(di) {
return (dx(di) + dy(di)) / 2;
}
var distfn = Fx.getDistanceFunction(hovermode, dx, dy, dxy);
Fx.getClosest(cd, distfn, pointData);
// skip the rest (for this trace) if we didn't find a close point
// and create the item(s) in closedata for this point
if (pointData.index === false) return [];
var di = cd[pointData.index];
var lc = trace.line.color;
var mc = (trace.marker || {}).color;
if (Color.opacity(lc) && trace.line.width) pointData.color = lc;else if (Color.opacity(mc) && trace.boxpoints) pointData.color = mc;else pointData.color = trace.fillcolor;
pointData[pLetter + '0'] = pAxis.c2p(di.pos + t.bPos - boxDeltaNeg, true);
pointData[pLetter + '1'] = pAxis.c2p(di.pos + t.bPos + boxDeltaPos, true);
pointData[pLetter + 'LabelVal'] = di.orig_p !== undefined ? di.orig_p : di.pos;
var spikePosAttr = pLetter + 'Spike';
pointData.spikeDistance = dxy(di) * spikePseudoDistance / hoverPseudoDistance;
pointData[spikePosAttr] = pAxis.c2p(di.pos, true);
var hasMean = trace.boxmean || trace.sizemode === 'sd' || (trace.meanline || {}).visible;
var hasFences = trace.boxpoints || trace.points;
// labels with equal values (e.g. when min === q1) should still be presented in the order they have when they're unequal
var attrs = hasFences && hasMean ? ['max', 'uf', 'q3', 'med', 'mean', 'q1', 'lf', 'min'] : hasFences && !hasMean ? ['max', 'uf', 'q3', 'med', 'q1', 'lf', 'min'] : !hasFences && hasMean ? ['max', 'q3', 'med', 'mean', 'q1', 'min'] : ['max', 'q3', 'med', 'q1', 'min'];
var rev = vAxis.range[1] < vAxis.range[0];
if (trace.orientation === (rev ? 'v' : 'h')) {
attrs.reverse();
}
var spikeDistance = pointData.spikeDistance;
var spikePosition = pointData[spikePosAttr];
var closeBoxData = [];
for (var i = 0; i < attrs.length; i++) {
var attr = attrs[i];
if (!(attr in di)) continue;
// copy out to a new object for each value to label
var val = di[attr];
var valPx = vAxis.c2p(val, true);
var pointData2 = Lib.extendFlat({}, pointData);
pointData2.attr = attr;
pointData2[vLetter + '0'] = pointData2[vLetter + '1'] = valPx;
pointData2[vLetter + 'LabelVal'] = val;
pointData2[vLetter + 'Label'] = (t.labels ? t.labels[attr] + ' ' : '') + Axes.hoverLabelText(vAxis, val, trace[vLetter + 'hoverformat']);
// Note: introduced to be able to distinguish a
// clicked point from a box during click-to-select
pointData2.hoverOnBox = true;
if (attr === 'mean' && 'sd' in di && (trace.boxmean === 'sd' || trace.sizemode === 'sd')) {
pointData2[vLetter + 'err'] = di.sd;
}
// no hovertemplate support yet
pointData2.hovertemplate = false;
closeBoxData.push(pointData2);
}
// only keep name and spikes on the median
pointData.name = '';
pointData.spikeDistance = undefined;
pointData[spikePosAttr] = undefined;
for (var k = 0; k < closeBoxData.length; k++) {
if (closeBoxData[k].attr !== 'med') {
closeBoxData[k].name = '';
closeBoxData[k].spikeDistance = undefined;
closeBoxData[k][spikePosAttr] = undefined;
} else {
closeBoxData[k].spikeDistance = spikeDistance;
closeBoxData[k][spikePosAttr] = spikePosition;
}
}
return closeBoxData;
}
function hoverOnPoints(pointData, xval, yval) {
var cd = pointData.cd;
var xa = pointData.xa;
var ya = pointData.ya;
var trace = cd[0].trace;
var xPx = xa.c2p(xval);
var yPx = ya.c2p(yval);
var closePtData;
var dx = function (di) {
var rad = Math.max(3, di.mrc || 0);
return Math.max(Math.abs(xa.c2p(di.x) - xPx) - rad, 1 - 3 / rad);
};
var dy = function (di) {
var rad = Math.max(3, di.mrc || 0);
return Math.max(Math.abs(ya.c2p(di.y) - yPx) - rad, 1 - 3 / rad);
};
var distfn = Fx.quadrature(dx, dy);
// show one point per trace
var ijClosest = false;
var di, pt;
for (var i = 0; i < cd.length; i++) {
di = cd[i];
for (var j = 0; j < (di.pts || []).length; j++) {
pt = di.pts[j];
var newDistance = distfn(pt);
if (newDistance <= pointData.distance) {
pointData.distance = newDistance;
ijClosest = [i, j];
}
}
}
if (!ijClosest) return false;
di = cd[ijClosest[0]];
pt = di.pts[ijClosest[1]];
var xc = xa.c2p(pt.x, true);
var yc = ya.c2p(pt.y, true);
var rad = pt.mrc || 1;
closePtData = Lib.extendFlat({}, pointData, {
// corresponds to index in x/y input data array
index: pt.i,
color: (trace.marker || {}).color,
name: trace.name,
x0: xc - rad,
x1: xc + rad,
y0: yc - rad,
y1: yc + rad,
spikeDistance: pointData.distance,
hovertemplate: trace.hovertemplate
});
var origPos = di.orig_p;
var pos = origPos !== undefined ? origPos : di.pos;
var pa;
if (trace.orientation === 'h') {
pa = ya;
closePtData.xLabelVal = pt.x;
closePtData.yLabelVal = pos;
} else {
pa = xa;
closePtData.xLabelVal = pos;
closePtData.yLabelVal = pt.y;
}
var pLetter = pa._id.charAt(0);
closePtData[pLetter + 'Spike'] = pa.c2p(di.pos, true);
fillText(pt, trace, closePtData);
return closePtData;
}
module.exports = {
hoverPoints: hoverPoints,
hoverOnBoxes: hoverOnBoxes,
hoverOnPoints: hoverOnPoints
};
/***/ }),
/***/ 9256:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(12292),
layoutAttributes: __webpack_require__(62352),
supplyDefaults: (__webpack_require__(18024).supplyDefaults),
crossTraceDefaults: (__webpack_require__(18024).crossTraceDefaults),
supplyLayoutDefaults: (__webpack_require__(15428).supplyLayoutDefaults),
calc: __webpack_require__(75816),
crossTraceCalc: (__webpack_require__(67872).crossTraceCalc),
plot: (__webpack_require__(46448).plot),
style: (__webpack_require__(11384).style),
styleOnSelect: (__webpack_require__(11384).styleOnSelect),
hoverPoints: (__webpack_require__(69616).hoverPoints),
eventData: __webpack_require__(56456),
selectPoints: __webpack_require__(5496),
moduleType: 'trace',
name: 'box',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', 'symbols', 'oriented', 'box-violin', 'showLegend', 'boxLayout', 'zoomScale'],
meta: {
description: ['Each box spans from quartile 1 (Q1) to quartile 3 (Q3).', 'The second quartile (Q2, i.e. the median) is marked by a line inside the box.', 'The fences grow outward from the boxes\' edges,', 'by default they span +/- 1.5 times the interquartile range (IQR: Q3-Q1),', 'The sample mean and standard deviation as well as notches and', 'the sample, outlier and suspected outliers points can be optionally', 'added to the box plot.', 'The values and positions corresponding to each boxes can be input', 'using two signatures.', 'The first signature expects users to supply the sample values in the `y`', 'data array for vertical boxes (`x` for horizontal boxes).', 'By supplying an `x` (`y`) array, one box per distinct `x` (`y`) value is drawn', 'If no `x` (`y`) {array} is provided, a single box is drawn.', 'In this case, the box is positioned with the trace `name` or with `x0` (`y0`) if provided.', 'The second signature expects users to supply the boxes corresponding Q1, median and Q3', 'statistics in the `q1`, `median` and `q3` data arrays respectively.', 'Other box features relying on statistics namely `lowerfence`, `upperfence`, `notchspan`', 'can be set directly by the users.', 'To have plotly compute them or to show sample points besides the boxes,', 'users can set the `y` data array for vertical boxes (`x` for horizontal boxes)', 'to a 2D array with the outer length corresponding', 'to the number of boxes in the traces and the inner length corresponding the sample size.'].join(' ')
}
};
/***/ }),
/***/ 62352:
/***/ (function(module) {
"use strict";
module.exports = {
boxmode: {
valType: 'enumerated',
values: ['group', 'overlay'],
dflt: 'overlay',
editType: 'calc',
description: ['Determines how boxes at the same location coordinate', 'are displayed on the graph.', 'If *group*, the boxes are plotted next to one another', 'centered around the shared location.', 'If *overlay*, the boxes are plotted over one another,', 'you might need to set *opacity* to see them multiple boxes.', 'Has no effect on traces that have *width* set.'].join(' ')
},
boxgap: {
valType: 'number',
min: 0,
max: 1,
dflt: 0.3,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between boxes of', 'adjacent location coordinates.', 'Has no effect on traces that have *width* set.'].join(' ')
},
boxgroupgap: {
valType: 'number',
min: 0,
max: 1,
dflt: 0.3,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between boxes of', 'the same location coordinate.', 'Has no effect on traces that have *width* set.'].join(' ')
}
};
/***/ }),
/***/ 15428:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(62352);
function _supply(layoutIn, layoutOut, fullData, coerce, traceType) {
var category = traceType + 'Layout';
var hasTraceType = false;
for (var i = 0; i < fullData.length; i++) {
var trace = fullData[i];
if (Registry.traceIs(trace, category)) {
hasTraceType = true;
break;
}
}
if (!hasTraceType) return;
coerce(traceType + 'mode');
coerce(traceType + 'gap');
coerce(traceType + 'groupgap');
}
function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
_supply(layoutIn, layoutOut, fullData, coerce, 'box');
}
module.exports = {
supplyLayoutDefaults: supplyLayoutDefaults,
_supply: _supply
};
/***/ }),
/***/ 46448:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
// constants for dynamic jitter (ie less jitter for sparser points)
var JITTERCOUNT = 5; // points either side of this to include
var JITTERSPREAD = 0.01; // fraction of IQR to count as "dense"
function plot(gd, plotinfo, cdbox, boxLayer) {
var isStatic = gd._context.staticPlot;
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
Lib.makeTraceGroups(boxLayer, cdbox, 'trace boxes').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var t = cd0.t;
var trace = cd0.trace;
// whisker width
t.wdPos = t.bdPos * trace.whiskerwidth;
if (trace.visible !== true || t.empty) {
plotGroup.remove();
return;
}
var posAxis, valAxis;
if (trace.orientation === 'h') {
posAxis = ya;
valAxis = xa;
} else {
posAxis = xa;
valAxis = ya;
}
plotBoxAndWhiskers(plotGroup, {
pos: posAxis,
val: valAxis
}, trace, t, isStatic);
plotPoints(plotGroup, {
x: xa,
y: ya
}, trace, t);
plotBoxMean(plotGroup, {
pos: posAxis,
val: valAxis
}, trace, t);
});
}
function plotBoxAndWhiskers(sel, axes, trace, t, isStatic) {
var isHorizontal = trace.orientation === 'h';
var valAxis = axes.val;
var posAxis = axes.pos;
var posHasRangeBreaks = !!posAxis.rangebreaks;
var bPos = t.bPos;
var wdPos = t.wdPos || 0;
var bPosPxOffset = t.bPosPxOffset || 0;
var whiskerWidth = trace.whiskerwidth || 0;
var showWhiskers = trace.showwhiskers !== false;
var notched = trace.notched || false;
var nw = notched ? 1 - 2 * trace.notchwidth : 1;
// to support for one-sided box
var bdPos0;
var bdPos1;
if (Array.isArray(t.bdPos)) {
bdPos0 = t.bdPos[0];
bdPos1 = t.bdPos[1];
} else {
bdPos0 = t.bdPos;
bdPos1 = t.bdPos;
}
var paths = sel.selectAll('path.box').data(trace.type !== 'violin' || trace.box.visible ? Lib.identity : []);
paths.enter().append('path').style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke').attr('class', 'box');
paths.exit().remove();
paths.each(function (d) {
if (d.empty) return d3.select(this).attr('d', 'M0,0Z');
var lcenter = posAxis.c2l(d.pos + bPos, true);
var pos0 = posAxis.l2p(lcenter - bdPos0) + bPosPxOffset;
var pos1 = posAxis.l2p(lcenter + bdPos1) + bPosPxOffset;
var posc = posHasRangeBreaks ? (pos0 + pos1) / 2 : posAxis.l2p(lcenter) + bPosPxOffset;
var r = trace.whiskerwidth;
var posw0 = posHasRangeBreaks ? pos0 * r + (1 - r) * posc : posAxis.l2p(lcenter - wdPos) + bPosPxOffset;
var posw1 = posHasRangeBreaks ? pos1 * r + (1 - r) * posc : posAxis.l2p(lcenter + wdPos) + bPosPxOffset;
var posm0 = posAxis.l2p(lcenter - bdPos0 * nw) + bPosPxOffset;
var posm1 = posAxis.l2p(lcenter + bdPos1 * nw) + bPosPxOffset;
var sdmode = trace.sizemode === 'sd';
var q1 = valAxis.c2p(sdmode ? d.mean - d.sd : d.q1, true);
var q3 = sdmode ? valAxis.c2p(d.mean + d.sd, true) : valAxis.c2p(d.q3, true);
// make sure median isn't identical to either of the
// quartiles, so we can see it
var m = Lib.constrain(sdmode ? valAxis.c2p(d.mean, true) : valAxis.c2p(d.med, true), Math.min(q1, q3) + 1, Math.max(q1, q3) - 1);
// for compatibility with box, violin, and candlestick
// perhaps we should put this into cd0.t instead so it's more explicit,
// but what we have now is:
// - box always has d.lf, but boxpoints can be anything
// - violin has d.lf and should always use it (boxpoints is undefined)
// - candlestick has only min/max
var useExtremes = d.lf === undefined || trace.boxpoints === false || sdmode;
var lf = valAxis.c2p(useExtremes ? d.min : d.lf, true);
var uf = valAxis.c2p(useExtremes ? d.max : d.uf, true);
var ln = valAxis.c2p(d.ln, true);
var un = valAxis.c2p(d.un, true);
if (isHorizontal) {
d3.select(this).attr('d', 'M' + m + ',' + posm0 + 'V' + posm1 +
// median line
'M' + q1 + ',' + pos0 + 'V' + pos1 + (
// left edge
notched ? 'H' + ln + 'L' + m + ',' + posm1 + 'L' + un + ',' + pos1 : '') +
// top notched edge
'H' + q3 +
// end of the top edge
'V' + pos0 + (
// right edge
notched ? 'H' + un + 'L' + m + ',' + posm0 + 'L' + ln + ',' + pos0 : '') +
// bottom notched edge
'Z' + (
// end of the box
showWhiskers ? 'M' + q1 + ',' + posc + 'H' + lf + 'M' + q3 + ',' + posc + 'H' + uf + (
// whiskers
whiskerWidth === 0 ? '' :
// whisker caps
'M' + lf + ',' + posw0 + 'V' + posw1 + 'M' + uf + ',' + posw0 + 'V' + posw1) : ''));
} else {
d3.select(this).attr('d', 'M' + posm0 + ',' + m + 'H' + posm1 +
// median line
'M' + pos0 + ',' + q1 + 'H' + pos1 + (
// top of the box
notched ? 'V' + ln + 'L' + posm1 + ',' + m + 'L' + pos1 + ',' + un : '') +
// notched right edge
'V' + q3 +
// end of the right edge
'H' + pos0 + (
// bottom of the box
notched ? 'V' + un + 'L' + posm0 + ',' + m + 'L' + pos0 + ',' + ln : '') +
// notched left edge
'Z' + (
// end of the box
showWhiskers ? 'M' + posc + ',' + q1 + 'V' + lf + 'M' + posc + ',' + q3 + 'V' + uf + (
// whiskers
whiskerWidth === 0 ? '' :
// whisker caps
'M' + posw0 + ',' + lf + 'H' + posw1 + 'M' + posw0 + ',' + uf + 'H' + posw1) : ''));
}
});
}
function plotPoints(sel, axes, trace, t) {
var xa = axes.x;
var ya = axes.y;
var bdPos = t.bdPos;
var bPos = t.bPos;
// to support violin points
var mode = trace.boxpoints || trace.points;
// repeatable pseudo-random number generator
Lib.seedPseudoRandom();
// since box plot points get an extra level of nesting, each
// box needs the trace styling info
var fn = function (d) {
d.forEach(function (v) {
v.t = t;
v.trace = trace;
});
return d;
};
var gPoints = sel.selectAll('g.points').data(mode ? fn : []);
gPoints.enter().append('g').attr('class', 'points');
gPoints.exit().remove();
var paths = gPoints.selectAll('path').data(function (d) {
var i;
var pts = d.pts2;
// normally use IQR, but if this is 0 or too small, use max-min
var typicalSpread = Math.max((d.max - d.min) / 10, d.q3 - d.q1);
var minSpread = typicalSpread * 1e-9;
var spreadLimit = typicalSpread * JITTERSPREAD;
var jitterFactors = [];
var maxJitterFactor = 0;
var newJitter;
// dynamic jitter
if (trace.jitter) {
if (typicalSpread === 0) {
// edge case of no spread at all: fall back to max jitter
maxJitterFactor = 1;
jitterFactors = new Array(pts.length);
for (i = 0; i < pts.length; i++) {
jitterFactors[i] = 1;
}
} else {
for (i = 0; i < pts.length; i++) {
var i0 = Math.max(0, i - JITTERCOUNT);
var pmin = pts[i0].v;
var i1 = Math.min(pts.length - 1, i + JITTERCOUNT);
var pmax = pts[i1].v;
if (mode !== 'all') {
if (pts[i].v < d.lf) pmax = Math.min(pmax, d.lf);else pmin = Math.max(pmin, d.uf);
}
var jitterFactor = Math.sqrt(spreadLimit * (i1 - i0) / (pmax - pmin + minSpread)) || 0;
jitterFactor = Lib.constrain(Math.abs(jitterFactor), 0, 1);
jitterFactors.push(jitterFactor);
maxJitterFactor = Math.max(jitterFactor, maxJitterFactor);
}
}
newJitter = trace.jitter * 2 / (maxJitterFactor || 1);
}
// fills in 'x' and 'y' in calcdata 'pts' item
for (i = 0; i < pts.length; i++) {
var pt = pts[i];
var v = pt.v;
var jitterOffset = trace.jitter ? newJitter * jitterFactors[i] * (Lib.pseudoRandom() - 0.5) : 0;
var posPx = d.pos + bPos + bdPos * (trace.pointpos + jitterOffset);
if (trace.orientation === 'h') {
pt.y = posPx;
pt.x = v;
} else {
pt.x = posPx;
pt.y = v;
}
// tag suspected outliers
if (mode === 'suspectedoutliers' && v < d.uo && v > d.lo) {
pt.so = true;
}
}
return pts;
});
paths.enter().append('path').classed('point', true);
paths.exit().remove();
paths.call(Drawing.translatePoints, xa, ya);
}
function plotBoxMean(sel, axes, trace, t) {
var valAxis = axes.val;
var posAxis = axes.pos;
var posHasRangeBreaks = !!posAxis.rangebreaks;
var bPos = t.bPos;
var bPosPxOffset = t.bPosPxOffset || 0;
// to support violin mean lines
var mode = trace.boxmean || (trace.meanline || {}).visible;
// to support for one-sided box
var bdPos0;
var bdPos1;
if (Array.isArray(t.bdPos)) {
bdPos0 = t.bdPos[0];
bdPos1 = t.bdPos[1];
} else {
bdPos0 = t.bdPos;
bdPos1 = t.bdPos;
}
var paths = sel.selectAll('path.mean').data(trace.type === 'box' && trace.boxmean || trace.type === 'violin' && trace.box.visible && trace.meanline.visible ? Lib.identity : []);
paths.enter().append('path').attr('class', 'mean').style({
fill: 'none',
'vector-effect': 'non-scaling-stroke'
});
paths.exit().remove();
paths.each(function (d) {
var lcenter = posAxis.c2l(d.pos + bPos, true);
var pos0 = posAxis.l2p(lcenter - bdPos0) + bPosPxOffset;
var pos1 = posAxis.l2p(lcenter + bdPos1) + bPosPxOffset;
var posc = posHasRangeBreaks ? (pos0 + pos1) / 2 : posAxis.l2p(lcenter) + bPosPxOffset;
var m = valAxis.c2p(d.mean, true);
var sl = valAxis.c2p(d.mean - d.sd, true);
var sh = valAxis.c2p(d.mean + d.sd, true);
if (trace.orientation === 'h') {
d3.select(this).attr('d', 'M' + m + ',' + pos0 + 'V' + pos1 + (mode === 'sd' ? 'm0,0L' + sl + ',' + posc + 'L' + m + ',' + pos0 + 'L' + sh + ',' + posc + 'Z' : ''));
} else {
d3.select(this).attr('d', 'M' + pos0 + ',' + m + 'H' + pos1 + (mode === 'sd' ? 'm0,0L' + posc + ',' + sl + 'L' + pos0 + ',' + m + 'L' + posc + ',' + sh + 'Z' : ''));
}
});
}
module.exports = {
plot: plot,
plotBoxAndWhiskers: plotBoxAndWhiskers,
plotPoints: plotPoints,
plotBoxMean: plotBoxMean
};
/***/ }),
/***/ 5496:
/***/ (function(module) {
"use strict";
module.exports = function selectPoints(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var selection = [];
var i, j;
if (selectionTester === false) {
for (i = 0; i < cd.length; i++) {
for (j = 0; j < (cd[i].pts || []).length; j++) {
// clear selection
cd[i].pts[j].selected = 0;
}
}
} else {
for (i = 0; i < cd.length; i++) {
for (j = 0; j < (cd[i].pts || []).length; j++) {
var pt = cd[i].pts[j];
var x = xa.c2p(pt.x);
var y = ya.c2p(pt.y);
if (selectionTester.contains([x, y], null, pt.i, searchInfo)) {
selection.push({
pointNumber: pt.i,
x: xa.c2d(pt.x),
y: ya.c2d(pt.y)
});
pt.selected = 1;
} else {
pt.selected = 0;
}
}
}
}
return selection;
};
/***/ }),
/***/ 11384:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Color = __webpack_require__(9240);
var Drawing = __webpack_require__(49348);
function style(gd, cd, sel) {
var s = sel ? sel : d3.select(gd).selectAll('g.trace.boxes');
s.style('opacity', function (d) {
return d[0].trace.opacity;
});
s.each(function (d) {
var el = d3.select(this);
var trace = d[0].trace;
var lineWidth = trace.line.width;
function styleBox(boxSel, lineWidth, lineColor, fillColor) {
boxSel.style('stroke-width', lineWidth + 'px').call(Color.stroke, lineColor).call(Color.fill, fillColor);
}
var allBoxes = el.selectAll('path.box');
if (trace.type === 'candlestick') {
allBoxes.each(function (boxData) {
if (boxData.empty) return;
var thisBox = d3.select(this);
var container = trace[boxData.dir]; // dir = 'increasing' or 'decreasing'
styleBox(thisBox, container.line.width, container.line.color, container.fillcolor);
// TODO: custom selection style for candlesticks
thisBox.style('opacity', trace.selectedpoints && !boxData.selected ? 0.3 : 1);
});
} else {
styleBox(allBoxes, lineWidth, trace.line.color, trace.fillcolor);
el.selectAll('path.mean').style({
'stroke-width': lineWidth,
'stroke-dasharray': 2 * lineWidth + 'px,' + lineWidth + 'px'
}).call(Color.stroke, trace.line.color);
var pts = el.selectAll('path.point');
Drawing.pointStyle(pts, trace, gd);
}
});
}
function styleOnSelect(gd, cd, sel) {
var trace = cd[0].trace;
var pts = sel.selectAll('path.point');
if (trace.selectedpoints) {
Drawing.selectedPointStyle(pts, trace);
} else {
Drawing.pointStyle(pts, trace, gd);
}
}
module.exports = {
style: style,
styleOnSelect: styleOnSelect
};
/***/ }),
/***/ 43024:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var extendFlat = (__webpack_require__(10923).extendFlat);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var OHLCattrs = __webpack_require__(29520);
var boxAttrs = __webpack_require__(12292);
function directionAttrs(lineColorDefault) {
return {
line: {
color: extendFlat({}, boxAttrs.line.color, {
dflt: lineColorDefault
}),
width: boxAttrs.line.width,
editType: 'style'
},
fillcolor: boxAttrs.fillcolor,
editType: 'style'
};
}
module.exports = {
xperiod: OHLCattrs.xperiod,
xperiod0: OHLCattrs.xperiod0,
xperiodalignment: OHLCattrs.xperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
x: OHLCattrs.x,
open: OHLCattrs.open,
high: OHLCattrs.high,
low: OHLCattrs.low,
close: OHLCattrs.close,
line: {
width: extendFlat({}, boxAttrs.line.width, {
description: [boxAttrs.line.width.description, 'Note that this style setting can also be set per', 'direction via `increasing.line.width` and', '`decreasing.line.width`.'].join(' ')
}),
editType: 'style'
},
increasing: directionAttrs(OHLCattrs.increasing.line.color.dflt),
decreasing: directionAttrs(OHLCattrs.decreasing.line.color.dflt),
text: OHLCattrs.text,
hovertext: OHLCattrs.hovertext,
whiskerwidth: extendFlat({}, boxAttrs.whiskerwidth, {
dflt: 0
}),
hoverlabel: OHLCattrs.hoverlabel,
zorder: boxAttrs.zorder
};
/***/ }),
/***/ 7948:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Axes = __webpack_require__(81536);
var alignPeriod = __webpack_require__(82260);
var calcCommon = (__webpack_require__(76952).calcCommon);
module.exports = function (gd, trace) {
var fullLayout = gd._fullLayout;
var xa = Axes.getFromId(gd, trace.xaxis);
var ya = Axes.getFromId(gd, trace.yaxis);
var origX = xa.makeCalcdata(trace, 'x');
var x = alignPeriod(trace, xa, 'x', origX).vals;
var cd = calcCommon(gd, trace, origX, x, ya, ptFunc);
if (cd.length) {
Lib.extendFlat(cd[0].t, {
num: fullLayout._numBoxes,
dPos: Lib.distinctVals(x).minDiff / 2,
posLetter: 'x',
valLetter: 'y'
});
fullLayout._numBoxes++;
return cd;
} else {
return [{
t: {
empty: true
}
}];
}
};
function ptFunc(o, h, l, c) {
return {
min: l,
q1: Math.min(o, c),
med: c,
q3: Math.max(o, c),
max: h
};
}
/***/ }),
/***/ 96848:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Color = __webpack_require__(9240);
var handleOHLC = __webpack_require__(584);
var handlePeriodDefaults = __webpack_require__(98632);
var attributes = __webpack_require__(43024);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleOHLC(traceIn, traceOut, coerce, layout);
if (!len) {
traceOut.visible = false;
return;
}
handlePeriodDefaults(traceIn, traceOut, layout, coerce, {
x: true
});
coerce('xhoverformat');
coerce('yhoverformat');
coerce('line.width');
handleDirection(traceIn, traceOut, coerce, 'increasing');
handleDirection(traceIn, traceOut, coerce, 'decreasing');
coerce('text');
coerce('hovertext');
coerce('whiskerwidth');
layout._requestRangeslider[traceOut.xaxis] = true;
coerce('zorder');
};
function handleDirection(traceIn, traceOut, coerce, direction) {
var lineColor = coerce(direction + '.line.color');
coerce(direction + '.line.width', traceOut.line.width);
coerce(direction + '.fillcolor', Color.addOpacity(lineColor, 0.5));
}
/***/ }),
/***/ 62256:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'candlestick',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', 'showLegend', 'candlestick', 'boxLayout'],
meta: {
description: ['The candlestick is a style of financial chart describing', 'open, high, low and close for a given `x` coordinate (most likely time).', 'The boxes represent the spread between the `open` and `close` values and', 'the lines represent the spread between the `low` and `high` values', 'Sample points where the close value is higher (lower) then the open', 'value are called increasing (decreasing).', 'By default, increasing candles are drawn in green whereas', 'decreasing are drawn in red.'].join(' ')
},
attributes: __webpack_require__(43024),
layoutAttributes: __webpack_require__(62352),
supplyLayoutDefaults: (__webpack_require__(15428).supplyLayoutDefaults),
crossTraceCalc: (__webpack_require__(67872).crossTraceCalc),
supplyDefaults: __webpack_require__(96848),
calc: __webpack_require__(7948),
plot: (__webpack_require__(46448).plot),
layerName: 'boxlayer',
style: (__webpack_require__(11384).style),
hoverPoints: (__webpack_require__(296).hoverPoints),
selectPoints: __webpack_require__(29844)
};
/***/ }),
/***/ 70480:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var handleAxisDefaults = __webpack_require__(63076);
var Template = __webpack_require__(58056);
module.exports = function handleABDefaults(traceIn, traceOut, fullLayout, coerce, dfltColor) {
var a = coerce('a');
if (!a) {
coerce('da');
coerce('a0');
}
var b = coerce('b');
if (!b) {
coerce('db');
coerce('b0');
}
mimickAxisDefaults(traceIn, traceOut, fullLayout, dfltColor);
};
function mimickAxisDefaults(traceIn, traceOut, fullLayout, dfltColor) {
var axesList = ['aaxis', 'baxis'];
axesList.forEach(function (axName) {
var axLetter = axName.charAt(0);
var axIn = traceIn[axName] || {};
var axOut = Template.newContainer(traceOut, axName);
var defaultOptions = {
noAutotickangles: true,
noTicklabelstep: true,
tickfont: 'x',
id: axLetter + 'axis',
letter: axLetter,
font: traceOut.font,
name: axName,
data: traceIn[axLetter],
calendar: traceOut.calendar,
dfltColor: dfltColor,
bgColor: fullLayout.paper_bgcolor,
autotypenumbersDflt: fullLayout.autotypenumbers,
fullLayout: fullLayout
};
handleAxisDefaults(axIn, axOut, defaultOptions);
axOut._categories = axOut._categories || [];
// so we don't have to repeat autotype unnecessarily,
// copy an autotype back to traceIn
if (!traceIn[axName] && axIn.type !== '-') {
traceIn[axName] = {
type: axIn.type
};
}
});
}
/***/ }),
/***/ 32512:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
module.exports = function (a) {
return minMax(a, 0);
};
function minMax(a, depth) {
// Limit to ten dimensional datasets. This seems *exceedingly* unlikely to
// ever cause problems or even be a concern. It's include strictly so that
// circular arrays could never cause this to loop.
if (!isArrayOrTypedArray(a) || depth >= 10) {
return null;
}
var min = Infinity;
var max = -Infinity;
var n = a.length;
for (var i = 0; i < n; i++) {
var datum = a[i];
if (isArrayOrTypedArray(datum)) {
var result = minMax(datum, depth + 1);
if (result) {
min = Math.min(result[0], min);
max = Math.max(result[1], max);
}
} else {
min = Math.min(datum, min);
max = Math.max(datum, max);
}
}
return [min, max];
}
/***/ }),
/***/ 74576:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var fontAttrs = __webpack_require__(71936);
var axisAttrs = __webpack_require__(60000);
var colorAttrs = __webpack_require__(51468);
var carpetFont = fontAttrs({
editType: 'calc',
description: 'The default font used for axis & tick labels on this carpet'
});
var zorder = (__webpack_require__(49992).zorder);
// TODO: inherit from global font
carpetFont.family.dflt = '"Open Sans", verdana, arial, sans-serif';
carpetFont.size.dflt = 12;
carpetFont.color.dflt = colorAttrs.defaultLine;
module.exports = {
carpet: {
valType: 'string',
editType: 'calc',
description: ['An identifier for this carpet, so that `scattercarpet` and', '`contourcarpet` traces can specify a carpet plot on which', 'they lie'].join(' ')
},
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['A two dimensional array of x coordinates at each carpet point.', 'If omitted, the plot is a cheater plot and the xaxis is hidden', 'by default.'].join(' ')
},
y: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: 'A two dimensional array of y coordinates at each carpet point.'
},
a: {
valType: 'data_array',
editType: 'calc',
description: ['An array containing values of the first parameter value'].join(' ')
},
a0: {
valType: 'number',
dflt: 0,
editType: 'calc',
description: ['Alternate to `a`.', 'Builds a linear space of a coordinates.', 'Use with `da`', 'where `a0` is the starting coordinate and `da` the step.'].join(' ')
},
da: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: ['Sets the a coordinate step.', 'See `a0` for more info.'].join(' ')
},
b: {
valType: 'data_array',
editType: 'calc',
description: 'A two dimensional array of y coordinates at each carpet point.'
},
b0: {
valType: 'number',
dflt: 0,
editType: 'calc',
description: ['Alternate to `b`.', 'Builds a linear space of a coordinates.', 'Use with `db`', 'where `b0` is the starting coordinate and `db` the step.'].join(' ')
},
db: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: ['Sets the b coordinate step.', 'See `b0` for more info.'].join(' ')
},
cheaterslope: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: ['The shift applied to each successive row of data in creating a cheater plot.', 'Only used if `x` is been omitted.'].join(' ')
},
aaxis: axisAttrs,
baxis: axisAttrs,
font: carpetFont,
color: {
valType: 'color',
dflt: colorAttrs.defaultLine,
editType: 'plot',
description: ['Sets default for all colors associated with this axis', 'all at once: line, font, tick, and grid colors.', 'Grid color is lightened by blending this with the plot background', 'Individual pieces can override this.'].join(' ')
},
transforms: undefined,
zorder: zorder
};
/***/ }),
/***/ 62240:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
/* This function retrns a set of control points that define a curve aligned along
* either the a or b axis. Exactly one of a or b must be an array defining the range
* spanned.
*
* Honestly this is the most complicated function I've implemente here so far because
* of the way it handles knot insertion and direction/axis-agnostic slices.
*/
module.exports = function (carpet, carpetcd, a, b) {
var idx, tangent, tanIsoIdx, tanIsoPar, segment, refidx;
var p0, p1, v0, v1, start, end, range;
var axis = isArrayOrTypedArray(a) ? 'a' : 'b';
var ax = axis === 'a' ? carpet.aaxis : carpet.baxis;
var smoothing = ax.smoothing;
var toIdx = axis === 'a' ? carpet.a2i : carpet.b2j;
var pt = axis === 'a' ? a : b;
var iso = axis === 'a' ? b : a;
var n = axis === 'a' ? carpetcd.a.length : carpetcd.b.length;
var m = axis === 'a' ? carpetcd.b.length : carpetcd.a.length;
var isoIdx = Math.floor(axis === 'a' ? carpet.b2j(iso) : carpet.a2i(iso));
var xy = axis === 'a' ? function (value) {
return carpet.evalxy([], value, isoIdx);
} : function (value) {
return carpet.evalxy([], isoIdx, value);
};
if (smoothing) {
tanIsoIdx = Math.max(0, Math.min(m - 2, isoIdx));
tanIsoPar = isoIdx - tanIsoIdx;
tangent = axis === 'a' ? function (i, ti) {
return carpet.dxydi([], i, tanIsoIdx, ti, tanIsoPar);
} : function (j, tj) {
return carpet.dxydj([], tanIsoIdx, j, tanIsoPar, tj);
};
}
var vstart = toIdx(pt[0]);
var vend = toIdx(pt[1]);
// So that we can make this work in two directions, flip all of the
// math functions if the direction is from higher to lower indices:
//
// Note that the tolerance is directional!
var dir = vstart < vend ? 1 : -1;
var tol = (vend - vstart) * 1e-8;
var dirfloor = dir > 0 ? Math.floor : Math.ceil;
var dirceil = dir > 0 ? Math.ceil : Math.floor;
var dirmin = dir > 0 ? Math.min : Math.max;
var dirmax = dir > 0 ? Math.max : Math.min;
var idx0 = dirfloor(vstart + tol);
var idx1 = dirceil(vend - tol);
p0 = xy(vstart);
var segments = [[p0]];
for (idx = idx0; idx * dir < idx1 * dir; idx += dir) {
segment = [];
start = dirmax(vstart, idx);
end = dirmin(vend, idx + dir);
range = end - start;
// In order to figure out which cell we're in for the derivative (remember,
// the derivatives are *not* constant across grid lines), let's just average
// the start and end points. This cuts out just a tiny bit of logic and
// there's really no computational difference:
refidx = Math.max(0, Math.min(n - 2, Math.floor(0.5 * (start + end))));
p1 = xy(end);
if (smoothing) {
v0 = tangent(refidx, start - refidx);
v1 = tangent(refidx, end - refidx);
segment.push([p0[0] + v0[0] / 3 * range, p0[1] + v0[1] / 3 * range]);
segment.push([p1[0] - v1[0] / 3 * range, p1[1] - v1[1] / 3 * range]);
}
segment.push(p1);
segments.push(segment);
p0 = p1;
}
return segments;
};
/***/ }),
/***/ 60000:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var fontAttrs = __webpack_require__(71936);
var colorAttrs = __webpack_require__(51468);
var axesAttrs = __webpack_require__(88176);
var descriptionWithDates = (__webpack_require__(67724).descriptionWithDates);
var overrideAll = (__webpack_require__(31176).overrideAll);
var dash = (__webpack_require__(9392)/* .dash */ .u);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = {
color: {
valType: 'color',
editType: 'calc',
description: ['Sets default for all colors associated with this axis', 'all at once: line, font, tick, and grid colors.', 'Grid color is lightened by blending this with the plot background', 'Individual pieces can override this.'].join(' ')
},
smoothing: {
valType: 'number',
dflt: 1,
min: 0,
max: 1.3,
editType: 'calc'
},
title: {
text: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['Sets the title of this axis.', 'Note that before the existence of `title.text`, the title\'s', 'contents used to be defined as the `title` attribute itself.', 'This behavior has been deprecated.'].join(' ')
},
font: fontAttrs({
editType: 'calc',
description: ['Sets this axis\' title font.', 'Note that the title\'s font used to be set', 'by the now deprecated `titlefont` attribute.'].join(' ')
}),
// TODO how is this different than `title.standoff`
offset: {
valType: 'number',
dflt: 10,
editType: 'calc',
description: ['An additional amount by which to offset the title from the tick', 'labels, given in pixels.', 'Note that this used to be set', 'by the now deprecated `titleoffset` attribute.'].join(' ')
},
editType: 'calc'
},
type: {
valType: 'enumerated',
// '-' means we haven't yet run autotype or couldn't find any data
// it gets turned into linear in gd._fullLayout but not copied back
// to gd.data like the others are.
values: ['-', 'linear', 'date', 'category'],
dflt: '-',
editType: 'calc',
description: ['Sets the axis type.', 'By default, plotly attempts to determined the axis type', 'by looking into the data of the traces that referenced', 'the axis in question.'].join(' ')
},
autotypenumbers: axesAttrs.autotypenumbers,
autorange: {
valType: 'enumerated',
values: [true, false, 'reversed'],
dflt: true,
editType: 'calc',
description: ['Determines whether or not the range of this axis is', 'computed in relation to the input data.', 'See `rangemode` for more info.', 'If `range` is provided, then `autorange` is set to *false*.'].join(' ')
},
rangemode: {
valType: 'enumerated',
values: ['normal', 'tozero', 'nonnegative'],
dflt: 'normal',
editType: 'calc',
description: ['If *normal*, the range is computed in relation to the extrema', 'of the input data.', 'If *tozero*`, the range extends to 0,', 'regardless of the input data', 'If *nonnegative*, the range is non-negative,', 'regardless of the input data.'].join(' ')
},
range: {
valType: 'info_array',
editType: 'calc',
items: [{
valType: 'any',
editType: 'calc'
}, {
valType: 'any',
editType: 'calc'
}],
description: ['Sets the range of this axis.', 'If the axis `type` is *log*, then you must take the log of your', 'desired range (e.g. to set the range from 1 to 100,', 'set the range from 0 to 2).', 'If the axis `type` is *date*, it should be date strings,', 'like date data, though Date objects and unix milliseconds', 'will be accepted and converted to strings.', 'If the axis `type` is *category*, it should be numbers,', 'using the scale where each category is assigned a serial', 'number from zero in the order it appears.'].join(' ')
},
fixedrange: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['Determines whether or not this axis is zoom-able.', 'If true, then zoom is disabled.'].join(' ')
},
cheatertype: {
valType: 'enumerated',
values: ['index', 'value'],
dflt: 'value',
editType: 'calc'
},
tickmode: {
valType: 'enumerated',
values: ['linear', 'array'],
dflt: 'array',
editType: 'calc'
},
nticks: {
valType: 'integer',
min: 0,
dflt: 0,
editType: 'calc',
description: ['Specifies the maximum number of ticks for the particular axis.', 'The actual number of ticks will be chosen automatically to be', 'less than or equal to `nticks`.', 'Has an effect only if `tickmode` is set to *auto*.'].join(' ')
},
tickvals: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the values at which ticks on this axis appear.', 'Only has an effect if `tickmode` is set to *array*.', 'Used with `ticktext`.'].join(' ')
},
ticktext: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the text displayed at the ticks position via `tickvals`.', 'Only has an effect if `tickmode` is set to *array*.', 'Used with `tickvals`.'].join(' ')
},
showticklabels: {
valType: 'enumerated',
values: ['start', 'end', 'both', 'none'],
dflt: 'start',
editType: 'calc',
description: ['Determines whether axis labels are drawn on the low side,', 'the high side, both, or neither side of the axis.'].join(' ')
},
labelalias: extendFlat({}, axesAttrs.labelalias, {
editType: 'calc'
}),
tickfont: fontAttrs({
editType: 'calc',
description: 'Sets the tick font.'
}),
tickangle: {
valType: 'angle',
dflt: 'auto',
editType: 'calc',
description: ['Sets the angle of the tick labels with respect to the horizontal.', 'For example, a `tickangle` of -90 draws the tick labels', 'vertically.'].join(' ')
},
tickprefix: {
valType: 'string',
dflt: '',
editType: 'calc',
description: 'Sets a tick label prefix.'
},
showtickprefix: {
valType: 'enumerated',
values: ['all', 'first', 'last', 'none'],
dflt: 'all',
editType: 'calc',
description: ['If *all*, all tick labels are displayed with a prefix.', 'If *first*, only the first tick is displayed with a prefix.', 'If *last*, only the last tick is displayed with a suffix.', 'If *none*, tick prefixes are hidden.'].join(' ')
},
ticksuffix: {
valType: 'string',
dflt: '',
editType: 'calc',
description: 'Sets a tick label suffix.'
},
showticksuffix: {
valType: 'enumerated',
values: ['all', 'first', 'last', 'none'],
dflt: 'all',
editType: 'calc',
description: 'Same as `showtickprefix` but for tick suffixes.'
},
showexponent: {
valType: 'enumerated',
values: ['all', 'first', 'last', 'none'],
dflt: 'all',
editType: 'calc',
description: ['If *all*, all exponents are shown besides their significands.', 'If *first*, only the exponent of the first tick is shown.', 'If *last*, only the exponent of the last tick is shown.', 'If *none*, no exponents appear.'].join(' ')
},
exponentformat: {
valType: 'enumerated',
values: ['none', 'e', 'E', 'power', 'SI', 'B'],
dflt: 'B',
editType: 'calc',
description: ['Determines a formatting rule for the tick exponents.', 'For example, consider the number 1,000,000,000.', 'If *none*, it appears as 1,000,000,000.', 'If *e*, 1e+9.', 'If *E*, 1E+9.', 'If *power*, 1x10^9 (with 9 in a super script).', 'If *SI*, 1G.', 'If *B*, 1B.'].join(' ')
},
minexponent: {
valType: 'number',
dflt: 3,
min: 0,
editType: 'calc',
description: ['Hide SI prefix for 10^n if |n| is below this number'].join(' ')
},
separatethousands: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['If "true", even 4-digit integers are separated'].join(' ')
},
tickformat: {
valType: 'string',
dflt: '',
editType: 'calc',
description: descriptionWithDates('tick label')
},
tickformatstops: overrideAll(axesAttrs.tickformatstops, 'calc', 'from-root'),
categoryorder: {
valType: 'enumerated',
values: ['trace', 'category ascending', 'category descending', 'array'
/* , 'value ascending', 'value descending'*/ // value ascending / descending to be implemented later
],
dflt: 'trace',
editType: 'calc',
description: ['Specifies the ordering logic for the case of categorical variables.', 'By default, plotly uses *trace*, which specifies the order that is present in the data supplied.', 'Set `categoryorder` to *category ascending* or *category descending* if order should be determined by', 'the alphanumerical order of the category names.',
/* 'Set `categoryorder` to *value ascending* or *value descending* if order should be determined by the',
'numerical order of the values.',*/ // // value ascending / descending to be implemented later
'Set `categoryorder` to *array* to derive the ordering from the attribute `categoryarray`. If a category', 'is not found in the `categoryarray` array, the sorting behavior for that attribute will be identical to', 'the *trace* mode. The unspecified categories will follow the categories in `categoryarray`.'].join(' ')
},
categoryarray: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the order in which categories on this axis appear.', 'Only has an effect if `categoryorder` is set to *array*.', 'Used with `categoryorder`.'].join(' ')
},
labelpadding: {
valType: 'integer',
dflt: 10,
editType: 'calc',
description: 'Extra padding between label and the axis'
},
labelprefix: {
valType: 'string',
editType: 'calc',
description: 'Sets a axis label prefix.'
},
labelsuffix: {
valType: 'string',
dflt: '',
editType: 'calc',
description: 'Sets a axis label suffix.'
},
// lines and grids
showline: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['Determines whether or not a line bounding this axis is drawn.'].join(' ')
},
linecolor: {
valType: 'color',
dflt: colorAttrs.defaultLine,
editType: 'calc',
description: 'Sets the axis line color.'
},
linewidth: {
valType: 'number',
min: 0,
dflt: 1,
editType: 'calc',
description: 'Sets the width (in px) of the axis line.'
},
gridcolor: {
valType: 'color',
editType: 'calc',
description: 'Sets the axis line color.'
},
gridwidth: {
valType: 'number',
min: 0,
dflt: 1,
editType: 'calc',
description: 'Sets the width (in px) of the axis line.'
},
griddash: extendFlat({}, dash, {
editType: 'calc'
}),
showgrid: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether or not grid lines are drawn.', 'If *true*, the grid lines are drawn at every tick mark.'].join(' ')
},
minorgridcount: {
valType: 'integer',
min: 0,
dflt: 0,
editType: 'calc',
description: 'Sets the number of minor grid ticks per major grid tick'
},
minorgridwidth: {
valType: 'number',
min: 0,
dflt: 1,
editType: 'calc',
description: 'Sets the width (in px) of the grid lines.'
},
minorgriddash: extendFlat({}, dash, {
editType: 'calc'
}),
minorgridcolor: {
valType: 'color',
dflt: colorAttrs.lightLine,
editType: 'calc',
description: 'Sets the color of the grid lines.'
},
startline: {
valType: 'boolean',
editType: 'calc',
description: ['Determines whether or not a line is drawn at along the starting value', 'of this axis.', 'If *true*, the start line is drawn on top of the grid lines.'].join(' ')
},
startlinecolor: {
valType: 'color',
editType: 'calc',
description: 'Sets the line color of the start line.'
},
startlinewidth: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: 'Sets the width (in px) of the start line.'
},
endline: {
valType: 'boolean',
editType: 'calc',
description: ['Determines whether or not a line is drawn at along the final value', 'of this axis.', 'If *true*, the end line is drawn on top of the grid lines.'].join(' ')
},
endlinewidth: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: 'Sets the width (in px) of the end line.'
},
endlinecolor: {
valType: 'color',
editType: 'calc',
description: 'Sets the line color of the end line.'
},
tick0: {
valType: 'number',
min: 0,
dflt: 0,
editType: 'calc',
description: 'The starting index of grid lines along the axis'
},
dtick: {
valType: 'number',
min: 0,
dflt: 1,
editType: 'calc',
description: 'The stride between grid lines along the axis'
},
arraytick0: {
valType: 'integer',
min: 0,
dflt: 0,
editType: 'calc',
description: 'The starting index of grid lines along the axis'
},
arraydtick: {
valType: 'integer',
min: 1,
dflt: 1,
editType: 'calc',
description: 'The stride between grid lines along the axis'
},
_deprecated: {
title: {
valType: 'string',
editType: 'calc',
description: ['Deprecated in favor of `title.text`.', 'Note that value of `title` is no longer a simple', '*string* but a set of sub-attributes.'].join(' ')
},
titlefont: fontAttrs({
editType: 'calc',
description: 'Deprecated in favor of `title.font`.'
}),
titleoffset: {
valType: 'number',
dflt: 10,
editType: 'calc',
description: 'Deprecated in favor of `title.offset`.'
}
},
editType: 'calc'
};
/***/ }),
/***/ 63076:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var carpetAttrs = __webpack_require__(74576);
var addOpacity = (__webpack_require__(9240).addOpacity);
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var handleTickValueDefaults = __webpack_require__(82960);
var handleTickLabelDefaults = __webpack_require__(99476);
var handlePrefixSuffixDefaults = __webpack_require__(64176);
var handleCategoryOrderDefaults = __webpack_require__(40832);
var setConvert = __webpack_require__(9224);
var autoType = __webpack_require__(30948);
/**
* options: object containing:
*
* letter: 'a' or 'b'
* title: name of the axis (ie 'Colorbar') to go in default title
* name: axis object name (ie 'xaxis') if one should be stored
* font: the default font to inherit
* outerTicks: boolean, should ticks default to outside?
* showGrid: boolean, should gridlines be shown by default?
* data: the plot data to use in choosing auto type
* bgColor: the plot background color, to calculate default gridline colors
*/
module.exports = function handleAxisDefaults(containerIn, containerOut, options) {
var letter = options.letter;
var font = options.font || {};
var attributes = carpetAttrs[letter + 'axis'];
function coerce(attr, dflt) {
return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
}
function coerce2(attr, dflt) {
return Lib.coerce2(containerIn, containerOut, attributes, attr, dflt);
}
// set up some private properties
if (options.name) {
containerOut._name = options.name;
containerOut._id = options.name;
}
// now figure out type and do some more initialization
coerce('autotypenumbers', options.autotypenumbersDflt);
var axType = coerce('type');
if (axType === '-') {
if (options.data) setAutoType(containerOut, options.data);
if (containerOut.type === '-') {
containerOut.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
axType = containerIn.type = containerOut.type;
}
}
coerce('smoothing');
coerce('cheatertype');
coerce('showticklabels');
coerce('labelprefix', letter + ' = ');
coerce('labelsuffix');
coerce('showtickprefix');
coerce('showticksuffix');
coerce('separatethousands');
coerce('tickformat');
coerce('exponentformat');
coerce('minexponent');
coerce('showexponent');
coerce('categoryorder');
coerce('tickmode');
coerce('tickvals');
coerce('ticktext');
coerce('tick0');
coerce('dtick');
if (containerOut.tickmode === 'array') {
coerce('arraytick0');
coerce('arraydtick');
}
coerce('labelpadding');
containerOut._hovertitle = letter;
if (axType === 'date') {
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleDefaults');
handleCalendarDefaults(containerIn, containerOut, 'calendar', options.calendar);
}
// we need some of the other functions setConvert attaches, but for
// path finding, override pixel scaling to simple passthrough (identity)
setConvert(containerOut, options.fullLayout);
containerOut.c2p = Lib.identity;
var dfltColor = coerce('color', options.dfltColor);
// if axis.color was provided, use it for fonts too; otherwise,
// inherit from global font color in case that was provided.
var dfltFontColor = dfltColor === containerIn.color ? dfltColor : font.color;
var title = coerce('title.text');
if (title) {
Lib.coerceFont(coerce, 'title.font', {
family: font.family,
size: Lib.bigFont(font.size),
color: dfltFontColor
});
coerce('title.offset');
}
coerce('tickangle');
var autoRange = coerce('autorange', !containerOut.isValidRange(containerIn.range));
if (autoRange) coerce('rangemode');
coerce('range');
containerOut.cleanRange();
coerce('fixedrange');
handleTickValueDefaults(containerIn, containerOut, coerce, axType);
handlePrefixSuffixDefaults(containerIn, containerOut, coerce, axType, options);
handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options);
handleCategoryOrderDefaults(containerIn, containerOut, coerce, {
data: options.data,
dataAttr: letter
});
var gridColor = coerce2('gridcolor', addOpacity(dfltColor, 0.3));
var gridWidth = coerce2('gridwidth');
var gridDash = coerce2('griddash');
var showGrid = coerce('showgrid');
if (!showGrid) {
delete containerOut.gridcolor;
delete containerOut.gridwidth;
delete containerOut.griddash;
}
var startLineColor = coerce2('startlinecolor', dfltColor);
var startLineWidth = coerce2('startlinewidth', gridWidth);
var showStartLine = coerce('startline', containerOut.showgrid || !!startLineColor || !!startLineWidth);
if (!showStartLine) {
delete containerOut.startlinecolor;
delete containerOut.startlinewidth;
}
var endLineColor = coerce2('endlinecolor', dfltColor);
var endLineWidth = coerce2('endlinewidth', gridWidth);
var showEndLine = coerce('endline', containerOut.showgrid || !!endLineColor || !!endLineWidth);
if (!showEndLine) {
delete containerOut.endlinecolor;
delete containerOut.endlinewidth;
}
if (!showGrid) {
delete containerOut.gridcolor;
delete containerOut.gridwidth;
delete containerOut.griddash;
} else {
coerce('minorgridcount');
coerce('minorgridwidth', gridWidth);
coerce('minorgriddash', gridDash);
coerce('minorgridcolor', addOpacity(gridColor, 0.06));
if (!containerOut.minorgridcount) {
delete containerOut.minorgridwidth;
delete containerOut.minorgriddash;
delete containerOut.minorgridcolor;
}
}
if (containerOut.showticklabels === 'none') {
delete containerOut.tickfont;
delete containerOut.tickangle;
delete containerOut.showexponent;
delete containerOut.exponentformat;
delete containerOut.minexponent;
delete containerOut.tickformat;
delete containerOut.showticksuffix;
delete containerOut.showtickprefix;
}
if (!containerOut.showticksuffix) {
delete containerOut.ticksuffix;
}
if (!containerOut.showtickprefix) {
delete containerOut.tickprefix;
}
// It needs to be coerced, then something above overrides this deep in the axis code,
// but no, we *actually* want to coerce this.
coerce('tickmode');
return containerOut;
};
function setAutoType(ax, data) {
// new logic: let people specify any type they want,
// only autotype if type is '-'
if (ax.type !== '-') return;
var id = ax._id;
var axLetter = id.charAt(0);
var calAttr = axLetter + 'calendar';
var calendar = ax[calAttr];
ax.type = autoType(data, calendar, {
autotypenumbers: ax.autotypenumbers
});
}
/***/ }),
/***/ 44883:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var isArray1D = (__webpack_require__(10923).isArray1D);
var cheaterBasis = __webpack_require__(43700);
var arrayMinmax = __webpack_require__(32512);
var calcGridlines = __webpack_require__(98544);
var calcLabels = __webpack_require__(97708);
var calcClipPath = __webpack_require__(22380);
var clean2dArray = __webpack_require__(20736);
var smoothFill2dArray = __webpack_require__(14528);
var convertColumnData = __webpack_require__(26848);
var setConvert = __webpack_require__(18704);
module.exports = function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis);
var ya = Axes.getFromId(gd, trace.yaxis);
var aax = trace.aaxis;
var bax = trace.baxis;
var x = trace.x;
var y = trace.y;
var cols = [];
if (x && isArray1D(x)) cols.push('x');
if (y && isArray1D(y)) cols.push('y');
if (cols.length) {
convertColumnData(trace, aax, bax, 'a', 'b', cols);
}
var a = trace._a = trace._a || trace.a;
var b = trace._b = trace._b || trace.b;
x = trace._x || trace.x;
y = trace._y || trace.y;
var t = {};
if (trace._cheater) {
var avals = aax.cheatertype === 'index' ? a.length : a;
var bvals = bax.cheatertype === 'index' ? b.length : b;
x = cheaterBasis(avals, bvals, trace.cheaterslope);
}
trace._x = x = clean2dArray(x);
trace._y = y = clean2dArray(y);
// Fill in any undefined values with elliptic smoothing. This doesn't take
// into account the spacing of the values. That is, the derivatives should
// be modified to use a and b values. It's not that hard, but this is already
// moderate overkill for just filling in missing values.
smoothFill2dArray(x, a, b);
smoothFill2dArray(y, a, b);
setConvert(trace);
// create conversion functions that depend on the data
trace.setScale();
// This is a rather expensive scan. Nothing guarantees monotonicity,
// so we need to scan through all data to get proper ranges:
var xrange = arrayMinmax(x);
var yrange = arrayMinmax(y);
var dx = 0.5 * (xrange[1] - xrange[0]);
var xc = 0.5 * (xrange[1] + xrange[0]);
var dy = 0.5 * (yrange[1] - yrange[0]);
var yc = 0.5 * (yrange[1] + yrange[0]);
// Expand the axes to fit the plot, except just grow it by a factor of 1.3
// because the labels should be taken into account except that's difficult
// hence 1.3.
var grow = 1.3;
xrange = [xc - dx * grow, xc + dx * grow];
yrange = [yc - dy * grow, yc + dy * grow];
trace._extremes[xa._id] = Axes.findExtremes(xa, xrange, {
padded: true
});
trace._extremes[ya._id] = Axes.findExtremes(ya, yrange, {
padded: true
});
// Enumerate the gridlines, both major and minor, and store them on the trace
// object:
calcGridlines(trace, 'a', 'b');
calcGridlines(trace, 'b', 'a');
// Calculate the text labels for each major gridline and store them on the
// trace object:
calcLabels(trace, aax);
calcLabels(trace, bax);
// Tabulate points for the four segments that bound the axes so that we can
// map to pixel coordinates in the plot function and create a clip rect:
t.clipsegments = calcClipPath(trace._xctrl, trace._yctrl, aax, bax);
t.x = x;
t.y = y;
t.a = a;
t.b = b;
return [t];
};
/***/ }),
/***/ 22380:
/***/ (function(module) {
"use strict";
module.exports = function makeClipPath(xctrl, yctrl, aax, bax) {
var i, x, y;
var segments = [];
var asmoothing = !!aax.smoothing;
var bsmoothing = !!bax.smoothing;
var nea1 = xctrl[0].length - 1;
var neb1 = xctrl.length - 1;
// Along the lower a axis:
for (i = 0, x = [], y = []; i <= nea1; i++) {
x[i] = xctrl[0][i];
y[i] = yctrl[0][i];
}
segments.push({
x: x,
y: y,
bicubic: asmoothing
});
// Along the upper b axis:
for (i = 0, x = [], y = []; i <= neb1; i++) {
x[i] = xctrl[i][nea1];
y[i] = yctrl[i][nea1];
}
segments.push({
x: x,
y: y,
bicubic: bsmoothing
});
// Backwards along the upper a axis:
for (i = nea1, x = [], y = []; i >= 0; i--) {
x[nea1 - i] = xctrl[neb1][i];
y[nea1 - i] = yctrl[neb1][i];
}
segments.push({
x: x,
y: y,
bicubic: asmoothing
});
// Backwards along the lower b axis:
for (i = neb1, x = [], y = []; i >= 0; i--) {
x[neb1 - i] = xctrl[i][0];
y[neb1 - i] = yctrl[i][0];
}
segments.push({
x: x,
y: y,
bicubic: bsmoothing
});
return segments;
};
/***/ }),
/***/ 98544:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = function calcGridlines(trace, axisLetter, crossAxisLetter) {
var i, j, j0;
var eps, bounds, n1, n2, n, value, v;
var j1, v0, v1, d;
var data = trace['_' + axisLetter];
var axis = trace[axisLetter + 'axis'];
var gridlines = axis._gridlines = [];
var minorgridlines = axis._minorgridlines = [];
var boundarylines = axis._boundarylines = [];
var crossData = trace['_' + crossAxisLetter];
var crossAxis = trace[crossAxisLetter + 'axis'];
if (axis.tickmode === 'array') {
axis.tickvals = data.slice();
}
var xcp = trace._xctrl;
var ycp = trace._yctrl;
var nea = xcp[0].length;
var neb = xcp.length;
var na = trace._a.length;
var nb = trace._b.length;
Axes.prepTicks(axis);
// don't leave tickvals in axis looking like an attribute
if (axis.tickmode === 'array') delete axis.tickvals;
// The default is an empty array that will cause the join to remove the gridline if
// it's just disappeared:
// axis._startline = axis._endline = [];
// If the cross axis uses bicubic interpolation, then the grid
// lines fall once every three expanded grid row/cols:
var stride = axis.smoothing ? 3 : 1;
function constructValueGridline(value) {
var i, j, j0, tj, pxy, i0, ti, xy, dxydi0, dxydi1, dxydj0, dxydj1;
var xpoints = [];
var ypoints = [];
var ret = {};
// Search for the fractional grid index giving this line:
if (axisLetter === 'b') {
// For the position we use just the i-j coordinates:
j = trace.b2j(value);
// The derivatives for catmull-rom splines are discontinuous across cell
// boundaries though, so we need to provide both the cell and the position
// within the cell separately:
j0 = Math.floor(Math.max(0, Math.min(nb - 2, j)));
tj = j - j0;
ret.length = nb;
ret.crossLength = na;
ret.xy = function (i) {
return trace.evalxy([], i, j);
};
ret.dxy = function (i0, ti) {
return trace.dxydi([], i0, j0, ti, tj);
};
for (i = 0; i < na; i++) {
i0 = Math.min(na - 2, i);
ti = i - i0;
xy = trace.evalxy([], i, j);
if (crossAxis.smoothing && i > 0) {
// First control point:
dxydi0 = trace.dxydi([], i - 1, j0, 0, tj);
xpoints.push(pxy[0] + dxydi0[0] / 3);
ypoints.push(pxy[1] + dxydi0[1] / 3);
// Second control point:
dxydi1 = trace.dxydi([], i - 1, j0, 1, tj);
xpoints.push(xy[0] - dxydi1[0] / 3);
ypoints.push(xy[1] - dxydi1[1] / 3);
}
xpoints.push(xy[0]);
ypoints.push(xy[1]);
pxy = xy;
}
} else {
i = trace.a2i(value);
i0 = Math.floor(Math.max(0, Math.min(na - 2, i)));
ti = i - i0;
ret.length = na;
ret.crossLength = nb;
ret.xy = function (j) {
return trace.evalxy([], i, j);
};
ret.dxy = function (j0, tj) {
return trace.dxydj([], i0, j0, ti, tj);
};
for (j = 0; j < nb; j++) {
j0 = Math.min(nb - 2, j);
tj = j - j0;
xy = trace.evalxy([], i, j);
if (crossAxis.smoothing && j > 0) {
// First control point:
dxydj0 = trace.dxydj([], i0, j - 1, ti, 0);
xpoints.push(pxy[0] + dxydj0[0] / 3);
ypoints.push(pxy[1] + dxydj0[1] / 3);
// Second control point:
dxydj1 = trace.dxydj([], i0, j - 1, ti, 1);
xpoints.push(xy[0] - dxydj1[0] / 3);
ypoints.push(xy[1] - dxydj1[1] / 3);
}
xpoints.push(xy[0]);
ypoints.push(xy[1]);
pxy = xy;
}
}
ret.axisLetter = axisLetter;
ret.axis = axis;
ret.crossAxis = crossAxis;
ret.value = value;
ret.constvar = crossAxisLetter;
ret.index = n;
ret.x = xpoints;
ret.y = ypoints;
ret.smoothing = crossAxis.smoothing;
return ret;
}
function constructArrayGridline(idx) {
var j, i0, j0, ti, tj;
var xpoints = [];
var ypoints = [];
var ret = {};
ret.length = data.length;
ret.crossLength = crossData.length;
if (axisLetter === 'b') {
j0 = Math.max(0, Math.min(nb - 2, idx));
tj = Math.min(1, Math.max(0, idx - j0));
ret.xy = function (i) {
return trace.evalxy([], i, idx);
};
ret.dxy = function (i0, ti) {
return trace.dxydi([], i0, j0, ti, tj);
};
// In the tickmode: array case, this operation is a simple
// transfer of data:
for (j = 0; j < nea; j++) {
xpoints[j] = xcp[idx * stride][j];
ypoints[j] = ycp[idx * stride][j];
}
} else {
i0 = Math.max(0, Math.min(na - 2, idx));
ti = Math.min(1, Math.max(0, idx - i0));
ret.xy = function (j) {
return trace.evalxy([], idx, j);
};
ret.dxy = function (j0, tj) {
return trace.dxydj([], i0, j0, ti, tj);
};
// In the tickmode: array case, this operation is a simple
// transfer of data:
for (j = 0; j < neb; j++) {
xpoints[j] = xcp[j][idx * stride];
ypoints[j] = ycp[j][idx * stride];
}
}
ret.axisLetter = axisLetter;
ret.axis = axis;
ret.crossAxis = crossAxis;
ret.value = data[idx];
ret.constvar = crossAxisLetter;
ret.index = idx;
ret.x = xpoints;
ret.y = ypoints;
ret.smoothing = crossAxis.smoothing;
return ret;
}
if (axis.tickmode === 'array') {
// var j0 = axis.startline ? 1 : 0;
// var j1 = data.length - (axis.endline ? 1 : 0);
eps = 5e-15;
bounds = [Math.floor((data.length - 1 - axis.arraytick0) / axis.arraydtick * (1 + eps)), Math.ceil(-axis.arraytick0 / axis.arraydtick / (1 + eps))].sort(function (a, b) {
return a - b;
});
// Unpack sorted values so we can be sure to avoid infinite loops if something
// is backwards:
n1 = bounds[0] - 1;
n2 = bounds[1] + 1;
// If the axes fall along array lines, then this is a much simpler process since
// we already have all the control points we need
for (n = n1; n < n2; n++) {
j = axis.arraytick0 + axis.arraydtick * n;
if (j < 0 || j > data.length - 1) continue;
gridlines.push(extendFlat(constructArrayGridline(j), {
color: axis.gridcolor,
width: axis.gridwidth,
dash: axis.griddash
}));
}
for (n = n1; n < n2; n++) {
j0 = axis.arraytick0 + axis.arraydtick * n;
j1 = Math.min(j0 + axis.arraydtick, data.length - 1);
// TODO: fix the bounds computation so we don't have to do a large range and then throw
// out unneeded numbers
if (j0 < 0 || j0 > data.length - 1) continue;
if (j1 < 0 || j1 > data.length - 1) continue;
v0 = data[j0];
v1 = data[j1];
for (i = 0; i < axis.minorgridcount; i++) {
d = j1 - j0;
// TODO: fix the bounds computation so we don't have to do a large range and then throw
// out unneeded numbers
if (d <= 0) continue;
// XXX: This calculation isn't quite right. Off by one somewhere?
v = v0 + (v1 - v0) * (i + 1) / (axis.minorgridcount + 1) * (axis.arraydtick / d);
// TODO: fix the bounds computation so we don't have to do a large range and then throw
// out unneeded numbers
if (v < data[0] || v > data[data.length - 1]) continue;
minorgridlines.push(extendFlat(constructValueGridline(v), {
color: axis.minorgridcolor,
width: axis.minorgridwidth,
dash: axis.minorgriddash
}));
}
}
if (axis.startline) {
boundarylines.push(extendFlat(constructArrayGridline(0), {
color: axis.startlinecolor,
width: axis.startlinewidth
}));
}
if (axis.endline) {
boundarylines.push(extendFlat(constructArrayGridline(data.length - 1), {
color: axis.endlinecolor,
width: axis.endlinewidth
}));
}
} else {
// If the lines do not fall along the axes, then we have to interpolate
// the contro points and so some math to figure out where the lines are
// in the first place.
// Compute the integer boudns of tick0 + n * dtick that fall within the range
// (roughly speaking):
// Give this a nice generous epsilon. We use at as * (1 + eps) in order to make
// inequalities a little tolerant in a more or less correct manner:
eps = 5e-15;
bounds = [Math.floor((data[data.length - 1] - axis.tick0) / axis.dtick * (1 + eps)), Math.ceil((data[0] - axis.tick0) / axis.dtick / (1 + eps))].sort(function (a, b) {
return a - b;
});
// Unpack sorted values so we can be sure to avoid infinite loops if something
// is backwards:
n1 = bounds[0];
n2 = bounds[1];
for (n = n1; n <= n2; n++) {
value = axis.tick0 + axis.dtick * n;
gridlines.push(extendFlat(constructValueGridline(value), {
color: axis.gridcolor,
width: axis.gridwidth,
dash: axis.griddash
}));
}
for (n = n1 - 1; n < n2 + 1; n++) {
value = axis.tick0 + axis.dtick * n;
for (i = 0; i < axis.minorgridcount; i++) {
v = value + axis.dtick * (i + 1) / (axis.minorgridcount + 1);
if (v < data[0] || v > data[data.length - 1]) continue;
minorgridlines.push(extendFlat(constructValueGridline(v), {
color: axis.minorgridcolor,
width: axis.minorgridwidth,
dash: axis.minorgriddash
}));
}
}
if (axis.startline) {
boundarylines.push(extendFlat(constructValueGridline(data[0]), {
color: axis.startlinecolor,
width: axis.startlinewidth
}));
}
if (axis.endline) {
boundarylines.push(extendFlat(constructValueGridline(data[data.length - 1]), {
color: axis.endlinecolor,
width: axis.endlinewidth
}));
}
}
};
/***/ }),
/***/ 97708:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = function calcLabels(trace, axis) {
var i, tobj, prefix, suffix, gridline;
var labels = axis._labels = [];
var gridlines = axis._gridlines;
for (i = 0; i < gridlines.length; i++) {
gridline = gridlines[i];
if (['start', 'both'].indexOf(axis.showticklabels) !== -1) {
tobj = Axes.tickText(axis, gridline.value);
extendFlat(tobj, {
prefix: prefix,
suffix: suffix,
endAnchor: true,
xy: gridline.xy(0),
dxy: gridline.dxy(0, 0),
axis: gridline.axis,
length: gridline.crossAxis.length,
font: gridline.axis.tickfont,
isFirst: i === 0,
isLast: i === gridlines.length - 1
});
labels.push(tobj);
}
if (['end', 'both'].indexOf(axis.showticklabels) !== -1) {
tobj = Axes.tickText(axis, gridline.value);
extendFlat(tobj, {
endAnchor: false,
xy: gridline.xy(gridline.crossLength - 1),
dxy: gridline.dxy(gridline.crossLength - 2, 1),
axis: gridline.axis,
length: gridline.crossAxis.length,
font: gridline.axis.tickfont,
isFirst: i === 0,
isLast: i === gridlines.length - 1
});
labels.push(tobj);
}
}
};
/***/ }),
/***/ 1016:
/***/ (function(module) {
"use strict";
/*
* Compute the tangent vector according to catmull-rom cubic splines (centripetal,
* I think). That differs from the control point in two ways:
* 1. It is a vector, not a position relative to the point
* 2. the vector is longer than the position relative to p1 by a factor of 3
*
* Close to the boundaries, we'll use these as *quadratic control points, so that
* to make a nice grid, we'll need to divide the tangent by 2 instead of 3. (The
* math works out this way if you work through the bezier derivatives)
*/
var CatmullRomExp = 0.5;
module.exports = function makeControlPoints(p0, p1, p2, smoothness) {
var d1x = p0[0] - p1[0];
var d1y = p0[1] - p1[1];
var d2x = p2[0] - p1[0];
var d2y = p2[1] - p1[1];
var d1a = Math.pow(d1x * d1x + d1y * d1y, CatmullRomExp / 2);
var d2a = Math.pow(d2x * d2x + d2y * d2y, CatmullRomExp / 2);
var numx = (d2a * d2a * d1x - d1a * d1a * d2x) * smoothness;
var numy = (d2a * d2a * d1y - d1a * d1a * d2y) * smoothness;
var denom1 = d2a * (d1a + d2a) * 3;
var denom2 = d1a * (d1a + d2a) * 3;
return [[p1[0] + (denom1 && numx / denom1), p1[1] + (denom1 && numy / denom1)], [p1[0] - (denom2 && numx / denom2), p1[1] - (denom2 && numy / denom2)]];
};
/***/ }),
/***/ 43700:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
/*
* Construct a 2D array of cheater values given a, b, and a slope.
* If
*/
module.exports = function (a, b, cheaterslope) {
var i, j, ascal, bscal, aval, bval;
var data = [];
var na = isArrayOrTypedArray(a) ? a.length : a;
var nb = isArrayOrTypedArray(b) ? b.length : b;
var adata = isArrayOrTypedArray(a) ? a : null;
var bdata = isArrayOrTypedArray(b) ? b : null;
// If we're using data, scale it so that for data that's just barely
// not evenly spaced, the switch to value-based indexing is continuous.
// This means evenly spaced data should look the same whether value
// or index cheatertype.
if (adata) {
ascal = (adata.length - 1) / (adata[adata.length - 1] - adata[0]) / (na - 1);
}
if (bdata) {
bscal = (bdata.length - 1) / (bdata[bdata.length - 1] - bdata[0]) / (nb - 1);
}
var xval;
var xmin = Infinity;
var xmax = -Infinity;
for (j = 0; j < nb; j++) {
data[j] = [];
bval = bdata ? (bdata[j] - bdata[0]) * bscal : j / (nb - 1);
for (i = 0; i < na; i++) {
aval = adata ? (adata[i] - adata[0]) * ascal : i / (na - 1);
xval = aval - bval * cheaterslope;
xmin = Math.min(xval, xmin);
xmax = Math.max(xval, xmax);
data[j][i] = xval;
}
}
// Normalize cheater values to the 0-1 range. This comes into play when you have
// multiple cheater plots. After careful consideration, it seems better if cheater
// values are normalized to a consistent range. Otherwise one cheater affects the
// layout of other cheaters on the same axis.
var slope = 1.0 / (xmax - xmin);
var offset = -xmin * slope;
for (j = 0; j < nb; j++) {
for (i = 0; i < na; i++) {
data[j][i] = slope * data[j][i] + offset;
}
}
return data;
};
/***/ }),
/***/ 4228:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var makeControlPoints = __webpack_require__(1016);
var ensureArray = (__webpack_require__(10923).ensureArray);
/*
* Turns a coarse grid into a fine grid with control points.
*
* Here's an ASCII representation:
*
* o ----- o ----- o ----- o
* | | | |
* | | | |
* | | | |
* o ----- o ----- o ----- o
* | | | |
* | | | |
* ^ | | | |
* | o ----- o ----- o ----- o
* b | | | | |
* | | | | |
* | | | | |
* o ----- o ----- o ----- o
* ------>
* a
*
* First of all, note that we want to do this in *cartesian* space. This means
* we might run into problems when there are extreme differences in x/y scaling,
* but the alternative is that the topology of the contours might actually be
* view-dependent, which seems worse. As a fallback, the only parameter that
* actually affects the result is the *aspect ratio*, so that we can at least
* improve the situation a bit without going all the way to screen coordinates.
*
* This function flattens the points + tangents into a slightly denser grid of
* *control points*. The resulting grid looks like this:
*
* 9 +--o-o--+ -o-o--+--o-o--+
* 8 o o o o o o o o o o
* | | | |
* 7 o o o o o o o o o o
* 6 +--o-o--+ -o-o--+--o-o--+
* 5 o o o o o o o o o o
* | | | |
* ^ 4 o o o o o o o o o o
* | 3 +--o-o--+ -o-o--+--o-o--+
* b | 2 o o o o o o o o o o
* | | | | |
* | 1 o o o o o o o o o o
* 0 +--o-o--+ -o-o--+--o-o--+
* 0 1 2 3 4 5 6 7 8 9
* ------>
* a
*
* where `o`s represent newly-computed control points. the resulting dimension is
*
* (m - 1) * 3 + 1
* = 3 * m - 2
*
* We could simply store the tangents separately, but that's a nightmare to organize
* in two dimensions since we'll be slicing grid lines in both directions and since
* that basically requires very nearly just as much storage as just storing the dense
* grid.
*
* Wow!
*/
/*
* Catmull-rom is biased at the boundaries toward the interior and we actually
* can't use catmull-rom to compute the control point closest to (but inside)
* the boundary.
*
* A note on plotly's spline interpolation. It uses the catmull rom control point
* closest to the boundary *as* a quadratic control point. This seems incorrect,
* so I've elected not to follow that. Given control points 0 and 1, regular plotly
* splines give *equivalent* cubic control points:
*
* Input:
*
* boundary
* | |
* p0 p2 p3 --> interior
* 0.0 0.667 1.0
* | |
*
* Cubic-equivalent of what plotly splines draw::
*
* boundary
* | |
* p0 p1 p2 p3 --> interior
* 0.0 0.4444 0.8888 1.0
* | |
*
* What this function fills in:
*
* boundary
* | |
* p0 p1 p2 p3 --> interior
* 0.0 0.333 0.667 1.0
* | |
*
* Parameters:
* p0: boundary point
* p2: catmull rom point based on computation at p3
* p3: first grid point
*
* Of course it works whichever way it's oriented; you just need to interpret the
* input/output accordingly.
*/
function inferCubicControlPoint(p0, p2, p3) {
// Extend p1 away from p0 by 50%. This is the equivalent quadratic point that
// would give the same slope as catmull rom at p0.
var p2e0 = -0.5 * p3[0] + 1.5 * p2[0];
var p2e1 = -0.5 * p3[1] + 1.5 * p2[1];
return [(2 * p2e0 + p0[0]) / 3, (2 * p2e1 + p0[1]) / 3];
}
module.exports = function computeControlPoints(xe, ye, x, y, asmoothing, bsmoothing) {
var i, j, ie, je, xej, yej, xj, yj, cp, p1;
// At this point, we know these dimensions are correct and representative of
// the whole 2D arrays:
var na = x[0].length;
var nb = x.length;
// (n)umber of (e)xpanded points:
var nea = asmoothing ? 3 * na - 2 : na;
var neb = bsmoothing ? 3 * nb - 2 : nb;
xe = ensureArray(xe, neb);
ye = ensureArray(ye, neb);
for (ie = 0; ie < neb; ie++) {
xe[ie] = ensureArray(xe[ie], nea);
ye[ie] = ensureArray(ye[ie], nea);
}
// This loop fills in the X'd points:
//
// . . . .
// . . . .
// | | | |
// | | | |
// X ----- X ----- X ----- X
// | | | |
// | | | |
// | | | |
// X ----- X ----- X ----- X
//
//
// ie = (i) (e)xpanded:
for (j = 0, je = 0; j < nb; j++, je += bsmoothing ? 3 : 1) {
xej = xe[je];
yej = ye[je];
xj = x[j];
yj = y[j];
// je = (j) (e)xpanded:
for (i = 0, ie = 0; i < na; i++, ie += asmoothing ? 3 : 1) {
xej[ie] = xj[i];
yej[ie] = yj[i];
}
}
if (asmoothing) {
// If there's a-smoothing, this loop fills in the X'd points with catmull-rom
// control points computed along the a-axis:
// . . . .
// . . . .
// | | | |
// | | | |
// o -Y-X- o -X-X- o -X-Y- o
// | | | |
// | | | |
// | | | |
// o -Y-X- o -X-X- o -X-Y- o
//
// i: 0 1 2 3
// ie: 0 1 3 3 4 5 6 7 8 9
//
// ------>
// a
//
for (j = 0, je = 0; j < nb; j++, je += bsmoothing ? 3 : 1) {
// Fill in the points marked X for this a-row:
for (i = 1, ie = 3; i < na - 1; i++, ie += 3) {
cp = makeControlPoints([x[j][i - 1], y[j][i - 1]], [x[j][i], y[j][i]], [x[j][i + 1], y[j][i + 1]], asmoothing);
xe[je][ie - 1] = cp[0][0];
ye[je][ie - 1] = cp[0][1];
xe[je][ie + 1] = cp[1][0];
ye[je][ie + 1] = cp[1][1];
}
// The very first cubic interpolation point (to the left for i = 1 above) is
// used as a *quadratic* interpolation point by the spline drawing function
// which isn't really correct. But for the sake of consistency, we'll use it
// as such. Since we're using cubic splines, that means we need to shorten the
// tangent by 1/3 and also construct a new cubic spline control point 1/3 from
// the original to the i = 0 point.
p1 = inferCubicControlPoint([xe[je][0], ye[je][0]], [xe[je][2], ye[je][2]], [xe[je][3], ye[je][3]]);
xe[je][1] = p1[0];
ye[je][1] = p1[1];
// Ditto last points, sans explanation:
p1 = inferCubicControlPoint([xe[je][nea - 1], ye[je][nea - 1]], [xe[je][nea - 3], ye[je][nea - 3]], [xe[je][nea - 4], ye[je][nea - 4]]);
xe[je][nea - 2] = p1[0];
ye[je][nea - 2] = p1[1];
}
}
if (bsmoothing) {
// If there's a-smoothing, this loop fills in the X'd points with catmull-rom
// control points computed along the b-axis:
// . . . .
// X X X X X X X X X X
// | | | |
// X X X X X X X X X X
// o -o-o- o -o-o- o -o-o- o
// X X X X X X X X X X
// | | | |
// Y Y Y Y Y Y Y Y Y Y
// o -o-o- o -o-o- o -o-o- o
//
// i: 0 1 2 3
// ie: 0 1 3 3 4 5 6 7 8 9
//
// ------>
// a
//
for (ie = 0; ie < nea; ie++) {
for (je = 3; je < neb - 3; je += 3) {
cp = makeControlPoints([xe[je - 3][ie], ye[je - 3][ie]], [xe[je][ie], ye[je][ie]], [xe[je + 3][ie], ye[je + 3][ie]], bsmoothing);
xe[je - 1][ie] = cp[0][0];
ye[je - 1][ie] = cp[0][1];
xe[je + 1][ie] = cp[1][0];
ye[je + 1][ie] = cp[1][1];
}
// Do the same boundary condition magic for these control points marked Y above:
p1 = inferCubicControlPoint([xe[0][ie], ye[0][ie]], [xe[2][ie], ye[2][ie]], [xe[3][ie], ye[3][ie]]);
xe[1][ie] = p1[0];
ye[1][ie] = p1[1];
p1 = inferCubicControlPoint([xe[neb - 1][ie], ye[neb - 1][ie]], [xe[neb - 3][ie], ye[neb - 3][ie]], [xe[neb - 4][ie], ye[neb - 4][ie]]);
xe[neb - 2][ie] = p1[0];
ye[neb - 2][ie] = p1[1];
}
}
if (asmoothing && bsmoothing) {
// Do one more pass, this time recomputing exactly what we just computed.
// It's overdetermined since we're peforming catmull-rom in two directions,
// so we'll just average the overdetermined. These points don't lie along the
// grid lines, so note that only grid lines will follow normal plotly spline
// interpolation.
//
// Unless of course there was no b smoothing. Then these intermediate points
// don't actually exist and this section is bypassed.
// . . . .
// o X X o X X o X X o
// | | | |
// o X X o X X o X X o
// o -o-o- o -o-o- o -o-o- o
// o X X o X X o X X o
// | | | |
// o Y Y o Y Y o Y Y o
// o -o-o- o -o-o- o -o-o- o
//
// i: 0 1 2 3
// ie: 0 1 3 3 4 5 6 7 8 9
//
// ------>
// a
//
for (je = 1; je < neb; je += (je + 1) % 3 === 0 ? 2 : 1) {
// Fill in the points marked X for this a-row:
for (ie = 3; ie < nea - 3; ie += 3) {
cp = makeControlPoints([xe[je][ie - 3], ye[je][ie - 3]], [xe[je][ie], ye[je][ie]], [xe[je][ie + 3], ye[je][ie + 3]], asmoothing);
xe[je][ie - 1] = 0.5 * (xe[je][ie - 1] + cp[0][0]);
ye[je][ie - 1] = 0.5 * (ye[je][ie - 1] + cp[0][1]);
xe[je][ie + 1] = 0.5 * (xe[je][ie + 1] + cp[1][0]);
ye[je][ie + 1] = 0.5 * (ye[je][ie + 1] + cp[1][1]);
}
// This case is just slightly different. The computation is the same,
// but having computed this, we'll average with the existing result.
p1 = inferCubicControlPoint([xe[je][0], ye[je][0]], [xe[je][2], ye[je][2]], [xe[je][3], ye[je][3]]);
xe[je][1] = 0.5 * (xe[je][1] + p1[0]);
ye[je][1] = 0.5 * (ye[je][1] + p1[1]);
p1 = inferCubicControlPoint([xe[je][nea - 1], ye[je][nea - 1]], [xe[je][nea - 3], ye[je][nea - 3]], [xe[je][nea - 4], ye[je][nea - 4]]);
xe[je][nea - 2] = 0.5 * (xe[je][nea - 2] + p1[0]);
ye[je][nea - 2] = 0.5 * (ye[je][nea - 2] + p1[1]);
}
}
return [xe, ye];
};
/***/ }),
/***/ 25716:
/***/ (function(module) {
"use strict";
module.exports = {
RELATIVE_CULL_TOLERANCE: 1e-6
};
/***/ }),
/***/ 72936:
/***/ (function(module) {
"use strict";
/*
* Evaluates the derivative of a list of control point arrays. That is, it expects an array or arrays
* that are expanded relative to the raw data to include the bicubic control points, if applicable. If
* only linear interpolation is desired, then the data points correspond 1-1 along that axis to the
* data itself. Since it's catmull-rom splines in either direction note in particular that the
* derivatives are discontinuous across cell boundaries. That's the reason you need both the *cell*
* and the *point within the cell*.
*
* Also note that the discontinuity of the derivative is in magnitude only. The direction *is*
* continuous across cell boundaries.
*
* For example, to compute the derivative of the xcoordinate halfway between the 7 and 8th i-gridpoints
* and the 10th and 11th j-gridpoints given bicubic smoothing in both dimensions, you'd write:
*
* var deriv = createIDerivativeEvaluator([x], 1, 1);
*
* var dxdi = deriv([], 7, 10, 0.5, 0.5);
* // => [0.12345]
*
* Since there'd be a bunch of duplicate computation to compute multiple derivatives, you can double
* this up by providing more arrays:
*
* var deriv = createIDerivativeEvaluator([x, y], 1, 1);
*
* var dxdi = deriv([], 7, 10, 0.5, 0.5);
* // => [0.12345, 0.78910]
*
* NB: It's presumed that at this point all data has been sanitized and is valid numerical data arrays
* of the correct dimension.
*/
module.exports = function (arrays, asmoothing, bsmoothing) {
if (asmoothing && bsmoothing) {
return function (out, i0, j0, u, v) {
if (!out) out = [];
var f0, f1, f2, f3, ak, k;
// Since it's a grid of control points, the actual indices are * 3:
i0 *= 3;
j0 *= 3;
// Precompute some numbers:
var u2 = u * u;
var ou = 1 - u;
var ou2 = ou * ou;
var ouu2 = ou * u * 2;
var a = -3 * ou2;
var b = 3 * (ou2 - ouu2);
var c = 3 * (ouu2 - u2);
var d = 3 * u2;
var v2 = v * v;
var v3 = v2 * v;
var ov = 1 - v;
var ov2 = ov * ov;
var ov3 = ov2 * ov;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
// Compute the derivatives in the u-direction:
f0 = a * ak[j0][i0] + b * ak[j0][i0 + 1] + c * ak[j0][i0 + 2] + d * ak[j0][i0 + 3];
f1 = a * ak[j0 + 1][i0] + b * ak[j0 + 1][i0 + 1] + c * ak[j0 + 1][i0 + 2] + d * ak[j0 + 1][i0 + 3];
f2 = a * ak[j0 + 2][i0] + b * ak[j0 + 2][i0 + 1] + c * ak[j0 + 2][i0 + 2] + d * ak[j0 + 2][i0 + 3];
f3 = a * ak[j0 + 3][i0] + b * ak[j0 + 3][i0 + 1] + c * ak[j0 + 3][i0 + 2] + d * ak[j0 + 3][i0 + 3];
// Now just interpolate in the v-direction since it's all separable:
out[k] = ov3 * f0 + 3 * (ov2 * v * f1 + ov * v2 * f2) + v3 * f3;
}
return out;
};
} else if (asmoothing) {
// Handle smooth in the a-direction but linear in the b-direction by performing four
// linear interpolations followed by one cubic interpolation of the result
return function (out, i0, j0, u, v) {
if (!out) out = [];
var f0, f1, k, ak;
i0 *= 3;
var u2 = u * u;
var ou = 1 - u;
var ou2 = ou * ou;
var ouu2 = ou * u * 2;
var a = -3 * ou2;
var b = 3 * (ou2 - ouu2);
var c = 3 * (ouu2 - u2);
var d = 3 * u2;
var ov = 1 - v;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = a * ak[j0][i0] + b * ak[j0][i0 + 1] + c * ak[j0][i0 + 2] + d * ak[j0][i0 + 3];
f1 = a * ak[j0 + 1][i0] + b * ak[j0 + 1][i0 + 1] + c * ak[j0 + 1][i0 + 2] + d * ak[j0 + 1][i0 + 3];
out[k] = ov * f0 + v * f1;
}
return out;
};
} else if (bsmoothing) {
// Same as the above case, except reversed. I've disabled the no-unused vars rule
// so that this function is fully interpolation-agnostic. Otherwise it would need
// to be called differently in different cases. Which wouldn't be the worst, but
/* eslint-disable no-unused-vars */
return function (out, i0, j0, u, v) {
/* eslint-enable no-unused-vars */
if (!out) out = [];
var f0, f1, f2, f3, k, ak;
j0 *= 3;
var v2 = v * v;
var v3 = v2 * v;
var ov = 1 - v;
var ov2 = ov * ov;
var ov3 = ov2 * ov;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = ak[j0][i0 + 1] - ak[j0][i0];
f1 = ak[j0 + 1][i0 + 1] - ak[j0 + 1][i0];
f2 = ak[j0 + 2][i0 + 1] - ak[j0 + 2][i0];
f3 = ak[j0 + 3][i0 + 1] - ak[j0 + 3][i0];
out[k] = ov3 * f0 + 3 * (ov2 * v * f1 + ov * v2 * f2) + v3 * f3;
}
return out;
};
} else {
// Finally, both directions are linear:
/* eslint-disable no-unused-vars */
return function (out, i0, j0, u, v) {
/* eslint-enable no-unused-vars */
if (!out) out = [];
var f0, f1, k, ak;
var ov = 1 - v;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = ak[j0][i0 + 1] - ak[j0][i0];
f1 = ak[j0 + 1][i0 + 1] - ak[j0 + 1][i0];
out[k] = ov * f0 + v * f1;
}
return out;
};
}
};
/***/ }),
/***/ 92064:
/***/ (function(module) {
"use strict";
module.exports = function (arrays, asmoothing, bsmoothing) {
if (asmoothing && bsmoothing) {
return function (out, i0, j0, u, v) {
if (!out) out = [];
var f0, f1, f2, f3, ak, k;
// Since it's a grid of control points, the actual indices are * 3:
i0 *= 3;
j0 *= 3;
// Precompute some numbers:
var u2 = u * u;
var u3 = u2 * u;
var ou = 1 - u;
var ou2 = ou * ou;
var ou3 = ou2 * ou;
var v2 = v * v;
var ov = 1 - v;
var ov2 = ov * ov;
var ovv2 = ov * v * 2;
var a = -3 * ov2;
var b = 3 * (ov2 - ovv2);
var c = 3 * (ovv2 - v2);
var d = 3 * v2;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
// Compute the derivatives in the v-direction:
f0 = a * ak[j0][i0] + b * ak[j0 + 1][i0] + c * ak[j0 + 2][i0] + d * ak[j0 + 3][i0];
f1 = a * ak[j0][i0 + 1] + b * ak[j0 + 1][i0 + 1] + c * ak[j0 + 2][i0 + 1] + d * ak[j0 + 3][i0 + 1];
f2 = a * ak[j0][i0 + 2] + b * ak[j0 + 1][i0 + 2] + c * ak[j0 + 2][i0 + 2] + d * ak[j0 + 3][i0 + 2];
f3 = a * ak[j0][i0 + 3] + b * ak[j0 + 1][i0 + 3] + c * ak[j0 + 2][i0 + 3] + d * ak[j0 + 3][i0 + 3];
// Now just interpolate in the v-direction since it's all separable:
out[k] = ou3 * f0 + 3 * (ou2 * u * f1 + ou * u2 * f2) + u3 * f3;
}
return out;
};
} else if (asmoothing) {
// Handle smooth in the a-direction but linear in the b-direction by performing four
// linear interpolations followed by one cubic interpolation of the result
return function (out, i0, j0, v, u) {
if (!out) out = [];
var f0, f1, f2, f3, k, ak;
i0 *= 3;
var u2 = u * u;
var u3 = u2 * u;
var ou = 1 - u;
var ou2 = ou * ou;
var ou3 = ou2 * ou;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = ak[j0 + 1][i0] - ak[j0][i0];
f1 = ak[j0 + 1][i0 + 1] - ak[j0][i0 + 1];
f2 = ak[j0 + 1][i0 + 2] - ak[j0][i0 + 2];
f3 = ak[j0 + 1][i0 + 3] - ak[j0][i0 + 3];
out[k] = ou3 * f0 + 3 * (ou2 * u * f1 + ou * u2 * f2) + u3 * f3;
// mathematically equivalent:
// f0 = ou3 * ak[j0 ][i0] + 3 * (ou2 * u * ak[j0 ][i0 + 1] + ou * u2 * ak[j0 ][i0 + 2]) + u3 * ak[j0 ][i0 + 3];
// f1 = ou3 * ak[j0 + 1][i0] + 3 * (ou2 * u * ak[j0 + 1][i0 + 1] + ou * u2 * ak[j0 + 1][i0 + 2]) + u3 * ak[j0 + 1][i0 + 3];
// out[k] = f1 - f0;
}
return out;
};
} else if (bsmoothing) {
// Same as the above case, except reversed:
/* eslint-disable no-unused-vars */
return function (out, i0, j0, u, v) {
/* eslint-enable no-unused-vars */
if (!out) out = [];
var f0, f1, k, ak;
j0 *= 3;
var ou = 1 - u;
var v2 = v * v;
var ov = 1 - v;
var ov2 = ov * ov;
var ovv2 = ov * v * 2;
var a = -3 * ov2;
var b = 3 * (ov2 - ovv2);
var c = 3 * (ovv2 - v2);
var d = 3 * v2;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = a * ak[j0][i0] + b * ak[j0 + 1][i0] + c * ak[j0 + 2][i0] + d * ak[j0 + 3][i0];
f1 = a * ak[j0][i0 + 1] + b * ak[j0 + 1][i0 + 1] + c * ak[j0 + 2][i0 + 1] + d * ak[j0 + 3][i0 + 1];
out[k] = ou * f0 + u * f1;
}
return out;
};
} else {
// Finally, both directions are linear:
/* eslint-disable no-unused-vars */
return function (out, i0, j0, v, u) {
/* eslint-enable no-unused-vars */
if (!out) out = [];
var f0, f1, k, ak;
var ov = 1 - v;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = ak[j0 + 1][i0] - ak[j0][i0];
f1 = ak[j0 + 1][i0 + 1] - ak[j0][i0 + 1];
out[k] = ov * f0 + v * f1;
}
return out;
};
}
};
/***/ }),
/***/ 67672:
/***/ (function(module) {
"use strict";
/*
* Return a function that evaluates a set of linear or bicubic control points.
* This will get evaluated a lot, so we'll at least do a bit of extra work to
* flatten some of the choices. In particular, we'll unroll the linear/bicubic
* combinations and we'll allow computing results in parallel to cut down
* on repeated arithmetic.
*
* Take note that we don't search for the correct range in this function. The
* reason is for consistency due to the corrresponding derivative function. In
* particular, the derivatives aren't continuous across cells, so it's important
* to be able control whether the derivative at a cell boundary is approached
* from one side or the other.
*/
module.exports = function (arrays, na, nb, asmoothing, bsmoothing) {
var imax = na - 2;
var jmax = nb - 2;
if (asmoothing && bsmoothing) {
return function (out, i, j) {
if (!out) out = [];
var f0, f1, f2, f3, ak, k;
var i0 = Math.max(0, Math.min(Math.floor(i), imax));
var j0 = Math.max(0, Math.min(Math.floor(j), jmax));
var u = Math.max(0, Math.min(1, i - i0));
var v = Math.max(0, Math.min(1, j - j0));
// Since it's a grid of control points, the actual indices are * 3:
i0 *= 3;
j0 *= 3;
// Precompute some numbers:
var u2 = u * u;
var u3 = u2 * u;
var ou = 1 - u;
var ou2 = ou * ou;
var ou3 = ou2 * ou;
var v2 = v * v;
var v3 = v2 * v;
var ov = 1 - v;
var ov2 = ov * ov;
var ov3 = ov2 * ov;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = ou3 * ak[j0][i0] + 3 * (ou2 * u * ak[j0][i0 + 1] + ou * u2 * ak[j0][i0 + 2]) + u3 * ak[j0][i0 + 3];
f1 = ou3 * ak[j0 + 1][i0] + 3 * (ou2 * u * ak[j0 + 1][i0 + 1] + ou * u2 * ak[j0 + 1][i0 + 2]) + u3 * ak[j0 + 1][i0 + 3];
f2 = ou3 * ak[j0 + 2][i0] + 3 * (ou2 * u * ak[j0 + 2][i0 + 1] + ou * u2 * ak[j0 + 2][i0 + 2]) + u3 * ak[j0 + 2][i0 + 3];
f3 = ou3 * ak[j0 + 3][i0] + 3 * (ou2 * u * ak[j0 + 3][i0 + 1] + ou * u2 * ak[j0 + 3][i0 + 2]) + u3 * ak[j0 + 3][i0 + 3];
out[k] = ov3 * f0 + 3 * (ov2 * v * f1 + ov * v2 * f2) + v3 * f3;
}
return out;
};
} else if (asmoothing) {
// Handle smooth in the a-direction but linear in the b-direction by performing four
// linear interpolations followed by one cubic interpolation of the result
return function (out, i, j) {
if (!out) out = [];
var i0 = Math.max(0, Math.min(Math.floor(i), imax));
var j0 = Math.max(0, Math.min(Math.floor(j), jmax));
var u = Math.max(0, Math.min(1, i - i0));
var v = Math.max(0, Math.min(1, j - j0));
var f0, f1, f2, f3, k, ak;
i0 *= 3;
var u2 = u * u;
var u3 = u2 * u;
var ou = 1 - u;
var ou2 = ou * ou;
var ou3 = ou2 * ou;
var ov = 1 - v;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = ov * ak[j0][i0] + v * ak[j0 + 1][i0];
f1 = ov * ak[j0][i0 + 1] + v * ak[j0 + 1][i0 + 1];
f2 = ov * ak[j0][i0 + 2] + v * ak[j0 + 1][i0 + 1];
f3 = ov * ak[j0][i0 + 3] + v * ak[j0 + 1][i0 + 1];
out[k] = ou3 * f0 + 3 * (ou2 * u * f1 + ou * u2 * f2) + u3 * f3;
}
return out;
};
} else if (bsmoothing) {
// Same as the above case, except reversed:
return function (out, i, j) {
if (!out) out = [];
var i0 = Math.max(0, Math.min(Math.floor(i), imax));
var j0 = Math.max(0, Math.min(Math.floor(j), jmax));
var u = Math.max(0, Math.min(1, i - i0));
var v = Math.max(0, Math.min(1, j - j0));
var f0, f1, f2, f3, k, ak;
j0 *= 3;
var v2 = v * v;
var v3 = v2 * v;
var ov = 1 - v;
var ov2 = ov * ov;
var ov3 = ov2 * ov;
var ou = 1 - u;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = ou * ak[j0][i0] + u * ak[j0][i0 + 1];
f1 = ou * ak[j0 + 1][i0] + u * ak[j0 + 1][i0 + 1];
f2 = ou * ak[j0 + 2][i0] + u * ak[j0 + 2][i0 + 1];
f3 = ou * ak[j0 + 3][i0] + u * ak[j0 + 3][i0 + 1];
out[k] = ov3 * f0 + 3 * (ov2 * v * f1 + ov * v2 * f2) + v3 * f3;
}
return out;
};
} else {
// Finally, both directions are linear:
return function (out, i, j) {
if (!out) out = [];
var i0 = Math.max(0, Math.min(Math.floor(i), imax));
var j0 = Math.max(0, Math.min(Math.floor(j), jmax));
var u = Math.max(0, Math.min(1, i - i0));
var v = Math.max(0, Math.min(1, j - j0));
var f0, f1, k, ak;
var ov = 1 - v;
var ou = 1 - u;
for (k = 0; k < arrays.length; k++) {
ak = arrays[k];
f0 = ou * ak[j0][i0] + u * ak[j0][i0 + 1];
f1 = ou * ak[j0 + 1][i0] + u * ak[j0 + 1][i0 + 1];
out[k] = ov * f0 + v * f1;
}
return out;
};
}
};
/***/ }),
/***/ 43536:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleXYDefaults = __webpack_require__(10259);
var handleABDefaults = __webpack_require__(70480);
var attributes = __webpack_require__(74576);
var colorAttrs = __webpack_require__(51468);
module.exports = function supplyDefaults(traceIn, traceOut, dfltColor, fullLayout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
traceOut._clipPathId = 'clip' + traceOut.uid + 'carpet';
var defaultColor = coerce('color', colorAttrs.defaultLine);
Lib.coerceFont(coerce, 'font');
coerce('carpet');
handleABDefaults(traceIn, traceOut, fullLayout, coerce, defaultColor);
if (!traceOut.a || !traceOut.b) {
traceOut.visible = false;
return;
}
if (traceOut.a.length < 3) {
traceOut.aaxis.smoothing = 0;
}
if (traceOut.b.length < 3) {
traceOut.baxis.smoothing = 0;
}
// NB: the input is x/y arrays. You should know that the *first* dimension of x and y
// corresponds to b and the second to a. This sounds backwards but ends up making sense
// the important part to know is that when you write y[j][i], j goes from 0 to b.length - 1
// and i goes from 0 to a.length - 1.
var validData = handleXYDefaults(traceIn, traceOut, coerce);
if (!validData) {
traceOut.visible = false;
}
if (traceOut._cheater) {
coerce('cheaterslope');
}
coerce('zorder');
};
/***/ }),
/***/ 10600:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(74576),
supplyDefaults: __webpack_require__(43536),
plot: __webpack_require__(70904),
calc: __webpack_require__(44883),
animatable: true,
isContainer: true,
// so carpet traces get `calc` before other traces
moduleType: 'trace',
name: 'carpet',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', 'carpet', 'carpetAxis', 'notLegendIsolatable', 'noMultiCategory', 'noHover', 'noSortingByValue'],
meta: {
description: ['The data describing carpet axis layout is set in `y` and (optionally)', 'also `x`. If only `y` is present, `x` the plot is interpreted as a', 'cheater plot and is filled in using the `y` values.', '`x` and `y` may either be 2D arrays matching with each dimension matching', 'that of `a` and `b`, or they may be 1D arrays with total length equal to', 'that of `a` and `b`.'].join(' ')
}
};
/***/ }),
/***/ 62952:
/***/ (function(module) {
"use strict";
/*
* Given a trace, look up the carpet axis by carpet.
*/
module.exports = function (gd, trace) {
var n = gd._fullData.length;
var firstAxis;
for (var i = 0; i < n; i++) {
var maybeCarpet = gd._fullData[i];
if (maybeCarpet.index === trace.index) continue;
if (maybeCarpet.type === 'carpet') {
if (!firstAxis) {
firstAxis = maybeCarpet;
}
if (maybeCarpet.carpet === trace.carpet) {
return maybeCarpet;
}
}
}
return firstAxis;
};
/***/ }),
/***/ 1280:
/***/ (function(module) {
"use strict";
module.exports = function makePath(xp, yp, isBicubic) {
// Prevent d3 errors that would result otherwise:
if (xp.length === 0) return '';
var i;
var path = [];
var stride = isBicubic ? 3 : 1;
for (i = 0; i < xp.length; i += stride) {
path.push(xp[i] + ',' + yp[i]);
if (isBicubic && i < xp.length - stride) {
path.push('C');
path.push([xp[i + 1] + ',' + yp[i + 1], xp[i + 2] + ',' + yp[i + 2] + ' '].join(' '));
}
}
return path.join(isBicubic ? '' : 'L');
};
/***/ }),
/***/ 25492:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
/*
* Map an array of x or y coordinates (c) to screen-space pixel coordinates (p).
* The output array is optional, but if provided, it will be reused without
* reallocation to the extent possible.
*/
module.exports = function mapArray(out, data, func) {
var i;
if (!isArrayOrTypedArray(out)) {
// If not an array, make it an array:
out = [];
} else if (out.length > data.length) {
// If too long, truncate. (If too short, it will grow
// automatically so we don't care about that case)
out = out.slice(0, data.length);
}
for (i = 0; i < data.length; i++) {
out[i] = func(data[i]);
}
return out;
};
/***/ }),
/***/ 26992:
/***/ (function(module) {
"use strict";
module.exports = function orientText(trace, xaxis, yaxis, xy, dxy, refDxy) {
var dx = dxy[0] * trace.dpdx(xaxis);
var dy = dxy[1] * trace.dpdy(yaxis);
var flip = 1;
var offsetMultiplier = 1.0;
if (refDxy) {
var l1 = Math.sqrt(dxy[0] * dxy[0] + dxy[1] * dxy[1]);
var l2 = Math.sqrt(refDxy[0] * refDxy[0] + refDxy[1] * refDxy[1]);
var dot = (dxy[0] * refDxy[0] + dxy[1] * refDxy[1]) / l1 / l2;
offsetMultiplier = Math.max(0.0, dot);
}
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
if (angle < -90) {
angle += 180;
flip = -flip;
} else if (angle > 90) {
angle -= 180;
flip = -flip;
}
return {
angle: angle,
flip: flip,
p: trace.c2p(xy, xaxis, yaxis),
offsetMultplier: offsetMultiplier
};
};
/***/ }),
/***/ 70904:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Drawing = __webpack_require__(49348);
var map1dArray = __webpack_require__(25492);
var makepath = __webpack_require__(1280);
var orientText = __webpack_require__(26992);
var svgTextUtils = __webpack_require__(41536);
var Lib = __webpack_require__(10923);
var strRotate = Lib.strRotate;
var strTranslate = Lib.strTranslate;
var alignmentConstants = __webpack_require__(83784);
module.exports = function plot(gd, plotinfo, cdcarpet, carpetLayer) {
var isStatic = gd._context.staticPlot;
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var fullLayout = gd._fullLayout;
var clipLayer = fullLayout._clips;
Lib.makeTraceGroups(carpetLayer, cdcarpet, 'trace').each(function (cd) {
var axisLayer = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
var aax = trace.aaxis;
var bax = trace.baxis;
var minorLayer = Lib.ensureSingle(axisLayer, 'g', 'minorlayer');
var majorLayer = Lib.ensureSingle(axisLayer, 'g', 'majorlayer');
var boundaryLayer = Lib.ensureSingle(axisLayer, 'g', 'boundarylayer');
var labelLayer = Lib.ensureSingle(axisLayer, 'g', 'labellayer');
axisLayer.style('opacity', trace.opacity);
drawGridLines(xa, ya, majorLayer, aax, 'a', aax._gridlines, true, isStatic);
drawGridLines(xa, ya, majorLayer, bax, 'b', bax._gridlines, true, isStatic);
drawGridLines(xa, ya, minorLayer, aax, 'a', aax._minorgridlines, true, isStatic);
drawGridLines(xa, ya, minorLayer, bax, 'b', bax._minorgridlines, true, isStatic);
// NB: These are not omitted if the lines are not active. The joins must be executed
// in order for them to get cleaned up without a full redraw
drawGridLines(xa, ya, boundaryLayer, aax, 'a-boundary', aax._boundarylines, isStatic);
drawGridLines(xa, ya, boundaryLayer, bax, 'b-boundary', bax._boundarylines, isStatic);
var labelOrientationA = drawAxisLabels(gd, xa, ya, trace, cd0, labelLayer, aax._labels, 'a-label');
var labelOrientationB = drawAxisLabels(gd, xa, ya, trace, cd0, labelLayer, bax._labels, 'b-label');
drawAxisTitles(gd, labelLayer, trace, cd0, xa, ya, labelOrientationA, labelOrientationB);
drawClipPath(trace, cd0, clipLayer, xa, ya);
});
};
function drawClipPath(trace, t, layer, xaxis, yaxis) {
var seg, xp, yp, i;
var clip = layer.select('#' + trace._clipPathId);
if (!clip.size()) {
clip = layer.append('clipPath').classed('carpetclip', true);
}
var path = Lib.ensureSingle(clip, 'path', 'carpetboundary');
var segments = t.clipsegments;
var segs = [];
for (i = 0; i < segments.length; i++) {
seg = segments[i];
xp = map1dArray([], seg.x, xaxis.c2p);
yp = map1dArray([], seg.y, yaxis.c2p);
segs.push(makepath(xp, yp, seg.bicubic));
}
// This could be optimized ever so slightly to avoid no-op L segments
// at the corners, but it's so negligible that I don't think it's worth
// the extra complexity
var clipPathData = 'M' + segs.join('L') + 'Z';
clip.attr('id', trace._clipPathId);
path.attr('d', clipPathData);
}
function drawGridLines(xaxis, yaxis, layer, axis, axisLetter, gridlines, isStatic) {
var lineClass = 'const-' + axisLetter + '-lines';
var gridJoin = layer.selectAll('.' + lineClass).data(gridlines);
gridJoin.enter().append('path').classed(lineClass, true).style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke');
gridJoin.each(function (d) {
var gridline = d;
var x = gridline.x;
var y = gridline.y;
var xp = map1dArray([], x, xaxis.c2p);
var yp = map1dArray([], y, yaxis.c2p);
var path = 'M' + makepath(xp, yp, gridline.smoothing);
var el = d3.select(this);
el.attr('d', path).style('stroke-width', gridline.width).style('stroke', gridline.color).style('stroke-dasharray', Drawing.dashStyle(gridline.dash, gridline.width)).style('fill', 'none');
});
gridJoin.exit().remove();
}
function drawAxisLabels(gd, xaxis, yaxis, trace, t, layer, labels, labelClass) {
var labelJoin = layer.selectAll('text.' + labelClass).data(labels);
labelJoin.enter().append('text').classed(labelClass, true);
var maxExtent = 0;
var labelOrientation = {};
labelJoin.each(function (label, i) {
// Most of the positioning is done in calc_labels. Only the parts that depend upon
// the screen space representation of the x and y axes are here:
var orientation;
if (label.axis.tickangle === 'auto') {
orientation = orientText(trace, xaxis, yaxis, label.xy, label.dxy);
} else {
var angle = (label.axis.tickangle + 180.0) * Math.PI / 180.0;
orientation = orientText(trace, xaxis, yaxis, label.xy, [Math.cos(angle), Math.sin(angle)]);
}
if (!i) {
// TODO: offsetMultiplier? Not currently used anywhere...
labelOrientation = {
angle: orientation.angle,
flip: orientation.flip
};
}
var direction = (label.endAnchor ? -1 : 1) * orientation.flip;
var labelEl = d3.select(this).attr({
'text-anchor': direction > 0 ? 'start' : 'end',
'data-notex': 1
}).call(Drawing.font, label.font).text(label.text).call(svgTextUtils.convertToTspans, gd);
var bbox = Drawing.bBox(this);
labelEl.attr('transform',
// Translate to the correct point:
strTranslate(orientation.p[0], orientation.p[1]) +
// Rotate to line up with grid line tangent:
strRotate(orientation.angle) +
// Adjust the baseline and indentation:
strTranslate(label.axis.labelpadding * direction, bbox.height * 0.3));
maxExtent = Math.max(maxExtent, bbox.width + label.axis.labelpadding);
});
labelJoin.exit().remove();
labelOrientation.maxExtent = maxExtent;
return labelOrientation;
}
function drawAxisTitles(gd, layer, trace, t, xa, ya, labelOrientationA, labelOrientationB) {
var a, b, xy, dxy;
var aMin = Lib.aggNums(Math.min, null, trace.a);
var aMax = Lib.aggNums(Math.max, null, trace.a);
var bMin = Lib.aggNums(Math.min, null, trace.b);
var bMax = Lib.aggNums(Math.max, null, trace.b);
a = 0.5 * (aMin + aMax);
b = bMin;
xy = trace.ab2xy(a, b, true);
dxy = trace.dxyda_rough(a, b);
if (labelOrientationA.angle === undefined) {
Lib.extendFlat(labelOrientationA, orientText(trace, xa, ya, xy, trace.dxydb_rough(a, b)));
}
drawAxisTitle(gd, layer, trace, t, xy, dxy, trace.aaxis, xa, ya, labelOrientationA, 'a-title');
a = aMin;
b = 0.5 * (bMin + bMax);
xy = trace.ab2xy(a, b, true);
dxy = trace.dxydb_rough(a, b);
if (labelOrientationB.angle === undefined) {
Lib.extendFlat(labelOrientationB, orientText(trace, xa, ya, xy, trace.dxyda_rough(a, b)));
}
drawAxisTitle(gd, layer, trace, t, xy, dxy, trace.baxis, xa, ya, labelOrientationB, 'b-title');
}
var lineSpacing = alignmentConstants.LINE_SPACING;
var midShift = (1 - alignmentConstants.MID_SHIFT) / lineSpacing + 1;
function drawAxisTitle(gd, layer, trace, t, xy, dxy, axis, xa, ya, labelOrientation, labelClass) {
var data = [];
if (axis.title.text) data.push(axis.title.text);
var titleJoin = layer.selectAll('text.' + labelClass).data(data);
var offset = labelOrientation.maxExtent;
titleJoin.enter().append('text').classed(labelClass, true);
// There's only one, but we'll do it as a join so it's updated nicely:
titleJoin.each(function () {
var orientation = orientText(trace, xa, ya, xy, dxy);
if (['start', 'both'].indexOf(axis.showticklabels) === -1) {
offset = 0;
}
// In addition to the size of the labels, add on some extra padding:
var titleSize = axis.title.font.size;
offset += titleSize + axis.title.offset;
var labelNorm = labelOrientation.angle + (labelOrientation.flip < 0 ? 180 : 0);
var angleDiff = (labelNorm - orientation.angle + 450) % 360;
var reverseTitle = angleDiff > 90 && angleDiff < 270;
var el = d3.select(this);
el.text(axis.title.text).call(svgTextUtils.convertToTspans, gd);
if (reverseTitle) {
offset = (-svgTextUtils.lineCount(el) + midShift) * lineSpacing * titleSize - offset;
}
el.attr('transform', strTranslate(orientation.p[0], orientation.p[1]) + strRotate(orientation.angle) + strTranslate(0, offset)).attr('text-anchor', 'middle').call(Drawing.font, axis.title.font);
});
titleJoin.exit().remove();
}
/***/ }),
/***/ 18704:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var constants = __webpack_require__(25716);
var search = (__webpack_require__(46888).findBin);
var computeControlPoints = __webpack_require__(4228);
var createSplineEvaluator = __webpack_require__(67672);
var createIDerivativeEvaluator = __webpack_require__(72936);
var createJDerivativeEvaluator = __webpack_require__(92064);
/*
* Create conversion functions to go from one basis to another. In particular the letter
* abbreviations are:
*
* i: i/j coordinates along the grid. Integer values correspond to data points
* a: real-valued coordinates along the a/b axes
* c: cartesian x-y coordinates
* p: screen-space pixel coordinates
*/
module.exports = function setConvert(trace) {
var a = trace._a;
var b = trace._b;
var na = a.length;
var nb = b.length;
var aax = trace.aaxis;
var bax = trace.baxis;
// Grab the limits once rather than recomputing the bounds for every point
// independently:
var amin = a[0];
var amax = a[na - 1];
var bmin = b[0];
var bmax = b[nb - 1];
var arange = a[a.length - 1] - a[0];
var brange = b[b.length - 1] - b[0];
// Compute the tolerance so that points are visible slightly outside the
// defined carpet axis:
var atol = arange * constants.RELATIVE_CULL_TOLERANCE;
var btol = brange * constants.RELATIVE_CULL_TOLERANCE;
// Expand the limits to include the relative tolerance:
amin -= atol;
amax += atol;
bmin -= btol;
bmax += btol;
trace.isVisible = function (a, b) {
return a > amin && a < amax && b > bmin && b < bmax;
};
trace.isOccluded = function (a, b) {
return a < amin || a > amax || b < bmin || b > bmax;
};
trace.setScale = function () {
var x = trace._x;
var y = trace._y;
// This is potentially a very expensive step! It does the bulk of the work of constructing
// an expanded basis of control points. Note in particular that it overwrites the existing
// basis without creating a new array since that would potentially thrash the garbage
// collector.
var result = computeControlPoints(trace._xctrl, trace._yctrl, x, y, aax.smoothing, bax.smoothing);
trace._xctrl = result[0];
trace._yctrl = result[1];
// This step is the second step in the process, but it's somewhat simpler. It just unrolls
// some logic since it would be unnecessarily expensive to compute both interpolations
// nearly identically but separately and to include a bunch of linear vs. bicubic logic in
// every single call.
trace.evalxy = createSplineEvaluator([trace._xctrl, trace._yctrl], na, nb, aax.smoothing, bax.smoothing);
trace.dxydi = createIDerivativeEvaluator([trace._xctrl, trace._yctrl], aax.smoothing, bax.smoothing);
trace.dxydj = createJDerivativeEvaluator([trace._xctrl, trace._yctrl], aax.smoothing, bax.smoothing);
};
/*
* Convert from i/j data grid coordinates to a/b values. Note in particular that this
* is *linear* interpolation, even if the data is interpolated bicubically.
*/
trace.i2a = function (i) {
var i0 = Math.max(0, Math.floor(i[0]), na - 2);
var ti = i[0] - i0;
return (1 - ti) * a[i0] + ti * a[i0 + 1];
};
trace.j2b = function (j) {
var j0 = Math.max(0, Math.floor(j[1]), na - 2);
var tj = j[1] - j0;
return (1 - tj) * b[j0] + tj * b[j0 + 1];
};
trace.ij2ab = function (ij) {
return [trace.i2a(ij[0]), trace.j2b(ij[1])];
};
/*
* Convert from a/b coordinates to i/j grid-numbered coordinates. This requires searching
* through the a/b data arrays and assumes they are monotonic, which is presumed to have
* been enforced already.
*/
trace.a2i = function (aval) {
var i0 = Math.max(0, Math.min(search(aval, a), na - 2));
var a0 = a[i0];
var a1 = a[i0 + 1];
return Math.max(0, Math.min(na - 1, i0 + (aval - a0) / (a1 - a0)));
};
trace.b2j = function (bval) {
var j0 = Math.max(0, Math.min(search(bval, b), nb - 2));
var b0 = b[j0];
var b1 = b[j0 + 1];
return Math.max(0, Math.min(nb - 1, j0 + (bval - b0) / (b1 - b0)));
};
trace.ab2ij = function (ab) {
return [trace.a2i(ab[0]), trace.b2j(ab[1])];
};
/*
* Convert from i/j coordinates to x/y caretesian coordinates. This means either bilinear
* or bicubic spline evaluation, but the hard part is already done at this point.
*/
trace.i2c = function (i, j) {
return trace.evalxy([], i, j);
};
trace.ab2xy = function (aval, bval, extrapolate) {
if (!extrapolate && (aval < a[0] || aval > a[na - 1] | bval < b[0] || bval > b[nb - 1])) {
return [false, false];
}
var i = trace.a2i(aval);
var j = trace.b2j(bval);
var pt = trace.evalxy([], i, j);
if (extrapolate) {
// This section uses the boundary derivatives to extrapolate linearly outside
// the defined range. Consider a scatter line with one point inside the carpet
// axis and one point outside. If we don't extrapolate, we can't draw the line
// at all.
var iex = 0;
var jex = 0;
var der = [];
var i0, ti, j0, tj;
if (aval < a[0]) {
i0 = 0;
ti = 0;
iex = (aval - a[0]) / (a[1] - a[0]);
} else if (aval > a[na - 1]) {
i0 = na - 2;
ti = 1;
iex = (aval - a[na - 1]) / (a[na - 1] - a[na - 2]);
} else {
i0 = Math.max(0, Math.min(na - 2, Math.floor(i)));
ti = i - i0;
}
if (bval < b[0]) {
j0 = 0;
tj = 0;
jex = (bval - b[0]) / (b[1] - b[0]);
} else if (bval > b[nb - 1]) {
j0 = nb - 2;
tj = 1;
jex = (bval - b[nb - 1]) / (b[nb - 1] - b[nb - 2]);
} else {
j0 = Math.max(0, Math.min(nb - 2, Math.floor(j)));
tj = j - j0;
}
if (iex) {
trace.dxydi(der, i0, j0, ti, tj);
pt[0] += der[0] * iex;
pt[1] += der[1] * iex;
}
if (jex) {
trace.dxydj(der, i0, j0, ti, tj);
pt[0] += der[0] * jex;
pt[1] += der[1] * jex;
}
}
return pt;
};
trace.c2p = function (xy, xa, ya) {
return [xa.c2p(xy[0]), ya.c2p(xy[1])];
};
trace.p2x = function (p, xa, ya) {
return [xa.p2c(p[0]), ya.p2c(p[1])];
};
trace.dadi = function (i /* , u*/) {
// Right now only a piecewise linear a or b basis is permitted since smoother interpolation
// would cause monotonicity problems. As a retult, u is entirely disregarded in this
// computation, though we'll specify it as a parameter for the sake of completeness and
// future-proofing. It would be possible to use monotonic cubic interpolation, for example.
//
// See: https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
// u = u || 0;
var i0 = Math.max(0, Math.min(a.length - 2, i));
// The step (denominator) is implicitly 1 since that's the grid spacing.
return a[i0 + 1] - a[i0];
};
trace.dbdj = function (j /* , v*/) {
// See above caveats for dadi which also apply here
var j0 = Math.max(0, Math.min(b.length - 2, j));
// The step (denominator) is implicitly 1 since that's the grid spacing.
return b[j0 + 1] - b[j0];
};
// Takes: grid cell coordinate (i, j) and fractional grid cell coordinates (u, v)
// Returns: (dx/da, dy/db)
//
// NB: separate grid cell + fractional grid cell coordinate format is due to the discontinuous
// derivative, as described better in create_i_derivative_evaluator.js
trace.dxyda = function (i0, j0, u, v) {
var dxydi = trace.dxydi(null, i0, j0, u, v);
var dadi = trace.dadi(i0, u);
return [dxydi[0] / dadi, dxydi[1] / dadi];
};
trace.dxydb = function (i0, j0, u, v) {
var dxydj = trace.dxydj(null, i0, j0, u, v);
var dbdj = trace.dbdj(j0, v);
return [dxydj[0] / dbdj, dxydj[1] / dbdj];
};
// Sometimes we don't care about precision and all we really want is decent rough
// directions (as is the case with labels). In that case, we can do a very rough finite
// difference and spare having to worry about precise grid coordinates:
trace.dxyda_rough = function (a, b, reldiff) {
var h = arange * (reldiff || 0.1);
var plus = trace.ab2xy(a + h, b, true);
var minus = trace.ab2xy(a - h, b, true);
return [(plus[0] - minus[0]) * 0.5 / h, (plus[1] - minus[1]) * 0.5 / h];
};
trace.dxydb_rough = function (a, b, reldiff) {
var h = brange * (reldiff || 0.1);
var plus = trace.ab2xy(a, b + h, true);
var minus = trace.ab2xy(a, b - h, true);
return [(plus[0] - minus[0]) * 0.5 / h, (plus[1] - minus[1]) * 0.5 / h];
};
trace.dpdx = function (xa) {
return xa._m;
};
trace.dpdy = function (ya) {
return ya._m;
};
};
/***/ }),
/***/ 14528:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
/*
* Given a 2D array as well as a basis in either direction, this function fills in the
* 2D array using a combination of smoothing and extrapolation. This is rather important
* for carpet plots since it's used for layout so that we can't simply omit or blank out
* points. We need a reasonable guess so that the interpolation puts points somewhere
* even if we were to somehow represent that the data was missing later on.
*
* input:
* - data: 2D array of arrays
* - a: array such that a.length === data[0].length
* - b: array such that b.length === data.length
*/
module.exports = function smoothFill2dArray(data, a, b) {
var i, j, k;
var ip = [];
var jp = [];
// var neighborCnts = [];
var ni = data[0].length;
var nj = data.length;
function avgSurrounding(i, j) {
// As a low-quality start, we can simply average surrounding points (in a not
// non-uniform grid aware manner):
var sum = 0.0;
var val;
var cnt = 0;
if (i > 0 && (val = data[j][i - 1]) !== undefined) {
cnt++;
sum += val;
}
if (i < ni - 1 && (val = data[j][i + 1]) !== undefined) {
cnt++;
sum += val;
}
if (j > 0 && (val = data[j - 1][i]) !== undefined) {
cnt++;
sum += val;
}
if (j < nj - 1 && (val = data[j + 1][i]) !== undefined) {
cnt++;
sum += val;
}
return sum / Math.max(1, cnt);
}
// This loop iterates over all cells. Any cells that are null will be noted and those
// are the only points we will loop over and update via laplace's equation. Points with
// any neighbors will receive the average. If there are no neighboring points, then they
// will be set to zero. Also as we go, track the maximum magnitude so that we can scale
// our tolerance accordingly.
var dmax = 0.0;
for (i = 0; i < ni; i++) {
for (j = 0; j < nj; j++) {
if (data[j][i] === undefined) {
ip.push(i);
jp.push(j);
data[j][i] = avgSurrounding(i, j);
// neighborCnts.push(result.neighbors);
}
dmax = Math.max(dmax, Math.abs(data[j][i]));
}
}
if (!ip.length) return data;
// The tolerance doesn't need to be excessive. It's just for display positioning
var dxp, dxm, dap, dam, dbp, dbm, c, d, diff, reldiff, overrelaxation;
var tol = 1e-5;
var resid = 0;
var itermax = 100;
var iter = 0;
var n = ip.length;
do {
resid = 0;
// Normally we'd loop in two dimensions, but not all points are blank and need
// an update, so we instead loop only over the points that were tabulated above
for (k = 0; k < n; k++) {
i = ip[k];
j = jp[k];
// neighborCnt = neighborCnts[k];
// Track a counter for how many contributions there are. We'll use this counter
// to average at the end, which reduces to laplace's equation with neumann boundary
// conditions on the first derivative (second derivative is zero so that we get
// a nice linear extrapolation at the boundaries).
var boundaryCnt = 0;
var newVal = 0;
var d0, d1, x0, x1, i0, j0;
if (i === 0) {
// If this lies along the i = 0 boundary, extrapolate from the two points
// to the right of this point. Note that the finite differences take into
// account non-uniform grid spacing:
i0 = Math.min(ni - 1, 2);
x0 = a[i0];
x1 = a[1];
d0 = data[j][i0];
d1 = data[j][1];
newVal += d1 + (d1 - d0) * (a[0] - x1) / (x1 - x0);
boundaryCnt++;
} else if (i === ni - 1) {
// If along the high i boundary, extrapolate from the two points to the
// left of this point
i0 = Math.max(0, ni - 3);
x0 = a[i0];
x1 = a[ni - 2];
d0 = data[j][i0];
d1 = data[j][ni - 2];
newVal += d1 + (d1 - d0) * (a[ni - 1] - x1) / (x1 - x0);
boundaryCnt++;
}
if ((i === 0 || i === ni - 1) && j > 0 && j < nj - 1) {
// If along the min(i) or max(i) boundaries, also smooth vertically as long
// as we're not in a corner. Note that the finite differences used here
// are also aware of nonuniform grid spacing:
dxp = b[j + 1] - b[j];
dxm = b[j] - b[j - 1];
newVal += (dxm * data[j + 1][i] + dxp * data[j - 1][i]) / (dxm + dxp);
boundaryCnt++;
}
if (j === 0) {
// If along the j = 0 boundary, extrpolate this point from the two points
// above it
j0 = Math.min(nj - 1, 2);
x0 = b[j0];
x1 = b[1];
d0 = data[j0][i];
d1 = data[1][i];
newVal += d1 + (d1 - d0) * (b[0] - x1) / (x1 - x0);
boundaryCnt++;
} else if (j === nj - 1) {
// Same for the max j boundary from the cells below it:
j0 = Math.max(0, nj - 3);
x0 = b[j0];
x1 = b[nj - 2];
d0 = data[j0][i];
d1 = data[nj - 2][i];
newVal += d1 + (d1 - d0) * (b[nj - 1] - x1) / (x1 - x0);
boundaryCnt++;
}
if ((j === 0 || j === nj - 1) && i > 0 && i < ni - 1) {
// Now average points to the left/right as long as not in a corner:
dxp = a[i + 1] - a[i];
dxm = a[i] - a[i - 1];
newVal += (dxm * data[j][i + 1] + dxp * data[j][i - 1]) / (dxm + dxp);
boundaryCnt++;
}
if (!boundaryCnt) {
// If none of the above conditions were triggered, then this is an interior
// point and we can just do a laplace equation update. As above, these differences
// are aware of nonuniform grid spacing:
dap = a[i + 1] - a[i];
dam = a[i] - a[i - 1];
dbp = b[j + 1] - b[j];
dbm = b[j] - b[j - 1];
// These are just some useful constants for the iteration, which is perfectly
// straightforward but a little long to derive from f_xx + f_yy = 0.
c = dap * dam * (dap + dam);
d = dbp * dbm * (dbp + dbm);
newVal = (c * (dbm * data[j + 1][i] + dbp * data[j - 1][i]) + d * (dam * data[j][i + 1] + dap * data[j][i - 1])) / (d * (dam + dap) + c * (dbm + dbp));
} else {
// If we did have contributions from the boundary conditions, then average
// the result from the various contributions:
newVal /= boundaryCnt;
}
// Jacobi updates are ridiculously slow to converge, so this approach uses a
// Gauss-seidel iteration which is dramatically faster.
diff = newVal - data[j][i];
reldiff = diff / dmax;
resid += reldiff * reldiff;
// Gauss-Seidel-ish iteration, omega chosen based on heuristics and some
// quick tests.
//
// NB: Don't overrelax the boundarie. Otherwise set an overrelaxation factor
// which is a little low but safely optimal-ish:
overrelaxation = boundaryCnt ? 0 : 0.85;
// If there are four non-null neighbors, then we want a simple average without
// overrelaxation. If all the surrounding points are null, then we want the full
// overrelaxation
//
// Based on experiments, this actually seems to slow down convergence just a bit.
// I'll leave it here for reference in case this needs to be revisited, but
// it seems to work just fine without this.
// if (overrelaxation) overrelaxation *= (4 - neighborCnt) / 4;
data[j][i] += diff * (1 + overrelaxation);
}
resid = Math.sqrt(resid);
} while (iter++ < itermax && resid > tol);
Lib.log('Smoother converged to', resid, 'after', iter, 'iterations');
return data;
};
/***/ }),
/***/ 10259:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isArray1D = (__webpack_require__(10923).isArray1D);
module.exports = function handleXYDefaults(traceIn, traceOut, coerce) {
var x = coerce('x');
var hasX = x && x.length;
var y = coerce('y');
var hasY = y && y.length;
if (!hasX && !hasY) return false;
traceOut._cheater = !x;
if ((!hasX || isArray1D(x)) && (!hasY || isArray1D(y))) {
var len = hasX ? x.length : Infinity;
if (hasY) len = Math.min(len, y.length);
if (traceOut.a && traceOut.a.length) len = Math.min(len, traceOut.a.length);
if (traceOut.b && traceOut.b.length) len = Math.min(len, traceOut.b.length);
traceOut._length = len;
} else traceOut._length = null;
return true;
};
/***/ }),
/***/ 94548:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var scatterGeoAttrs = __webpack_require__(88804);
var colorScaleAttrs = __webpack_require__(99732);
var baseAttrs = __webpack_require__(6040);
var defaultLine = (__webpack_require__(51468).defaultLine);
var extendFlat = (__webpack_require__(55016).extendFlat);
var scatterGeoMarkerLineAttrs = scatterGeoAttrs.marker.line;
module.exports = extendFlat({
locations: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the coordinates via location IDs or names.', 'See `locationmode` for more info.'].join(' ')
},
locationmode: scatterGeoAttrs.locationmode,
z: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the color values.'
},
geojson: extendFlat({}, scatterGeoAttrs.geojson, {
description: ['Sets optional GeoJSON data associated with this trace.', 'If not given, the features on the base map are used.', 'It can be set as a valid GeoJSON object or as a URL string.', 'Note that we only accept GeoJSONs of type *FeatureCollection* or *Feature*', 'with geometries of type *Polygon* or *MultiPolygon*.'
// TODO add topojson support with additional 'topojsonobject' attr?
// https://github.com/topojson/topojson-specification/blob/master/README.md
].join(' ')
}),
featureidkey: scatterGeoAttrs.featureidkey,
text: extendFlat({}, scatterGeoAttrs.text, {
description: 'Sets the text elements associated with each location.'
}),
hovertext: extendFlat({}, scatterGeoAttrs.hovertext, {
description: 'Same as `text`.'
}),
marker: {
line: {
color: extendFlat({}, scatterGeoMarkerLineAttrs.color, {
dflt: defaultLine
}),
width: extendFlat({}, scatterGeoMarkerLineAttrs.width, {
dflt: 1
}),
editType: 'calc'
},
opacity: {
valType: 'number',
arrayOk: true,
min: 0,
max: 1,
dflt: 1,
editType: 'style',
description: 'Sets the opacity of the locations.'
},
editType: 'calc'
},
selected: {
marker: {
opacity: scatterGeoAttrs.selected.marker.opacity,
editType: 'plot'
},
editType: 'plot'
},
unselected: {
marker: {
opacity: scatterGeoAttrs.unselected.marker.opacity,
editType: 'plot'
},
editType: 'plot'
},
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
editType: 'calc',
flags: ['location', 'z', 'text', 'name']
}),
hovertemplate: hovertemplateAttrs(),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
}, colorScaleAttrs('', {
cLetter: 'z',
editTypeOverride: 'calc'
}));
/***/ }),
/***/ 10832:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var BADNUM = (__webpack_require__(41752).BADNUM);
var colorscaleCalc = __webpack_require__(60416);
var arraysToCalcdata = __webpack_require__(67368);
var calcSelection = __webpack_require__(62496);
function isNonBlankString(v) {
return v && typeof v === 'string';
}
module.exports = function calc(gd, trace) {
var len = trace._length;
var calcTrace = new Array(len);
var isValidLoc;
if (trace.geojson) {
isValidLoc = function (v) {
return isNonBlankString(v) || isNumeric(v);
};
} else {
isValidLoc = isNonBlankString;
}
for (var i = 0; i < len; i++) {
var calcPt = calcTrace[i] = {};
var loc = trace.locations[i];
var z = trace.z[i];
if (isValidLoc(loc) && isNumeric(z)) {
calcPt.loc = loc;
calcPt.z = z;
} else {
calcPt.loc = null;
calcPt.z = BADNUM;
}
calcPt.index = i;
}
arraysToCalcdata(calcTrace, trace);
colorscaleCalc(gd, trace, {
vals: trace.z,
containerStr: '',
cLetter: 'z'
});
calcSelection(calcTrace, trace);
return calcTrace;
};
/***/ }),
/***/ 13164:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(94548);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var locations = coerce('locations');
var z = coerce('z');
if (!(locations && locations.length && Lib.isArrayOrTypedArray(z) && z.length)) {
traceOut.visible = false;
return;
}
traceOut._length = Math.min(locations.length, z.length);
var geojson = coerce('geojson');
var locationmodeDflt;
if (typeof geojson === 'string' && geojson !== '' || Lib.isPlainObject(geojson)) {
locationmodeDflt = 'geojson-id';
}
var locationMode = coerce('locationmode', locationmodeDflt);
if (locationMode === 'geojson-id') {
coerce('featureidkey');
}
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
var mlw = coerce('marker.line.width');
if (mlw) coerce('marker.line.color');
coerce('marker.opacity');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'z'
});
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 88496:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt, trace, cd, pointNumber) {
out.location = pt.location;
out.z = pt.z;
// include feature properties from input geojson
var cdi = cd[pointNumber];
if (cdi.fIn && cdi.fIn.properties) {
out.properties = cdi.fIn.properties;
}
out.ct = cdi.ct;
return out;
};
/***/ }),
/***/ 50528:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var attributes = __webpack_require__(94548);
var fillText = (__webpack_require__(10923).fillText);
module.exports = function hoverPoints(pointData, xval, yval) {
var cd = pointData.cd;
var trace = cd[0].trace;
var geo = pointData.subplot;
var pt, i, j, isInside;
var xy = [xval, yval];
var altXy = [xval + 360, yval];
for (i = 0; i < cd.length; i++) {
pt = cd[i];
isInside = false;
if (pt._polygons) {
for (j = 0; j < pt._polygons.length; j++) {
if (pt._polygons[j].contains(xy)) {
isInside = !isInside;
}
// for polygons that cross antimeridian as xval is in [-180, 180]
if (pt._polygons[j].contains(altXy)) {
isInside = !isInside;
}
}
if (isInside) break;
}
}
if (!isInside || !pt) return;
pointData.x0 = pointData.x1 = pointData.xa.c2p(pt.ct);
pointData.y0 = pointData.y1 = pointData.ya.c2p(pt.ct);
pointData.index = pt.index;
pointData.location = pt.loc;
pointData.z = pt.z;
pointData.zLabel = Axes.tickText(geo.mockAxis, geo.mockAxis.c2l(pt.z), 'hover').text;
pointData.hovertemplate = pt.hovertemplate;
makeHoverInfo(pointData, trace, pt);
return [pointData];
};
function makeHoverInfo(pointData, trace, pt) {
if (trace.hovertemplate) return;
var hoverinfo = pt.hi || trace.hoverinfo;
var loc = String(pt.loc);
var parts = hoverinfo === 'all' ? attributes.hoverinfo.flags : hoverinfo.split('+');
var hasName = parts.indexOf('name') !== -1;
var hasLocation = parts.indexOf('location') !== -1;
var hasZ = parts.indexOf('z') !== -1;
var hasText = parts.indexOf('text') !== -1;
var hasIdAsNameLabel = !hasName && hasLocation;
var text = [];
if (hasIdAsNameLabel) {
pointData.nameOverride = loc;
} else {
if (hasName) pointData.nameOverride = trace.name;
if (hasLocation) text.push(loc);
}
if (hasZ) {
text.push(pointData.zLabel);
}
if (hasText) {
fillText(pt, trace, text);
}
pointData.extraText = text.join('
');
}
/***/ }),
/***/ 80116:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(94548),
supplyDefaults: __webpack_require__(13164),
colorbar: __webpack_require__(72680),
calc: __webpack_require__(10832),
calcGeoJSON: (__webpack_require__(48784).calcGeoJSON),
plot: (__webpack_require__(48784).plot),
style: (__webpack_require__(76596).style),
styleOnSelect: (__webpack_require__(76596).styleOnSelect),
hoverPoints: __webpack_require__(50528),
eventData: __webpack_require__(88496),
selectPoints: __webpack_require__(55068),
moduleType: 'trace',
name: 'choropleth',
basePlotModule: __webpack_require__(28224),
categories: ['geo', 'noOpacity', 'showLegend'],
meta: {
description: ['The data that describes the choropleth value-to-color mapping', 'is set in `z`.', 'The geographic locations corresponding to each value in `z`', 'are set in `locations`.'].join(' ')
}
};
/***/ }),
/***/ 48784:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var geoUtils = __webpack_require__(89096);
var getTopojsonFeatures = (__webpack_require__(27052).getTopojsonFeatures);
var findExtremes = (__webpack_require__(66044).findExtremes);
var style = (__webpack_require__(76596).style);
function plot(gd, geo, calcData) {
var choroplethLayer = geo.layers.backplot.select('.choroplethlayer');
Lib.makeTraceGroups(choroplethLayer, calcData, 'trace choropleth').each(function (calcTrace) {
var sel = d3.select(this);
var paths = sel.selectAll('path.choroplethlocation').data(Lib.identity);
paths.enter().append('path').classed('choroplethlocation', true);
paths.exit().remove();
// call style here within topojson request callback
style(gd, calcTrace);
});
}
function calcGeoJSON(calcTrace, fullLayout) {
var trace = calcTrace[0].trace;
var geoLayout = fullLayout[trace.geo];
var geo = geoLayout._subplot;
var locationmode = trace.locationmode;
var len = trace._length;
var features = locationmode === 'geojson-id' ? geoUtils.extractTraceFeature(calcTrace) : getTopojsonFeatures(trace, geo.topojson);
var lonArray = [];
var latArray = [];
for (var i = 0; i < len; i++) {
var calcPt = calcTrace[i];
var feature = locationmode === 'geojson-id' ? calcPt.fOut : geoUtils.locationToFeature(locationmode, calcPt.loc, features);
if (feature) {
calcPt.geojson = feature;
calcPt.ct = feature.properties.ct;
calcPt._polygons = geoUtils.feature2polygons(feature);
var bboxFeature = geoUtils.computeBbox(feature);
lonArray.push(bboxFeature[0], bboxFeature[2]);
latArray.push(bboxFeature[1], bboxFeature[3]);
} else {
calcPt.geojson = null;
}
}
if (geoLayout.fitbounds === 'geojson' && locationmode === 'geojson-id') {
var bboxGeojson = geoUtils.computeBbox(geoUtils.getTraceGeojson(trace));
lonArray = [bboxGeojson[0], bboxGeojson[2]];
latArray = [bboxGeojson[1], bboxGeojson[3]];
}
var opts = {
padded: true
};
trace._extremes.lon = findExtremes(geoLayout.lonaxis._ax, lonArray, opts);
trace._extremes.lat = findExtremes(geoLayout.lataxis._ax, latArray, opts);
}
module.exports = {
calcGeoJSON: calcGeoJSON,
plot: plot
};
/***/ }),
/***/ 55068:
/***/ (function(module) {
"use strict";
module.exports = function selectPoints(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var selection = [];
var i, di, ct, x, y;
if (selectionTester === false) {
for (i = 0; i < cd.length; i++) {
cd[i].selected = 0;
}
} else {
for (i = 0; i < cd.length; i++) {
di = cd[i];
ct = di.ct;
if (!ct) continue;
x = xa.c2p(ct);
y = ya.c2p(ct);
if (selectionTester.contains([x, y], null, i, searchInfo)) {
selection.push({
pointNumber: i,
lon: ct[0],
lat: ct[1]
});
di.selected = 1;
} else {
di.selected = 0;
}
}
}
return selection;
};
/***/ }),
/***/ 76596:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Color = __webpack_require__(9240);
var Drawing = __webpack_require__(49348);
var Colorscale = __webpack_require__(26733);
function style(gd, calcTrace) {
if (calcTrace) styleTrace(gd, calcTrace);
}
function styleTrace(gd, calcTrace) {
var trace = calcTrace[0].trace;
var s = calcTrace[0].node3;
var locs = s.selectAll('.choroplethlocation');
var marker = trace.marker || {};
var markerLine = marker.line || {};
var sclFunc = Colorscale.makeColorScaleFuncFromTrace(trace);
locs.each(function (d) {
d3.select(this).attr('fill', sclFunc(d.z)).call(Color.stroke, d.mlc || markerLine.color).call(Drawing.dashLine, '', d.mlw || markerLine.width || 0).style('opacity', marker.opacity);
});
Drawing.selectedPointStyle(locs, trace);
}
function styleOnSelect(gd, calcTrace) {
var s = calcTrace[0].node3;
var trace = calcTrace[0].trace;
if (trace.selectedpoints) {
Drawing.selectedPointStyle(s.selectAll('.choroplethlocation'), trace);
} else {
styleTrace(gd, calcTrace);
}
}
module.exports = {
style: style,
styleOnSelect: styleOnSelect
};
/***/ }),
/***/ 95620:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var choroplethAttrs = __webpack_require__(94548);
var colorScaleAttrs = __webpack_require__(99732);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var baseAttrs = __webpack_require__(6040);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = extendFlat({
locations: {
valType: 'data_array',
editType: 'calc',
description: ['Sets which features found in *geojson* to plot using', 'their feature `id` field.'].join(' ')
},
// TODO
// Maybe start with only one value (that we could name e.g. 'geojson-id'),
// but eventually:
// - we could also support for our own dist/topojson/*
// .. and locationmode: choroplethAttrs.locationmode,
z: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the color values.'
},
// TODO maybe we could also set a "key" to dig out values out of the
// GeoJSON feature `properties` fields?
geojson: {
valType: 'any',
editType: 'calc',
description: ['Sets the GeoJSON data associated with this trace.', 'It can be set as a valid GeoJSON object or as a URL string.', 'Note that we only accept GeoJSONs of type *FeatureCollection* or *Feature*', 'with geometries of type *Polygon* or *MultiPolygon*.'].join(' ')
},
featureidkey: extendFlat({}, choroplethAttrs.featureidkey, {
description: ['Sets the key in GeoJSON features which is used as id to match the items', 'included in the `locations` array.', 'Support nested property, for example *properties.name*.'].join(' ')
}),
// TODO agree on name / behaviour
//
// 'below' is used currently for layout.mapbox.layers,
// even though it's not very plotly-esque.
//
// Note also, that the mapbox-gl style don't all have the same layers,
// see https://codepen.io/etpinard/pen/ydVMwM for full list
below: {
valType: 'string',
editType: 'plot',
description: ['Determines if the choropleth polygons will be inserted', 'before the layer with the specified ID.', 'By default, choroplethmapbox traces are placed above the water layers.', 'If set to \'\',', 'the layer will be inserted above every existing layer.'].join(' ')
},
text: choroplethAttrs.text,
hovertext: choroplethAttrs.hovertext,
marker: {
line: {
color: extendFlat({}, choroplethAttrs.marker.line.color, {
editType: 'plot'
}),
width: extendFlat({}, choroplethAttrs.marker.line.width, {
editType: 'plot'
}),
editType: 'calc'
},
// TODO maybe having a dflt less than 1, together with `below:''` would be better?
opacity: extendFlat({}, choroplethAttrs.marker.opacity, {
editType: 'plot'
}),
editType: 'calc'
},
selected: {
marker: {
opacity: extendFlat({}, choroplethAttrs.selected.marker.opacity, {
editType: 'plot'
}),
editType: 'plot'
},
editType: 'plot'
},
unselected: {
marker: {
opacity: extendFlat({}, choroplethAttrs.unselected.marker.opacity, {
editType: 'plot'
}),
editType: 'plot'
},
editType: 'plot'
},
hoverinfo: choroplethAttrs.hoverinfo,
hovertemplate: hovertemplateAttrs({}, {
keys: ['properties']
}),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
}, colorScaleAttrs('', {
cLetter: 'z',
editTypeOverride: 'calc'
}));
/***/ }),
/***/ 28828:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var Colorscale = __webpack_require__(26733);
var Drawing = __webpack_require__(49348);
var makeBlank = (__webpack_require__(23308).makeBlank);
var geoUtils = __webpack_require__(89096);
/* N.B.
*
* We fetch the GeoJSON files "ourselves" (during
* mapbox.prototype.fetchMapData) where they are stored in a global object
* named `PlotlyGeoAssets` (same as for topojson files in `geo` subplots).
*
* Mapbox does allow using URLs as geojson sources, but does NOT allow filtering
* features by feature `id` that are not numbers (more info in:
* https://github.com/mapbox/mapbox-gl-js/issues/8088).
*/
function convert(calcTrace) {
var trace = calcTrace[0].trace;
var isVisible = trace.visible === true && trace._length !== 0;
var fill = {
layout: {
visibility: 'none'
},
paint: {}
};
var line = {
layout: {
visibility: 'none'
},
paint: {}
};
var opts = trace._opts = {
fill: fill,
line: line,
geojson: makeBlank()
};
if (!isVisible) return opts;
var features = geoUtils.extractTraceFeature(calcTrace);
if (!features) return opts;
var sclFunc = Colorscale.makeColorScaleFuncFromTrace(trace);
var marker = trace.marker;
var markerLine = marker.line || {};
var opacityFn;
if (Lib.isArrayOrTypedArray(marker.opacity)) {
opacityFn = function (d) {
var mo = d.mo;
return isNumeric(mo) ? +Lib.constrain(mo, 0, 1) : 0;
};
}
var lineColorFn;
if (Lib.isArrayOrTypedArray(markerLine.color)) {
lineColorFn = function (d) {
return d.mlc;
};
}
var lineWidthFn;
if (Lib.isArrayOrTypedArray(markerLine.width)) {
lineWidthFn = function (d) {
return d.mlw;
};
}
for (var i = 0; i < calcTrace.length; i++) {
var cdi = calcTrace[i];
var fOut = cdi.fOut;
if (fOut) {
var props = fOut.properties;
props.fc = sclFunc(cdi.z);
if (opacityFn) props.mo = opacityFn(cdi);
if (lineColorFn) props.mlc = lineColorFn(cdi);
if (lineWidthFn) props.mlw = lineWidthFn(cdi);
cdi.ct = props.ct;
cdi._polygons = geoUtils.feature2polygons(fOut);
}
}
var opacitySetting = opacityFn ? {
type: 'identity',
property: 'mo'
} : marker.opacity;
Lib.extendFlat(fill.paint, {
'fill-color': {
type: 'identity',
property: 'fc'
},
'fill-opacity': opacitySetting
});
Lib.extendFlat(line.paint, {
'line-color': lineColorFn ? {
type: 'identity',
property: 'mlc'
} : markerLine.color,
'line-width': lineWidthFn ? {
type: 'identity',
property: 'mlw'
} : markerLine.width,
'line-opacity': opacitySetting
});
fill.layout.visibility = 'visible';
line.layout.visibility = 'visible';
opts.geojson = {
type: 'FeatureCollection',
features: features
};
convertOnSelect(calcTrace);
return opts;
}
function convertOnSelect(calcTrace) {
var trace = calcTrace[0].trace;
var opts = trace._opts;
var opacitySetting;
if (trace.selectedpoints) {
var fns = Drawing.makeSelectedPointStyleFns(trace);
for (var i = 0; i < calcTrace.length; i++) {
var cdi = calcTrace[i];
if (cdi.fOut) {
cdi.fOut.properties.mo2 = fns.selectedOpacityFn(cdi);
}
}
opacitySetting = {
type: 'identity',
property: 'mo2'
};
} else {
opacitySetting = Lib.isArrayOrTypedArray(trace.marker.opacity) ? {
type: 'identity',
property: 'mo'
} : trace.marker.opacity;
}
Lib.extendFlat(opts.fill.paint, {
'fill-opacity': opacitySetting
});
Lib.extendFlat(opts.line.paint, {
'line-opacity': opacitySetting
});
return opts;
}
module.exports = {
convert: convert,
convertOnSelect: convertOnSelect
};
/***/ }),
/***/ 83992:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(95620);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var locations = coerce('locations');
var z = coerce('z');
var geojson = coerce('geojson');
if (!Lib.isArrayOrTypedArray(locations) || !locations.length || !Lib.isArrayOrTypedArray(z) || !z.length || !(typeof geojson === 'string' && geojson !== '' || Lib.isPlainObject(geojson))) {
traceOut.visible = false;
return;
}
coerce('featureidkey');
traceOut._length = Math.min(locations.length, z.length);
coerce('below');
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
var mlw = coerce('marker.line.width');
if (mlw) coerce('marker.line.color');
coerce('marker.opacity');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'z'
});
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 52116:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(95620),
supplyDefaults: __webpack_require__(83992),
colorbar: __webpack_require__(72680),
calc: __webpack_require__(10832),
plot: __webpack_require__(4992),
hoverPoints: __webpack_require__(50528),
eventData: __webpack_require__(88496),
selectPoints: __webpack_require__(55068),
styleOnSelect: function (_, cd) {
if (cd) {
var trace = cd[0].trace;
trace._glTrace.updateOnSelect(cd);
}
},
getBelow: function (trace, subplot) {
var mapLayers = subplot.getMapLayers();
// find layer just above top-most "water" layer
// that is not a plotly layer
for (var i = mapLayers.length - 2; i >= 0; i--) {
var layerId = mapLayers[i].id;
if (typeof layerId === 'string' && layerId.indexOf('water') === 0) {
for (var j = i + 1; j < mapLayers.length; j++) {
layerId = mapLayers[j].id;
if (typeof layerId === 'string' && layerId.indexOf('plotly-') === -1) {
return layerId;
}
}
}
}
},
moduleType: 'trace',
name: 'choroplethmapbox',
basePlotModule: __webpack_require__(90419),
categories: ['mapbox', 'gl', 'noOpacity', 'showLegend'],
meta: {
hr_name: 'choropleth_mapbox',
description: ['GeoJSON features to be filled are set in `geojson`', 'The data that describes the choropleth value-to-color mapping', 'is set in `locations` and `z`.'].join(' ')
}
};
/***/ }),
/***/ 4992:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var convert = (__webpack_require__(28828).convert);
var convertOnSelect = (__webpack_require__(28828).convertOnSelect);
var LAYER_PREFIX = (__webpack_require__(11376).traceLayerPrefix);
function ChoroplethMapbox(subplot, uid) {
this.type = 'choroplethmapbox';
this.subplot = subplot;
this.uid = uid;
// N.B. fill and line layers share same source
this.sourceId = 'source-' + uid;
this.layerList = [['fill', LAYER_PREFIX + uid + '-fill'], ['line', LAYER_PREFIX + uid + '-line']];
// previous 'below' value,
// need this to update it properly
this.below = null;
}
var proto = ChoroplethMapbox.prototype;
proto.update = function (calcTrace) {
this._update(convert(calcTrace));
// link ref for quick update during selections
calcTrace[0].trace._glTrace = this;
};
proto.updateOnSelect = function (calcTrace) {
this._update(convertOnSelect(calcTrace));
};
proto._update = function (optsAll) {
var subplot = this.subplot;
var layerList = this.layerList;
var below = subplot.belowLookup['trace-' + this.uid];
subplot.map.getSource(this.sourceId).setData(optsAll.geojson);
if (below !== this.below) {
this._removeLayers();
this._addLayers(optsAll, below);
this.below = below;
}
for (var i = 0; i < layerList.length; i++) {
var item = layerList[i];
var k = item[0];
var id = item[1];
var opts = optsAll[k];
subplot.setOptions(id, 'setLayoutProperty', opts.layout);
if (opts.layout.visibility === 'visible') {
subplot.setOptions(id, 'setPaintProperty', opts.paint);
}
}
};
proto._addLayers = function (optsAll, below) {
var subplot = this.subplot;
var layerList = this.layerList;
var sourceId = this.sourceId;
for (var i = 0; i < layerList.length; i++) {
var item = layerList[i];
var k = item[0];
var opts = optsAll[k];
subplot.addLayer({
type: k,
id: item[1],
source: sourceId,
layout: opts.layout,
paint: opts.paint
}, below);
}
};
proto._removeLayers = function () {
var map = this.subplot.map;
var layerList = this.layerList;
for (var i = layerList.length - 1; i >= 0; i--) {
map.removeLayer(layerList[i][1]);
}
};
proto.dispose = function () {
var map = this.subplot.map;
this._removeLayers();
map.removeSource(this.sourceId);
};
module.exports = function createChoroplethMapbox(subplot, calcTrace) {
var trace = calcTrace[0].trace;
var choroplethMapbox = new ChoroplethMapbox(subplot, trace.uid);
var sourceId = choroplethMapbox.sourceId;
var optsAll = convert(calcTrace);
var below = choroplethMapbox.below = subplot.belowLookup['trace-' + trace.uid];
subplot.map.addSource(sourceId, {
type: 'geojson',
data: optsAll.geojson
});
choroplethMapbox._addLayers(optsAll, below);
// link ref for quick update during selections
calcTrace[0].trace._glTrace = choroplethMapbox;
return choroplethMapbox;
};
/***/ }),
/***/ 87792:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorScaleAttrs = __webpack_require__(99732);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var mesh3dAttrs = __webpack_require__(13000);
var baseAttrs = __webpack_require__(6040);
var extendFlat = (__webpack_require__(55016).extendFlat);
var attrs = {
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the x coordinates of the vector field', 'and of the displayed cones.'].join(' ')
},
y: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the y coordinates of the vector field', 'and of the displayed cones.'].join(' ')
},
z: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the z coordinates of the vector field', 'and of the displayed cones.'].join(' ')
},
u: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the x components of the vector field.'
},
v: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the y components of the vector field.'
},
w: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the z components of the vector field.'
},
// TODO add way to specify cone positions independently of the vector field
// provided, similar to MATLAB's coneplot Cx/Cy/Cz meshgrids,
// see https://www.mathworks.com/help/matlab/ref/coneplot.html
//
// Alternatively, if our goal is only to 'fill in gaps' in the vector data,
// we could try to extend the heatmap 'connectgaps' algorithm to 3D.
// From AJ: this particular algorithm which amounts to a Poisson equation,
// both for interpolation and extrapolation - is the right one to use for
// cones too. It makes a field with zero divergence, which is a good
// baseline assumption for vector fields.
//
// cones: {
// // potential attributes to add:
// //
// // - meshmode: 'cartesian-product', 'pts', 'grid'
// //
// // under `meshmode: 'grid'`
// // - (x|y|z)grid.start
// // - (x|y|z)grid.end
// // - (x|y|z)grid.size
//
// x: {
// valType: 'data_array',
// editType: 'calc',
// description: 'Sets the x coordinates of the cones to be displayed.'
// },
// y: {
// valType: 'data_array',
// editType: 'calc',
// description: 'Sets the y coordinates of the cones to be displayed.'
// },
// z: {
// valType: 'data_array',
// editType: 'calc',
// description: 'Sets the z coordinates of the cones to be displayed.'
// },
//
// editType: 'calc',
// description: [
// 'By setting `cones.x`, `cones.y` and `cones.z` to 1D arrays,',
// 'plotly creates a mesh using the cartesian product of those 3 arrays.'
// ].join(' ')
// },
sizemode: {
valType: 'enumerated',
values: ['scaled', 'absolute', 'raw'],
editType: 'calc',
dflt: 'scaled',
description: ['Determines whether `sizeref` is set as a *scaled* (i.e unitless) scalar', '(normalized by the max u/v/w norm in the vector field) or as', '*absolute* value (in the same units as the vector field).', 'To display sizes in actual vector length use *raw*.'].join(' ')
},
sizeref: {
valType: 'number',
editType: 'calc',
min: 0,
description: ['Adjusts the cone size scaling.', 'The size of the cones is determined by their u/v/w norm multiplied a factor and `sizeref`.', 'This factor (computed internally) corresponds to the minimum "time" to travel across', 'two successive x/y/z positions at the average velocity of those two successive positions.', 'All cones in a given trace use the same factor.', 'With `sizemode` set to *raw*, its default value is *1*.', 'With `sizemode` set to *scaled*, `sizeref` is unitless, its default value is *0.5*.', 'With `sizemode` set to *absolute*, `sizeref` has the same units as the u/v/w vector field,', 'its the default value is half the sample\'s maximum vector norm.'].join(' ')
},
anchor: {
valType: 'enumerated',
editType: 'calc',
values: ['tip', 'tail', 'cm', 'center'],
dflt: 'cm',
description: ['Sets the cones\' anchor with respect to their x/y/z positions.', 'Note that *cm* denote the cone\'s center of mass which corresponds to', '1/4 from the tail to tip.'].join(' ')
},
text: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'calc',
description: ['Sets the text elements associated with the cones.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
},
hovertext: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'calc',
description: 'Same as `text`.'
},
hovertemplate: hovertemplateAttrs({
editType: 'calc'
}, {
keys: ['norm']
}),
uhoverformat: axisHoverFormat('u', 1),
vhoverformat: axisHoverFormat('v', 1),
whoverformat: axisHoverFormat('w', 1),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z'),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
};
extendFlat(attrs, colorScaleAttrs('', {
colorAttr: 'u/v/w norm',
showScaleDflt: true,
editTypeOverride: 'calc'
}));
var fromMesh3d = ['opacity', 'lightposition', 'lighting'];
fromMesh3d.forEach(function (k) {
attrs[k] = mesh3dAttrs[k];
});
attrs.hoverinfo = extendFlat({}, baseAttrs.hoverinfo, {
editType: 'calc',
flags: ['x', 'y', 'z', 'u', 'v', 'w', 'norm', 'text', 'name'],
dflt: 'x+y+z+norm+text+name'
});
attrs.transforms = undefined;
module.exports = attrs;
/***/ }),
/***/ 72104:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorscaleCalc = __webpack_require__(60416);
module.exports = function calc(gd, trace) {
var u = trace.u;
var v = trace.v;
var w = trace.w;
var len = Math.min(trace.x.length, trace.y.length, trace.z.length, u.length, v.length, w.length);
var normMax = -Infinity;
var normMin = Infinity;
for (var i = 0; i < len; i++) {
var uu = u[i];
var vv = v[i];
var ww = w[i];
var norm = Math.sqrt(uu * uu + vv * vv + ww * ww);
normMax = Math.max(normMax, norm);
normMin = Math.min(normMin, norm);
}
trace._len = len;
trace._normMax = normMax;
colorscaleCalc(gd, trace, {
vals: [normMin, normMax],
containerStr: '',
cLetter: 'c'
});
};
/***/ }),
/***/ 50800:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var conePlot = (__webpack_require__(14656).gl_cone3d);
var createConeMesh = (__webpack_require__(14656).gl_cone3d).createConeMesh;
var simpleMap = (__webpack_require__(10923).simpleMap);
var parseColorScale = (__webpack_require__(13396).parseColorScale);
var extractOpts = (__webpack_require__(26733).extractOpts);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var zip3 = __webpack_require__(90644);
function Cone(scene, uid) {
this.scene = scene;
this.uid = uid;
this.mesh = null;
this.data = null;
}
var proto = Cone.prototype;
proto.handlePick = function (selection) {
if (selection.object === this.mesh) {
var selectIndex = selection.index = selection.data.index;
var xx = this.data.x[selectIndex];
var yy = this.data.y[selectIndex];
var zz = this.data.z[selectIndex];
var uu = this.data.u[selectIndex];
var vv = this.data.v[selectIndex];
var ww = this.data.w[selectIndex];
selection.traceCoordinate = [xx, yy, zz, uu, vv, ww, Math.sqrt(uu * uu + vv * vv + ww * ww)];
var text = this.data.hovertext || this.data.text;
if (isArrayOrTypedArray(text) && text[selectIndex] !== undefined) {
selection.textLabel = text[selectIndex];
} else if (text) {
selection.textLabel = text;
}
return true;
}
};
var axisName2scaleIndex = {
xaxis: 0,
yaxis: 1,
zaxis: 2
};
var anchor2coneOffset = {
tip: 1,
tail: 0,
cm: 0.25,
center: 0.5
};
var anchor2coneSpan = {
tip: 1,
tail: 1,
cm: 0.75,
center: 0.5
};
function convert(scene, trace) {
var sceneLayout = scene.fullSceneLayout;
var dataScale = scene.dataScale;
var coneOpts = {};
function toDataCoords(arr, axisName) {
var ax = sceneLayout[axisName];
var scale = dataScale[axisName2scaleIndex[axisName]];
return simpleMap(arr, function (v) {
return ax.d2l(v) * scale;
});
}
coneOpts.vectors = zip3(toDataCoords(trace.u, 'xaxis'), toDataCoords(trace.v, 'yaxis'), toDataCoords(trace.w, 'zaxis'), trace._len);
coneOpts.positions = zip3(toDataCoords(trace.x, 'xaxis'), toDataCoords(trace.y, 'yaxis'), toDataCoords(trace.z, 'zaxis'), trace._len);
var cOpts = extractOpts(trace);
coneOpts.colormap = parseColorScale(trace);
coneOpts.vertexIntensityBounds = [cOpts.min / trace._normMax, cOpts.max / trace._normMax];
coneOpts.coneOffset = anchor2coneOffset[trace.anchor];
var sizemode = trace.sizemode;
if (sizemode === 'scaled') {
// unitless sizeref
coneOpts.coneSize = trace.sizeref || 0.5;
} else if (sizemode === 'absolute') {
// sizeref here has unit of velocity
coneOpts.coneSize = trace.sizeref && trace._normMax ? trace.sizeref / trace._normMax : 0.5;
} else if (sizemode === 'raw') {
coneOpts.coneSize = trace.sizeref;
}
coneOpts.coneSizemode = sizemode;
var meshData = conePlot(coneOpts);
// pass gl-mesh3d lighting attributes
var lp = trace.lightposition;
meshData.lightPosition = [lp.x, lp.y, lp.z];
meshData.ambient = trace.lighting.ambient;
meshData.diffuse = trace.lighting.diffuse;
meshData.specular = trace.lighting.specular;
meshData.roughness = trace.lighting.roughness;
meshData.fresnel = trace.lighting.fresnel;
meshData.opacity = trace.opacity;
// stash autorange pad value
trace._pad = anchor2coneSpan[trace.anchor] * meshData.vectorScale * meshData.coneScale * trace._normMax;
return meshData;
}
proto.update = function (data) {
this.data = data;
var meshData = convert(this.scene, data);
this.mesh.update(meshData);
};
proto.dispose = function () {
this.scene.glplot.remove(this.mesh);
this.mesh.dispose();
};
function createConeTrace(scene, data) {
var gl = scene.glplot.gl;
var meshData = convert(scene, data);
var mesh = createConeMesh(gl, meshData);
var cone = new Cone(scene, data.uid);
cone.mesh = mesh;
cone.data = data;
mesh._trace = cone;
scene.glplot.add(mesh);
return cone;
}
module.exports = createConeTrace;
/***/ }),
/***/ 49936:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(87792);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var u = coerce('u');
var v = coerce('v');
var w = coerce('w');
var x = coerce('x');
var y = coerce('y');
var z = coerce('z');
if (!u || !u.length || !v || !v.length || !w || !w.length || !x || !x.length || !y || !y.length || !z || !z.length) {
traceOut.visible = false;
return;
}
var sizemode = coerce('sizemode');
coerce('sizeref', sizemode === 'raw' ? 1 : 0.5);
coerce('anchor');
coerce('lighting.ambient');
coerce('lighting.diffuse');
coerce('lighting.specular');
coerce('lighting.roughness');
coerce('lighting.fresnel');
coerce('lightposition.x');
coerce('lightposition.y');
coerce('lightposition.z');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'c'
});
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('uhoverformat');
coerce('vhoverformat');
coerce('whoverformat');
coerce('xhoverformat');
coerce('yhoverformat');
coerce('zhoverformat');
// disable 1D transforms (for now)
traceOut._length = null;
};
/***/ }),
/***/ 3880:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'cone',
basePlotModule: __webpack_require__(26544),
categories: ['gl3d', 'showLegend'],
attributes: __webpack_require__(87792),
supplyDefaults: __webpack_require__(49936),
colorbar: {
min: 'cmin',
max: 'cmax'
},
calc: __webpack_require__(72104),
plot: __webpack_require__(50800),
eventData: function (out, pt) {
out.norm = pt.traceCoordinate[6];
return out;
},
meta: {
description: ['Use cone traces to visualize vector fields.', '', 'Specify a vector field using 6 1D arrays,', '3 position arrays `x`, `y` and `z`', 'and 3 vector component arrays `u`, `v`, `w`.', 'The cones are drawn exactly at the positions given', 'by `x`, `y` and `z`.'].join(' ')
}
};
/***/ }),
/***/ 12115:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var heatmapAttrs = __webpack_require__(7944);
var scatterAttrs = __webpack_require__(49992);
var axisFormat = __webpack_require__(67724);
var axisHoverFormat = axisFormat.axisHoverFormat;
var descriptionOnlyNumbers = axisFormat.descriptionOnlyNumbers;
var colorScaleAttrs = __webpack_require__(99732);
var dash = (__webpack_require__(9392)/* .dash */ .u);
var fontAttrs = __webpack_require__(71936);
var extendFlat = (__webpack_require__(55016).extendFlat);
var filterOps = __webpack_require__(60180);
var COMPARISON_OPS2 = filterOps.COMPARISON_OPS2;
var INTERVAL_OPS = filterOps.INTERVAL_OPS;
var scatterLineAttrs = scatterAttrs.line;
module.exports = extendFlat({
z: heatmapAttrs.z,
x: heatmapAttrs.x,
x0: heatmapAttrs.x0,
dx: heatmapAttrs.dx,
y: heatmapAttrs.y,
y0: heatmapAttrs.y0,
dy: heatmapAttrs.dy,
xperiod: heatmapAttrs.xperiod,
yperiod: heatmapAttrs.yperiod,
xperiod0: scatterAttrs.xperiod0,
yperiod0: scatterAttrs.yperiod0,
xperiodalignment: heatmapAttrs.xperiodalignment,
yperiodalignment: heatmapAttrs.yperiodalignment,
text: heatmapAttrs.text,
hovertext: heatmapAttrs.hovertext,
transpose: heatmapAttrs.transpose,
xtype: heatmapAttrs.xtype,
ytype: heatmapAttrs.ytype,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z', 1),
hovertemplate: heatmapAttrs.hovertemplate,
texttemplate: extendFlat({}, heatmapAttrs.texttemplate, {
description: ['For this trace it only has an effect if `coloring` is set to *heatmap*.', heatmapAttrs.texttemplate.description].join(' ')
}),
textfont: extendFlat({}, heatmapAttrs.textfont, {
description: ['For this trace it only has an effect if `coloring` is set to *heatmap*.', heatmapAttrs.textfont.description].join(' ')
}),
hoverongaps: heatmapAttrs.hoverongaps,
connectgaps: extendFlat({}, heatmapAttrs.connectgaps, {
description: ['Determines whether or not gaps', '(i.e. {nan} or missing values)', 'in the `z` data are filled in.', 'It is defaulted to true if `z` is a', 'one dimensional array', 'otherwise it is defaulted to false.'].join(' ')
}),
fillcolor: {
valType: 'color',
editType: 'calc',
description: ['Sets the fill color if `contours.type` is *constraint*.', 'Defaults to a half-transparent variant of the line color,', 'marker color, or marker line color, whichever is available.'].join(' ')
},
autocontour: {
valType: 'boolean',
dflt: true,
editType: 'calc',
impliedEdits: {
'contours.start': undefined,
'contours.end': undefined,
'contours.size': undefined
},
description: ['Determines whether or not the contour level attributes are', 'picked by an algorithm.', 'If *true*, the number of contour levels can be set in `ncontours`.', 'If *false*, set the contour level attributes in `contours`.'].join(' ')
},
ncontours: {
valType: 'integer',
dflt: 15,
min: 1,
editType: 'calc',
description: ['Sets the maximum number of contour levels. The actual number', 'of contours will be chosen automatically to be less than or', 'equal to the value of `ncontours`.', 'Has an effect only if `autocontour` is *true* or if', '`contours.size` is missing.'].join(' ')
},
contours: {
type: {
valType: 'enumerated',
values: ['levels', 'constraint'],
dflt: 'levels',
editType: 'calc',
description: ['If `levels`, the data is represented as a contour plot with multiple', 'levels displayed. If `constraint`, the data is represented as constraints', 'with the invalid region shaded as specified by the `operation` and', '`value` parameters.'].join(' ')
},
start: {
valType: 'number',
dflt: null,
editType: 'plot',
impliedEdits: {
'^autocontour': false
},
description: ['Sets the starting contour level value.', 'Must be less than `contours.end`'].join(' ')
},
end: {
valType: 'number',
dflt: null,
editType: 'plot',
impliedEdits: {
'^autocontour': false
},
description: ['Sets the end contour level value.', 'Must be more than `contours.start`'].join(' ')
},
size: {
valType: 'number',
dflt: null,
min: 0,
editType: 'plot',
impliedEdits: {
'^autocontour': false
},
description: ['Sets the step between each contour level.', 'Must be positive.'].join(' ')
},
coloring: {
valType: 'enumerated',
values: ['fill', 'heatmap', 'lines', 'none'],
dflt: 'fill',
editType: 'calc',
description: ['Determines the coloring method showing the contour values.', 'If *fill*, coloring is done evenly between each contour level', 'If *heatmap*, a heatmap gradient coloring is applied', 'between each contour level.', 'If *lines*, coloring is done on the contour lines.', 'If *none*, no coloring is applied on this trace.'].join(' ')
},
showlines: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: ['Determines whether or not the contour lines are drawn.', 'Has an effect only if `contours.coloring` is set to *fill*.'].join(' ')
},
showlabels: {
valType: 'boolean',
dflt: false,
editType: 'plot',
description: ['Determines whether to label the contour lines with their values.'].join(' ')
},
labelfont: fontAttrs({
editType: 'plot',
colorEditType: 'style',
description: ['Sets the font used for labeling the contour levels.', 'The default color comes from the lines, if shown.', 'The default family and size come from `layout.font`.'].join(' ')
}),
labelformat: {
valType: 'string',
dflt: '',
editType: 'plot',
description: descriptionOnlyNumbers('contour label')
},
operation: {
valType: 'enumerated',
values: [].concat(COMPARISON_OPS2).concat(INTERVAL_OPS),
dflt: '=',
editType: 'calc',
description: ['Sets the constraint operation.', '*=* keeps regions equal to `value`', '*<* and *<=* keep regions less than `value`', '*>* and *>=* keep regions greater than `value`', '*[]*, *()*, *[)*, and *(]* keep regions inside `value[0]` to `value[1]`', '*][*, *)(*, *](*, *)[* keep regions outside `value[0]` to value[1]`', 'Open vs. closed intervals make no difference to constraint display, but', 'all versions are allowed for consistency with filter transforms.'].join(' ')
},
value: {
valType: 'any',
dflt: 0,
editType: 'calc',
description: ['Sets the value or values of the constraint boundary.', 'When `operation` is set to one of the comparison values', '(' + COMPARISON_OPS2 + ')', '*value* is expected to be a number.', 'When `operation` is set to one of the interval values', '(' + INTERVAL_OPS + ')', '*value* is expected to be an array of two numbers where the first', 'is the lower bound and the second is the upper bound.'].join(' ')
},
editType: 'calc',
impliedEdits: {
autocontour: false
}
},
line: {
color: extendFlat({}, scatterLineAttrs.color, {
editType: 'style+colorbars',
description: ['Sets the color of the contour level.', 'Has no effect if `contours.coloring` is set to *lines*.'].join(' ')
}),
width: {
valType: 'number',
min: 0,
editType: 'style+colorbars',
description: ['Sets the contour line width in (in px)', 'Defaults to *0.5* when `contours.type` is *levels*.', 'Defaults to *2* when `contour.type` is *constraint*.'].join(' ')
},
dash: dash,
smoothing: extendFlat({}, scatterLineAttrs.smoothing, {
description: ['Sets the amount of smoothing for the contour lines,', 'where *0* corresponds to no smoothing.'].join(' ')
}),
editType: 'plot'
},
zorder: scatterAttrs.zorder
}, colorScaleAttrs('', {
cLetter: 'z',
autoColorDflt: false,
editTypeOverride: 'calc'
}));
/***/ }),
/***/ 50820:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Colorscale = __webpack_require__(26733);
var heatmapCalc = __webpack_require__(53984);
var setContours = __webpack_require__(73416);
var endPlus = __webpack_require__(47336);
// most is the same as heatmap calc, then adjust it
// though a few things inside heatmap calc still look for
// contour maps, because the makeBoundArray calls are too entangled
module.exports = function calc(gd, trace) {
var cd = heatmapCalc(gd, trace);
var zOut = cd[0].z;
setContours(trace, zOut);
var contours = trace.contours;
var cOpts = Colorscale.extractOpts(trace);
var cVals;
if (contours.coloring === 'heatmap' && cOpts.auto && trace.autocontour === false) {
var start = contours.start;
var end = endPlus(contours);
var cs = contours.size || 1;
var nc = Math.floor((end - start) / cs) + 1;
if (!isFinite(cs)) {
cs = 1;
nc = 1;
}
var min0 = start - cs / 2;
var max0 = min0 + nc * cs;
cVals = [min0, max0];
} else {
cVals = zOut;
}
Colorscale.calc(gd, trace, {
vals: cVals,
cLetter: 'z'
});
return cd;
};
/***/ }),
/***/ 82608:
/***/ (function(module) {
"use strict";
module.exports = function (pathinfo, contours) {
var pi0 = pathinfo[0];
var z = pi0.z;
var i;
switch (contours.type) {
case 'levels':
// Why (just) use z[0][0] and z[0][1]?
//
// N.B. using boundaryMin instead of edgeVal2 here makes the
// `contour_scatter` mock fail
var edgeVal2 = Math.min(z[0][0], z[0][1]);
for (i = 0; i < pathinfo.length; i++) {
var pi = pathinfo[i];
pi.prefixBoundary = !pi.edgepaths.length && (edgeVal2 > pi.level || pi.starts.length && edgeVal2 === pi.level);
}
break;
case 'constraint':
// after convertToConstraints, pathinfo has length=0
pi0.prefixBoundary = false;
// joinAllPaths does enough already when edgepaths are present
if (pi0.edgepaths.length) return;
var na = pi0.x.length;
var nb = pi0.y.length;
var boundaryMax = -Infinity;
var boundaryMin = Infinity;
for (i = 0; i < nb; i++) {
boundaryMin = Math.min(boundaryMin, z[i][0]);
boundaryMin = Math.min(boundaryMin, z[i][na - 1]);
boundaryMax = Math.max(boundaryMax, z[i][0]);
boundaryMax = Math.max(boundaryMax, z[i][na - 1]);
}
for (i = 1; i < na - 1; i++) {
boundaryMin = Math.min(boundaryMin, z[0][i]);
boundaryMin = Math.min(boundaryMin, z[nb - 1][i]);
boundaryMax = Math.max(boundaryMax, z[0][i]);
boundaryMax = Math.max(boundaryMax, z[nb - 1][i]);
}
var contoursValue = contours.value;
var v1, v2;
switch (contours._operation) {
case '>':
if (contoursValue > boundaryMax) {
pi0.prefixBoundary = true;
}
break;
case '<':
if (contoursValue < boundaryMin || pi0.starts.length && contoursValue === boundaryMin) {
pi0.prefixBoundary = true;
}
break;
case '[]':
v1 = Math.min(contoursValue[0], contoursValue[1]);
v2 = Math.max(contoursValue[0], contoursValue[1]);
if (v2 < boundaryMin || v1 > boundaryMax || pi0.starts.length && v2 === boundaryMin) {
pi0.prefixBoundary = true;
}
break;
case '][':
v1 = Math.min(contoursValue[0], contoursValue[1]);
v2 = Math.max(contoursValue[0], contoursValue[1]);
if (v1 < boundaryMin && v2 > boundaryMax) {
pi0.prefixBoundary = true;
}
break;
}
break;
}
};
/***/ }),
/***/ 50128:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Colorscale = __webpack_require__(26733);
var makeColorMap = __webpack_require__(79464);
var endPlus = __webpack_require__(47336);
function calc(gd, trace, opts) {
var contours = trace.contours;
var line = trace.line;
var cs = contours.size || 1;
var coloring = contours.coloring;
var colorMap = makeColorMap(trace, {
isColorbar: true
});
if (coloring === 'heatmap') {
var cOpts = Colorscale.extractOpts(trace);
opts._fillgradient = cOpts.reversescale ? Colorscale.flipScale(cOpts.colorscale) : cOpts.colorscale;
opts._zrange = [cOpts.min, cOpts.max];
} else if (coloring === 'fill') {
opts._fillcolor = colorMap;
}
opts._line = {
color: coloring === 'lines' ? colorMap : line.color,
width: contours.showlines !== false ? line.width : 0,
dash: line.dash
};
opts._levels = {
start: contours.start,
end: endPlus(contours),
size: cs
};
}
module.exports = {
min: 'zmin',
max: 'zmax',
calc: calc
};
/***/ }),
/***/ 60512:
/***/ (function(module) {
"use strict";
module.exports = {
// some constants to help with marching squares algorithm
// where does the path start for each index?
BOTTOMSTART: [1, 9, 13, 104, 713],
TOPSTART: [4, 6, 7, 104, 713],
LEFTSTART: [8, 12, 14, 208, 1114],
RIGHTSTART: [2, 3, 11, 208, 1114],
// which way [dx,dy] do we leave a given index?
// saddles are already disambiguated
NEWDELTA: [null, [-1, 0], [0, -1], [-1, 0], [1, 0], null, [0, -1], [-1, 0], [0, 1], [0, 1], null, [0, 1], [1, 0], [1, 0], [0, -1]],
// for each saddle, the first index here is used
// for dx||dy<0, the second for dx||dy>0
CHOOSESADDLE: {
104: [4, 1],
208: [2, 8],
713: [7, 13],
1114: [11, 14]
},
// after one index has been used for a saddle, which do we
// substitute to be used up later?
SADDLEREMAINDER: {
1: 4,
2: 8,
4: 1,
7: 13,
8: 2,
11: 14,
13: 7,
14: 11
},
// length of a contour, as a multiple of the plot area diagonal, per label
LABELDISTANCE: 2,
// number of contour levels after which we start increasing the number of
// labels we draw. Many contours means they will generally be close
// together, so it will be harder to follow a long way to find a label
LABELINCREASE: 10,
// minimum length of a contour line, as a multiple of the label length,
// at which we draw *any* labels
LABELMIN: 3,
// max number of labels to draw on a single contour path, no matter how long
LABELMAX: 10,
// constants for the label position cost function
LABELOPTIMIZER: {
// weight given to edge proximity
EDGECOST: 1,
// weight given to the angle off horizontal
ANGLECOST: 1,
// weight given to distance from already-placed labels
NEIGHBORCOST: 5,
// cost multiplier for labels on the same level
SAMELEVELFACTOR: 10,
// minimum distance (as a multiple of the label length)
// for labels on the same level
SAMELEVELDISTANCE: 5,
// maximum cost before we won't even place the label
MAXCOST: 100,
// number of evenly spaced points to look at in the first
// iteration of the search
INITIALSEARCHPOINTS: 10,
// number of binary search iterations after the initial wide search
ITERATIONS: 5
}
};
/***/ }),
/***/ 80464:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var handleLabelDefaults = __webpack_require__(5669);
var Color = __webpack_require__(9240);
var addOpacity = Color.addOpacity;
var opacity = Color.opacity;
var filterOps = __webpack_require__(60180);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var CONSTRAINT_REDUCTION = filterOps.CONSTRAINT_REDUCTION;
var COMPARISON_OPS2 = filterOps.COMPARISON_OPS2;
module.exports = function handleConstraintDefaults(traceIn, traceOut, coerce, layout, defaultColor, opts) {
var contours = traceOut.contours;
var showLines, lineColor, fillColor;
var operation = coerce('contours.operation');
contours._operation = CONSTRAINT_REDUCTION[operation];
handleConstraintValueDefaults(coerce, contours);
if (operation === '=') {
showLines = contours.showlines = true;
} else {
showLines = coerce('contours.showlines');
fillColor = coerce('fillcolor', addOpacity((traceIn.line || {}).color || defaultColor, 0.5));
}
if (showLines) {
var lineDfltColor = fillColor && opacity(fillColor) ? addOpacity(traceOut.fillcolor, 1) : defaultColor;
lineColor = coerce('line.color', lineDfltColor);
coerce('line.width', 2);
coerce('line.dash');
}
coerce('line.smoothing');
handleLabelDefaults(coerce, layout, lineColor, opts);
};
function handleConstraintValueDefaults(coerce, contours) {
var zvalue;
if (COMPARISON_OPS2.indexOf(contours.operation) === -1) {
// Requires an array of two numbers:
coerce('contours.value', [0, 1]);
if (!isArrayOrTypedArray(contours.value)) {
if (isNumeric(contours.value)) {
zvalue = parseFloat(contours.value);
contours.value = [zvalue, zvalue + 1];
}
} else if (contours.value.length > 2) {
contours.value = contours.value.slice(2);
} else if (contours.length === 0) {
contours.value = [0, 1];
} else if (contours.length < 2) {
zvalue = parseFloat(contours.value[0]);
contours.value = [zvalue, zvalue + 1];
} else {
contours.value = [parseFloat(contours.value[0]), parseFloat(contours.value[1])];
}
} else {
// Requires a single scalar:
coerce('contours.value', 0);
if (!isNumeric(contours.value)) {
if (isArrayOrTypedArray(contours.value)) {
contours.value = parseFloat(contours.value[0]);
} else {
contours.value = 0;
}
}
}
}
/***/ }),
/***/ 18592:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var filterOps = __webpack_require__(60180);
var isNumeric = __webpack_require__(88120);
// This syntax conforms to the existing filter transform syntax, but we don't care
// about open vs. closed intervals for simply drawing contours constraints:
module.exports = {
'[]': makeRangeSettings('[]'),
'][': makeRangeSettings(']['),
'>': makeInequalitySettings('>'),
'<': makeInequalitySettings('<'),
'=': makeInequalitySettings('=')
};
// This does not in any way shape or form support calendars. It's adapted from
// transforms/filter.js.
function coerceValue(operation, value) {
var hasArrayValue = Array.isArray(value);
var coercedValue;
function coerce(value) {
return isNumeric(value) ? +value : null;
}
if (filterOps.COMPARISON_OPS2.indexOf(operation) !== -1) {
coercedValue = hasArrayValue ? coerce(value[0]) : coerce(value);
} else if (filterOps.INTERVAL_OPS.indexOf(operation) !== -1) {
coercedValue = hasArrayValue ? [coerce(value[0]), coerce(value[1])] : [coerce(value), coerce(value)];
} else if (filterOps.SET_OPS.indexOf(operation) !== -1) {
coercedValue = hasArrayValue ? value.map(coerce) : [coerce(value)];
}
return coercedValue;
}
// Returns a parabola scaled so that the min/max is either +/- 1 and zero at the two values
// provided. The data is mapped by this function when constructing intervals so that it's
// very easy to construct contours as normal.
function makeRangeSettings(operation) {
return function (value) {
value = coerceValue(operation, value);
// Ensure proper ordering:
var min = Math.min(value[0], value[1]);
var max = Math.max(value[0], value[1]);
return {
start: min,
end: max,
size: max - min
};
};
}
function makeInequalitySettings(operation) {
return function (value) {
value = coerceValue(operation, value);
return {
start: value,
end: Infinity,
size: Infinity
};
};
}
/***/ }),
/***/ 5032:
/***/ (function(module) {
"use strict";
module.exports = function handleContourDefaults(traceIn, traceOut, coerce, coerce2) {
var contourStart = coerce2('contours.start');
var contourEnd = coerce2('contours.end');
var missingEnd = contourStart === false || contourEnd === false;
// normally we only need size if autocontour is off. But contour.calc
// pushes its calculated contour size back to the input trace, so for
// things like restyle that can call supplyDefaults without calc
// after the initial draw, we can just reuse the previous calculation
var contourSize = coerce('contours.size');
var autoContour;
if (missingEnd) autoContour = traceOut.autocontour = true;else autoContour = coerce('autocontour', false);
if (autoContour || !contourSize) coerce('ncontours');
};
/***/ }),
/***/ 15651:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
// The contour extraction is great, except it totally fails for constraints because we
// need weird range loops and flipped contours instead of the usual format. This function
// does some weird manipulation of the extracted pathinfo data such that it magically
// draws contours correctly *as* constraints.
//
// ** I do not know which "weird range loops" the comment above is referring to.
module.exports = function (pathinfo, operation) {
var i, pi0, pi1;
var op0 = function (arr) {
return arr.reverse();
};
var op1 = function (arr) {
return arr;
};
switch (operation) {
case '=':
case '<':
return pathinfo;
case '>':
if (pathinfo.length !== 1) {
Lib.warn('Contour data invalid for the specified inequality operation.');
}
// In this case there should be exactly one contour levels in pathinfo.
// We flip all of the data. This will draw the contour as closed.
pi0 = pathinfo[0];
for (i = 0; i < pi0.edgepaths.length; i++) {
pi0.edgepaths[i] = op0(pi0.edgepaths[i]);
}
for (i = 0; i < pi0.paths.length; i++) {
pi0.paths[i] = op0(pi0.paths[i]);
}
for (i = 0; i < pi0.starts.length; i++) {
pi0.starts[i] = op0(pi0.starts[i]);
}
return pathinfo;
case '][':
var tmp = op0;
op0 = op1;
op1 = tmp;
// It's a nice rule, except this definitely *is* what's intended here.
/* eslint-disable: no-fallthrough */
case '[]':
/* eslint-enable: no-fallthrough */
if (pathinfo.length !== 2) {
Lib.warn('Contour data invalid for the specified inequality range operation.');
}
// In this case there should be exactly two contour levels in pathinfo.
// - We concatenate the info into one pathinfo.
// - We must also flip all of the data in the `[]` case.
// This will draw the contours as closed.
pi0 = copyPathinfo(pathinfo[0]);
pi1 = copyPathinfo(pathinfo[1]);
for (i = 0; i < pi0.edgepaths.length; i++) {
pi0.edgepaths[i] = op0(pi0.edgepaths[i]);
}
for (i = 0; i < pi0.paths.length; i++) {
pi0.paths[i] = op0(pi0.paths[i]);
}
for (i = 0; i < pi0.starts.length; i++) {
pi0.starts[i] = op0(pi0.starts[i]);
}
while (pi1.edgepaths.length) {
pi0.edgepaths.push(op1(pi1.edgepaths.shift()));
}
while (pi1.paths.length) {
pi0.paths.push(op1(pi1.paths.shift()));
}
while (pi1.starts.length) {
pi0.starts.push(op1(pi1.starts.shift()));
}
return [pi0];
}
};
function copyPathinfo(pi) {
return Lib.extendFlat({}, pi, {
edgepaths: Lib.extendDeep([], pi.edgepaths),
paths: Lib.extendDeep([], pi.paths),
starts: Lib.extendDeep([], pi.starts)
});
}
/***/ }),
/***/ 77032:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleXYZDefaults = __webpack_require__(53024);
var handlePeriodDefaults = __webpack_require__(98632);
var handleConstraintDefaults = __webpack_require__(80464);
var handleContoursDefaults = __webpack_require__(5032);
var handleStyleDefaults = __webpack_require__(38936);
var handleHeatmapLabelDefaults = __webpack_require__(20152);
var attributes = __webpack_require__(12115);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
function coerce2(attr) {
return Lib.coerce2(traceIn, traceOut, attributes, attr);
}
var len = handleXYZDefaults(traceIn, traceOut, coerce, layout);
if (!len) {
traceOut.visible = false;
return;
}
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');
coerce('text');
coerce('hovertext');
coerce('hoverongaps');
coerce('hovertemplate');
var isConstraint = coerce('contours.type') === 'constraint';
coerce('connectgaps', Lib.isArray1D(traceOut.z));
if (isConstraint) {
handleConstraintDefaults(traceIn, traceOut, coerce, layout, defaultColor);
} else {
handleContoursDefaults(traceIn, traceOut, coerce, coerce2);
handleStyleDefaults(traceIn, traceOut, coerce, layout);
}
if (traceOut.contours && traceOut.contours.coloring === 'heatmap') {
handleHeatmapLabelDefaults(coerce, layout);
}
coerce('zorder');
};
/***/ }),
/***/ 67356:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var constraintMapping = __webpack_require__(18592);
var endPlus = __webpack_require__(47336);
module.exports = function emptyPathinfo(contours, plotinfo, cd0) {
var contoursFinal = contours.type === 'constraint' ? constraintMapping[contours._operation](contours.value) : contours;
var cs = contoursFinal.size;
var pathinfo = [];
var end = endPlus(contoursFinal);
var carpet = cd0.trace._carpetTrace;
var basePathinfo = carpet ? {
// store axes so we can convert to px
xaxis: carpet.aaxis,
yaxis: carpet.baxis,
// full data arrays to use for interpolation
x: cd0.a,
y: cd0.b
} : {
xaxis: plotinfo.xaxis,
yaxis: plotinfo.yaxis,
x: cd0.x,
y: cd0.y
};
for (var ci = contoursFinal.start; ci < end; ci += cs) {
pathinfo.push(Lib.extendFlat({
level: ci,
// all the cells with nontrivial marching index
crossings: {},
// starting points on the edges of the lattice for each contour
starts: [],
// all unclosed paths (may have less items than starts,
// if a path is closed by rounding)
edgepaths: [],
// all closed paths
paths: [],
z: cd0.z,
smoothing: cd0.trace.line.smoothing
}, basePathinfo));
if (pathinfo.length > 1000) {
Lib.warn('Too many contours, clipping at 1000', contours);
break;
}
}
return pathinfo;
};
/***/ }),
/***/ 47336:
/***/ (function(module) {
"use strict";
/*
* tiny helper to move the end of the contours a little to prevent
* losing the last contour to rounding errors
*/
module.exports = function endPlus(contours) {
return contours.end + contours.size / 1e6;
};
/***/ }),
/***/ 16349:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var constants = __webpack_require__(60512);
module.exports = function findAllPaths(pathinfo, xtol, ytol) {
var cnt, startLoc, i, pi, j;
// Default just passes these values through as they were before:
xtol = xtol || 0.01;
ytol = ytol || 0.01;
for (i = 0; i < pathinfo.length; i++) {
pi = pathinfo[i];
for (j = 0; j < pi.starts.length; j++) {
startLoc = pi.starts[j];
makePath(pi, startLoc, 'edge', xtol, ytol);
}
cnt = 0;
while (Object.keys(pi.crossings).length && cnt < 10000) {
cnt++;
startLoc = Object.keys(pi.crossings)[0].split(',').map(Number);
makePath(pi, startLoc, undefined, xtol, ytol);
}
if (cnt === 10000) Lib.log('Infinite loop in contour?');
}
};
function equalPts(pt1, pt2, xtol, ytol) {
return Math.abs(pt1[0] - pt2[0]) < xtol && Math.abs(pt1[1] - pt2[1]) < ytol;
}
// distance in index units - uses the 3rd and 4th items in points
function ptDist(pt1, pt2) {
var dx = pt1[2] - pt2[2];
var dy = pt1[3] - pt2[3];
return Math.sqrt(dx * dx + dy * dy);
}
function makePath(pi, loc, edgeflag, xtol, ytol) {
var locStr = loc.join(',');
var mi = pi.crossings[locStr];
var marchStep = getStartStep(mi, edgeflag, loc);
// start by going backward a half step and finding the crossing point
var pts = [getInterpPx(pi, loc, [-marchStep[0], -marchStep[1]])];
var m = pi.z.length;
var n = pi.z[0].length;
var startLoc = loc.slice();
var startStep = marchStep.slice();
var cnt;
// now follow the path
for (cnt = 0; cnt < 10000; cnt++) {
// just to avoid infinite loops
if (mi > 20) {
mi = constants.CHOOSESADDLE[mi][(marchStep[0] || marchStep[1]) < 0 ? 0 : 1];
pi.crossings[locStr] = constants.SADDLEREMAINDER[mi];
} else {
delete pi.crossings[locStr];
}
marchStep = constants.NEWDELTA[mi];
if (!marchStep) {
Lib.log('Found bad marching index:', mi, loc, pi.level);
break;
}
// find the crossing a half step forward, and then take the full step
pts.push(getInterpPx(pi, loc, marchStep));
loc[0] += marchStep[0];
loc[1] += marchStep[1];
locStr = loc.join(',');
// don't include the same point multiple times
if (equalPts(pts[pts.length - 1], pts[pts.length - 2], xtol, ytol)) pts.pop();
var atEdge = marchStep[0] && (loc[0] < 0 || loc[0] > n - 2) || marchStep[1] && (loc[1] < 0 || loc[1] > m - 2);
var closedLoop = loc[0] === startLoc[0] && loc[1] === startLoc[1] && marchStep[0] === startStep[0] && marchStep[1] === startStep[1];
// have we completed a loop, or reached an edge?
if (closedLoop || edgeflag && atEdge) break;
mi = pi.crossings[locStr];
}
if (cnt === 10000) {
Lib.log('Infinite loop in contour?');
}
var closedpath = equalPts(pts[0], pts[pts.length - 1], xtol, ytol);
var totaldist = 0;
var distThresholdFactor = 0.2 * pi.smoothing;
var alldists = [];
var cropstart = 0;
var distgroup, cnt2, cnt3, newpt, ptcnt, ptavg, thisdist, i, j, edgepathi, edgepathj;
/*
* Check for points that are too close together (<1/5 the average dist
* *in grid index units* (important for log axes and nonuniform grids),
* less if less smoothed) and just take the center (or avg of center 2).
* This cuts down on funny behavior when a point is very close to a
* contour level.
*/
for (cnt = 1; cnt < pts.length; cnt++) {
thisdist = ptDist(pts[cnt], pts[cnt - 1]);
totaldist += thisdist;
alldists.push(thisdist);
}
var distThreshold = totaldist / alldists.length * distThresholdFactor;
function getpt(i) {
return pts[i % pts.length];
}
for (cnt = pts.length - 2; cnt >= cropstart; cnt--) {
distgroup = alldists[cnt];
if (distgroup < distThreshold) {
cnt3 = 0;
for (cnt2 = cnt - 1; cnt2 >= cropstart; cnt2--) {
if (distgroup + alldists[cnt2] < distThreshold) {
distgroup += alldists[cnt2];
} else break;
}
// closed path with close points wrapping around the boundary?
if (closedpath && cnt === pts.length - 2) {
for (cnt3 = 0; cnt3 < cnt2; cnt3++) {
if (distgroup + alldists[cnt3] < distThreshold) {
distgroup += alldists[cnt3];
} else break;
}
}
ptcnt = cnt - cnt2 + cnt3 + 1;
ptavg = Math.floor((cnt + cnt2 + cnt3 + 2) / 2);
// either endpoint included: keep the endpoint
if (!closedpath && cnt === pts.length - 2) newpt = pts[pts.length - 1];else if (!closedpath && cnt2 === -1) newpt = pts[0];
// odd # of points - just take the central one
else if (ptcnt % 2) newpt = getpt(ptavg);
// even # of pts - average central two
else {
newpt = [(getpt(ptavg)[0] + getpt(ptavg + 1)[0]) / 2, (getpt(ptavg)[1] + getpt(ptavg + 1)[1]) / 2];
}
pts.splice(cnt2 + 1, cnt - cnt2 + 1, newpt);
cnt = cnt2 + 1;
if (cnt3) cropstart = cnt3;
if (closedpath) {
if (cnt === pts.length - 2) pts[cnt3] = pts[pts.length - 1];else if (cnt === 0) pts[pts.length - 1] = pts[0];
}
}
}
pts.splice(0, cropstart);
// done with the index parts - remove them so path generation works right
// because it depends on only having [xpx, ypx]
for (cnt = 0; cnt < pts.length; cnt++) pts[cnt].length = 2;
// don't return single-point paths (ie all points were the same
// so they got deleted?)
if (pts.length < 2) return;else if (closedpath) {
pts.pop();
pi.paths.push(pts);
} else {
if (!edgeflag) {
Lib.log('Unclosed interior contour?', pi.level, startLoc.join(','), pts.join('L'));
}
// edge path - does it start where an existing edge path ends, or vice versa?
var merged = false;
for (i = 0; i < pi.edgepaths.length; i++) {
edgepathi = pi.edgepaths[i];
if (!merged && equalPts(edgepathi[0], pts[pts.length - 1], xtol, ytol)) {
pts.pop();
merged = true;
// now does it ALSO meet the end of another (or the same) path?
var doublemerged = false;
for (j = 0; j < pi.edgepaths.length; j++) {
edgepathj = pi.edgepaths[j];
if (equalPts(edgepathj[edgepathj.length - 1], pts[0], xtol, ytol)) {
doublemerged = true;
pts.shift();
pi.edgepaths.splice(i, 1);
if (j === i) {
// the path is now closed
pi.paths.push(pts.concat(edgepathj));
} else {
if (j > i) j--;
pi.edgepaths[j] = edgepathj.concat(pts, edgepathi);
}
break;
}
}
if (!doublemerged) {
pi.edgepaths[i] = pts.concat(edgepathi);
}
}
}
for (i = 0; i < pi.edgepaths.length; i++) {
if (merged) break;
edgepathi = pi.edgepaths[i];
if (equalPts(edgepathi[edgepathi.length - 1], pts[0], xtol, ytol)) {
pts.shift();
pi.edgepaths[i] = edgepathi.concat(pts);
merged = true;
}
}
if (!merged) pi.edgepaths.push(pts);
}
}
// special function to get the marching step of the
// first point in the path (leading to loc)
function getStartStep(mi, edgeflag, loc) {
var dx = 0;
var dy = 0;
if (mi > 20 && edgeflag) {
// these saddles start at +/- x
if (mi === 208 || mi === 1114) {
// if we're starting at the left side, we must be going right
dx = loc[0] === 0 ? 1 : -1;
} else {
// if we're starting at the bottom, we must be going up
dy = loc[1] === 0 ? 1 : -1;
}
} else if (constants.BOTTOMSTART.indexOf(mi) !== -1) dy = 1;else if (constants.LEFTSTART.indexOf(mi) !== -1) dx = 1;else if (constants.TOPSTART.indexOf(mi) !== -1) dy = -1;else dx = -1;
return [dx, dy];
}
/*
* Find the pixel coordinates of a particular crossing
*
* @param {object} pi: the pathinfo object at this level
* @param {array} loc: the grid index [x, y] of the crossing
* @param {array} step: the direction [dx, dy] we're moving on the grid
*
* @return {array} [xpx, ypx, xi, yi]: the first two are the pixel location,
* the next two are the interpolated grid indices, which we use for
* distance calculations to delete points that are too close together.
* This is important when the grid is nonuniform (and most dramatically when
* we're on log axes and include invalid (0 or negative) values.
* It's crucial to delete these extra two before turning an array of these
* points into a path, because those routines require length-2 points.
*/
function getInterpPx(pi, loc, step) {
var locx = loc[0] + Math.max(step[0], 0);
var locy = loc[1] + Math.max(step[1], 0);
var zxy = pi.z[locy][locx];
var xa = pi.xaxis;
var ya = pi.yaxis;
// Interpolate in linear space, then convert to pixel
if (step[1]) {
var dx = (pi.level - zxy) / (pi.z[locy][locx + 1] - zxy);
// Interpolate, but protect against NaN linear values for log axis (dx will equal 1 or 0)
var dxl = (dx !== 1 ? (1 - dx) * xa.c2l(pi.x[locx]) : 0) + (dx !== 0 ? dx * xa.c2l(pi.x[locx + 1]) : 0);
return [xa.c2p(xa.l2c(dxl), true), ya.c2p(pi.y[locy], true), locx + dx, locy];
} else {
var dy = (pi.level - zxy) / (pi.z[locy + 1][locx] - zxy);
var dyl = (dy !== 1 ? (1 - dy) * ya.c2l(pi.y[locy]) : 0) + (dy !== 0 ? dy * ya.c2l(pi.y[locy + 1]) : 0);
return [xa.c2p(pi.x[locx], true), ya.c2p(ya.l2c(dyl), true), locx, locy + dy];
}
}
/***/ }),
/***/ 93452:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Color = __webpack_require__(9240);
var heatmapHoverPoints = __webpack_require__(41864);
module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) {
if (!opts) opts = {};
opts.isContour = true;
var hoverData = heatmapHoverPoints(pointData, xval, yval, hovermode, opts);
if (hoverData) {
hoverData.forEach(function (hoverPt) {
var trace = hoverPt.trace;
if (trace.contours.type === 'constraint') {
if (trace.fillcolor && Color.opacity(trace.fillcolor)) {
hoverPt.color = Color.addOpacity(trace.fillcolor, 1);
} else if (trace.contours.showlines && Color.opacity(trace.line.color)) {
hoverPt.color = Color.addOpacity(trace.line.color, 1);
}
}
});
}
return hoverData;
};
/***/ }),
/***/ 30659:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(12115),
supplyDefaults: __webpack_require__(77032),
calc: __webpack_require__(50820),
plot: (__webpack_require__(7344).plot),
style: __webpack_require__(46496),
colorbar: __webpack_require__(50128),
hoverPoints: __webpack_require__(93452),
moduleType: 'trace',
name: 'contour',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', '2dMap', 'contour', 'showLegend'],
meta: {
description: ['The data from which contour lines are computed is set in `z`.', 'Data in `z` must be a {2D array} of numbers.', 'Say that `z` has N rows and M columns, then by default,', 'these N rows correspond to N y coordinates', '(set in `y` or auto-generated) and the M columns', 'correspond to M x coordinates (set in `x` or auto-generated).', 'By setting `transpose` to *true*, the above behavior is flipped.'].join(' ')
}
};
/***/ }),
/***/ 5669:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
module.exports = function handleLabelDefaults(coerce, layout, lineColor, opts) {
if (!opts) opts = {};
var showLabels = coerce('contours.showlabels');
if (showLabels) {
var globalFont = layout.font;
Lib.coerceFont(coerce, 'contours.labelfont', {
family: globalFont.family,
size: globalFont.size,
color: lineColor
});
coerce('contours.labelformat');
}
if (opts.hasHover !== false) coerce('zhoverformat');
};
/***/ }),
/***/ 79464:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Colorscale = __webpack_require__(26733);
var endPlus = __webpack_require__(47336);
module.exports = function makeColorMap(trace) {
var contours = trace.contours;
var start = contours.start;
var end = endPlus(contours);
var cs = contours.size || 1;
var nc = Math.floor((end - start) / cs) + 1;
var extra = contours.coloring === 'lines' ? 0 : 1;
var cOpts = Colorscale.extractOpts(trace);
if (!isFinite(cs)) {
cs = 1;
nc = 1;
}
var scl = cOpts.reversescale ? Colorscale.flipScale(cOpts.colorscale) : cOpts.colorscale;
var len = scl.length;
var domain = new Array(len);
var range = new Array(len);
var si, i;
var zmin0 = cOpts.min;
var zmax0 = cOpts.max;
if (contours.coloring === 'heatmap') {
for (i = 0; i < len; i++) {
si = scl[i];
domain[i] = si[0] * (zmax0 - zmin0) + zmin0;
range[i] = si[1];
}
// do the contours extend beyond the colorscale?
// if so, extend the colorscale with constants
var zRange = d3.extent([zmin0, zmax0, contours.start, contours.start + cs * (nc - 1)]);
var zmin = zRange[zmin0 < zmax0 ? 0 : 1];
var zmax = zRange[zmin0 < zmax0 ? 1 : 0];
if (zmin !== zmin0) {
domain.splice(0, 0, zmin);
range.splice(0, 0, range[0]);
}
if (zmax !== zmax0) {
domain.push(zmax);
range.push(range[range.length - 1]);
}
} else {
var zRangeInput = trace._input && typeof trace._input.zmin === 'number' && typeof trace._input.zmax === 'number';
// If zmin/zmax are explicitly set, consider case where user specifies a
// narrower z range than that of the contours start/end.
if (zRangeInput && (start <= zmin0 || end >= zmax0)) {
if (start <= zmin0) start = zmin0;
if (end >= zmax0) end = zmax0;
nc = Math.floor((end - start) / cs) + 1;
extra = 0;
}
for (i = 0; i < len; i++) {
si = scl[i];
domain[i] = (si[0] * (nc + extra - 1) - extra / 2) * cs + start;
range[i] = si[1];
}
// Make the colorscale fit the z range except if contours are explicitly
// set BUT NOT zmin/zmax.
if (zRangeInput || trace.autocontour) {
if (domain[0] > zmin0) {
domain.unshift(zmin0);
range.unshift(range[0]);
}
if (domain[domain.length - 1] < zmax0) {
domain.push(zmax0);
range.push(range[range.length - 1]);
}
}
}
return Colorscale.makeColorScaleFunc({
domain: domain,
range: range
}, {
noNumericCheck: true
});
};
/***/ }),
/***/ 81672:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var constants = __webpack_require__(60512);
// Calculate all the marching indices, for ALL levels at once.
// since we want to be exhaustive we'll check for contour crossings
// at every intersection, rather than just following a path
// TODO: shorten the inner loop to only the relevant levels
module.exports = function makeCrossings(pathinfo) {
var z = pathinfo[0].z;
var m = z.length;
var n = z[0].length; // we already made sure z isn't ragged in interp2d
var twoWide = m === 2 || n === 2;
var xi;
var yi;
var startIndices;
var ystartIndices;
var label;
var corners;
var mi;
var pi;
var i;
for (yi = 0; yi < m - 1; yi++) {
ystartIndices = [];
if (yi === 0) ystartIndices = ystartIndices.concat(constants.BOTTOMSTART);
if (yi === m - 2) ystartIndices = ystartIndices.concat(constants.TOPSTART);
for (xi = 0; xi < n - 1; xi++) {
startIndices = ystartIndices.slice();
if (xi === 0) startIndices = startIndices.concat(constants.LEFTSTART);
if (xi === n - 2) startIndices = startIndices.concat(constants.RIGHTSTART);
label = xi + ',' + yi;
corners = [[z[yi][xi], z[yi][xi + 1]], [z[yi + 1][xi], z[yi + 1][xi + 1]]];
for (i = 0; i < pathinfo.length; i++) {
pi = pathinfo[i];
mi = getMarchingIndex(pi.level, corners);
if (!mi) continue;
pi.crossings[label] = mi;
if (startIndices.indexOf(mi) !== -1) {
pi.starts.push([xi, yi]);
if (twoWide && startIndices.indexOf(mi, startIndices.indexOf(mi) + 1) !== -1) {
// the same square has starts from opposite sides
// it's not possible to have starts on opposite edges
// of a corner, only a start and an end...
// but if the array is only two points wide (either way)
// you can have starts on opposite sides.
pi.starts.push([xi, yi]);
}
}
}
}
}
};
// modified marching squares algorithm,
// so we disambiguate the saddle points from the start
// and we ignore the cases with no crossings
// the index I'm using is based on:
// http://en.wikipedia.org/wiki/Marching_squares
// except that the saddles bifurcate and I represent them
// as the decimal combination of the two appropriate
// non-saddle indices
function getMarchingIndex(val, corners) {
var mi = (corners[0][0] > val ? 0 : 1) + (corners[0][1] > val ? 0 : 2) + (corners[1][1] > val ? 0 : 4) + (corners[1][0] > val ? 0 : 8);
if (mi === 5 || mi === 10) {
var avg = (corners[0][0] + corners[0][1] + corners[1][0] + corners[1][1]) / 4;
// two peaks with a big valley
if (val > avg) return mi === 5 ? 713 : 1114;
// two valleys with a big ridge
return mi === 5 ? 104 : 208;
}
return mi === 15 ? 0 : mi;
}
/***/ }),
/***/ 7344:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var Colorscale = __webpack_require__(26733);
var svgTextUtils = __webpack_require__(41536);
var Axes = __webpack_require__(81536);
var setConvert = __webpack_require__(9224);
var heatmapPlot = __webpack_require__(97440);
var makeCrossings = __webpack_require__(81672);
var findAllPaths = __webpack_require__(16349);
var emptyPathinfo = __webpack_require__(67356);
var convertToConstraints = __webpack_require__(15651);
var closeBoundaries = __webpack_require__(82608);
var constants = __webpack_require__(60512);
var costConstants = constants.LABELOPTIMIZER;
exports.plot = function plot(gd, plotinfo, cdcontours, contourLayer) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
Lib.makeTraceGroups(contourLayer, cdcontours, 'contour').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
var x = cd0.x;
var y = cd0.y;
var contours = trace.contours;
var pathinfo = emptyPathinfo(contours, plotinfo, cd0);
// use a heatmap to fill - draw it behind the lines
var heatmapColoringLayer = Lib.ensureSingle(plotGroup, 'g', 'heatmapcoloring');
var cdheatmaps = [];
if (contours.coloring === 'heatmap') {
cdheatmaps = [cd];
}
heatmapPlot(gd, plotinfo, cdheatmaps, heatmapColoringLayer);
makeCrossings(pathinfo);
findAllPaths(pathinfo);
var leftedge = xa.c2p(x[0], true);
var rightedge = xa.c2p(x[x.length - 1], true);
var bottomedge = ya.c2p(y[0], true);
var topedge = ya.c2p(y[y.length - 1], true);
var perimeter = [[leftedge, topedge], [rightedge, topedge], [rightedge, bottomedge], [leftedge, bottomedge]];
var fillPathinfo = pathinfo;
if (contours.type === 'constraint') {
// N.B. this also mutates pathinfo
fillPathinfo = convertToConstraints(pathinfo, contours._operation);
}
// draw everything
makeBackground(plotGroup, perimeter, contours);
makeFills(plotGroup, fillPathinfo, perimeter, contours);
makeLinesAndLabels(plotGroup, pathinfo, gd, cd0, contours);
clipGaps(plotGroup, plotinfo, gd, cd0, perimeter);
});
};
function makeBackground(plotgroup, perimeter, contours) {
var bggroup = Lib.ensureSingle(plotgroup, 'g', 'contourbg');
var bgfill = bggroup.selectAll('path').data(contours.coloring === 'fill' ? [0] : []);
bgfill.enter().append('path');
bgfill.exit().remove();
bgfill.attr('d', 'M' + perimeter.join('L') + 'Z').style('stroke', 'none');
}
function makeFills(plotgroup, pathinfo, perimeter, contours) {
var hasFills = contours.coloring === 'fill' || contours.type === 'constraint' && contours._operation !== '=';
var boundaryPath = 'M' + perimeter.join('L') + 'Z';
// fills prefixBoundary in pathinfo items
if (hasFills) {
closeBoundaries(pathinfo, contours);
}
var fillgroup = Lib.ensureSingle(plotgroup, 'g', 'contourfill');
var fillitems = fillgroup.selectAll('path').data(hasFills ? pathinfo : []);
fillitems.enter().append('path');
fillitems.exit().remove();
fillitems.each(function (pi) {
// join all paths for this level together into a single path
// first follow clockwise around the perimeter to close any open paths
// if the whole perimeter is above this level, start with a path
// enclosing the whole thing. With all that, the parity should mean
// that we always fill everything above the contour, nothing below
var fullpath = (pi.prefixBoundary ? boundaryPath : '') + joinAllPaths(pi, perimeter);
if (!fullpath) {
d3.select(this).remove();
} else {
d3.select(this).attr('d', fullpath).style('stroke', 'none');
}
});
}
function joinAllPaths(pi, perimeter) {
var fullpath = '';
var i = 0;
var startsleft = pi.edgepaths.map(function (v, i) {
return i;
});
var newloop = true;
var endpt;
var newendpt;
var cnt;
var nexti;
var possiblei;
var addpath;
function istop(pt) {
return Math.abs(pt[1] - perimeter[0][1]) < 0.01;
}
function isbottom(pt) {
return Math.abs(pt[1] - perimeter[2][1]) < 0.01;
}
function isleft(pt) {
return Math.abs(pt[0] - perimeter[0][0]) < 0.01;
}
function isright(pt) {
return Math.abs(pt[0] - perimeter[2][0]) < 0.01;
}
while (startsleft.length) {
addpath = Drawing.smoothopen(pi.edgepaths[i], pi.smoothing);
fullpath += newloop ? addpath : addpath.replace(/^M/, 'L');
startsleft.splice(startsleft.indexOf(i), 1);
endpt = pi.edgepaths[i][pi.edgepaths[i].length - 1];
nexti = -1;
// now loop through sides, moving our endpoint until we find a new start
for (cnt = 0; cnt < 4; cnt++) {
// just to prevent infinite loops
if (!endpt) {
Lib.log('Missing end?', i, pi);
break;
}
if (istop(endpt) && !isright(endpt)) newendpt = perimeter[1]; // right top
else if (isleft(endpt)) newendpt = perimeter[0]; // left top
else if (isbottom(endpt)) newendpt = perimeter[3]; // right bottom
else if (isright(endpt)) newendpt = perimeter[2]; // left bottom
for (possiblei = 0; possiblei < pi.edgepaths.length; possiblei++) {
var ptNew = pi.edgepaths[possiblei][0];
// is ptNew on the (horz. or vert.) segment from endpt to newendpt?
if (Math.abs(endpt[0] - newendpt[0]) < 0.01) {
if (Math.abs(endpt[0] - ptNew[0]) < 0.01 && (ptNew[1] - endpt[1]) * (newendpt[1] - ptNew[1]) >= 0) {
newendpt = ptNew;
nexti = possiblei;
}
} else if (Math.abs(endpt[1] - newendpt[1]) < 0.01) {
if (Math.abs(endpt[1] - ptNew[1]) < 0.01 && (ptNew[0] - endpt[0]) * (newendpt[0] - ptNew[0]) >= 0) {
newendpt = ptNew;
nexti = possiblei;
}
} else {
Lib.log('endpt to newendpt is not vert. or horz.', endpt, newendpt, ptNew);
}
}
endpt = newendpt;
if (nexti >= 0) break;
fullpath += 'L' + newendpt;
}
if (nexti === pi.edgepaths.length) {
Lib.log('unclosed perimeter path');
break;
}
i = nexti;
// if we closed back on a loop we already included,
// close it and start a new loop
newloop = startsleft.indexOf(i) === -1;
if (newloop) {
i = startsleft[0];
fullpath += 'Z';
}
}
// finally add the interior paths
for (i = 0; i < pi.paths.length; i++) {
fullpath += Drawing.smoothclosed(pi.paths[i], pi.smoothing);
}
return fullpath;
}
function makeLinesAndLabels(plotgroup, pathinfo, gd, cd0, contours) {
var isStatic = gd._context.staticPlot;
var lineContainer = Lib.ensureSingle(plotgroup, 'g', 'contourlines');
var showLines = contours.showlines !== false;
var showLabels = contours.showlabels;
var clipLinesForLabels = showLines && showLabels;
// Even if we're not going to show lines, we need to create them
// if we're showing labels, because the fill paths include the perimeter
// so can't be used to position the labels correctly.
// In this case we'll remove the lines after making the labels.
var linegroup = exports.createLines(lineContainer, showLines || showLabels, pathinfo, isStatic);
var lineClip = exports.createLineClip(lineContainer, clipLinesForLabels, gd, cd0.trace.uid);
var labelGroup = plotgroup.selectAll('g.contourlabels').data(showLabels ? [0] : []);
labelGroup.exit().remove();
labelGroup.enter().append('g').classed('contourlabels', true);
if (showLabels) {
var labelClipPathData = [];
var labelData = [];
// invalidate the getTextLocation cache in case paths changed
Lib.clearLocationCache();
var contourFormat = exports.labelFormatter(gd, cd0);
var dummyText = Drawing.tester.append('text').attr('data-notex', 1).call(Drawing.font, contours.labelfont);
var xa = pathinfo[0].xaxis;
var ya = pathinfo[0].yaxis;
var xLen = xa._length;
var yLen = ya._length;
var xRng = xa.range;
var yRng = ya.range;
var xMin = Lib.aggNums(Math.min, null, cd0.x);
var xMax = Lib.aggNums(Math.max, null, cd0.x);
var yMin = Lib.aggNums(Math.min, null, cd0.y);
var yMax = Lib.aggNums(Math.max, null, cd0.y);
var x0 = Math.max(xa.c2p(xMin, true), 0);
var x1 = Math.min(xa.c2p(xMax, true), xLen);
var y0 = Math.max(ya.c2p(yMax, true), 0);
var y1 = Math.min(ya.c2p(yMin, true), yLen);
// visible bounds of the contour trace (and the midpoints, to
// help with cost calculations)
var bounds = {};
if (xRng[0] < xRng[1]) {
bounds.left = x0;
bounds.right = x1;
} else {
bounds.left = x1;
bounds.right = x0;
}
if (yRng[0] < yRng[1]) {
bounds.top = y0;
bounds.bottom = y1;
} else {
bounds.top = y1;
bounds.bottom = y0;
}
bounds.middle = (bounds.top + bounds.bottom) / 2;
bounds.center = (bounds.left + bounds.right) / 2;
labelClipPathData.push([[bounds.left, bounds.top], [bounds.right, bounds.top], [bounds.right, bounds.bottom], [bounds.left, bounds.bottom]]);
var plotDiagonal = Math.sqrt(xLen * xLen + yLen * yLen);
// the path length to use to scale the number of labels to draw:
var normLength = constants.LABELDISTANCE * plotDiagonal / Math.max(1, pathinfo.length / constants.LABELINCREASE);
linegroup.each(function (d) {
var textOpts = exports.calcTextOpts(d.level, contourFormat, dummyText, gd);
d3.select(this).selectAll('path').each(function () {
var path = this;
var pathBounds = Lib.getVisibleSegment(path, bounds, textOpts.height / 2);
if (!pathBounds) return;
if (pathBounds.len < (textOpts.width + textOpts.height) * constants.LABELMIN) return;
var maxLabels = Math.min(Math.ceil(pathBounds.len / normLength), constants.LABELMAX);
for (var i = 0; i < maxLabels; i++) {
var loc = exports.findBestTextLocation(path, pathBounds, textOpts, labelData, bounds);
if (!loc) break;
exports.addLabelData(loc, textOpts, labelData, labelClipPathData);
}
});
});
dummyText.remove();
exports.drawLabels(labelGroup, labelData, gd, lineClip, clipLinesForLabels ? labelClipPathData : null);
}
if (showLabels && !showLines) linegroup.remove();
}
exports.createLines = function (lineContainer, makeLines, pathinfo, isStatic) {
var smoothing = pathinfo[0].smoothing;
var linegroup = lineContainer.selectAll('g.contourlevel').data(makeLines ? pathinfo : []);
linegroup.exit().remove();
linegroup.enter().append('g').classed('contourlevel', true);
if (makeLines) {
// pedgepaths / ppaths are used by contourcarpet, for the paths transformed from a/b to x/y
// edgepaths / paths are used by contour since it's in x/y from the start
var opencontourlines = linegroup.selectAll('path.openline').data(function (d) {
return d.pedgepaths || d.edgepaths;
});
opencontourlines.exit().remove();
opencontourlines.enter().append('path').classed('openline', true);
opencontourlines.attr('d', function (d) {
return Drawing.smoothopen(d, smoothing);
}).style('stroke-miterlimit', 1).style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke');
var closedcontourlines = linegroup.selectAll('path.closedline').data(function (d) {
return d.ppaths || d.paths;
});
closedcontourlines.exit().remove();
closedcontourlines.enter().append('path').classed('closedline', true);
closedcontourlines.attr('d', function (d) {
return Drawing.smoothclosed(d, smoothing);
}).style('stroke-miterlimit', 1).style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke');
}
return linegroup;
};
exports.createLineClip = function (lineContainer, clipLinesForLabels, gd, uid) {
var clips = gd._fullLayout._clips;
var clipId = clipLinesForLabels ? 'clipline' + uid : null;
var lineClip = clips.selectAll('#' + clipId).data(clipLinesForLabels ? [0] : []);
lineClip.exit().remove();
lineClip.enter().append('clipPath').classed('contourlineclip', true).attr('id', clipId);
Drawing.setClipUrl(lineContainer, clipId, gd);
return lineClip;
};
exports.labelFormatter = function (gd, cd0) {
var fullLayout = gd._fullLayout;
var trace = cd0.trace;
var contours = trace.contours;
var formatAxis = {
type: 'linear',
_id: 'ycontour',
showexponent: 'all',
exponentformat: 'B'
};
if (contours.labelformat) {
formatAxis.tickformat = contours.labelformat;
setConvert(formatAxis, fullLayout);
} else {
var cOpts = Colorscale.extractOpts(trace);
if (cOpts && cOpts.colorbar && cOpts.colorbar._axis) {
formatAxis = cOpts.colorbar._axis;
} else {
if (contours.type === 'constraint') {
var value = contours.value;
if (Lib.isArrayOrTypedArray(value)) {
formatAxis.range = [value[0], value[value.length - 1]];
} else formatAxis.range = [value, value];
} else {
formatAxis.range = [contours.start, contours.end];
formatAxis.nticks = (contours.end - contours.start) / contours.size;
}
if (formatAxis.range[0] === formatAxis.range[1]) {
formatAxis.range[1] += formatAxis.range[0] || 1;
}
if (!formatAxis.nticks) formatAxis.nticks = 1000;
setConvert(formatAxis, fullLayout);
Axes.prepTicks(formatAxis);
formatAxis._tmin = null;
formatAxis._tmax = null;
}
}
return function (v) {
return Axes.tickText(formatAxis, v).text;
};
};
exports.calcTextOpts = function (level, contourFormat, dummyText, gd) {
var text = contourFormat(level);
dummyText.text(text).call(svgTextUtils.convertToTspans, gd);
var el = dummyText.node();
var bBox = Drawing.bBox(el, true);
return {
text: text,
width: bBox.width,
height: bBox.height,
fontSize: +el.style['font-size'].replace('px', ''),
level: level,
dy: (bBox.top + bBox.bottom) / 2
};
};
exports.findBestTextLocation = function (path, pathBounds, textOpts, labelData, plotBounds) {
var textWidth = textOpts.width;
var p0, dp, pMax, pMin, loc;
if (pathBounds.isClosed) {
dp = pathBounds.len / costConstants.INITIALSEARCHPOINTS;
p0 = pathBounds.min + dp / 2;
pMax = pathBounds.max;
} else {
dp = (pathBounds.len - textWidth) / (costConstants.INITIALSEARCHPOINTS + 1);
p0 = pathBounds.min + dp + textWidth / 2;
pMax = pathBounds.max - (dp + textWidth) / 2;
}
var cost = Infinity;
for (var j = 0; j < costConstants.ITERATIONS; j++) {
for (var p = p0; p < pMax; p += dp) {
var newLocation = Lib.getTextLocation(path, pathBounds.total, p, textWidth);
var newCost = locationCost(newLocation, textOpts, labelData, plotBounds);
if (newCost < cost) {
cost = newCost;
loc = newLocation;
pMin = p;
}
}
if (cost > costConstants.MAXCOST * 2) break;
// subsequent iterations just look half steps away from the
// best we found in the previous iteration
if (j) dp /= 2;
p0 = pMin - dp / 2;
pMax = p0 + dp * 1.5;
}
if (cost <= costConstants.MAXCOST) return loc;
};
/*
* locationCost: a cost function for label locations
* composed of three kinds of penalty:
* - for open paths, being close to the end of the path
* - the angle away from horizontal
* - being too close to already placed neighbors
*/
function locationCost(loc, textOpts, labelData, bounds) {
var halfWidth = textOpts.width / 2;
var halfHeight = textOpts.height / 2;
var x = loc.x;
var y = loc.y;
var theta = loc.theta;
var dx = Math.cos(theta) * halfWidth;
var dy = Math.sin(theta) * halfWidth;
// cost for being near an edge
var normX = (x > bounds.center ? bounds.right - x : x - bounds.left) / (dx + Math.abs(Math.sin(theta) * halfHeight));
var normY = (y > bounds.middle ? bounds.bottom - y : y - bounds.top) / (Math.abs(dy) + Math.cos(theta) * halfHeight);
if (normX < 1 || normY < 1) return Infinity;
var cost = costConstants.EDGECOST * (1 / (normX - 1) + 1 / (normY - 1));
// cost for not being horizontal
cost += costConstants.ANGLECOST * theta * theta;
// cost for being close to other labels
var x1 = x - dx;
var y1 = y - dy;
var x2 = x + dx;
var y2 = y + dy;
for (var i = 0; i < labelData.length; i++) {
var labeli = labelData[i];
var dxd = Math.cos(labeli.theta) * labeli.width / 2;
var dyd = Math.sin(labeli.theta) * labeli.width / 2;
var dist = Lib.segmentDistance(x1, y1, x2, y2, labeli.x - dxd, labeli.y - dyd, labeli.x + dxd, labeli.y + dyd) * 2 / (textOpts.height + labeli.height);
var sameLevel = labeli.level === textOpts.level;
var distOffset = sameLevel ? costConstants.SAMELEVELDISTANCE : 1;
if (dist <= distOffset) return Infinity;
var distFactor = costConstants.NEIGHBORCOST * (sameLevel ? costConstants.SAMELEVELFACTOR : 1);
cost += distFactor / (dist - distOffset);
}
return cost;
}
exports.addLabelData = function (loc, textOpts, labelData, labelClipPathData) {
var fontSize = textOpts.fontSize;
var w = textOpts.width + fontSize / 3;
var h = Math.max(0, textOpts.height - fontSize / 3);
var x = loc.x;
var y = loc.y;
var theta = loc.theta;
var sin = Math.sin(theta);
var cos = Math.cos(theta);
var rotateXY = function (dx, dy) {
return [x + dx * cos - dy * sin, y + dx * sin + dy * cos];
};
var bBoxPts = [rotateXY(-w / 2, -h / 2), rotateXY(-w / 2, h / 2), rotateXY(w / 2, h / 2), rotateXY(w / 2, -h / 2)];
labelData.push({
text: textOpts.text,
x: x,
y: y,
dy: textOpts.dy,
theta: theta,
level: textOpts.level,
width: w,
height: h
});
labelClipPathData.push(bBoxPts);
};
exports.drawLabels = function (labelGroup, labelData, gd, lineClip, labelClipPathData) {
var labels = labelGroup.selectAll('text').data(labelData, function (d) {
return d.text + ',' + d.x + ',' + d.y + ',' + d.theta;
});
labels.exit().remove();
labels.enter().append('text').attr({
'data-notex': 1,
'text-anchor': 'middle'
}).each(function (d) {
var x = d.x + Math.sin(d.theta) * d.dy;
var y = d.y - Math.cos(d.theta) * d.dy;
d3.select(this).text(d.text).attr({
x: x,
y: y,
transform: 'rotate(' + 180 * d.theta / Math.PI + ' ' + x + ' ' + y + ')'
}).call(svgTextUtils.convertToTspans, gd);
});
if (labelClipPathData) {
var clipPath = '';
for (var i = 0; i < labelClipPathData.length; i++) {
clipPath += 'M' + labelClipPathData[i].join('L') + 'Z';
}
var lineClipPath = Lib.ensureSingle(lineClip, 'path', '');
lineClipPath.attr('d', clipPath);
}
};
function clipGaps(plotGroup, plotinfo, gd, cd0, perimeter) {
var trace = cd0.trace;
var clips = gd._fullLayout._clips;
var clipId = 'clip' + trace.uid;
var clipPath = clips.selectAll('#' + clipId).data(trace.connectgaps ? [] : [0]);
clipPath.enter().append('clipPath').classed('contourclip', true).attr('id', clipId);
clipPath.exit().remove();
if (trace.connectgaps === false) {
var clipPathInfo = {
// fraction of the way from missing to present point
// to draw the boundary.
// if you make this 1 (or 1-epsilon) then a point in
// a sea of missing data will disappear entirely.
level: 0.9,
crossings: {},
starts: [],
edgepaths: [],
paths: [],
xaxis: plotinfo.xaxis,
yaxis: plotinfo.yaxis,
x: cd0.x,
y: cd0.y,
// 0 = no data, 1 = data
z: makeClipMask(cd0),
smoothing: 0
};
makeCrossings([clipPathInfo]);
findAllPaths([clipPathInfo]);
closeBoundaries([clipPathInfo], {
type: 'levels'
});
var path = Lib.ensureSingle(clipPath, 'path', '');
path.attr('d', (clipPathInfo.prefixBoundary ? 'M' + perimeter.join('L') + 'Z' : '') + joinAllPaths(clipPathInfo, perimeter));
} else clipId = null;
Drawing.setClipUrl(plotGroup, clipId, gd);
}
function makeClipMask(cd0) {
var empties = cd0.trace._emptypoints;
var z = [];
var m = cd0.z.length;
var n = cd0.z[0].length;
var i;
var row = [];
var emptyPoint;
for (i = 0; i < n; i++) row.push(1);
for (i = 0; i < m; i++) z.push(row.slice());
for (i = 0; i < empties.length; i++) {
emptyPoint = empties[i];
z[emptyPoint[0]][emptyPoint[1]] = 0;
}
// save this mask to determine whether to show this data in hover
cd0.zmask = z;
return z;
}
/***/ }),
/***/ 73416:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var Lib = __webpack_require__(10923);
module.exports = function setContours(trace, vals) {
var contours = trace.contours;
// check if we need to auto-choose contour levels
if (trace.autocontour) {
// N.B. do not try to use coloraxis cmin/cmax,
// these values here are meant to remain "per-trace" for now
var zmin = trace.zmin;
var zmax = trace.zmax;
if (trace.zauto || zmin === undefined) {
zmin = Lib.aggNums(Math.min, null, vals);
}
if (trace.zauto || zmax === undefined) {
zmax = Lib.aggNums(Math.max, null, vals);
}
var dummyAx = autoContours(zmin, zmax, trace.ncontours);
contours.size = dummyAx.dtick;
contours.start = Axes.tickFirst(dummyAx);
dummyAx.range.reverse();
contours.end = Axes.tickFirst(dummyAx);
if (contours.start === zmin) contours.start += contours.size;
if (contours.end === zmax) contours.end -= contours.size;
// if you set a small ncontours, *and* the ends are exactly on zmin/zmax
// there's an edge case where start > end now. Make sure there's at least
// one meaningful contour, put it midway between the crossed values
if (contours.start > contours.end) {
contours.start = contours.end = (contours.start + contours.end) / 2;
}
// copy auto-contour info back to the source data.
// previously we copied the whole contours object back, but that had
// other info (coloring, showlines) that should be left to supplyDefaults
if (!trace._input.contours) trace._input.contours = {};
Lib.extendFlat(trace._input.contours, {
start: contours.start,
end: contours.end,
size: contours.size
});
trace._input.autocontour = true;
} else if (contours.type !== 'constraint') {
// sanity checks on manually-supplied start/end/size
var start = contours.start;
var end = contours.end;
var inputContours = trace._input.contours;
if (start > end) {
contours.start = inputContours.start = end;
end = contours.end = inputContours.end = start;
start = contours.start;
}
if (!(contours.size > 0)) {
var sizeOut;
if (start === end) sizeOut = 1;else sizeOut = autoContours(start, end, trace.ncontours).dtick;
inputContours.size = contours.size = sizeOut;
}
}
};
/*
* autoContours: make a dummy axis object with dtick we can use
* as contours.size, and if needed we can use Axes.tickFirst
* with this axis object to calculate the start and end too
*
* start: the value to start the contours at
* end: the value to end at (must be > start)
* ncontours: max number of contours to make, like roughDTick
*
* returns: an axis object
*/
function autoContours(start, end, ncontours) {
var dummyAx = {
type: 'linear',
range: [start, end]
};
Axes.autoTicks(dummyAx, (end - start) / (ncontours || 15));
return dummyAx;
}
/***/ }),
/***/ 46496:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Drawing = __webpack_require__(49348);
var heatmapStyle = __webpack_require__(47824);
var makeColorMap = __webpack_require__(79464);
module.exports = function style(gd) {
var contours = d3.select(gd).selectAll('g.contour');
contours.style('opacity', function (d) {
return d[0].trace.opacity;
});
contours.each(function (d) {
var c = d3.select(this);
var trace = d[0].trace;
var contours = trace.contours;
var line = trace.line;
var cs = contours.size || 1;
var start = contours.start;
// for contourcarpet only - is this a constraint-type contour trace?
var isConstraintType = contours.type === 'constraint';
var colorLines = !isConstraintType && contours.coloring === 'lines';
var colorFills = !isConstraintType && contours.coloring === 'fill';
var colorMap = colorLines || colorFills ? makeColorMap(trace) : null;
c.selectAll('g.contourlevel').each(function (d) {
d3.select(this).selectAll('path').call(Drawing.lineGroupStyle, line.width, colorLines ? colorMap(d.level) : line.color, line.dash);
});
var labelFont = contours.labelfont;
c.selectAll('g.contourlabels text').each(function (d) {
Drawing.font(d3.select(this), {
family: labelFont.family,
size: labelFont.size,
color: labelFont.color || (colorLines ? colorMap(d.level) : line.color)
});
});
if (isConstraintType) {
c.selectAll('g.contourfill path').style('fill', trace.fillcolor);
} else if (colorFills) {
var firstFill;
c.selectAll('g.contourfill path').style('fill', function (d) {
if (firstFill === undefined) firstFill = d.level;
return colorMap(d.level + 0.5 * cs);
});
if (firstFill === undefined) firstFill = start;
c.selectAll('g.contourbg path').style('fill', colorMap(firstFill - 0.5 * cs));
}
});
heatmapStyle(gd);
};
/***/ }),
/***/ 38936:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorscaleDefaults = __webpack_require__(47280);
var handleLabelDefaults = __webpack_require__(5669);
module.exports = function handleStyleDefaults(traceIn, traceOut, coerce, layout, opts) {
var coloring = coerce('contours.coloring');
var showLines;
var lineColor = '';
if (coloring === 'fill') showLines = coerce('contours.showlines');
if (showLines !== false) {
if (coloring !== 'lines') lineColor = coerce('line.color', '#000');
coerce('line.width', 0.5);
coerce('line.dash');
}
if (coloring !== 'none') {
// plots/plots always coerces showlegend to true, but in this case
// we default to false and (by default) show a colorbar instead
if (traceIn.showlegend !== true) traceOut.showlegend = false;
traceOut._dfltShowLegend = false;
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'z'
});
}
coerce('line.smoothing');
handleLabelDefaults(coerce, layout, lineColor, opts);
};
/***/ }),
/***/ 17264:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var heatmapAttrs = __webpack_require__(7944);
var contourAttrs = __webpack_require__(12115);
var colorScaleAttrs = __webpack_require__(99732);
var extendFlat = (__webpack_require__(55016).extendFlat);
var contourContourAttrs = contourAttrs.contours;
module.exports = extendFlat({
carpet: {
valType: 'string',
editType: 'calc',
description: ['The `carpet` of the carpet axes on which this contour trace lies'].join(' ')
},
z: heatmapAttrs.z,
a: heatmapAttrs.x,
a0: heatmapAttrs.x0,
da: heatmapAttrs.dx,
b: heatmapAttrs.y,
b0: heatmapAttrs.y0,
db: heatmapAttrs.dy,
text: heatmapAttrs.text,
hovertext: heatmapAttrs.hovertext,
transpose: heatmapAttrs.transpose,
atype: heatmapAttrs.xtype,
btype: heatmapAttrs.ytype,
fillcolor: contourAttrs.fillcolor,
autocontour: contourAttrs.autocontour,
ncontours: contourAttrs.ncontours,
contours: {
type: contourContourAttrs.type,
start: contourContourAttrs.start,
end: contourContourAttrs.end,
size: contourContourAttrs.size,
coloring: {
// from contourAttrs.contours.coloring but no 'heatmap' option
valType: 'enumerated',
values: ['fill', 'lines', 'none'],
dflt: 'fill',
editType: 'calc',
description: ['Determines the coloring method showing the contour values.', 'If *fill*, coloring is done evenly between each contour level', 'If *lines*, coloring is done on the contour lines.', 'If *none*, no coloring is applied on this trace.'].join(' ')
},
showlines: contourContourAttrs.showlines,
showlabels: contourContourAttrs.showlabels,
labelfont: contourContourAttrs.labelfont,
labelformat: contourContourAttrs.labelformat,
operation: contourContourAttrs.operation,
value: contourContourAttrs.value,
editType: 'calc',
impliedEdits: {
autocontour: false
}
},
line: {
color: contourAttrs.line.color,
width: contourAttrs.line.width,
dash: contourAttrs.line.dash,
smoothing: contourAttrs.line.smoothing,
editType: 'plot'
},
zorder: contourAttrs.zorder,
transforms: undefined
}, colorScaleAttrs('', {
cLetter: 'z',
autoColorDflt: false
}));
/***/ }),
/***/ 81100:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorscaleCalc = __webpack_require__(60416);
var Lib = __webpack_require__(10923);
var convertColumnData = __webpack_require__(26848);
var clean2dArray = __webpack_require__(20736);
var interp2d = __webpack_require__(5912);
var findEmpties = __webpack_require__(4648);
var makeBoundArray = __webpack_require__(69672);
var supplyDefaults = __webpack_require__(7016);
var lookupCarpet = __webpack_require__(62952);
var setContours = __webpack_require__(73416);
// most is the same as heatmap calc, then adjust it
// though a few things inside heatmap calc still look for
// contour maps, because the makeBoundArray calls are too entangled
module.exports = function calc(gd, trace) {
var carpet = trace._carpetTrace = lookupCarpet(gd, trace);
if (!carpet || !carpet.visible || carpet.visible === 'legendonly') return;
if (!trace.a || !trace.b) {
// Look up the original incoming carpet data:
var carpetdata = gd.data[carpet.index];
// Look up the incoming trace data, *except* perform a shallow
// copy so that we're not actually modifying it when we use it
// to supply defaults:
var tracedata = gd.data[trace.index];
// var tracedata = extendFlat({}, gd.data[trace.index]);
// If the data is not specified
if (!tracedata.a) tracedata.a = carpetdata.a;
if (!tracedata.b) tracedata.b = carpetdata.b;
supplyDefaults(tracedata, trace, trace._defaultColor, gd._fullLayout);
}
var cd = heatmappishCalc(gd, trace);
setContours(trace, trace._z);
return cd;
};
function heatmappishCalc(gd, trace) {
// prepare the raw data
// run makeCalcdata on x and y even for heatmaps, in case of category mappings
var carpet = trace._carpetTrace;
var aax = carpet.aaxis;
var bax = carpet.baxis;
var a, a0, da, b, b0, db, z;
// cancel minimum tick spacings (only applies to bars and boxes)
aax._minDtick = 0;
bax._minDtick = 0;
if (Lib.isArray1D(trace.z)) convertColumnData(trace, aax, bax, 'a', 'b', ['z']);
a = trace._a = trace._a || trace.a;
b = trace._b = trace._b || trace.b;
a = a ? aax.makeCalcdata(trace, '_a') : [];
b = b ? bax.makeCalcdata(trace, '_b') : [];
a0 = trace.a0 || 0;
da = trace.da || 1;
b0 = trace.b0 || 0;
db = trace.db || 1;
z = trace._z = clean2dArray(trace._z || trace.z, trace.transpose);
trace._emptypoints = findEmpties(z);
interp2d(z, trace._emptypoints);
// create arrays of brick boundaries, to be used by autorange and heatmap.plot
var xlen = Lib.maxRowLength(z);
var xIn = trace.xtype === 'scaled' ? '' : a;
var xArray = makeBoundArray(trace, xIn, a0, da, xlen, aax);
var yIn = trace.ytype === 'scaled' ? '' : b;
var yArray = makeBoundArray(trace, yIn, b0, db, z.length, bax);
var cd0 = {
a: xArray,
b: yArray,
z: z
};
if (trace.contours.type === 'levels' && trace.contours.coloring !== 'none') {
// auto-z and autocolorscale if applicable
colorscaleCalc(gd, trace, {
vals: z,
containerStr: '',
cLetter: 'z'
});
}
return [cd0];
}
/***/ }),
/***/ 7016:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleXYZDefaults = __webpack_require__(53024);
var attributes = __webpack_require__(17264);
var handleConstraintDefaults = __webpack_require__(80464);
var handleContoursDefaults = __webpack_require__(5032);
var handleStyleDefaults = __webpack_require__(38936);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
function coerce2(attr) {
return Lib.coerce2(traceIn, traceOut, attributes, attr);
}
coerce('carpet');
// If either a or b is not present, then it's not a valid trace *unless* the carpet
// axis has the a or b values we're looking for. So if these are not found, just defer
// that decision until the calc step.
//
// NB: the calc step will modify the original data input by assigning whichever of
// a or b are missing. This is necessary because panning goes right from supplyDefaults
// to plot (skipping calc). That means on subsequent updates, this *will* need to be
// able to find a and b.
//
// The long-term proper fix is that this should perhaps use underscored attributes to
// at least modify the user input to a slightly lesser extent. Fully removing the
// input mutation is challenging. The underscore approach is not currently taken since
// it requires modification to all of the functions below that expect the coerced
// attribute name to match the property name -- except '_a' !== 'a' so that is not
// straightforward.
if (traceIn.a && traceIn.b) {
var len = handleXYZDefaults(traceIn, traceOut, coerce, layout, 'a', 'b');
if (!len) {
traceOut.visible = false;
return;
}
coerce('text');
var isConstraint = coerce('contours.type') === 'constraint';
if (isConstraint) {
handleConstraintDefaults(traceIn, traceOut, coerce, layout, defaultColor, {
hasHover: false
});
} else {
handleContoursDefaults(traceIn, traceOut, coerce, coerce2);
handleStyleDefaults(traceIn, traceOut, coerce, layout, {
hasHover: false
});
}
} else {
traceOut._defaultColor = defaultColor;
traceOut._length = null;
}
coerce('zorder');
};
/***/ }),
/***/ 41572:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(17264),
supplyDefaults: __webpack_require__(7016),
colorbar: __webpack_require__(50128),
calc: __webpack_require__(81100),
plot: __webpack_require__(27452),
style: __webpack_require__(46496),
moduleType: 'trace',
name: 'contourcarpet',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', 'carpet', 'contour', 'symbols', 'showLegend', 'hasLines', 'carpetDependent', 'noHover', 'noSortingByValue'],
meta: {
hrName: 'contour_carpet',
description: ['Plots contours on either the first carpet axis or the', 'carpet axis with a matching `carpet` attribute. Data `z`', 'is interpreted as matching that of the corresponding carpet', 'axis.'].join(' ')
}
};
/***/ }),
/***/ 27452:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var map1dArray = __webpack_require__(25492);
var makepath = __webpack_require__(1280);
var Drawing = __webpack_require__(49348);
var Lib = __webpack_require__(10923);
var makeCrossings = __webpack_require__(81672);
var findAllPaths = __webpack_require__(16349);
var contourPlot = __webpack_require__(7344);
var constants = __webpack_require__(60512);
var convertToConstraints = __webpack_require__(15651);
var emptyPathinfo = __webpack_require__(67356);
var closeBoundaries = __webpack_require__(82608);
var lookupCarpet = __webpack_require__(62952);
var axisAlignedLine = __webpack_require__(62240);
module.exports = function plot(gd, plotinfo, cdcontours, contourcarpetLayer) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
Lib.makeTraceGroups(contourcarpetLayer, cdcontours, 'contour').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
var carpet = trace._carpetTrace = lookupCarpet(gd, trace);
var carpetcd = gd.calcdata[carpet.index][0];
if (!carpet.visible || carpet.visible === 'legendonly') return;
var a = cd0.a;
var b = cd0.b;
var contours = trace.contours;
var pathinfo = emptyPathinfo(contours, plotinfo, cd0);
var isConstraint = contours.type === 'constraint';
var operation = contours._operation;
var coloring = isConstraint ? operation === '=' ? 'lines' : 'fill' : contours.coloring;
// Map [a, b] (data) --> [i, j] (pixels)
function ab2p(ab) {
var pt = carpet.ab2xy(ab[0], ab[1], true);
return [xa.c2p(pt[0]), ya.c2p(pt[1])];
}
// Define the perimeter in a/b coordinates:
var perimeter = [[a[0], b[b.length - 1]], [a[a.length - 1], b[b.length - 1]], [a[a.length - 1], b[0]], [a[0], b[0]]];
// Extract the contour levels:
makeCrossings(pathinfo);
var atol = (a[a.length - 1] - a[0]) * 1e-8;
var btol = (b[b.length - 1] - b[0]) * 1e-8;
findAllPaths(pathinfo, atol, btol);
// Constraints might need to be draw inverted, which is not something contours
// handle by default since they're assumed fully opaque so that they can be
// drawn overlapping. This function flips the paths as necessary so that they're
// drawn correctly.
//
// TODO: Perhaps this should be generalized and *all* paths should be drawn as
// closed regions so that translucent contour levels would be valid.
// See: https://github.com/plotly/plotly.js/issues/1356
var fillPathinfo = pathinfo;
if (contours.type === 'constraint') {
fillPathinfo = convertToConstraints(pathinfo, operation);
}
// Map the paths in a/b coordinates to pixel coordinates:
mapPathinfo(pathinfo, ab2p);
// draw everything
// Compute the boundary path
var seg, xp, yp, i;
var segs = [];
for (i = carpetcd.clipsegments.length - 1; i >= 0; i--) {
seg = carpetcd.clipsegments[i];
xp = map1dArray([], seg.x, xa.c2p);
yp = map1dArray([], seg.y, ya.c2p);
xp.reverse();
yp.reverse();
segs.push(makepath(xp, yp, seg.bicubic));
}
var boundaryPath = 'M' + segs.join('L') + 'Z';
// Draw the baseline background fill that fills in the space behind any other
// contour levels:
makeBackground(plotGroup, carpetcd.clipsegments, xa, ya, isConstraint, coloring);
// Draw the specific contour fills. As a simplification, they're assumed to be
// fully opaque so that it's easy to draw them simply overlapping. The alternative
// would be to flip adjacent paths and draw closed paths for each level instead.
makeFills(trace, plotGroup, xa, ya, fillPathinfo, perimeter, ab2p, carpet, carpetcd, coloring, boundaryPath);
// Draw contour lines:
makeLinesAndLabels(plotGroup, pathinfo, gd, cd0, contours, plotinfo, carpet);
// Clip the boundary of the plot
Drawing.setClipUrl(plotGroup, carpet._clipPathId, gd);
});
};
function mapPathinfo(pathinfo, map) {
var i, j, k, pi, pedgepaths, ppaths, pedgepath, ppath, path;
for (i = 0; i < pathinfo.length; i++) {
pi = pathinfo[i];
pedgepaths = pi.pedgepaths = [];
ppaths = pi.ppaths = [];
for (j = 0; j < pi.edgepaths.length; j++) {
path = pi.edgepaths[j];
pedgepath = [];
for (k = 0; k < path.length; k++) {
pedgepath[k] = map(path[k]);
}
pedgepaths.push(pedgepath);
}
for (j = 0; j < pi.paths.length; j++) {
path = pi.paths[j];
ppath = [];
for (k = 0; k < path.length; k++) {
ppath[k] = map(path[k]);
}
ppaths.push(ppath);
}
}
}
function makeLinesAndLabels(plotgroup, pathinfo, gd, cd0, contours, plotinfo, carpet) {
var isStatic = gd._context.staticPlot;
var lineContainer = Lib.ensureSingle(plotgroup, 'g', 'contourlines');
var showLines = contours.showlines !== false;
var showLabels = contours.showlabels;
var clipLinesForLabels = showLines && showLabels;
// Even if we're not going to show lines, we need to create them
// if we're showing labels, because the fill paths include the perimeter
// so can't be used to position the labels correctly.
// In this case we'll remove the lines after making the labels.
var linegroup = contourPlot.createLines(lineContainer, showLines || showLabels, pathinfo, isStatic);
var lineClip = contourPlot.createLineClip(lineContainer, clipLinesForLabels, gd, cd0.trace.uid);
var labelGroup = plotgroup.selectAll('g.contourlabels').data(showLabels ? [0] : []);
labelGroup.exit().remove();
labelGroup.enter().append('g').classed('contourlabels', true);
if (showLabels) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var xLen = xa._length;
var yLen = ya._length;
// for simplicity use the xy box for label clipping outline.
var labelClipPathData = [[[0, 0], [xLen, 0], [xLen, yLen], [0, yLen]]];
var labelData = [];
// invalidate the getTextLocation cache in case paths changed
Lib.clearLocationCache();
var contourFormat = contourPlot.labelFormatter(gd, cd0);
var dummyText = Drawing.tester.append('text').attr('data-notex', 1).call(Drawing.font, contours.labelfont);
// use `bounds` only to keep labels away from the x/y boundaries
// `constrainToCarpet` below ensures labels don't go off the
// carpet edges
var bounds = {
left: 0,
right: xLen,
center: xLen / 2,
top: 0,
bottom: yLen,
middle: yLen / 2
};
var plotDiagonal = Math.sqrt(xLen * xLen + yLen * yLen);
// the path length to use to scale the number of labels to draw:
var normLength = constants.LABELDISTANCE * plotDiagonal / Math.max(1, pathinfo.length / constants.LABELINCREASE);
linegroup.each(function (d) {
var textOpts = contourPlot.calcTextOpts(d.level, contourFormat, dummyText, gd);
d3.select(this).selectAll('path').each(function (pathData) {
var path = this;
var pathBounds = Lib.getVisibleSegment(path, bounds, textOpts.height / 2);
if (!pathBounds) return;
constrainToCarpet(path, pathData, d, pathBounds, carpet, textOpts.height);
if (pathBounds.len < (textOpts.width + textOpts.height) * constants.LABELMIN) return;
var maxLabels = Math.min(Math.ceil(pathBounds.len / normLength), constants.LABELMAX);
for (var i = 0; i < maxLabels; i++) {
var loc = contourPlot.findBestTextLocation(path, pathBounds, textOpts, labelData, bounds);
if (!loc) break;
contourPlot.addLabelData(loc, textOpts, labelData, labelClipPathData);
}
});
});
dummyText.remove();
contourPlot.drawLabels(labelGroup, labelData, gd, lineClip, clipLinesForLabels ? labelClipPathData : null);
}
if (showLabels && !showLines) linegroup.remove();
}
// figure out if this path goes off the edge of the carpet
// and shorten the part we call visible to keep labels away from the edge
function constrainToCarpet(path, pathData, levelData, pathBounds, carpet, textHeight) {
var pathABData;
for (var i = 0; i < levelData.pedgepaths.length; i++) {
if (pathData === levelData.pedgepaths[i]) {
pathABData = levelData.edgepaths[i];
}
}
if (!pathABData) return;
var aMin = carpet.a[0];
var aMax = carpet.a[carpet.a.length - 1];
var bMin = carpet.b[0];
var bMax = carpet.b[carpet.b.length - 1];
function getOffset(abPt, pathVector) {
var offset = 0;
var edgeVector;
var dAB = 0.1;
if (Math.abs(abPt[0] - aMin) < dAB || Math.abs(abPt[0] - aMax) < dAB) {
edgeVector = normalizeVector(carpet.dxydb_rough(abPt[0], abPt[1], dAB));
offset = Math.max(offset, textHeight * vectorTan(pathVector, edgeVector) / 2);
}
if (Math.abs(abPt[1] - bMin) < dAB || Math.abs(abPt[1] - bMax) < dAB) {
edgeVector = normalizeVector(carpet.dxyda_rough(abPt[0], abPt[1], dAB));
offset = Math.max(offset, textHeight * vectorTan(pathVector, edgeVector) / 2);
}
return offset;
}
var startVector = getUnitVector(path, 0, 1);
var endVector = getUnitVector(path, pathBounds.total, pathBounds.total - 1);
var minStart = getOffset(pathABData[0], startVector);
var maxEnd = pathBounds.total - getOffset(pathABData[pathABData.length - 1], endVector);
if (pathBounds.min < minStart) pathBounds.min = minStart;
if (pathBounds.max > maxEnd) pathBounds.max = maxEnd;
pathBounds.len = pathBounds.max - pathBounds.min;
}
function getUnitVector(path, p0, p1) {
var pt0 = path.getPointAtLength(p0);
var pt1 = path.getPointAtLength(p1);
var dx = pt1.x - pt0.x;
var dy = pt1.y - pt0.y;
var len = Math.sqrt(dx * dx + dy * dy);
return [dx / len, dy / len];
}
function normalizeVector(v) {
var len = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
return [v[0] / len, v[1] / len];
}
function vectorTan(v0, v1) {
var cos = Math.abs(v0[0] * v1[0] + v0[1] * v1[1]);
var sin = Math.sqrt(1 - cos * cos);
return sin / cos;
}
function makeBackground(plotgroup, clipsegments, xaxis, yaxis, isConstraint, coloring) {
var seg, xp, yp, i;
var bggroup = Lib.ensureSingle(plotgroup, 'g', 'contourbg');
var bgfill = bggroup.selectAll('path').data(coloring === 'fill' && !isConstraint ? [0] : []);
bgfill.enter().append('path');
bgfill.exit().remove();
var segs = [];
for (i = 0; i < clipsegments.length; i++) {
seg = clipsegments[i];
xp = map1dArray([], seg.x, xaxis.c2p);
yp = map1dArray([], seg.y, yaxis.c2p);
segs.push(makepath(xp, yp, seg.bicubic));
}
bgfill.attr('d', 'M' + segs.join('L') + 'Z').style('stroke', 'none');
}
function makeFills(trace, plotgroup, xa, ya, pathinfo, perimeter, ab2p, carpet, carpetcd, coloring, boundaryPath) {
var hasFills = coloring === 'fill';
// fills prefixBoundary in pathinfo items
if (hasFills) {
closeBoundaries(pathinfo, trace.contours);
}
var fillgroup = Lib.ensureSingle(plotgroup, 'g', 'contourfill');
var fillitems = fillgroup.selectAll('path').data(hasFills ? pathinfo : []);
fillitems.enter().append('path');
fillitems.exit().remove();
fillitems.each(function (pi) {
// join all paths for this level together into a single path
// first follow clockwise around the perimeter to close any open paths
// if the whole perimeter is above this level, start with a path
// enclosing the whole thing. With all that, the parity should mean
// that we always fill everything above the contour, nothing below
var fullpath = (pi.prefixBoundary ? boundaryPath : '') + joinAllPaths(trace, pi, perimeter, ab2p, carpet, carpetcd, xa, ya);
if (!fullpath) {
d3.select(this).remove();
} else {
d3.select(this).attr('d', fullpath).style('stroke', 'none');
}
});
}
function joinAllPaths(trace, pi, perimeter, ab2p, carpet, carpetcd, xa, ya) {
var i;
var fullpath = '';
var startsleft = pi.edgepaths.map(function (v, i) {
return i;
});
var newloop = true;
var endpt, newendpt, cnt, nexti, possiblei, addpath;
var atol = Math.abs(perimeter[0][0] - perimeter[2][0]) * 1e-4;
var btol = Math.abs(perimeter[0][1] - perimeter[2][1]) * 1e-4;
function istop(pt) {
return Math.abs(pt[1] - perimeter[0][1]) < btol;
}
function isbottom(pt) {
return Math.abs(pt[1] - perimeter[2][1]) < btol;
}
function isleft(pt) {
return Math.abs(pt[0] - perimeter[0][0]) < atol;
}
function isright(pt) {
return Math.abs(pt[0] - perimeter[2][0]) < atol;
}
function pathto(pt0, pt1) {
var i, j, segments, axis;
var path = '';
if (istop(pt0) && !isright(pt0) || isbottom(pt0) && !isleft(pt0)) {
axis = carpet.aaxis;
segments = axisAlignedLine(carpet, carpetcd, [pt0[0], pt1[0]], 0.5 * (pt0[1] + pt1[1]));
} else {
axis = carpet.baxis;
segments = axisAlignedLine(carpet, carpetcd, 0.5 * (pt0[0] + pt1[0]), [pt0[1], pt1[1]]);
}
for (i = 1; i < segments.length; i++) {
path += axis.smoothing ? 'C' : 'L';
for (j = 0; j < segments[i].length; j++) {
var pt = segments[i][j];
path += [xa.c2p(pt[0]), ya.c2p(pt[1])] + ' ';
}
}
return path;
}
i = 0;
endpt = null;
while (startsleft.length) {
var startpt = pi.edgepaths[i][0];
if (endpt) {
fullpath += pathto(endpt, startpt);
}
addpath = Drawing.smoothopen(pi.edgepaths[i].map(ab2p), pi.smoothing);
fullpath += newloop ? addpath : addpath.replace(/^M/, 'L');
startsleft.splice(startsleft.indexOf(i), 1);
endpt = pi.edgepaths[i][pi.edgepaths[i].length - 1];
nexti = -1;
// now loop through sides, moving our endpoint until we find a new start
for (cnt = 0; cnt < 4; cnt++) {
// just to prevent infinite loops
if (!endpt) {
Lib.log('Missing end?', i, pi);
break;
}
if (istop(endpt) && !isright(endpt)) {
newendpt = perimeter[1]; // left top ---> right top
} else if (isleft(endpt)) {
newendpt = perimeter[0]; // left bottom ---> left top
} else if (isbottom(endpt)) {
newendpt = perimeter[3]; // right bottom
} else if (isright(endpt)) {
newendpt = perimeter[2]; // left bottom
}
for (possiblei = 0; possiblei < pi.edgepaths.length; possiblei++) {
var ptNew = pi.edgepaths[possiblei][0];
// is ptNew on the (horz. or vert.) segment from endpt to newendpt?
if (Math.abs(endpt[0] - newendpt[0]) < atol) {
if (Math.abs(endpt[0] - ptNew[0]) < atol && (ptNew[1] - endpt[1]) * (newendpt[1] - ptNew[1]) >= 0) {
newendpt = ptNew;
nexti = possiblei;
}
} else if (Math.abs(endpt[1] - newendpt[1]) < btol) {
if (Math.abs(endpt[1] - ptNew[1]) < btol && (ptNew[0] - endpt[0]) * (newendpt[0] - ptNew[0]) >= 0) {
newendpt = ptNew;
nexti = possiblei;
}
} else {
Lib.log('endpt to newendpt is not vert. or horz.', endpt, newendpt, ptNew);
}
}
if (nexti >= 0) break;
fullpath += pathto(endpt, newendpt);
endpt = newendpt;
}
if (nexti === pi.edgepaths.length) {
Lib.log('unclosed perimeter path');
break;
}
i = nexti;
// if we closed back on a loop we already included,
// close it and start a new loop
newloop = startsleft.indexOf(i) === -1;
if (newloop) {
i = startsleft[0];
fullpath += pathto(endpt, newendpt) + 'Z';
endpt = null;
}
}
// finally add the interior paths
for (i = 0; i < pi.paths.length; i++) {
fullpath += Drawing.smoothclosed(pi.paths[i].map(ab2p), pi.smoothing);
}
return fullpath;
}
/***/ }),
/***/ 41268:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorScaleAttrs = __webpack_require__(99732);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var baseAttrs = __webpack_require__(6040);
var scatterMapboxAttrs = __webpack_require__(91940);
var extendFlat = (__webpack_require__(55016).extendFlat);
/*
* - https://docs.mapbox.com/help/tutorials/make-a-heatmap-with-mapbox-gl-js/
* - https://docs.mapbox.com/mapbox-gl-js/example/heatmap-layer/
* - https://docs.mapbox.com/mapbox-gl-js/style-spec/#layers-heatmap
* - https://blog.mapbox.com/introducing-heatmaps-in-mapbox-gl-js-71355ada9e6c
*
* Gotchas:
* - https://github.com/mapbox/mapbox-gl-js/issues/6463
* - https://github.com/mapbox/mapbox-gl-js/issues/6112
*/
/*
*
* In mathematical terms, Mapbox GL heatmaps are a bivariate (2D) kernel density
* estimation with a Gaussian kernel. It means that each data point has an area
* of “influence” around it (called a kernel) where the numerical value of
* influence (which we call density) decreases as you go further from the point.
* If we sum density values of all points in every pixel of the screen, we get a
* combined density value which we then map to a heatmap color.
*
*/
module.exports = extendFlat({
lon: scatterMapboxAttrs.lon,
lat: scatterMapboxAttrs.lat,
z: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the points\' weight.', 'For example, a value of 10 would be equivalent to having 10 points of weight 1', 'in the same spot'].join(' ')
},
radius: {
valType: 'number',
editType: 'plot',
arrayOk: true,
min: 1,
dflt: 30,
description: ['Sets the radius of influence of one `lon` / `lat` point in pixels.', 'Increasing the value makes the densitymapbox trace smoother, but less detailed.'].join(' ')
},
below: {
valType: 'string',
editType: 'plot',
description: ['Determines if the densitymapbox trace will be inserted', 'before the layer with the specified ID.', 'By default, densitymapbox traces are placed below the first', 'layer of type symbol', 'If set to \'\',', 'the layer will be inserted above every existing layer.'].join(' ')
},
text: scatterMapboxAttrs.text,
hovertext: scatterMapboxAttrs.hovertext,
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['lon', 'lat', 'z', 'text', 'name']
}),
hovertemplate: hovertemplateAttrs(),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
}, colorScaleAttrs('', {
cLetter: 'z',
editTypeOverride: 'calc'
}));
/***/ }),
/***/ 50371:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var BADNUM = (__webpack_require__(41752).BADNUM);
var colorscaleCalc = __webpack_require__(60416);
var _ = (__webpack_require__(10923)._);
module.exports = function calc(gd, trace) {
var len = trace._length;
var calcTrace = new Array(len);
var z = trace.z;
var hasZ = isArrayOrTypedArray(z) && z.length;
for (var i = 0; i < len; i++) {
var cdi = calcTrace[i] = {};
var lon = trace.lon[i];
var lat = trace.lat[i];
cdi.lonlat = isNumeric(lon) && isNumeric(lat) ? [+lon, +lat] : [BADNUM, BADNUM];
if (hasZ) {
var zi = z[i];
cdi.z = isNumeric(zi) ? zi : BADNUM;
}
}
colorscaleCalc(gd, trace, {
vals: hasZ ? z : [0, 1],
containerStr: '',
cLetter: 'z'
});
if (len) {
calcTrace[0].t = {
labels: {
lat: _(gd, 'lat:') + ' ',
lon: _(gd, 'lon:') + ' '
}
};
}
return calcTrace;
};
/***/ }),
/***/ 65368:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var Color = __webpack_require__(9240);
var Colorscale = __webpack_require__(26733);
var BADNUM = (__webpack_require__(41752).BADNUM);
var makeBlank = (__webpack_require__(23308).makeBlank);
module.exports = function convert(calcTrace) {
var trace = calcTrace[0].trace;
var isVisible = trace.visible === true && trace._length !== 0;
var heatmap = {
layout: {
visibility: 'none'
},
paint: {}
};
var opts = trace._opts = {
heatmap: heatmap,
geojson: makeBlank()
};
// early return if not visible or placeholder
if (!isVisible) return opts;
var features = [];
var i;
var z = trace.z;
var radius = trace.radius;
var hasZ = Lib.isArrayOrTypedArray(z) && z.length;
var hasArrayRadius = Lib.isArrayOrTypedArray(radius);
for (i = 0; i < calcTrace.length; i++) {
var cdi = calcTrace[i];
var lonlat = cdi.lonlat;
if (lonlat[0] !== BADNUM) {
var props = {};
if (hasZ) {
var zi = cdi.z;
props.z = zi !== BADNUM ? zi : 0;
}
if (hasArrayRadius) {
props.r = isNumeric(radius[i]) && radius[i] > 0 ? +radius[i] : 0;
}
features.push({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: lonlat
},
properties: props
});
}
}
var cOpts = Colorscale.extractOpts(trace);
var scl = cOpts.reversescale ? Colorscale.flipScale(cOpts.colorscale) : cOpts.colorscale;
// Add alpha channel to first colorscale step.
// If not, we would essentially color the entire map.
// See https://docs.mapbox.com/mapbox-gl-js/example/heatmap-layer/
var scl01 = scl[0][1];
var color0 = Color.opacity(scl01) < 1 ? scl01 : Color.addOpacity(scl01, 0);
var heatmapColor = ['interpolate', ['linear'], ['heatmap-density'], 0, color0];
for (i = 1; i < scl.length; i++) {
heatmapColor.push(scl[i][0], scl[i][1]);
}
// Those "weights" have to be in [0, 1], we can do this either:
// - as here using a mapbox-gl expression
// - or, scale the 'z' property in the feature loop
var zExp = ['interpolate', ['linear'], ['get', 'z'], cOpts.min, 0, cOpts.max, 1];
Lib.extendFlat(opts.heatmap.paint, {
'heatmap-weight': hasZ ? zExp : 1 / (cOpts.max - cOpts.min),
'heatmap-color': heatmapColor,
'heatmap-radius': hasArrayRadius ? {
type: 'identity',
property: 'r'
} : trace.radius,
'heatmap-opacity': trace.opacity
});
opts.geojson = {
type: 'FeatureCollection',
features: features
};
opts.heatmap.layout.visibility = 'visible';
return opts;
};
/***/ }),
/***/ 17920:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(41268);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var lon = coerce('lon') || [];
var lat = coerce('lat') || [];
var len = Math.min(lon.length, lat.length);
if (!len) {
traceOut.visible = false;
return;
}
traceOut._length = len;
coerce('z');
coerce('radius');
coerce('below');
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'z'
});
};
/***/ }),
/***/ 80052:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt) {
out.lon = pt.lon;
out.lat = pt.lat;
out.z = pt.z;
return out;
};
/***/ }),
/***/ 84080:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var scatterMapboxHoverPoints = (__webpack_require__(55348).hoverPoints);
var getExtraText = (__webpack_require__(55348).getExtraText);
module.exports = function hoverPoints(pointData, xval, yval) {
var pts = scatterMapboxHoverPoints(pointData, xval, yval);
if (!pts) return;
var newPointData = pts[0];
var cd = newPointData.cd;
var trace = cd[0].trace;
var di = cd[newPointData.index];
// let Fx.hover pick the color
delete newPointData.color;
if ('z' in di) {
var ax = newPointData.subplot.mockAxis;
newPointData.z = di.z;
newPointData.zLabel = Axes.tickText(ax, ax.c2l(di.z), 'hover').text;
}
newPointData.extraText = getExtraText(trace, di, cd[0].t.labels);
return [newPointData];
};
/***/ }),
/***/ 92668:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(41268),
supplyDefaults: __webpack_require__(17920),
colorbar: __webpack_require__(72680),
formatLabels: __webpack_require__(43300),
calc: __webpack_require__(50371),
plot: __webpack_require__(82576),
hoverPoints: __webpack_require__(84080),
eventData: __webpack_require__(80052),
getBelow: function (trace, subplot) {
var mapLayers = subplot.getMapLayers();
// find first layer with `type: 'symbol'`,
// that is not a plotly layer
for (var i = 0; i < mapLayers.length; i++) {
var layer = mapLayers[i];
var layerId = layer.id;
if (layer.type === 'symbol' && typeof layerId === 'string' && layerId.indexOf('plotly-') === -1) {
return layerId;
}
}
},
moduleType: 'trace',
name: 'densitymapbox',
basePlotModule: __webpack_require__(90419),
categories: ['mapbox', 'gl', 'showLegend'],
meta: {
hr_name: 'density_mapbox',
description: ['Draws a bivariate kernel density estimation with a Gaussian kernel', 'from `lon` and `lat` coordinates and optional `z` values using a colorscale.'].join(' ')
}
};
/***/ }),
/***/ 82576:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var convert = __webpack_require__(65368);
var LAYER_PREFIX = (__webpack_require__(11376).traceLayerPrefix);
function DensityMapbox(subplot, uid) {
this.type = 'densitymapbox';
this.subplot = subplot;
this.uid = uid;
this.sourceId = 'source-' + uid;
this.layerList = [['heatmap', LAYER_PREFIX + uid + '-heatmap']];
// previous 'below' value,
// need this to update it properly
this.below = null;
}
var proto = DensityMapbox.prototype;
proto.update = function (calcTrace) {
var subplot = this.subplot;
var layerList = this.layerList;
var optsAll = convert(calcTrace);
var below = subplot.belowLookup['trace-' + this.uid];
subplot.map.getSource(this.sourceId).setData(optsAll.geojson);
if (below !== this.below) {
this._removeLayers();
this._addLayers(optsAll, below);
this.below = below;
}
for (var i = 0; i < layerList.length; i++) {
var item = layerList[i];
var k = item[0];
var id = item[1];
var opts = optsAll[k];
subplot.setOptions(id, 'setLayoutProperty', opts.layout);
if (opts.layout.visibility === 'visible') {
subplot.setOptions(id, 'setPaintProperty', opts.paint);
}
}
};
proto._addLayers = function (optsAll, below) {
var subplot = this.subplot;
var layerList = this.layerList;
var sourceId = this.sourceId;
for (var i = 0; i < layerList.length; i++) {
var item = layerList[i];
var k = item[0];
var opts = optsAll[k];
subplot.addLayer({
type: k,
id: item[1],
source: sourceId,
layout: opts.layout,
paint: opts.paint
}, below);
}
};
proto._removeLayers = function () {
var map = this.subplot.map;
var layerList = this.layerList;
for (var i = layerList.length - 1; i >= 0; i--) {
map.removeLayer(layerList[i][1]);
}
};
proto.dispose = function () {
var map = this.subplot.map;
this._removeLayers();
map.removeSource(this.sourceId);
};
module.exports = function createDensityMapbox(subplot, calcTrace) {
var trace = calcTrace[0].trace;
var densityMapbox = new DensityMapbox(subplot, trace.uid);
var sourceId = densityMapbox.sourceId;
var optsAll = convert(calcTrace);
var below = densityMapbox.below = subplot.belowLookup['trace-' + trace.uid];
subplot.map.addSource(sourceId, {
type: 'geojson',
data: optsAll.geojson
});
densityMapbox._addLayers(optsAll, below);
return densityMapbox;
};
/***/ }),
/***/ 73656:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
// arrayOk attributes, merge them into calcdata array
module.exports = function arraysToCalcdata(cd, trace) {
for (var i = 0; i < cd.length; i++) cd[i].i = i;
Lib.mergeArray(trace.text, cd, 'tx');
Lib.mergeArray(trace.hovertext, cd, 'htx');
var marker = trace.marker;
if (marker) {
Lib.mergeArray(marker.opacity, cd, 'mo');
Lib.mergeArray(marker.color, cd, 'mc');
var markerLine = marker.line;
if (markerLine) {
Lib.mergeArray(markerLine.color, cd, 'mlc');
Lib.mergeArrayCastPositive(markerLine.width, cd, 'mlw');
}
}
};
/***/ }),
/***/ 91628:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var barAttrs = __webpack_require__(39788);
var lineAttrs = (__webpack_require__(49992).line);
var baseAttrs = __webpack_require__(6040);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var constants = __webpack_require__(90648);
var extendFlat = (__webpack_require__(55016).extendFlat);
var Color = __webpack_require__(9240);
module.exports = {
x: barAttrs.x,
x0: barAttrs.x0,
dx: barAttrs.dx,
y: barAttrs.y,
y0: barAttrs.y0,
dy: barAttrs.dy,
xperiod: barAttrs.xperiod,
yperiod: barAttrs.yperiod,
xperiod0: barAttrs.xperiod0,
yperiod0: barAttrs.yperiod0,
xperiodalignment: barAttrs.xperiodalignment,
yperiodalignment: barAttrs.yperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
hovertext: barAttrs.hovertext,
hovertemplate: hovertemplateAttrs({}, {
keys: constants.eventDataKeys
}),
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['name', 'x', 'y', 'text', 'percent initial', 'percent previous', 'percent total']
}),
textinfo: {
valType: 'flaglist',
flags: ['label', 'text', 'percent initial', 'percent previous', 'percent total', 'value'],
extras: ['none'],
editType: 'plot',
arrayOk: false,
description: ['Determines which trace information appear on the graph.', 'In the case of having multiple funnels, percentages & totals', 'are computed separately (per trace).'].join(' ')
},
// TODO: incorporate `label` and `value` in the eventData
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: constants.eventDataKeys.concat(['label', 'value'])
}),
text: barAttrs.text,
textposition: barAttrs.textposition,
insidetextanchor: extendFlat({}, barAttrs.insidetextanchor, {
dflt: 'middle'
}),
textangle: extendFlat({}, barAttrs.textangle, {
dflt: 0
}),
textfont: barAttrs.textfont,
insidetextfont: barAttrs.insidetextfont,
outsidetextfont: barAttrs.outsidetextfont,
constraintext: barAttrs.constraintext,
cliponaxis: barAttrs.cliponaxis,
orientation: extendFlat({}, barAttrs.orientation, {
description: ['Sets the orientation of the funnels.', 'With *v* (*h*), the value of the each bar spans', 'along the vertical (horizontal).', 'By default funnels are tend to be oriented horizontally;', 'unless only *y* array is presented or orientation is set to *v*.', 'Also regarding graphs including only \'horizontal\' funnels,', '*autorange* on the *y-axis* are set to *reversed*.'].join(' ')
}),
offset: extendFlat({}, barAttrs.offset, {
arrayOk: false
}),
width: extendFlat({}, barAttrs.width, {
arrayOk: false
}),
marker: funnelMarker(),
connector: {
fillcolor: {
valType: 'color',
editType: 'style',
description: ['Sets the fill color.'].join(' ')
},
line: {
color: extendFlat({}, lineAttrs.color, {
dflt: Color.defaultLine
}),
width: extendFlat({}, lineAttrs.width, {
dflt: 0,
editType: 'plot'
}),
dash: lineAttrs.dash,
editType: 'style'
},
visible: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: ['Determines if connector regions and lines are drawn.'].join(' ')
},
editType: 'plot'
},
offsetgroup: barAttrs.offsetgroup,
alignmentgroup: barAttrs.alignmentgroup,
zorder: barAttrs.zorder
};
function funnelMarker() {
var marker = extendFlat({}, barAttrs.marker);
delete marker.pattern;
delete marker.cornerradius;
return marker;
}
/***/ }),
/***/ 71852:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var alignPeriod = __webpack_require__(82260);
var arraysToCalcdata = __webpack_require__(73656);
var calcSelection = __webpack_require__(62496);
var BADNUM = (__webpack_require__(41752).BADNUM);
module.exports = function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var size, pos, origPos, pObj, hasPeriod, pLetter, i, cdi;
if (trace.orientation === 'h') {
size = xa.makeCalcdata(trace, 'x');
origPos = ya.makeCalcdata(trace, 'y');
pObj = alignPeriod(trace, ya, 'y', origPos);
hasPeriod = !!trace.yperiodalignment;
pLetter = 'y';
} else {
size = ya.makeCalcdata(trace, 'y');
origPos = xa.makeCalcdata(trace, 'x');
pObj = alignPeriod(trace, xa, 'x', origPos);
hasPeriod = !!trace.xperiodalignment;
pLetter = 'x';
}
pos = pObj.vals;
// create the "calculated data" to plot
var serieslen = Math.min(pos.length, size.length);
var cd = new Array(serieslen);
// Unlike other bar-like traces funnels do not support base attribute.
// bases for funnels are computed internally in a way that
// the mid-point of each bar are located on the axis line.
trace._base = [];
// set position and size
for (i = 0; i < serieslen; i++) {
// treat negative values as bad numbers
if (size[i] < 0) size[i] = BADNUM;
var connectToNext = false;
if (size[i] !== BADNUM) {
if (i + 1 < serieslen && size[i + 1] !== BADNUM) {
connectToNext = true;
}
}
cdi = cd[i] = {
p: pos[i],
s: size[i],
cNext: connectToNext
};
trace._base[i] = -0.5 * cdi.s;
if (hasPeriod) {
cd[i].orig_p = origPos[i]; // used by hover
cd[i][pLetter + 'End'] = pObj.ends[i];
cd[i][pLetter + 'Start'] = pObj.starts[i];
}
if (trace.ids) {
cdi.id = String(trace.ids[i]);
}
// calculate total values
if (i === 0) cd[0].vTotal = 0;
cd[0].vTotal += fixNum(cdi.s);
// ratio from initial value
cdi.begR = fixNum(cdi.s) / fixNum(cd[0].s);
}
var prevGoodNum;
for (i = 0; i < serieslen; i++) {
cdi = cd[i];
if (cdi.s === BADNUM) continue;
// ratio of total value
cdi.sumR = cdi.s / cd[0].vTotal;
// ratio of previous (good) value
cdi.difR = prevGoodNum !== undefined ? cdi.s / prevGoodNum : 1;
prevGoodNum = cdi.s;
}
arraysToCalcdata(cd, trace);
calcSelection(cd, trace);
return cd;
};
function fixNum(a) {
return a === BADNUM ? 0 : a;
}
/***/ }),
/***/ 90648:
/***/ (function(module) {
"use strict";
module.exports = {
eventDataKeys: ['percentInitial', 'percentPrevious', 'percentTotal']
};
/***/ }),
/***/ 85720:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var setGroupPositions = (__webpack_require__(2616).setGroupPositions);
module.exports = function crossTraceCalc(gd, plotinfo) {
var fullLayout = gd._fullLayout;
var fullData = gd._fullData;
var calcdata = gd.calcdata;
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var funnels = [];
var funnelsVert = [];
var funnelsHorz = [];
var cd, i;
for (i = 0; i < fullData.length; i++) {
var fullTrace = fullData[i];
var isHorizontal = fullTrace.orientation === 'h';
if (fullTrace.visible === true && fullTrace.xaxis === xa._id && fullTrace.yaxis === ya._id && fullTrace.type === 'funnel') {
cd = calcdata[i];
if (isHorizontal) {
funnelsHorz.push(cd);
} else {
funnelsVert.push(cd);
}
funnels.push(cd);
}
}
var opts = {
mode: fullLayout.funnelmode,
norm: fullLayout.funnelnorm,
gap: fullLayout.funnelgap,
groupgap: fullLayout.funnelgroupgap
};
setGroupPositions(gd, xa, ya, funnelsVert, opts);
setGroupPositions(gd, ya, xa, funnelsHorz, opts);
for (i = 0; i < funnels.length; i++) {
cd = funnels[i];
for (var j = 0; j < cd.length; j++) {
if (j + 1 < cd.length) {
cd[j].nextP0 = cd[j + 1].p0;
cd[j].nextS0 = cd[j + 1].s0;
cd[j].nextP1 = cd[j + 1].p1;
cd[j].nextS1 = cd[j + 1].s1;
}
}
}
};
/***/ }),
/***/ 7028:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleGroupingDefaults = __webpack_require__(8584);
var handleText = (__webpack_require__(49520).handleText);
var handleXYDefaults = __webpack_require__(88376);
var handlePeriodDefaults = __webpack_require__(98632);
var attributes = __webpack_require__(91628);
var Color = __webpack_require__(9240);
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleXYDefaults(traceIn, traceOut, layout, coerce);
if (!len) {
traceOut.visible = false;
return;
}
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');
coerce('orientation', traceOut.y && !traceOut.x ? 'v' : 'h');
coerce('offset');
coerce('width');
var text = coerce('text');
coerce('hovertext');
coerce('hovertemplate');
var textposition = coerce('textposition');
handleText(traceIn, traceOut, layout, coerce, textposition, {
moduleHasSelected: false,
moduleHasUnselected: false,
moduleHasConstrain: true,
moduleHasCliponaxis: true,
moduleHasTextangle: true,
moduleHasInsideanchor: true
});
if (traceOut.textposition !== 'none' && !traceOut.texttemplate) {
coerce('textinfo', Lib.isArrayOrTypedArray(text) ? 'text+value' : 'value');
}
var markerColor = coerce('marker.color', defaultColor);
coerce('marker.line.color', Color.defaultLine);
coerce('marker.line.width');
var connectorVisible = coerce('connector.visible');
if (connectorVisible) {
coerce('connector.fillcolor', defaultFillColor(markerColor));
var connectorLineWidth = coerce('connector.line.width');
if (connectorLineWidth) {
coerce('connector.line.color');
coerce('connector.line.dash');
}
}
coerce('zorder');
}
function defaultFillColor(markerColor) {
var cBase = Lib.isArrayOrTypedArray(markerColor) ? '#000' : markerColor;
return Color.addOpacity(cBase, 0.5 * Color.opacity(cBase));
}
function crossTraceDefaults(fullData, fullLayout) {
var traceIn, traceOut;
function coerce(attr) {
return Lib.coerce(traceOut._input, traceOut, attributes, attr);
}
if (fullLayout.funnelmode === 'group') {
for (var i = 0; i < fullData.length; i++) {
traceOut = fullData[i];
traceIn = traceOut._input;
handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce);
}
}
}
module.exports = {
supplyDefaults: supplyDefaults,
crossTraceDefaults: crossTraceDefaults
};
/***/ }),
/***/ 71808:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt /* , trace, cd, pointNumber */) {
// standard cartesian event data
out.x = 'xVal' in pt ? pt.xVal : pt.x;
out.y = 'yVal' in pt ? pt.yVal : pt.y;
// for funnel
if ('percentInitial' in pt) out.percentInitial = pt.percentInitial;
if ('percentPrevious' in pt) out.percentPrevious = pt.percentPrevious;
if ('percentTotal' in pt) out.percentTotal = pt.percentTotal;
if (pt.xa) out.xaxis = pt.xa;
if (pt.ya) out.yaxis = pt.ya;
return out;
};
/***/ }),
/***/ 87400:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var opacity = (__webpack_require__(9240).opacity);
var hoverOnBars = (__webpack_require__(30284).hoverOnBars);
var formatPercent = (__webpack_require__(10923).formatPercent);
module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) {
var point = hoverOnBars(pointData, xval, yval, hovermode, opts);
if (!point) return;
var cd = point.cd;
var trace = cd[0].trace;
var isHorizontal = trace.orientation === 'h';
// the closest data point
var index = point.index;
var di = cd[index];
var sizeLetter = isHorizontal ? 'x' : 'y';
point[sizeLetter + 'LabelVal'] = di.s;
point.percentInitial = di.begR;
point.percentInitialLabel = formatPercent(di.begR, 1);
point.percentPrevious = di.difR;
point.percentPreviousLabel = formatPercent(di.difR, 1);
point.percentTotal = di.sumR;
point.percentTotalLabel = formatPercent(di.sumR, 1);
var hoverinfo = di.hi || trace.hoverinfo;
var text = [];
if (hoverinfo && hoverinfo !== 'none' && hoverinfo !== 'skip') {
var isAll = hoverinfo === 'all';
var parts = hoverinfo.split('+');
var hasFlag = function (flag) {
return isAll || parts.indexOf(flag) !== -1;
};
if (hasFlag('percent initial')) {
text.push(point.percentInitialLabel + ' of initial');
}
if (hasFlag('percent previous')) {
text.push(point.percentPreviousLabel + ' of previous');
}
if (hasFlag('percent total')) {
text.push(point.percentTotalLabel + ' of total');
}
}
point.extraText = text.join('
');
point.color = getTraceColor(trace, di);
return [point];
};
function getTraceColor(trace, di) {
var cont = trace.marker;
var mc = di.mc || cont.color;
var mlc = di.mlc || cont.line.color;
var mlw = di.mlw || cont.line.width;
if (opacity(mc)) return mc;else if (opacity(mlc) && mlw) return mlc;
}
/***/ }),
/***/ 92496:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(91628),
layoutAttributes: __webpack_require__(41668),
supplyDefaults: (__webpack_require__(7028).supplyDefaults),
crossTraceDefaults: (__webpack_require__(7028).crossTraceDefaults),
supplyLayoutDefaults: __webpack_require__(85776),
calc: __webpack_require__(71852),
crossTraceCalc: __webpack_require__(85720),
plot: __webpack_require__(48944),
style: (__webpack_require__(48640).style),
hoverPoints: __webpack_require__(87400),
eventData: __webpack_require__(71808),
selectPoints: __webpack_require__(10512),
moduleType: 'trace',
name: 'funnel',
basePlotModule: __webpack_require__(34316),
categories: ['bar-like', 'cartesian', 'svg', 'oriented', 'showLegend', 'zoomScale'],
meta: {
description: ['Visualize stages in a process using length-encoded bars. This trace can be used', 'to show data in either a part-to-whole representation wherein each item appears', 'in a single stage, or in a "drop-off" representation wherein each item appears in', 'each stage it traversed. See also the "funnelarea" trace type for a different', 'approach to visualizing funnel data.'].join(' ')
}
};
/***/ }),
/***/ 41668:
/***/ (function(module) {
"use strict";
module.exports = {
funnelmode: {
valType: 'enumerated',
values: ['stack', 'group', 'overlay'],
dflt: 'stack',
editType: 'calc',
description: ['Determines how bars at the same location coordinate', 'are displayed on the graph.', 'With *stack*, the bars are stacked on top of one another', 'With *group*, the bars are plotted next to one another', 'centered around the shared location.', 'With *overlay*, the bars are plotted over one another,', 'you might need to reduce *opacity* to see multiple bars.'].join(' ')
},
funnelgap: {
valType: 'number',
min: 0,
max: 1,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between bars of', 'adjacent location coordinates.'].join(' ')
},
funnelgroupgap: {
valType: 'number',
min: 0,
max: 1,
dflt: 0,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between bars of', 'the same location coordinate.'].join(' ')
}
};
/***/ }),
/***/ 85776:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(41668);
module.exports = function (layoutIn, layoutOut, fullData) {
var hasTraceType = false;
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
for (var i = 0; i < fullData.length; i++) {
var trace = fullData[i];
if (trace.visible && trace.type === 'funnel') {
hasTraceType = true;
break;
}
}
if (hasTraceType) {
coerce('funnelmode');
coerce('funnelgap', 0.2);
coerce('funnelgroupgap');
}
};
/***/ }),
/***/ 48944:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var BADNUM = (__webpack_require__(41752).BADNUM);
var barPlot = __webpack_require__(39176);
var clearMinTextSize = (__webpack_require__(4096).clearMinTextSize);
module.exports = function plot(gd, plotinfo, cdModule, traceLayer) {
var fullLayout = gd._fullLayout;
clearMinTextSize('funnel', fullLayout);
plotConnectorRegions(gd, plotinfo, cdModule, traceLayer);
plotConnectorLines(gd, plotinfo, cdModule, traceLayer);
barPlot.plot(gd, plotinfo, cdModule, traceLayer, {
mode: fullLayout.funnelmode,
norm: fullLayout.funnelmode,
gap: fullLayout.funnelgap,
groupgap: fullLayout.funnelgroupgap
});
};
function plotConnectorRegions(gd, plotinfo, cdModule, traceLayer) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
Lib.makeTraceGroups(traceLayer, cdModule, 'trace bars').each(function (cd) {
var plotGroup = d3.select(this);
var trace = cd[0].trace;
var group = Lib.ensureSingle(plotGroup, 'g', 'regions');
if (!trace.connector || !trace.connector.visible) {
group.remove();
return;
}
var isHorizontal = trace.orientation === 'h';
var connectors = group.selectAll('g.region').data(Lib.identity);
connectors.enter().append('g').classed('region', true);
connectors.exit().remove();
var len = connectors.size();
connectors.each(function (di, i) {
// don't draw lines between nulls
if (i !== len - 1 && !di.cNext) return;
var xy = getXY(di, xa, ya, isHorizontal);
var x = xy[0];
var y = xy[1];
var shape = '';
if (x[0] !== BADNUM && y[0] !== BADNUM && x[1] !== BADNUM && y[1] !== BADNUM && x[2] !== BADNUM && y[2] !== BADNUM && x[3] !== BADNUM && y[3] !== BADNUM) {
if (isHorizontal) {
shape += 'M' + x[0] + ',' + y[1] + 'L' + x[2] + ',' + y[2] + 'H' + x[3] + 'L' + x[1] + ',' + y[1] + 'Z';
} else {
shape += 'M' + x[1] + ',' + y[1] + 'L' + x[2] + ',' + y[3] + 'V' + y[2] + 'L' + x[1] + ',' + y[0] + 'Z';
}
}
if (shape === '') shape = 'M0,0Z';
Lib.ensureSingle(d3.select(this), 'path').attr('d', shape).call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
});
});
}
function plotConnectorLines(gd, plotinfo, cdModule, traceLayer) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
Lib.makeTraceGroups(traceLayer, cdModule, 'trace bars').each(function (cd) {
var plotGroup = d3.select(this);
var trace = cd[0].trace;
var group = Lib.ensureSingle(plotGroup, 'g', 'lines');
if (!trace.connector || !trace.connector.visible || !trace.connector.line.width) {
group.remove();
return;
}
var isHorizontal = trace.orientation === 'h';
var connectors = group.selectAll('g.line').data(Lib.identity);
connectors.enter().append('g').classed('line', true);
connectors.exit().remove();
var len = connectors.size();
connectors.each(function (di, i) {
// don't draw lines between nulls
if (i !== len - 1 && !di.cNext) return;
var xy = getXY(di, xa, ya, isHorizontal);
var x = xy[0];
var y = xy[1];
var shape = '';
if (x[3] !== undefined && y[3] !== undefined) {
if (isHorizontal) {
shape += 'M' + x[0] + ',' + y[1] + 'L' + x[2] + ',' + y[2];
shape += 'M' + x[1] + ',' + y[1] + 'L' + x[3] + ',' + y[2];
} else {
shape += 'M' + x[1] + ',' + y[1] + 'L' + x[2] + ',' + y[3];
shape += 'M' + x[1] + ',' + y[0] + 'L' + x[2] + ',' + y[2];
}
}
if (shape === '') shape = 'M0,0Z';
Lib.ensureSingle(d3.select(this), 'path').attr('d', shape).call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
});
});
}
function getXY(di, xa, ya, isHorizontal) {
var s = [];
var p = [];
var sAxis = isHorizontal ? xa : ya;
var pAxis = isHorizontal ? ya : xa;
s[0] = sAxis.c2p(di.s0, true);
p[0] = pAxis.c2p(di.p0, true);
s[1] = sAxis.c2p(di.s1, true);
p[1] = pAxis.c2p(di.p1, true);
s[2] = sAxis.c2p(di.nextS0, true);
p[2] = pAxis.c2p(di.nextP0, true);
s[3] = sAxis.c2p(di.nextS1, true);
p[3] = pAxis.c2p(di.nextP1, true);
return isHorizontal ? [s, p] : [p, s];
}
/***/ }),
/***/ 48640:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Drawing = __webpack_require__(49348);
var Color = __webpack_require__(9240);
var DESELECTDIM = (__webpack_require__(1172).DESELECTDIM);
var barStyle = __webpack_require__(21212);
var resizeText = (__webpack_require__(4096).resizeText);
var styleTextPoints = barStyle.styleTextPoints;
function style(gd, cd, sel) {
var s = sel ? sel : d3.select(gd).selectAll('g[class^="funnellayer"]').selectAll('g.trace');
resizeText(gd, s, 'funnel');
s.style('opacity', function (d) {
return d[0].trace.opacity;
});
s.each(function (d) {
var gTrace = d3.select(this);
var trace = d[0].trace;
gTrace.selectAll('.point > path').each(function (di) {
if (!di.isBlank) {
var cont = trace.marker;
d3.select(this).call(Color.fill, di.mc || cont.color).call(Color.stroke, di.mlc || cont.line.color).call(Drawing.dashLine, cont.line.dash, di.mlw || cont.line.width).style('opacity', trace.selectedpoints && !di.selected ? DESELECTDIM : 1);
}
});
styleTextPoints(gTrace, trace, gd);
gTrace.selectAll('.regions').each(function () {
d3.select(this).selectAll('path').style('stroke-width', 0).call(Color.fill, trace.connector.fillcolor);
});
gTrace.selectAll('.lines').each(function () {
var cont = trace.connector.line;
Drawing.lineGroupStyle(d3.select(this).selectAll('path'), cont.width, cont.color, cont.dash);
});
});
}
module.exports = {
style: style
};
/***/ }),
/***/ 32048:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var pieAttrs = __webpack_require__(99644);
var baseAttrs = __webpack_require__(6040);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = {
labels: pieAttrs.labels,
// equivalent of x0 and dx, if label is missing
label0: pieAttrs.label0,
dlabel: pieAttrs.dlabel,
values: pieAttrs.values,
marker: {
colors: pieAttrs.marker.colors,
line: {
color: extendFlat({}, pieAttrs.marker.line.color, {
dflt: null,
description: ['Sets the color of the line enclosing each sector.', 'Defaults to the `paper_bgcolor` value.'].join(' ')
}),
width: extendFlat({}, pieAttrs.marker.line.width, {
dflt: 1
}),
editType: 'calc'
},
pattern: pieAttrs.marker.pattern,
editType: 'calc'
},
text: pieAttrs.text,
hovertext: pieAttrs.hovertext,
scalegroup: extendFlat({}, pieAttrs.scalegroup, {
description: ['If there are multiple funnelareas that should be sized according to', 'their totals, link them by providing a non-empty group id here', 'shared by every trace in the same group.'].join(' ')
}),
textinfo: extendFlat({}, pieAttrs.textinfo, {
flags: ['label', 'text', 'value', 'percent']
}),
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['label', 'color', 'value', 'text', 'percent']
}),
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['label', 'text', 'value', 'percent', 'name']
}),
hovertemplate: hovertemplateAttrs({}, {
keys: ['label', 'color', 'value', 'text', 'percent']
}),
textposition: extendFlat({}, pieAttrs.textposition, {
values: ['inside', 'none'],
dflt: 'inside'
}),
textfont: pieAttrs.textfont,
insidetextfont: pieAttrs.insidetextfont,
title: {
text: pieAttrs.title.text,
font: pieAttrs.title.font,
position: extendFlat({}, pieAttrs.title.position, {
values: ['top left', 'top center', 'top right'],
dflt: 'top center'
}),
editType: 'plot'
},
domain: domainAttrs({
name: 'funnelarea',
trace: true,
editType: 'calc'
}),
aspectratio: {
valType: 'number',
min: 0,
dflt: 1,
editType: 'plot',
description: ['Sets the ratio between height and width'].join(' ')
},
baseratio: {
valType: 'number',
min: 0,
max: 1,
dflt: 0.333,
editType: 'plot',
description: ['Sets the ratio between bottom length and maximum top length.'].join(' ')
}
};
/***/ }),
/***/ 64952:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var plots = __webpack_require__(19896);
exports.name = 'funnelarea';
exports.plot = function (gd, traces, transitionOpts, makeOnCompleteCallback) {
plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout);
};
/***/ }),
/***/ 74368:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var pieCalc = __webpack_require__(71120);
function calc(gd, trace) {
return pieCalc.calc(gd, trace);
}
function crossTraceCalc(gd) {
pieCalc.crossTraceCalc(gd, {
type: 'funnelarea'
});
}
module.exports = {
calc: calc,
crossTraceCalc: crossTraceCalc
};
/***/ }),
/***/ 46432:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(32048);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var handleText = (__webpack_require__(49520).handleText);
var handleLabelsAndValues = (__webpack_require__(87048).handleLabelsAndValues);
var handleMarkerDefaults = (__webpack_require__(87048).handleMarkerDefaults);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var labels = coerce('labels');
var values = coerce('values');
var res = handleLabelsAndValues(labels, values);
var len = res.len;
traceOut._hasLabels = res.hasLabels;
traceOut._hasValues = res.hasValues;
if (!traceOut._hasLabels && traceOut._hasValues) {
coerce('label0');
coerce('dlabel');
}
if (!len) {
traceOut.visible = false;
return;
}
traceOut._length = len;
handleMarkerDefaults(traceIn, traceOut, layout, coerce);
coerce('scalegroup');
var textData = coerce('text');
var textTemplate = coerce('texttemplate');
var textInfo;
if (!textTemplate) textInfo = coerce('textinfo', Array.isArray(textData) ? 'text+percent' : 'percent');
coerce('hovertext');
coerce('hovertemplate');
if (textTemplate || textInfo && textInfo !== 'none') {
var textposition = coerce('textposition');
handleText(traceIn, traceOut, layout, coerce, textposition, {
moduleHasSelected: false,
moduleHasUnselected: false,
moduleHasConstrain: false,
moduleHasCliponaxis: false,
moduleHasTextangle: false,
moduleHasInsideanchor: false
});
} else if (textInfo === 'none') {
coerce('textposition', 'none');
}
handleDomainDefaults(traceOut, layout, coerce);
var title = coerce('title.text');
if (title) {
coerce('title.position');
Lib.coerceFont(coerce, 'title.font', layout.font);
}
coerce('aspectratio');
coerce('baseratio');
};
/***/ }),
/***/ 49792:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'funnelarea',
basePlotModule: __webpack_require__(64952),
categories: ['pie-like', 'funnelarea', 'showLegend'],
attributes: __webpack_require__(32048),
layoutAttributes: __webpack_require__(91792),
supplyDefaults: __webpack_require__(46432),
supplyLayoutDefaults: __webpack_require__(33616),
calc: (__webpack_require__(74368).calc),
crossTraceCalc: (__webpack_require__(74368).crossTraceCalc),
plot: __webpack_require__(14892),
style: __webpack_require__(29440),
styleOne: __webpack_require__(72035),
meta: {
description: ['Visualize stages in a process using area-encoded trapezoids. This trace can be used', 'to show data in a part-to-whole representation similar to a "pie" trace, wherein', 'each item appears in a single stage. See also the "funnel" trace type for a different', 'approach to visualizing funnel data.'].join(' ')
}
};
/***/ }),
/***/ 91792:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hiddenlabels = (__webpack_require__(85216).hiddenlabels);
module.exports = {
hiddenlabels: hiddenlabels,
funnelareacolorway: {
valType: 'colorlist',
editType: 'calc',
description: ['Sets the default funnelarea slice colors. Defaults to the main', '`colorway` used for trace colors. If you specify a new', 'list here it can still be extended with lighter and darker', 'colors, see `extendfunnelareacolors`.'].join(' ')
},
extendfunnelareacolors: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['If `true`, the funnelarea slice colors (whether given by `funnelareacolorway` or', 'inherited from `colorway`) will be extended to three times its', 'original length by first repeating every color 20% lighter then', 'each color 20% darker. This is intended to reduce the likelihood', 'of reusing the same color when you have many slices, but you can', 'set `false` to disable.', 'Colors provided in the trace, using `marker.colors`, are never', 'extended.'].join(' ')
}
};
/***/ }),
/***/ 33616:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(91792);
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
coerce('hiddenlabels');
coerce('funnelareacolorway', layoutOut.colorway);
coerce('extendfunnelareacolors');
};
/***/ }),
/***/ 14892:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Drawing = __webpack_require__(49348);
var Lib = __webpack_require__(10923);
var strScale = Lib.strScale;
var strTranslate = Lib.strTranslate;
var svgTextUtils = __webpack_require__(41536);
var barPlot = __webpack_require__(39176);
var toMoveInsideBar = barPlot.toMoveInsideBar;
var uniformText = __webpack_require__(4096);
var recordMinTextSize = uniformText.recordMinTextSize;
var clearMinTextSize = uniformText.clearMinTextSize;
var pieHelpers = __webpack_require__(27760);
var piePlot = __webpack_require__(60476);
var attachFxHandlers = piePlot.attachFxHandlers;
var determineInsideTextFont = piePlot.determineInsideTextFont;
var layoutAreas = piePlot.layoutAreas;
var prerenderTitles = piePlot.prerenderTitles;
var positionTitleOutside = piePlot.positionTitleOutside;
var formatSliceLabel = piePlot.formatSliceLabel;
module.exports = function plot(gd, cdModule) {
var isStatic = gd._context.staticPlot;
var fullLayout = gd._fullLayout;
clearMinTextSize('funnelarea', fullLayout);
prerenderTitles(cdModule, gd);
layoutAreas(cdModule, fullLayout._size);
Lib.makeTraceGroups(fullLayout._funnelarealayer, cdModule, 'trace').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
setCoords(cd);
plotGroup.each(function () {
var slices = d3.select(this).selectAll('g.slice').data(cd);
slices.enter().append('g').classed('slice', true);
slices.exit().remove();
slices.each(function (pt, i) {
if (pt.hidden) {
d3.select(this).selectAll('path,g').remove();
return;
}
// to have consistent event data compared to other traces
pt.pointNumber = pt.i;
pt.curveNumber = trace.index;
var cx = cd0.cx;
var cy = cd0.cy;
var sliceTop = d3.select(this);
var slicePath = sliceTop.selectAll('path.surface').data([pt]);
slicePath.enter().append('path').classed('surface', true).style({
'pointer-events': isStatic ? 'none' : 'all'
});
sliceTop.call(attachFxHandlers, gd, cd);
var shape = 'M' + (cx + pt.TR[0]) + ',' + (cy + pt.TR[1]) + line(pt.TR, pt.BR) + line(pt.BR, pt.BL) + line(pt.BL, pt.TL) + 'Z';
slicePath.attr('d', shape);
// add text
formatSliceLabel(gd, pt, cd0);
var textPosition = pieHelpers.castOption(trace.textposition, pt.pts);
var sliceTextGroup = sliceTop.selectAll('g.slicetext').data(pt.text && textPosition !== 'none' ? [0] : []);
sliceTextGroup.enter().append('g').classed('slicetext', true);
sliceTextGroup.exit().remove();
sliceTextGroup.each(function () {
var sliceText = Lib.ensureSingle(d3.select(this), 'text', '', function (s) {
// prohibit tex interpretation until we can handle
// tex and regular text together
s.attr('data-notex', 1);
});
var font = Lib.ensureUniformFontSize(gd, determineInsideTextFont(trace, pt, fullLayout.font));
sliceText.text(pt.text).attr({
class: 'slicetext',
transform: '',
'text-anchor': 'middle'
}).call(Drawing.font, font).call(svgTextUtils.convertToTspans, gd);
// position the text relative to the slice
var textBB = Drawing.bBox(sliceText.node());
var transform;
var x0, x1;
var y0 = Math.min(pt.BL[1], pt.BR[1]) + cy;
var y1 = Math.max(pt.TL[1], pt.TR[1]) + cy;
x0 = Math.max(pt.TL[0], pt.BL[0]) + cx;
x1 = Math.min(pt.TR[0], pt.BR[0]) + cx;
transform = toMoveInsideBar(x0, x1, y0, y1, textBB, {
isHorizontal: true,
constrained: true,
angle: 0,
anchor: 'middle'
});
transform.fontSize = font.size;
recordMinTextSize(trace.type, transform, fullLayout);
cd[i].transform = transform;
Lib.setTransormAndDisplay(sliceText, transform);
});
});
// add the title
var titleTextGroup = d3.select(this).selectAll('g.titletext').data(trace.title.text ? [0] : []);
titleTextGroup.enter().append('g').classed('titletext', true);
titleTextGroup.exit().remove();
titleTextGroup.each(function () {
var titleText = Lib.ensureSingle(d3.select(this), 'text', '', function (s) {
// prohibit tex interpretation as above
s.attr('data-notex', 1);
});
var txt = trace.title.text;
if (trace._meta) {
txt = Lib.templateString(txt, trace._meta);
}
titleText.text(txt).attr({
class: 'titletext',
transform: '',
'text-anchor': 'middle'
}).call(Drawing.font, trace.title.font).call(svgTextUtils.convertToTspans, gd);
var transform = positionTitleOutside(cd0, fullLayout._size);
titleText.attr('transform', strTranslate(transform.x, transform.y) + strScale(Math.min(1, transform.scale)) + strTranslate(transform.tx, transform.ty));
});
});
});
};
function line(a, b) {
var dx = b[0] - a[0];
var dy = b[1] - a[1];
return 'l' + dx + ',' + dy;
}
function getBetween(a, b) {
return [0.5 * (a[0] + b[0]), 0.5 * (a[1] + b[1])];
}
function setCoords(cd) {
if (!cd.length) return;
var cd0 = cd[0];
var trace = cd0.trace;
var aspectratio = trace.aspectratio;
var h = trace.baseratio;
if (h > 0.999) h = 0.999; // TODO: may handle this case separately
var h2 = Math.pow(h, 2);
var v1 = cd0.vTotal;
var v0 = v1 * h2 / (1 - h2);
var totalValues = v1;
var sumSteps = v0 / v1;
function calcPos() {
var q = Math.sqrt(sumSteps);
return {
x: q,
y: -q
};
}
function getPoint() {
var pos = calcPos();
return [pos.x, pos.y];
}
var p;
var allPoints = [];
allPoints.push(getPoint());
var i, cdi;
for (i = cd.length - 1; i > -1; i--) {
cdi = cd[i];
if (cdi.hidden) continue;
var step = cdi.v / totalValues;
sumSteps += step;
allPoints.push(getPoint());
}
var minY = Infinity;
var maxY = -Infinity;
for (i = 0; i < allPoints.length; i++) {
p = allPoints[i];
minY = Math.min(minY, p[1]);
maxY = Math.max(maxY, p[1]);
}
// center the shape
for (i = 0; i < allPoints.length; i++) {
allPoints[i][1] -= (maxY + minY) / 2;
}
var lastX = allPoints[allPoints.length - 1][0];
// get pie r
var r = cd0.r;
var rY = (maxY - minY) / 2;
var scaleX = r / lastX;
var scaleY = r / rY * aspectratio;
// set funnelarea r
cd0.r = scaleY * rY;
// scale the shape
for (i = 0; i < allPoints.length; i++) {
allPoints[i][0] *= scaleX;
allPoints[i][1] *= scaleY;
}
// record first position
p = allPoints[0];
var prevLeft = [-p[0], p[1]];
var prevRight = [p[0], p[1]];
var n = 0; // note we skip the very first point.
for (i = cd.length - 1; i > -1; i--) {
cdi = cd[i];
if (cdi.hidden) continue;
n += 1;
var x = allPoints[n][0];
var y = allPoints[n][1];
cdi.TL = [-x, y];
cdi.TR = [x, y];
cdi.BL = prevLeft;
cdi.BR = prevRight;
cdi.pxmid = getBetween(cdi.TR, cdi.BR);
prevLeft = cdi.TL;
prevRight = cdi.TR;
}
}
/***/ }),
/***/ 29440:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var styleOne = __webpack_require__(72035);
var resizeText = (__webpack_require__(4096).resizeText);
module.exports = function style(gd) {
var s = gd._fullLayout._funnelarealayer.selectAll('.trace');
resizeText(gd, s, 'funnelarea');
s.each(function (cd) {
var cd0 = cd[0];
var trace = cd0.trace;
var traceSelection = d3.select(this);
traceSelection.style({
opacity: trace.opacity
});
traceSelection.selectAll('path.surface').each(function (pt) {
d3.select(this).call(styleOne, pt, trace, gd);
});
});
};
/***/ }),
/***/ 7944:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterAttrs = __webpack_require__(49992);
var baseAttrs = __webpack_require__(6040);
var fontAttrs = __webpack_require__(71936);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var colorScaleAttrs = __webpack_require__(99732);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = extendFlat({
z: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the z data.'
},
x: extendFlat({}, scatterAttrs.x, {
impliedEdits: {
xtype: 'array'
}
}),
x0: extendFlat({}, scatterAttrs.x0, {
impliedEdits: {
xtype: 'scaled'
}
}),
dx: extendFlat({}, scatterAttrs.dx, {
impliedEdits: {
xtype: 'scaled'
}
}),
y: extendFlat({}, scatterAttrs.y, {
impliedEdits: {
ytype: 'array'
}
}),
y0: extendFlat({}, scatterAttrs.y0, {
impliedEdits: {
ytype: 'scaled'
}
}),
dy: extendFlat({}, scatterAttrs.dy, {
impliedEdits: {
ytype: 'scaled'
}
}),
xperiod: extendFlat({}, scatterAttrs.xperiod, {
impliedEdits: {
xtype: 'scaled'
}
}),
yperiod: extendFlat({}, scatterAttrs.yperiod, {
impliedEdits: {
ytype: 'scaled'
}
}),
xperiod0: extendFlat({}, scatterAttrs.xperiod0, {
impliedEdits: {
xtype: 'scaled'
}
}),
yperiod0: extendFlat({}, scatterAttrs.yperiod0, {
impliedEdits: {
ytype: 'scaled'
}
}),
xperiodalignment: extendFlat({}, scatterAttrs.xperiodalignment, {
impliedEdits: {
xtype: 'scaled'
}
}),
yperiodalignment: extendFlat({}, scatterAttrs.yperiodalignment, {
impliedEdits: {
ytype: 'scaled'
}
}),
text: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the text elements associated with each z value.'
},
hovertext: {
valType: 'data_array',
editType: 'calc',
description: 'Same as `text`.'
},
transpose: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: 'Transposes the z data.'
},
xtype: {
valType: 'enumerated',
values: ['array', 'scaled'],
editType: 'calc+clearAxisTypes',
description: ['If *array*, the heatmap\'s x coordinates are given by *x*', '(the default behavior when `x` is provided).', 'If *scaled*, the heatmap\'s x coordinates are given by *x0* and *dx*', '(the default behavior when `x` is not provided).'].join(' ')
},
ytype: {
valType: 'enumerated',
values: ['array', 'scaled'],
editType: 'calc+clearAxisTypes',
description: ['If *array*, the heatmap\'s y coordinates are given by *y*', '(the default behavior when `y` is provided)', 'If *scaled*, the heatmap\'s y coordinates are given by *y0* and *dy*', '(the default behavior when `y` is not provided)'].join(' ')
},
zsmooth: {
valType: 'enumerated',
values: ['fast', 'best', false],
dflt: false,
editType: 'calc',
description: ['Picks a smoothing algorithm use to smooth `z` data.'].join(' ')
},
hoverongaps: {
valType: 'boolean',
dflt: true,
editType: 'none',
description: ['Determines whether or not gaps', '(i.e. {nan} or missing values)', 'in the `z` data have hover labels associated with them.'].join(' ')
},
connectgaps: {
valType: 'boolean',
editType: 'calc',
description: ['Determines whether or not gaps', '(i.e. {nan} or missing values)', 'in the `z` data are filled in.', 'It is defaulted to true if `z` is a', 'one dimensional array and `zsmooth` is not false;', 'otherwise it is defaulted to false.'].join(' ')
},
xgap: {
valType: 'number',
dflt: 0,
min: 0,
editType: 'plot',
description: 'Sets the horizontal gap (in pixels) between bricks.'
},
ygap: {
valType: 'number',
dflt: 0,
min: 0,
editType: 'plot',
description: 'Sets the vertical gap (in pixels) between bricks.'
},
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z', 1),
hovertemplate: hovertemplateAttrs(),
texttemplate: texttemplateAttrs({
arrayOk: false,
editType: 'plot'
}, {
keys: ['x', 'y', 'z', 'text']
}),
textfont: fontAttrs({
editType: 'plot',
autoSize: true,
autoColor: true,
colorEditType: 'style',
description: 'Sets the text font.'
}),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
}),
zorder: scatterAttrs.zorder
}, {
transforms: undefined
}, colorScaleAttrs('', {
cLetter: 'z',
autoColorDflt: false
}));
/***/ }),
/***/ 53984:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var Axes = __webpack_require__(81536);
var alignPeriod = __webpack_require__(82260);
var histogram2dCalc = __webpack_require__(28824);
var colorscaleCalc = __webpack_require__(60416);
var convertColumnData = __webpack_require__(26848);
var clean2dArray = __webpack_require__(20736);
var interp2d = __webpack_require__(5912);
var findEmpties = __webpack_require__(4648);
var makeBoundArray = __webpack_require__(69672);
var BADNUM = (__webpack_require__(41752).BADNUM);
module.exports = function calc(gd, trace) {
// prepare the raw data
// run makeCalcdata on x and y even for heatmaps, in case of category mappings
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var isContour = Registry.traceIs(trace, 'contour');
var isHist = Registry.traceIs(trace, 'histogram');
var isGL2D = Registry.traceIs(trace, 'gl2d');
var zsmooth = isContour ? 'best' : trace.zsmooth;
var x, x0, dx, origX;
var y, y0, dy, origY;
var z, i, binned;
// cancel minimum tick spacings (only applies to bars and boxes)
xa._minDtick = 0;
ya._minDtick = 0;
if (isHist) {
binned = histogram2dCalc(gd, trace);
origX = binned.orig_x;
x = binned.x;
x0 = binned.x0;
dx = binned.dx;
origY = binned.orig_y;
y = binned.y;
y0 = binned.y0;
dy = binned.dy;
z = binned.z;
} else {
var zIn = trace.z;
if (Lib.isArray1D(zIn)) {
convertColumnData(trace, xa, ya, 'x', 'y', ['z']);
x = trace._x;
y = trace._y;
zIn = trace._z;
} else {
origX = trace.x ? xa.makeCalcdata(trace, 'x') : [];
origY = trace.y ? ya.makeCalcdata(trace, 'y') : [];
x = alignPeriod(trace, xa, 'x', origX).vals;
y = alignPeriod(trace, ya, 'y', origY).vals;
trace._x = x;
trace._y = y;
}
x0 = trace.x0;
dx = trace.dx;
y0 = trace.y0;
dy = trace.dy;
z = clean2dArray(zIn, trace, xa, ya);
}
if (xa.rangebreaks || ya.rangebreaks) {
z = dropZonBreaks(x, y, z);
if (!isHist) {
x = skipBreaks(x);
y = skipBreaks(y);
trace._x = x;
trace._y = y;
}
}
if (!isHist && (isContour || trace.connectgaps)) {
trace._emptypoints = findEmpties(z);
interp2d(z, trace._emptypoints);
}
function noZsmooth(msg) {
zsmooth = trace._input.zsmooth = trace.zsmooth = false;
Lib.warn('cannot use zsmooth: "fast": ' + msg);
}
function scaleIsLinear(s) {
if (s.length > 1) {
var avgdx = (s[s.length - 1] - s[0]) / (s.length - 1);
var maxErrX = Math.abs(avgdx / 100);
for (i = 0; i < s.length - 1; i++) {
if (Math.abs(s[i + 1] - s[i] - avgdx) > maxErrX) {
return false;
}
}
}
return true;
}
// Check whether all brick are uniform
trace._islinear = false;
if (xa.type === 'log' || ya.type === 'log') {
if (zsmooth === 'fast') {
noZsmooth('log axis found');
}
} else if (!scaleIsLinear(x)) {
if (zsmooth === 'fast') noZsmooth('x scale is not linear');
} else if (!scaleIsLinear(y)) {
if (zsmooth === 'fast') noZsmooth('y scale is not linear');
} else {
trace._islinear = true;
}
// create arrays of brick boundaries, to be used by autorange and heatmap.plot
var xlen = Lib.maxRowLength(z);
var xIn = trace.xtype === 'scaled' ? '' : x;
var xArray = makeBoundArray(trace, xIn, x0, dx, xlen, xa);
var yIn = trace.ytype === 'scaled' ? '' : y;
var yArray = makeBoundArray(trace, yIn, y0, dy, z.length, ya);
// handled in gl2d convert step
if (!isGL2D) {
trace._extremes[xa._id] = Axes.findExtremes(xa, xArray);
trace._extremes[ya._id] = Axes.findExtremes(ya, yArray);
}
var cd0 = {
x: xArray,
y: yArray,
z: z,
text: trace._text || trace.text,
hovertext: trace._hovertext || trace.hovertext
};
if (trace.xperiodalignment && origX) {
cd0.orig_x = origX;
}
if (trace.yperiodalignment && origY) {
cd0.orig_y = origY;
}
if (xIn && xIn.length === xArray.length - 1) cd0.xCenter = xIn;
if (yIn && yIn.length === yArray.length - 1) cd0.yCenter = yIn;
if (isHist) {
cd0.xRanges = binned.xRanges;
cd0.yRanges = binned.yRanges;
cd0.pts = binned.pts;
}
if (!isContour) {
colorscaleCalc(gd, trace, {
vals: z,
cLetter: 'z'
});
}
if (isContour && trace.contours && trace.contours.coloring === 'heatmap') {
var dummyTrace = {
type: trace.type === 'contour' ? 'heatmap' : 'histogram2d',
xcalendar: trace.xcalendar,
ycalendar: trace.ycalendar
};
cd0.xfill = makeBoundArray(dummyTrace, xIn, x0, dx, xlen, xa);
cd0.yfill = makeBoundArray(dummyTrace, yIn, y0, dy, z.length, ya);
}
return [cd0];
};
function skipBreaks(a) {
var b = [];
var len = a.length;
for (var i = 0; i < len; i++) {
var v = a[i];
if (v !== BADNUM) b.push(v);
}
return b;
}
function dropZonBreaks(x, y, z) {
var newZ = [];
var k = -1;
for (var i = 0; i < z.length; i++) {
if (y[i] === BADNUM) continue;
k++;
newZ[k] = [];
for (var j = 0; j < z[i].length; j++) {
if (x[j] === BADNUM) continue;
newZ[k].push(z[i][j]);
}
}
return newZ;
}
/***/ }),
/***/ 20736:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var BADNUM = (__webpack_require__(41752).BADNUM);
module.exports = function clean2dArray(zOld, trace, xa, ya) {
var rowlen, collen, getCollen, old2new, i, j;
function cleanZvalue(v) {
if (!isNumeric(v)) return undefined;
return +v;
}
if (trace && trace.transpose) {
rowlen = 0;
for (i = 0; i < zOld.length; i++) rowlen = Math.max(rowlen, zOld[i].length);
if (rowlen === 0) return false;
getCollen = function (zOld) {
return zOld.length;
};
old2new = function (zOld, i, j) {
return (zOld[j] || [])[i];
};
} else {
rowlen = zOld.length;
getCollen = function (zOld, i) {
return zOld[i].length;
};
old2new = function (zOld, i, j) {
return (zOld[i] || [])[j];
};
}
var padOld2new = function (zOld, i, j) {
if (i === BADNUM || j === BADNUM) return BADNUM;
return old2new(zOld, i, j);
};
function axisMapping(ax) {
if (trace && trace.type !== 'carpet' && trace.type !== 'contourcarpet' && ax && ax.type === 'category' && trace['_' + ax._id.charAt(0)].length) {
var axLetter = ax._id.charAt(0);
var axMapping = {};
var traceCategories = trace['_' + axLetter + 'CategoryMap'] || trace[axLetter];
for (i = 0; i < traceCategories.length; i++) {
axMapping[traceCategories[i]] = i;
}
return function (i) {
var ind = axMapping[ax._categories[i]];
return ind + 1 ? ind : BADNUM;
};
} else {
return Lib.identity;
}
}
var xMap = axisMapping(xa);
var yMap = axisMapping(ya);
if (ya && ya.type === 'category') rowlen = ya._categories.length;
var zNew = new Array(rowlen);
for (i = 0; i < rowlen; i++) {
if (xa && xa.type === 'category') {
collen = xa._categories.length;
} else {
collen = getCollen(zOld, i);
}
zNew[i] = new Array(collen);
for (j = 0; j < collen; j++) zNew[i][j] = cleanZvalue(padOld2new(zOld, yMap(i), xMap(j)));
}
return zNew;
};
/***/ }),
/***/ 72680:
/***/ (function(module) {
"use strict";
module.exports = {
min: 'zmin',
max: 'zmax'
};
/***/ }),
/***/ 26848:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var BADNUM = (__webpack_require__(41752).BADNUM);
var alignPeriod = __webpack_require__(82260);
module.exports = function convertColumnData(trace, ax1, ax2, var1Name, var2Name, arrayVarNames) {
var colLen = trace._length;
var col1 = ax1.makeCalcdata(trace, var1Name);
var col2 = ax2.makeCalcdata(trace, var2Name);
col1 = alignPeriod(trace, ax1, var1Name, col1).vals;
col2 = alignPeriod(trace, ax2, var2Name, col2).vals;
var textCol = trace.text;
var hasColumnText = textCol !== undefined && Lib.isArray1D(textCol);
var hoverTextCol = trace.hovertext;
var hasColumnHoverText = hoverTextCol !== undefined && Lib.isArray1D(hoverTextCol);
var i, j;
var col1dv = Lib.distinctVals(col1);
var col1vals = col1dv.vals;
var col2dv = Lib.distinctVals(col2);
var col2vals = col2dv.vals;
var newArrays = [];
var text;
var hovertext;
var nI = col2vals.length;
var nJ = col1vals.length;
for (i = 0; i < arrayVarNames.length; i++) {
newArrays[i] = Lib.init2dArray(nI, nJ);
}
if (hasColumnText) {
text = Lib.init2dArray(nI, nJ);
}
if (hasColumnHoverText) {
hovertext = Lib.init2dArray(nI, nJ);
}
var after2before = Lib.init2dArray(nI, nJ);
for (i = 0; i < colLen; i++) {
if (col1[i] !== BADNUM && col2[i] !== BADNUM) {
var i1 = Lib.findBin(col1[i] + col1dv.minDiff / 2, col1vals);
var i2 = Lib.findBin(col2[i] + col2dv.minDiff / 2, col2vals);
for (j = 0; j < arrayVarNames.length; j++) {
var arrayVarName = arrayVarNames[j];
var arrayVar = trace[arrayVarName];
var newArray = newArrays[j];
newArray[i2][i1] = arrayVar[i];
after2before[i2][i1] = i;
}
if (hasColumnText) text[i2][i1] = textCol[i];
if (hasColumnHoverText) hovertext[i2][i1] = hoverTextCol[i];
}
}
trace['_' + var1Name] = col1vals;
trace['_' + var2Name] = col2vals;
for (j = 0; j < arrayVarNames.length; j++) {
trace['_' + arrayVarNames[j]] = newArrays[j];
}
if (hasColumnText) trace._text = text;
if (hasColumnHoverText) trace._hovertext = hovertext;
if (ax1 && ax1.type === 'category') {
trace['_' + var1Name + 'CategoryMap'] = col1vals.map(function (v) {
return ax1._categories[v];
});
}
if (ax2 && ax2.type === 'category') {
trace['_' + var2Name + 'CategoryMap'] = col2vals.map(function (v) {
return ax2._categories[v];
});
}
trace._after2before = after2before;
};
/***/ }),
/***/ 27667:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleXYZDefaults = __webpack_require__(53024);
var handleHeatmapLabelDefaults = __webpack_require__(20152);
var handlePeriodDefaults = __webpack_require__(98632);
var handleStyleDefaults = __webpack_require__(39012);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(7944);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var validData = handleXYZDefaults(traceIn, traceOut, coerce, layout);
if (!validData) {
traceOut.visible = false;
return;
}
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
handleHeatmapLabelDefaults(coerce, layout);
handleStyleDefaults(traceIn, traceOut, coerce, layout);
coerce('hoverongaps');
coerce('connectgaps', Lib.isArray1D(traceOut.z) && traceOut.zsmooth !== false);
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'z'
});
coerce('zorder');
};
/***/ }),
/***/ 4648:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var maxRowLength = (__webpack_require__(10923).maxRowLength);
/* Return a list of empty points in 2D array z
* each empty point z[i][j] gives an array [i, j, neighborCount]
* neighborCount is the count of 4 nearest neighbors that DO exist
* this is to give us an order of points to evaluate for interpolation.
* if no neighbors exist, we iteratively look for neighbors that HAVE
* neighbors, and add a fractional neighborCount
*/
module.exports = function findEmpties(z) {
var empties = [];
var neighborHash = {};
var noNeighborList = [];
var nextRow = z[0];
var row = [];
var blank = [0, 0, 0];
var rowLength = maxRowLength(z);
var prevRow;
var i;
var j;
var thisPt;
var p;
var neighborCount;
var newNeighborHash;
var foundNewNeighbors;
for (i = 0; i < z.length; i++) {
prevRow = row;
row = nextRow;
nextRow = z[i + 1] || [];
for (j = 0; j < rowLength; j++) {
if (row[j] === undefined) {
neighborCount = (row[j - 1] !== undefined ? 1 : 0) + (row[j + 1] !== undefined ? 1 : 0) + (prevRow[j] !== undefined ? 1 : 0) + (nextRow[j] !== undefined ? 1 : 0);
if (neighborCount) {
// for this purpose, don't count off-the-edge points
// as undefined neighbors
if (i === 0) neighborCount++;
if (j === 0) neighborCount++;
if (i === z.length - 1) neighborCount++;
if (j === row.length - 1) neighborCount++;
// if all neighbors that could exist do, we don't
// need this for finding farther neighbors
if (neighborCount < 4) {
neighborHash[[i, j]] = [i, j, neighborCount];
}
empties.push([i, j, neighborCount]);
} else noNeighborList.push([i, j]);
}
}
}
while (noNeighborList.length) {
newNeighborHash = {};
foundNewNeighbors = false;
// look for cells that now have neighbors but didn't before
for (p = noNeighborList.length - 1; p >= 0; p--) {
thisPt = noNeighborList[p];
i = thisPt[0];
j = thisPt[1];
neighborCount = ((neighborHash[[i - 1, j]] || blank)[2] + (neighborHash[[i + 1, j]] || blank)[2] + (neighborHash[[i, j - 1]] || blank)[2] + (neighborHash[[i, j + 1]] || blank)[2]) / 20;
if (neighborCount) {
newNeighborHash[thisPt] = [i, j, neighborCount];
noNeighborList.splice(p, 1);
foundNewNeighbors = true;
}
}
if (!foundNewNeighbors) {
throw 'findEmpties iterated with no new neighbors';
}
// put these new cells into the main neighbor list
for (thisPt in newNeighborHash) {
neighborHash[thisPt] = newNeighborHash[thisPt];
empties.push(newNeighborHash[thisPt]);
}
}
// sort the full list in descending order of neighbor count
return empties.sort(function (a, b) {
return b[2] - a[2];
});
};
/***/ }),
/***/ 41864:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Fx = __webpack_require__(39184);
var Lib = __webpack_require__(10923);
var isArrayOrTypedArray = Lib.isArrayOrTypedArray;
var Axes = __webpack_require__(81536);
var extractOpts = (__webpack_require__(26733).extractOpts);
module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) {
if (!opts) opts = {};
var isContour = opts.isContour;
var cd0 = pointData.cd[0];
var trace = cd0.trace;
var xa = pointData.xa;
var ya = pointData.ya;
var x = cd0.x;
var y = cd0.y;
var z = cd0.z;
var xc = cd0.xCenter;
var yc = cd0.yCenter;
var zmask = cd0.zmask;
var zhoverformat = trace.zhoverformat;
var x2 = x;
var y2 = y;
var xl, yl, nx, ny;
if (pointData.index !== false) {
try {
nx = Math.round(pointData.index[1]);
ny = Math.round(pointData.index[0]);
} catch (e) {
Lib.error('Error hovering on heatmap, ' + 'pointNumber must be [row,col], found:', pointData.index);
return;
}
if (nx < 0 || nx >= z[0].length || ny < 0 || ny > z.length) {
return;
}
} else if (Fx.inbox(xval - x[0], xval - x[x.length - 1], 0) > 0 || Fx.inbox(yval - y[0], yval - y[y.length - 1], 0) > 0) {
return;
} else {
if (isContour) {
var i2;
x2 = [2 * x[0] - x[1]];
for (i2 = 1; i2 < x.length; i2++) {
x2.push((x[i2] + x[i2 - 1]) / 2);
}
x2.push([2 * x[x.length - 1] - x[x.length - 2]]);
y2 = [2 * y[0] - y[1]];
for (i2 = 1; i2 < y.length; i2++) {
y2.push((y[i2] + y[i2 - 1]) / 2);
}
y2.push([2 * y[y.length - 1] - y[y.length - 2]]);
}
nx = Math.max(0, Math.min(x2.length - 2, Lib.findBin(xval, x2)));
ny = Math.max(0, Math.min(y2.length - 2, Lib.findBin(yval, y2)));
}
var x0 = xa.c2p(x[nx]);
var x1 = xa.c2p(x[nx + 1]);
var y0 = ya.c2p(y[ny]);
var y1 = ya.c2p(y[ny + 1]);
var _x, _y;
if (isContour) {
_x = cd0.orig_x || x;
_y = cd0.orig_y || y;
x1 = x0;
xl = _x[nx];
y1 = y0;
yl = _y[ny];
} else {
_x = cd0.orig_x || xc || x;
_y = cd0.orig_y || yc || y;
xl = xc ? _x[nx] : (_x[nx] + _x[nx + 1]) / 2;
yl = yc ? _y[ny] : (_y[ny] + _y[ny + 1]) / 2;
if (xa && xa.type === 'category') xl = x[nx];
if (ya && ya.type === 'category') yl = y[ny];
if (trace.zsmooth) {
x0 = x1 = xa.c2p(xl);
y0 = y1 = ya.c2p(yl);
}
}
var zVal = z[ny][nx];
if (zmask && !zmask[ny][nx]) zVal = undefined;
if (zVal === undefined && !trace.hoverongaps) return;
var text;
if (isArrayOrTypedArray(cd0.hovertext) && isArrayOrTypedArray(cd0.hovertext[ny])) {
text = cd0.hovertext[ny][nx];
} else if (isArrayOrTypedArray(cd0.text) && isArrayOrTypedArray(cd0.text[ny])) {
text = cd0.text[ny][nx];
}
// dummy axis for formatting the z value
var cOpts = extractOpts(trace);
var dummyAx = {
type: 'linear',
range: [cOpts.min, cOpts.max],
hoverformat: zhoverformat,
_separators: xa._separators,
_numFormat: xa._numFormat
};
var zLabel = Axes.tickText(dummyAx, zVal, 'hover').text;
return [Lib.extendFlat(pointData, {
index: trace._after2before ? trace._after2before[ny][nx] : [ny, nx],
// never let a 2D override 1D type as closest point
distance: pointData.maxHoverDistance,
spikeDistance: pointData.maxSpikeDistance,
x0: x0,
x1: x1,
y0: y0,
y1: y1,
xLabelVal: xl,
yLabelVal: yl,
zLabelVal: zVal,
zLabel: zLabel,
text: text
})];
};
/***/ }),
/***/ 95792:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(7944),
supplyDefaults: __webpack_require__(27667),
calc: __webpack_require__(53984),
plot: __webpack_require__(97440),
colorbar: __webpack_require__(72680),
style: __webpack_require__(47824),
hoverPoints: __webpack_require__(41864),
moduleType: 'trace',
name: 'heatmap',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', '2dMap', 'showLegend'],
meta: {
description: ['The data that describes the heatmap value-to-color mapping', 'is set in `z`.', 'Data in `z` can either be a {2D array} of values (ragged or not)', 'or a 1D array of values.', 'In the case where `z` is a {2D array},', 'say that `z` has N rows and M columns.', 'Then, by default, the resulting heatmap will have N partitions along', 'the y axis and M partitions along the x axis.', 'In other words, the i-th row/ j-th column cell in `z`', 'is mapped to the i-th partition of the y axis', '(starting from the bottom of the plot) and the j-th partition', 'of the x-axis (starting from the left of the plot).', 'This behavior can be flipped by using `transpose`.', 'Moreover, `x` (`y`) can be provided with M or M+1 (N or N+1) elements.', 'If M (N), then the coordinates correspond to the center of the', 'heatmap cells and the cells have equal width.', 'If M+1 (N+1), then the coordinates correspond to the edges of the', 'heatmap cells.', 'In the case where `z` is a 1D {array}, the x and y coordinates must be', 'provided in `x` and `y` respectively to form data triplets.'].join(' ')
}
};
/***/ }),
/***/ 5912:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var INTERPTHRESHOLD = 1e-2;
var NEIGHBORSHIFTS = [[-1, 0], [1, 0], [0, -1], [0, 1]];
function correctionOvershoot(maxFractionalChange) {
// start with less overshoot, until we know it's converging,
// then ramp up the overshoot for faster convergence
return 0.5 - 0.25 * Math.min(1, maxFractionalChange * 0.5);
}
/*
* interp2d: Fill in missing data from a 2D array using an iterative
* poisson equation solver with zero-derivative BC at edges.
* Amazingly, this just amounts to repeatedly averaging all the existing
* nearest neighbors, at least if we don't take x/y scaling into account,
* which is the right approach here where x and y may not even have the
* same units.
*
* @param {array of arrays} z
* The 2D array to fill in. Will be mutated here. Assumed to already be
* cleaned, so all entries are numbers except gaps, which are `undefined`.
* @param {array of arrays} emptyPoints
* Each entry [i, j, neighborCount] for empty points z[i][j] and the number
* of neighbors that are *not* missing. Assumed to be sorted from most to
* least neighbors, as produced by heatmap/find_empties.
*/
module.exports = function interp2d(z, emptyPoints) {
var maxFractionalChange = 1;
var i;
// one pass to fill in a starting value for all the empties
iterateInterp2d(z, emptyPoints);
// we're don't need to iterate lone empties - remove them
for (i = 0; i < emptyPoints.length; i++) {
if (emptyPoints[i][2] < 4) break;
}
// but don't remove these points from the original array,
// we'll use them for masking, so make a copy.
emptyPoints = emptyPoints.slice(i);
for (i = 0; i < 100 && maxFractionalChange > INTERPTHRESHOLD; i++) {
maxFractionalChange = iterateInterp2d(z, emptyPoints, correctionOvershoot(maxFractionalChange));
}
if (maxFractionalChange > INTERPTHRESHOLD) {
Lib.log('interp2d didn\'t converge quickly', maxFractionalChange);
}
return z;
};
function iterateInterp2d(z, emptyPoints, overshoot) {
var maxFractionalChange = 0;
var thisPt;
var i;
var j;
var p;
var q;
var neighborShift;
var neighborRow;
var neighborVal;
var neighborCount;
var neighborSum;
var initialVal;
var minNeighbor;
var maxNeighbor;
for (p = 0; p < emptyPoints.length; p++) {
thisPt = emptyPoints[p];
i = thisPt[0];
j = thisPt[1];
initialVal = z[i][j];
neighborSum = 0;
neighborCount = 0;
for (q = 0; q < 4; q++) {
neighborShift = NEIGHBORSHIFTS[q];
neighborRow = z[i + neighborShift[0]];
if (!neighborRow) continue;
neighborVal = neighborRow[j + neighborShift[1]];
if (neighborVal !== undefined) {
if (neighborSum === 0) {
minNeighbor = maxNeighbor = neighborVal;
} else {
minNeighbor = Math.min(minNeighbor, neighborVal);
maxNeighbor = Math.max(maxNeighbor, neighborVal);
}
neighborCount++;
neighborSum += neighborVal;
}
}
if (neighborCount === 0) {
throw 'iterateInterp2d order is wrong: no defined neighbors';
}
// this is the laplace equation interpolation:
// each point is just the average of its neighbors
// note that this ignores differential x/y scaling
// which I think is the right approach, since we
// don't know what that scaling means
z[i][j] = neighborSum / neighborCount;
if (initialVal === undefined) {
if (neighborCount < 4) maxFractionalChange = 1;
} else {
// we can make large empty regions converge faster
// if we overshoot the change vs the previous value
z[i][j] = (1 + overshoot) * z[i][j] - overshoot * initialVal;
if (maxNeighbor > minNeighbor) {
maxFractionalChange = Math.max(maxFractionalChange, Math.abs(z[i][j] - initialVal) / (maxNeighbor - minNeighbor));
}
}
}
return maxFractionalChange;
}
/***/ }),
/***/ 20152:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
module.exports = function handleHeatmapLabelDefaults(coerce, layout) {
coerce('texttemplate');
var fontDflt = Lib.extendFlat({}, layout.font, {
color: 'auto',
size: 'auto'
});
Lib.coerceFont(coerce, 'textfont', fontDflt);
};
/***/ }),
/***/ 69672:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
module.exports = function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) {
var arrayOut = [];
var isContour = Registry.traceIs(trace, 'contour');
var isHist = Registry.traceIs(trace, 'histogram');
var isGL2D = Registry.traceIs(trace, 'gl2d');
var v0;
var dv;
var i;
var isArrayOfTwoItemsOrMore = isArrayOrTypedArray(arrayIn) && arrayIn.length > 1;
if (isArrayOfTwoItemsOrMore && !isHist && ax.type !== 'category') {
var len = arrayIn.length;
// given vals are brick centers
// hopefully length === numbricks, but use this method even if too few are supplied
// and extend it linearly based on the last two points
if (len <= numbricks) {
// contour plots only want the centers
if (isContour || isGL2D) arrayOut = Array.from(arrayIn).slice(0, numbricks);else if (numbricks === 1) {
if (ax.type === 'log') {
arrayOut = [0.5 * arrayIn[0], 2 * arrayIn[0]];
} else {
arrayOut = [arrayIn[0] - 0.5, arrayIn[0] + 0.5];
}
} else if (ax.type === 'log') {
arrayOut = [Math.pow(arrayIn[0], 1.5) / Math.pow(arrayIn[1], 0.5)];
for (i = 1; i < len; i++) {
// Geomean
arrayOut.push(Math.sqrt(arrayIn[i - 1] * arrayIn[i]));
}
arrayOut.push(Math.pow(arrayIn[len - 1], 1.5) / Math.pow(arrayIn[len - 2], 0.5));
} else {
arrayOut = [1.5 * arrayIn[0] - 0.5 * arrayIn[1]];
for (i = 1; i < len; i++) {
// Arithmetic mean
arrayOut.push((arrayIn[i - 1] + arrayIn[i]) * 0.5);
}
arrayOut.push(1.5 * arrayIn[len - 1] - 0.5 * arrayIn[len - 2]);
}
if (len < numbricks) {
var lastPt = arrayOut[arrayOut.length - 1];
var delta; // either multiplicative delta (log axis type) or arithmetic delta (all other axis types)
if (ax.type === 'log') {
delta = lastPt / arrayOut[arrayOut.length - 2];
for (i = len; i < numbricks; i++) {
lastPt *= delta;
arrayOut.push(lastPt);
}
} else {
delta = lastPt - arrayOut[arrayOut.length - 2];
for (i = len; i < numbricks; i++) {
lastPt += delta;
arrayOut.push(lastPt);
}
}
}
} else {
// hopefully length === numbricks+1, but do something regardless:
// given vals are brick boundaries
return isContour ? arrayIn.slice(0, numbricks) :
// we must be strict for contours
arrayIn.slice(0, numbricks + 1);
}
} else {
var calendar = trace[ax._id.charAt(0) + 'calendar'];
if (isHist) {
v0 = ax.r2c(v0In, 0, calendar);
} else {
if (isArrayOrTypedArray(arrayIn) && arrayIn.length === 1) {
v0 = arrayIn[0];
} else if (v0In === undefined) {
v0 = 0;
} else {
var fn = ax.type === 'log' ? ax.d2c : ax.r2c;
v0 = fn(v0In, 0, calendar);
}
}
dv = dvIn || 1;
for (i = isContour || isGL2D ? 0 : -0.5; i < numbricks; i++) {
arrayOut.push(v0 + dv * i);
}
}
return arrayOut;
};
/***/ }),
/***/ 97440:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var tinycolor = __webpack_require__(70336);
var Registry = __webpack_require__(30364);
var Drawing = __webpack_require__(49348);
var Axes = __webpack_require__(81536);
var Lib = __webpack_require__(10923);
var svgTextUtils = __webpack_require__(41536);
var formatLabels = __webpack_require__(23400);
var Color = __webpack_require__(9240);
var extractOpts = (__webpack_require__(26733).extractOpts);
var makeColorScaleFuncFromTrace = (__webpack_require__(26733).makeColorScaleFuncFromTrace);
var xmlnsNamespaces = __webpack_require__(51608);
var alignmentConstants = __webpack_require__(83784);
var LINE_SPACING = alignmentConstants.LINE_SPACING;
var supportsPixelatedImage = __webpack_require__(37640);
var PIXELATED_IMAGE_STYLE = (__webpack_require__(4020).STYLE);
var labelClass = 'heatmap-label';
function selectLabels(plotGroup) {
return plotGroup.selectAll('g.' + labelClass);
}
function removeLabels(plotGroup) {
selectLabels(plotGroup).remove();
}
module.exports = function (gd, plotinfo, cdheatmaps, heatmapLayer) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
Lib.makeTraceGroups(heatmapLayer, cdheatmaps, 'hm').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
var xGap = trace.xgap || 0;
var yGap = trace.ygap || 0;
var z = cd0.z;
var x = cd0.x;
var y = cd0.y;
var xc = cd0.xCenter;
var yc = cd0.yCenter;
var isContour = Registry.traceIs(trace, 'contour');
var zsmooth = isContour ? 'best' : trace.zsmooth;
// get z dims
var m = z.length;
var n = Lib.maxRowLength(z);
var xrev = false;
var yrev = false;
var left, right, temp, top, bottom, i, j, k;
// TODO: if there are multiple overlapping categorical heatmaps,
// or if we allow category sorting, then the categories may not be
// sequential... may need to reorder and/or expand z
// Get edges of png in pixels (xa.c2p() maps axes coordinates to pixel coordinates)
// figure out if either axis is reversed (y is usually reversed, in pixel coords)
// also clip the image to maximum 50% outside the visible plot area
// bigger image lets you pan more naturally, but slows performance.
// TODO: use low-resolution images outside the visible plot for panning
// these while loops find the first and last brick bounds that are defined
// (in case of log of a negative)
i = 0;
while (left === undefined && i < x.length - 1) {
left = xa.c2p(x[i]);
i++;
}
i = x.length - 1;
while (right === undefined && i > 0) {
right = xa.c2p(x[i]);
i--;
}
if (right < left) {
temp = right;
right = left;
left = temp;
xrev = true;
}
i = 0;
while (top === undefined && i < y.length - 1) {
top = ya.c2p(y[i]);
i++;
}
i = y.length - 1;
while (bottom === undefined && i > 0) {
bottom = ya.c2p(y[i]);
i--;
}
if (bottom < top) {
temp = top;
top = bottom;
bottom = temp;
yrev = true;
}
// for contours with heatmap fill, we generate the boundaries based on
// brick centers but then use the brick edges for drawing the bricks
if (isContour) {
xc = x;
yc = y;
x = cd0.xfill;
y = cd0.yfill;
}
var drawingMethod = 'default';
if (zsmooth) {
drawingMethod = zsmooth === 'best' ? 'smooth' : 'fast';
} else if (trace._islinear && xGap === 0 && yGap === 0 && supportsPixelatedImage()) {
drawingMethod = 'fast';
}
// make an image that goes at most half a screen off either side, to keep
// time reasonable when you zoom in. if drawingMethod is fast, don't worry
// about this, because zooming doesn't increase number of pixels
// if zsmooth is best, don't include anything off screen because it takes too long
if (drawingMethod !== 'fast') {
var extra = zsmooth === 'best' ? 0 : 0.5;
left = Math.max(-extra * xa._length, left);
right = Math.min((1 + extra) * xa._length, right);
top = Math.max(-extra * ya._length, top);
bottom = Math.min((1 + extra) * ya._length, bottom);
}
var imageWidth = Math.round(right - left);
var imageHeight = Math.round(bottom - top);
// setup image nodes
// if image is entirely off-screen, don't even draw it
var isOffScreen = left >= xa._length || right <= 0 || top >= ya._length || bottom <= 0;
if (isOffScreen) {
var noImage = plotGroup.selectAll('image').data([]);
noImage.exit().remove();
removeLabels(plotGroup);
return;
}
// generate image data
var canvasW, canvasH;
if (drawingMethod === 'fast') {
canvasW = n;
canvasH = m;
} else {
canvasW = imageWidth;
canvasH = imageHeight;
}
var canvas = document.createElement('canvas');
canvas.width = canvasW;
canvas.height = canvasH;
var context = canvas.getContext('2d', {
willReadFrequently: true
});
var sclFunc = makeColorScaleFuncFromTrace(trace, {
noNumericCheck: true,
returnArray: true
});
// map brick boundaries to image pixels
var xpx, ypx;
if (drawingMethod === 'fast') {
xpx = xrev ? function (index) {
return n - 1 - index;
} : Lib.identity;
ypx = yrev ? function (index) {
return m - 1 - index;
} : Lib.identity;
} else {
xpx = function (index) {
return Lib.constrain(Math.round(xa.c2p(x[index]) - left), 0, imageWidth);
};
ypx = function (index) {
return Lib.constrain(Math.round(ya.c2p(y[index]) - top), 0, imageHeight);
};
}
// build the pixel map brick-by-brick
// cruise through z-matrix row-by-row
// build a brick at each z-matrix value
var yi = ypx(0);
var yb = [yi, yi];
var xbi = xrev ? 0 : 1;
var ybi = yrev ? 0 : 1;
// for collecting an average luminosity of the heatmap
var pixcount = 0;
var rcount = 0;
var gcount = 0;
var bcount = 0;
var xb, xi, v, row, c;
function setColor(v, pixsize) {
if (v !== undefined) {
var c = sclFunc(v);
c[0] = Math.round(c[0]);
c[1] = Math.round(c[1]);
c[2] = Math.round(c[2]);
pixcount += pixsize;
rcount += c[0] * pixsize;
gcount += c[1] * pixsize;
bcount += c[2] * pixsize;
return c;
}
return [0, 0, 0, 0];
}
function interpColor(r0, r1, xinterp, yinterp) {
var z00 = r0[xinterp.bin0];
if (z00 === undefined) return setColor(undefined, 1);
var z01 = r0[xinterp.bin1];
var z10 = r1[xinterp.bin0];
var z11 = r1[xinterp.bin1];
var dx = z01 - z00 || 0;
var dy = z10 - z00 || 0;
var dxy;
// the bilinear interpolation term needs different calculations
// for all the different permutations of missing data
// among the neighbors of the main point, to ensure
// continuity across brick boundaries.
if (z01 === undefined) {
if (z11 === undefined) dxy = 0;else if (z10 === undefined) dxy = 2 * (z11 - z00);else dxy = (2 * z11 - z10 - z00) * 2 / 3;
} else if (z11 === undefined) {
if (z10 === undefined) dxy = 0;else dxy = (2 * z00 - z01 - z10) * 2 / 3;
} else if (z10 === undefined) dxy = (2 * z11 - z01 - z00) * 2 / 3;else dxy = z11 + z00 - z01 - z10;
return setColor(z00 + xinterp.frac * dx + yinterp.frac * (dy + xinterp.frac * dxy));
}
if (drawingMethod !== 'default') {
// works fastest with imageData
var pxIndex = 0;
var pixels;
try {
pixels = new Uint8Array(canvasW * canvasH * 4);
} catch (e) {
pixels = new Array(canvasW * canvasH * 4);
}
if (drawingMethod === 'smooth') {
// zsmooth="best"
var xForPx = xc || x;
var yForPx = yc || y;
var xPixArray = new Array(xForPx.length);
var yPixArray = new Array(yForPx.length);
var xinterpArray = new Array(imageWidth);
var findInterpX = xc ? findInterpFromCenters : findInterp;
var findInterpY = yc ? findInterpFromCenters : findInterp;
var yinterp, r0, r1;
// first make arrays of x and y pixel locations of brick boundaries
for (i = 0; i < xForPx.length; i++) xPixArray[i] = Math.round(xa.c2p(xForPx[i]) - left);
for (i = 0; i < yForPx.length; i++) yPixArray[i] = Math.round(ya.c2p(yForPx[i]) - top);
// then make arrays of interpolations
// (bin0=closest, bin1=next, frac=fractional dist.)
for (i = 0; i < imageWidth; i++) xinterpArray[i] = findInterpX(i, xPixArray);
// now do the interpolations and fill the png
for (j = 0; j < imageHeight; j++) {
yinterp = findInterpY(j, yPixArray);
r0 = z[yinterp.bin0];
r1 = z[yinterp.bin1];
for (i = 0; i < imageWidth; i++, pxIndex += 4) {
c = interpColor(r0, r1, xinterpArray[i], yinterp);
putColor(pixels, pxIndex, c);
}
}
} else {
// drawingMethod = "fast" (zsmooth = "fast"|false)
for (j = 0; j < m; j++) {
row = z[j];
yb = ypx(j);
for (i = 0; i < n; i++) {
c = setColor(row[i], 1);
pxIndex = (yb * n + xpx(i)) * 4;
putColor(pixels, pxIndex, c);
}
}
}
var imageData = context.createImageData(canvasW, canvasH);
try {
imageData.data.set(pixels);
} catch (e) {
var pxArray = imageData.data;
var dlen = pxArray.length;
for (j = 0; j < dlen; j++) {
pxArray[j] = pixels[j];
}
}
context.putImageData(imageData, 0, 0);
} else {
// rawingMethod = "default" (zsmooth = false)
// filling potentially large bricks works fastest with fillRect
// gaps do not need to be exact integers, but if they *are* we will get
// cleaner edges by rounding at least one edge
var xGapLeft = Math.floor(xGap / 2);
var yGapTop = Math.floor(yGap / 2);
for (j = 0; j < m; j++) {
row = z[j];
yb.reverse();
yb[ybi] = ypx(j + 1);
if (yb[0] === yb[1] || yb[0] === undefined || yb[1] === undefined) {
continue;
}
xi = xpx(0);
xb = [xi, xi];
for (i = 0; i < n; i++) {
// build one color brick!
xb.reverse();
xb[xbi] = xpx(i + 1);
if (xb[0] === xb[1] || xb[0] === undefined || xb[1] === undefined) {
continue;
}
v = row[i];
c = setColor(v, (xb[1] - xb[0]) * (yb[1] - yb[0]));
context.fillStyle = 'rgba(' + c.join(',') + ')';
context.fillRect(xb[0] + xGapLeft, yb[0] + yGapTop, xb[1] - xb[0] - xGap, yb[1] - yb[0] - yGap);
}
}
}
rcount = Math.round(rcount / pixcount);
gcount = Math.round(gcount / pixcount);
bcount = Math.round(bcount / pixcount);
var avgColor = tinycolor('rgb(' + rcount + ',' + gcount + ',' + bcount + ')');
gd._hmpixcount = (gd._hmpixcount || 0) + pixcount;
gd._hmlumcount = (gd._hmlumcount || 0) + pixcount * avgColor.getLuminance();
var image3 = plotGroup.selectAll('image').data(cd);
image3.enter().append('svg:image').attr({
xmlns: xmlnsNamespaces.svg,
preserveAspectRatio: 'none'
});
image3.attr({
height: imageHeight,
width: imageWidth,
x: left,
y: top,
'xlink:href': canvas.toDataURL('image/png')
});
if (drawingMethod === 'fast' && !zsmooth) {
image3.attr('style', PIXELATED_IMAGE_STYLE);
}
removeLabels(plotGroup);
var texttemplate = trace.texttemplate;
if (texttemplate) {
// dummy axis for formatting the z value
var cOpts = extractOpts(trace);
var dummyAx = {
type: 'linear',
range: [cOpts.min, cOpts.max],
_separators: xa._separators,
_numFormat: xa._numFormat
};
var aHistogram2dContour = trace.type === 'histogram2dcontour';
var aContour = trace.type === 'contour';
var iStart = aContour ? 1 : 0;
var iStop = aContour ? m - 1 : m;
var jStart = aContour ? 1 : 0;
var jStop = aContour ? n - 1 : n;
var textData = [];
for (i = iStart; i < iStop; i++) {
var yVal;
if (aContour) {
yVal = cd0.y[i];
} else if (aHistogram2dContour) {
if (i === 0 || i === m - 1) continue;
yVal = cd0.y[i];
} else if (cd0.yCenter) {
yVal = cd0.yCenter[i];
} else {
if (i + 1 === m && cd0.y[i + 1] === undefined) continue;
yVal = (cd0.y[i] + cd0.y[i + 1]) / 2;
}
var _y = Math.round(ya.c2p(yVal));
if (0 > _y || _y > ya._length) continue;
for (j = jStart; j < jStop; j++) {
var xVal;
if (aContour) {
xVal = cd0.x[j];
} else if (aHistogram2dContour) {
if (j === 0 || j === n - 1) continue;
xVal = cd0.x[j];
} else if (cd0.xCenter) {
xVal = cd0.xCenter[j];
} else {
if (j + 1 === n && cd0.x[j + 1] === undefined) continue;
xVal = (cd0.x[j] + cd0.x[j + 1]) / 2;
}
var _x = Math.round(xa.c2p(xVal));
if (0 > _x || _x > xa._length) continue;
var obj = formatLabels({
x: xVal,
y: yVal
}, trace, gd._fullLayout);
obj.x = xVal;
obj.y = yVal;
var zVal = cd0.z[i][j];
if (zVal === undefined) {
obj.z = '';
obj.zLabel = '';
} else {
obj.z = zVal;
obj.zLabel = Axes.tickText(dummyAx, zVal, 'hover').text;
}
var theText = cd0.text && cd0.text[i] && cd0.text[i][j];
if (theText === undefined || theText === false) theText = '';
obj.text = theText;
var _t = Lib.texttemplateString(texttemplate, obj, gd._fullLayout._d3locale, obj, trace._meta || {});
if (!_t) continue;
var lines = _t.split('
');
var nL = lines.length;
var nC = 0;
for (k = 0; k < nL; k++) {
nC = Math.max(nC, lines[k].length);
}
textData.push({
l: nL,
// number of lines
c: nC,
// maximum number of chars in a line
t: _t,
// text
x: _x,
y: _y,
z: zVal
});
}
}
var font = trace.textfont;
var fontFamily = font.family;
var fontSize = font.size;
var globalFontSize = gd._fullLayout.font.size;
if (!fontSize || fontSize === 'auto') {
var minW = Infinity;
var minH = Infinity;
var maxL = 0;
var maxC = 0;
for (k = 0; k < textData.length; k++) {
var d = textData[k];
maxL = Math.max(maxL, d.l);
maxC = Math.max(maxC, d.c);
if (k < textData.length - 1) {
var nextD = textData[k + 1];
var dx = Math.abs(nextD.x - d.x);
var dy = Math.abs(nextD.y - d.y);
if (dx) minW = Math.min(minW, dx);
if (dy) minH = Math.min(minH, dy);
}
}
if (!isFinite(minW) || !isFinite(minH)) {
fontSize = globalFontSize;
} else {
minW -= xGap;
minH -= yGap;
minW /= maxC;
minH /= maxL;
minW /= LINE_SPACING / 2;
minH /= LINE_SPACING;
fontSize = Math.min(Math.floor(minW), Math.floor(minH), globalFontSize);
}
}
if (fontSize <= 0 || !isFinite(fontSize)) return;
var xFn = function (d) {
return d.x;
};
var yFn = function (d) {
return d.y - fontSize * (d.l * LINE_SPACING / 2 - 1);
};
var labels = selectLabels(plotGroup).data(textData);
labels.enter().append('g').classed(labelClass, 1).append('text').attr('text-anchor', 'middle').each(function (d) {
var thisLabel = d3.select(this);
var fontColor = font.color;
if (!fontColor || fontColor === 'auto') {
fontColor = Color.contrast(d.z === undefined ? gd._fullLayout.plot_bgcolor : 'rgba(' + sclFunc(d.z).join() + ')');
}
thisLabel.attr('data-notex', 1).call(svgTextUtils.positionText, xFn(d), yFn(d)).call(Drawing.font, fontFamily, fontSize, fontColor).text(d.t).call(svgTextUtils.convertToTspans, gd);
});
}
});
};
// get interpolated bin value. Returns {bin0:closest bin, frac:fractional dist to next, bin1:next bin}
function findInterp(pixel, pixArray) {
var maxBin = pixArray.length - 2;
var bin = Lib.constrain(Lib.findBin(pixel, pixArray), 0, maxBin);
var pix0 = pixArray[bin];
var pix1 = pixArray[bin + 1];
var interp = Lib.constrain(bin + (pixel - pix0) / (pix1 - pix0) - 0.5, 0, maxBin);
var bin0 = Math.round(interp);
var frac = Math.abs(interp - bin0);
if (!interp || interp === maxBin || !frac) {
return {
bin0: bin0,
bin1: bin0,
frac: 0
};
}
return {
bin0: bin0,
frac: frac,
bin1: Math.round(bin0 + frac / (interp - bin0))
};
}
function findInterpFromCenters(pixel, centerPixArray) {
var maxBin = centerPixArray.length - 1;
var bin = Lib.constrain(Lib.findBin(pixel, centerPixArray), 0, maxBin);
var pix0 = centerPixArray[bin];
var pix1 = centerPixArray[bin + 1];
var frac = (pixel - pix0) / (pix1 - pix0) || 0;
if (frac <= 0) {
return {
bin0: bin,
bin1: bin,
frac: 0
};
}
if (frac < 0.5) {
return {
bin0: bin,
bin1: bin + 1,
frac: frac
};
}
return {
bin0: bin + 1,
bin1: bin,
frac: 1 - frac
};
}
function putColor(pixels, pxIndex, c) {
pixels[pxIndex] = c[0];
pixels[pxIndex + 1] = c[1];
pixels[pxIndex + 2] = c[2];
pixels[pxIndex + 3] = Math.round(c[3] * 255);
}
/***/ }),
/***/ 47824:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
module.exports = function style(gd) {
d3.select(gd).selectAll('.hm image').style('opacity', function (d) {
return d.trace.opacity;
});
};
/***/ }),
/***/ 39012:
/***/ (function(module) {
"use strict";
module.exports = function handleStyleDefaults(traceIn, traceOut, coerce) {
var zsmooth = coerce('zsmooth');
if (zsmooth === false) {
// ensure that xgap and ygap are coerced only when zsmooth allows them to have an effect.
coerce('xgap');
coerce('ygap');
}
coerce('zhoverformat');
};
/***/ }),
/***/ 53024:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
module.exports = function handleXYZDefaults(traceIn, traceOut, coerce, layout, xName, yName) {
var z = coerce('z');
xName = xName || 'x';
yName = yName || 'y';
var x, y;
if (z === undefined || !z.length) return 0;
if (Lib.isArray1D(z)) {
x = coerce(xName);
y = coerce(yName);
var xlen = Lib.minRowLength(x);
var ylen = Lib.minRowLength(y);
// column z must be accompanied by xName and yName arrays
if (xlen === 0 || ylen === 0) return 0;
traceOut._length = Math.min(xlen, ylen, z.length);
} else {
x = coordDefaults(xName, coerce);
y = coordDefaults(yName, coerce);
// TODO put z validation elsewhere
if (!isValidZ(z)) return 0;
coerce('transpose');
traceOut._length = null;
}
if (traceIn.type === 'heatmapgl') return true; // skip calendars until we handle them in those traces
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, [xName, yName], layout);
return true;
};
function coordDefaults(coordStr, coerce) {
var coord = coerce(coordStr);
var coordType = coord ? coerce(coordStr + 'type', 'array') : 'scaled';
if (coordType === 'scaled') {
coerce(coordStr + '0');
coerce('d' + coordStr);
}
return coord;
}
function isValidZ(z) {
var allRowsAreArrays = true;
var oneRowIsFilled = false;
var hasOneNumber = false;
var zi;
/*
* Without this step:
*
* hasOneNumber = false breaks contour but not heatmap
* allRowsAreArrays = false breaks contour but not heatmap
* oneRowIsFilled = false breaks both
*/
for (var i = 0; i < z.length; i++) {
zi = z[i];
if (!Lib.isArrayOrTypedArray(zi)) {
allRowsAreArrays = false;
break;
}
if (zi.length > 0) oneRowIsFilled = true;
for (var j = 0; j < zi.length; j++) {
if (isNumeric(zi[j])) {
hasOneNumber = true;
break;
}
}
}
return allRowsAreArrays && oneRowIsFilled && hasOneNumber;
}
/***/ }),
/***/ 49976:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var heatmapAttrs = __webpack_require__(7944);
var colorScaleAttrs = __webpack_require__(99732);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
var commonList = ['z', 'x', 'x0', 'dx', 'y', 'y0', 'dy', 'text', 'transpose', 'xtype', 'ytype'];
var attrs = {};
for (var i = 0; i < commonList.length; i++) {
var k = commonList[i];
attrs[k] = heatmapAttrs[k];
}
attrs.zsmooth = {
valType: 'enumerated',
values: ['fast', false],
dflt: 'fast',
editType: 'calc',
description: 'Picks a smoothing algorithm use to smooth `z` data.'
};
extendFlat(attrs, colorScaleAttrs('', {
cLetter: 'z',
autoColorDflt: false
}));
module.exports = overrideAll(attrs, 'calc', 'nested');
/***/ }),
/***/ 7836:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createHeatmap2D = (__webpack_require__(14656).gl_heatmap2d);
var Axes = __webpack_require__(81536);
var str2RGBArray = __webpack_require__(29864);
function Heatmap(scene, uid) {
this.scene = scene;
this.uid = uid;
this.type = 'heatmapgl';
this.name = '';
this.hoverinfo = 'all';
this.xData = [];
this.yData = [];
this.zData = [];
this.textLabels = [];
this.idToIndex = [];
this.bounds = [0, 0, 0, 0];
this.options = {
zsmooth: 'fast',
z: [],
x: [],
y: [],
shape: [0, 0],
colorLevels: [0],
colorValues: [0, 0, 0, 1]
};
this.heatmap = createHeatmap2D(scene.glplot, this.options);
this.heatmap._trace = this;
}
var proto = Heatmap.prototype;
proto.handlePick = function (pickResult) {
var options = this.options;
var shape = options.shape;
var index = pickResult.pointId;
var xIndex = index % shape[0];
var yIndex = Math.floor(index / shape[0]);
var zIndex = index;
return {
trace: this,
dataCoord: pickResult.dataCoord,
traceCoord: [options.x[xIndex], options.y[yIndex], options.z[zIndex]],
textLabel: this.textLabels[index],
name: this.name,
pointIndex: [yIndex, xIndex],
hoverinfo: this.hoverinfo
};
};
proto.update = function (fullTrace, calcTrace) {
var calcPt = calcTrace[0];
this.index = fullTrace.index;
this.name = fullTrace.name;
this.hoverinfo = fullTrace.hoverinfo;
// convert z from 2D -> 1D
var z = calcPt.z;
this.options.z = [].concat.apply([], z);
var rowLen = z[0].length;
var colLen = z.length;
this.options.shape = [rowLen, colLen];
this.options.x = calcPt.x;
this.options.y = calcPt.y;
this.options.zsmooth = fullTrace.zsmooth;
var colorOptions = convertColorscale(fullTrace);
this.options.colorLevels = colorOptions.colorLevels;
this.options.colorValues = colorOptions.colorValues;
// convert text from 2D -> 1D
this.textLabels = [].concat.apply([], fullTrace.text);
this.heatmap.update(this.options);
var xa = this.scene.xaxis;
var ya = this.scene.yaxis;
var xOpts, yOpts;
if (fullTrace.zsmooth === false) {
// increase padding for discretised heatmap as suggested by Louise Ord
xOpts = {
ppad: calcPt.x[1] - calcPt.x[0]
};
yOpts = {
ppad: calcPt.y[1] - calcPt.y[0]
};
}
fullTrace._extremes[xa._id] = Axes.findExtremes(xa, calcPt.x, xOpts);
fullTrace._extremes[ya._id] = Axes.findExtremes(ya, calcPt.y, yOpts);
};
proto.dispose = function () {
this.heatmap.dispose();
};
function convertColorscale(fullTrace) {
var scl = fullTrace.colorscale;
var zmin = fullTrace.zmin;
var zmax = fullTrace.zmax;
var N = scl.length;
var domain = new Array(N);
var range = new Array(4 * N);
for (var i = 0; i < N; i++) {
var si = scl[i];
var color = str2RGBArray(si[1]);
domain[i] = zmin + si[0] * (zmax - zmin);
for (var j = 0; j < 4; j++) {
range[4 * i + j] = color[j];
}
}
return {
colorLevels: domain,
colorValues: range
};
}
function createHeatmap(scene, fullTrace, calcTrace) {
var plot = new Heatmap(scene, fullTrace.uid);
plot.update(fullTrace, calcTrace);
return plot;
}
module.exports = createHeatmap;
/***/ }),
/***/ 25312:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleXYZDefaults = __webpack_require__(53024);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(49976);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var validData = handleXYZDefaults(traceIn, traceOut, coerce, layout);
if (!validData) {
traceOut.visible = false;
return;
}
coerce('text');
coerce('zsmooth');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'z'
});
};
/***/ }),
/***/ 86304:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var deprecationWarning = ['*heatmapgl* trace is deprecated!', 'Please consider switching to the *heatmap* or *image* trace types.', 'Alternatively you could contribute/sponsor rewriting this trace type', 'based on cartesian features and using regl framework.'].join(' ');
module.exports = {
attributes: __webpack_require__(49976),
supplyDefaults: __webpack_require__(25312),
colorbar: __webpack_require__(72680),
calc: __webpack_require__(53984),
plot: __webpack_require__(7836),
moduleType: 'trace',
name: 'heatmapgl',
basePlotModule: __webpack_require__(88768),
categories: ['gl', 'gl2d', '2dMap'],
meta: {
description: [deprecationWarning, 'WebGL version of the heatmap trace type.'].join(' ')
}
};
/***/ }),
/***/ 82264:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var barAttrs = __webpack_require__(39788);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var fontAttrs = __webpack_require__(71936);
var makeBinAttrs = __webpack_require__(40184);
var constants = __webpack_require__(18584);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = {
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the sample data to be binned on the x axis.'].join(' ')
},
y: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the sample data to be binned on the y axis.'].join(' ')
},
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
text: extendFlat({}, barAttrs.text, {
description: ['Sets hover text elements associated with each bar.', 'If a single string, the same string appears over all bars.', 'If an array of string, the items are mapped in order to the', 'this trace\'s coordinates.'].join(' ')
}),
hovertext: extendFlat({}, barAttrs.hovertext, {
description: 'Same as `text`.'
}),
orientation: barAttrs.orientation,
histfunc: {
valType: 'enumerated',
values: ['count', 'sum', 'avg', 'min', 'max'],
dflt: 'count',
editType: 'calc',
description: ['Specifies the binning function used for this histogram trace.', 'If *count*, the histogram values are computed by counting the', 'number of values lying inside each bin.', 'If *sum*, *avg*, *min*, *max*,', 'the histogram values are computed using', 'the sum, the average, the minimum or the maximum', 'of the values lying inside each bin respectively.'].join(' ')
},
histnorm: {
valType: 'enumerated',
values: ['', 'percent', 'probability', 'density', 'probability density'],
dflt: '',
editType: 'calc',
description: ['Specifies the type of normalization used for this histogram trace.', 'If **, the span of each bar corresponds to the number of', 'occurrences (i.e. the number of data points lying inside the bins).', 'If *percent* / *probability*, the span of each bar corresponds to', 'the percentage / fraction of occurrences with respect to the total', 'number of sample points', '(here, the sum of all bin HEIGHTS equals 100% / 1).', 'If *density*, the span of each bar corresponds to the number of', 'occurrences in a bin divided by the size of the bin interval', '(here, the sum of all bin AREAS equals the', 'total number of sample points).', 'If *probability density*, the area of each bar corresponds to the', 'probability that an event will fall into the corresponding bin', '(here, the sum of all bin AREAS equals 1).'].join(' ')
},
cumulative: {
enabled: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['If true, display the cumulative distribution by summing the', 'binned values. Use the `direction` and `centralbin` attributes', 'to tune the accumulation method.', 'Note: in this mode, the *density* `histnorm` settings behave', 'the same as their equivalents without *density*:', '** and *density* both rise to the number of data points, and', '*probability* and *probability density* both rise to the', 'number of sample points.'].join(' ')
},
direction: {
valType: 'enumerated',
values: ['increasing', 'decreasing'],
dflt: 'increasing',
editType: 'calc',
description: ['Only applies if cumulative is enabled.', 'If *increasing* (default) we sum all prior bins, so the result', 'increases from left to right. If *decreasing* we sum later bins', 'so the result decreases from left to right.'].join(' ')
},
currentbin: {
valType: 'enumerated',
values: ['include', 'exclude', 'half'],
dflt: 'include',
editType: 'calc',
description: ['Only applies if cumulative is enabled.', 'Sets whether the current bin is included, excluded, or has half', 'of its value included in the current cumulative value.', '*include* is the default for compatibility with various other', 'tools, however it introduces a half-bin bias to the results.', '*exclude* makes the opposite half-bin bias, and *half* removes', 'it.'].join(' ')
},
editType: 'calc'
},
nbinsx: {
valType: 'integer',
min: 0,
dflt: 0,
editType: 'calc',
description: ['Specifies the maximum number of desired bins. This value will be used', 'in an algorithm that will decide the optimal bin size such that the', 'histogram best visualizes the distribution of the data.', 'Ignored if `xbins.size` is provided.'].join(' ')
},
xbins: makeBinAttrs('x', true),
nbinsy: {
valType: 'integer',
min: 0,
dflt: 0,
editType: 'calc',
description: ['Specifies the maximum number of desired bins. This value will be used', 'in an algorithm that will decide the optimal bin size such that the', 'histogram best visualizes the distribution of the data.', 'Ignored if `ybins.size` is provided.'].join(' ')
},
ybins: makeBinAttrs('y', true),
autobinx: {
valType: 'boolean',
dflt: null,
editType: 'calc',
description: ['Obsolete: since v1.42 each bin attribute is auto-determined', 'separately and `autobinx` is not needed. However, we accept', '`autobinx: true` or `false` and will update `xbins` accordingly', 'before deleting `autobinx` from the trace.'].join(' ')
},
autobiny: {
valType: 'boolean',
dflt: null,
editType: 'calc',
description: ['Obsolete: since v1.42 each bin attribute is auto-determined', 'separately and `autobiny` is not needed. However, we accept', '`autobiny: true` or `false` and will update `ybins` accordingly', 'before deleting `autobiny` from the trace.'].join(' ')
},
bingroup: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['Set a group of histogram traces which will have compatible bin settings.', 'Note that traces on the same subplot and with the same *orientation*', 'under `barmode` *stack*, *relative* and *group* are forced into the same bingroup,', 'Using `bingroup`, traces under `barmode` *overlay* and on different axes', '(of the same axis type) can have compatible bin settings.', 'Note that histogram and histogram2d* trace can share the same `bingroup`'].join(' ')
},
hovertemplate: hovertemplateAttrs({}, {
keys: constants.eventDataKeys
}),
texttemplate: texttemplateAttrs({
arrayOk: false,
editType: 'plot'
}, {
keys: ['label', 'value']
}),
textposition: extendFlat({}, barAttrs.textposition, {
arrayOk: false
}),
textfont: fontAttrs({
arrayOk: false,
editType: 'plot',
colorEditType: 'style',
description: 'Sets the text font.'
}),
outsidetextfont: fontAttrs({
arrayOk: false,
editType: 'plot',
colorEditType: 'style',
description: 'Sets the font used for `text` lying outside the bar.'
}),
insidetextfont: fontAttrs({
arrayOk: false,
editType: 'plot',
colorEditType: 'style',
description: 'Sets the font used for `text` lying inside the bar.'
}),
insidetextanchor: barAttrs.insidetextanchor,
textangle: barAttrs.textangle,
cliponaxis: barAttrs.cliponaxis,
constraintext: barAttrs.constraintext,
marker: barAttrs.marker,
offsetgroup: barAttrs.offsetgroup,
alignmentgroup: barAttrs.alignmentgroup,
selected: barAttrs.selected,
unselected: barAttrs.unselected,
_deprecated: {
bardir: barAttrs._deprecated.bardir
},
zorder: barAttrs.zorder
};
/***/ }),
/***/ 86488:
/***/ (function(module) {
"use strict";
module.exports = function doAvg(size, counts) {
var nMax = size.length;
var total = 0;
for (var i = 0; i < nMax; i++) {
if (counts[i]) {
size[i] /= counts[i];
total += size[i];
} else size[i] = null;
}
return total;
};
/***/ }),
/***/ 40184:
/***/ (function(module) {
"use strict";
module.exports = function makeBinAttrs(axLetter, match) {
return {
start: {
valType: 'any',
// for date axes
editType: 'calc',
description: ['Sets the starting value for the', axLetter, 'axis bins. Defaults to the minimum data value,', 'shifted down if necessary to make nice round values', 'and to remove ambiguous bin edges. For example, if most of the', 'data is integers we shift the bin edges 0.5 down, so a `size`', 'of 5 would have a default `start` of -0.5, so it is clear', 'that 0-4 are in the first bin, 5-9 in the second, but', 'continuous data gets a start of 0 and bins [0,5), [5,10) etc.', 'Dates behave similarly, and `start` should be a date string.', 'For category data, `start` is based on the category serial', 'numbers, and defaults to -0.5.', match ? 'If multiple non-overlaying histograms share a subplot, ' + 'the first explicit `start` is used exactly and all others ' + 'are shifted down (if necessary) to differ from that one ' + 'by an integer number of bins.' : ''].join(' ')
},
end: {
valType: 'any',
// for date axes
editType: 'calc',
description: ['Sets the end value for the', axLetter, 'axis bins. The last bin may not end exactly at this value,', 'we increment the bin edge by `size` from `start` until we', 'reach or exceed `end`. Defaults to the maximum data value.', 'Like `start`, for dates use a date string, and for category', 'data `end` is based on the category serial numbers.'].join(' ')
},
size: {
valType: 'any',
// for date axes
editType: 'calc',
description: ['Sets the size of each', axLetter, 'axis bin.', 'Default behavior: If `nbins' + axLetter + '` is 0 or omitted,', 'we choose a nice round bin size such that the number of bins', 'is about the same as the typical number of samples in each bin.', 'If `nbins' + axLetter + '` is provided, we choose a nice round', 'bin size giving no more than that many bins.', 'For date data, use milliseconds or *M
* for months, as in', '`axis.dtick`. For category data, the number of categories to', 'bin together (always defaults to 1).', match ? 'If multiple non-overlaying histograms share a subplot, ' + 'the first explicit `size` is used and all others discarded. ' + 'If no `size` is provided,the sample data from all traces ' + 'is combined to determine `size` as described above.' : ''].join(' ')
},
editType: 'calc'
};
};
/***/ }),
/***/ 74080:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
module.exports = {
count: function (n, i, size) {
size[n]++;
return 1;
},
sum: function (n, i, size, counterData) {
var v = counterData[i];
if (isNumeric(v)) {
v = Number(v);
size[n] += v;
return v;
}
return 0;
},
avg: function (n, i, size, counterData, counts) {
var v = counterData[i];
if (isNumeric(v)) {
v = Number(v);
size[n] += v;
counts[n]++;
}
return 0;
},
min: function (n, i, size, counterData) {
var v = counterData[i];
if (isNumeric(v)) {
v = Number(v);
if (!isNumeric(size[n])) {
size[n] = v;
return v;
} else if (size[n] > v) {
var delta = v - size[n];
size[n] = v;
return delta;
}
}
return 0;
},
max: function (n, i, size, counterData) {
var v = counterData[i];
if (isNumeric(v)) {
v = Number(v);
if (!isNumeric(size[n])) {
size[n] = v;
return v;
} else if (size[n] < v) {
var delta = v - size[n];
size[n] = v;
return delta;
}
}
return 0;
}
};
/***/ }),
/***/ 49848:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var numConstants = __webpack_require__(41752);
var oneYear = numConstants.ONEAVGYEAR;
var oneMonth = numConstants.ONEAVGMONTH;
var oneDay = numConstants.ONEDAY;
var oneHour = numConstants.ONEHOUR;
var oneMin = numConstants.ONEMIN;
var oneSec = numConstants.ONESEC;
var tickIncrement = (__webpack_require__(81536).tickIncrement);
/*
* make a function that will find rounded bin edges
* @param {number} leftGap: how far from the left edge of any bin is the closest data value?
* @param {number} rightGap: how far from the right edge of any bin is the closest data value?
* @param {Array[number]} binEdges: the actual edge values used in binning
* @param {object} pa: the position axis
* @param {string} calendar: the data calendar
*
* @return {function(v, isRightEdge)}:
* find the start (isRightEdge is falsy) or end (truthy) label value for a bin edge `v`
*/
module.exports = function getBinSpanLabelRound(leftGap, rightGap, binEdges, pa, calendar) {
// the rounding digit is the largest digit that changes in *all* of 4 regions:
// - inside the rightGap before binEdges[0] (shifted 10% to the left)
// - inside the leftGap after binEdges[0] (expanded by 10% of rightGap on each end)
// - same for binEdges[1]
var dv0 = -1.1 * rightGap;
var dv1 = -0.1 * rightGap;
var dv2 = leftGap - dv1;
var edge0 = binEdges[0];
var edge1 = binEdges[1];
var leftDigit = Math.min(biggestDigitChanged(edge0 + dv1, edge0 + dv2, pa, calendar), biggestDigitChanged(edge1 + dv1, edge1 + dv2, pa, calendar));
var rightDigit = Math.min(biggestDigitChanged(edge0 + dv0, edge0 + dv1, pa, calendar), biggestDigitChanged(edge1 + dv0, edge1 + dv1, pa, calendar));
// normally we try to make the label for the right edge different from
// the left edge label, so it's unambiguous which bin gets data on the edge.
// but if this results in more than 3 extra digits (or for dates, more than
// 2 fields ie hr&min or min&sec, which is 3600x), it'll be more clutter than
// useful so keep the label cleaner instead
var digit, disambiguateEdges;
if (leftDigit > rightDigit && rightDigit < Math.abs(edge1 - edge0) / 4000) {
digit = leftDigit;
disambiguateEdges = false;
} else {
digit = Math.min(leftDigit, rightDigit);
disambiguateEdges = true;
}
if (pa.type === 'date' && digit > oneDay) {
var dashExclude = digit === oneYear ? 1 : 6;
var increment = digit === oneYear ? 'M12' : 'M1';
return function (v, isRightEdge) {
var dateStr = pa.c2d(v, oneYear, calendar);
var dashPos = dateStr.indexOf('-', dashExclude);
if (dashPos > 0) dateStr = dateStr.substr(0, dashPos);
var roundedV = pa.d2c(dateStr, 0, calendar);
if (roundedV < v) {
var nextV = tickIncrement(roundedV, increment, false, calendar);
if ((roundedV + nextV) / 2 < v + leftGap) roundedV = nextV;
}
if (isRightEdge && disambiguateEdges) {
return tickIncrement(roundedV, increment, true, calendar);
}
return roundedV;
};
}
return function (v, isRightEdge) {
var roundedV = digit * Math.round(v / digit);
// if we rounded down and we could round up and still be < leftGap
// (or what leftGap values round to), do that
if (roundedV + digit / 10 < v && roundedV + digit * 0.9 < v + leftGap) {
roundedV += digit;
}
// finally for the right edge back off one digit - but only if we can do that
// and not clip off any data that's potentially in the bin
if (isRightEdge && disambiguateEdges) {
roundedV -= digit;
}
return roundedV;
};
};
/*
* Find the largest digit that changes within a (calcdata) region [v1, v2]
* if dates, "digit" means date/time part when it's bigger than a second
* returns the unit value to round to this digit, eg 0.01 to round to hundredths, or
* 100 to round to hundreds. returns oneMonth or oneYear for month or year rounding,
* so that Math.min will work, rather than 'M1' and 'M12'
*/
function biggestDigitChanged(v1, v2, pa, calendar) {
// are we crossing zero? can't say anything.
// in principle this doesn't apply to dates but turns out this doesn't matter.
if (v1 * v2 <= 0) return Infinity;
var dv = Math.abs(v2 - v1);
var isDate = pa.type === 'date';
var digit = biggestGuaranteedDigitChanged(dv, isDate);
// see if a larger digit also changed
for (var i = 0; i < 10; i++) {
// numbers: next digit needs to be >10x but <100x then gets rounded down.
// dates: next digit can be as much as 60x (then rounded down)
var nextDigit = biggestGuaranteedDigitChanged(digit * 80, isDate);
// if we get to years, the chain stops
if (digit === nextDigit) break;
if (didDigitChange(nextDigit, v1, v2, isDate, pa, calendar)) digit = nextDigit;else break;
}
return digit;
}
/*
* Find the largest digit that *definitely* changes in a region [v, v + dv] for any v
* for nonuniform date regions (months/years) pick the largest
*/
function biggestGuaranteedDigitChanged(dv, isDate) {
if (isDate && dv > oneSec) {
// this is supposed to be the biggest *guaranteed* change
// so compare to the longest month and year across any calendar,
// and we'll iterate back up later
// note: does not support rounding larger than one year. We could add
// that if anyone wants it, but seems unusual and not strictly necessary.
if (dv > oneDay) {
if (dv > oneYear * 1.1) return oneYear;
if (dv > oneMonth * 1.1) return oneMonth;
return oneDay;
}
if (dv > oneHour) return oneHour;
if (dv > oneMin) return oneMin;
return oneSec;
}
return Math.pow(10, Math.floor(Math.log(dv) / Math.LN10));
}
function didDigitChange(digit, v1, v2, isDate, pa, calendar) {
if (isDate && digit > oneDay) {
var dateParts1 = dateParts(v1, pa, calendar);
var dateParts2 = dateParts(v2, pa, calendar);
var parti = digit === oneYear ? 0 : 1;
return dateParts1[parti] !== dateParts2[parti];
}
return Math.floor(v2 / digit) - Math.floor(v1 / digit) > 0.1;
}
function dateParts(v, pa, calendar) {
var parts = pa.c2d(v, oneYear, calendar).split('-');
if (parts[0] === '') {
parts.unshift();
parts[0] = '-' + parts[0];
}
return parts;
}
/***/ }),
/***/ 95468:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
var Axes = __webpack_require__(81536);
var arraysToCalcdata = __webpack_require__(79224);
var binFunctions = __webpack_require__(74080);
var normFunctions = __webpack_require__(42908);
var doAvg = __webpack_require__(86488);
var getBinSpanLabelRound = __webpack_require__(49848);
function calc(gd, trace) {
var pos = [];
var size = [];
var isHorizontal = trace.orientation === 'h';
var pa = Axes.getFromId(gd, isHorizontal ? trace.yaxis : trace.xaxis);
var mainData = isHorizontal ? 'y' : 'x';
var counterData = {
x: 'y',
y: 'x'
}[mainData];
var calendar = trace[mainData + 'calendar'];
var cumulativeSpec = trace.cumulative;
var i;
var binsAndPos = calcAllAutoBins(gd, trace, pa, mainData);
var binSpec = binsAndPos[0];
var pos0 = binsAndPos[1];
var nonuniformBins = typeof binSpec.size === 'string';
var binEdges = [];
var bins = nonuniformBins ? binEdges : binSpec;
// make the empty bin array
var inc = [];
var counts = [];
var inputPoints = [];
var total = 0;
var norm = trace.histnorm;
var func = trace.histfunc;
var densityNorm = norm.indexOf('density') !== -1;
var i2, binEnd, n;
if (cumulativeSpec.enabled && densityNorm) {
// we treat "cumulative" like it means "integral" if you use a density norm,
// which in the end means it's the same as without "density"
norm = norm.replace(/ ?density$/, '');
densityNorm = false;
}
var extremeFunc = func === 'max' || func === 'min';
var sizeInit = extremeFunc ? null : 0;
var binFunc = binFunctions.count;
var normFunc = normFunctions[norm];
var isAvg = false;
var pr2c = function (v) {
return pa.r2c(v, 0, calendar);
};
var rawCounterData;
if (Lib.isArrayOrTypedArray(trace[counterData]) && func !== 'count') {
rawCounterData = trace[counterData];
isAvg = func === 'avg';
binFunc = binFunctions[func];
}
// create the bins (and any extra arrays needed)
// assume more than 1e6 bins is an error, so we don't crash the browser
i = pr2c(binSpec.start);
// decrease end a little in case of rounding errors
binEnd = pr2c(binSpec.end) + (i - Axes.tickIncrement(i, binSpec.size, false, calendar)) / 1e6;
while (i < binEnd && pos.length < 1e6) {
i2 = Axes.tickIncrement(i, binSpec.size, false, calendar);
pos.push((i + i2) / 2);
size.push(sizeInit);
inputPoints.push([]);
// nonuniform bins (like months) we need to search,
// rather than straight calculate the bin we're in
binEdges.push(i);
// nonuniform bins also need nonuniform normalization factors
if (densityNorm) inc.push(1 / (i2 - i));
if (isAvg) counts.push(0);
// break to avoid infinite loops
if (i2 <= i) break;
i = i2;
}
binEdges.push(i);
// for date axes we need bin bounds to be calcdata. For nonuniform bins
// we already have this, but uniform with start/end/size they're still strings.
if (!nonuniformBins && pa.type === 'date') {
bins = {
start: pr2c(bins.start),
end: pr2c(bins.end),
size: bins.size
};
}
// stash left and right gaps by group
if (!gd._fullLayout._roundFnOpts) gd._fullLayout._roundFnOpts = {};
var groupName = trace['_' + mainData + 'bingroup'];
var roundFnOpts = {
leftGap: Infinity,
rightGap: Infinity
};
if (groupName) {
if (!gd._fullLayout._roundFnOpts[groupName]) gd._fullLayout._roundFnOpts[groupName] = roundFnOpts;
roundFnOpts = gd._fullLayout._roundFnOpts[groupName];
}
// bin the data
// and make histogram-specific pt-number-to-cd-index map object
var nMax = size.length;
var uniqueValsPerBin = true;
var leftGap = roundFnOpts.leftGap;
var rightGap = roundFnOpts.rightGap;
var ptNumber2cdIndex = {};
for (i = 0; i < pos0.length; i++) {
var posi = pos0[i];
n = Lib.findBin(posi, bins);
if (n >= 0 && n < nMax) {
total += binFunc(n, i, size, rawCounterData, counts);
if (uniqueValsPerBin && inputPoints[n].length && posi !== pos0[inputPoints[n][0]]) {
uniqueValsPerBin = false;
}
inputPoints[n].push(i);
ptNumber2cdIndex[i] = n;
leftGap = Math.min(leftGap, posi - binEdges[n]);
rightGap = Math.min(rightGap, binEdges[n + 1] - posi);
}
}
roundFnOpts.leftGap = leftGap;
roundFnOpts.rightGap = rightGap;
var roundFn;
if (!uniqueValsPerBin) {
roundFn = function (v, isRightEdge) {
return function () {
var roundFnOpts = gd._fullLayout._roundFnOpts[groupName];
return getBinSpanLabelRound(roundFnOpts.leftGap, roundFnOpts.rightGap, binEdges, pa, calendar)(v, isRightEdge);
};
};
}
// average and/or normalize the data, if needed
if (isAvg) total = doAvg(size, counts);
if (normFunc) normFunc(size, total, inc);
// after all normalization etc, now we can accumulate if desired
if (cumulativeSpec.enabled) cdf(size, cumulativeSpec.direction, cumulativeSpec.currentbin);
var seriesLen = Math.min(pos.length, size.length);
var cd = [];
var firstNonzero = 0;
var lastNonzero = seriesLen - 1;
// look for empty bins at the ends to remove, so autoscale omits them
for (i = 0; i < seriesLen; i++) {
if (size[i]) {
firstNonzero = i;
break;
}
}
for (i = seriesLen - 1; i >= firstNonzero; i--) {
if (size[i]) {
lastNonzero = i;
break;
}
}
// create the "calculated data" to plot
for (i = firstNonzero; i <= lastNonzero; i++) {
if (isNumeric(pos[i]) && isNumeric(size[i])) {
var cdi = {
p: pos[i],
s: size[i],
b: 0
};
// setup hover and event data fields,
// N.B. pts and "hover" positions ph0/ph1 don't seem to make much sense
// for cumulative distributions
if (!cumulativeSpec.enabled) {
cdi.pts = inputPoints[i];
if (uniqueValsPerBin) {
cdi.ph0 = cdi.ph1 = inputPoints[i].length ? pos0[inputPoints[i][0]] : pos[i];
} else {
// Defer evaluation of ph(0|1) in crossTraceCalc
trace._computePh = true;
cdi.ph0 = roundFn(binEdges[i]);
cdi.ph1 = roundFn(binEdges[i + 1], true);
}
}
cd.push(cdi);
}
}
if (cd.length === 1) {
// when we collapse to a single bin, calcdata no longer describes bin size
// so we need to explicitly specify it
cd[0].width1 = Axes.tickIncrement(cd[0].p, binSpec.size, false, calendar) - cd[0].p;
}
arraysToCalcdata(cd, trace);
if (Lib.isArrayOrTypedArray(trace.selectedpoints)) {
Lib.tagSelected(cd, trace, ptNumber2cdIndex);
}
return cd;
}
/*
* calcAllAutoBins: we want all histograms inside the same bingroup
* (see logic in Histogram.crossTraceDefaults) to share bin specs
*
* If the user has explicitly specified differing
* bin specs, there's nothing we can do, but if possible we will try to use the
* smallest bins of any of the auto values for all histograms inside the same
* bingroup.
*/
function calcAllAutoBins(gd, trace, pa, mainData, _overlayEdgeCase) {
var binAttr = mainData + 'bins';
var fullLayout = gd._fullLayout;
var groupName = trace['_' + mainData + 'bingroup'];
var binOpts = fullLayout._histogramBinOpts[groupName];
var isOverlay = fullLayout.barmode === 'overlay';
var i, traces, tracei, calendar, pos0, autoVals, cumulativeSpec;
var r2c = function (v) {
return pa.r2c(v, 0, calendar);
};
var c2r = function (v) {
return pa.c2r(v, 0, calendar);
};
var cleanBound = pa.type === 'date' ? function (v) {
return v || v === 0 ? Lib.cleanDate(v, null, calendar) : null;
} : function (v) {
return isNumeric(v) ? Number(v) : null;
};
function setBound(attr, bins, newBins) {
if (bins[attr + 'Found']) {
bins[attr] = cleanBound(bins[attr]);
if (bins[attr] === null) bins[attr] = newBins[attr];
} else {
autoVals[attr] = bins[attr] = newBins[attr];
Lib.nestedProperty(traces[0], binAttr + '.' + attr).set(newBins[attr]);
}
}
// all but the first trace in this group has already been marked finished
// clear this flag, so next time we run calc we will run autobin again
if (trace['_' + mainData + 'autoBinFinished']) {
delete trace['_' + mainData + 'autoBinFinished'];
} else {
traces = binOpts.traces;
var allPos = [];
// Note: we're including `legendonly` traces here for autobin purposes,
// so that showing & hiding from the legend won't affect bins.
// But this complicates things a bit since those traces don't `calc`,
// hence `isFirstVisible`.
var isFirstVisible = true;
var has2dMap = false;
var hasHist2dContour = false;
for (i = 0; i < traces.length; i++) {
tracei = traces[i];
if (tracei.visible) {
var mainDatai = binOpts.dirs[i];
pos0 = tracei['_' + mainDatai + 'pos0'] = pa.makeCalcdata(tracei, mainDatai);
allPos = Lib.concat(allPos, pos0);
delete tracei['_' + mainData + 'autoBinFinished'];
if (trace.visible === true) {
if (isFirstVisible) {
isFirstVisible = false;
} else {
delete tracei._autoBin;
tracei['_' + mainData + 'autoBinFinished'] = 1;
}
if (Registry.traceIs(tracei, '2dMap')) {
has2dMap = true;
}
if (tracei.type === 'histogram2dcontour') {
hasHist2dContour = true;
}
}
}
}
calendar = traces[0][mainData + 'calendar'];
var newBinSpec = Axes.autoBin(allPos, pa, binOpts.nbins, has2dMap, calendar, binOpts.sizeFound && binOpts.size);
var autoBin = traces[0]._autoBin = {};
autoVals = autoBin[binOpts.dirs[0]] = {};
if (hasHist2dContour) {
// the "true" 2nd argument reverses the tick direction (which we can't
// just do with a minus sign because of month bins)
if (!binOpts.size) {
newBinSpec.start = c2r(Axes.tickIncrement(r2c(newBinSpec.start), newBinSpec.size, true, calendar));
}
if (binOpts.end === undefined) {
newBinSpec.end = c2r(Axes.tickIncrement(r2c(newBinSpec.end), newBinSpec.size, false, calendar));
}
}
// Edge case: single-valued histogram overlaying others
// Use them all together to calculate the bin size for the single-valued one
// Don't re-calculate bin width if user manually specified it (checing in bingroup=='' or xbins is defined)
if (isOverlay && !Registry.traceIs(trace, '2dMap') && newBinSpec._dataSpan === 0 && pa.type !== 'category' && pa.type !== 'multicategory' && trace.bingroup === '' && typeof trace.xbins === 'undefined') {
// Several single-valued histograms! Stop infinite recursion,
// just return an extra flag that tells handleSingleValueOverlays
// to sort out this trace too
if (_overlayEdgeCase) return [newBinSpec, pos0, true];
newBinSpec = handleSingleValueOverlays(gd, trace, pa, mainData, binAttr);
}
// adjust for CDF edge cases
cumulativeSpec = tracei.cumulative || {};
if (cumulativeSpec.enabled && cumulativeSpec.currentbin !== 'include') {
if (cumulativeSpec.direction === 'decreasing') {
newBinSpec.start = c2r(Axes.tickIncrement(r2c(newBinSpec.start), newBinSpec.size, true, calendar));
} else {
newBinSpec.end = c2r(Axes.tickIncrement(r2c(newBinSpec.end), newBinSpec.size, false, calendar));
}
}
binOpts.size = newBinSpec.size;
if (!binOpts.sizeFound) {
autoVals.size = newBinSpec.size;
Lib.nestedProperty(traces[0], binAttr + '.size').set(newBinSpec.size);
}
setBound('start', binOpts, newBinSpec);
setBound('end', binOpts, newBinSpec);
}
pos0 = trace['_' + mainData + 'pos0'];
delete trace['_' + mainData + 'pos0'];
// Each trace can specify its own start/end, or if omitted
// we ensure they're beyond the bounds of this trace's data,
// and we need to make sure start is aligned with the main start
var traceInputBins = trace._input[binAttr] || {};
var traceBinOptsCalc = Lib.extendFlat({}, binOpts);
var mainStart = binOpts.start;
var startIn = pa.r2l(traceInputBins.start);
var hasStart = startIn !== undefined;
if ((binOpts.startFound || hasStart) && startIn !== pa.r2l(mainStart)) {
// We have an explicit start to reconcile across traces
// if this trace has an explicit start, shift it down to a bin edge
// if another trace had an explicit start, shift it down to a
// bin edge past our data
var traceStart = hasStart ? startIn : Lib.aggNums(Math.min, null, pos0);
var dummyAx = {
type: pa.type === 'category' || pa.type === 'multicategory' ? 'linear' : pa.type,
r2l: pa.r2l,
dtick: binOpts.size,
tick0: mainStart,
calendar: calendar,
range: [traceStart, Axes.tickIncrement(traceStart, binOpts.size, false, calendar)].map(pa.l2r)
};
var newStart = Axes.tickFirst(dummyAx);
if (newStart > pa.r2l(traceStart)) {
newStart = Axes.tickIncrement(newStart, binOpts.size, true, calendar);
}
traceBinOptsCalc.start = pa.l2r(newStart);
if (!hasStart) Lib.nestedProperty(trace, binAttr + '.start').set(traceBinOptsCalc.start);
}
var mainEnd = binOpts.end;
var endIn = pa.r2l(traceInputBins.end);
var hasEnd = endIn !== undefined;
if ((binOpts.endFound || hasEnd) && endIn !== pa.r2l(mainEnd)) {
// Reconciling an explicit end is easier, as it doesn't need to
// match bin edges
var traceEnd = hasEnd ? endIn : Lib.aggNums(Math.max, null, pos0);
traceBinOptsCalc.end = pa.l2r(traceEnd);
if (!hasEnd) Lib.nestedProperty(trace, binAttr + '.start').set(traceBinOptsCalc.end);
}
// Backward compatibility for one-time autobinning.
// autobin: true is handled in cleanData, but autobin: false
// needs to be here where we have determined the values.
var autoBinAttr = 'autobin' + mainData;
if (trace._input[autoBinAttr] === false) {
trace._input[binAttr] = Lib.extendFlat({}, trace[binAttr] || {});
delete trace._input[autoBinAttr];
delete trace[autoBinAttr];
}
return [traceBinOptsCalc, pos0];
}
/*
* Adjust single-value histograms in overlay mode to make as good a
* guess as we can at autobin values the user would like.
*
* Returns the binSpec for the trace that sparked all this
*/
function handleSingleValueOverlays(gd, trace, pa, mainData, binAttr) {
var fullLayout = gd._fullLayout;
var overlaidTraceGroup = getConnectedHistograms(gd, trace);
var pastThisTrace = false;
var minSize = Infinity;
var singleValuedTraces = [trace];
var i, tracei, binOpts;
// first collect all the:
// - min bin size from all multi-valued traces
// - single-valued traces
for (i = 0; i < overlaidTraceGroup.length; i++) {
tracei = overlaidTraceGroup[i];
if (tracei === trace) {
pastThisTrace = true;
} else if (!pastThisTrace) {
// This trace has already had its autobins calculated, so either:
// - it is part of a bingroup
// - it is NOT a single-valued trace
binOpts = fullLayout._histogramBinOpts[tracei['_' + mainData + 'bingroup']];
minSize = Math.min(minSize, binOpts.size || tracei[binAttr].size);
} else {
var resulti = calcAllAutoBins(gd, tracei, pa, mainData, true);
var binSpeci = resulti[0];
var isSingleValued = resulti[2];
// so we can use this result when we get to tracei in the normal
// course of events, mark it as done and put _pos0 back
tracei['_' + mainData + 'autoBinFinished'] = 1;
tracei['_' + mainData + 'pos0'] = resulti[1];
if (isSingleValued) {
singleValuedTraces.push(tracei);
} else {
minSize = Math.min(minSize, binSpeci.size);
}
}
}
// find the real data values for each single-valued trace
// hunt through pos0 for the first valid value
var dataVals = new Array(singleValuedTraces.length);
for (i = 0; i < singleValuedTraces.length; i++) {
var pos0 = singleValuedTraces[i]['_' + mainData + 'pos0'];
for (var j = 0; j < pos0.length; j++) {
if (pos0[j] !== undefined) {
dataVals[i] = pos0[j];
break;
}
}
}
// are ALL traces are single-valued? use the min difference between
// all of their values (which defaults to 1 if there's still only one)
if (!isFinite(minSize)) {
minSize = Lib.distinctVals(dataVals).minDiff;
}
// now apply the min size we found to all single-valued traces
for (i = 0; i < singleValuedTraces.length; i++) {
tracei = singleValuedTraces[i];
var calendar = tracei[mainData + 'calendar'];
var newBins = {
start: pa.c2r(dataVals[i] - minSize / 2, 0, calendar),
end: pa.c2r(dataVals[i] + minSize / 2, 0, calendar),
size: minSize
};
tracei._input[binAttr] = tracei[binAttr] = newBins;
binOpts = fullLayout._histogramBinOpts[tracei['_' + mainData + 'bingroup']];
if (binOpts) Lib.extendFlat(binOpts, newBins);
}
return trace[binAttr];
}
/*
* Return an array of histograms that share axes and orientation.
*
* Only considers histograms. In principle we could include bars in a
* similar way to how we do manually binned histograms, though this
* would have tons of edge cases and value judgments to make.
*/
function getConnectedHistograms(gd, trace) {
var xid = trace.xaxis;
var yid = trace.yaxis;
var orientation = trace.orientation;
var out = [];
var fullData = gd._fullData;
for (var i = 0; i < fullData.length; i++) {
var tracei = fullData[i];
if (tracei.type === 'histogram' && tracei.visible === true && tracei.orientation === orientation && tracei.xaxis === xid && tracei.yaxis === yid) {
out.push(tracei);
}
}
return out;
}
function cdf(size, direction, currentBin) {
var i, vi, prevSum;
function firstHalfPoint(i) {
prevSum = size[i];
size[i] /= 2;
}
function nextHalfPoint(i) {
vi = size[i];
size[i] = prevSum + vi / 2;
prevSum += vi;
}
if (currentBin === 'half') {
if (direction === 'increasing') {
firstHalfPoint(0);
for (i = 1; i < size.length; i++) {
nextHalfPoint(i);
}
} else {
firstHalfPoint(size.length - 1);
for (i = size.length - 2; i >= 0; i--) {
nextHalfPoint(i);
}
}
} else if (direction === 'increasing') {
for (i = 1; i < size.length; i++) {
size[i] += size[i - 1];
}
// 'exclude' is identical to 'include' just shifted one bin over
if (currentBin === 'exclude') {
size.unshift(0);
size.pop();
}
} else {
for (i = size.length - 2; i >= 0; i--) {
size[i] += size[i + 1];
}
if (currentBin === 'exclude') {
size.push(0);
size.shift();
}
}
}
module.exports = {
calc: calc,
calcAllAutoBins: calcAllAutoBins
};
/***/ }),
/***/ 18584:
/***/ (function(module) {
"use strict";
module.exports = {
eventDataKeys: ['binNumber']
};
/***/ }),
/***/ 91388:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var axisIds = __webpack_require__(21504);
var traceIs = (__webpack_require__(30364).traceIs);
var handleGroupingDefaults = __webpack_require__(8584);
var validateCornerradius = (__webpack_require__(49520).validateCornerradius);
var nestedProperty = Lib.nestedProperty;
var getAxisGroup = (__webpack_require__(76908).getAxisGroup);
var BINATTRS = [{
aStr: {
x: 'xbins.start',
y: 'ybins.start'
},
name: 'start'
}, {
aStr: {
x: 'xbins.end',
y: 'ybins.end'
},
name: 'end'
}, {
aStr: {
x: 'xbins.size',
y: 'ybins.size'
},
name: 'size'
}, {
aStr: {
x: 'nbinsx',
y: 'nbinsy'
},
name: 'nbins'
}];
var BINDIRECTIONS = ['x', 'y'];
// handle bin attrs and relink auto-determined values so fullData is complete
module.exports = function crossTraceDefaults(fullData, fullLayout) {
var allBinOpts = fullLayout._histogramBinOpts = {};
var histTraces = [];
var mustMatchTracesLookup = {};
var otherTracesList = [];
var traceOut, traces, groupName, binDir;
var i, j, k;
function coerce(attr, dflt) {
return Lib.coerce(traceOut._input, traceOut, traceOut._module.attributes, attr, dflt);
}
function orientation2binDir(traceOut) {
return traceOut.orientation === 'v' ? 'x' : 'y';
}
function getAxisType(traceOut, binDir) {
var ax = axisIds.getFromTrace({
_fullLayout: fullLayout
}, traceOut, binDir);
return ax.type;
}
function fillBinOpts(traceOut, groupName, binDir) {
// N.B. group traces that don't have a bingroup with themselves
var fallbackGroupName = traceOut.uid + '__' + binDir;
if (!groupName) groupName = fallbackGroupName;
var axType = getAxisType(traceOut, binDir);
var calendar = traceOut[binDir + 'calendar'] || '';
var binOpts = allBinOpts[groupName];
var needsNewItem = true;
if (binOpts) {
if (axType === binOpts.axType && calendar === binOpts.calendar) {
needsNewItem = false;
binOpts.traces.push(traceOut);
binOpts.dirs.push(binDir);
} else {
groupName = fallbackGroupName;
if (axType !== binOpts.axType) {
Lib.warn(['Attempted to group the bins of trace', traceOut.index, 'set on a', 'type:' + axType, 'axis', 'with bins on', 'type:' + binOpts.axType, 'axis.'].join(' '));
}
if (calendar !== binOpts.calendar) {
// prohibit bingroup for traces using different calendar,
// there's probably a way to make this work, but skip for now
Lib.warn(['Attempted to group the bins of trace', traceOut.index, 'set with a', calendar, 'calendar', 'with bins', binOpts.calendar ? 'on a ' + binOpts.calendar + ' calendar' : 'w/o a set calendar'].join(' '));
}
}
}
if (needsNewItem) {
allBinOpts[groupName] = {
traces: [traceOut],
dirs: [binDir],
axType: axType,
calendar: traceOut[binDir + 'calendar'] || ''
};
}
traceOut['_' + binDir + 'bingroup'] = groupName;
}
for (i = 0; i < fullData.length; i++) {
traceOut = fullData[i];
if (traceIs(traceOut, 'histogram')) {
histTraces.push(traceOut);
// TODO: this shouldn't be relinked as it's only used within calc
// https://github.com/plotly/plotly.js/issues/749
delete traceOut._xautoBinFinished;
delete traceOut._yautoBinFinished;
if (traceOut.type === 'histogram') {
var r = coerce('marker.cornerradius', fullLayout.barcornerradius);
if (traceOut.marker) {
traceOut.marker.cornerradius = validateCornerradius(r);
}
}
// N.B. need to coerce *alignmentgroup* before *bingroup*, as traces
// in same alignmentgroup "have to match"
if (!traceIs(traceOut, '2dMap')) {
handleGroupingDefaults(traceOut._input, traceOut, fullLayout, coerce);
}
}
}
var alignmentOpts = fullLayout._alignmentOpts || {};
// Look for traces that "have to match", that is:
// - 1d histogram traces on the same subplot with same orientation under barmode:stack,
// - 1d histogram traces on the same subplot with same orientation under barmode:group
// - 1d histogram traces on the same position axis with the same orientation
// and the same *alignmentgroup* (coerced under barmode:group)
// - Once `stackgroup` gets implemented (see https://github.com/plotly/plotly.js/issues/3614),
// traces within the same stackgroup will also "have to match"
for (i = 0; i < histTraces.length; i++) {
traceOut = histTraces[i];
groupName = '';
if (!traceIs(traceOut, '2dMap')) {
binDir = orientation2binDir(traceOut);
if (fullLayout.barmode === 'group' && traceOut.alignmentgroup) {
var pa = traceOut[binDir + 'axis'];
var aGroupId = getAxisGroup(fullLayout, pa) + traceOut.orientation;
if ((alignmentOpts[aGroupId] || {})[traceOut.alignmentgroup]) {
groupName = aGroupId;
}
}
if (!groupName && fullLayout.barmode !== 'overlay') {
groupName = getAxisGroup(fullLayout, traceOut.xaxis) + getAxisGroup(fullLayout, traceOut.yaxis) + orientation2binDir(traceOut);
}
}
if (groupName) {
if (!mustMatchTracesLookup[groupName]) {
mustMatchTracesLookup[groupName] = [];
}
mustMatchTracesLookup[groupName].push(traceOut);
} else {
otherTracesList.push(traceOut);
}
}
// Setup binOpts for traces that have to match,
// if the traces have a valid bingroup, use that
// if not use axis+binDir groupName
for (groupName in mustMatchTracesLookup) {
traces = mustMatchTracesLookup[groupName];
// no need to 'force' anything when a single
// trace is detected as "must match"
if (traces.length === 1) {
otherTracesList.push(traces[0]);
continue;
}
var binGroupFound = false;
if (traces.length) {
traceOut = traces[0];
binGroupFound = coerce('bingroup');
}
groupName = binGroupFound || groupName;
for (i = 0; i < traces.length; i++) {
traceOut = traces[i];
var bingroupIn = traceOut._input.bingroup;
if (bingroupIn && bingroupIn !== groupName) {
Lib.warn(['Trace', traceOut.index, 'must match', 'within bingroup', groupName + '.', 'Ignoring its bingroup:', bingroupIn, 'setting.'].join(' '));
}
traceOut.bingroup = groupName;
// N.B. no need to worry about 2dMap case
// (where both bin direction are set in each trace)
// as 2dMap trace never "have to match"
fillBinOpts(traceOut, groupName, orientation2binDir(traceOut));
}
}
// setup binOpts for traces that can but don't have to match,
// notice that these traces can be matched with traces that have to match
for (i = 0; i < otherTracesList.length; i++) {
traceOut = otherTracesList[i];
var binGroup = coerce('bingroup');
if (traceIs(traceOut, '2dMap')) {
for (k = 0; k < 2; k++) {
binDir = BINDIRECTIONS[k];
var binGroupInDir = coerce(binDir + 'bingroup', binGroup ? binGroup + '__' + binDir : null);
fillBinOpts(traceOut, binGroupInDir, binDir);
}
} else {
fillBinOpts(traceOut, binGroup, orientation2binDir(traceOut));
}
}
// coerce bin attrs!
for (groupName in allBinOpts) {
var binOpts = allBinOpts[groupName];
traces = binOpts.traces;
for (j = 0; j < BINATTRS.length; j++) {
var attrSpec = BINATTRS[j];
var attr = attrSpec.name;
var aStr;
var autoVals;
// nbins(x|y) is moot if we have a size. This depends on
// nbins coming after size in binAttrs.
if (attr === 'nbins' && binOpts.sizeFound) continue;
for (i = 0; i < traces.length; i++) {
traceOut = traces[i];
binDir = binOpts.dirs[i];
aStr = attrSpec.aStr[binDir];
if (nestedProperty(traceOut._input, aStr).get() !== undefined) {
binOpts[attr] = coerce(aStr);
binOpts[attr + 'Found'] = true;
break;
}
autoVals = (traceOut._autoBin || {})[binDir] || {};
if (autoVals[attr]) {
// if this is the *first* autoval
nestedProperty(traceOut, aStr).set(autoVals[attr]);
}
}
// start and end we need to coerce anyway, after having collected the
// first of each into binOpts, in case a trace wants to restrict its
// data to a certain range
if (attr === 'start' || attr === 'end') {
for (; i < traces.length; i++) {
traceOut = traces[i];
if (traceOut['_' + binDir + 'bingroup']) {
autoVals = (traceOut._autoBin || {})[binDir] || {};
coerce(aStr, autoVals[attr]);
}
}
}
if (attr === 'nbins' && !binOpts.sizeFound && !binOpts.nbinsFound) {
traceOut = traces[0];
binOpts[attr] = coerce(aStr);
}
}
}
};
/***/ }),
/***/ 19484:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var Color = __webpack_require__(9240);
var handleText = (__webpack_require__(49520).handleText);
var handleStyleDefaults = __webpack_require__(37408);
var attributes = __webpack_require__(82264);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var x = coerce('x');
var y = coerce('y');
var cumulative = coerce('cumulative.enabled');
if (cumulative) {
coerce('cumulative.direction');
coerce('cumulative.currentbin');
}
coerce('text');
var textposition = coerce('textposition');
handleText(traceIn, traceOut, layout, coerce, textposition, {
moduleHasSelected: true,
moduleHasUnselected: true,
moduleHasConstrain: true,
moduleHasCliponaxis: true,
moduleHasTextangle: true,
moduleHasInsideanchor: true
});
coerce('hovertext');
coerce('hovertemplate');
coerce('xhoverformat');
coerce('yhoverformat');
var orientation = coerce('orientation', y && !x ? 'h' : 'v');
var sampleLetter = orientation === 'v' ? 'x' : 'y';
var aggLetter = orientation === 'v' ? 'y' : 'x';
var len = x && y ? Math.min(Lib.minRowLength(x) && Lib.minRowLength(y)) : Lib.minRowLength(traceOut[sampleLetter] || []);
if (!len) {
traceOut.visible = false;
return;
}
traceOut._length = len;
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x', 'y'], layout);
var hasAggregationData = traceOut[aggLetter];
if (hasAggregationData) coerce('histfunc');
coerce('histnorm');
// Note: bin defaults are now handled in Histogram.crossTraceDefaults
// autobin(x|y) are only included here to appease Plotly.validate
coerce('autobin' + sampleLetter);
handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout);
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
var lineColor = (traceOut.marker.line || {}).color;
// override defaultColor for error bars with defaultLine
var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults');
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || Color.defaultLine, {
axis: 'y'
});
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || Color.defaultLine, {
axis: 'x',
inherit: 'y'
});
coerce('zorder');
};
/***/ }),
/***/ 1572:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt, trace, cd, pointNumber) {
// standard cartesian event data
out.x = 'xVal' in pt ? pt.xVal : pt.x;
out.y = 'yVal' in pt ? pt.yVal : pt.y;
// for 2d histograms
if ('zLabelVal' in pt) out.z = pt.zLabelVal;
if (pt.xa) out.xaxis = pt.xa;
if (pt.ya) out.yaxis = pt.ya;
// specific to histogram - CDFs do not have pts (yet?)
if (!(trace.cumulative || {}).enabled) {
var pts = Array.isArray(pointNumber) ? cd[0].pts[pointNumber[0]][pointNumber[1]] : cd[pointNumber].pts;
out.pointNumbers = pts;
out.binNumber = out.pointNumber;
delete out.pointNumber;
delete out.pointIndex;
var pointIndices;
if (trace._indexToPoints) {
pointIndices = [];
for (var i = 0; i < pts.length; i++) {
pointIndices = pointIndices.concat(trace._indexToPoints[pts[i]]);
}
} else {
pointIndices = pts;
}
out.pointIndices = pointIndices;
}
return out;
};
/***/ }),
/***/ 43112:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var barHover = (__webpack_require__(30284).hoverPoints);
var hoverLabelText = (__webpack_require__(81536).hoverLabelText);
module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) {
var pts = barHover(pointData, xval, yval, hovermode, opts);
if (!pts) return;
pointData = pts[0];
var di = pointData.cd[pointData.index];
var trace = pointData.cd[0].trace;
if (!trace.cumulative.enabled) {
var posLetter = trace.orientation === 'h' ? 'y' : 'x';
pointData[posLetter + 'Label'] = hoverLabelText(pointData[posLetter + 'a'], [di.ph0, di.ph1], trace[posLetter + 'hoverformat']);
}
return pts;
};
/***/ }),
/***/ 8928:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
/**
* Histogram has its own attribute, defaults and calc steps,
* but uses bar's plot to display
* and bar's crossTraceCalc (formerly known as setPositions) for stacking and grouping
*/
/**
* histogram errorBarsOK is debatable, but it's put in for backward compat.
* there are use cases for it - sqrt for a simple histogram works right now,
* constant and % work but they're not so meaningful. I guess it could be cool
* to allow quadrature combination of errors in summed histograms...
*/
module.exports = {
attributes: __webpack_require__(82264),
layoutAttributes: __webpack_require__(90192),
supplyDefaults: __webpack_require__(19484),
crossTraceDefaults: __webpack_require__(91388),
supplyLayoutDefaults: __webpack_require__(38700),
calc: (__webpack_require__(95468).calc),
crossTraceCalc: (__webpack_require__(2616).crossTraceCalc),
plot: (__webpack_require__(39176).plot),
layerName: 'barlayer',
style: (__webpack_require__(21212).style),
styleOnSelect: (__webpack_require__(21212).styleOnSelect),
colorbar: __webpack_require__(71416),
hoverPoints: __webpack_require__(43112),
selectPoints: __webpack_require__(10512),
eventData: __webpack_require__(1572),
moduleType: 'trace',
name: 'histogram',
basePlotModule: __webpack_require__(34316),
categories: ['bar-like', 'cartesian', 'svg', 'bar', 'histogram', 'oriented', 'errorBarsOK', 'showLegend'],
meta: {
description: ['The sample data from which statistics are computed is set in `x`', 'for vertically spanning histograms and', 'in `y` for horizontally spanning histograms.', 'Binning options are set `xbins` and `ybins` respectively', 'if no aggregation data is provided.'].join(' ')
}
};
/***/ }),
/***/ 42908:
/***/ (function(module) {
"use strict";
module.exports = {
percent: function (size, total) {
var nMax = size.length;
var norm = 100 / total;
for (var n = 0; n < nMax; n++) size[n] *= norm;
},
probability: function (size, total) {
var nMax = size.length;
for (var n = 0; n < nMax; n++) size[n] /= total;
},
density: function (size, total, inc, yinc) {
var nMax = size.length;
yinc = yinc || 1;
for (var n = 0; n < nMax; n++) size[n] *= inc[n] * yinc;
},
'probability density': function (size, total, inc, yinc) {
var nMax = size.length;
if (yinc) total /= yinc;
for (var n = 0; n < nMax; n++) size[n] *= inc[n] / total;
}
};
/***/ }),
/***/ 90229:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var histogramAttrs = __webpack_require__(82264);
var makeBinAttrs = __webpack_require__(40184);
var heatmapAttrs = __webpack_require__(7944);
var baseAttrs = __webpack_require__(6040);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var colorScaleAttrs = __webpack_require__(99732);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = extendFlat({
x: histogramAttrs.x,
y: histogramAttrs.y,
z: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the aggregation data.'
},
marker: {
color: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the aggregation data.'
},
editType: 'calc'
},
histnorm: histogramAttrs.histnorm,
histfunc: histogramAttrs.histfunc,
nbinsx: histogramAttrs.nbinsx,
xbins: makeBinAttrs('x'),
nbinsy: histogramAttrs.nbinsy,
ybins: makeBinAttrs('y'),
autobinx: histogramAttrs.autobinx,
autobiny: histogramAttrs.autobiny,
bingroup: extendFlat({}, histogramAttrs.bingroup, {
description: ['Set the `xbingroup` and `ybingroup` default prefix', 'For example, setting a `bingroup` of *1* on two histogram2d traces', 'will make them their x-bins and y-bins match separately.'].join(' ')
}),
xbingroup: extendFlat({}, histogramAttrs.bingroup, {
description: ['Set a group of histogram traces which will have compatible x-bin settings.', 'Using `xbingroup`, histogram2d and histogram2dcontour traces ', '(on axes of the same axis type) can have compatible x-bin settings.', 'Note that the same `xbingroup` value can be used to set (1D) histogram `bingroup`'].join(' ')
}),
ybingroup: extendFlat({}, histogramAttrs.bingroup, {
description: ['Set a group of histogram traces which will have compatible y-bin settings.', 'Using `ybingroup`, histogram2d and histogram2dcontour traces ', '(on axes of the same axis type) can have compatible y-bin settings.', 'Note that the same `ybingroup` value can be used to set (1D) histogram `bingroup`'].join(' ')
}),
xgap: heatmapAttrs.xgap,
ygap: heatmapAttrs.ygap,
zsmooth: heatmapAttrs.zsmooth,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z', 1),
hovertemplate: hovertemplateAttrs({}, {
keys: 'z'
}),
texttemplate: texttemplateAttrs({
arrayOk: false,
editType: 'plot'
}, {
keys: 'z'
}),
textfont: heatmapAttrs.textfont,
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
}, colorScaleAttrs('', {
cLetter: 'z',
autoColorDflt: false
}));
/***/ }),
/***/ 28824:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Axes = __webpack_require__(81536);
var binFunctions = __webpack_require__(74080);
var normFunctions = __webpack_require__(42908);
var doAvg = __webpack_require__(86488);
var getBinSpanLabelRound = __webpack_require__(49848);
var calcAllAutoBins = (__webpack_require__(95468).calcAllAutoBins);
module.exports = function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis);
var ya = Axes.getFromId(gd, trace.yaxis);
var xcalendar = trace.xcalendar;
var ycalendar = trace.ycalendar;
var xr2c = function (v) {
return xa.r2c(v, 0, xcalendar);
};
var yr2c = function (v) {
return ya.r2c(v, 0, ycalendar);
};
var xc2r = function (v) {
return xa.c2r(v, 0, xcalendar);
};
var yc2r = function (v) {
return ya.c2r(v, 0, ycalendar);
};
var i, j, n, m;
// calculate the bins
var xBinsAndPos = calcAllAutoBins(gd, trace, xa, 'x');
var xBinSpec = xBinsAndPos[0];
var xPos0 = xBinsAndPos[1];
var yBinsAndPos = calcAllAutoBins(gd, trace, ya, 'y');
var yBinSpec = yBinsAndPos[0];
var yPos0 = yBinsAndPos[1];
var serieslen = trace._length;
if (xPos0.length > serieslen) xPos0.splice(serieslen, xPos0.length - serieslen);
if (yPos0.length > serieslen) yPos0.splice(serieslen, yPos0.length - serieslen);
// make the empty bin array & scale the map
var z = [];
var onecol = [];
var zerocol = [];
var nonuniformBinsX = typeof xBinSpec.size === 'string';
var nonuniformBinsY = typeof yBinSpec.size === 'string';
var xEdges = [];
var yEdges = [];
var xbins = nonuniformBinsX ? xEdges : xBinSpec;
var ybins = nonuniformBinsY ? yEdges : yBinSpec;
var total = 0;
var counts = [];
var inputPoints = [];
var norm = trace.histnorm;
var func = trace.histfunc;
var densitynorm = norm.indexOf('density') !== -1;
var extremefunc = func === 'max' || func === 'min';
var sizeinit = extremefunc ? null : 0;
var binfunc = binFunctions.count;
var normfunc = normFunctions[norm];
var doavg = false;
var xinc = [];
var yinc = [];
// set a binning function other than count?
// for binning functions: check first for 'z',
// then 'mc' in case we had a colored scatter plot
// and want to transfer these colors to the 2D histo
// TODO: axe this, make it the responsibility of the app changing type? or an impliedEdit?
var rawCounterData = 'z' in trace ? trace.z : 'marker' in trace && Array.isArray(trace.marker.color) ? trace.marker.color : '';
if (rawCounterData && func !== 'count') {
doavg = func === 'avg';
binfunc = binFunctions[func];
}
// decrease end a little in case of rounding errors
var xBinSize = xBinSpec.size;
var xBinStart = xr2c(xBinSpec.start);
var xBinEnd = xr2c(xBinSpec.end) + (xBinStart - Axes.tickIncrement(xBinStart, xBinSize, false, xcalendar)) / 1e6;
for (i = xBinStart; i < xBinEnd; i = Axes.tickIncrement(i, xBinSize, false, xcalendar)) {
onecol.push(sizeinit);
xEdges.push(i);
if (doavg) zerocol.push(0);
}
xEdges.push(i);
var nx = onecol.length;
var dx = (i - xBinStart) / nx;
var x0 = xc2r(xBinStart + dx / 2);
var yBinSize = yBinSpec.size;
var yBinStart = yr2c(yBinSpec.start);
var yBinEnd = yr2c(yBinSpec.end) + (yBinStart - Axes.tickIncrement(yBinStart, yBinSize, false, ycalendar)) / 1e6;
for (i = yBinStart; i < yBinEnd; i = Axes.tickIncrement(i, yBinSize, false, ycalendar)) {
z.push(onecol.slice());
yEdges.push(i);
var ipCol = new Array(nx);
for (j = 0; j < nx; j++) ipCol[j] = [];
inputPoints.push(ipCol);
if (doavg) counts.push(zerocol.slice());
}
yEdges.push(i);
var ny = z.length;
var dy = (i - yBinStart) / ny;
var y0 = yc2r(yBinStart + dy / 2);
if (densitynorm) {
xinc = makeIncrements(onecol.length, xbins, dx, nonuniformBinsX);
yinc = makeIncrements(z.length, ybins, dy, nonuniformBinsY);
}
// for date axes we need bin bounds to be calcdata. For nonuniform bins
// we already have this, but uniform with start/end/size they're still strings.
if (!nonuniformBinsX && xa.type === 'date') xbins = binsToCalc(xr2c, xbins);
if (!nonuniformBinsY && ya.type === 'date') ybins = binsToCalc(yr2c, ybins);
// put data into bins
var uniqueValsPerX = true;
var uniqueValsPerY = true;
var xVals = new Array(nx);
var yVals = new Array(ny);
var xGapLow = Infinity;
var xGapHigh = Infinity;
var yGapLow = Infinity;
var yGapHigh = Infinity;
for (i = 0; i < serieslen; i++) {
var xi = xPos0[i];
var yi = yPos0[i];
n = Lib.findBin(xi, xbins);
m = Lib.findBin(yi, ybins);
if (n >= 0 && n < nx && m >= 0 && m < ny) {
total += binfunc(n, i, z[m], rawCounterData, counts[m]);
inputPoints[m][n].push(i);
if (uniqueValsPerX) {
if (xVals[n] === undefined) xVals[n] = xi;else if (xVals[n] !== xi) uniqueValsPerX = false;
}
if (uniqueValsPerY) {
if (yVals[m] === undefined) yVals[m] = yi;else if (yVals[m] !== yi) uniqueValsPerY = false;
}
xGapLow = Math.min(xGapLow, xi - xEdges[n]);
xGapHigh = Math.min(xGapHigh, xEdges[n + 1] - xi);
yGapLow = Math.min(yGapLow, yi - yEdges[m]);
yGapHigh = Math.min(yGapHigh, yEdges[m + 1] - yi);
}
}
// normalize, if needed
if (doavg) {
for (m = 0; m < ny; m++) total += doAvg(z[m], counts[m]);
}
if (normfunc) {
for (m = 0; m < ny; m++) normfunc(z[m], total, xinc, yinc[m]);
}
return {
x: xPos0,
xRanges: getRanges(xEdges, uniqueValsPerX && xVals, xGapLow, xGapHigh, xa, xcalendar),
x0: x0,
dx: dx,
y: yPos0,
yRanges: getRanges(yEdges, uniqueValsPerY && yVals, yGapLow, yGapHigh, ya, ycalendar),
y0: y0,
dy: dy,
z: z,
pts: inputPoints
};
};
function makeIncrements(len, bins, dv, nonuniform) {
var out = new Array(len);
var i;
if (nonuniform) {
for (i = 0; i < len; i++) out[i] = 1 / (bins[i + 1] - bins[i]);
} else {
var inc = 1 / dv;
for (i = 0; i < len; i++) out[i] = inc;
}
return out;
}
function binsToCalc(r2c, bins) {
return {
start: r2c(bins.start),
end: r2c(bins.end),
size: bins.size
};
}
function getRanges(edges, uniqueVals, gapLow, gapHigh, ax, calendar) {
var i;
var len = edges.length - 1;
var out = new Array(len);
var roundFn = getBinSpanLabelRound(gapLow, gapHigh, edges, ax, calendar);
for (i = 0; i < len; i++) {
var v = (uniqueVals || [])[i];
out[i] = v === undefined ? [roundFn(edges[i]), roundFn(edges[i + 1], true)] : [v, v];
}
return out;
}
/***/ }),
/***/ 72456:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleSampleDefaults = __webpack_require__(50152);
var handleStyleDefaults = __webpack_require__(39012);
var colorscaleDefaults = __webpack_require__(47280);
var handleHeatmapLabelDefaults = __webpack_require__(20152);
var attributes = __webpack_require__(90229);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
handleSampleDefaults(traceIn, traceOut, coerce, layout);
if (traceOut.visible === false) return;
handleStyleDefaults(traceIn, traceOut, coerce, layout);
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'z'
});
coerce('hovertemplate');
handleHeatmapLabelDefaults(coerce, layout);
coerce('xhoverformat');
coerce('yhoverformat');
};
/***/ }),
/***/ 63160:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var heatmapHover = __webpack_require__(41864);
var hoverLabelText = (__webpack_require__(81536).hoverLabelText);
module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) {
var pts = heatmapHover(pointData, xval, yval, hovermode, opts);
if (!pts) return;
pointData = pts[0];
var indices = pointData.index;
var ny = indices[0];
var nx = indices[1];
var cd0 = pointData.cd[0];
var trace = cd0.trace;
var xRange = cd0.xRanges[nx];
var yRange = cd0.yRanges[ny];
pointData.xLabel = hoverLabelText(pointData.xa, [xRange[0], xRange[1]], trace.xhoverformat);
pointData.yLabel = hoverLabelText(pointData.ya, [yRange[0], yRange[1]], trace.yhoverformat);
return pts;
};
/***/ }),
/***/ 52720:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(90229),
supplyDefaults: __webpack_require__(72456),
crossTraceDefaults: __webpack_require__(91388),
calc: __webpack_require__(53984),
plot: __webpack_require__(97440),
layerName: 'heatmaplayer',
colorbar: __webpack_require__(72680),
style: __webpack_require__(47824),
hoverPoints: __webpack_require__(63160),
eventData: __webpack_require__(1572),
moduleType: 'trace',
name: 'histogram2d',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', '2dMap', 'histogram', 'showLegend'],
meta: {
hrName: 'histogram_2d',
description: ['The sample data from which statistics are computed is set in `x`', 'and `y` (where `x` and `y` represent marginal distributions,', 'binning is set in `xbins` and `ybins` in this case)', 'or `z` (where `z` represent the 2D distribution and binning set,', 'binning is set by `x` and `y` in this case).', 'The resulting distribution is visualized as a heatmap.'].join(' ')
}
};
/***/ }),
/***/ 50152:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
module.exports = function handleSampleDefaults(traceIn, traceOut, coerce, layout) {
var x = coerce('x');
var y = coerce('y');
var xlen = Lib.minRowLength(x);
var ylen = Lib.minRowLength(y);
// we could try to accept x0 and dx, etc...
// but that's a pretty weird use case.
// for now require both x and y explicitly specified.
if (!xlen || !ylen) {
traceOut.visible = false;
return;
}
traceOut._length = Math.min(xlen, ylen);
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x', 'y'], layout);
// if marker.color is an array, we can use it in aggregation instead of z
var hasAggregationData = coerce('z') || coerce('marker.color');
if (hasAggregationData) coerce('histfunc');
coerce('histnorm');
// Note: bin defaults are now handled in Histogram2D.crossTraceDefaults
// autobin(x|y) are only included here to appease Plotly.validate
coerce('autobinx');
coerce('autobiny');
};
/***/ }),
/***/ 17032:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var histogram2dAttrs = __webpack_require__(90229);
var contourAttrs = __webpack_require__(12115);
var colorScaleAttrs = __webpack_require__(99732);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = extendFlat({
x: histogram2dAttrs.x,
y: histogram2dAttrs.y,
z: histogram2dAttrs.z,
marker: histogram2dAttrs.marker,
histnorm: histogram2dAttrs.histnorm,
histfunc: histogram2dAttrs.histfunc,
nbinsx: histogram2dAttrs.nbinsx,
xbins: histogram2dAttrs.xbins,
nbinsy: histogram2dAttrs.nbinsy,
ybins: histogram2dAttrs.ybins,
autobinx: histogram2dAttrs.autobinx,
autobiny: histogram2dAttrs.autobiny,
bingroup: histogram2dAttrs.bingroup,
xbingroup: histogram2dAttrs.xbingroup,
ybingroup: histogram2dAttrs.ybingroup,
autocontour: contourAttrs.autocontour,
ncontours: contourAttrs.ncontours,
contours: contourAttrs.contours,
line: {
color: contourAttrs.line.color,
width: extendFlat({}, contourAttrs.line.width, {
dflt: 0.5,
description: 'Sets the contour line width in (in px)'
}),
dash: contourAttrs.line.dash,
smoothing: contourAttrs.line.smoothing,
editType: 'plot'
},
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z', 1),
hovertemplate: histogram2dAttrs.hovertemplate,
texttemplate: contourAttrs.texttemplate,
textfont: contourAttrs.textfont
}, colorScaleAttrs('', {
cLetter: 'z',
editTypeOverride: 'calc'
}));
/***/ }),
/***/ 13844:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleSampleDefaults = __webpack_require__(50152);
var handleContoursDefaults = __webpack_require__(5032);
var handleStyleDefaults = __webpack_require__(38936);
var handleHeatmapLabelDefaults = __webpack_require__(20152);
var attributes = __webpack_require__(17032);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
function coerce2(attr) {
return Lib.coerce2(traceIn, traceOut, attributes, attr);
}
handleSampleDefaults(traceIn, traceOut, coerce, layout);
if (traceOut.visible === false) return;
handleContoursDefaults(traceIn, traceOut, coerce, coerce2);
handleStyleDefaults(traceIn, traceOut, coerce, layout);
coerce('xhoverformat');
coerce('yhoverformat');
coerce('hovertemplate');
if (traceOut.contours && traceOut.contours.coloring === 'heatmap') {
handleHeatmapLabelDefaults(coerce, layout);
}
};
/***/ }),
/***/ 39972:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(17032),
supplyDefaults: __webpack_require__(13844),
crossTraceDefaults: __webpack_require__(91388),
calc: __webpack_require__(50820),
plot: (__webpack_require__(7344).plot),
layerName: 'contourlayer',
style: __webpack_require__(46496),
colorbar: __webpack_require__(50128),
hoverPoints: __webpack_require__(93452),
moduleType: 'trace',
name: 'histogram2dcontour',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', '2dMap', 'contour', 'histogram', 'showLegend'],
meta: {
hrName: 'histogram_2d_contour',
description: ['The sample data from which statistics are computed is set in `x`', 'and `y` (where `x` and `y` represent marginal distributions,', 'binning is set in `xbins` and `ybins` in this case)', 'or `z` (where `z` represent the 2D distribution and binning set,', 'binning is set by `x` and `y` in this case).', 'The resulting distribution is visualized as a contour plot.'].join(' ')
}
};
/***/ }),
/***/ 46752:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var colorScaleAttrs = __webpack_require__(99732);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var pieAttrs = __webpack_require__(99644);
var sunburstAttrs = __webpack_require__(36404);
var treemapAttrs = __webpack_require__(36468);
var constants = __webpack_require__(73220);
var extendFlat = (__webpack_require__(55016).extendFlat);
var pattern = (__webpack_require__(9392)/* .pattern */ .c);
module.exports = {
labels: sunburstAttrs.labels,
parents: sunburstAttrs.parents,
values: sunburstAttrs.values,
branchvalues: sunburstAttrs.branchvalues,
count: sunburstAttrs.count,
level: sunburstAttrs.level,
maxdepth: sunburstAttrs.maxdepth,
tiling: {
orientation: {
valType: 'enumerated',
values: ['v', 'h'],
dflt: 'h',
editType: 'plot',
description: ['When set in conjunction with `tiling.flip`, determines on', 'which side the root nodes are drawn in the chart. If', '`tiling.orientation` is *v* and `tiling.flip` is **, the root', 'nodes appear at the top. If `tiling.orientation` is *v* and', '`tiling.flip` is *y*, the root nodes appear at the bottom. If', '`tiling.orientation` is *h* and `tiling.flip` is **, the', 'root nodes appear at the left. If `tiling.orientation` is *h*', 'and `tiling.flip` is *x*, the root nodes appear at the right.'].join(' ')
},
flip: treemapAttrs.tiling.flip,
pad: {
valType: 'number',
min: 0,
dflt: 0,
editType: 'plot',
description: ['Sets the inner padding (in px).'].join(' ')
},
editType: 'calc'
},
marker: extendFlat({
colors: sunburstAttrs.marker.colors,
line: sunburstAttrs.marker.line,
pattern: pattern,
editType: 'calc'
}, colorScaleAttrs('marker', {
colorAttr: 'colors',
anim: false // TODO: set to anim: true?
})),
leaf: sunburstAttrs.leaf,
pathbar: treemapAttrs.pathbar,
text: pieAttrs.text,
textinfo: sunburstAttrs.textinfo,
// TODO: incorporate `label` and `value` in the eventData
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: constants.eventDataKeys.concat(['label', 'value'])
}),
hovertext: pieAttrs.hovertext,
hoverinfo: sunburstAttrs.hoverinfo,
hovertemplate: hovertemplateAttrs({}, {
keys: constants.eventDataKeys
}),
textfont: pieAttrs.textfont,
insidetextfont: pieAttrs.insidetextfont,
outsidetextfont: treemapAttrs.outsidetextfont,
textposition: treemapAttrs.textposition,
sort: pieAttrs.sort,
root: sunburstAttrs.root,
domain: domainAttrs({
name: 'icicle',
trace: true,
editType: 'calc'
})
};
/***/ }),
/***/ 1996:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var plots = __webpack_require__(19896);
exports.name = 'icicle';
exports.plot = function (gd, traces, transitionOpts, makeOnCompleteCallback) {
plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout);
};
/***/ }),
/***/ 49471:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var calc = __webpack_require__(45780);
exports.r = function (gd, trace) {
return calc.calc(gd, trace);
};
exports.q = function (gd) {
return calc._runCrossTraceCalc('icicle', gd);
};
/***/ }),
/***/ 67252:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(46752);
var Color = __webpack_require__(9240);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var handleText = (__webpack_require__(49520).handleText);
var TEXTPAD = (__webpack_require__(77216).TEXTPAD);
var handleMarkerDefaults = (__webpack_require__(87048).handleMarkerDefaults);
var Colorscale = __webpack_require__(26733);
var hasColorscale = Colorscale.hasColorscale;
var colorscaleDefaults = Colorscale.handleDefaults;
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var labels = coerce('labels');
var parents = coerce('parents');
if (!labels || !labels.length || !parents || !parents.length) {
traceOut.visible = false;
return;
}
var vals = coerce('values');
if (vals && vals.length) {
coerce('branchvalues');
} else {
coerce('count');
}
coerce('level');
coerce('maxdepth');
coerce('tiling.orientation');
coerce('tiling.flip');
coerce('tiling.pad');
var text = coerce('text');
coerce('texttemplate');
if (!traceOut.texttemplate) coerce('textinfo', Lib.isArrayOrTypedArray(text) ? 'text+label' : 'label');
coerce('hovertext');
coerce('hovertemplate');
var hasPathbar = coerce('pathbar.visible');
var textposition = 'auto';
handleText(traceIn, traceOut, layout, coerce, textposition, {
hasPathbar: hasPathbar,
moduleHasSelected: false,
moduleHasUnselected: false,
moduleHasConstrain: false,
moduleHasCliponaxis: false,
moduleHasTextangle: false,
moduleHasInsideanchor: false
});
coerce('textposition');
handleMarkerDefaults(traceIn, traceOut, layout, coerce);
var withColorscale = traceOut._hasColorscale = hasColorscale(traceIn, 'marker', 'colors') || (traceIn.marker || {}).coloraxis // N.B. special logic to consider "values" colorscales
;
if (withColorscale) {
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'marker.',
cLetter: 'c'
});
}
coerce('leaf.opacity', withColorscale ? 1 : 0.7);
traceOut._hovered = {
marker: {
line: {
width: 2,
color: Color.contrast(layout.paper_bgcolor)
}
}
};
if (hasPathbar) {
// This works even for multi-line labels as icicle pathbar trim out line breaks
coerce('pathbar.thickness', traceOut.pathbar.textfont.size + 2 * TEXTPAD);
coerce('pathbar.side');
coerce('pathbar.edgeshape');
}
coerce('sort');
coerce('root.color');
handleDomainDefaults(traceOut, layout, coerce);
// do not support transforms for now
traceOut._length = null;
};
/***/ }),
/***/ 89452:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var svgTextUtils = __webpack_require__(41536);
var partition = __webpack_require__(97304);
var styleOne = (__webpack_require__(89360).styleOne);
var constants = __webpack_require__(73220);
var helpers = __webpack_require__(54844);
var attachFxHandlers = __webpack_require__(58528);
var formatSliceLabel = (__webpack_require__(35384).formatSliceLabel);
var onPathbar = false; // for Descendants
module.exports = function drawDescendants(gd, cd, entry, slices, opts) {
var width = opts.width;
var height = opts.height;
var viewX = opts.viewX;
var viewY = opts.viewY;
var pathSlice = opts.pathSlice;
var toMoveInsideSlice = opts.toMoveInsideSlice;
var strTransform = opts.strTransform;
var hasTransition = opts.hasTransition;
var handleSlicesExit = opts.handleSlicesExit;
var makeUpdateSliceInterpolator = opts.makeUpdateSliceInterpolator;
var makeUpdateTextInterpolator = opts.makeUpdateTextInterpolator;
var prevEntry = opts.prevEntry;
var refRect = {};
var isStatic = gd._context.staticPlot;
var fullLayout = gd._fullLayout;
var cd0 = cd[0];
var trace = cd0.trace;
var hasLeft = trace.textposition.indexOf('left') !== -1;
var hasRight = trace.textposition.indexOf('right') !== -1;
var hasBottom = trace.textposition.indexOf('bottom') !== -1;
// N.B. slice data isn't the calcdata,
// grab corresponding calcdata item in sliceData[i].data.data
var allData = partition(entry, [width, height], {
flipX: trace.tiling.flip.indexOf('x') > -1,
flipY: trace.tiling.flip.indexOf('y') > -1,
orientation: trace.tiling.orientation,
pad: {
inner: trace.tiling.pad
},
maxDepth: trace._maxDepth
});
var sliceData = allData.descendants();
var minVisibleDepth = Infinity;
var maxVisibleDepth = -Infinity;
sliceData.forEach(function (pt) {
var depth = pt.depth;
if (depth >= trace._maxDepth) {
// hide slices that won't show up on graph
pt.x0 = pt.x1 = (pt.x0 + pt.x1) / 2;
pt.y0 = pt.y1 = (pt.y0 + pt.y1) / 2;
} else {
minVisibleDepth = Math.min(minVisibleDepth, depth);
maxVisibleDepth = Math.max(maxVisibleDepth, depth);
}
});
slices = slices.data(sliceData, helpers.getPtId);
trace._maxVisibleLayers = isFinite(maxVisibleDepth) ? maxVisibleDepth - minVisibleDepth + 1 : 0;
slices.enter().append('g').classed('slice', true);
handleSlicesExit(slices, onPathbar, refRect, [width, height], pathSlice);
slices.order();
// next coords of previous entry
var nextOfPrevEntry = null;
if (hasTransition && prevEntry) {
var prevEntryId = helpers.getPtId(prevEntry);
slices.each(function (pt) {
if (nextOfPrevEntry === null && helpers.getPtId(pt) === prevEntryId) {
nextOfPrevEntry = {
x0: pt.x0,
x1: pt.x1,
y0: pt.y0,
y1: pt.y1
};
}
});
}
var getRefRect = function () {
return nextOfPrevEntry || {
x0: 0,
x1: width,
y0: 0,
y1: height
};
};
var updateSlices = slices;
if (hasTransition) {
updateSlices = updateSlices.transition().each('end', function () {
// N.B. gd._transitioning is (still) *true* by the time
// transition updates get here
var sliceTop = d3.select(this);
helpers.setSliceCursor(sliceTop, gd, {
hideOnRoot: true,
hideOnLeaves: false,
isTransitioning: false
});
});
}
updateSlices.each(function (pt) {
// for bbox
pt._x0 = viewX(pt.x0);
pt._x1 = viewX(pt.x1);
pt._y0 = viewY(pt.y0);
pt._y1 = viewY(pt.y1);
pt._hoverX = viewX(pt.x1 - trace.tiling.pad), pt._hoverY = hasBottom ? viewY(pt.y1 - trace.tiling.pad / 2) : viewY(pt.y0 + trace.tiling.pad / 2);
var sliceTop = d3.select(this);
var slicePath = Lib.ensureSingle(sliceTop, 'path', 'surface', function (s) {
s.style('pointer-events', isStatic ? 'none' : 'all');
});
if (hasTransition) {
slicePath.transition().attrTween('d', function (pt2) {
var interp = makeUpdateSliceInterpolator(pt2, onPathbar, getRefRect(), [width, height], {
orientation: trace.tiling.orientation,
flipX: trace.tiling.flip.indexOf('x') > -1,
flipY: trace.tiling.flip.indexOf('y') > -1
});
return function (t) {
return pathSlice(interp(t));
};
});
} else {
slicePath.attr('d', pathSlice);
}
sliceTop.call(attachFxHandlers, entry, gd, cd, {
styleOne: styleOne,
eventDataKeys: constants.eventDataKeys,
transitionTime: constants.CLICK_TRANSITION_TIME,
transitionEasing: constants.CLICK_TRANSITION_EASING
}).call(helpers.setSliceCursor, gd, {
isTransitioning: gd._transitioning
});
slicePath.call(styleOne, pt, trace, gd, {
hovered: false
});
if (pt.x0 === pt.x1 || pt.y0 === pt.y1) {
pt._text = '';
} else {
pt._text = formatSliceLabel(pt, entry, trace, cd, fullLayout) || '';
}
var sliceTextGroup = Lib.ensureSingle(sliceTop, 'g', 'slicetext');
var sliceText = Lib.ensureSingle(sliceTextGroup, 'text', '', function (s) {
// prohibit tex interpretation until we can handle
// tex and regular text together
s.attr('data-notex', 1);
});
var font = Lib.ensureUniformFontSize(gd, helpers.determineTextFont(trace, pt, fullLayout.font));
sliceText.text(pt._text || ' ') // use one space character instead of a blank string to avoid jumps during transition
.classed('slicetext', true).attr('text-anchor', hasRight ? 'end' : hasLeft ? 'start' : 'middle').call(Drawing.font, font).call(svgTextUtils.convertToTspans, gd);
pt.textBB = Drawing.bBox(sliceText.node());
pt.transform = toMoveInsideSlice(pt, {
fontSize: font.size
});
pt.transform.fontSize = font.size;
if (hasTransition) {
sliceText.transition().attrTween('transform', function (pt2) {
var interp = makeUpdateTextInterpolator(pt2, onPathbar, getRefRect(), [width, height]);
return function (t) {
return strTransform(interp(t));
};
});
} else {
sliceText.attr('transform', strTransform(pt));
}
});
return nextOfPrevEntry;
};
/***/ }),
/***/ 3648:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'icicle',
basePlotModule: __webpack_require__(1996),
categories: [],
animatable: true,
attributes: __webpack_require__(46752),
layoutAttributes: __webpack_require__(36492),
supplyDefaults: __webpack_require__(67252),
supplyLayoutDefaults: __webpack_require__(64569),
calc: (__webpack_require__(49471)/* .calc */ .r),
crossTraceCalc: (__webpack_require__(49471)/* .crossTraceCalc */ .q),
plot: __webpack_require__(68280),
style: (__webpack_require__(89360).style),
colorbar: __webpack_require__(71416),
meta: {
description: ['Visualize hierarchal data from leaves (and/or outer branches) towards root', 'with rectangles. The icicle sectors are determined by the entries in', '*labels* or *ids* and in *parents*.'].join(' ')
}
};
/***/ }),
/***/ 36492:
/***/ (function(module) {
"use strict";
module.exports = {
iciclecolorway: {
valType: 'colorlist',
editType: 'calc',
description: ['Sets the default icicle slice colors. Defaults to the main', '`colorway` used for trace colors. If you specify a new', 'list here it can still be extended with lighter and darker', 'colors, see `extendiciclecolors`.'].join(' ')
},
extendiciclecolors: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['If `true`, the icicle slice colors (whether given by `iciclecolorway` or', 'inherited from `colorway`) will be extended to three times its', 'original length by first repeating every color 20% lighter then', 'each color 20% darker. This is intended to reduce the likelihood', 'of reusing the same color when you have many slices, but you can', 'set `false` to disable.', 'Colors provided in the trace, using `marker.colors`, are never', 'extended.'].join(' ')
}
};
/***/ }),
/***/ 64569:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(36492);
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
coerce('iciclecolorway', layoutOut.colorway);
coerce('extendiciclecolors');
};
/***/ }),
/***/ 97304:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3Hierarchy = __webpack_require__(89332);
var flipTree = __webpack_require__(57984);
module.exports = function partition(entry, size, opts) {
var flipX = opts.flipX;
var flipY = opts.flipY;
var swapXY = opts.orientation === 'h';
var maxDepth = opts.maxDepth;
var newWidth = size[0];
var newHeight = size[1];
if (maxDepth) {
newWidth = (entry.height + 1) * size[0] / Math.min(entry.height + 1, maxDepth);
newHeight = (entry.height + 1) * size[1] / Math.min(entry.height + 1, maxDepth);
}
var result = d3Hierarchy.partition().padding(opts.pad.inner).size(swapXY ? [size[1], newWidth] : [size[0], newHeight])(entry);
if (swapXY || flipX || flipY) {
flipTree(result, size, {
swapXY: swapXY,
flipX: flipX,
flipY: flipY
});
}
return result;
};
/***/ }),
/***/ 68280:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var draw = __webpack_require__(62148);
var drawDescendants = __webpack_require__(89452);
module.exports = function _plot(gd, cdmodule, transitionOpts, makeOnCompleteCallback) {
return draw(gd, cdmodule, transitionOpts, makeOnCompleteCallback, {
type: 'icicle',
drawDescendants: drawDescendants
});
};
/***/ }),
/***/ 89360:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Color = __webpack_require__(9240);
var Lib = __webpack_require__(10923);
var resizeText = (__webpack_require__(4096).resizeText);
var fillOne = __webpack_require__(81136);
function style(gd) {
var s = gd._fullLayout._iciclelayer.selectAll('.trace');
resizeText(gd, s, 'icicle');
s.each(function (cd) {
var gTrace = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
gTrace.style('opacity', trace.opacity);
gTrace.selectAll('path.surface').each(function (pt) {
d3.select(this).call(styleOne, pt, trace, gd);
});
});
}
function styleOne(s, pt, trace, gd) {
var cdi = pt.data.data;
var isLeaf = !pt.children;
var ptNumber = cdi.i;
var lineColor = Lib.castOption(trace, ptNumber, 'marker.line.color') || Color.defaultLine;
var lineWidth = Lib.castOption(trace, ptNumber, 'marker.line.width') || 0;
s.call(fillOne, pt, trace, gd).style('stroke-width', lineWidth).call(Color.stroke, lineColor).style('opacity', isLeaf ? trace.leaf.opacity : null);
}
module.exports = {
style: style,
styleOne: styleOne
};
/***/ }),
/***/ 91788:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var baseAttrs = __webpack_require__(6040);
var zorder = (__webpack_require__(49992).zorder);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var extendFlat = (__webpack_require__(55016).extendFlat);
var colormodel = (__webpack_require__(48000).colormodel);
var cm = ['rgb', 'rgba', 'rgba256', 'hsl', 'hsla'];
var zminDesc = [];
var zmaxDesc = [];
for (var i = 0; i < cm.length; i++) {
var cr = colormodel[cm[i]];
zminDesc.push('For the `' + cm[i] + '` colormodel, it is [' + (cr.zminDflt || cr.min).join(', ') + '].');
zmaxDesc.push('For the `' + cm[i] + '` colormodel, it is [' + (cr.zmaxDflt || cr.max).join(', ') + '].');
}
module.exports = extendFlat({
source: {
valType: 'string',
editType: 'calc',
description: ['Specifies the data URI of the image to be visualized.', 'The URI consists of "data:image/[][;base64],"'].join(' ')
},
z: {
valType: 'data_array',
editType: 'calc',
description: ['A 2-dimensional array in which each element is an array of 3 or 4 numbers representing a color.'].join(' ')
},
colormodel: {
valType: 'enumerated',
values: cm,
editType: 'calc',
description: ['Color model used to map the numerical color components described in `z` into colors.', 'If `source` is specified, this attribute will be set to `rgba256`', 'otherwise it defaults to `rgb`.'].join(' ')
},
zsmooth: {
valType: 'enumerated',
values: ['fast', false],
dflt: false,
editType: 'plot',
description: ['Picks a smoothing algorithm used to smooth `z` data.', 'This only applies for image traces that use the `source` attribute.'].join(' ')
},
zmin: {
valType: 'info_array',
items: [{
valType: 'number',
editType: 'calc'
}, {
valType: 'number',
editType: 'calc'
}, {
valType: 'number',
editType: 'calc'
}, {
valType: 'number',
editType: 'calc'
}],
editType: 'calc',
description: ['Array defining the lower bound for each color component.', 'Note that the default value will depend on the colormodel.', zminDesc.join(' ')].join(' ')
},
zmax: {
valType: 'info_array',
items: [{
valType: 'number',
editType: 'calc'
}, {
valType: 'number',
editType: 'calc'
}, {
valType: 'number',
editType: 'calc'
}, {
valType: 'number',
editType: 'calc'
}],
editType: 'calc',
description: ['Array defining the higher bound for each color component.', 'Note that the default value will depend on the colormodel.', zmaxDesc.join(' ')].join(' ')
},
x0: {
valType: 'any',
dflt: 0,
editType: 'calc+clearAxisTypes',
description: ['Set the image\'s x position. The left edge of the image', '(or the right edge if the x axis is reversed or dx is negative)', 'will be found at xmin=x0-dx/2'].join(' ')
},
y0: {
valType: 'any',
dflt: 0,
editType: 'calc+clearAxisTypes',
description: ['Set the image\'s y position. The top edge of the image', '(or the bottom edge if the y axis is NOT reversed or if dy is negative)', 'will be found at ymin=y0-dy/2. By default when an image trace is', 'included, the y axis will be reversed so that the image is right-side-up,', 'but you can disable this by setting yaxis.autorange=true or by providing', 'an explicit y axis range.'].join(' ')
},
dx: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: 'Set the pixel\'s horizontal size.'
},
dy: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: 'Set the pixel\'s vertical size'
},
text: {
valType: 'data_array',
editType: 'plot',
description: 'Sets the text elements associated with each z value.'
},
hovertext: {
valType: 'data_array',
editType: 'plot',
description: 'Same as `text`.'
},
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['x', 'y', 'z', 'color', 'name', 'text'],
dflt: 'x+y+z+text+name'
}),
hovertemplate: hovertemplateAttrs({}, {
keys: ['z', 'color', 'colormodel']
}),
zorder: zorder,
transforms: undefined
});
/***/ }),
/***/ 57131:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var constants = __webpack_require__(48000);
var isNumeric = __webpack_require__(88120);
var Axes = __webpack_require__(81536);
var maxRowLength = (__webpack_require__(10923).maxRowLength);
var getImageSize = (__webpack_require__(23144)/* .getImageSize */ .i);
module.exports = function calc(gd, trace) {
var h;
var w;
if (trace._hasZ) {
h = trace.z.length;
w = maxRowLength(trace.z);
} else if (trace._hasSource) {
var size = getImageSize(trace.source);
h = size.height;
w = size.width;
}
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var x0 = xa.d2c(trace.x0) - trace.dx / 2;
var y0 = ya.d2c(trace.y0) - trace.dy / 2;
// Set axis range
var i;
var xrange = [x0, x0 + w * trace.dx];
var yrange = [y0, y0 + h * trace.dy];
if (xa && xa.type === 'log') for (i = 0; i < w; i++) xrange.push(x0 + i * trace.dx);
if (ya && ya.type === 'log') for (i = 0; i < h; i++) yrange.push(y0 + i * trace.dy);
trace._extremes[xa._id] = Axes.findExtremes(xa, xrange);
trace._extremes[ya._id] = Axes.findExtremes(ya, yrange);
trace._scaler = makeScaler(trace);
var cd0 = {
x0: x0,
y0: y0,
z: trace.z,
w: w,
h: h
};
return [cd0];
};
function scale(zero, ratio, min, max) {
return function (c) {
return Lib.constrain((c - zero) * ratio, min, max);
};
}
function constrain(min, max) {
return function (c) {
return Lib.constrain(c, min, max);
};
}
// Generate a function to scale color components according to zmin/zmax and the colormodel
function makeScaler(trace) {
var cr = constants.colormodel[trace.colormodel];
var colormodel = cr.colormodel || trace.colormodel;
var n = colormodel.length;
trace._sArray = [];
// Loop over all color components
for (var k = 0; k < n; k++) {
if (cr.min[k] !== trace.zmin[k] || cr.max[k] !== trace.zmax[k]) {
trace._sArray.push(scale(trace.zmin[k], (cr.max[k] - cr.min[k]) / (trace.zmax[k] - trace.zmin[k]), cr.min[k], cr.max[k]));
} else {
trace._sArray.push(constrain(cr.min[k], cr.max[k]));
}
}
return function (pixel) {
var c = pixel.slice(0, n);
for (var k = 0; k < n; k++) {
var ck = c[k];
if (!isNumeric(ck)) return false;
c[k] = trace._sArray[k](ck);
}
return c;
};
}
/***/ }),
/***/ 48000:
/***/ (function(module) {
"use strict";
module.exports = {
colormodel: {
// min and max define the numerical range accepted in CSS
// If z(min|max)Dflt are not defined, z(min|max) will default to min/max
rgb: {
min: [0, 0, 0],
max: [255, 255, 255],
fmt: function (c) {
return c.slice(0, 3);
},
suffix: ['', '', '']
},
rgba: {
min: [0, 0, 0, 0],
max: [255, 255, 255, 1],
fmt: function (c) {
return c.slice(0, 4);
},
suffix: ['', '', '', '']
},
rgba256: {
colormodel: 'rgba',
// because rgba256 is not an accept colormodel in CSS
zminDflt: [0, 0, 0, 0],
zmaxDflt: [255, 255, 255, 255],
min: [0, 0, 0, 0],
max: [255, 255, 255, 1],
fmt: function (c) {
return c.slice(0, 4);
},
suffix: ['', '', '', '']
},
hsl: {
min: [0, 0, 0],
max: [360, 100, 100],
fmt: function (c) {
var p = c.slice(0, 3);
p[1] = p[1] + '%';
p[2] = p[2] + '%';
return p;
},
suffix: ['°', '%', '%']
},
hsla: {
min: [0, 0, 0, 0],
max: [360, 100, 100, 1],
fmt: function (c) {
var p = c.slice(0, 4);
p[1] = p[1] + '%';
p[2] = p[2] + '%';
return p;
},
suffix: ['°', '%', '%', '']
}
}
};
/***/ }),
/***/ 61784:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(91788);
var constants = __webpack_require__(48000);
var dataUri = (__webpack_require__(48688).IMAGE_URL_PREFIX);
module.exports = function supplyDefaults(traceIn, traceOut) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
coerce('source');
// sanitize source to only allow for data URI representing images
if (traceOut.source && !traceOut.source.match(dataUri)) delete traceOut.source;
traceOut._hasSource = !!traceOut.source;
var z = coerce('z');
traceOut._hasZ = !(z === undefined || !z.length || !z[0] || !z[0].length);
if (!traceOut._hasZ && !traceOut._hasSource) {
traceOut.visible = false;
return;
}
coerce('x0');
coerce('y0');
coerce('dx');
coerce('dy');
var cm;
if (traceOut._hasZ) {
coerce('colormodel', 'rgb');
cm = constants.colormodel[traceOut.colormodel];
coerce('zmin', cm.zminDflt || cm.min);
coerce('zmax', cm.zmaxDflt || cm.max);
} else if (traceOut._hasSource) {
traceOut.colormodel = 'rgba256';
cm = constants.colormodel[traceOut.colormodel];
traceOut.zmin = cm.zminDflt;
traceOut.zmax = cm.zmaxDflt;
}
coerce('zsmooth');
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
traceOut._length = null;
coerce('zorder');
};
/***/ }),
/***/ 82528:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt) {
if ('xVal' in pt) out.x = pt.xVal;
if ('yVal' in pt) out.y = pt.yVal;
if (pt.xa) out.xaxis = pt.xa;
if (pt.ya) out.yaxis = pt.ya;
out.color = pt.color;
out.colormodel = pt.trace.colormodel;
if (!out.z) out.z = pt.color;
return out;
};
/***/ }),
/***/ 23144:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var probeSync = __webpack_require__(86032);
var dataUri = (__webpack_require__(48688).IMAGE_URL_PREFIX);
var Buffer = (__webpack_require__(38436).Buffer); // note: the trailing slash is important!
exports.i = function (src) {
var data = src.replace(dataUri, '');
var buff = new Buffer(data, 'base64');
return probeSync(buff);
};
/***/ }),
/***/ 80992:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Fx = __webpack_require__(39184);
var Lib = __webpack_require__(10923);
var isArrayOrTypedArray = Lib.isArrayOrTypedArray;
var constants = __webpack_require__(48000);
module.exports = function hoverPoints(pointData, xval, yval) {
var cd0 = pointData.cd[0];
var trace = cd0.trace;
var xa = pointData.xa;
var ya = pointData.ya;
// Return early if not on image
if (Fx.inbox(xval - cd0.x0, xval - (cd0.x0 + cd0.w * trace.dx), 0) > 0 || Fx.inbox(yval - cd0.y0, yval - (cd0.y0 + cd0.h * trace.dy), 0) > 0) {
return;
}
// Find nearest pixel's index
var nx = Math.floor((xval - cd0.x0) / trace.dx);
var ny = Math.floor(Math.abs(yval - cd0.y0) / trace.dy);
var pixel;
if (trace._hasZ) {
pixel = cd0.z[ny][nx];
} else if (trace._hasSource) {
pixel = trace._canvas.el.getContext('2d', {
willReadFrequently: true
}).getImageData(nx, ny, 1, 1).data;
}
// return early if pixel is undefined
if (!pixel) return;
var hoverinfo = cd0.hi || trace.hoverinfo;
var fmtColor;
if (hoverinfo) {
var parts = hoverinfo.split('+');
if (parts.indexOf('all') !== -1) parts = ['color'];
if (parts.indexOf('color') !== -1) fmtColor = true;
}
var cr = constants.colormodel[trace.colormodel];
var colormodel = cr.colormodel || trace.colormodel;
var dims = colormodel.length;
var c = trace._scaler(pixel);
var s = cr.suffix;
var colorstring = [];
if (trace.hovertemplate || fmtColor) {
colorstring.push('[' + [c[0] + s[0], c[1] + s[1], c[2] + s[2]].join(', '));
if (dims === 4) colorstring.push(', ' + c[3] + s[3]);
colorstring.push(']');
colorstring = colorstring.join('');
pointData.extraText = colormodel.toUpperCase() + ': ' + colorstring;
}
var text;
if (isArrayOrTypedArray(trace.hovertext) && isArrayOrTypedArray(trace.hovertext[ny])) {
text = trace.hovertext[ny][nx];
} else if (isArrayOrTypedArray(trace.text) && isArrayOrTypedArray(trace.text[ny])) {
text = trace.text[ny][nx];
}
// TODO: for color model with 3 dims, display something useful for hovertemplate `%{color[3]}`
var py = ya.c2p(cd0.y0 + (ny + 0.5) * trace.dy);
var xVal = cd0.x0 + (nx + 0.5) * trace.dx;
var yVal = cd0.y0 + (ny + 0.5) * trace.dy;
var zLabel = '[' + pixel.slice(0, trace.colormodel.length).join(', ') + ']';
return [Lib.extendFlat(pointData, {
index: [ny, nx],
x0: xa.c2p(cd0.x0 + nx * trace.dx),
x1: xa.c2p(cd0.x0 + (nx + 1) * trace.dx),
y0: py,
y1: py,
color: c,
xVal: xVal,
xLabelVal: xVal,
yVal: yVal,
yLabelVal: yVal,
zLabelVal: zLabel,
text: text,
hovertemplateLabels: {
zLabel: zLabel,
colorLabel: colorstring,
'color[0]Label': c[0] + s[0],
'color[1]Label': c[1] + s[1],
'color[2]Label': c[2] + s[2],
'color[3]Label': c[3] + s[3]
}
})];
};
/***/ }),
/***/ 48840:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(91788),
supplyDefaults: __webpack_require__(61784),
calc: __webpack_require__(57131),
plot: __webpack_require__(53400),
style: __webpack_require__(37480),
hoverPoints: __webpack_require__(80992),
eventData: __webpack_require__(82528),
moduleType: 'trace',
name: 'image',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', '2dMap', 'noSortingByValue'],
animatable: false,
meta: {
description: ['Display an image, i.e. data on a 2D regular raster.', 'By default, when an image is displayed in a subplot,', 'its y axis will be reversed (ie. `autorange: \'reversed\'`),', 'constrained to the domain (ie. `constrain: \'domain\'`)', 'and it will have the same scale as its x axis (ie. `scaleanchor: \'x\,`)', 'in order for pixels to be rendered as squares.'].join(' ')
}
};
/***/ }),
/***/ 53400:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var strTranslate = Lib.strTranslate;
var xmlnsNamespaces = __webpack_require__(51608);
var constants = __webpack_require__(48000);
var supportsPixelatedImage = __webpack_require__(37640);
var PIXELATED_IMAGE_STYLE = (__webpack_require__(4020).STYLE);
module.exports = function plot(gd, plotinfo, cdimage, imageLayer) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var supportsPixelated = !gd._context._exportedPlot && supportsPixelatedImage();
Lib.makeTraceGroups(imageLayer, cdimage, 'im').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
var realImage = (trace.zsmooth === 'fast' || trace.zsmooth === false && supportsPixelated) && !trace._hasZ && trace._hasSource && xa.type === 'linear' && ya.type === 'linear';
trace._realImage = realImage;
var z = cd0.z;
var x0 = cd0.x0;
var y0 = cd0.y0;
var w = cd0.w;
var h = cd0.h;
var dx = trace.dx;
var dy = trace.dy;
var left, right, temp, top, bottom, i;
// in case of log of a negative
i = 0;
while (left === undefined && i < w) {
left = xa.c2p(x0 + i * dx);
i++;
}
i = w;
while (right === undefined && i > 0) {
right = xa.c2p(x0 + i * dx);
i--;
}
i = 0;
while (top === undefined && i < h) {
top = ya.c2p(y0 + i * dy);
i++;
}
i = h;
while (bottom === undefined && i > 0) {
bottom = ya.c2p(y0 + i * dy);
i--;
}
if (right < left) {
temp = right;
right = left;
left = temp;
}
if (bottom < top) {
temp = top;
top = bottom;
bottom = temp;
}
// Reduce image size when zoomed in to save memory
if (!realImage) {
var extra = 0.5; // half the axis size
left = Math.max(-extra * xa._length, left);
right = Math.min((1 + extra) * xa._length, right);
top = Math.max(-extra * ya._length, top);
bottom = Math.min((1 + extra) * ya._length, bottom);
}
var imageWidth = Math.round(right - left);
var imageHeight = Math.round(bottom - top);
// if image is entirely off-screen, don't even draw it
var isOffScreen = imageWidth <= 0 || imageHeight <= 0;
if (isOffScreen) {
var noImage = plotGroup.selectAll('image').data([]);
noImage.exit().remove();
return;
}
// Create a new canvas and draw magnified pixels on it
function drawMagnifiedPixelsOnCanvas(readPixel) {
var canvas = document.createElement('canvas');
canvas.width = imageWidth;
canvas.height = imageHeight;
var context = canvas.getContext('2d', {
willReadFrequently: true
});
var ipx = function (i) {
return Lib.constrain(Math.round(xa.c2p(x0 + i * dx) - left), 0, imageWidth);
};
var jpx = function (j) {
return Lib.constrain(Math.round(ya.c2p(y0 + j * dy) - top), 0, imageHeight);
};
var cr = constants.colormodel[trace.colormodel];
var colormodel = cr.colormodel || trace.colormodel;
var fmt = cr.fmt;
var c;
for (i = 0; i < cd0.w; i++) {
var ipx0 = ipx(i);
var ipx1 = ipx(i + 1);
if (ipx1 === ipx0 || isNaN(ipx1) || isNaN(ipx0)) continue;
for (var j = 0; j < cd0.h; j++) {
var jpx0 = jpx(j);
var jpx1 = jpx(j + 1);
if (jpx1 === jpx0 || isNaN(jpx1) || isNaN(jpx0) || !readPixel(i, j)) continue;
c = trace._scaler(readPixel(i, j));
if (c) {
context.fillStyle = colormodel + '(' + fmt(c).join(',') + ')';
} else {
// Return a transparent pixel
context.fillStyle = 'rgba(0,0,0,0)';
}
context.fillRect(ipx0, jpx0, ipx1 - ipx0, jpx1 - jpx0);
}
}
return canvas;
}
var image3 = plotGroup.selectAll('image').data([cd]);
image3.enter().append('svg:image').attr({
xmlns: xmlnsNamespaces.svg,
preserveAspectRatio: 'none'
});
image3.exit().remove();
var style = trace.zsmooth === false ? PIXELATED_IMAGE_STYLE : '';
if (realImage) {
var xRange = Lib.simpleMap(xa.range, xa.r2l);
var yRange = Lib.simpleMap(ya.range, ya.r2l);
var flipX = xRange[1] < xRange[0];
var flipY = yRange[1] > yRange[0];
if (flipX || flipY) {
var tx = left + imageWidth / 2;
var ty = top + imageHeight / 2;
style += 'transform:' + strTranslate(tx + 'px', ty + 'px') + 'scale(' + (flipX ? -1 : 1) + ',' + (flipY ? -1 : 1) + ')' + strTranslate(-tx + 'px', -ty + 'px') + ';';
}
}
image3.attr('style', style);
var p = new Promise(function (resolve) {
if (trace._hasZ) {
resolve();
} else if (trace._hasSource) {
// Check if canvas already exists and has the right data
if (trace._canvas && trace._canvas.el.width === w && trace._canvas.el.height === h && trace._canvas.source === trace.source) {
resolve();
} else {
// Create a canvas and transfer image onto it to access pixel information
var canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
var context = canvas.getContext('2d', {
willReadFrequently: true
});
trace._image = trace._image || new Image();
var image = trace._image;
image.onload = function () {
context.drawImage(image, 0, 0);
trace._canvas = {
el: canvas,
source: trace.source
};
resolve();
};
image.setAttribute('src', trace.source);
}
}
}).then(function () {
var href, canvas;
if (trace._hasZ) {
canvas = drawMagnifiedPixelsOnCanvas(function (i, j) {
var _z = z[j][i];
if (Lib.isTypedArray(_z)) _z = Array.from(_z);
return _z;
});
href = canvas.toDataURL('image/png');
} else if (trace._hasSource) {
if (realImage) {
href = trace.source;
} else {
var context = trace._canvas.el.getContext('2d', {
willReadFrequently: true
});
var data = context.getImageData(0, 0, w, h).data;
canvas = drawMagnifiedPixelsOnCanvas(function (i, j) {
var index = 4 * (j * w + i);
return [data[index], data[index + 1], data[index + 2], data[index + 3]];
});
href = canvas.toDataURL('image/png');
}
}
image3.attr({
'xlink:href': href,
height: imageHeight,
width: imageWidth,
x: left,
y: top
});
});
gd._promises.push(p);
});
};
/***/ }),
/***/ 37480:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
module.exports = function style(gd) {
d3.select(gd).selectAll('.im image').style('opacity', function (d) {
return d[0].trace.opacity;
});
};
/***/ }),
/***/ 94956:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var extendFlat = (__webpack_require__(55016).extendFlat);
var extendDeep = (__webpack_require__(55016).extendDeep);
var overrideAll = (__webpack_require__(31176).overrideAll);
var fontAttrs = __webpack_require__(71936);
var colorAttrs = __webpack_require__(51468);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var axesAttrs = __webpack_require__(88176);
var templatedArray = (__webpack_require__(58056).templatedArray);
var delta = __webpack_require__(91136);
var descriptionOnlyNumbers = (__webpack_require__(67724).descriptionOnlyNumbers);
var textFontAttrs = fontAttrs({
editType: 'plot',
colorEditType: 'plot'
});
var gaugeBarAttrs = {
color: {
valType: 'color',
editType: 'plot',
description: ['Sets the background color of the arc.'].join(' ')
},
line: {
color: {
valType: 'color',
dflt: colorAttrs.defaultLine,
editType: 'plot',
description: ['Sets the color of the line enclosing each sector.'].join(' ')
},
width: {
valType: 'number',
min: 0,
dflt: 0,
editType: 'plot',
description: ['Sets the width (in px) of the line enclosing each sector.'].join(' ')
},
editType: 'calc'
},
thickness: {
valType: 'number',
min: 0,
max: 1,
dflt: 1,
editType: 'plot',
description: ['Sets the thickness of the bar as a fraction of the total thickness of the gauge.'].join(' ')
},
editType: 'calc'
};
var rangeAttr = {
valType: 'info_array',
items: [{
valType: 'number',
editType: 'plot'
}, {
valType: 'number',
editType: 'plot'
}],
editType: 'plot',
description: ['Sets the range of this axis.'
// TODO: add support for other axis type
// 'If the axis `type` is *log*, then you must take the log of your',
// 'desired range (e.g. to set the range from 1 to 100,',
// 'set the range from 0 to 2).',
// 'If the axis `type` is *date*, it should be date strings,',
// 'like date data, though Date objects and unix milliseconds',
// 'will be accepted and converted to strings.',
// 'If the axis `type` is *category*, it should be numbers,',
// 'using the scale where each category is assigned a serial',
// 'number from zero in the order it appears.'
].join(' ')
};
var stepsAttrs = templatedArray('step', extendDeep({}, gaugeBarAttrs, {
range: rangeAttr
}));
module.exports = {
mode: {
valType: 'flaglist',
editType: 'calc',
flags: ['number', 'delta', 'gauge'],
dflt: 'number',
description: ['Determines how the value is displayed on the graph.', '`number` displays the value numerically in text.', '`delta` displays the difference to a reference value in text.', 'Finally, `gauge` displays the value graphically on an axis.'].join(' ')
},
value: {
valType: 'number',
editType: 'calc',
anim: true,
description: ['Sets the number to be displayed.'].join(' ')
},
align: {
valType: 'enumerated',
values: ['left', 'center', 'right'],
editType: 'plot',
description: ['Sets the horizontal alignment of the `text` within the box.', 'Note that this attribute has no effect if an angular gauge is displayed:', 'in this case, it is always centered'].join(' ')
},
// position
domain: domainAttrs({
name: 'indicator',
trace: true,
editType: 'calc'
}),
title: {
text: {
valType: 'string',
editType: 'plot',
description: ['Sets the title of this indicator.'].join(' ')
},
align: {
valType: 'enumerated',
values: ['left', 'center', 'right'],
editType: 'plot',
description: ['Sets the horizontal alignment of the title.', 'It defaults to `center` except for bullet charts', 'for which it defaults to right.'].join(' ')
},
font: extendFlat({}, textFontAttrs, {
description: ['Set the font used to display the title'].join(' ')
}),
editType: 'plot'
},
number: {
valueformat: {
valType: 'string',
dflt: '',
editType: 'plot',
description: descriptionOnlyNumbers('value')
},
font: extendFlat({}, textFontAttrs, {
description: ['Set the font used to display main number'].join(' ')
}),
prefix: {
valType: 'string',
dflt: '',
editType: 'plot',
description: ['Sets a prefix appearing before the number.'].join(' ')
},
suffix: {
valType: 'string',
dflt: '',
editType: 'plot',
description: ['Sets a suffix appearing next to the number.'].join(' ')
},
editType: 'plot'
},
delta: {
reference: {
valType: 'number',
editType: 'calc',
description: ['Sets the reference value to compute the delta.', 'By default, it is set to the current value.'].join(' ')
},
position: {
valType: 'enumerated',
values: ['top', 'bottom', 'left', 'right'],
dflt: 'bottom',
editType: 'plot',
description: ['Sets the position of delta with respect to the number.'].join(' ')
},
relative: {
valType: 'boolean',
editType: 'plot',
dflt: false,
description: ['Show relative change'].join(' ')
},
valueformat: {
valType: 'string',
editType: 'plot',
description: descriptionOnlyNumbers('value')
},
increasing: {
symbol: {
valType: 'string',
dflt: delta.INCREASING.SYMBOL,
editType: 'plot',
description: ['Sets the symbol to display for increasing value'].join(' ')
},
color: {
valType: 'color',
dflt: delta.INCREASING.COLOR,
editType: 'plot',
description: ['Sets the color for increasing value.'].join(' ')
},
// TODO: add attribute to show sign
editType: 'plot'
},
decreasing: {
symbol: {
valType: 'string',
dflt: delta.DECREASING.SYMBOL,
editType: 'plot',
description: ['Sets the symbol to display for increasing value'].join(' ')
},
color: {
valType: 'color',
dflt: delta.DECREASING.COLOR,
editType: 'plot',
description: ['Sets the color for increasing value.'].join(' ')
},
// TODO: add attribute to hide sign
editType: 'plot'
},
font: extendFlat({}, textFontAttrs, {
description: ['Set the font used to display the delta'].join(' ')
}),
prefix: {
valType: 'string',
dflt: '',
editType: 'plot',
description: ['Sets a prefix appearing before the delta.'].join(' ')
},
suffix: {
valType: 'string',
dflt: '',
editType: 'plot',
description: ['Sets a suffix appearing next to the delta.'].join(' ')
},
editType: 'calc'
},
gauge: {
shape: {
valType: 'enumerated',
editType: 'plot',
dflt: 'angular',
values: ['angular', 'bullet'],
description: ['Set the shape of the gauge'].join(' ')
},
bar: extendDeep({}, gaugeBarAttrs, {
color: {
dflt: 'green'
},
description: ['Set the appearance of the gauge\'s value'].join(' ')
}),
// Background of the gauge
bgcolor: {
valType: 'color',
editType: 'plot',
description: 'Sets the gauge background color.'
},
bordercolor: {
valType: 'color',
dflt: colorAttrs.defaultLine,
editType: 'plot',
description: 'Sets the color of the border enclosing the gauge.'
},
borderwidth: {
valType: 'number',
min: 0,
dflt: 1,
editType: 'plot',
description: 'Sets the width (in px) of the border enclosing the gauge.'
},
axis: overrideAll({
range: rangeAttr,
visible: extendFlat({}, axesAttrs.visible, {
dflt: true
}),
// tick and title properties named and function exactly as in axes
tickmode: axesAttrs.minor.tickmode,
nticks: axesAttrs.nticks,
tick0: axesAttrs.tick0,
dtick: axesAttrs.dtick,
tickvals: axesAttrs.tickvals,
ticktext: axesAttrs.ticktext,
ticks: extendFlat({}, axesAttrs.ticks, {
dflt: 'outside'
}),
ticklen: axesAttrs.ticklen,
tickwidth: axesAttrs.tickwidth,
tickcolor: axesAttrs.tickcolor,
ticklabelstep: axesAttrs.ticklabelstep,
showticklabels: axesAttrs.showticklabels,
labelalias: axesAttrs.labelalias,
tickfont: fontAttrs({
description: 'Sets the color bar\'s tick label font'
}),
tickangle: axesAttrs.tickangle,
tickformat: axesAttrs.tickformat,
tickformatstops: axesAttrs.tickformatstops,
tickprefix: axesAttrs.tickprefix,
showtickprefix: axesAttrs.showtickprefix,
ticksuffix: axesAttrs.ticksuffix,
showticksuffix: axesAttrs.showticksuffix,
separatethousands: axesAttrs.separatethousands,
exponentformat: axesAttrs.exponentformat,
minexponent: axesAttrs.minexponent,
showexponent: axesAttrs.showexponent,
editType: 'plot'
}, 'plot'),
// Steps (or ranges) and thresholds
steps: stepsAttrs,
threshold: {
line: {
color: extendFlat({}, gaugeBarAttrs.line.color, {
description: ['Sets the color of the threshold line.'].join(' ')
}),
width: extendFlat({}, gaugeBarAttrs.line.width, {
dflt: 1,
description: ['Sets the width (in px) of the threshold line.'].join(' ')
}),
editType: 'plot'
},
thickness: extendFlat({}, gaugeBarAttrs.thickness, {
dflt: 0.85,
description: ['Sets the thickness of the threshold line as a fraction of the thickness of the gauge.'].join(' ')
}),
value: {
valType: 'number',
editType: 'calc',
dflt: false,
description: ['Sets a treshold value drawn as a line.'].join(' ')
},
editType: 'plot'
},
description: 'The gauge of the Indicator plot.',
editType: 'plot'
// TODO: in future version, add marker: (bar|needle)
}
};
/***/ }),
/***/ 13440:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var plots = __webpack_require__(19896);
exports.name = 'indicator';
exports.plot = function (gd, traces, transitionOpts, makeOnCompleteCallback) {
plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout);
};
/***/ }),
/***/ 29146:
/***/ (function(module) {
"use strict";
// var Lib = require('../../lib');
function calc(gd, trace) {
var cd = [];
var lastReading = trace.value;
if (!(typeof trace._lastValue === 'number')) trace._lastValue = trace.value;
var secondLastReading = trace._lastValue;
var deltaRef = secondLastReading;
if (trace._hasDelta && typeof trace.delta.reference === 'number') {
deltaRef = trace.delta.reference;
}
cd[0] = {
y: lastReading,
lastY: secondLastReading,
delta: lastReading - deltaRef,
relativeDelta: (lastReading - deltaRef) / deltaRef
};
return cd;
}
module.exports = {
calc: calc
};
/***/ }),
/***/ 76852:
/***/ (function(module) {
"use strict";
module.exports = {
// Defaults for delta
defaultNumberFontSize: 80,
bulletNumberDomainSize: 0.25,
bulletPadding: 0.025,
innerRadius: 0.75,
valueThickness: 0.5,
// thickness of value bars relative to full thickness,
titlePadding: 5,
horizontalPadding: 10
};
/***/ }),
/***/ 68704:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(94956);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var Template = __webpack_require__(58056);
var handleArrayContainerDefaults = __webpack_require__(95631);
var cn = __webpack_require__(76852);
var handleTickValueDefaults = __webpack_require__(82960);
var handleTickMarkDefaults = __webpack_require__(1772);
var handleTickLabelDefaults = __webpack_require__(99476);
var handlePrefixSuffixDefaults = __webpack_require__(64176);
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
handleDomainDefaults(traceOut, layout, coerce);
// Mode
coerce('mode');
traceOut._hasNumber = traceOut.mode.indexOf('number') !== -1;
traceOut._hasDelta = traceOut.mode.indexOf('delta') !== -1;
traceOut._hasGauge = traceOut.mode.indexOf('gauge') !== -1;
var value = coerce('value');
traceOut._range = [0, typeof value === 'number' ? 1.5 * value : 1];
// Number attributes
var auto = new Array(2);
var bignumberFontSize;
if (traceOut._hasNumber) {
coerce('number.valueformat');
coerce('number.font.color', layout.font.color);
coerce('number.font.family', layout.font.family);
coerce('number.font.size');
if (traceOut.number.font.size === undefined) {
traceOut.number.font.size = cn.defaultNumberFontSize;
auto[0] = true;
}
coerce('number.prefix');
coerce('number.suffix');
bignumberFontSize = traceOut.number.font.size;
}
// delta attributes
var deltaFontSize;
if (traceOut._hasDelta) {
coerce('delta.font.color', layout.font.color);
coerce('delta.font.family', layout.font.family);
coerce('delta.font.size');
if (traceOut.delta.font.size === undefined) {
traceOut.delta.font.size = (traceOut._hasNumber ? 0.5 : 1) * (bignumberFontSize || cn.defaultNumberFontSize);
auto[1] = true;
}
coerce('delta.reference', traceOut.value);
coerce('delta.relative');
coerce('delta.valueformat', traceOut.delta.relative ? '2%' : '');
coerce('delta.increasing.symbol');
coerce('delta.increasing.color');
coerce('delta.decreasing.symbol');
coerce('delta.decreasing.color');
coerce('delta.position');
coerce('delta.prefix');
coerce('delta.suffix');
deltaFontSize = traceOut.delta.font.size;
}
traceOut._scaleNumbers = (!traceOut._hasNumber || auto[0]) && (!traceOut._hasDelta || auto[1]) || false;
// Title attributes
coerce('title.font.color', layout.font.color);
coerce('title.font.family', layout.font.family);
coerce('title.font.size', 0.25 * (bignumberFontSize || deltaFontSize || cn.defaultNumberFontSize));
coerce('title.text');
// Gauge attributes
var gaugeIn, gaugeOut, axisIn, axisOut;
function coerceGauge(attr, dflt) {
return Lib.coerce(gaugeIn, gaugeOut, attributes.gauge, attr, dflt);
}
function coerceGaugeAxis(attr, dflt) {
return Lib.coerce(axisIn, axisOut, attributes.gauge.axis, attr, dflt);
}
if (traceOut._hasGauge) {
gaugeIn = traceIn.gauge;
if (!gaugeIn) gaugeIn = {};
gaugeOut = Template.newContainer(traceOut, 'gauge');
coerceGauge('shape');
var isBullet = traceOut._isBullet = traceOut.gauge.shape === 'bullet';
if (!isBullet) {
coerce('title.align', 'center');
}
var isAngular = traceOut._isAngular = traceOut.gauge.shape === 'angular';
if (!isAngular) {
coerce('align', 'center');
}
// gauge background
coerceGauge('bgcolor', layout.paper_bgcolor);
coerceGauge('borderwidth');
coerceGauge('bordercolor');
// gauge bar indicator
coerceGauge('bar.color');
coerceGauge('bar.line.color');
coerceGauge('bar.line.width');
var defaultBarThickness = cn.valueThickness * (traceOut.gauge.shape === 'bullet' ? 0.5 : 1);
coerceGauge('bar.thickness', defaultBarThickness);
// Gauge steps
handleArrayContainerDefaults(gaugeIn, gaugeOut, {
name: 'steps',
handleItemDefaults: stepDefaults
});
// Gauge threshold
coerceGauge('threshold.value');
coerceGauge('threshold.thickness');
coerceGauge('threshold.line.width');
coerceGauge('threshold.line.color');
// Gauge axis
axisIn = {};
if (gaugeIn) axisIn = gaugeIn.axis || {};
axisOut = Template.newContainer(gaugeOut, 'axis');
coerceGaugeAxis('visible');
traceOut._range = coerceGaugeAxis('range', traceOut._range);
var opts = {
noAutotickangles: true,
outerTicks: true
};
handleTickValueDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear');
handlePrefixSuffixDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear', opts);
handleTickLabelDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear', opts);
handleTickMarkDefaults(axisIn, axisOut, coerceGaugeAxis, opts);
} else {
coerce('title.align', 'center');
coerce('align', 'center');
traceOut._isAngular = traceOut._isBullet = false;
}
// disable 1D transforms
traceOut._length = null;
}
function stepDefaults(stepIn, stepOut) {
function coerce(attr, dflt) {
return Lib.coerce(stepIn, stepOut, attributes.gauge.steps, attr, dflt);
}
coerce('color');
coerce('line.color');
coerce('line.width');
coerce('range');
coerce('thickness');
}
module.exports = {
supplyDefaults: supplyDefaults
};
/***/ }),
/***/ 684:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'indicator',
basePlotModule: __webpack_require__(13440),
categories: ['svg', 'noOpacity', 'noHover'],
animatable: true,
attributes: __webpack_require__(94956),
supplyDefaults: (__webpack_require__(68704).supplyDefaults),
calc: (__webpack_require__(29146).calc),
plot: __webpack_require__(57168),
meta: {
description: ['An indicator is used to visualize a single `value` along with some', 'contextual information such as `steps` or a `threshold`, using a', 'combination of three visual elements: a number, a delta, and/or a gauge.', 'Deltas are taken with respect to a `reference`.', 'Gauges can be either angular or bullet (aka linear) gauges.'].join(' ')
}
};
/***/ }),
/***/ 57168:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var interpolate = (__webpack_require__(78204)/* .interpolate */ .qy);
var interpolateNumber = (__webpack_require__(78204)/* .interpolateNumber */ .Gz);
var Lib = __webpack_require__(10923);
var strScale = Lib.strScale;
var strTranslate = Lib.strTranslate;
var rad2deg = Lib.rad2deg;
var MID_SHIFT = (__webpack_require__(83784).MID_SHIFT);
var Drawing = __webpack_require__(49348);
var cn = __webpack_require__(76852);
var svgTextUtils = __webpack_require__(41536);
var Axes = __webpack_require__(81536);
var handleAxisDefaults = __webpack_require__(88976);
var handleAxisPositionDefaults = __webpack_require__(90059);
var axisLayoutAttrs = __webpack_require__(88176);
var Color = __webpack_require__(9240);
var anchor = {
left: 'start',
center: 'middle',
right: 'end'
};
var position = {
left: 0,
center: 0.5,
right: 1
};
var SI_PREFIX = /[yzafpnµmkMGTPEZY]/;
function hasTransition(transitionOpts) {
// If transition config is provided, then it is only a partial replot and traces not
// updated are removed.
return transitionOpts && transitionOpts.duration > 0;
}
module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallback) {
var fullLayout = gd._fullLayout;
var onComplete;
if (hasTransition(transitionOpts)) {
if (makeOnCompleteCallback) {
// If it was passed a callback to register completion, make a callback. If
// this is created, then it must be executed on completion, otherwise the
// pos-transition redraw will not execute:
onComplete = makeOnCompleteCallback();
}
}
Lib.makeTraceGroups(fullLayout._indicatorlayer, cdModule, 'trace').each(function (cd) {
var cd0 = cd[0];
var trace = cd0.trace;
var plotGroup = d3.select(this);
// Elements in trace
var hasGauge = trace._hasGauge;
var isAngular = trace._isAngular;
var isBullet = trace._isBullet;
// Domain size
var domain = trace.domain;
var size = {
w: fullLayout._size.w * (domain.x[1] - domain.x[0]),
h: fullLayout._size.h * (domain.y[1] - domain.y[0]),
l: fullLayout._size.l + fullLayout._size.w * domain.x[0],
r: fullLayout._size.r + fullLayout._size.w * (1 - domain.x[1]),
t: fullLayout._size.t + fullLayout._size.h * (1 - domain.y[1]),
b: fullLayout._size.b + fullLayout._size.h * domain.y[0]
};
var centerX = size.l + size.w / 2;
var centerY = size.t + size.h / 2;
// Angular gauge size
var radius = Math.min(size.w / 2, size.h); // fill domain
var innerRadius = cn.innerRadius * radius;
// Position numbers based on mode and set the scaling logic
var numbersX, numbersY, numbersScaler;
var numbersAlign = trace.align || 'center';
numbersY = centerY;
if (!hasGauge) {
numbersX = size.l + position[numbersAlign] * size.w;
numbersScaler = function (el) {
return fitTextInsideBox(el, size.w, size.h);
};
} else {
if (isAngular) {
numbersX = centerX;
numbersY = centerY + radius / 2;
numbersScaler = function (el) {
return fitTextInsideCircle(el, 0.9 * innerRadius);
};
}
if (isBullet) {
var padding = cn.bulletPadding;
var p = 1 - cn.bulletNumberDomainSize + padding;
numbersX = size.l + (p + (1 - p) * position[numbersAlign]) * size.w;
numbersScaler = function (el) {
return fitTextInsideBox(el, (cn.bulletNumberDomainSize - padding) * size.w, size.h);
};
}
}
// Draw numbers
drawNumbers(gd, plotGroup, cd, {
numbersX: numbersX,
numbersY: numbersY,
numbersScaler: numbersScaler,
transitionOpts: transitionOpts,
onComplete: onComplete
});
// Reexpress our gauge background attributes for drawing
var gaugeBg, gaugeOutline;
if (hasGauge) {
gaugeBg = {
range: trace.gauge.axis.range,
color: trace.gauge.bgcolor,
line: {
color: trace.gauge.bordercolor,
width: 0
},
thickness: 1
};
gaugeOutline = {
range: trace.gauge.axis.range,
color: 'rgba(0, 0, 0, 0)',
line: {
color: trace.gauge.bordercolor,
width: trace.gauge.borderwidth
},
thickness: 1
};
}
// Prepare angular gauge layers
var angularGauge = plotGroup.selectAll('g.angular').data(isAngular ? cd : []);
angularGauge.exit().remove();
var angularaxisLayer = plotGroup.selectAll('g.angularaxis').data(isAngular ? cd : []);
angularaxisLayer.exit().remove();
if (isAngular) {
drawAngularGauge(gd, plotGroup, cd, {
radius: radius,
innerRadius: innerRadius,
gauge: angularGauge,
layer: angularaxisLayer,
size: size,
gaugeBg: gaugeBg,
gaugeOutline: gaugeOutline,
transitionOpts: transitionOpts,
onComplete: onComplete
});
}
// Prepare bullet layers
var bulletGauge = plotGroup.selectAll('g.bullet').data(isBullet ? cd : []);
bulletGauge.exit().remove();
var bulletaxisLayer = plotGroup.selectAll('g.bulletaxis').data(isBullet ? cd : []);
bulletaxisLayer.exit().remove();
if (isBullet) {
drawBulletGauge(gd, plotGroup, cd, {
gauge: bulletGauge,
layer: bulletaxisLayer,
size: size,
gaugeBg: gaugeBg,
gaugeOutline: gaugeOutline,
transitionOpts: transitionOpts,
onComplete: onComplete
});
}
// title
var title = plotGroup.selectAll('text.title').data(cd);
title.exit().remove();
title.enter().append('text').classed('title', true);
title.attr('text-anchor', function () {
return isBullet ? anchor.right : anchor[trace.title.align];
}).text(trace.title.text).call(Drawing.font, trace.title.font).call(svgTextUtils.convertToTspans, gd);
// Position title
title.attr('transform', function () {
var titleX = size.l + size.w * position[trace.title.align];
var titleY;
var titlePadding = cn.titlePadding;
var titlebBox = Drawing.bBox(title.node());
if (hasGauge) {
if (isAngular) {
// position above axis ticks/labels
if (trace.gauge.axis.visible) {
var bBox = Drawing.bBox(angularaxisLayer.node());
titleY = bBox.top - titlePadding - titlebBox.bottom;
} else {
titleY = size.t + size.h / 2 - radius / 2 - titlebBox.bottom - titlePadding;
}
}
if (isBullet) {
// position outside domain
titleY = numbersY - (titlebBox.top + titlebBox.bottom) / 2;
titleX = size.l - cn.bulletPadding * size.w; // Outside domain, on the left
}
} else {
// position above numbers
titleY = trace._numbersTop - titlePadding - titlebBox.bottom;
}
return strTranslate(titleX, titleY);
});
});
};
function drawBulletGauge(gd, plotGroup, cd, opts) {
var trace = cd[0].trace;
var bullet = opts.gauge;
var axisLayer = opts.layer;
var gaugeBg = opts.gaugeBg;
var gaugeOutline = opts.gaugeOutline;
var size = opts.size;
var domain = trace.domain;
var transitionOpts = opts.transitionOpts;
var onComplete = opts.onComplete;
// preparing axis
var ax, vals, transFn, tickSign, shift;
// Enter bullet, axis
bullet.enter().append('g').classed('bullet', true);
bullet.attr('transform', strTranslate(size.l, size.t));
axisLayer.enter().append('g').classed('bulletaxis', true).classed('crisp', true);
axisLayer.selectAll('g.' + 'xbulletaxis' + 'tick,path,text').remove();
// Draw bullet
var bulletHeight = size.h; // use all vertical domain
var innerBulletHeight = trace.gauge.bar.thickness * bulletHeight;
var bulletLeft = domain.x[0];
var bulletRight = domain.x[0] + (domain.x[1] - domain.x[0]) * (trace._hasNumber || trace._hasDelta ? 1 - cn.bulletNumberDomainSize : 1);
ax = mockAxis(gd, trace.gauge.axis);
ax._id = 'xbulletaxis';
ax.domain = [bulletLeft, bulletRight];
ax.setScale();
vals = Axes.calcTicks(ax);
transFn = Axes.makeTransTickFn(ax);
tickSign = Axes.getTickSigns(ax)[2];
shift = size.t + size.h;
if (ax.visible) {
Axes.drawTicks(gd, ax, {
vals: ax.ticks === 'inside' ? Axes.clipEnds(ax, vals) : vals,
layer: axisLayer,
path: Axes.makeTickPath(ax, shift, tickSign),
transFn: transFn
});
Axes.drawLabels(gd, ax, {
vals: vals,
layer: axisLayer,
transFn: transFn,
labelFns: Axes.makeLabelFns(ax, shift)
});
}
function drawRect(s) {
s.attr('width', function (d) {
return Math.max(0, ax.c2p(d.range[1]) - ax.c2p(d.range[0]));
}).attr('x', function (d) {
return ax.c2p(d.range[0]);
}).attr('y', function (d) {
return 0.5 * (1 - d.thickness) * bulletHeight;
}).attr('height', function (d) {
return d.thickness * bulletHeight;
});
}
// Draw bullet background, steps
var boxes = [gaugeBg].concat(trace.gauge.steps);
var bgBullet = bullet.selectAll('g.bg-bullet').data(boxes);
bgBullet.enter().append('g').classed('bg-bullet', true).append('rect');
bgBullet.select('rect').call(drawRect).call(styleShape);
bgBullet.exit().remove();
// Draw value bar with transitions
var fgBullet = bullet.selectAll('g.value-bullet').data([trace.gauge.bar]);
fgBullet.enter().append('g').classed('value-bullet', true).append('rect');
fgBullet.select('rect').attr('height', innerBulletHeight).attr('y', (bulletHeight - innerBulletHeight) / 2).call(styleShape);
if (hasTransition(transitionOpts)) {
fgBullet.select('rect').transition().duration(transitionOpts.duration).ease(transitionOpts.easing).each('end', function () {
onComplete && onComplete();
}).each('interrupt', function () {
onComplete && onComplete();
}).attr('width', Math.max(0, ax.c2p(Math.min(trace.gauge.axis.range[1], cd[0].y))));
} else {
fgBullet.select('rect').attr('width', typeof cd[0].y === 'number' ? Math.max(0, ax.c2p(Math.min(trace.gauge.axis.range[1], cd[0].y))) : 0);
}
fgBullet.exit().remove();
var data = cd.filter(function () {
return trace.gauge.threshold.value || trace.gauge.threshold.value === 0;
});
var threshold = bullet.selectAll('g.threshold-bullet').data(data);
threshold.enter().append('g').classed('threshold-bullet', true).append('line');
threshold.select('line').attr('x1', ax.c2p(trace.gauge.threshold.value)).attr('x2', ax.c2p(trace.gauge.threshold.value)).attr('y1', (1 - trace.gauge.threshold.thickness) / 2 * bulletHeight).attr('y2', (1 - (1 - trace.gauge.threshold.thickness) / 2) * bulletHeight).call(Color.stroke, trace.gauge.threshold.line.color).style('stroke-width', trace.gauge.threshold.line.width);
threshold.exit().remove();
var bulletOutline = bullet.selectAll('g.gauge-outline').data([gaugeOutline]);
bulletOutline.enter().append('g').classed('gauge-outline', true).append('rect');
bulletOutline.select('rect').call(drawRect).call(styleShape);
bulletOutline.exit().remove();
}
function drawAngularGauge(gd, plotGroup, cd, opts) {
var trace = cd[0].trace;
var size = opts.size;
var radius = opts.radius;
var innerRadius = opts.innerRadius;
var gaugeBg = opts.gaugeBg;
var gaugeOutline = opts.gaugeOutline;
var gaugePosition = [size.l + size.w / 2, size.t + size.h / 2 + radius / 2];
var gauge = opts.gauge;
var axisLayer = opts.layer;
var transitionOpts = opts.transitionOpts;
var onComplete = opts.onComplete;
// circular gauge
var theta = Math.PI / 2;
function valueToAngle(v) {
var min = trace.gauge.axis.range[0];
var max = trace.gauge.axis.range[1];
var angle = (v - min) / (max - min) * Math.PI - theta;
if (angle < -theta) return -theta;
if (angle > theta) return theta;
return angle;
}
function arcPathGenerator(size) {
return d3.svg.arc().innerRadius((innerRadius + radius) / 2 - size / 2 * (radius - innerRadius)).outerRadius((innerRadius + radius) / 2 + size / 2 * (radius - innerRadius)).startAngle(-theta);
}
function drawArc(p) {
p.attr('d', function (d) {
return arcPathGenerator(d.thickness).startAngle(valueToAngle(d.range[0])).endAngle(valueToAngle(d.range[1]))();
});
}
// preparing axis
var ax, vals, transFn, tickSign;
// Enter gauge and axis
gauge.enter().append('g').classed('angular', true);
gauge.attr('transform', strTranslate(gaugePosition[0], gaugePosition[1]));
axisLayer.enter().append('g').classed('angularaxis', true).classed('crisp', true);
axisLayer.selectAll('g.' + 'xangularaxis' + 'tick,path,text').remove();
ax = mockAxis(gd, trace.gauge.axis);
ax.type = 'linear';
ax.range = trace.gauge.axis.range;
ax._id = 'xangularaxis'; // or 'y', but I don't think this makes a difference here
ax.ticklabeloverflow = 'allow';
ax.setScale();
// 't'ick to 'g'eometric radians is used all over the place here
var t2g = function (d) {
return (ax.range[0] - d.x) / (ax.range[1] - ax.range[0]) * Math.PI + Math.PI;
};
var labelFns = {};
var out = Axes.makeLabelFns(ax, 0);
var labelStandoff = out.labelStandoff;
labelFns.xFn = function (d) {
var rad = t2g(d);
return Math.cos(rad) * labelStandoff;
};
labelFns.yFn = function (d) {
var rad = t2g(d);
var ff = Math.sin(rad) > 0 ? 0.2 : 1;
return -Math.sin(rad) * (labelStandoff + d.fontSize * ff) + Math.abs(Math.cos(rad)) * (d.fontSize * MID_SHIFT);
};
labelFns.anchorFn = function (d) {
var rad = t2g(d);
var cos = Math.cos(rad);
return Math.abs(cos) < 0.1 ? 'middle' : cos > 0 ? 'start' : 'end';
};
labelFns.heightFn = function (d, a, h) {
var rad = t2g(d);
return -0.5 * (1 + Math.sin(rad)) * h;
};
var _transFn = function (rad) {
return strTranslate(gaugePosition[0] + radius * Math.cos(rad), gaugePosition[1] - radius * Math.sin(rad));
};
transFn = function (d) {
return _transFn(t2g(d));
};
var transFn2 = function (d) {
var rad = t2g(d);
return _transFn(rad) + 'rotate(' + -rad2deg(rad) + ')';
};
vals = Axes.calcTicks(ax);
tickSign = Axes.getTickSigns(ax)[2];
if (ax.visible) {
tickSign = ax.ticks === 'inside' ? -1 : 1;
var pad = (ax.linewidth || 1) / 2;
Axes.drawTicks(gd, ax, {
vals: vals,
layer: axisLayer,
path: 'M' + tickSign * pad + ',0h' + tickSign * ax.ticklen,
transFn: transFn2
});
Axes.drawLabels(gd, ax, {
vals: vals,
layer: axisLayer,
transFn: transFn,
labelFns: labelFns
});
}
// Draw background + steps
var arcs = [gaugeBg].concat(trace.gauge.steps);
var bgArc = gauge.selectAll('g.bg-arc').data(arcs);
bgArc.enter().append('g').classed('bg-arc', true).append('path');
bgArc.select('path').call(drawArc).call(styleShape);
bgArc.exit().remove();
// Draw foreground with transition
var valueArcPathGenerator = arcPathGenerator(trace.gauge.bar.thickness);
var valueArc = gauge.selectAll('g.value-arc').data([trace.gauge.bar]);
valueArc.enter().append('g').classed('value-arc', true).append('path');
var valueArcPath = valueArc.select('path');
if (hasTransition(transitionOpts)) {
valueArcPath.transition().duration(transitionOpts.duration).ease(transitionOpts.easing).each('end', function () {
onComplete && onComplete();
}).each('interrupt', function () {
onComplete && onComplete();
}).attrTween('d', arcTween(valueArcPathGenerator, valueToAngle(cd[0].lastY), valueToAngle(cd[0].y)));
trace._lastValue = cd[0].y;
} else {
valueArcPath.attr('d', typeof cd[0].y === 'number' ? valueArcPathGenerator.endAngle(valueToAngle(cd[0].y)) : 'M0,0Z');
}
valueArcPath.call(styleShape);
valueArc.exit().remove();
// Draw threshold
arcs = [];
var v = trace.gauge.threshold.value;
if (v || v === 0) {
arcs.push({
range: [v, v],
color: trace.gauge.threshold.color,
line: {
color: trace.gauge.threshold.line.color,
width: trace.gauge.threshold.line.width
},
thickness: trace.gauge.threshold.thickness
});
}
var thresholdArc = gauge.selectAll('g.threshold-arc').data(arcs);
thresholdArc.enter().append('g').classed('threshold-arc', true).append('path');
thresholdArc.select('path').call(drawArc).call(styleShape);
thresholdArc.exit().remove();
// Draw border last
var gaugeBorder = gauge.selectAll('g.gauge-outline').data([gaugeOutline]);
gaugeBorder.enter().append('g').classed('gauge-outline', true).append('path');
gaugeBorder.select('path').call(drawArc).call(styleShape);
gaugeBorder.exit().remove();
}
function drawNumbers(gd, plotGroup, cd, opts) {
var trace = cd[0].trace;
var numbersX = opts.numbersX;
var numbersY = opts.numbersY;
var numbersAlign = trace.align || 'center';
var numbersAnchor = anchor[numbersAlign];
var transitionOpts = opts.transitionOpts;
var onComplete = opts.onComplete;
var numbers = Lib.ensureSingle(plotGroup, 'g', 'numbers');
var bignumberbBox, deltabBox;
var numbersbBox;
var data = [];
if (trace._hasNumber) data.push('number');
if (trace._hasDelta) {
data.push('delta');
if (trace.delta.position === 'left') data.reverse();
}
var sel = numbers.selectAll('text').data(data);
sel.enter().append('text');
sel.attr('text-anchor', function () {
return numbersAnchor;
}).attr('class', function (d) {
return d;
}).attr('x', null).attr('y', null).attr('dx', null).attr('dy', null);
sel.exit().remove();
// Function to override the number formatting used during transitions
function transitionFormat(valueformat, fmt, from, to) {
// For now, do not display SI prefix if start and end value do not have any
if (valueformat.match('s') &&
// If using SI prefix
from >= 0 !== to >= 0 &&
// If sign change
!fmt(from).slice(-1).match(SI_PREFIX) && !fmt(to).slice(-1).match(SI_PREFIX) // Has no SI prefix
) {
var transitionValueFormat = valueformat.slice().replace('s', 'f').replace(/\d+/, function (m) {
return parseInt(m) - 1;
});
var transitionAx = mockAxis(gd, {
tickformat: transitionValueFormat
});
return function (v) {
// Switch to fixed precision if number is smaller than one
if (Math.abs(v) < 1) return Axes.tickText(transitionAx, v).text;
return fmt(v);
};
} else {
return fmt;
}
}
function drawBignumber() {
var bignumberAx = mockAxis(gd, {
tickformat: trace.number.valueformat
}, trace._range);
bignumberAx.setScale();
Axes.prepTicks(bignumberAx);
var bignumberFmt = function (v) {
return Axes.tickText(bignumberAx, v).text;
};
var bignumberSuffix = trace.number.suffix;
var bignumberPrefix = trace.number.prefix;
var number = numbers.select('text.number');
function writeNumber() {
var txt = typeof cd[0].y === 'number' ? bignumberPrefix + bignumberFmt(cd[0].y) + bignumberSuffix : '-';
number.text(txt).call(Drawing.font, trace.number.font).call(svgTextUtils.convertToTspans, gd);
}
if (hasTransition(transitionOpts)) {
number.transition().duration(transitionOpts.duration).ease(transitionOpts.easing).each('end', function () {
writeNumber();
onComplete && onComplete();
}).each('interrupt', function () {
writeNumber();
onComplete && onComplete();
}).attrTween('text', function () {
var that = d3.select(this);
var interpolator = interpolateNumber(cd[0].lastY, cd[0].y);
trace._lastValue = cd[0].y;
var transitionFmt = transitionFormat(trace.number.valueformat, bignumberFmt, cd[0].lastY, cd[0].y);
return function (t) {
that.text(bignumberPrefix + transitionFmt(interpolator(t)) + bignumberSuffix);
};
});
} else {
writeNumber();
}
bignumberbBox = measureText(bignumberPrefix + bignumberFmt(cd[0].y) + bignumberSuffix, trace.number.font, numbersAnchor, gd);
return number;
}
function drawDelta() {
var deltaAx = mockAxis(gd, {
tickformat: trace.delta.valueformat
}, trace._range);
deltaAx.setScale();
Axes.prepTicks(deltaAx);
var deltaFmt = function (v) {
return Axes.tickText(deltaAx, v).text;
};
var deltaSuffix = trace.delta.suffix;
var deltaPrefix = trace.delta.prefix;
var deltaValue = function (d) {
var value = trace.delta.relative ? d.relativeDelta : d.delta;
return value;
};
var deltaFormatText = function (value, numberFmt) {
if (value === 0 || typeof value !== 'number' || isNaN(value)) return '-';
return (value > 0 ? trace.delta.increasing.symbol : trace.delta.decreasing.symbol) + deltaPrefix + numberFmt(value) + deltaSuffix;
};
var deltaFill = function (d) {
return d.delta >= 0 ? trace.delta.increasing.color : trace.delta.decreasing.color;
};
if (trace._deltaLastValue === undefined) {
trace._deltaLastValue = deltaValue(cd[0]);
}
var delta = numbers.select('text.delta');
delta.call(Drawing.font, trace.delta.font).call(Color.fill, deltaFill({
delta: trace._deltaLastValue
}));
function writeDelta() {
delta.text(deltaFormatText(deltaValue(cd[0]), deltaFmt)).call(Color.fill, deltaFill(cd[0])).call(svgTextUtils.convertToTspans, gd);
}
if (hasTransition(transitionOpts)) {
delta.transition().duration(transitionOpts.duration).ease(transitionOpts.easing).tween('text', function () {
var that = d3.select(this);
var to = deltaValue(cd[0]);
var from = trace._deltaLastValue;
var transitionFmt = transitionFormat(trace.delta.valueformat, deltaFmt, from, to);
var interpolator = interpolateNumber(from, to);
trace._deltaLastValue = to;
return function (t) {
that.text(deltaFormatText(interpolator(t), transitionFmt));
that.call(Color.fill, deltaFill({
delta: interpolator(t)
}));
};
}).each('end', function () {
writeDelta();
onComplete && onComplete();
}).each('interrupt', function () {
writeDelta();
onComplete && onComplete();
});
} else {
writeDelta();
}
deltabBox = measureText(deltaFormatText(deltaValue(cd[0]), deltaFmt), trace.delta.font, numbersAnchor, gd);
return delta;
}
var key = trace.mode + trace.align;
var delta;
if (trace._hasDelta) {
delta = drawDelta();
key += trace.delta.position + trace.delta.font.size + trace.delta.font.family + trace.delta.valueformat;
key += trace.delta.increasing.symbol + trace.delta.decreasing.symbol;
numbersbBox = deltabBox;
}
if (trace._hasNumber) {
drawBignumber();
key += trace.number.font.size + trace.number.font.family + trace.number.valueformat + trace.number.suffix + trace.number.prefix;
numbersbBox = bignumberbBox;
}
// Position delta relative to bignumber
if (trace._hasDelta && trace._hasNumber) {
var bignumberCenter = [(bignumberbBox.left + bignumberbBox.right) / 2, (bignumberbBox.top + bignumberbBox.bottom) / 2];
var deltaCenter = [(deltabBox.left + deltabBox.right) / 2, (deltabBox.top + deltabBox.bottom) / 2];
var dx, dy;
var padding = 0.75 * trace.delta.font.size;
if (trace.delta.position === 'left') {
dx = cache(trace, 'deltaPos', 0, -1 * (bignumberbBox.width * position[trace.align] + deltabBox.width * (1 - position[trace.align]) + padding), key, Math.min);
dy = bignumberCenter[1] - deltaCenter[1];
numbersbBox = {
width: bignumberbBox.width + deltabBox.width + padding,
height: Math.max(bignumberbBox.height, deltabBox.height),
left: deltabBox.left + dx,
right: bignumberbBox.right,
top: Math.min(bignumberbBox.top, deltabBox.top + dy),
bottom: Math.max(bignumberbBox.bottom, deltabBox.bottom + dy)
};
}
if (trace.delta.position === 'right') {
dx = cache(trace, 'deltaPos', 0, bignumberbBox.width * (1 - position[trace.align]) + deltabBox.width * position[trace.align] + padding, key, Math.max);
dy = bignumberCenter[1] - deltaCenter[1];
numbersbBox = {
width: bignumberbBox.width + deltabBox.width + padding,
height: Math.max(bignumberbBox.height, deltabBox.height),
left: bignumberbBox.left,
right: deltabBox.right + dx,
top: Math.min(bignumberbBox.top, deltabBox.top + dy),
bottom: Math.max(bignumberbBox.bottom, deltabBox.bottom + dy)
};
}
if (trace.delta.position === 'bottom') {
dx = null;
dy = deltabBox.height;
numbersbBox = {
width: Math.max(bignumberbBox.width, deltabBox.width),
height: bignumberbBox.height + deltabBox.height,
left: Math.min(bignumberbBox.left, deltabBox.left),
right: Math.max(bignumberbBox.right, deltabBox.right),
top: bignumberbBox.bottom - bignumberbBox.height,
bottom: bignumberbBox.bottom + deltabBox.height
};
}
if (trace.delta.position === 'top') {
dx = null;
dy = bignumberbBox.top;
numbersbBox = {
width: Math.max(bignumberbBox.width, deltabBox.width),
height: bignumberbBox.height + deltabBox.height,
left: Math.min(bignumberbBox.left, deltabBox.left),
right: Math.max(bignumberbBox.right, deltabBox.right),
top: bignumberbBox.bottom - bignumberbBox.height - deltabBox.height,
bottom: bignumberbBox.bottom
};
}
delta.attr({
dx: dx,
dy: dy
});
}
// Resize numbers to fit within space and position
if (trace._hasNumber || trace._hasDelta) {
numbers.attr('transform', function () {
var m = opts.numbersScaler(numbersbBox);
key += m[2];
var scaleRatio = cache(trace, 'numbersScale', 1, m[0], key, Math.min);
var translateY;
if (!trace._scaleNumbers) scaleRatio = 1;
if (trace._isAngular) {
// align vertically to bottom
translateY = numbersY - scaleRatio * numbersbBox.bottom;
} else {
// align vertically to center
translateY = numbersY - scaleRatio * (numbersbBox.top + numbersbBox.bottom) / 2;
}
// Stash the top position of numbersbBox for title positioning
trace._numbersTop = scaleRatio * numbersbBox.top + translateY;
var ref = numbersbBox[numbersAlign];
if (numbersAlign === 'center') ref = (numbersbBox.left + numbersbBox.right) / 2;
var translateX = numbersX - scaleRatio * ref;
// Stash translateX
translateX = cache(trace, 'numbersTranslate', 0, translateX, key, Math.max);
return strTranslate(translateX, translateY) + strScale(scaleRatio);
});
}
}
// Apply fill, stroke, stroke-width to SVG shape
function styleShape(p) {
p.each(function (d) {
Color.stroke(d3.select(this), d.line.color);
}).each(function (d) {
Color.fill(d3.select(this), d.color);
}).style('stroke-width', function (d) {
return d.line.width;
});
}
// Returns a tween for a transition’s "d" attribute, transitioning any selected
// arcs from their current angle to the specified new angle.
function arcTween(arc, endAngle, newAngle) {
return function () {
var interp = interpolate(endAngle, newAngle);
return function (t) {
return arc.endAngle(interp(t))();
};
};
}
// mocks our axis
function mockAxis(gd, opts, zrange) {
var fullLayout = gd._fullLayout;
var axisIn = Lib.extendFlat({
type: 'linear',
ticks: 'outside',
range: zrange,
showline: true
}, opts);
var axisOut = {
type: 'linear',
_id: 'x' + opts._id
};
var axisOptions = {
letter: 'x',
font: fullLayout.font,
noAutotickangles: true,
noHover: true,
noTickson: true
};
function coerce(attr, dflt) {
return Lib.coerce(axisIn, axisOut, axisLayoutAttrs, attr, dflt);
}
handleAxisDefaults(axisIn, axisOut, coerce, axisOptions, fullLayout);
handleAxisPositionDefaults(axisIn, axisOut, coerce, axisOptions);
return axisOut;
}
function fitTextInsideBox(textBB, width, height) {
// compute scaling ratio to have text fit within specified width and height
var ratio = Math.min(width / textBB.width, height / textBB.height);
return [ratio, textBB, width + 'x' + height];
}
function fitTextInsideCircle(textBB, radius) {
// compute scaling ratio to have text fit within specified radius
var elRadius = Math.sqrt(textBB.width / 2 * (textBB.width / 2) + textBB.height * textBB.height);
var ratio = radius / elRadius;
return [ratio, textBB, radius];
}
function measureText(txt, font, textAnchor, gd) {
var element = document.createElementNS('http://www.w3.org/2000/svg', 'text');
var sel = d3.select(element);
sel.text(txt).attr('x', 0).attr('y', 0).attr('text-anchor', textAnchor).attr('data-unformatted', txt).call(svgTextUtils.convertToTspans, gd).call(Drawing.font, font);
return Drawing.bBox(sel.node());
}
function cache(trace, name, initialValue, value, key, fn) {
var objName = '_cache' + name;
if (!(trace[objName] && trace[objName].key === key)) {
trace[objName] = {
key: key,
value: initialValue
};
}
var v = Lib.aggNums(fn, null, [trace[objName].value, value], 2);
trace[objName].value = v;
return v;
}
/***/ }),
/***/ 32560:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorScaleAttrs = __webpack_require__(99732);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var meshAttrs = __webpack_require__(13000);
var baseAttrs = __webpack_require__(6040);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
function makeSliceAttr(axLetter) {
return {
show: {
valType: 'boolean',
dflt: false,
description: ['Determines whether or not slice planes about the', axLetter, 'dimension are drawn.'].join(' ')
},
locations: {
valType: 'data_array',
dflt: [],
description: ['Specifies the location(s) of slices on the axis.', 'When not specified slices would be created for', 'all points of the axis', axLetter, 'except start and end.'].join(' ')
},
fill: {
valType: 'number',
min: 0,
max: 1,
dflt: 1,
description: ['Sets the fill ratio of the `slices`. The default fill value of the', '`slices` is 1 meaning that they are entirely shaded. On the other hand', 'Applying a `fill` ratio less than one would allow the creation of', 'openings parallel to the edges.'].join(' ')
}
};
}
function makeCapAttr(axLetter) {
return {
show: {
valType: 'boolean',
dflt: true,
description: ['Sets the fill ratio of the `slices`. The default fill value of the', axLetter, '`slices` is 1 meaning that they are entirely shaded. On the other hand', 'Applying a `fill` ratio less than one would allow the creation of', 'openings parallel to the edges.'].join(' ')
},
fill: {
valType: 'number',
min: 0,
max: 1,
dflt: 1,
description: ['Sets the fill ratio of the `caps`. The default fill value of the', '`caps` is 1 meaning that they are entirely shaded. On the other hand', 'Applying a `fill` ratio less than one would allow the creation of', 'openings parallel to the edges.'].join(' ')
}
};
}
var attrs = module.exports = overrideAll(extendFlat({
x: {
valType: 'data_array',
description: ['Sets the X coordinates of the vertices on X axis.'].join(' ')
},
y: {
valType: 'data_array',
description: ['Sets the Y coordinates of the vertices on Y axis.'].join(' ')
},
z: {
valType: 'data_array',
description: ['Sets the Z coordinates of the vertices on Z axis.'].join(' ')
},
value: {
valType: 'data_array',
description: ['Sets the 4th dimension (value) of the vertices.'].join(' ')
},
isomin: {
valType: 'number',
description: ['Sets the minimum boundary for iso-surface plot.'].join(' ')
},
isomax: {
valType: 'number',
description: ['Sets the maximum boundary for iso-surface plot.'].join(' ')
},
surface: {
show: {
valType: 'boolean',
dflt: true,
description: ['Hides/displays surfaces between minimum and maximum iso-values.'].join(' ')
},
count: {
valType: 'integer',
dflt: 2,
min: 1,
description: ['Sets the number of iso-surfaces between minimum and maximum iso-values.', 'By default this value is 2 meaning that only minimum and maximum surfaces', 'would be drawn.'].join(' ')
},
fill: {
valType: 'number',
min: 0,
max: 1,
dflt: 1,
description: ['Sets the fill ratio of the iso-surface. The default fill value of the', 'surface is 1 meaning that they are entirely shaded. On the other hand', 'Applying a `fill` ratio less than one would allow the creation of', 'openings parallel to the edges.'].join(' ')
},
pattern: {
valType: 'flaglist',
flags: ['A', 'B', 'C', 'D', 'E'],
extras: ['all', 'odd', 'even'],
dflt: 'all',
description: ['Sets the surface pattern of the iso-surface 3-D sections. The default pattern of', 'the surface is `all` meaning that the rest of surface elements would be shaded.', 'The check options (either 1 or 2) could be used to draw half of the squares', 'on the surface. Using various combinations of capital `A`, `B`, `C`, `D` and `E`', 'may also be used to reduce the number of triangles on the iso-surfaces and', 'creating other patterns of interest.'].join(' ')
}
},
spaceframe: {
show: {
valType: 'boolean',
dflt: false,
description: ['Displays/hides tetrahedron shapes between minimum and', 'maximum iso-values. Often useful when either caps or', 'surfaces are disabled or filled with values less than 1.'].join(' ')
},
fill: {
valType: 'number',
min: 0,
max: 1,
dflt: 0.15,
description: ['Sets the fill ratio of the `spaceframe` elements. The default fill value', 'is 0.15 meaning that only 15% of the area of every faces of tetras would be', 'shaded. Applying a greater `fill` ratio would allow the creation of stronger', 'elements or could be sued to have entirely closed areas (in case of using 1).'].join(' ')
}
},
slices: {
x: makeSliceAttr('x'),
y: makeSliceAttr('y'),
z: makeSliceAttr('z')
},
caps: {
x: makeCapAttr('x'),
y: makeCapAttr('y'),
z: makeCapAttr('z')
},
text: {
valType: 'string',
dflt: '',
arrayOk: true,
description: ['Sets the text elements associated with the vertices.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
},
hovertext: {
valType: 'string',
dflt: '',
arrayOk: true,
description: 'Same as `text`.'
},
hovertemplate: hovertemplateAttrs(),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z'),
valuehoverformat: axisHoverFormat('value', 1),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
}, colorScaleAttrs('', {
colorAttr: '`value`',
showScaleDflt: true,
editTypeOverride: 'calc'
}), {
opacity: meshAttrs.opacity,
lightposition: meshAttrs.lightposition,
lighting: meshAttrs.lighting,
flatshading: meshAttrs.flatshading,
contour: meshAttrs.contour,
hoverinfo: extendFlat({}, baseAttrs.hoverinfo)
}), 'calc', 'nested');
// required defaults to speed up surface normal calculations
attrs.flatshading.dflt = true;
attrs.lighting.facenormalsepsilon.dflt = 0;
attrs.x.editType = attrs.y.editType = attrs.z.editType = attrs.value.editType = 'calc+clearAxisTypes';
attrs.transforms = undefined;
/***/ }),
/***/ 70260:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorscaleCalc = __webpack_require__(60416);
var processGrid = (__webpack_require__(84720).processGrid);
var filter = (__webpack_require__(84720).filter);
module.exports = function calc(gd, trace) {
trace._len = Math.min(trace.x.length, trace.y.length, trace.z.length, trace.value.length);
trace._x = filter(trace.x, trace._len);
trace._y = filter(trace.y, trace._len);
trace._z = filter(trace.z, trace._len);
trace._value = filter(trace.value, trace._len);
var grid = processGrid(trace);
trace._gridFill = grid.fill;
trace._Xs = grid.Xs;
trace._Ys = grid.Ys;
trace._Zs = grid.Zs;
trace._len = grid.len;
var min = Infinity;
var max = -Infinity;
for (var i = 0; i < trace._len; i++) {
var v = trace._value[i];
min = Math.min(min, v);
max = Math.max(max, v);
}
trace._minValues = min;
trace._maxValues = max;
trace._vMin = trace.isomin === undefined || trace.isomin === null ? min : trace.isomin;
trace._vMax = trace.isomax === undefined || trace.isomin === null ? max : trace.isomax;
colorscaleCalc(gd, trace, {
vals: [trace._vMin, trace._vMax],
containerStr: '',
cLetter: 'c'
});
};
/***/ }),
/***/ 80296:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createMesh = (__webpack_require__(14656).gl_mesh3d);
var parseColorScale = (__webpack_require__(13396).parseColorScale);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var str2RgbaArray = __webpack_require__(29864);
var extractOpts = (__webpack_require__(26733).extractOpts);
var zip3 = __webpack_require__(90644);
var findNearestOnAxis = function (w, arr) {
for (var q = arr.length - 1; q > 0; q--) {
var min = Math.min(arr[q], arr[q - 1]);
var max = Math.max(arr[q], arr[q - 1]);
if (max > min && min < w && w <= max) {
return {
id: q,
distRatio: (max - w) / (max - min)
};
}
}
return {
id: 0,
distRatio: 0
};
};
function IsosurfaceTrace(scene, mesh, uid) {
this.scene = scene;
this.uid = uid;
this.mesh = mesh;
this.name = '';
this.data = null;
this.showContour = false;
}
var proto = IsosurfaceTrace.prototype;
proto.handlePick = function (selection) {
if (selection.object === this.mesh) {
var rawId = selection.data.index;
var x = this.data._meshX[rawId];
var y = this.data._meshY[rawId];
var z = this.data._meshZ[rawId];
var height = this.data._Ys.length;
var depth = this.data._Zs.length;
var i = findNearestOnAxis(x, this.data._Xs).id;
var j = findNearestOnAxis(y, this.data._Ys).id;
var k = findNearestOnAxis(z, this.data._Zs).id;
var selectIndex = selection.index = k + depth * j + depth * height * i;
selection.traceCoordinate = [this.data._meshX[selectIndex], this.data._meshY[selectIndex], this.data._meshZ[selectIndex], this.data._value[selectIndex]];
var text = this.data.hovertext || this.data.text;
if (isArrayOrTypedArray(text) && text[selectIndex] !== undefined) {
selection.textLabel = text[selectIndex];
} else if (text) {
selection.textLabel = text;
}
return true;
}
};
proto.update = function (data) {
var scene = this.scene;
var layout = scene.fullSceneLayout;
this.data = generateIsoMeshes(data);
// Unpack position data
function toDataCoords(axis, coord, scale, calendar) {
return coord.map(function (x) {
return axis.d2l(x, 0, calendar) * scale;
});
}
var positions = zip3(toDataCoords(layout.xaxis, data._meshX, scene.dataScale[0], data.xcalendar), toDataCoords(layout.yaxis, data._meshY, scene.dataScale[1], data.ycalendar), toDataCoords(layout.zaxis, data._meshZ, scene.dataScale[2], data.zcalendar));
var cells = zip3(data._meshI, data._meshJ, data._meshK);
var config = {
positions: positions,
cells: cells,
lightPosition: [data.lightposition.x, data.lightposition.y, data.lightposition.z],
ambient: data.lighting.ambient,
diffuse: data.lighting.diffuse,
specular: data.lighting.specular,
roughness: data.lighting.roughness,
fresnel: data.lighting.fresnel,
vertexNormalsEpsilon: data.lighting.vertexnormalsepsilon,
faceNormalsEpsilon: data.lighting.facenormalsepsilon,
opacity: data.opacity,
contourEnable: data.contour.show,
contourColor: str2RgbaArray(data.contour.color).slice(0, 3),
contourWidth: data.contour.width,
useFacetNormals: data.flatshading
};
var cOpts = extractOpts(data);
config.vertexIntensity = data._meshIntensity;
config.vertexIntensityBounds = [cOpts.min, cOpts.max];
config.colormap = parseColorScale(data);
// Update mesh
this.mesh.update(config);
};
proto.dispose = function () {
this.scene.glplot.remove(this.mesh);
this.mesh.dispose();
};
var GRID_TYPES = ['xyz', 'xzy', 'yxz', 'yzx', 'zxy', 'zyx'];
function generateIsoMeshes(data) {
data._meshI = [];
data._meshJ = [];
data._meshK = [];
var showSurface = data.surface.show;
var showSpaceframe = data.spaceframe.show;
var surfaceFill = data.surface.fill;
var spaceframeFill = data.spaceframe.fill;
var drawingSurface = false;
var drawingSpaceframe = false;
var numFaces = 0;
var numVertices;
var beginVertextLength;
var Xs = data._Xs;
var Ys = data._Ys;
var Zs = data._Zs;
var width = Xs.length;
var height = Ys.length;
var depth = Zs.length;
var filled = GRID_TYPES.indexOf(data._gridFill.replace(/-/g, '').replace(/\+/g, ''));
var getIndex = function (i, j, k) {
switch (filled) {
case 5:
// 'zyx'
return k + depth * j + depth * height * i;
case 4:
// 'zxy'
return k + depth * i + depth * width * j;
case 3:
// 'yzx'
return j + height * k + height * depth * i;
case 2:
// 'yxz'
return j + height * i + height * width * k;
case 1:
// 'xzy'
return i + width * k + width * depth * j;
default:
// case 0: // 'xyz'
return i + width * j + width * height * k;
}
};
var minValues = data._minValues;
var maxValues = data._maxValues;
var vMin = data._vMin;
var vMax = data._vMax;
var allXs;
var allYs;
var allZs;
var allVs;
function findVertexId(x, y, z) {
// could be used to find the vertex id of previously generated vertex within the group
var len = allVs.length;
for (var f = beginVertextLength; f < len; f++) {
if (x === allXs[f] && y === allYs[f] && z === allZs[f]) {
return f;
}
}
return -1;
}
function beginGroup() {
beginVertextLength = numVertices;
}
function emptyVertices() {
allXs = [];
allYs = [];
allZs = [];
allVs = [];
numVertices = 0;
beginGroup();
}
function addVertex(x, y, z, v) {
allXs.push(x);
allYs.push(y);
allZs.push(z);
allVs.push(v);
numVertices++;
return numVertices - 1;
}
function addFace(a, b, c) {
data._meshI.push(a);
data._meshJ.push(b);
data._meshK.push(c);
numFaces++;
return numFaces - 1;
}
function getCenter(A, B, C) {
var M = [];
for (var i = 0; i < A.length; i++) {
M[i] = (A[i] + B[i] + C[i]) / 3.0;
}
return M;
}
function getBetween(A, B, r) {
var M = [];
for (var i = 0; i < A.length; i++) {
M[i] = A[i] * (1 - r) + r * B[i];
}
return M;
}
var activeFill;
function setFill(fill) {
activeFill = fill;
}
function createOpenTri(xyzv, abc) {
var A = xyzv[0];
var B = xyzv[1];
var C = xyzv[2];
var G = getCenter(A, B, C);
var r = Math.sqrt(1 - activeFill);
var p1 = getBetween(G, A, r);
var p2 = getBetween(G, B, r);
var p3 = getBetween(G, C, r);
var a = abc[0];
var b = abc[1];
var c = abc[2];
return {
xyzv: [[A, B, p2], [p2, p1, A], [B, C, p3], [p3, p2, B], [C, A, p1], [p1, p3, C]],
abc: [[a, b, -1], [-1, -1, a], [b, c, -1], [-1, -1, b], [c, a, -1], [-1, -1, c]]
};
}
function styleIncludes(style, char) {
if (style === 'all' || style === null) return true;
return style.indexOf(char) > -1;
}
function mapValue(style, value) {
if (style === null) return value;
return style;
}
function drawTri(style, xyzv, abc) {
beginGroup();
var allXYZVs = [xyzv];
var allABCs = [abc];
if (activeFill >= 1) {
allXYZVs = [xyzv];
allABCs = [abc];
} else if (activeFill > 0) {
var openTri = createOpenTri(xyzv, abc);
allXYZVs = openTri.xyzv;
allABCs = openTri.abc;
}
for (var f = 0; f < allXYZVs.length; f++) {
xyzv = allXYZVs[f];
abc = allABCs[f];
var pnts = [];
for (var i = 0; i < 3; i++) {
var x = xyzv[i][0];
var y = xyzv[i][1];
var z = xyzv[i][2];
var v = xyzv[i][3];
var id = abc[i] > -1 ? abc[i] : findVertexId(x, y, z);
if (id > -1) {
pnts[i] = id;
} else {
pnts[i] = addVertex(x, y, z, mapValue(style, v));
}
}
addFace(pnts[0], pnts[1], pnts[2]);
}
}
function drawQuad(style, xyzv, abcd) {
var makeTri = function (i, j, k) {
drawTri(style, [xyzv[i], xyzv[j], xyzv[k]], [abcd[i], abcd[j], abcd[k]]);
};
makeTri(0, 1, 2);
makeTri(2, 3, 0);
}
function drawTetra(style, xyzv, abcd) {
var makeTri = function (i, j, k) {
drawTri(style, [xyzv[i], xyzv[j], xyzv[k]], [abcd[i], abcd[j], abcd[k]]);
};
makeTri(0, 1, 2);
makeTri(3, 0, 1);
makeTri(2, 3, 0);
makeTri(1, 2, 3);
}
function calcIntersection(pointOut, pointIn, min, max) {
var value = pointOut[3];
if (value < min) value = min;
if (value > max) value = max;
var ratio = (pointOut[3] - value) / (pointOut[3] - pointIn[3] + 0.000000001); // we had to add this error to force solve the tiny caps
var result = [];
for (var s = 0; s < 4; s++) {
result[s] = (1 - ratio) * pointOut[s] + ratio * pointIn[s];
}
return result;
}
function inRange(value, min, max) {
return value >= min && value <= max;
}
function almostInFinalRange(value) {
var vErr = 0.001 * (vMax - vMin);
return value >= vMin - vErr && value <= vMax + vErr;
}
function getXYZV(indecies) {
var xyzv = [];
for (var q = 0; q < 4; q++) {
var index = indecies[q];
xyzv.push([data._x[index], data._y[index], data._z[index], data._value[index]]);
}
return xyzv;
}
var MAX_PASS = 3;
function tryCreateTri(style, xyzv, abc, min, max, nPass) {
if (!nPass) nPass = 1;
abc = [-1, -1, -1]; // Note: for the moment we override indices
// to run faster! But it is possible to comment this line
// to reduce the number of vertices.
var result = false;
var ok = [inRange(xyzv[0][3], min, max), inRange(xyzv[1][3], min, max), inRange(xyzv[2][3], min, max)];
if (!ok[0] && !ok[1] && !ok[2]) {
return false;
}
var tryDrawTri = function (style, xyzv, abc) {
if (
// we check here if the points are in `real` iso-min/max range
almostInFinalRange(xyzv[0][3]) && almostInFinalRange(xyzv[1][3]) && almostInFinalRange(xyzv[2][3])) {
drawTri(style, xyzv, abc);
return true;
} else if (nPass < MAX_PASS) {
return tryCreateTri(style, xyzv, abc, vMin, vMax, ++nPass); // i.e. second pass using actual vMin vMax bounds
}
return false;
};
if (ok[0] && ok[1] && ok[2]) {
return tryDrawTri(style, xyzv, abc) || result;
}
var interpolated = false;
[[0, 1, 2], [2, 0, 1], [1, 2, 0]].forEach(function (e) {
if (ok[e[0]] && ok[e[1]] && !ok[e[2]]) {
var A = xyzv[e[0]];
var B = xyzv[e[1]];
var C = xyzv[e[2]];
var p1 = calcIntersection(C, A, min, max);
var p2 = calcIntersection(C, B, min, max);
result = tryDrawTri(style, [p2, p1, A], [-1, -1, abc[e[0]]]) || result;
result = tryDrawTri(style, [A, B, p2], [abc[e[0]], abc[e[1]], -1]) || result;
interpolated = true;
}
});
if (interpolated) return result;
[[0, 1, 2], [1, 2, 0], [2, 0, 1]].forEach(function (e) {
if (ok[e[0]] && !ok[e[1]] && !ok[e[2]]) {
var A = xyzv[e[0]];
var B = xyzv[e[1]];
var C = xyzv[e[2]];
var p1 = calcIntersection(B, A, min, max);
var p2 = calcIntersection(C, A, min, max);
result = tryDrawTri(style, [p2, p1, A], [-1, -1, abc[e[0]]]) || result;
interpolated = true;
}
});
return result;
}
function tryCreateTetra(style, abcd, min, max) {
var result = false;
var xyzv = getXYZV(abcd);
var ok = [inRange(xyzv[0][3], min, max), inRange(xyzv[1][3], min, max), inRange(xyzv[2][3], min, max), inRange(xyzv[3][3], min, max)];
if (!ok[0] && !ok[1] && !ok[2] && !ok[3]) {
return result;
}
if (ok[0] && ok[1] && ok[2] && ok[3]) {
if (drawingSpaceframe) {
result = drawTetra(style, xyzv, abcd) || result;
}
return result;
}
var interpolated = false;
[[0, 1, 2, 3], [3, 0, 1, 2], [2, 3, 0, 1], [1, 2, 3, 0]].forEach(function (e) {
if (ok[e[0]] && ok[e[1]] && ok[e[2]] && !ok[e[3]]) {
var A = xyzv[e[0]];
var B = xyzv[e[1]];
var C = xyzv[e[2]];
var D = xyzv[e[3]];
if (drawingSpaceframe) {
result = drawTri(style, [A, B, C], [abcd[e[0]], abcd[e[1]], abcd[e[2]]]) || result;
} else {
var p1 = calcIntersection(D, A, min, max);
var p2 = calcIntersection(D, B, min, max);
var p3 = calcIntersection(D, C, min, max);
result = drawTri(null, [p1, p2, p3], [-1, -1, -1]) || result;
}
interpolated = true;
}
});
if (interpolated) return result;
[[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 0, 1, 2], [0, 2, 3, 1], [1, 3, 2, 0]].forEach(function (e) {
if (ok[e[0]] && ok[e[1]] && !ok[e[2]] && !ok[e[3]]) {
var A = xyzv[e[0]];
var B = xyzv[e[1]];
var C = xyzv[e[2]];
var D = xyzv[e[3]];
var p1 = calcIntersection(C, A, min, max);
var p2 = calcIntersection(C, B, min, max);
var p3 = calcIntersection(D, B, min, max);
var p4 = calcIntersection(D, A, min, max);
if (drawingSpaceframe) {
result = drawTri(style, [A, p4, p1], [abcd[e[0]], -1, -1]) || result;
result = drawTri(style, [B, p2, p3], [abcd[e[1]], -1, -1]) || result;
} else {
result = drawQuad(null, [p1, p2, p3, p4], [-1, -1, -1, -1]) || result;
}
interpolated = true;
}
});
if (interpolated) return result;
[[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 0, 1, 2]].forEach(function (e) {
if (ok[e[0]] && !ok[e[1]] && !ok[e[2]] && !ok[e[3]]) {
var A = xyzv[e[0]];
var B = xyzv[e[1]];
var C = xyzv[e[2]];
var D = xyzv[e[3]];
var p1 = calcIntersection(B, A, min, max);
var p2 = calcIntersection(C, A, min, max);
var p3 = calcIntersection(D, A, min, max);
if (drawingSpaceframe) {
result = drawTri(style, [A, p1, p2], [abcd[e[0]], -1, -1]) || result;
result = drawTri(style, [A, p2, p3], [abcd[e[0]], -1, -1]) || result;
result = drawTri(style, [A, p3, p1], [abcd[e[0]], -1, -1]) || result;
} else {
result = drawTri(null, [p1, p2, p3], [-1, -1, -1]) || result;
}
interpolated = true;
}
});
return result;
}
function addCube(style, p000, p001, p010, p011, p100, p101, p110, p111, min, max) {
var result = false;
if (drawingSurface) {
if (styleIncludes(style, 'A')) {
result = tryCreateTetra(null, [p000, p001, p010, p100], min, max) || result;
}
if (styleIncludes(style, 'B')) {
result = tryCreateTetra(null, [p001, p010, p011, p111], min, max) || result;
}
if (styleIncludes(style, 'C')) {
result = tryCreateTetra(null, [p001, p100, p101, p111], min, max) || result;
}
if (styleIncludes(style, 'D')) {
result = tryCreateTetra(null, [p010, p100, p110, p111], min, max) || result;
}
if (styleIncludes(style, 'E')) {
result = tryCreateTetra(null, [p001, p010, p100, p111], min, max) || result;
}
}
if (drawingSpaceframe) {
result = tryCreateTetra(style, [p001, p010, p100, p111], min, max) || result;
}
return result;
}
function addRect(style, a, b, c, d, min, max, previousResult) {
return [previousResult[0] === true ? true : tryCreateTri(style, getXYZV([a, b, c]), [a, b, c], min, max), previousResult[1] === true ? true : tryCreateTri(style, getXYZV([c, d, a]), [c, d, a], min, max)];
}
function begin2dCell(style, p00, p01, p10, p11, min, max, isEven, previousResult) {
// used to create caps and/or slices on exact axis points
if (isEven) {
return addRect(style, p00, p01, p11, p10, min, max, previousResult);
} else {
return addRect(style, p01, p11, p10, p00, min, max, previousResult);
}
}
function beginSection(style, i, j, k, min, max, distRatios) {
// used to create slices between axis points
var result = false;
var A, B, C, D;
var makeSection = function () {
result = tryCreateTri(style, [A, B, C], [-1, -1, -1], min, max) || result;
result = tryCreateTri(style, [C, D, A], [-1, -1, -1], min, max) || result;
};
var rX = distRatios[0];
var rY = distRatios[1];
var rZ = distRatios[2];
if (rX) {
A = getBetween(getXYZV([getIndex(i, j - 0, k - 0)])[0], getXYZV([getIndex(i - 1, j - 0, k - 0)])[0], rX);
B = getBetween(getXYZV([getIndex(i, j - 0, k - 1)])[0], getXYZV([getIndex(i - 1, j - 0, k - 1)])[0], rX);
C = getBetween(getXYZV([getIndex(i, j - 1, k - 1)])[0], getXYZV([getIndex(i - 1, j - 1, k - 1)])[0], rX);
D = getBetween(getXYZV([getIndex(i, j - 1, k - 0)])[0], getXYZV([getIndex(i - 1, j - 1, k - 0)])[0], rX);
makeSection();
}
if (rY) {
A = getBetween(getXYZV([getIndex(i - 0, j, k - 0)])[0], getXYZV([getIndex(i - 0, j - 1, k - 0)])[0], rY);
B = getBetween(getXYZV([getIndex(i - 0, j, k - 1)])[0], getXYZV([getIndex(i - 0, j - 1, k - 1)])[0], rY);
C = getBetween(getXYZV([getIndex(i - 1, j, k - 1)])[0], getXYZV([getIndex(i - 1, j - 1, k - 1)])[0], rY);
D = getBetween(getXYZV([getIndex(i - 1, j, k - 0)])[0], getXYZV([getIndex(i - 1, j - 1, k - 0)])[0], rY);
makeSection();
}
if (rZ) {
A = getBetween(getXYZV([getIndex(i - 0, j - 0, k)])[0], getXYZV([getIndex(i - 0, j - 0, k - 1)])[0], rZ);
B = getBetween(getXYZV([getIndex(i - 0, j - 1, k)])[0], getXYZV([getIndex(i - 0, j - 1, k - 1)])[0], rZ);
C = getBetween(getXYZV([getIndex(i - 1, j - 1, k)])[0], getXYZV([getIndex(i - 1, j - 1, k - 1)])[0], rZ);
D = getBetween(getXYZV([getIndex(i - 1, j - 0, k)])[0], getXYZV([getIndex(i - 1, j - 0, k - 1)])[0], rZ);
makeSection();
}
return result;
}
function begin3dCell(style, p000, p001, p010, p011, p100, p101, p110, p111, min, max, isEven) {
// used to create spaceframe and/or iso-surfaces
var cellStyle = style;
if (isEven) {
if (drawingSurface && style === 'even') cellStyle = null;
return addCube(cellStyle, p000, p001, p010, p011, p100, p101, p110, p111, min, max);
} else {
if (drawingSurface && style === 'odd') cellStyle = null;
return addCube(cellStyle, p111, p110, p101, p100, p011, p010, p001, p000, min, max);
}
}
function draw2dX(style, items, min, max, previousResult) {
var result = [];
var n = 0;
for (var q = 0; q < items.length; q++) {
var i = items[q];
for (var k = 1; k < depth; k++) {
for (var j = 1; j < height; j++) {
result.push(begin2dCell(style, getIndex(i, j - 1, k - 1), getIndex(i, j - 1, k), getIndex(i, j, k - 1), getIndex(i, j, k), min, max, (i + j + k) % 2, previousResult && previousResult[n] ? previousResult[n] : []));
n++;
}
}
}
return result;
}
function draw2dY(style, items, min, max, previousResult) {
var result = [];
var n = 0;
for (var q = 0; q < items.length; q++) {
var j = items[q];
for (var i = 1; i < width; i++) {
for (var k = 1; k < depth; k++) {
result.push(begin2dCell(style, getIndex(i - 1, j, k - 1), getIndex(i, j, k - 1), getIndex(i - 1, j, k), getIndex(i, j, k), min, max, (i + j + k) % 2, previousResult && previousResult[n] ? previousResult[n] : []));
n++;
}
}
}
return result;
}
function draw2dZ(style, items, min, max, previousResult) {
var result = [];
var n = 0;
for (var q = 0; q < items.length; q++) {
var k = items[q];
for (var j = 1; j < height; j++) {
for (var i = 1; i < width; i++) {
result.push(begin2dCell(style, getIndex(i - 1, j - 1, k), getIndex(i - 1, j, k), getIndex(i, j - 1, k), getIndex(i, j, k), min, max, (i + j + k) % 2, previousResult && previousResult[n] ? previousResult[n] : []));
n++;
}
}
}
return result;
}
function draw3d(style, min, max) {
for (var k = 1; k < depth; k++) {
for (var j = 1; j < height; j++) {
for (var i = 1; i < width; i++) {
begin3dCell(style, getIndex(i - 1, j - 1, k - 1), getIndex(i - 1, j - 1, k), getIndex(i - 1, j, k - 1), getIndex(i - 1, j, k), getIndex(i, j - 1, k - 1), getIndex(i, j - 1, k), getIndex(i, j, k - 1), getIndex(i, j, k), min, max, (i + j + k) % 2);
}
}
}
}
function drawSpaceframe(style, min, max) {
drawingSpaceframe = true;
draw3d(style, min, max);
drawingSpaceframe = false;
}
function drawSurface(style, min, max) {
drawingSurface = true;
draw3d(style, min, max);
drawingSurface = false;
}
function drawSectionX(style, items, min, max, distRatios, previousResult) {
var result = [];
var n = 0;
for (var q = 0; q < items.length; q++) {
var i = items[q];
for (var k = 1; k < depth; k++) {
for (var j = 1; j < height; j++) {
result.push(beginSection(style, i, j, k, min, max, distRatios[q], previousResult && previousResult[n] ? previousResult[n] : []));
n++;
}
}
}
return result;
}
function drawSectionY(style, items, min, max, distRatios, previousResult) {
var result = [];
var n = 0;
for (var q = 0; q < items.length; q++) {
var j = items[q];
for (var i = 1; i < width; i++) {
for (var k = 1; k < depth; k++) {
result.push(beginSection(style, i, j, k, min, max, distRatios[q], previousResult && previousResult[n] ? previousResult[n] : []));
n++;
}
}
}
return result;
}
function drawSectionZ(style, items, min, max, distRatios, previousResult) {
var result = [];
var n = 0;
for (var q = 0; q < items.length; q++) {
var k = items[q];
for (var j = 1; j < height; j++) {
for (var i = 1; i < width; i++) {
result.push(beginSection(style, i, j, k, min, max, distRatios[q], previousResult && previousResult[n] ? previousResult[n] : []));
n++;
}
}
}
return result;
}
function createRange(a, b) {
var range = [];
for (var q = a; q < b; q++) {
range.push(q);
}
return range;
}
function insertGridPoints() {
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++) {
for (var k = 0; k < depth; k++) {
var index = getIndex(i, j, k);
addVertex(data._x[index], data._y[index], data._z[index], data._value[index]);
}
}
}
}
function drawAll() {
emptyVertices();
// insert grid points
insertGridPoints();
var activeStyle = null;
// draw spaceframes
if (showSpaceframe && spaceframeFill) {
setFill(spaceframeFill);
drawSpaceframe(activeStyle, vMin, vMax);
}
// draw iso-surfaces
if (showSurface && surfaceFill) {
setFill(surfaceFill);
var surfacePattern = data.surface.pattern;
var surfaceCount = data.surface.count;
for (var q = 0; q < surfaceCount; q++) {
var ratio = surfaceCount === 1 ? 0.5 : q / (surfaceCount - 1);
var level = (1 - ratio) * vMin + ratio * vMax;
var d1 = Math.abs(level - minValues);
var d2 = Math.abs(level - maxValues);
var ranges = d1 > d2 ? [minValues, level] : [level, maxValues];
drawSurface(surfacePattern, ranges[0], ranges[1]);
}
}
var setupMinMax = [[Math.min(vMin, maxValues), Math.max(vMin, maxValues)], [Math.min(minValues, vMax), Math.max(minValues, vMax)]];
['x', 'y', 'z'].forEach(function (e) {
var preRes = [];
for (var s = 0; s < setupMinMax.length; s++) {
var count = 0;
var activeMin = setupMinMax[s][0];
var activeMax = setupMinMax[s][1];
// draw slices
var slice = data.slices[e];
if (slice.show && slice.fill) {
setFill(slice.fill);
var exactIndices = [];
var ceilIndices = [];
var distRatios = [];
if (slice.locations.length) {
for (var q = 0; q < slice.locations.length; q++) {
var near = findNearestOnAxis(slice.locations[q], e === 'x' ? Xs : e === 'y' ? Ys : Zs);
if (near.distRatio === 0) {
exactIndices.push(near.id);
} else if (near.id > 0) {
ceilIndices.push(near.id);
if (e === 'x') {
distRatios.push([near.distRatio, 0, 0]);
} else if (e === 'y') {
distRatios.push([0, near.distRatio, 0]);
} else {
distRatios.push([0, 0, near.distRatio]);
}
}
}
} else {
if (e === 'x') {
exactIndices = createRange(1, width - 1);
} else if (e === 'y') {
exactIndices = createRange(1, height - 1);
} else {
exactIndices = createRange(1, depth - 1);
}
}
if (ceilIndices.length > 0) {
if (e === 'x') {
preRes[count] = drawSectionX(activeStyle, ceilIndices, activeMin, activeMax, distRatios, preRes[count]);
} else if (e === 'y') {
preRes[count] = drawSectionY(activeStyle, ceilIndices, activeMin, activeMax, distRatios, preRes[count]);
} else {
preRes[count] = drawSectionZ(activeStyle, ceilIndices, activeMin, activeMax, distRatios, preRes[count]);
}
count++;
}
if (exactIndices.length > 0) {
if (e === 'x') {
preRes[count] = draw2dX(activeStyle, exactIndices, activeMin, activeMax, preRes[count]);
} else if (e === 'y') {
preRes[count] = draw2dY(activeStyle, exactIndices, activeMin, activeMax, preRes[count]);
} else {
preRes[count] = draw2dZ(activeStyle, exactIndices, activeMin, activeMax, preRes[count]);
}
count++;
}
}
// draw caps
var cap = data.caps[e];
if (cap.show && cap.fill) {
setFill(cap.fill);
if (e === 'x') {
preRes[count] = draw2dX(activeStyle, [0, width - 1], activeMin, activeMax, preRes[count]);
} else if (e === 'y') {
preRes[count] = draw2dY(activeStyle, [0, height - 1], activeMin, activeMax, preRes[count]);
} else {
preRes[count] = draw2dZ(activeStyle, [0, depth - 1], activeMin, activeMax, preRes[count]);
}
count++;
}
}
});
// remove vertices arrays (i.e. grid points) in case no face was created.
if (numFaces === 0) {
emptyVertices();
}
data._meshX = allXs;
data._meshY = allYs;
data._meshZ = allZs;
data._meshIntensity = allVs;
data._Xs = Xs;
data._Ys = Ys;
data._Zs = Zs;
}
drawAll();
return data;
}
function createIsosurfaceTrace(scene, data) {
var gl = scene.glplot.gl;
var mesh = createMesh({
gl: gl
});
var result = new IsosurfaceTrace(scene, mesh, data.uid);
mesh._trace = result;
result.update(data);
scene.glplot.add(mesh);
return result;
}
module.exports = {
findNearestOnAxis: findNearestOnAxis,
generateIsoMeshes: generateIsoMeshes,
createIsosurfaceTrace: createIsosurfaceTrace
};
/***/ }),
/***/ 30592:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
var attributes = __webpack_require__(32560);
var colorscaleDefaults = __webpack_require__(47280);
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
supplyIsoDefaults(traceIn, traceOut, defaultColor, layout, coerce);
}
function supplyIsoDefaults(traceIn, traceOut, defaultColor, layout, coerce) {
var isomin = coerce('isomin');
var isomax = coerce('isomax');
if (isomax !== undefined && isomax !== null && isomin !== undefined && isomin !== null && isomin > isomax) {
// applying default values in this case:
traceOut.isomin = null;
traceOut.isomax = null;
}
var x = coerce('x');
var y = coerce('y');
var z = coerce('z');
var value = coerce('value');
if (!x || !x.length || !y || !y.length || !z || !z.length || !value || !value.length) {
traceOut.visible = false;
return;
}
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x', 'y', 'z'], layout);
coerce('valuehoverformat');
['x', 'y', 'z'].forEach(function (dim) {
coerce(dim + 'hoverformat');
var capDim = 'caps.' + dim;
var showCap = coerce(capDim + '.show');
if (showCap) {
coerce(capDim + '.fill');
}
var sliceDim = 'slices.' + dim;
var showSlice = coerce(sliceDim + '.show');
if (showSlice) {
coerce(sliceDim + '.fill');
coerce(sliceDim + '.locations');
}
});
var showSpaceframe = coerce('spaceframe.show');
if (showSpaceframe) {
coerce('spaceframe.fill');
}
var showSurface = coerce('surface.show');
if (showSurface) {
coerce('surface.count');
coerce('surface.fill');
coerce('surface.pattern');
}
var showContour = coerce('contour.show');
if (showContour) {
coerce('contour.color');
coerce('contour.width');
}
// Coerce remaining properties
['text', 'hovertext', 'hovertemplate', 'lighting.ambient', 'lighting.diffuse', 'lighting.specular', 'lighting.roughness', 'lighting.fresnel', 'lighting.vertexnormalsepsilon', 'lighting.facenormalsepsilon', 'lightposition.x', 'lightposition.y', 'lightposition.z', 'flatshading', 'opacity'].forEach(function (x) {
coerce(x);
});
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'c'
});
// disable 1D transforms (for now)
traceOut._length = null;
}
module.exports = {
supplyDefaults: supplyDefaults,
supplyIsoDefaults: supplyIsoDefaults
};
/***/ }),
/***/ 82368:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(32560),
supplyDefaults: (__webpack_require__(30592).supplyDefaults),
calc: __webpack_require__(70260),
colorbar: {
min: 'cmin',
max: 'cmax'
},
plot: (__webpack_require__(80296).createIsosurfaceTrace),
moduleType: 'trace',
name: 'isosurface',
basePlotModule: __webpack_require__(26544),
categories: ['gl3d', 'showLegend'],
meta: {
description: ['Draws isosurfaces between iso-min and iso-max values with coordinates given by', 'four 1-dimensional arrays containing the `value`, `x`, `y` and `z` of every vertex', 'of a uniform or non-uniform 3-D grid. Horizontal or vertical slices, caps as well as', 'spaceframe between iso-min and iso-max values could also be drawn using this trace.'].join(' ')
}
};
/***/ }),
/***/ 13000:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorScaleAttrs = __webpack_require__(99732);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var surfaceAttrs = __webpack_require__(32004);
var baseAttrs = __webpack_require__(6040);
var extendFlat = (__webpack_require__(55016).extendFlat);
module.exports = extendFlat({
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the X coordinates of the vertices. The nth element of vectors `x`, `y` and `z`', 'jointly represent the X, Y and Z coordinates of the nth vertex.'].join(' ')
},
y: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the Y coordinates of the vertices. The nth element of vectors `x`, `y` and `z`', 'jointly represent the X, Y and Z coordinates of the nth vertex.'].join(' ')
},
z: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the Z coordinates of the vertices. The nth element of vectors `x`, `y` and `z`', 'jointly represent the X, Y and Z coordinates of the nth vertex.'].join(' ')
},
i: {
valType: 'data_array',
editType: 'calc',
description: ['A vector of vertex indices, i.e. integer values between 0 and the length of the vertex', 'vectors, representing the *first* vertex of a triangle. For example, `{i[m], j[m], k[m]}`', 'together represent face m (triangle m) in the mesh, where `i[m] = n` points to the triplet', '`{x[n], y[n], z[n]}` in the vertex arrays. Therefore, each element in `i` represents a', 'point in space, which is the first vertex of a triangle.'].join(' ')
},
j: {
valType: 'data_array',
editType: 'calc',
description: ['A vector of vertex indices, i.e. integer values between 0 and the length of the vertex', 'vectors, representing the *second* vertex of a triangle. For example, `{i[m], j[m], k[m]}` ', 'together represent face m (triangle m) in the mesh, where `j[m] = n` points to the triplet', '`{x[n], y[n], z[n]}` in the vertex arrays. Therefore, each element in `j` represents a', 'point in space, which is the second vertex of a triangle.'].join(' ')
},
k: {
valType: 'data_array',
editType: 'calc',
description: ['A vector of vertex indices, i.e. integer values between 0 and the length of the vertex', 'vectors, representing the *third* vertex of a triangle. For example, `{i[m], j[m], k[m]}`', 'together represent face m (triangle m) in the mesh, where `k[m] = n` points to the triplet ', '`{x[n], y[n], z[n]}` in the vertex arrays. Therefore, each element in `k` represents a', 'point in space, which is the third vertex of a triangle.'].join(' ')
},
text: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'calc',
description: ['Sets the text elements associated with the vertices.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
},
hovertext: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'calc',
description: 'Same as `text`.'
},
hovertemplate: hovertemplateAttrs({
editType: 'calc'
}),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z'),
delaunayaxis: {
valType: 'enumerated',
values: ['x', 'y', 'z'],
dflt: 'z',
editType: 'calc',
description: ['Sets the Delaunay axis, which is the axis that is perpendicular to the surface of the', 'Delaunay triangulation.', 'It has an effect if `i`, `j`, `k` are not provided and `alphahull` is set to indicate', 'Delaunay triangulation.'].join(' ')
},
alphahull: {
valType: 'number',
dflt: -1,
editType: 'calc',
description: ['Determines how the mesh surface triangles are derived from the set of', 'vertices (points) represented by the `x`, `y` and `z` arrays, if', 'the `i`, `j`, `k` arrays are not supplied.', 'For general use of `mesh3d` it is preferred that `i`, `j`, `k` are', 'supplied.', 'If *-1*, Delaunay triangulation is used, which is mainly suitable if the', 'mesh is a single, more or less layer surface that is perpendicular to `delaunayaxis`.', 'In case the `delaunayaxis` intersects the mesh surface at more than one point', 'it will result triangles that are very long in the dimension of `delaunayaxis`.', 'If *>0*, the alpha-shape algorithm is used. In this case, the positive `alphahull` value', 'signals the use of the alpha-shape algorithm, _and_ its value', 'acts as the parameter for the mesh fitting.', 'If *0*, the convex-hull algorithm is used. It is suitable for convex bodies', 'or if the intention is to enclose the `x`, `y` and `z` point set into a convex', 'hull.'].join(' ')
},
intensity: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the intensity values for vertices or cells', 'as defined by `intensitymode`.', 'It can be used for plotting fields on meshes.'].join(' ')
},
intensitymode: {
valType: 'enumerated',
values: ['vertex', 'cell'],
dflt: 'vertex',
editType: 'calc',
description: ['Determines the source of `intensity` values.'].join(' ')
},
// Color field
color: {
valType: 'color',
editType: 'calc',
description: 'Sets the color of the whole mesh'
},
vertexcolor: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the color of each vertex', 'Overrides *color*. While Red, green and blue colors', 'are in the range of 0 and 255; in the case of having', 'vertex color data in RGBA format, the alpha color', 'should be normalized to be between 0 and 1.'].join(' ')
},
facecolor: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the color of each face', 'Overrides *color* and *vertexcolor*.'].join(' ')
},
transforms: undefined
}, colorScaleAttrs('', {
colorAttr: '`intensity`',
showScaleDflt: true,
editTypeOverride: 'calc'
}), {
opacity: surfaceAttrs.opacity,
// Flat shaded mode
flatshading: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['Determines whether or not normal smoothing is applied to the meshes,', 'creating meshes with an angular, low-poly look via flat reflections.'].join(' ')
},
contour: {
show: extendFlat({}, surfaceAttrs.contours.x.show, {
description: ['Sets whether or not dynamic contours are shown on hover'].join(' ')
}),
color: surfaceAttrs.contours.x.color,
width: surfaceAttrs.contours.x.width,
editType: 'calc'
},
lightposition: {
x: extendFlat({}, surfaceAttrs.lightposition.x, {
dflt: 1e5
}),
y: extendFlat({}, surfaceAttrs.lightposition.y, {
dflt: 1e5
}),
z: extendFlat({}, surfaceAttrs.lightposition.z, {
dflt: 0
}),
editType: 'calc'
},
lighting: extendFlat({
vertexnormalsepsilon: {
valType: 'number',
min: 0.00,
max: 1,
dflt: 1e-12,
// otherwise finely tessellated things eg. the brain will have no specular light reflection
editType: 'calc',
description: 'Epsilon for vertex normals calculation avoids math issues arising from degenerate geometry.'
},
facenormalsepsilon: {
valType: 'number',
min: 0.00,
max: 1,
dflt: 1e-6,
// even the brain model doesn't appear to need finer than this
editType: 'calc',
description: 'Epsilon for face normals calculation avoids math issues arising from degenerate geometry.'
},
editType: 'calc'
}, surfaceAttrs.lighting),
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
editType: 'calc'
}),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
});
/***/ }),
/***/ 91056:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorscaleCalc = __webpack_require__(60416);
module.exports = function calc(gd, trace) {
if (trace.intensity) {
colorscaleCalc(gd, trace, {
vals: trace.intensity,
containerStr: '',
cLetter: 'c'
});
}
};
/***/ }),
/***/ 54096:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createMesh = (__webpack_require__(14656).gl_mesh3d);
var triangulate = (__webpack_require__(14656).delaunay_triangulate);
var alphaShape = (__webpack_require__(14656).alpha_shape);
var convexHull = (__webpack_require__(14656).convex_hull);
var parseColorScale = (__webpack_require__(13396).parseColorScale);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var str2RgbaArray = __webpack_require__(29864);
var extractOpts = (__webpack_require__(26733).extractOpts);
var zip3 = __webpack_require__(90644);
function Mesh3DTrace(scene, mesh, uid) {
this.scene = scene;
this.uid = uid;
this.mesh = mesh;
this.name = '';
this.color = '#fff';
this.data = null;
this.showContour = false;
}
var proto = Mesh3DTrace.prototype;
proto.handlePick = function (selection) {
if (selection.object === this.mesh) {
var selectIndex = selection.index = selection.data.index;
if (selection.data._cellCenter) {
selection.traceCoordinate = selection.data.dataCoordinate;
} else {
selection.traceCoordinate = [this.data.x[selectIndex], this.data.y[selectIndex], this.data.z[selectIndex]];
}
var text = this.data.hovertext || this.data.text;
if (isArrayOrTypedArray(text) && text[selectIndex] !== undefined) {
selection.textLabel = text[selectIndex];
} else if (text) {
selection.textLabel = text;
}
return true;
}
};
function parseColorArray(colors) {
var b = [];
var len = colors.length;
for (var i = 0; i < len; i++) {
b[i] = str2RgbaArray(colors[i]);
}
return b;
}
// Unpack position data
function toDataCoords(axis, coord, scale, calendar) {
var b = [];
var len = coord.length;
for (var i = 0; i < len; i++) {
b[i] = axis.d2l(coord[i], 0, calendar) * scale;
}
return b;
}
// Round indices if passed as floats
function toRoundIndex(a) {
var b = [];
var len = a.length;
for (var i = 0; i < len; i++) {
b[i] = Math.round(a[i]);
}
return b;
}
function delaunayCells(delaunayaxis, positions) {
var d = ['x', 'y', 'z'].indexOf(delaunayaxis);
var b = [];
var len = positions.length;
for (var i = 0; i < len; i++) {
b[i] = [positions[i][(d + 1) % 3], positions[i][(d + 2) % 3]];
}
return triangulate(b);
}
// Validate indices
function hasValidIndices(list, numVertices) {
var len = list.length;
for (var i = 0; i < len; i++) {
if (list[i] <= -0.5 || list[i] >= numVertices - 0.5) {
// Note: the indices would be rounded -0.49 is valid.
return false;
}
}
return true;
}
proto.update = function (data) {
var scene = this.scene;
var layout = scene.fullSceneLayout;
this.data = data;
var numVertices = data.x.length;
var positions = zip3(toDataCoords(layout.xaxis, data.x, scene.dataScale[0], data.xcalendar), toDataCoords(layout.yaxis, data.y, scene.dataScale[1], data.ycalendar), toDataCoords(layout.zaxis, data.z, scene.dataScale[2], data.zcalendar));
var cells;
if (data.i && data.j && data.k) {
if (data.i.length !== data.j.length || data.j.length !== data.k.length || !hasValidIndices(data.i, numVertices) || !hasValidIndices(data.j, numVertices) || !hasValidIndices(data.k, numVertices)) {
return;
}
cells = zip3(toRoundIndex(data.i), toRoundIndex(data.j), toRoundIndex(data.k));
} else if (data.alphahull === 0) {
cells = convexHull(positions);
} else if (data.alphahull > 0) {
cells = alphaShape(data.alphahull, positions);
} else {
cells = delaunayCells(data.delaunayaxis, positions);
}
var config = {
positions: positions,
cells: cells,
lightPosition: [data.lightposition.x, data.lightposition.y, data.lightposition.z],
ambient: data.lighting.ambient,
diffuse: data.lighting.diffuse,
specular: data.lighting.specular,
roughness: data.lighting.roughness,
fresnel: data.lighting.fresnel,
vertexNormalsEpsilon: data.lighting.vertexnormalsepsilon,
faceNormalsEpsilon: data.lighting.facenormalsepsilon,
opacity: data.opacity,
contourEnable: data.contour.show,
contourColor: str2RgbaArray(data.contour.color).slice(0, 3),
contourWidth: data.contour.width,
useFacetNormals: data.flatshading
};
if (data.intensity) {
var cOpts = extractOpts(data);
this.color = '#fff';
var mode = data.intensitymode;
config[mode + 'Intensity'] = data.intensity;
config[mode + 'IntensityBounds'] = [cOpts.min, cOpts.max];
config.colormap = parseColorScale(data);
} else if (data.vertexcolor) {
this.color = data.vertexcolor[0];
config.vertexColors = parseColorArray(data.vertexcolor);
} else if (data.facecolor) {
this.color = data.facecolor[0];
config.cellColors = parseColorArray(data.facecolor);
} else {
this.color = data.color;
config.meshColor = str2RgbaArray(data.color);
}
// Update mesh
this.mesh.update(config);
};
proto.dispose = function () {
this.scene.glplot.remove(this.mesh);
this.mesh.dispose();
};
function createMesh3DTrace(scene, data) {
var gl = scene.glplot.gl;
var mesh = createMesh({
gl: gl
});
var result = new Mesh3DTrace(scene, mesh, data.uid);
mesh._trace = result;
result.update(data);
scene.glplot.add(mesh);
return result;
}
module.exports = createMesh3DTrace;
/***/ }),
/***/ 19576:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(13000);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
// read in face/vertex properties
function readComponents(array) {
var ret = array.map(function (attr) {
var result = coerce(attr);
if (result && Lib.isArrayOrTypedArray(result)) return result;
return null;
});
return ret.every(function (x) {
return x && x.length === ret[0].length;
}) && ret;
}
var coords = readComponents(['x', 'y', 'z']);
if (!coords) {
traceOut.visible = false;
return;
}
readComponents(['i', 'j', 'k']);
// three indices should be all provided or not
if (traceOut.i && (!traceOut.j || !traceOut.k) || traceOut.j && (!traceOut.k || !traceOut.i) || traceOut.k && (!traceOut.i || !traceOut.j)) {
traceOut.visible = false;
return;
}
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x', 'y', 'z'], layout);
// Coerce remaining properties
['lighting.ambient', 'lighting.diffuse', 'lighting.specular', 'lighting.roughness', 'lighting.fresnel', 'lighting.vertexnormalsepsilon', 'lighting.facenormalsepsilon', 'lightposition.x', 'lightposition.y', 'lightposition.z', 'flatshading', 'alphahull', 'delaunayaxis', 'opacity'].forEach(function (x) {
coerce(x);
});
var showContour = coerce('contour.show');
if (showContour) {
coerce('contour.color');
coerce('contour.width');
}
if ('intensity' in traceIn) {
coerce('intensity');
coerce('intensitymode');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'c'
});
} else {
traceOut.showscale = false;
if ('facecolor' in traceIn) coerce('facecolor');else if ('vertexcolor' in traceIn) coerce('vertexcolor');else coerce('color', defaultColor);
}
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('xhoverformat');
coerce('yhoverformat');
coerce('zhoverformat');
// disable 1D transforms
// x/y/z should match lengths, and i/j/k should match as well, but
// the two sets have different lengths so transforms wouldn't work.
traceOut._length = null;
};
/***/ }),
/***/ 86287:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(13000),
supplyDefaults: __webpack_require__(19576),
calc: __webpack_require__(91056),
colorbar: {
min: 'cmin',
max: 'cmax'
},
plot: __webpack_require__(54096),
moduleType: 'trace',
name: 'mesh3d',
basePlotModule: __webpack_require__(26544),
categories: ['gl3d', 'showLegend'],
meta: {
description: ['Draws sets of triangles with coordinates given by', 'three 1-dimensional arrays in `x`, `y`, `z` and', '(1) a sets of `i`, `j`, `k` indices', '(2) Delaunay triangulation or', '(3) the Alpha-shape algorithm or', '(4) the Convex-hull algorithm'].join(' ')
}
};
/***/ }),
/***/ 29520:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var extendFlat = (__webpack_require__(10923).extendFlat);
var scatterAttrs = __webpack_require__(49992);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var dash = (__webpack_require__(9392)/* .dash */ .u);
var fxAttrs = __webpack_require__(71516);
var delta = __webpack_require__(91136);
var INCREASING_COLOR = delta.INCREASING.COLOR;
var DECREASING_COLOR = delta.DECREASING.COLOR;
var lineAttrs = scatterAttrs.line;
function directionAttrs(lineColorDefault) {
return {
line: {
color: extendFlat({}, lineAttrs.color, {
dflt: lineColorDefault
}),
width: lineAttrs.width,
dash: dash,
editType: 'style'
},
editType: 'style'
};
}
module.exports = {
xperiod: scatterAttrs.xperiod,
xperiod0: scatterAttrs.xperiod0,
xperiodalignment: scatterAttrs.xperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the x coordinates.', 'If absent, linear coordinate will be generated.'].join(' ')
},
open: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the open values.'
},
high: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the high values.'
},
low: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the low values.'
},
close: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the close values.'
},
line: {
width: extendFlat({}, lineAttrs.width, {
description: [lineAttrs.width, 'Note that this style setting can also be set per', 'direction via `increasing.line.width` and', '`decreasing.line.width`.'].join(' ')
}),
dash: extendFlat({}, dash, {
description: [dash.description, 'Note that this style setting can also be set per', 'direction via `increasing.line.dash` and', '`decreasing.line.dash`.'].join(' ')
}),
editType: 'style'
},
increasing: directionAttrs(INCREASING_COLOR),
decreasing: directionAttrs(DECREASING_COLOR),
text: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'calc',
description: ['Sets hover text elements associated with each sample point.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to', 'this trace\'s sample points.'].join(' ')
},
hovertext: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'calc',
description: 'Same as `text`.'
},
tickwidth: {
valType: 'number',
min: 0,
max: 0.5,
dflt: 0.3,
editType: 'calc',
description: ['Sets the width of the open/close tick marks', 'relative to the *x* minimal interval.'].join(' ')
},
hoverlabel: extendFlat({}, fxAttrs.hoverlabel, {
split: {
valType: 'boolean',
dflt: false,
editType: 'style',
description: ['Show hover information (open, close, high, low) in', 'separate labels.'].join(' ')
}
}),
zorder: scatterAttrs.zorder
};
/***/ }),
/***/ 76952:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var _ = Lib._;
var Axes = __webpack_require__(81536);
var alignPeriod = __webpack_require__(82260);
var BADNUM = (__webpack_require__(41752).BADNUM);
function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis);
var ya = Axes.getFromId(gd, trace.yaxis);
var tickLen = convertTickWidth(gd, xa, trace);
var minDiff = trace._minDiff;
trace._minDiff = null;
var origX = trace._origX;
trace._origX = null;
var x = trace._xcalc;
trace._xcalc = null;
var cd = calcCommon(gd, trace, origX, x, ya, ptFunc);
trace._extremes[xa._id] = Axes.findExtremes(xa, x, {
vpad: minDiff / 2
});
if (cd.length) {
Lib.extendFlat(cd[0].t, {
wHover: minDiff / 2,
tickLen: tickLen
});
return cd;
} else {
return [{
t: {
empty: true
}
}];
}
}
function ptFunc(o, h, l, c) {
return {
o: o,
h: h,
l: l,
c: c
};
}
// shared between OHLC and candlestick
// ptFunc makes a calcdata point specific to each trace type, from oi, hi, li, ci
function calcCommon(gd, trace, origX, x, ya, ptFunc) {
var o = ya.makeCalcdata(trace, 'open');
var h = ya.makeCalcdata(trace, 'high');
var l = ya.makeCalcdata(trace, 'low');
var c = ya.makeCalcdata(trace, 'close');
var hasTextArray = Lib.isArrayOrTypedArray(trace.text);
var hasHovertextArray = Lib.isArrayOrTypedArray(trace.hovertext);
// we're optimists - before we have any changing data, assume increasing
var increasing = true;
var cPrev = null;
var hasPeriod = !!trace.xperiodalignment;
var cd = [];
for (var i = 0; i < x.length; i++) {
var xi = x[i];
var oi = o[i];
var hi = h[i];
var li = l[i];
var ci = c[i];
if (xi !== BADNUM && oi !== BADNUM && hi !== BADNUM && li !== BADNUM && ci !== BADNUM) {
if (ci === oi) {
// if open == close, look for a change from the previous close
if (cPrev !== null && ci !== cPrev) increasing = ci > cPrev;
// else (c === cPrev or cPrev is null) no change
} else increasing = ci > oi;
cPrev = ci;
var pt = ptFunc(oi, hi, li, ci);
pt.pos = xi;
pt.yc = (oi + ci) / 2;
pt.i = i;
pt.dir = increasing ? 'increasing' : 'decreasing';
// For categoryorder, store low and high
pt.x = pt.pos;
pt.y = [li, hi];
if (hasPeriod) pt.orig_p = origX[i]; // used by hover
if (hasTextArray) pt.tx = trace.text[i];
if (hasHovertextArray) pt.htx = trace.hovertext[i];
cd.push(pt);
} else {
cd.push({
pos: xi,
empty: true
});
}
}
trace._extremes[ya._id] = Axes.findExtremes(ya, Lib.concat(l, h), {
padded: true
});
if (cd.length) {
cd[0].t = {
labels: {
open: _(gd, 'open:') + ' ',
high: _(gd, 'high:') + ' ',
low: _(gd, 'low:') + ' ',
close: _(gd, 'close:') + ' '
}
};
}
return cd;
}
/*
* find min x-coordinates difference of all traces
* attached to this x-axis and stash the result in _minDiff
* in all traces; when a trace uses this in its
* calc step it deletes _minDiff, so that next calc this is
* done again in case the data changed.
* also since we need it here, stash _xcalc (and _origX) on the trace
*/
function convertTickWidth(gd, xa, trace) {
var minDiff = trace._minDiff;
if (!minDiff) {
var fullData = gd._fullData;
var ohlcTracesOnThisXaxis = [];
minDiff = Infinity;
var i;
for (i = 0; i < fullData.length; i++) {
var tracei = fullData[i];
if (tracei.type === 'ohlc' && tracei.visible === true && tracei.xaxis === xa._id) {
ohlcTracesOnThisXaxis.push(tracei);
var origX = xa.makeCalcdata(tracei, 'x');
tracei._origX = origX;
var xcalc = alignPeriod(trace, xa, 'x', origX).vals;
tracei._xcalc = xcalc;
var _minDiff = Lib.distinctVals(xcalc).minDiff;
if (_minDiff && isFinite(_minDiff)) {
minDiff = Math.min(minDiff, _minDiff);
}
}
}
// if minDiff is still Infinity here, set it to 1
if (minDiff === Infinity) minDiff = 1;
for (i = 0; i < ohlcTracesOnThisXaxis.length; i++) {
ohlcTracesOnThisXaxis[i]._minDiff = minDiff;
}
}
return minDiff * trace.tickwidth;
}
module.exports = {
calc: calc,
calcCommon: calcCommon
};
/***/ }),
/***/ 42112:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleOHLC = __webpack_require__(584);
var handlePeriodDefaults = __webpack_require__(98632);
var attributes = __webpack_require__(29520);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleOHLC(traceIn, traceOut, coerce, layout);
if (!len) {
traceOut.visible = false;
return;
}
handlePeriodDefaults(traceIn, traceOut, layout, coerce, {
x: true
});
coerce('xhoverformat');
coerce('yhoverformat');
coerce('line.width');
coerce('line.dash');
handleDirection(traceIn, traceOut, coerce, 'increasing');
handleDirection(traceIn, traceOut, coerce, 'decreasing');
coerce('text');
coerce('hovertext');
coerce('tickwidth');
layout._requestRangeslider[traceOut.xaxis] = true;
coerce('zorder');
};
function handleDirection(traceIn, traceOut, coerce, direction) {
coerce(direction + '.line.color');
coerce(direction + '.line.width', traceOut.line.width);
coerce(direction + '.line.dash', traceOut.line.dash);
}
/***/ }),
/***/ 296:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var Lib = __webpack_require__(10923);
var Fx = __webpack_require__(39184);
var Color = __webpack_require__(9240);
var fillText = (__webpack_require__(10923).fillText);
var delta = __webpack_require__(91136);
var DIRSYMBOL = {
increasing: delta.INCREASING.SYMBOL,
decreasing: delta.DECREASING.SYMBOL
};
function hoverPoints(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var trace = cd[0].trace;
if (trace.hoverlabel.split) {
return hoverSplit(pointData, xval, yval, hovermode);
}
return hoverOnPoints(pointData, xval, yval, hovermode);
}
function _getClosestPoint(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var xa = pointData.xa;
var trace = cd[0].trace;
var t = cd[0].t;
var type = trace.type;
var minAttr = type === 'ohlc' ? 'l' : 'min';
var maxAttr = type === 'ohlc' ? 'h' : 'max';
var hoverPseudoDistance, spikePseudoDistance;
// potentially shift xval for grouped candlesticks
var centerShift = t.bPos || 0;
var shiftPos = function (di) {
return di.pos + centerShift - xval;
};
// ohlc and candlestick call displayHalfWidth different things...
var displayHalfWidth = t.bdPos || t.tickLen;
var hoverHalfWidth = t.wHover;
// if two figures are overlaying, let the narrowest one win
var pseudoDistance = Math.min(1, displayHalfWidth / Math.abs(xa.r2c(xa.range[1]) - xa.r2c(xa.range[0])));
hoverPseudoDistance = pointData.maxHoverDistance - pseudoDistance;
spikePseudoDistance = pointData.maxSpikeDistance - pseudoDistance;
function dx(di) {
var pos = shiftPos(di);
return Fx.inbox(pos - hoverHalfWidth, pos + hoverHalfWidth, hoverPseudoDistance);
}
function dy(di) {
var min = di[minAttr];
var max = di[maxAttr];
return min === max || Fx.inbox(min - yval, max - yval, hoverPseudoDistance);
}
function dxy(di) {
return (dx(di) + dy(di)) / 2;
}
var distfn = Fx.getDistanceFunction(hovermode, dx, dy, dxy);
Fx.getClosest(cd, distfn, pointData);
if (pointData.index === false) return null;
var di = cd[pointData.index];
if (di.empty) return null;
var dir = di.dir;
var container = trace[dir];
var lc = container.line.color;
if (Color.opacity(lc) && container.line.width) pointData.color = lc;else pointData.color = container.fillcolor;
pointData.x0 = xa.c2p(di.pos + centerShift - displayHalfWidth, true);
pointData.x1 = xa.c2p(di.pos + centerShift + displayHalfWidth, true);
pointData.xLabelVal = di.orig_p !== undefined ? di.orig_p : di.pos;
pointData.spikeDistance = dxy(di) * spikePseudoDistance / hoverPseudoDistance;
pointData.xSpike = xa.c2p(di.pos, true);
return pointData;
}
function hoverSplit(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var ya = pointData.ya;
var trace = cd[0].trace;
var t = cd[0].t;
var closeBoxData = [];
var closestPoint = _getClosestPoint(pointData, xval, yval, hovermode);
// skip the rest (for this trace) if we didn't find a close point
if (!closestPoint) return [];
var cdIndex = closestPoint.index;
var di = cd[cdIndex];
var hoverinfo = di.hi || trace.hoverinfo;
var hoverParts = hoverinfo.split('+');
var isAll = hoverinfo === 'all';
var hasY = isAll || hoverParts.indexOf('y') !== -1;
// similar to hoverOnPoints, we return nothing
// if all or y is not present.
if (!hasY) return [];
var attrs = ['high', 'open', 'close', 'low'];
// several attributes can have the same y-coordinate. We will
// bunch them together in a single text block. For this, we keep
// a dictionary mapping y-coord -> point data.
var usedVals = {};
for (var i = 0; i < attrs.length; i++) {
var attr = attrs[i];
var val = trace[attr][closestPoint.index];
var valPx = ya.c2p(val, true);
var pointData2;
if (val in usedVals) {
pointData2 = usedVals[val];
pointData2.yLabel += '
' + t.labels[attr] + Axes.hoverLabelText(ya, val, trace.yhoverformat);
} else {
// copy out to a new object for each new y-value to label
pointData2 = Lib.extendFlat({}, closestPoint);
pointData2.y0 = pointData2.y1 = valPx;
pointData2.yLabelVal = val;
pointData2.yLabel = t.labels[attr] + Axes.hoverLabelText(ya, val, trace.yhoverformat);
pointData2.name = '';
closeBoxData.push(pointData2);
usedVals[val] = pointData2;
}
}
return closeBoxData;
}
function hoverOnPoints(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var ya = pointData.ya;
var trace = cd[0].trace;
var t = cd[0].t;
var closestPoint = _getClosestPoint(pointData, xval, yval, hovermode);
// skip the rest (for this trace) if we didn't find a close point
if (!closestPoint) return [];
// we don't make a calcdata point if we're missing any piece (x/o/h/l/c)
// so we need to fix the index here to point to the data arrays
var cdIndex = closestPoint.index;
var di = cd[cdIndex];
var i = closestPoint.index = di.i;
var dir = di.dir;
function getLabelLine(attr) {
return t.labels[attr] + Axes.hoverLabelText(ya, trace[attr][i], trace.yhoverformat);
}
var hoverinfo = di.hi || trace.hoverinfo;
var hoverParts = hoverinfo.split('+');
var isAll = hoverinfo === 'all';
var hasY = isAll || hoverParts.indexOf('y') !== -1;
var hasText = isAll || hoverParts.indexOf('text') !== -1;
var textParts = hasY ? [getLabelLine('open'), getLabelLine('high'), getLabelLine('low'), getLabelLine('close') + ' ' + DIRSYMBOL[dir]] : [];
if (hasText) fillText(di, trace, textParts);
// don't make .yLabelVal or .text, since we're managing hoverinfo
// put it all in .extraText
closestPoint.extraText = textParts.join('
');
// this puts the label *and the spike* at the midpoint of the box, ie
// halfway between open and close, not between high and low.
closestPoint.y0 = closestPoint.y1 = ya.c2p(di.yc, true);
return [closestPoint];
}
module.exports = {
hoverPoints: hoverPoints,
hoverSplit: hoverSplit,
hoverOnPoints: hoverOnPoints
};
/***/ }),
/***/ 60708:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'ohlc',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', 'showLegend'],
meta: {
description: ['The ohlc (short for Open-High-Low-Close) is a style of financial chart describing', 'open, high, low and close for a given `x` coordinate (most likely time).', 'The tip of the lines represent the `low` and `high` values and', 'the horizontal segments represent the `open` and `close` values.', 'Sample points where the close value is higher (lower) then the open', 'value are called increasing (decreasing).', 'By default, increasing items are drawn in green whereas', 'decreasing are drawn in red.'].join(' ')
},
attributes: __webpack_require__(29520),
supplyDefaults: __webpack_require__(42112),
calc: (__webpack_require__(76952).calc),
plot: __webpack_require__(96),
style: __webpack_require__(32936),
hoverPoints: (__webpack_require__(296).hoverPoints),
selectPoints: __webpack_require__(29844)
};
/***/ }),
/***/ 584:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
module.exports = function handleOHLC(traceIn, traceOut, coerce, layout) {
var x = coerce('x');
var open = coerce('open');
var high = coerce('high');
var low = coerce('low');
var close = coerce('close');
coerce('hoverlabel.split');
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x'], layout);
if (!(open && high && low && close)) return;
var len = Math.min(open.length, high.length, low.length, close.length);
if (x) len = Math.min(len, Lib.minRowLength(x));
traceOut._length = len;
return len;
};
/***/ }),
/***/ 96:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
module.exports = function plot(gd, plotinfo, cdOHLC, ohlcLayer) {
var ya = plotinfo.yaxis;
var xa = plotinfo.xaxis;
var posHasRangeBreaks = !!xa.rangebreaks;
Lib.makeTraceGroups(ohlcLayer, cdOHLC, 'trace ohlc').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var t = cd0.t;
var trace = cd0.trace;
if (trace.visible !== true || t.empty) {
plotGroup.remove();
return;
}
var tickLen = t.tickLen;
var paths = plotGroup.selectAll('path').data(Lib.identity);
paths.enter().append('path');
paths.exit().remove();
paths.attr('d', function (d) {
if (d.empty) return 'M0,0Z';
var xo = xa.c2p(d.pos - tickLen, true);
var xc = xa.c2p(d.pos + tickLen, true);
var x = posHasRangeBreaks ? (xo + xc) / 2 : xa.c2p(d.pos, true);
var yo = ya.c2p(d.o, true);
var yh = ya.c2p(d.h, true);
var yl = ya.c2p(d.l, true);
var yc = ya.c2p(d.c, true);
return 'M' + xo + ',' + yo + 'H' + x + 'M' + x + ',' + yh + 'V' + yl + 'M' + xc + ',' + yc + 'H' + x;
});
});
};
/***/ }),
/***/ 29844:
/***/ (function(module) {
"use strict";
module.exports = function selectPoints(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var selection = [];
var i;
// for (potentially grouped) candlesticks
var posOffset = cd[0].t.bPos || 0;
if (selectionTester === false) {
// clear selection
for (i = 0; i < cd.length; i++) {
cd[i].selected = 0;
}
} else {
for (i = 0; i < cd.length; i++) {
var di = cd[i];
if (selectionTester.contains([xa.c2p(di.pos + posOffset), ya.c2p(di.yc)], null, di.i, searchInfo)) {
selection.push({
pointNumber: di.i,
x: xa.c2d(di.pos),
y: ya.c2d(di.yc)
});
di.selected = 1;
} else {
di.selected = 0;
}
}
}
return selection;
};
/***/ }),
/***/ 32936:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Drawing = __webpack_require__(49348);
var Color = __webpack_require__(9240);
module.exports = function style(gd, cd, sel) {
var s = sel ? sel : d3.select(gd).selectAll('g.ohlclayer').selectAll('g.trace');
s.style('opacity', function (d) {
return d[0].trace.opacity;
});
s.each(function (d) {
var trace = d[0].trace;
d3.select(this).selectAll('path').each(function (di) {
if (di.empty) return;
var dirLine = trace[di.dir].line;
d3.select(this).style('fill', 'none').call(Color.stroke, dirLine.color).call(Drawing.dashLine, dirLine.dash, dirLine.width)
// TODO: custom selection style for OHLC
.style('opacity', trace.selectedpoints && !di.selected ? 0.3 : 1);
});
});
};
/***/ }),
/***/ 78208:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var extendFlat = (__webpack_require__(55016).extendFlat);
var baseAttrs = __webpack_require__(6040);
var fontAttrs = __webpack_require__(71936);
var colorScaleAttrs = __webpack_require__(99732);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var line = extendFlat({
editType: 'calc'
}, colorScaleAttrs('line', {
editTypeOverride: 'calc'
}), {
shape: {
valType: 'enumerated',
values: ['linear', 'hspline'],
dflt: 'linear',
editType: 'plot',
description: ['Sets the shape of the paths.', 'If `linear`, paths are composed of straight lines.', 'If `hspline`, paths are composed of horizontal curved splines'].join(' ')
},
hovertemplate: hovertemplateAttrs({
editType: 'plot',
arrayOk: false
}, {
keys: ['count', 'probability'],
description: ['This value here applies when hovering over lines.'].join(' ')
})
});
module.exports = {
domain: domainAttrs({
name: 'parcats',
trace: true,
editType: 'calc'
}),
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['count', 'probability'],
editType: 'plot',
arrayOk: false
}),
hoveron: {
valType: 'enumerated',
values: ['category', 'color', 'dimension'],
dflt: 'category',
editType: 'plot',
description: ['Sets the hover interaction mode for the parcats diagram.', 'If `category`, hover interaction take place per category.', 'If `color`, hover interactions take place per color per category.', 'If `dimension`, hover interactions take place across all categories per dimension.'].join(' ')
},
hovertemplate: hovertemplateAttrs({
editType: 'plot',
arrayOk: false
}, {
keys: ['count', 'probability', 'category', 'categorycount', 'colorcount', 'bandcolorcount'],
description: ['This value here applies when hovering over dimensions.', 'Note that `*categorycount`, *colorcount* and *bandcolorcount*', 'are only available when `hoveron` contains the *color* flag'].join(' ')
}),
arrangement: {
valType: 'enumerated',
values: ['perpendicular', 'freeform', 'fixed'],
dflt: 'perpendicular',
editType: 'plot',
description: ['Sets the drag interaction mode for categories and dimensions.', 'If `perpendicular`, the categories can only move along a line perpendicular to the paths.', 'If `freeform`, the categories can freely move on the plane.', 'If `fixed`, the categories and dimensions are stationary.'].join(' ')
},
bundlecolors: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: 'Sort paths so that like colors are bundled together within each category.'
},
sortpaths: {
valType: 'enumerated',
values: ['forward', 'backward'],
dflt: 'forward',
editType: 'plot',
description: ['Sets the path sorting algorithm.', 'If `forward`, sort paths based on dimension categories from left to right.', 'If `backward`, sort paths based on dimensions categories from right to left.'].join(' ')
},
labelfont: fontAttrs({
editType: 'calc',
description: 'Sets the font for the `dimension` labels.'
}),
tickfont: fontAttrs({
editType: 'calc',
description: 'Sets the font for the `category` labels.'
}),
dimensions: {
_isLinkedToArray: 'dimension',
label: {
valType: 'string',
editType: 'calc',
description: 'The shown name of the dimension.'
},
categoryorder: {
valType: 'enumerated',
values: ['trace', 'category ascending', 'category descending', 'array'],
dflt: 'trace',
editType: 'calc',
description: ['Specifies the ordering logic for the categories in the dimension.', 'By default, plotly uses *trace*, which specifies the order that is present in the data supplied.', 'Set `categoryorder` to *category ascending* or *category descending* if order should be determined by', 'the alphanumerical order of the category names.', 'Set `categoryorder` to *array* to derive the ordering from the attribute `categoryarray`. If a category', 'is not found in the `categoryarray` array, the sorting behavior for that attribute will be identical to', 'the *trace* mode. The unspecified categories will follow the categories in `categoryarray`.'].join(' ')
},
categoryarray: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the order in which categories in this dimension appear.', 'Only has an effect if `categoryorder` is set to *array*.', 'Used with `categoryorder`.'].join(' ')
},
ticktext: {
valType: 'data_array',
editType: 'calc',
description: ['Sets alternative tick labels for the categories in this dimension.', 'Only has an effect if `categoryorder` is set to *array*.', 'Should be an array the same length as `categoryarray`', 'Used with `categoryorder`.'].join(' ')
},
values: {
valType: 'data_array',
dflt: [],
editType: 'calc',
description: ['Dimension values. `values[n]` represents the category value of the `n`th point in the dataset,', 'therefore the `values` vector for all dimensions must be the same (longer vectors', 'will be truncated).'].join(' ')
},
displayindex: {
valType: 'integer',
editType: 'calc',
description: ['The display index of dimension, from left to right, zero indexed, defaults to dimension', 'index.'].join(' ')
},
editType: 'calc',
description: 'The dimensions (variables) of the parallel categories diagram.',
visible: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: 'Shows the dimension when set to `true` (the default). Hides the dimension for `false`.'
}
},
line: line,
counts: {
valType: 'number',
min: 0,
dflt: 1,
arrayOk: true,
editType: 'calc',
description: ['The number of observations represented by each state. Defaults to 1 so that each state represents', 'one observation'].join(' ')
},
// Hide unsupported top-level properties from plot-schema
customdata: undefined,
hoverlabel: undefined,
ids: undefined,
legend: undefined,
legendgroup: undefined,
legendrank: undefined,
opacity: undefined,
selectedpoints: undefined,
showlegend: undefined
};
/***/ }),
/***/ 26256:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var getModuleCalcData = (__webpack_require__(49824)/* .getModuleCalcData */ ._M);
var parcatsPlot = __webpack_require__(56664);
var PARCATS = 'parcats';
exports.name = PARCATS;
exports.plot = function (gd, traces, transitionOpts, makeOnCompleteCallback) {
var cdModuleAndOthers = getModuleCalcData(gd.calcdata, PARCATS);
if (cdModuleAndOthers.length) {
var calcData = cdModuleAndOthers[0];
parcatsPlot(gd, calcData, transitionOpts, makeOnCompleteCallback);
}
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
var hadTable = oldFullLayout._has && oldFullLayout._has('parcats');
var hasTable = newFullLayout._has && newFullLayout._has('parcats');
if (hadTable && !hasTable) {
oldFullLayout._paperdiv.selectAll('.parcats').remove();
}
};
/***/ }),
/***/ 15144:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
// Requirements
// ============
var wrap = (__webpack_require__(83104).wrap);
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var colorscaleCalc = __webpack_require__(60416);
var filterUnique = __webpack_require__(14664);
var Drawing = __webpack_require__(49348);
var Lib = __webpack_require__(10923);
var isNumeric = __webpack_require__(88120);
/**
* Create a wrapped ParcatsModel object from trace
*
* Note: trace defaults have already been applied
* @param {Object} gd
* @param {Object} trace
* @return {Array.}
*/
module.exports = function calc(gd, trace) {
var visibleDims = Lib.filterVisible(trace.dimensions);
if (visibleDims.length === 0) return [];
var uniqueInfoDims = visibleDims.map(function (dim) {
var categoryValues;
if (dim.categoryorder === 'trace') {
// Use order of first occurrence in trace
categoryValues = null;
} else if (dim.categoryorder === 'array') {
// Use categories specified in `categoryarray` first,
// then add extra to the end in trace order
categoryValues = dim.categoryarray;
} else {
// Get all categories up front
categoryValues = filterUnique(dim.values);
// order them
var allNumeric = true;
for (var i = 0; i < categoryValues.length; i++) {
if (!isNumeric(categoryValues[i])) {
allNumeric = false;
break;
}
}
categoryValues.sort(allNumeric ? Lib.sorterAsc : undefined);
if (dim.categoryorder === 'category descending') {
categoryValues = categoryValues.reverse();
}
}
return getUniqueInfo(dim.values, categoryValues);
});
var counts, count, totalCount;
if (Lib.isArrayOrTypedArray(trace.counts)) {
counts = trace.counts;
} else {
counts = [trace.counts];
}
validateDimensionDisplayInds(visibleDims);
visibleDims.forEach(function (dim, dimInd) {
validateCategoryProperties(dim, uniqueInfoDims[dimInd]);
});
// Handle path colors
// ------------------
var line = trace.line;
var markerColorscale;
// Process colorscale
if (line) {
if (hasColorscale(trace, 'line')) {
colorscaleCalc(gd, trace, {
vals: trace.line.color,
containerStr: 'line',
cLetter: 'c'
});
}
markerColorscale = Drawing.tryColorscale(line);
} else {
markerColorscale = Lib.identity;
}
// Build color generation function
function getMarkerColorInfo(index) {
var value, rawColor;
if (Lib.isArrayOrTypedArray(line.color)) {
value = line.color[index % line.color.length];
rawColor = value;
} else {
value = line.color;
}
return {
color: markerColorscale(value),
rawColor: rawColor
};
}
// Number of values and counts
// ---------------------------
var numValues = visibleDims[0].values.length;
// Build path info
// ---------------
// Mapping from category inds to PathModel objects
var pathModels = {};
// Category inds array for each dimension
var categoryIndsDims = uniqueInfoDims.map(function (di) {
return di.inds;
});
// Initialize total count
totalCount = 0;
var valueInd;
var d;
for (valueInd = 0; valueInd < numValues; valueInd++) {
// Category inds for this input value across dimensions
var categoryIndsPath = [];
for (d = 0; d < categoryIndsDims.length; d++) {
categoryIndsPath.push(categoryIndsDims[d][valueInd]);
}
// Count
count = counts[valueInd % counts.length];
// Update total count
totalCount += count;
// Path color
var pathColorInfo = getMarkerColorInfo(valueInd);
// path key
var pathKey = categoryIndsPath + '-' + pathColorInfo.rawColor;
// Create / Update PathModel
if (pathModels[pathKey] === undefined) {
pathModels[pathKey] = createPathModel(categoryIndsPath, pathColorInfo.color, pathColorInfo.rawColor);
}
updatePathModel(pathModels[pathKey], valueInd, count);
}
var dimensionModels = visibleDims.map(function (di, i) {
return createDimensionModel(i, di._index, di._displayindex, di.label, totalCount);
});
for (valueInd = 0; valueInd < numValues; valueInd++) {
count = counts[valueInd % counts.length];
for (d = 0; d < dimensionModels.length; d++) {
var containerInd = dimensionModels[d].containerInd;
var catInd = uniqueInfoDims[d].inds[valueInd];
var cats = dimensionModels[d].categories;
if (cats[catInd] === undefined) {
var catValue = trace.dimensions[containerInd]._categoryarray[catInd];
var catLabel = trace.dimensions[containerInd]._ticktext[catInd];
cats[catInd] = createCategoryModel(d, catInd, catValue, catLabel);
}
updateCategoryModel(cats[catInd], valueInd, count);
}
}
// Compute unique
return wrap(createParcatsModel(dimensionModels, pathModels, totalCount));
};
// Models
// ======
// Parcats Model
// -------------
/**
* @typedef {Object} ParcatsModel
* Object containing calculated information about a parcats trace
*
* @property {Array.} dimensions
* Array of dimension models
* @property {Object.} paths
* Dictionary from category inds string (e.g. "1,2,1,1") to path model
* @property {Number} maxCats
* The maximum number of categories of any dimension in the diagram
* @property {Number} count
* Total number of input values
* @property {Object} trace
*/
/**
* Create and new ParcatsModel object
* @param {Array.} dimensions
* @param {Object.} paths
* @param {Number} count
* @return {ParcatsModel}
*/
function createParcatsModel(dimensions, paths, count) {
var maxCats = dimensions.map(function (d) {
return d.categories.length;
}).reduce(function (v1, v2) {
return Math.max(v1, v2);
});
return {
dimensions: dimensions,
paths: paths,
trace: undefined,
maxCats: maxCats,
count: count
};
}
// Dimension Model
// ---------------
/**
* @typedef {Object} DimensionModel
* Object containing calculated information about a single dimension
*
* @property {Number} dimensionInd
* The index of this dimension among the *visible* dimensions
* @property {Number} containerInd
* The index of this dimension in the original dimensions container,
* irrespective of dimension visibility
* @property {Number} displayInd
* The display index of this dimension (where 0 is the left most dimension)
* @property {String} dimensionLabel
* The label of this dimension
* @property {Number} count
* Total number of input values
* @property {Array.} categories
* @property {Number|null} dragX
* The x position of dimension that is currently being dragged. null if not being dragged
*/
/**
* Create and new DimensionModel object with an empty categories array
* @param {Number} dimensionInd
* @param {Number} containerInd
* @param {Number} displayInd
* @param {String} dimensionLabel
* @param {Number} count
* Total number of input values
* @return {DimensionModel}
*/
function createDimensionModel(dimensionInd, containerInd, displayInd, dimensionLabel, count) {
return {
dimensionInd: dimensionInd,
containerInd: containerInd,
displayInd: displayInd,
dimensionLabel: dimensionLabel,
count: count,
categories: [],
dragX: null
};
}
// Category Model
// --------------
/**
* @typedef {Object} CategoryModel
* Object containing calculated information about a single category.
*
* @property {Number} dimensionInd
* The index of this categories dimension
* @property {Number} categoryInd
* The index of this category
* @property {Number} displayInd
* The display index of this category (where 0 is the topmost category)
* @property {String} categoryLabel
* The name of this category
* @property categoryValue: Raw value of the category
* @property {Array} valueInds
* Array of indices (into the original value array) of all samples in this category
* @property {Number} count
* The number of elements from the original array in this path
* @property {Number|null} dragY
* The y position of category that is currently being dragged. null if not being dragged
*/
/**
* Create and return a new CategoryModel object
* @param {Number} dimensionInd
* @param {Number} categoryInd
* The display index of this category (where 0 is the topmost category)
* @param {String} categoryValue
* @param {String} categoryLabel
* @return {CategoryModel}
*/
function createCategoryModel(dimensionInd, categoryInd, categoryValue, categoryLabel) {
return {
dimensionInd: dimensionInd,
categoryInd: categoryInd,
categoryValue: categoryValue,
displayInd: categoryInd,
categoryLabel: categoryLabel,
valueInds: [],
count: 0,
dragY: null
};
}
/**
* Update a CategoryModel object with a new value index
* Note: The calling parameter is modified in place.
*
* @param {CategoryModel} categoryModel
* @param {Number} valueInd
* @param {Number} count
*/
function updateCategoryModel(categoryModel, valueInd, count) {
categoryModel.valueInds.push(valueInd);
categoryModel.count += count;
}
// Path Model
// ----------
/**
* @typedef {Object} PathModel
* Object containing calculated information about the samples in a path.
*
* @property {Array} categoryInds
* Array of category indices for each dimension (length `numDimensions`)
* @param {String} pathColor
* Color of this path. (Note: Any colorscaling has already taken place)
* @property {Array} valueInds
* Array of indices (into the original value array) of all samples in this path
* @property {Number} count
* The number of elements from the original array in this path
* @property {String} color
* The path's color (ass CSS color string)
* @property rawColor
* The raw color value specified by the user. May be a CSS color string or a Number
*/
/**
* Create and return a new PathModel object
* @param {Array} categoryInds
* @param color
* @param rawColor
* @return {PathModel}
*/
function createPathModel(categoryInds, color, rawColor) {
return {
categoryInds: categoryInds,
color: color,
rawColor: rawColor,
valueInds: [],
count: 0
};
}
/**
* Update a PathModel object with a new value index
* Note: The calling parameter is modified in place.
*
* @param {PathModel} pathModel
* @param {Number} valueInd
* @param {Number} count
*/
function updatePathModel(pathModel, valueInd, count) {
pathModel.valueInds.push(valueInd);
pathModel.count += count;
}
// Unique calculations
// ===================
/**
* @typedef {Object} UniqueInfo
* Object containing information about the unique values of an input array
*
* @property {Array} uniqueValues
* The unique values in the input array
* @property {Array} uniqueCounts
* The number of times each entry in uniqueValues occurs in input array.
* This has the same length as `uniqueValues`
* @property {Array} inds
* Indices into uniqueValues that would reproduce original input array
*/
/**
* Compute unique value information for an array
*
* IMPORTANT: Note that values are considered unique
* if their string representations are unique.
*
* @param {Array} values
* @param {Array|undefined} uniqueValues
* Array of expected unique values. The uniqueValues property of the resulting UniqueInfo object will begin with
* these entries. Entries are included even if there are zero occurrences in the values array. Entries found in
* the values array that are not present in uniqueValues will be included at the end of the array in the
* UniqueInfo object.
* @return {UniqueInfo}
*/
function getUniqueInfo(values, uniqueValues) {
// Initialize uniqueValues if not specified
if (uniqueValues === undefined || uniqueValues === null) {
uniqueValues = [];
} else {
// Shallow copy so append below doesn't alter input array
uniqueValues = uniqueValues.map(function (e) {
return e;
});
}
// Initialize Variables
var uniqueValueCounts = {};
var uniqueValueInds = {};
var inds = [];
// Initialize uniqueValueCounts and
uniqueValues.forEach(function (uniqueVal, valInd) {
uniqueValueCounts[uniqueVal] = 0;
uniqueValueInds[uniqueVal] = valInd;
});
// Compute the necessary unique info in a single pass
for (var i = 0; i < values.length; i++) {
var item = values[i];
var itemInd;
if (uniqueValueCounts[item] === undefined) {
// This item has a previously unseen value
uniqueValueCounts[item] = 1;
itemInd = uniqueValues.push(item) - 1;
uniqueValueInds[item] = itemInd;
} else {
// Increment count for this item
uniqueValueCounts[item]++;
itemInd = uniqueValueInds[item];
}
inds.push(itemInd);
}
// Build UniqueInfo
var uniqueCounts = uniqueValues.map(function (v) {
return uniqueValueCounts[v];
});
return {
uniqueValues: uniqueValues,
uniqueCounts: uniqueCounts,
inds: inds
};
}
/**
* Validate the requested display order for the dimensions.
* If the display order is a permutation of 0 through dimensions.length - 1, link to _displayindex
* Otherwise, replace the display order with the dimension order
* @param {Object} trace
*/
function validateDimensionDisplayInds(visibleDims) {
var displayInds = visibleDims.map(function (d) {
return d.displayindex;
});
var i;
if (isRangePermutation(displayInds)) {
for (i = 0; i < visibleDims.length; i++) {
visibleDims[i]._displayindex = visibleDims[i].displayindex;
}
} else {
for (i = 0; i < visibleDims.length; i++) {
visibleDims[i]._displayindex = i;
}
}
}
/**
* Update category properties based on the unique values found for this dimension
* @param {Object} dim
* @param {UniqueInfo} uniqueInfoDim
*/
function validateCategoryProperties(dim, uniqueInfoDim) {
// Update categoryarray
dim._categoryarray = uniqueInfoDim.uniqueValues;
// Handle ticktext
if (dim.ticktext === null || dim.ticktext === undefined) {
dim._ticktext = [];
} else {
// Shallow copy to avoid modifying input array
dim._ticktext = dim.ticktext.slice();
}
// Extend ticktext with elements from uniqueInfoDim.uniqueValues
for (var i = dim._ticktext.length; i < uniqueInfoDim.uniqueValues.length; i++) {
dim._ticktext.push(uniqueInfoDim.uniqueValues[i]);
}
}
/**
* Determine whether an array contains a permutation of the integers from 0 to the array's length - 1
* @param {Array} inds
* @return {boolean}
*/
function isRangePermutation(inds) {
var indsSpecified = new Array(inds.length);
for (var i = 0; i < inds.length; i++) {
// Check for out of bounds
if (inds[i] < 0 || inds[i] >= inds.length) {
return false;
}
// Check for collisions with already specified index
if (indsSpecified[inds[i]] !== undefined) {
return false;
}
indsSpecified[inds[i]] = true;
}
// Nothing out of bounds and no collisions. We have a permutation
return true;
}
/***/ }),
/***/ 67188:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var colorscaleDefaults = __webpack_require__(47280);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var handleArrayContainerDefaults = __webpack_require__(95631);
var attributes = __webpack_require__(78208);
var mergeLength = __webpack_require__(97048);
var isTypedArraySpec = (__webpack_require__(2764).isTypedArraySpec);
function handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce) {
coerce('line.shape');
coerce('line.hovertemplate');
var lineColor = coerce('line.color', layout.colorway[0]);
if (hasColorscale(traceIn, 'line') && Lib.isArrayOrTypedArray(lineColor)) {
if (lineColor.length) {
coerce('line.colorscale');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'line.',
cLetter: 'c'
});
return lineColor.length;
} else {
traceOut.line.color = defaultColor;
}
}
return Infinity;
}
function dimensionDefaults(dimensionIn, dimensionOut) {
function coerce(attr, dflt) {
return Lib.coerce(dimensionIn, dimensionOut, attributes.dimensions, attr, dflt);
}
var values = coerce('values');
var visible = coerce('visible');
if (!(values && values.length)) {
visible = dimensionOut.visible = false;
}
if (visible) {
// Dimension level
coerce('label');
coerce('displayindex', dimensionOut._index);
// Category level
var arrayIn = dimensionIn.categoryarray;
var isValidArray = Lib.isArrayOrTypedArray(arrayIn) && arrayIn.length > 0 || isTypedArraySpec(arrayIn);
var orderDefault;
if (isValidArray) orderDefault = 'array';
var order = coerce('categoryorder', orderDefault);
// coerce 'categoryarray' only in array order case
if (order === 'array') {
coerce('categoryarray');
coerce('ticktext');
} else {
delete dimensionIn.categoryarray;
delete dimensionIn.ticktext;
}
// cannot set 'categoryorder' to 'array' with an invalid 'categoryarray'
if (!isValidArray && order === 'array') {
dimensionOut.categoryorder = 'trace';
}
}
}
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var dimensions = handleArrayContainerDefaults(traceIn, traceOut, {
name: 'dimensions',
handleItemDefaults: dimensionDefaults
});
var len = handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
handleDomainDefaults(traceOut, layout, coerce);
if (!Array.isArray(dimensions) || !dimensions.length) {
traceOut.visible = false;
}
mergeLength(traceOut, dimensions, 'values', len);
coerce('hoveron');
coerce('hovertemplate');
coerce('arrangement');
coerce('bundlecolors');
coerce('sortpaths');
coerce('counts');
var labelfontDflt = {
family: layout.font.family,
size: Math.round(layout.font.size),
color: layout.font.color
};
Lib.coerceFont(coerce, 'labelfont', labelfontDflt);
var categoryfontDefault = {
family: layout.font.family,
size: Math.round(layout.font.size / 1.2),
color: layout.font.color
};
Lib.coerceFont(coerce, 'tickfont', categoryfontDefault);
};
/***/ }),
/***/ 53580:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(78208),
supplyDefaults: __webpack_require__(67188),
calc: __webpack_require__(15144),
plot: __webpack_require__(56664),
colorbar: {
container: 'line',
min: 'cmin',
max: 'cmax'
},
moduleType: 'trace',
name: 'parcats',
basePlotModule: __webpack_require__(26256),
categories: ['noOpacity'],
meta: {
description: ['Parallel categories diagram for multidimensional categorical data.'].join(' ')
}
};
/***/ }),
/***/ 4308:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var interpolateNumber = (__webpack_require__(78204)/* .interpolateNumber */ .Gz);
var Plotly = __webpack_require__(31520);
var Fx = __webpack_require__(39184);
var Lib = __webpack_require__(10923);
var strTranslate = Lib.strTranslate;
var Drawing = __webpack_require__(49348);
var tinycolor = __webpack_require__(70336);
var svgTextUtils = __webpack_require__(41536);
function performPlot(parcatsModels, graphDiv, layout, svg) {
var isStatic = graphDiv._context.staticPlot;
var viewModels = parcatsModels.map(createParcatsViewModel.bind(0, graphDiv, layout));
// Get (potentially empty) parcatslayer selection with bound data to single element array
var layerSelection = svg.selectAll('g.parcatslayer').data([null]);
// Initialize single parcatslayer group if it doesn't exist
layerSelection.enter().append('g').attr('class', 'parcatslayer').style('pointer-events', isStatic ? 'none' : 'all');
// Bind data to children of layerSelection and get reference to traceSelection
var traceSelection = layerSelection.selectAll('g.trace.parcats').data(viewModels, key);
// Initialize group for each trace/dimensions
var traceEnter = traceSelection.enter().append('g').attr('class', 'trace parcats');
// Update properties for each trace
traceSelection.attr('transform', function (d) {
return strTranslate(d.x, d.y);
});
// Initialize paths group
traceEnter.append('g').attr('class', 'paths');
// Update paths transform
var pathsSelection = traceSelection.select('g.paths');
// Get paths selection
var pathSelection = pathsSelection.selectAll('path.path').data(function (d) {
return d.paths;
}, key);
// Update existing path colors
pathSelection.attr('fill', function (d) {
return d.model.color;
});
// Create paths
var pathSelectionEnter = pathSelection.enter().append('path').attr('class', 'path').attr('stroke-opacity', 0).attr('fill', function (d) {
return d.model.color;
}).attr('fill-opacity', 0);
stylePathsNoHover(pathSelectionEnter);
// Set path geometry
pathSelection.attr('d', function (d) {
return d.svgD;
});
// sort paths
if (!pathSelectionEnter.empty()) {
// Only sort paths if there has been a change.
// Otherwise paths are already sorted or a hover operation may be in progress
pathSelection.sort(compareRawColor);
}
// Remove any old paths
pathSelection.exit().remove();
// Path hover
pathSelection.on('mouseover', mouseoverPath).on('mouseout', mouseoutPath).on('click', clickPath);
// Initialize dimensions group
traceEnter.append('g').attr('class', 'dimensions');
// Update dimensions transform
var dimensionsSelection = traceSelection.select('g.dimensions');
// Get dimension selection
var dimensionSelection = dimensionsSelection.selectAll('g.dimension').data(function (d) {
return d.dimensions;
}, key);
// Create dimension groups
dimensionSelection.enter().append('g').attr('class', 'dimension');
// Update dimension group transforms
dimensionSelection.attr('transform', function (d) {
return strTranslate(d.x, 0);
});
// Remove any old dimensions
dimensionSelection.exit().remove();
// Get category selection
var categorySelection = dimensionSelection.selectAll('g.category').data(function (d) {
return d.categories;
}, key);
// Initialize category groups
var categoryGroupEnterSelection = categorySelection.enter().append('g').attr('class', 'category');
// Update category transforms
categorySelection.attr('transform', function (d) {
return strTranslate(0, d.y);
});
// Initialize rectangle
categoryGroupEnterSelection.append('rect').attr('class', 'catrect').attr('pointer-events', 'none');
// Update rectangle
categorySelection.select('rect.catrect').attr('fill', 'none').attr('width', function (d) {
return d.width;
}).attr('height', function (d) {
return d.height;
});
styleCategoriesNoHover(categoryGroupEnterSelection);
// Initialize color band rects
var bandSelection = categorySelection.selectAll('rect.bandrect').data( /** @param {CategoryViewModel} catViewModel*/
function (catViewModel) {
return catViewModel.bands;
}, key);
// Raise all update bands to the top so that fading enter/exit bands will be behind
bandSelection.each(function () {
Lib.raiseToTop(this);
});
// Update band color
bandSelection.attr('fill', function (d) {
return d.color;
});
var bandsSelectionEnter = bandSelection.enter().append('rect').attr('class', 'bandrect').attr('stroke-opacity', 0).attr('fill', function (d) {
return d.color;
}).attr('fill-opacity', 0);
bandSelection.attr('fill', function (d) {
return d.color;
}).attr('width', function (d) {
return d.width;
}).attr('height', function (d) {
return d.height;
}).attr('y', function (d) {
return d.y;
}).attr('cursor', /** @param {CategoryBandViewModel} bandModel*/
function (bandModel) {
if (bandModel.parcatsViewModel.arrangement === 'fixed') {
return 'default';
} else if (bandModel.parcatsViewModel.arrangement === 'perpendicular') {
return 'ns-resize';
} else {
return 'move';
}
});
styleBandsNoHover(bandsSelectionEnter);
bandSelection.exit().remove();
// Initialize category label
categoryGroupEnterSelection.append('text').attr('class', 'catlabel').attr('pointer-events', 'none');
var paperColor = graphDiv._fullLayout.paper_bgcolor;
// Update category label
categorySelection.select('text.catlabel').attr('text-anchor', function (d) {
if (catInRightDim(d)) {
// Place label to the right of category
return 'start';
} else {
// Place label to the left of category
return 'end';
}
}).attr('alignment-baseline', 'middle').style('text-shadow', svgTextUtils.makeTextShadow(paperColor)).style('fill', 'rgb(0, 0, 0)').attr('x', function (d) {
if (catInRightDim(d)) {
// Place label to the right of category
return d.width + 5;
} else {
// Place label to the left of category
return -5;
}
}).attr('y', function (d) {
return d.height / 2;
}).text(function (d) {
return d.model.categoryLabel;
}).each( /** @param {CategoryViewModel} catModel*/
function (catModel) {
Drawing.font(d3.select(this), catModel.parcatsViewModel.categorylabelfont);
svgTextUtils.convertToTspans(d3.select(this), graphDiv);
});
// Initialize dimension label
categoryGroupEnterSelection.append('text').attr('class', 'dimlabel');
// Update dimension label
categorySelection.select('text.dimlabel').attr('text-anchor', 'middle').attr('alignment-baseline', 'baseline').attr('cursor', /** @param {CategoryViewModel} catModel*/
function (catModel) {
if (catModel.parcatsViewModel.arrangement === 'fixed') {
return 'default';
} else {
return 'ew-resize';
}
}).attr('x', function (d) {
return d.width / 2;
}).attr('y', -5).text(function (d, i) {
if (i === 0) {
// Add dimension label above topmost category
return d.parcatsViewModel.model.dimensions[d.model.dimensionInd].dimensionLabel;
} else {
return null;
}
}).each( /** @param {CategoryViewModel} catModel*/
function (catModel) {
Drawing.font(d3.select(this), catModel.parcatsViewModel.labelfont);
});
// Category hover
// categorySelection.select('rect.catrect')
categorySelection.selectAll('rect.bandrect').on('mouseover', mouseoverCategoryBand).on('mouseout', mouseoutCategory);
// Remove unused categories
categorySelection.exit().remove();
// Setup drag
dimensionSelection.call(d3.behavior.drag().origin(function (d) {
return {
x: d.x,
y: 0
};
}).on('dragstart', dragDimensionStart).on('drag', dragDimension).on('dragend', dragDimensionEnd));
// Save off selections to view models
traceSelection.each(function (d) {
d.traceSelection = d3.select(this);
d.pathSelection = d3.select(this).selectAll('g.paths').selectAll('path.path');
d.dimensionSelection = d3.select(this).selectAll('g.dimensions').selectAll('g.dimension');
});
// Remove any orphan traces
traceSelection.exit().remove();
}
/**
* Create / update parcat traces
*
* @param {Object} graphDiv
* @param {Object} svg
* @param {Array.} parcatsModels
* @param {Layout} layout
*/
module.exports = function (graphDiv, svg, parcatsModels, layout) {
performPlot(parcatsModels, graphDiv, layout, svg);
};
/**
* Function the returns the key property of an object for use with as D3 join function
* @param d
*/
function key(d) {
return d.key;
}
/** True if a category view model is in the right-most display dimension
* @param {CategoryViewModel} d */
function catInRightDim(d) {
var numDims = d.parcatsViewModel.dimensions.length;
var leftDimInd = d.parcatsViewModel.dimensions[numDims - 1].model.dimensionInd;
return d.model.dimensionInd === leftDimInd;
}
/**
* @param {PathViewModel} a
* @param {PathViewModel} b
*/
function compareRawColor(a, b) {
if (a.model.rawColor > b.model.rawColor) {
return 1;
} else if (a.model.rawColor < b.model.rawColor) {
return -1;
} else {
return 0;
}
}
/**
* Handle path mouseover
* @param {PathViewModel} d
*/
function mouseoverPath(d) {
if (!d.parcatsViewModel.dragDimension) {
// We're not currently dragging
if (d.parcatsViewModel.hoverinfoItems.indexOf('skip') === -1) {
// hoverinfo is not skip, so we at least style the paths and emit interaction events
// Raise path to top
Lib.raiseToTop(this);
stylePathsHover(d3.select(this));
// Emit hover event
var points = buildPointsArrayForPath(d);
var constraints = buildConstraintsForPath(d);
d.parcatsViewModel.graphDiv.emit('plotly_hover', {
points: points,
event: d3.event,
constraints: constraints
});
// Handle hover label
if (d.parcatsViewModel.hoverinfoItems.indexOf('none') === -1) {
// hoverinfo is a combination of 'count' and 'probability'
// Mouse
var hoverX = d3.mouse(this)[0];
// Label
var gd = d.parcatsViewModel.graphDiv;
var trace = d.parcatsViewModel.trace;
var fullLayout = gd._fullLayout;
var rootBBox = fullLayout._paperdiv.node().getBoundingClientRect();
var graphDivBBox = d.parcatsViewModel.graphDiv.getBoundingClientRect();
// Find path center in path coordinates
var pathCenterX, pathCenterY, dimInd;
for (dimInd = 0; dimInd < d.leftXs.length - 1; dimInd++) {
if (d.leftXs[dimInd] + d.dimWidths[dimInd] - 2 <= hoverX && hoverX <= d.leftXs[dimInd + 1] + 2) {
var leftDim = d.parcatsViewModel.dimensions[dimInd];
var rightDim = d.parcatsViewModel.dimensions[dimInd + 1];
pathCenterX = (leftDim.x + leftDim.width + rightDim.x) / 2;
pathCenterY = (d.topYs[dimInd] + d.topYs[dimInd + 1] + d.height) / 2;
break;
}
}
// Find path center in root coordinates
var hoverCenterX = d.parcatsViewModel.x + pathCenterX;
var hoverCenterY = d.parcatsViewModel.y + pathCenterY;
var textColor = tinycolor.mostReadable(d.model.color, ['black', 'white']);
var count = d.model.count;
var prob = count / d.parcatsViewModel.model.count;
var labels = {
countLabel: count,
probabilityLabel: prob.toFixed(3)
};
// Build hover text
var hovertextParts = [];
if (d.parcatsViewModel.hoverinfoItems.indexOf('count') !== -1) {
hovertextParts.push(['Count:', labels.countLabel].join(' '));
}
if (d.parcatsViewModel.hoverinfoItems.indexOf('probability') !== -1) {
hovertextParts.push(['P:', labels.probabilityLabel].join(' '));
}
var hovertext = hovertextParts.join('
');
var mouseX = d3.mouse(gd)[0];
Fx.loneHover({
trace: trace,
x: hoverCenterX - rootBBox.left + graphDivBBox.left,
y: hoverCenterY - rootBBox.top + graphDivBBox.top,
text: hovertext,
color: d.model.color,
borderColor: 'black',
fontFamily: 'Monaco, "Courier New", monospace',
fontSize: 10,
fontColor: textColor,
idealAlign: mouseX < hoverCenterX ? 'right' : 'left',
hovertemplate: (trace.line || {}).hovertemplate,
hovertemplateLabels: labels,
eventData: [{
data: trace._input,
fullData: trace,
count: count,
probability: prob
}]
}, {
container: fullLayout._hoverlayer.node(),
outerContainer: fullLayout._paper.node(),
gd: gd
});
}
}
}
}
/**
* Handle path mouseout
* @param {PathViewModel} d
*/
function mouseoutPath(d) {
if (!d.parcatsViewModel.dragDimension) {
// We're not currently dragging
stylePathsNoHover(d3.select(this));
// Remove and hover label
Fx.loneUnhover(d.parcatsViewModel.graphDiv._fullLayout._hoverlayer.node());
// Restore path order
d.parcatsViewModel.pathSelection.sort(compareRawColor);
// Emit unhover event
if (d.parcatsViewModel.hoverinfoItems.indexOf('skip') === -1) {
var points = buildPointsArrayForPath(d);
var constraints = buildConstraintsForPath(d);
d.parcatsViewModel.graphDiv.emit('plotly_unhover', {
points: points,
event: d3.event,
constraints: constraints
});
}
}
}
/**
* Build array of point objects for a path
*
* For use in click/hover events
* @param {PathViewModel} d
*/
function buildPointsArrayForPath(d) {
var points = [];
var curveNumber = getTraceIndex(d.parcatsViewModel);
for (var i = 0; i < d.model.valueInds.length; i++) {
var pointNumber = d.model.valueInds[i];
points.push({
curveNumber: curveNumber,
pointNumber: pointNumber
});
}
return points;
}
/**
* Build constraints object for a path
*
* For use in click/hover events
* @param {PathViewModel} d
*/
function buildConstraintsForPath(d) {
var constraints = {};
var dimensions = d.parcatsViewModel.model.dimensions;
// dimensions
for (var i = 0; i < dimensions.length; i++) {
var dimension = dimensions[i];
var category = dimension.categories[d.model.categoryInds[i]];
constraints[dimension.containerInd] = category.categoryValue;
}
// color
if (d.model.rawColor !== undefined) {
constraints.color = d.model.rawColor;
}
return constraints;
}
/**
* Handle path click
* @param {PathViewModel} d
*/
function clickPath(d) {
if (d.parcatsViewModel.hoverinfoItems.indexOf('skip') === -1) {
// hoverinfo it's skip, so interaction events aren't disabled
var points = buildPointsArrayForPath(d);
var constraints = buildConstraintsForPath(d);
d.parcatsViewModel.graphDiv.emit('plotly_click', {
points: points,
event: d3.event,
constraints: constraints
});
}
}
function stylePathsNoHover(pathSelection) {
pathSelection.attr('fill', function (d) {
return d.model.color;
}).attr('fill-opacity', 0.6).attr('stroke', 'lightgray').attr('stroke-width', 0.2).attr('stroke-opacity', 1.0);
}
function stylePathsHover(pathSelection) {
pathSelection.attr('fill-opacity', 0.8).attr('stroke', function (d) {
return tinycolor.mostReadable(d.model.color, ['black', 'white']);
}).attr('stroke-width', 0.3);
}
function styleCategoryHover(categorySelection) {
categorySelection.select('rect.catrect').attr('stroke', 'black').attr('stroke-width', 2.5);
}
function styleCategoriesNoHover(categorySelection) {
categorySelection.select('rect.catrect').attr('stroke', 'black').attr('stroke-width', 1).attr('stroke-opacity', 1);
}
function styleBandsHover(bandsSelection) {
bandsSelection.attr('stroke', 'black').attr('stroke-width', 1.5);
}
function styleBandsNoHover(bandsSelection) {
bandsSelection.attr('stroke', 'black').attr('stroke-width', 0.2).attr('stroke-opacity', 1.0).attr('fill-opacity', 1.0);
}
/**
* Return selection of all paths that pass through the specified category
* @param {CategoryBandViewModel} catBandViewModel
*/
function selectPathsThroughCategoryBandColor(catBandViewModel) {
var allPaths = catBandViewModel.parcatsViewModel.pathSelection;
var dimInd = catBandViewModel.categoryViewModel.model.dimensionInd;
var catInd = catBandViewModel.categoryViewModel.model.categoryInd;
return allPaths.filter( /** @param {PathViewModel} pathViewModel */
function (pathViewModel) {
return pathViewModel.model.categoryInds[dimInd] === catInd && pathViewModel.model.color === catBandViewModel.color;
});
}
/**
* Perform hover styling for all paths that pass though the specified band element's category
*
* @param {HTMLElement} bandElement
* HTML element for band
*
*/
function styleForCategoryHovermode(bandElement) {
// Get all bands in the current category
var bandSel = d3.select(bandElement.parentNode).selectAll('rect.bandrect');
// Raise and style paths
bandSel.each(function (bvm) {
var paths = selectPathsThroughCategoryBandColor(bvm);
stylePathsHover(paths);
paths.each(function () {
// Raise path to top
Lib.raiseToTop(this);
});
});
// Style category
styleCategoryHover(d3.select(bandElement.parentNode));
}
/**
* Perform hover styling for all paths that pass though the category of the specified band element and share the
* same color
*
* @param {HTMLElement} bandElement
* HTML element for band
*
*/
function styleForColorHovermode(bandElement) {
var bandViewModel = d3.select(bandElement).datum();
var catPaths = selectPathsThroughCategoryBandColor(bandViewModel);
stylePathsHover(catPaths);
catPaths.each(function () {
// Raise path to top
Lib.raiseToTop(this);
});
// Style category for drag
d3.select(bandElement.parentNode).selectAll('rect.bandrect').filter(function (b) {
return b.color === bandViewModel.color;
}).each(function () {
Lib.raiseToTop(this);
styleBandsHover(d3.select(this));
});
}
/**
* @param {HTMLElement} bandElement
* HTML element for band
* @param eventName
* Event name (plotly_hover or plotly_click)
* @param event
* Mouse Event
*/
function emitPointsEventCategoryHovermode(bandElement, eventName, event) {
// Get all bands in the current category
var bandViewModel = d3.select(bandElement).datum();
var categoryModel = bandViewModel.categoryViewModel.model;
var gd = bandViewModel.parcatsViewModel.graphDiv;
var bandSel = d3.select(bandElement.parentNode).selectAll('rect.bandrect');
var points = [];
bandSel.each(function (bvm) {
var paths = selectPathsThroughCategoryBandColor(bvm);
paths.each(function (pathViewModel) {
// Extend points array
Array.prototype.push.apply(points, buildPointsArrayForPath(pathViewModel));
});
});
var constraints = {};
constraints[categoryModel.dimensionInd] = categoryModel.categoryValue;
gd.emit(eventName, {
points: points,
event: event,
constraints: constraints
});
}
/**
* @param {HTMLElement} bandElement
* HTML element for band
* @param eventName
* Event name (plotly_hover or plotly_click)
* @param event
* Mouse Event
*/
function emitPointsEventColorHovermode(bandElement, eventName, event) {
var bandViewModel = d3.select(bandElement).datum();
var categoryModel = bandViewModel.categoryViewModel.model;
var gd = bandViewModel.parcatsViewModel.graphDiv;
var paths = selectPathsThroughCategoryBandColor(bandViewModel);
var points = [];
paths.each(function (pathViewModel) {
// Extend points array
Array.prototype.push.apply(points, buildPointsArrayForPath(pathViewModel));
});
var constraints = {};
constraints[categoryModel.dimensionInd] = categoryModel.categoryValue;
// color
if (bandViewModel.rawColor !== undefined) {
constraints.color = bandViewModel.rawColor;
}
gd.emit(eventName, {
points: points,
event: event,
constraints: constraints
});
}
/**
* Create hover label for a band element's category (for use when hoveron === 'category')
*
* @param {ClientRect} rootBBox
* Client bounding box for root of figure
* @param {HTMLElement} bandElement
* HTML element for band
*
*/
function createHoverLabelForCategoryHovermode(gd, rootBBox, bandElement) {
gd._fullLayout._calcInverseTransform(gd);
var scaleX = gd._fullLayout._invScaleX;
var scaleY = gd._fullLayout._invScaleY;
// Selections
var rectSelection = d3.select(bandElement.parentNode).select('rect.catrect');
var rectBoundingBox = rectSelection.node().getBoundingClientRect();
// Models
/** @type {CategoryViewModel} */
var catViewModel = rectSelection.datum();
var parcatsViewModel = catViewModel.parcatsViewModel;
var dimensionModel = parcatsViewModel.model.dimensions[catViewModel.model.dimensionInd];
var trace = parcatsViewModel.trace;
// Positions
var hoverCenterY = rectBoundingBox.top + rectBoundingBox.height / 2;
var hoverCenterX, hoverLabelIdealAlign;
if (parcatsViewModel.dimensions.length > 1 && dimensionModel.displayInd === parcatsViewModel.dimensions.length - 1) {
// right most dimension
hoverCenterX = rectBoundingBox.left;
hoverLabelIdealAlign = 'left';
} else {
hoverCenterX = rectBoundingBox.left + rectBoundingBox.width;
hoverLabelIdealAlign = 'right';
}
var count = catViewModel.model.count;
var catLabel = catViewModel.model.categoryLabel;
var prob = count / catViewModel.parcatsViewModel.model.count;
var labels = {
countLabel: count,
categoryLabel: catLabel,
probabilityLabel: prob.toFixed(3)
};
// Hover label text
var hoverinfoParts = [];
if (catViewModel.parcatsViewModel.hoverinfoItems.indexOf('count') !== -1) {
hoverinfoParts.push(['Count:', labels.countLabel].join(' '));
}
if (catViewModel.parcatsViewModel.hoverinfoItems.indexOf('probability') !== -1) {
hoverinfoParts.push(['P(' + labels.categoryLabel + '):', labels.probabilityLabel].join(' '));
}
var hovertext = hoverinfoParts.join('
');
return {
trace: trace,
x: scaleX * (hoverCenterX - rootBBox.left),
y: scaleY * (hoverCenterY - rootBBox.top),
text: hovertext,
color: 'lightgray',
borderColor: 'black',
fontFamily: 'Monaco, "Courier New", monospace',
fontSize: 12,
fontColor: 'black',
idealAlign: hoverLabelIdealAlign,
hovertemplate: trace.hovertemplate,
hovertemplateLabels: labels,
eventData: [{
data: trace._input,
fullData: trace,
count: count,
category: catLabel,
probability: prob
}]
};
}
/**
* Create hover label for a band element's category (for use when hoveron === 'category')
*
* @param {ClientRect} rootBBox
* Client bounding box for root of figure
* @param {HTMLElement} bandElement
* HTML element for band
*
*/
function createHoverLabelForDimensionHovermode(gd, rootBBox, bandElement) {
var allHoverlabels = [];
d3.select(bandElement.parentNode.parentNode).selectAll('g.category').select('rect.catrect').each(function () {
var bandNode = this;
allHoverlabels.push(createHoverLabelForCategoryHovermode(gd, rootBBox, bandNode));
});
return allHoverlabels;
}
/**
* Create hover labels for a band element's category (for use when hoveron === 'dimension')
*
* @param {ClientRect} rootBBox
* Client bounding box for root of figure
* @param {HTMLElement} bandElement
* HTML element for band
*
*/
function createHoverLabelForColorHovermode(gd, rootBBox, bandElement) {
gd._fullLayout._calcInverseTransform(gd);
var scaleX = gd._fullLayout._invScaleX;
var scaleY = gd._fullLayout._invScaleY;
var bandBoundingBox = bandElement.getBoundingClientRect();
// Models
/** @type {CategoryBandViewModel} */
var bandViewModel = d3.select(bandElement).datum();
var catViewModel = bandViewModel.categoryViewModel;
var parcatsViewModel = catViewModel.parcatsViewModel;
var dimensionModel = parcatsViewModel.model.dimensions[catViewModel.model.dimensionInd];
var trace = parcatsViewModel.trace;
// positions
var hoverCenterY = bandBoundingBox.y + bandBoundingBox.height / 2;
var hoverCenterX, hoverLabelIdealAlign;
if (parcatsViewModel.dimensions.length > 1 && dimensionModel.displayInd === parcatsViewModel.dimensions.length - 1) {
// right most dimension
hoverCenterX = bandBoundingBox.left;
hoverLabelIdealAlign = 'left';
} else {
hoverCenterX = bandBoundingBox.left + bandBoundingBox.width;
hoverLabelIdealAlign = 'right';
}
// Labels
var catLabel = catViewModel.model.categoryLabel;
// Counts
var totalCount = bandViewModel.parcatsViewModel.model.count;
var bandColorCount = 0;
bandViewModel.categoryViewModel.bands.forEach(function (b) {
if (b.color === bandViewModel.color) {
bandColorCount += b.count;
}
});
var catCount = catViewModel.model.count;
var colorCount = 0;
parcatsViewModel.pathSelection.each( /** @param {PathViewModel} pathViewModel */
function (pathViewModel) {
if (pathViewModel.model.color === bandViewModel.color) {
colorCount += pathViewModel.model.count;
}
});
var pColorAndCat = bandColorCount / totalCount;
var pCatGivenColor = bandColorCount / colorCount;
var pColorGivenCat = bandColorCount / catCount;
var labels = {
countLabel: bandColorCount,
categoryLabel: catLabel,
probabilityLabel: pColorAndCat.toFixed(3)
};
// Hover label text
var hoverinfoParts = [];
if (catViewModel.parcatsViewModel.hoverinfoItems.indexOf('count') !== -1) {
hoverinfoParts.push(['Count:', labels.countLabel].join(' '));
}
if (catViewModel.parcatsViewModel.hoverinfoItems.indexOf('probability') !== -1) {
hoverinfoParts.push('P(color ∩ ' + catLabel + '): ' + labels.probabilityLabel);
hoverinfoParts.push('P(' + catLabel + ' | color): ' + pCatGivenColor.toFixed(3));
hoverinfoParts.push('P(color | ' + catLabel + '): ' + pColorGivenCat.toFixed(3));
}
var hovertext = hoverinfoParts.join('
');
// Compute text color
var textColor = tinycolor.mostReadable(bandViewModel.color, ['black', 'white']);
return {
trace: trace,
x: scaleX * (hoverCenterX - rootBBox.left),
y: scaleY * (hoverCenterY - rootBBox.top),
// name: 'NAME',
text: hovertext,
color: bandViewModel.color,
borderColor: 'black',
fontFamily: 'Monaco, "Courier New", monospace',
fontColor: textColor,
fontSize: 10,
idealAlign: hoverLabelIdealAlign,
hovertemplate: trace.hovertemplate,
hovertemplateLabels: labels,
eventData: [{
data: trace._input,
fullData: trace,
category: catLabel,
count: totalCount,
probability: pColorAndCat,
categorycount: catCount,
colorcount: colorCount,
bandcolorcount: bandColorCount
}]
};
}
/**
* Handle dimension mouseover
* @param {CategoryBandViewModel} bandViewModel
*/
function mouseoverCategoryBand(bandViewModel) {
if (!bandViewModel.parcatsViewModel.dragDimension) {
// We're not currently dragging
if (bandViewModel.parcatsViewModel.hoverinfoItems.indexOf('skip') === -1) {
// hoverinfo is not skip, so we at least style the bands and emit interaction events
// Mouse
var mouseY = d3.mouse(this)[1];
if (mouseY < -1) {
// Hover is above above the category rectangle (probably the dimension title text)
return;
}
var gd = bandViewModel.parcatsViewModel.graphDiv;
var fullLayout = gd._fullLayout;
var rootBBox = fullLayout._paperdiv.node().getBoundingClientRect();
var hoveron = bandViewModel.parcatsViewModel.hoveron;
/** @type {HTMLElement} */
var bandElement = this;
// Handle style and events
if (hoveron === 'color') {
styleForColorHovermode(bandElement);
emitPointsEventColorHovermode(bandElement, 'plotly_hover', d3.event);
} else {
styleForCategoryHovermode(bandElement);
emitPointsEventCategoryHovermode(bandElement, 'plotly_hover', d3.event);
}
// Handle hover label
if (bandViewModel.parcatsViewModel.hoverinfoItems.indexOf('none') === -1) {
var hoverItems;
if (hoveron === 'category') {
hoverItems = createHoverLabelForCategoryHovermode(gd, rootBBox, bandElement);
} else if (hoveron === 'color') {
hoverItems = createHoverLabelForColorHovermode(gd, rootBBox, bandElement);
} else if (hoveron === 'dimension') {
hoverItems = createHoverLabelForDimensionHovermode(gd, rootBBox, bandElement);
}
if (hoverItems) {
Fx.loneHover(hoverItems, {
container: fullLayout._hoverlayer.node(),
outerContainer: fullLayout._paper.node(),
gd: gd
});
}
}
}
}
}
/**
* Handle dimension mouseover
* @param {CategoryBandViewModel} bandViewModel
*/
function mouseoutCategory(bandViewModel) {
var parcatsViewModel = bandViewModel.parcatsViewModel;
if (!parcatsViewModel.dragDimension) {
// We're not dragging anything
// Reset unhovered styles
stylePathsNoHover(parcatsViewModel.pathSelection);
styleCategoriesNoHover(parcatsViewModel.dimensionSelection.selectAll('g.category'));
styleBandsNoHover(parcatsViewModel.dimensionSelection.selectAll('g.category').selectAll('rect.bandrect'));
// Remove hover label
Fx.loneUnhover(parcatsViewModel.graphDiv._fullLayout._hoverlayer.node());
// Restore path order
parcatsViewModel.pathSelection.sort(compareRawColor);
// Emit unhover event
if (parcatsViewModel.hoverinfoItems.indexOf('skip') === -1) {
var hoveron = bandViewModel.parcatsViewModel.hoveron;
var bandElement = this;
// Handle style and events
if (hoveron === 'color') {
emitPointsEventColorHovermode(bandElement, 'plotly_unhover', d3.event);
} else {
emitPointsEventCategoryHovermode(bandElement, 'plotly_unhover', d3.event);
}
}
}
}
/**
* Handle dimension drag start
* @param {DimensionViewModel} d
*/
function dragDimensionStart(d) {
// Check if dragging is supported
if (d.parcatsViewModel.arrangement === 'fixed') {
return;
}
// Save off initial drag indexes for dimension
d.dragDimensionDisplayInd = d.model.displayInd;
d.initialDragDimensionDisplayInds = d.parcatsViewModel.model.dimensions.map(function (d) {
return d.displayInd;
});
d.dragHasMoved = false;
// Check for category hit
d.dragCategoryDisplayInd = null;
d3.select(this).selectAll('g.category').select('rect.catrect').each( /** @param {CategoryViewModel} catViewModel */
function (catViewModel) {
var catMouseX = d3.mouse(this)[0];
var catMouseY = d3.mouse(this)[1];
if (-2 <= catMouseX && catMouseX <= catViewModel.width + 2 && -2 <= catMouseY && catMouseY <= catViewModel.height + 2) {
// Save off initial drag indexes for categories
d.dragCategoryDisplayInd = catViewModel.model.displayInd;
d.initialDragCategoryDisplayInds = d.model.categories.map(function (c) {
return c.displayInd;
});
// Initialize categories dragY to be the current y position
catViewModel.model.dragY = catViewModel.y;
// Raise category
Lib.raiseToTop(this.parentNode);
// Get band element
d3.select(this.parentNode).selectAll('rect.bandrect')
/** @param {CategoryBandViewModel} bandViewModel */.each(function (bandViewModel) {
if (bandViewModel.y < catMouseY && catMouseY <= bandViewModel.y + bandViewModel.height) {
d.potentialClickBand = this;
}
});
}
});
// Update toplevel drag dimension
d.parcatsViewModel.dragDimension = d;
// Remove hover label if any
Fx.loneUnhover(d.parcatsViewModel.graphDiv._fullLayout._hoverlayer.node());
}
/**
* Handle dimension drag
* @param {DimensionViewModel} d
*/
function dragDimension(d) {
// Check if dragging is supported
if (d.parcatsViewModel.arrangement === 'fixed') {
return;
}
d.dragHasMoved = true;
if (d.dragDimensionDisplayInd === null) {
return;
}
var dragDimInd = d.dragDimensionDisplayInd;
var prevDimInd = dragDimInd - 1;
var nextDimInd = dragDimInd + 1;
var dragDimension = d.parcatsViewModel.dimensions[dragDimInd];
// Update category
if (d.dragCategoryDisplayInd !== null) {
var dragCategory = dragDimension.categories[d.dragCategoryDisplayInd];
// Update dragY by dy
dragCategory.model.dragY += d3.event.dy;
var categoryY = dragCategory.model.dragY;
// Check for category drag swaps
var catDisplayInd = dragCategory.model.displayInd;
var dimCategoryViews = dragDimension.categories;
var catAbove = dimCategoryViews[catDisplayInd - 1];
var catBelow = dimCategoryViews[catDisplayInd + 1];
// Check for overlap above
if (catAbove !== undefined) {
if (categoryY < catAbove.y + catAbove.height / 2.0) {
// Swap display inds
dragCategory.model.displayInd = catAbove.model.displayInd;
catAbove.model.displayInd = catDisplayInd;
}
}
if (catBelow !== undefined) {
if (categoryY + dragCategory.height > catBelow.y + catBelow.height / 2.0) {
// Swap display inds
dragCategory.model.displayInd = catBelow.model.displayInd;
catBelow.model.displayInd = catDisplayInd;
}
}
// Update category drag display index
d.dragCategoryDisplayInd = dragCategory.model.displayInd;
}
// Update dimension position
if (d.dragCategoryDisplayInd === null || d.parcatsViewModel.arrangement === 'freeform') {
dragDimension.model.dragX = d3.event.x;
// Check for dimension swaps
var prevDimension = d.parcatsViewModel.dimensions[prevDimInd];
var nextDimension = d.parcatsViewModel.dimensions[nextDimInd];
if (prevDimension !== undefined) {
if (dragDimension.model.dragX < prevDimension.x + prevDimension.width) {
// Swap display inds
dragDimension.model.displayInd = prevDimension.model.displayInd;
prevDimension.model.displayInd = dragDimInd;
}
}
if (nextDimension !== undefined) {
if (dragDimension.model.dragX + dragDimension.width > nextDimension.x) {
// Swap display inds
dragDimension.model.displayInd = nextDimension.model.displayInd;
nextDimension.model.displayInd = d.dragDimensionDisplayInd;
}
}
// Update drag display index
d.dragDimensionDisplayInd = dragDimension.model.displayInd;
}
// Update view models
updateDimensionViewModels(d.parcatsViewModel);
updatePathViewModels(d.parcatsViewModel);
// Update svg geometry
updateSvgCategories(d.parcatsViewModel);
updateSvgPaths(d.parcatsViewModel);
}
/**
* Handle dimension drag end
* @param {DimensionViewModel} d
*/
function dragDimensionEnd(d) {
// Check if dragging is supported
if (d.parcatsViewModel.arrangement === 'fixed') {
return;
}
if (d.dragDimensionDisplayInd === null) {
return;
}
d3.select(this).selectAll('text').attr('font-weight', 'normal');
// Compute restyle command
// -----------------------
var restyleData = {};
var traceInd = getTraceIndex(d.parcatsViewModel);
// ### Handle dimension reordering ###
var finalDragDimensionDisplayInds = d.parcatsViewModel.model.dimensions.map(function (d) {
return d.displayInd;
});
var anyDimsReordered = d.initialDragDimensionDisplayInds.some(function (initDimDisplay, dimInd) {
return initDimDisplay !== finalDragDimensionDisplayInds[dimInd];
});
if (anyDimsReordered) {
finalDragDimensionDisplayInds.forEach(function (finalDimDisplay, dimInd) {
var containerInd = d.parcatsViewModel.model.dimensions[dimInd].containerInd;
restyleData['dimensions[' + containerInd + '].displayindex'] = finalDimDisplay;
});
}
// ### Handle category reordering ###
var anyCatsReordered = false;
if (d.dragCategoryDisplayInd !== null) {
var finalDragCategoryDisplayInds = d.model.categories.map(function (c) {
return c.displayInd;
});
anyCatsReordered = d.initialDragCategoryDisplayInds.some(function (initCatDisplay, catInd) {
return initCatDisplay !== finalDragCategoryDisplayInds[catInd];
});
if (anyCatsReordered) {
// Sort a shallow copy of the category models by display index
var sortedCategoryModels = d.model.categories.slice().sort(function (a, b) {
return a.displayInd - b.displayInd;
});
// Get new categoryarray and ticktext values
var newCategoryArray = sortedCategoryModels.map(function (v) {
return v.categoryValue;
});
var newCategoryLabels = sortedCategoryModels.map(function (v) {
return v.categoryLabel;
});
restyleData['dimensions[' + d.model.containerInd + '].categoryarray'] = [newCategoryArray];
restyleData['dimensions[' + d.model.containerInd + '].ticktext'] = [newCategoryLabels];
restyleData['dimensions[' + d.model.containerInd + '].categoryorder'] = 'array';
}
}
// Handle potential click event
// ----------------------------
if (d.parcatsViewModel.hoverinfoItems.indexOf('skip') === -1) {
if (!d.dragHasMoved && d.potentialClickBand) {
if (d.parcatsViewModel.hoveron === 'color') {
emitPointsEventColorHovermode(d.potentialClickBand, 'plotly_click', d3.event.sourceEvent);
} else {
emitPointsEventCategoryHovermode(d.potentialClickBand, 'plotly_click', d3.event.sourceEvent);
}
}
}
// Nullify drag states
// -------------------
d.model.dragX = null;
if (d.dragCategoryDisplayInd !== null) {
var dragCategory = d.parcatsViewModel.dimensions[d.dragDimensionDisplayInd].categories[d.dragCategoryDisplayInd];
dragCategory.model.dragY = null;
d.dragCategoryDisplayInd = null;
}
d.dragDimensionDisplayInd = null;
d.parcatsViewModel.dragDimension = null;
d.dragHasMoved = null;
d.potentialClickBand = null;
// Update view models
// ------------------
updateDimensionViewModels(d.parcatsViewModel);
updatePathViewModels(d.parcatsViewModel);
// Perform transition
// ------------------
var transition = d3.transition().duration(300).ease('cubic-in-out');
transition.each(function () {
updateSvgCategories(d.parcatsViewModel, true);
updateSvgPaths(d.parcatsViewModel, true);
}).each('end', function () {
if (anyDimsReordered || anyCatsReordered) {
// Perform restyle if the order of categories or dimensions changed
Plotly.restyle(d.parcatsViewModel.graphDiv, restyleData, [traceInd]);
}
});
}
/**
*
* @param {ParcatsViewModel} parcatsViewModel
*/
function getTraceIndex(parcatsViewModel) {
var traceInd;
var allTraces = parcatsViewModel.graphDiv._fullData;
for (var i = 0; i < allTraces.length; i++) {
if (parcatsViewModel.key === allTraces[i].uid) {
traceInd = i;
break;
}
}
return traceInd;
}
/** Update the svg paths for view model
* @param {ParcatsViewModel} parcatsViewModel
* @param {boolean} hasTransition Whether to update element with transition
*/
function updateSvgPaths(parcatsViewModel, hasTransition) {
if (hasTransition === undefined) {
hasTransition = false;
}
function transition(selection) {
return hasTransition ? selection.transition() : selection;
}
// Update binding
parcatsViewModel.pathSelection.data(function (d) {
return d.paths;
}, key);
// Update paths
transition(parcatsViewModel.pathSelection).attr('d', function (d) {
return d.svgD;
});
}
/** Update the svg paths for view model
* @param {ParcatsViewModel} parcatsViewModel
* @param {boolean} hasTransition Whether to update element with transition
*/
function updateSvgCategories(parcatsViewModel, hasTransition) {
if (hasTransition === undefined) {
hasTransition = false;
}
function transition(selection) {
return hasTransition ? selection.transition() : selection;
}
// Update binding
parcatsViewModel.dimensionSelection.data(function (d) {
return d.dimensions;
}, key);
var categorySelection = parcatsViewModel.dimensionSelection.selectAll('g.category').data(function (d) {
return d.categories;
}, key);
// Update dimension position
transition(parcatsViewModel.dimensionSelection).attr('transform', function (d) {
return strTranslate(d.x, 0);
});
// Update category position
transition(categorySelection).attr('transform', function (d) {
return strTranslate(0, d.y);
});
var dimLabelSelection = categorySelection.select('.dimlabel');
// ### Update dimension label
// Only the top-most display category should have the dimension label
dimLabelSelection.text(function (d, i) {
if (i === 0) {
// Add dimension label above topmost category
return d.parcatsViewModel.model.dimensions[d.model.dimensionInd].dimensionLabel;
} else {
return null;
}
});
// Update category label
// Categories in the right-most display dimension have their labels on
// the right, all others on the left
var catLabelSelection = categorySelection.select('.catlabel');
catLabelSelection.attr('text-anchor', function (d) {
if (catInRightDim(d)) {
// Place label to the right of category
return 'start';
} else {
// Place label to the left of category
return 'end';
}
}).attr('x', function (d) {
if (catInRightDim(d)) {
// Place label to the right of category
return d.width + 5;
} else {
// Place label to the left of category
return -5;
}
}).each(function (d) {
// Update attriubutes of elements
var newX;
var newAnchor;
if (catInRightDim(d)) {
// Place label to the right of category
newX = d.width + 5;
newAnchor = 'start';
} else {
// Place label to the left of category
newX = -5;
newAnchor = 'end';
}
d3.select(this).selectAll('tspan').attr('x', newX).attr('text-anchor', newAnchor);
});
// Update bands
// Initialize color band rects
var bandSelection = categorySelection.selectAll('rect.bandrect').data( /** @param {CategoryViewModel} catViewModel*/
function (catViewModel) {
return catViewModel.bands;
}, key);
var bandsSelectionEnter = bandSelection.enter().append('rect').attr('class', 'bandrect').attr('cursor', 'move').attr('stroke-opacity', 0).attr('fill', function (d) {
return d.color;
}).attr('fill-opacity', 0);
bandSelection.attr('fill', function (d) {
return d.color;
}).attr('width', function (d) {
return d.width;
}).attr('height', function (d) {
return d.height;
}).attr('y', function (d) {
return d.y;
});
styleBandsNoHover(bandsSelectionEnter);
// Raise bands to the top
bandSelection.each(function () {
Lib.raiseToTop(this);
});
// Remove unused bands
bandSelection.exit().remove();
}
/**
* Create a ParcatsViewModel traces
* @param {Object} graphDiv
* Top-level graph div element
* @param {Layout} layout
* SVG layout object
* @param {Array.} wrappedParcatsModel
* Wrapped ParcatsModel for this trace
* @return {ParcatsViewModel}
*/
function createParcatsViewModel(graphDiv, layout, wrappedParcatsModel) {
// Unwrap model
var parcatsModel = wrappedParcatsModel[0];
// Compute margin
var margin = layout.margin || {
l: 80,
r: 80,
t: 100,
b: 80
};
// Compute pixel position/extents
var trace = parcatsModel.trace;
var domain = trace.domain;
var figureWidth = layout.width;
var figureHeight = layout.height;
var traceWidth = Math.floor(figureWidth * (domain.x[1] - domain.x[0]));
var traceHeight = Math.floor(figureHeight * (domain.y[1] - domain.y[0]));
var traceX = domain.x[0] * figureWidth + margin.l;
var traceY = layout.height - domain.y[1] * layout.height + margin.t;
// Handle path shape
// -----------------
var pathShape = trace.line.shape;
// Handle hover info
// -----------------
var hoverinfoItems;
if (trace.hoverinfo === 'all') {
hoverinfoItems = ['count', 'probability'];
} else {
hoverinfoItems = (trace.hoverinfo || '').split('+');
}
// Construct parcatsViewModel
// --------------------------
var parcatsViewModel = {
trace: trace,
key: trace.uid,
model: parcatsModel,
x: traceX,
y: traceY,
width: traceWidth,
height: traceHeight,
hoveron: trace.hoveron,
hoverinfoItems: hoverinfoItems,
arrangement: trace.arrangement,
bundlecolors: trace.bundlecolors,
sortpaths: trace.sortpaths,
labelfont: trace.labelfont,
categorylabelfont: trace.tickfont,
pathShape: pathShape,
dragDimension: null,
margin: margin,
paths: [],
dimensions: [],
graphDiv: graphDiv,
traceSelection: null,
pathSelection: null,
dimensionSelection: null
};
// Update dimension view models if we have at least 1 dimension
if (parcatsModel.dimensions) {
updateDimensionViewModels(parcatsViewModel);
// Update path view models if we have at least 2 dimensions
updatePathViewModels(parcatsViewModel);
}
// Inside a categories view model
return parcatsViewModel;
}
/**
* Build the SVG string to represents a parallel categories path
* @param {Array.} leftXPositions
* Array of the x positions of the left edge of each dimension (in display order)
* @param {Array.} pathYs
* Array of the y positions of the top of the path at each dimension (in display order)
* @param {Array.} dimWidths
* Array of the widths of each dimension in display order
* @param {Number} pathHeight
* The height of the path in pixels
* @param {Number} curvature
* The curvature factor for the path. 0 results in a straight line and values greater than zero result in curved paths
* @return {string}
*/
function buildSvgPath(leftXPositions, pathYs, dimWidths, pathHeight, curvature) {
// Compute the x midpoint of each path segment
var xRefPoints1 = [];
var xRefPoints2 = [];
var refInterpolator;
var d;
for (d = 0; d < dimWidths.length - 1; d++) {
refInterpolator = interpolateNumber(dimWidths[d] + leftXPositions[d], leftXPositions[d + 1]);
xRefPoints1.push(refInterpolator(curvature));
xRefPoints2.push(refInterpolator(1 - curvature));
}
// Move to top of path on left edge of left-most category
var svgD = 'M ' + leftXPositions[0] + ',' + pathYs[0];
// Horizontal line to right edge
svgD += 'l' + dimWidths[0] + ',0 ';
// Horizontal line to right edge
for (d = 1; d < dimWidths.length; d++) {
// Curve to left edge of category
svgD += 'C' + xRefPoints1[d - 1] + ',' + pathYs[d - 1] + ' ' + xRefPoints2[d - 1] + ',' + pathYs[d] + ' ' + leftXPositions[d] + ',' + pathYs[d];
// svgD += 'L' + leftXPositions[d] + ',' + pathYs[d];
// Horizontal line to right edge
svgD += 'l' + dimWidths[d] + ',0 ';
}
// Line down
svgD += 'l' + '0,' + pathHeight + ' ';
// Line to left edge of right-most category
svgD += 'l -' + dimWidths[dimWidths.length - 1] + ',0 ';
for (d = dimWidths.length - 2; d >= 0; d--) {
// Curve to right edge of category
svgD += 'C' + xRefPoints2[d] + ',' + (pathYs[d + 1] + pathHeight) + ' ' + xRefPoints1[d] + ',' + (pathYs[d] + pathHeight) + ' ' + (leftXPositions[d] + dimWidths[d]) + ',' + (pathYs[d] + pathHeight);
// svgD += 'L' + (leftXPositions[d] + dimWidths[d]) + ',' + (pathYs[d] + pathHeight);
// Horizontal line to right edge
svgD += 'l-' + dimWidths[d] + ',0 ';
}
// Close path
svgD += 'Z';
return svgD;
}
/**
* Update the path view models based on the dimension view models in a ParcatsViewModel
*
* @param {ParcatsViewModel} parcatsViewModel
* View model for trace
*/
function updatePathViewModels(parcatsViewModel) {
// Initialize an array of the y position of the top of the next path to be added to each category.
//
// nextYPositions[d][c] is the y position of the next path through category with index c of dimension with index d
var dimensionViewModels = parcatsViewModel.dimensions;
var parcatsModel = parcatsViewModel.model;
var nextYPositions = dimensionViewModels.map(function (d) {
return d.categories.map(function (c) {
return c.y;
});
});
// Array from category index to category display index for each true dimension index
var catToDisplayIndPerDim = parcatsViewModel.model.dimensions.map(function (d) {
return d.categories.map(function (c) {
return c.displayInd;
});
});
// Array from true dimension index to dimension display index
var dimToDisplayInd = parcatsViewModel.model.dimensions.map(function (d) {
return d.displayInd;
});
var displayToDimInd = parcatsViewModel.dimensions.map(function (d) {
return d.model.dimensionInd;
});
// Array of the x position of the left edge of the rectangles for each dimension
var leftXPositions = dimensionViewModels.map(function (d) {
return d.x;
});
// Compute dimension widths
var dimWidths = dimensionViewModels.map(function (d) {
return d.width;
});
// Build sorted Array of PathModel objects
var pathModels = [];
for (var p in parcatsModel.paths) {
if (parcatsModel.paths.hasOwnProperty(p)) {
pathModels.push(parcatsModel.paths[p]);
}
}
// Compute category display inds to use for sorting paths
function pathDisplayCategoryInds(pathModel) {
var dimensionInds = pathModel.categoryInds.map(function (catInd, dimInd) {
return catToDisplayIndPerDim[dimInd][catInd];
});
var displayInds = displayToDimInd.map(function (dimInd) {
return dimensionInds[dimInd];
});
return displayInds;
}
// Sort in ascending order by display index array
pathModels.sort(function (v1, v2) {
// Build display inds for each path
var sortArray1 = pathDisplayCategoryInds(v1);
var sortArray2 = pathDisplayCategoryInds(v2);
// Handle path sort order
if (parcatsViewModel.sortpaths === 'backward') {
sortArray1.reverse();
sortArray2.reverse();
}
// Append the first value index of the path to break ties
sortArray1.push(v1.valueInds[0]);
sortArray2.push(v2.valueInds[0]);
// Handle color bundling
if (parcatsViewModel.bundlecolors) {
// Prepend sort array with the raw color value
sortArray1.unshift(v1.rawColor);
sortArray2.unshift(v2.rawColor);
}
// colors equal, sort by display categories
if (sortArray1 < sortArray2) {
return -1;
}
if (sortArray1 > sortArray2) {
return 1;
}
return 0;
});
// Create path models
var pathViewModels = new Array(pathModels.length);
var totalCount = dimensionViewModels[0].model.count;
var totalHeight = dimensionViewModels[0].categories.map(function (c) {
return c.height;
}).reduce(function (v1, v2) {
return v1 + v2;
});
for (var pathNumber = 0; pathNumber < pathModels.length; pathNumber++) {
var pathModel = pathModels[pathNumber];
var pathHeight;
if (totalCount > 0) {
pathHeight = totalHeight * (pathModel.count / totalCount);
} else {
pathHeight = 0;
}
// Build path y coords
var pathYs = new Array(nextYPositions.length);
for (var d = 0; d < pathModel.categoryInds.length; d++) {
var catInd = pathModel.categoryInds[d];
var catDisplayInd = catToDisplayIndPerDim[d][catInd];
var dimDisplayInd = dimToDisplayInd[d];
// Update next y position
pathYs[dimDisplayInd] = nextYPositions[dimDisplayInd][catDisplayInd];
nextYPositions[dimDisplayInd][catDisplayInd] += pathHeight;
// Update category color information
var catViewModle = parcatsViewModel.dimensions[dimDisplayInd].categories[catDisplayInd];
var numBands = catViewModle.bands.length;
var lastCatBand = catViewModle.bands[numBands - 1];
if (lastCatBand === undefined || pathModel.rawColor !== lastCatBand.rawColor) {
// Create a new band
var bandY = lastCatBand === undefined ? 0 : lastCatBand.y + lastCatBand.height;
catViewModle.bands.push({
key: bandY,
color: pathModel.color,
rawColor: pathModel.rawColor,
height: pathHeight,
width: catViewModle.width,
count: pathModel.count,
y: bandY,
categoryViewModel: catViewModle,
parcatsViewModel: parcatsViewModel
});
} else {
// Extend current band
var currentBand = catViewModle.bands[numBands - 1];
currentBand.height += pathHeight;
currentBand.count += pathModel.count;
}
}
// build svg path
var svgD;
if (parcatsViewModel.pathShape === 'hspline') {
svgD = buildSvgPath(leftXPositions, pathYs, dimWidths, pathHeight, 0.5);
} else {
svgD = buildSvgPath(leftXPositions, pathYs, dimWidths, pathHeight, 0);
}
pathViewModels[pathNumber] = {
key: pathModel.valueInds[0],
model: pathModel,
height: pathHeight,
leftXs: leftXPositions,
topYs: pathYs,
dimWidths: dimWidths,
svgD: svgD,
parcatsViewModel: parcatsViewModel
};
}
parcatsViewModel.paths = pathViewModels;
// * @property key
// * Unique key for this model
// * @property {PathModel} model
// * Source path model
// * @property {Number} height
// * Height of this path (pixels)
// * @property {String} svgD
// * SVG path "d" attribute string
}
/**
* Update the dimension view models based on the dimension models in a ParcatsViewModel
*
* @param {ParcatsViewModel} parcatsViewModel
* View model for trace
*/
function updateDimensionViewModels(parcatsViewModel) {
// Compute dimension ordering
var dimensionsIndInfo = parcatsViewModel.model.dimensions.map(function (d) {
return {
displayInd: d.displayInd,
dimensionInd: d.dimensionInd
};
});
dimensionsIndInfo.sort(function (a, b) {
return a.displayInd - b.displayInd;
});
var dimensions = [];
for (var displayInd in dimensionsIndInfo) {
var dimensionInd = dimensionsIndInfo[displayInd].dimensionInd;
var dimModel = parcatsViewModel.model.dimensions[dimensionInd];
dimensions.push(createDimensionViewModel(parcatsViewModel, dimModel));
}
parcatsViewModel.dimensions = dimensions;
}
/**
* Create a parcats DimensionViewModel
*
* @param {ParcatsViewModel} parcatsViewModel
* View model for trace
* @param {DimensionModel} dimensionModel
* @return {DimensionViewModel}
*/
function createDimensionViewModel(parcatsViewModel, dimensionModel) {
// Compute dimension x position
var categoryLabelPad = 40;
var dimWidth = 16;
var numDimensions = parcatsViewModel.model.dimensions.length;
var displayInd = dimensionModel.displayInd;
// Compute x coordinate values
var dimDx;
var dimX0;
var dimX;
if (numDimensions > 1) {
dimDx = (parcatsViewModel.width - 2 * categoryLabelPad - dimWidth) / (numDimensions - 1);
} else {
dimDx = 0;
}
dimX0 = categoryLabelPad;
dimX = dimX0 + dimDx * displayInd;
// Compute categories
var categories = [];
var maxCats = parcatsViewModel.model.maxCats;
var numCats = dimensionModel.categories.length;
var catSpacing = 8;
var totalCount = dimensionModel.count;
var totalHeight = parcatsViewModel.height - catSpacing * (maxCats - 1);
var nextCatHeight;
var nextCatModel;
var nextCat;
var catInd;
var catDisplayInd;
// Compute starting Y offset
var nextCatY = (maxCats - numCats) * catSpacing / 2.0;
// Compute category ordering
var categoryIndInfo = dimensionModel.categories.map(function (c) {
return {
displayInd: c.displayInd,
categoryInd: c.categoryInd
};
});
categoryIndInfo.sort(function (a, b) {
return a.displayInd - b.displayInd;
});
for (catDisplayInd = 0; catDisplayInd < numCats; catDisplayInd++) {
catInd = categoryIndInfo[catDisplayInd].categoryInd;
nextCatModel = dimensionModel.categories[catInd];
if (totalCount > 0) {
nextCatHeight = nextCatModel.count / totalCount * totalHeight;
} else {
nextCatHeight = 0;
}
nextCat = {
key: nextCatModel.valueInds[0],
model: nextCatModel,
width: dimWidth,
height: nextCatHeight,
y: nextCatModel.dragY !== null ? nextCatModel.dragY : nextCatY,
bands: [],
parcatsViewModel: parcatsViewModel
};
nextCatY = nextCatY + nextCatHeight + catSpacing;
categories.push(nextCat);
}
return {
key: dimensionModel.dimensionInd,
x: dimensionModel.dragX !== null ? dimensionModel.dragX : dimX,
y: 0,
width: dimWidth,
model: dimensionModel,
categories: categories,
parcatsViewModel: parcatsViewModel,
dragCategoryDisplayInd: null,
dragDimensionDisplayInd: null,
initialDragDimensionDisplayInds: null,
initialDragCategoryDisplayInds: null,
dragHasMoved: null,
potentialClickBand: null
};
}
// JSDoc typedefs
// ==============
/**
* @typedef {Object} Layout
* Object containing svg layout information
*
* @property {Number} width (pixels)
* Usable width for Figure (after margins are removed)
* @property {Number} height (pixels)
* Usable height for Figure (after margins are removed)
* @property {Margin} margin
* Margin around the Figure (pixels)
*/
/**
* @typedef {Object} Margin
* Object containing padding information in pixels
*
* @property {Number} t
* Top margin
* @property {Number} r
* Right margin
* @property {Number} b
* Bottom margin
* @property {Number} l
* Left margin
*/
/**
* @typedef {Object} Font
* Object containing font information
*
* @property {Number} size: Font size
* @property {String} color: Font color
* @property {String} family: Font family
*/
/**
* @typedef {Object} ParcatsViewModel
* Object containing calculated parcats view information
*
* These are quantities that require Layout information to calculate
* @property key
* Unique key for this model
* @property {ParcatsModel} model
* Source parcats model
* @property {Array.} dimensions
* Array of dimension view models
* @property {Number} width
* Width for this trace (pixels)
* @property {Number} height
* Height for this trace (pixels)
* @property {Number} x
* X position of this trace with respect to the Figure (pixels)
* @property {Number} y
* Y position of this trace with respect to the Figure (pixels)
* @property {String} hoveron
* Hover interaction mode. One of: 'category', 'color', or 'dimension'
* @property {Array.} hoverinfoItems
* Info to display on hover. Array with a combination of 'counts' and/or 'probabilities', or 'none', or 'skip'
* @property {String} arrangement
* Category arrangement. One of: 'perpendicular', 'freeform', or 'fixed'
* @property {Boolean} bundlecolors
* Whether paths should be sorted so that like colors are bundled together as they pass through categories
* @property {String} sortpaths
* If 'forward' then sort paths based on dimensions from left to right. If 'backward' sort based on dimensions
* from right to left
* @property {Font} labelfont
* Font for the dimension labels
* @property {Font} categorylabelfont
* Font for the category labels
* @property {String} pathShape
* The shape of the paths. Either 'linear' or 'hspline'.
* @property {DimensionViewModel|null} dragDimension
* Dimension currently being dragged. Null if no drag in progress
* @property {Margin} margin
* Margin around the Figure
* @property {Object} graphDiv
* Top-level graph div element
* @property {Object} traceSelection
* D3 selection of this view models trace group element
* @property {Object} pathSelection
* D3 selection of this view models path elements
* @property {Object} dimensionSelection
* D3 selection of this view models dimension group element
*/
/**
* @typedef {Object} DimensionViewModel
* Object containing calculated parcats dimension view information
*
* These are quantities that require Layout information to calculate
* @property key
* Unique key for this model
* @property {DimensionModel} model
* Source dimension model
* @property {Number} x
* X position of the center of this dimension with respect to the Figure (pixels)
* @property {Number} y
* Y position of the top of this dimension with respect to the Figure (pixels)
* @property {Number} width
* Width of categories in this dimension (pixels)
* @property {ParcatsViewModel} parcatsViewModel
* The parent trace's view model
* @property {Array.} categories
* Dimensions category view models
* @property {Number|null} dragCategoryDisplayInd
* Display index of category currently being dragged. null if no category is being dragged
* @property {Number|null} dragDimensionDisplayInd
* Display index of the dimension being dragged. null if no dimension is being dragged
* @property {Array.|null} initialDragDimensionDisplayInds
* Dimensions display indexes at the beginning of the current drag. null if no dimension is being dragged
* @property {Array.|null} initialDragCategoryDisplayInds
* Category display indexes for the at the beginning of the current drag. null if no category is being dragged
* @property {HTMLElement} potentialClickBand
* Band under mouse when current drag began. If no drag movement takes place then a click will be emitted for this
* band. Null if not drag in progress.
* @property {Boolean} dragHasMoved
* True if there is an active drag and the drag has moved. If drag doesn't move before being ended then
* this may be interpreted as a click. Null if no drag in progress
*/
/**
* @typedef {Object} CategoryViewModel
* Object containing calculated parcats category view information
*
* These are quantities that require Layout information to calculate
* @property key
* Unique key for this model
* @property {CategoryModel} model
* Source category model
* @property {Number} width
* Width for this category (pixels)
* @property {Number} height
* Height for this category (pixels)
* @property {Number} y
* Y position of this cateogry with respect to the Figure (pixels)
* @property {Array.} bands
* Array of color bands inside the category
* @property {ParcatsViewModel} parcatsViewModel
* The parent trace's view model
*/
/**
* @typedef {Object} CategoryBandViewModel
* Object containing calculated category band information. A category band is a region inside a category covering
* paths of a single color
*
* @property key
* Unique key for this model
* @property color
* Band color
* @property rawColor
* Raw color value for band
* @property {Number} width
* Band width
* @property {Number} height
* Band height
* @property {Number} y
* Y position of top of the band with respect to the category
* @property {Number} count
* The number of samples represented by the band
* @property {CategoryViewModel} categoryViewModel
* The parent categorie's view model
* @property {ParcatsViewModel} parcatsViewModel
* The parent trace's view model
*/
/**
* @typedef {Object} PathViewModel
* Object containing calculated parcats path view information
*
* These are quantities that require Layout information to calculate
* @property key
* Unique key for this model
* @property {PathModel} model
* Source path model
* @property {Number} height
* Height of this path (pixels)
* @property {Array.} leftXs
* The x position of the left edge of each display dimension
* @property {Array.} topYs
* The y position of the top of the path for each display dimension
* @property {Array.} dimWidths
* The width of each display dimension
* @property {String} svgD
* SVG path "d" attribute string
* @property {ParcatsViewModel} parcatsViewModel
* The parent trace's view model
*/
/***/ }),
/***/ 56664:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var parcats = __webpack_require__(4308);
/**
* Create / update parcat traces
*
* @param {Object} graphDiv
* @param {Array.} parcatsModels
*/
module.exports = function plot(graphDiv, parcatsModels, transitionOpts, makeOnCompleteCallback) {
var fullLayout = graphDiv._fullLayout;
var svg = fullLayout._paper;
var size = fullLayout._size;
parcats(graphDiv, svg, parcatsModels, {
width: size.w,
height: size.h,
margin: {
t: size.t,
r: size.r,
b: size.b,
l: size.l
}
}, transitionOpts, makeOnCompleteCallback);
};
/***/ }),
/***/ 99584:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorScaleAttrs = __webpack_require__(99732);
var axesAttrs = __webpack_require__(88176);
var fontAttrs = __webpack_require__(71936);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var extendFlat = (__webpack_require__(55016).extendFlat);
var templatedArray = (__webpack_require__(58056).templatedArray);
module.exports = {
domain: domainAttrs({
name: 'parcoords',
trace: true,
editType: 'plot'
}),
labelangle: {
valType: 'angle',
dflt: 0,
editType: 'plot',
description: ['Sets the angle of the labels with respect to the horizontal.', 'For example, a `tickangle` of -90 draws the labels vertically.', 'Tilted labels with *labelangle* may be positioned better', 'inside margins when `labelposition` is set to *bottom*.'].join(' ')
},
labelside: {
valType: 'enumerated',
values: ['top', 'bottom'],
dflt: 'top',
editType: 'plot',
description: ['Specifies the location of the `label`.', '*top* positions labels above, next to the title', '*bottom* positions labels below the graph', 'Tilted labels with *labelangle* may be positioned better', 'inside margins when `labelposition` is set to *bottom*.'].join(' ')
},
labelfont: fontAttrs({
editType: 'plot',
description: 'Sets the font for the `dimension` labels.'
}),
tickfont: fontAttrs({
editType: 'plot',
description: 'Sets the font for the `dimension` tick values.'
}),
rangefont: fontAttrs({
editType: 'plot',
description: 'Sets the font for the `dimension` range values.'
}),
dimensions: templatedArray('dimension', {
label: {
valType: 'string',
editType: 'plot',
description: 'The shown name of the dimension.'
},
// TODO: better way to determine ordinal vs continuous axes,
// so users can use tickvals/ticktext with a continuous axis.
tickvals: extendFlat({}, axesAttrs.tickvals, {
editType: 'plot',
description: ['Sets the values at which ticks on this axis appear.'].join(' ')
}),
ticktext: extendFlat({}, axesAttrs.ticktext, {
editType: 'plot',
description: ['Sets the text displayed at the ticks position via `tickvals`.'].join(' ')
}),
tickformat: extendFlat({}, axesAttrs.tickformat, {
editType: 'plot'
}),
visible: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: 'Shows the dimension when set to `true` (the default). Hides the dimension for `false`.'
},
range: {
valType: 'info_array',
items: [{
valType: 'number',
editType: 'plot'
}, {
valType: 'number',
editType: 'plot'
}],
editType: 'plot',
description: ['The domain range that represents the full, shown axis extent. Defaults to the `values` extent.', 'Must be an array of `[fromValue, toValue]` with finite numbers as elements.'].join(' ')
},
constraintrange: {
valType: 'info_array',
freeLength: true,
dimensions: '1-2',
items: [{
valType: 'any',
editType: 'plot'
}, {
valType: 'any',
editType: 'plot'
}],
editType: 'plot',
description: ['The domain range to which the filter on the dimension is constrained. Must be an array', 'of `[fromValue, toValue]` with `fromValue <= toValue`, or if `multiselect` is not', 'disabled, you may give an array of arrays, where each inner array is `[fromValue, toValue]`.'].join(' ')
},
multiselect: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: 'Do we allow multiple selection ranges or just a single range?'
},
values: {
valType: 'data_array',
editType: 'calc',
description: ['Dimension values. `values[n]` represents the value of the `n`th point in the dataset,', 'therefore the `values` vector for all dimensions must be the same (longer vectors', 'will be truncated). Each value must be a finite number.'].join(' ')
},
editType: 'calc',
description: 'The dimensions (variables) of the parallel coordinates chart. 2..60 dimensions are supported.'
}),
line: extendFlat({
editType: 'calc'
}, colorScaleAttrs('line', {
// the default autocolorscale isn't quite usable for parcoords due to context ambiguity around 0 (grey, off-white)
// autocolorscale therefore defaults to false too, to avoid being overridden by the blue-white-red autocolor palette
colorscaleDflt: 'Viridis',
autoColorDflt: false,
editTypeOverride: 'calc'
})),
unselected: {
line: {
color: {
valType: 'color',
dflt: '#7f7f7f',
editType: 'plot',
description: ['Sets the base color of unselected lines.', 'in connection with `unselected.line.opacity`.'].join(' ')
},
opacity: {
valType: 'number',
min: 0,
max: 1,
dflt: 'auto',
editType: 'plot',
description: ['Sets the opacity of unselected lines.', 'The default *auto* decreases the opacity smoothly as the number of lines increases.', 'Use *1* to achieve exact `unselected.line.color`.'].join(' ')
},
editType: 'plot'
},
editType: 'plot'
}
};
/***/ }),
/***/ 54376:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var c = __webpack_require__(92304);
var d3 = __webpack_require__(6592);
var keyFun = (__webpack_require__(83104).keyFun);
var repeat = (__webpack_require__(83104).repeat);
var sortAsc = (__webpack_require__(10923).sorterAsc);
var strTranslate = (__webpack_require__(10923).strTranslate);
var snapRatio = c.bar.snapRatio;
function snapOvershoot(v, vAdjacent) {
return v * (1 - snapRatio) + vAdjacent * snapRatio;
}
var snapClose = c.bar.snapClose;
function closeToCovering(v, vAdjacent) {
return v * (1 - snapClose) + vAdjacent * snapClose;
}
// snap for the low end of a range on an ordinal scale
// on an ordinal scale, always show some overshoot from the exact value,
// so it's clear we're covering it
// find the interval we're in, and snap to 1/4 the distance to the next
// these two could be unified at a slight loss of readability / perf
function ordinalScaleSnap(isHigh, a, v, existingRanges) {
if (overlappingExisting(v, existingRanges)) return v;
var dir = isHigh ? -1 : 1;
var first = 0;
var last = a.length - 1;
if (dir < 0) {
var tmp = first;
first = last;
last = tmp;
}
var aHere = a[first];
var aPrev = aHere;
for (var i = first; dir * i < dir * last; i += dir) {
var nextI = i + dir;
var aNext = a[nextI];
// very close to the previous - snap down to it
if (dir * v < dir * closeToCovering(aHere, aNext)) return snapOvershoot(aHere, aPrev);
if (dir * v < dir * aNext || nextI === last) return snapOvershoot(aNext, aHere);
aPrev = aHere;
aHere = aNext;
}
}
function overlappingExisting(v, existingRanges) {
for (var i = 0; i < existingRanges.length; i++) {
if (v >= existingRanges[i][0] && v <= existingRanges[i][1]) return true;
}
return false;
}
function barHorizontalSetup(selection) {
selection.attr('x', -c.bar.captureWidth / 2).attr('width', c.bar.captureWidth);
}
function backgroundBarHorizontalSetup(selection) {
selection.attr('visibility', 'visible').style('visibility', 'visible').attr('fill', 'yellow').attr('opacity', 0);
}
function setHighlight(d) {
if (!d.brush.filterSpecified) {
return '0,' + d.height;
}
var pixelRanges = unitToPx(d.brush.filter.getConsolidated(), d.height);
var dashArray = [0]; // we start with a 0 length selection as filter ranges are inclusive, not exclusive
var p, sectionHeight, iNext;
var currentGap = pixelRanges.length ? pixelRanges[0][0] : null;
for (var i = 0; i < pixelRanges.length; i++) {
p = pixelRanges[i];
sectionHeight = p[1] - p[0];
dashArray.push(currentGap);
dashArray.push(sectionHeight);
iNext = i + 1;
if (iNext < pixelRanges.length) {
currentGap = pixelRanges[iNext][0] - p[1];
}
}
dashArray.push(d.height);
// d.height is added at the end to ensure that (1) we have an even number of dasharray points, MDN page says
// "If an odd number of values is provided, then the list of values is repeated to yield an even number of values."
// and (2) it's _at least_ as long as the full height (even if range is minuscule and at the bottom) though this
// may not be necessary, maybe duplicating the last point would do too. But no harm in a longer dasharray than line.
return dashArray;
}
function unitToPx(unitRanges, height) {
return unitRanges.map(function (pr) {
return pr.map(function (v) {
return Math.max(0, v * height);
}).sort(sortAsc);
});
}
// is the cursor over the north, middle, or south of a bar?
// the end handles extend over the last 10% of the bar
function getRegion(fPix, y) {
var pad = c.bar.handleHeight;
if (y > fPix[1] + pad || y < fPix[0] - pad) return;
if (y >= 0.9 * fPix[1] + 0.1 * fPix[0]) return 'n';
if (y <= 0.9 * fPix[0] + 0.1 * fPix[1]) return 's';
return 'ns';
}
function clearCursor() {
d3.select(document.body).style('cursor', null);
}
function styleHighlight(selection) {
// stroke-dasharray is used to minimize the number of created DOM nodes, because the requirement calls for up to
// 1000 individual selections on an axis, and there can be 60 axes per parcoords, and multiple parcoords per
// dashboard. The technique is similar to https://codepen.io/monfera/pen/rLYqWR and using a `polyline` with
// multiple sections, or a `path` element via its `d` attribute would also be DOM-sparing alternatives.
selection.attr('stroke-dasharray', setHighlight);
}
function renderHighlight(root, tweenCallback) {
var bar = d3.select(root).selectAll('.highlight, .highlight-shadow');
var barToStyle = tweenCallback ? bar.transition().duration(c.bar.snapDuration).each('end', tweenCallback) : bar;
styleHighlight(barToStyle);
}
function getInterval(d, y) {
var b = d.brush;
var active = b.filterSpecified;
var closestInterval = NaN;
var out = {};
var i;
if (active) {
var height = d.height;
var intervals = b.filter.getConsolidated();
var pixIntervals = unitToPx(intervals, height);
var hoveredInterval = NaN;
var previousInterval = NaN;
var nextInterval = NaN;
for (i = 0; i <= pixIntervals.length; i++) {
var p = pixIntervals[i];
if (p && p[0] <= y && y <= p[1]) {
// over a bar
hoveredInterval = i;
break;
} else {
// between bars, or before/after the first/last bar
previousInterval = i ? i - 1 : NaN;
if (p && p[0] > y) {
nextInterval = i;
break; // no point continuing as intervals are non-overlapping and sorted; could use log search
}
}
}
closestInterval = hoveredInterval;
if (isNaN(closestInterval)) {
if (isNaN(previousInterval) || isNaN(nextInterval)) {
closestInterval = isNaN(previousInterval) ? nextInterval : previousInterval;
} else {
closestInterval = y - pixIntervals[previousInterval][1] < pixIntervals[nextInterval][0] - y ? previousInterval : nextInterval;
}
}
if (!isNaN(closestInterval)) {
var fPix = pixIntervals[closestInterval];
var region = getRegion(fPix, y);
if (region) {
out.interval = intervals[closestInterval];
out.intervalPix = fPix;
out.region = region;
}
}
}
if (d.ordinal && !out.region) {
var a = d.unitTickvals;
var unitLocation = d.unitToPaddedPx.invert(y);
for (i = 0; i < a.length; i++) {
var rangei = [a[Math.max(i - 1, 0)] * 0.25 + a[i] * 0.75, a[Math.min(i + 1, a.length - 1)] * 0.25 + a[i] * 0.75];
if (unitLocation >= rangei[0] && unitLocation <= rangei[1]) {
out.clickableOrdinalRange = rangei;
break;
}
}
}
return out;
}
function dragstart(lThis, d) {
d3.event.sourceEvent.stopPropagation();
var y = d.height - d3.mouse(lThis)[1] - 2 * c.verticalPadding;
var unitLocation = d.unitToPaddedPx.invert(y);
var b = d.brush;
var interval = getInterval(d, y);
var unitRange = interval.interval;
var s = b.svgBrush;
s.wasDragged = false; // we start assuming there won't be a drag - useful for reset
s.grabbingBar = interval.region === 'ns';
if (s.grabbingBar) {
var pixelRange = unitRange.map(d.unitToPaddedPx);
s.grabPoint = y - pixelRange[0] - c.verticalPadding;
s.barLength = pixelRange[1] - pixelRange[0];
}
s.clickableOrdinalRange = interval.clickableOrdinalRange;
s.stayingIntervals = d.multiselect && b.filterSpecified ? b.filter.getConsolidated() : [];
if (unitRange) {
s.stayingIntervals = s.stayingIntervals.filter(function (int2) {
return int2[0] !== unitRange[0] && int2[1] !== unitRange[1];
});
}
s.startExtent = interval.region ? unitRange[interval.region === 's' ? 1 : 0] : unitLocation;
d.parent.inBrushDrag = true;
s.brushStartCallback();
}
function drag(lThis, d) {
d3.event.sourceEvent.stopPropagation();
var y = d.height - d3.mouse(lThis)[1] - 2 * c.verticalPadding;
var s = d.brush.svgBrush;
s.wasDragged = true;
s._dragging = true;
if (s.grabbingBar) {
// moving the bar
s.newExtent = [y - s.grabPoint, y + s.barLength - s.grabPoint].map(d.unitToPaddedPx.invert);
} else {
// south/north drag or new bar creation
s.newExtent = [s.startExtent, d.unitToPaddedPx.invert(y)].sort(sortAsc);
}
d.brush.filterSpecified = true;
s.extent = s.stayingIntervals.concat([s.newExtent]);
s.brushCallback(d);
renderHighlight(lThis.parentNode);
}
function dragend(lThis, d) {
var brush = d.brush;
var filter = brush.filter;
var s = brush.svgBrush;
if (!s._dragging) {
// i.e. click
// mock zero drag
mousemove(lThis, d);
drag(lThis, d);
// remember it is a click not a drag
d.brush.svgBrush.wasDragged = false;
}
s._dragging = false;
var e = d3.event;
e.sourceEvent.stopPropagation();
var grabbingBar = s.grabbingBar;
s.grabbingBar = false;
s.grabLocation = undefined;
d.parent.inBrushDrag = false;
clearCursor(); // instead of clearing, a nicer thing would be to set it according to current location
if (!s.wasDragged) {
// a click+release on the same spot (ie. w/o dragging) means a bar or full reset
s.wasDragged = undefined; // logic-wise unneeded, just shows `wasDragged` has no longer a meaning
if (s.clickableOrdinalRange) {
if (brush.filterSpecified && d.multiselect) {
s.extent.push(s.clickableOrdinalRange);
} else {
s.extent = [s.clickableOrdinalRange];
brush.filterSpecified = true;
}
} else if (grabbingBar) {
s.extent = s.stayingIntervals;
if (s.extent.length === 0) {
brushClear(brush);
}
} else {
brushClear(brush);
}
s.brushCallback(d);
renderHighlight(lThis.parentNode);
s.brushEndCallback(brush.filterSpecified ? filter.getConsolidated() : []);
return; // no need to fuse intervals or snap to ordinals, so we can bail early
}
var mergeIntervals = function () {
// Key piece of logic: once the button is released, possibly overlapping intervals will be fused:
// Here it's done immediately on click release while on ordinal snap transition it's done at the end
filter.set(filter.getConsolidated());
};
if (d.ordinal) {
var a = d.unitTickvals;
if (a[a.length - 1] < a[0]) a.reverse();
s.newExtent = [ordinalScaleSnap(0, a, s.newExtent[0], s.stayingIntervals), ordinalScaleSnap(1, a, s.newExtent[1], s.stayingIntervals)];
var hasNewExtent = s.newExtent[1] > s.newExtent[0];
s.extent = s.stayingIntervals.concat(hasNewExtent ? [s.newExtent] : []);
if (!s.extent.length) {
brushClear(brush);
}
s.brushCallback(d);
if (hasNewExtent) {
// merging intervals post the snap tween
renderHighlight(lThis.parentNode, mergeIntervals);
} else {
// if no new interval, don't animate, just redraw the highlight immediately
mergeIntervals();
renderHighlight(lThis.parentNode);
}
} else {
mergeIntervals(); // merging intervals immediately
}
s.brushEndCallback(brush.filterSpecified ? filter.getConsolidated() : []);
}
function mousemove(lThis, d) {
var y = d.height - d3.mouse(lThis)[1] - 2 * c.verticalPadding;
var interval = getInterval(d, y);
var cursor = 'crosshair';
if (interval.clickableOrdinalRange) cursor = 'pointer';else if (interval.region) cursor = interval.region + '-resize';
d3.select(document.body).style('cursor', cursor);
}
function attachDragBehavior(selection) {
// There's some fiddling with pointer cursor styling so that the cursor preserves its shape while dragging a brush
// even if the cursor strays from the interacting bar, which is bound to happen as bars are thin and the user
// will inevitably leave the hotspot strip. In this regard, it does something similar to what the D3 brush would do.
selection.on('mousemove', function (d) {
d3.event.preventDefault();
if (!d.parent.inBrushDrag) mousemove(this, d);
}).on('mouseleave', function (d) {
if (!d.parent.inBrushDrag) clearCursor();
}).call(d3.behavior.drag().on('dragstart', function (d) {
dragstart(this, d);
}).on('drag', function (d) {
drag(this, d);
}).on('dragend', function (d) {
dragend(this, d);
}));
}
function startAsc(a, b) {
return a[0] - b[0];
}
function renderAxisBrush(axisBrush, paperColor, gd) {
var isStatic = gd._context.staticPlot;
var background = axisBrush.selectAll('.background').data(repeat);
background.enter().append('rect').classed('background', true).call(barHorizontalSetup).call(backgroundBarHorizontalSetup).style('pointer-events', isStatic ? 'none' : 'auto') // parent pointer events are disabled; we must have it to register events
.attr('transform', strTranslate(0, c.verticalPadding));
background.call(attachDragBehavior).attr('height', function (d) {
return d.height - c.verticalPadding;
});
var highlightShadow = axisBrush.selectAll('.highlight-shadow').data(repeat); // we have a set here, can't call it `extent`
highlightShadow.enter().append('line').classed('highlight-shadow', true).attr('x', -c.bar.width / 2).attr('stroke-width', c.bar.width + c.bar.strokeWidth).attr('stroke', paperColor).attr('opacity', c.bar.strokeOpacity).attr('stroke-linecap', 'butt');
highlightShadow.attr('y1', function (d) {
return d.height;
}).call(styleHighlight);
var highlight = axisBrush.selectAll('.highlight').data(repeat); // we have a set here, can't call it `extent`
highlight.enter().append('line').classed('highlight', true).attr('x', -c.bar.width / 2).attr('stroke-width', c.bar.width - c.bar.strokeWidth).attr('stroke', c.bar.fillColor).attr('opacity', c.bar.fillOpacity).attr('stroke-linecap', 'butt');
highlight.attr('y1', function (d) {
return d.height;
}).call(styleHighlight);
}
function ensureAxisBrush(axisOverlays, paperColor, gd) {
var axisBrush = axisOverlays.selectAll('.' + c.cn.axisBrush).data(repeat, keyFun);
axisBrush.enter().append('g').classed(c.cn.axisBrush, true);
renderAxisBrush(axisBrush, paperColor, gd);
}
function getBrushExtent(brush) {
return brush.svgBrush.extent.map(function (e) {
return e.slice();
});
}
function brushClear(brush) {
brush.filterSpecified = false;
brush.svgBrush.extent = [[-Infinity, Infinity]];
}
function axisBrushMoved(callback) {
return function axisBrushMoved(dimension) {
var brush = dimension.brush;
var extent = getBrushExtent(brush);
var newExtent = extent.slice();
brush.filter.set(newExtent);
callback();
};
}
function dedupeRealRanges(intervals) {
// Fuses elements of intervals if they overlap, yielding discontiguous intervals, results.length <= intervals.length
// Currently uses closed intervals, ie. dedupeRealRanges([[400, 800], [300, 400]]) -> [300, 800]
var queue = intervals.slice();
var result = [];
var currentInterval;
var current = queue.shift();
while (current) {
// [].shift === undefined, so we don't descend into an empty array
currentInterval = current.slice();
while ((current = queue.shift()) && current[0] <= /* right-open interval would need `<` */currentInterval[1]) {
currentInterval[1] = Math.max(currentInterval[1], current[1]);
}
result.push(currentInterval);
}
if (result.length === 1 && result[0][0] > result[0][1]) {
// discard result
result = [];
}
return result;
}
function makeFilter() {
var filter = [];
var consolidated;
var bounds;
return {
set: function (a) {
filter = a.map(function (d) {
return d.slice().sort(sortAsc);
}).sort(startAsc);
// handle unselected case
if (filter.length === 1 && filter[0][0] === -Infinity && filter[0][1] === Infinity) {
filter = [[0, -1]];
}
consolidated = dedupeRealRanges(filter);
bounds = filter.reduce(function (p, n) {
return [Math.min(p[0], n[0]), Math.max(p[1], n[1])];
}, [Infinity, -Infinity]);
},
get: function () {
return filter.slice();
},
getConsolidated: function () {
return consolidated;
},
getBounds: function () {
return bounds;
}
};
}
function makeBrush(state, rangeSpecified, initialRange, brushStartCallback, brushCallback, brushEndCallback) {
var filter = makeFilter();
filter.set(initialRange);
return {
filter: filter,
filterSpecified: rangeSpecified,
// there's a difference between not filtering and filtering a non-proper subset
svgBrush: {
extent: [],
// this is where the svgBrush writes contents into
brushStartCallback: brushStartCallback,
brushCallback: axisBrushMoved(brushCallback),
brushEndCallback: brushEndCallback
}
};
}
// for use by supplyDefaults, but it needed tons of pieces from here so
// seemed to make more sense just to put the whole routine here
function cleanRanges(ranges, dimension) {
if (Array.isArray(ranges[0])) {
ranges = ranges.map(function (ri) {
return ri.sort(sortAsc);
});
if (!dimension.multiselect) ranges = [ranges[0]];else ranges = dedupeRealRanges(ranges.sort(startAsc));
} else ranges = [ranges.sort(sortAsc)];
// ordinal snapping
if (dimension.tickvals) {
var sortedTickVals = dimension.tickvals.slice().sort(sortAsc);
ranges = ranges.map(function (ri) {
var rSnapped = [ordinalScaleSnap(0, sortedTickVals, ri[0], []), ordinalScaleSnap(1, sortedTickVals, ri[1], [])];
if (rSnapped[1] > rSnapped[0]) return rSnapped;
}).filter(function (ri) {
return ri;
});
if (!ranges.length) return;
}
return ranges.length > 1 ? ranges : ranges[0];
}
module.exports = {
makeBrush: makeBrush,
ensureAxisBrush: ensureAxisBrush,
cleanRanges: cleanRanges
};
/***/ }),
/***/ 44048:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(99584),
supplyDefaults: __webpack_require__(77708),
calc: __webpack_require__(65789),
colorbar: {
container: 'line',
min: 'cmin',
max: 'cmax'
},
moduleType: 'trace',
name: 'parcoords',
basePlotModule: __webpack_require__(27120),
categories: ['gl', 'regl', 'noOpacity', 'noHover'],
meta: {
description: ['Parallel coordinates for multidimensional exploratory data analysis.', 'The samples are specified in `dimensions`.', 'The colors are set in `line.color`.'].join(' ')
}
};
/***/ }),
/***/ 27120:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var getModuleCalcData = (__webpack_require__(49824)/* .getModuleCalcData */ ._M);
var parcoordsPlot = __webpack_require__(87572);
var xmlnsNamespaces = __webpack_require__(51608);
exports.name = 'parcoords';
exports.plot = function (gd) {
var calcData = getModuleCalcData(gd.calcdata, 'parcoords')[0];
if (calcData.length) parcoordsPlot(gd, calcData);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
var hadParcoords = oldFullLayout._has && oldFullLayout._has('parcoords');
var hasParcoords = newFullLayout._has && newFullLayout._has('parcoords');
if (hadParcoords && !hasParcoords) {
oldFullLayout._paperdiv.selectAll('.parcoords').remove();
oldFullLayout._glimages.selectAll('*').remove();
}
};
exports.toSVG = function (gd) {
var imageRoot = gd._fullLayout._glimages;
var root = d3.select(gd).selectAll('.svg-container');
var canvases = root.filter(function (d, i) {
return i === root.size() - 1;
}).selectAll('.gl-canvas-context, .gl-canvas-focus');
function canvasToImage() {
var canvas = this;
var imageData = canvas.toDataURL('image/png');
var image = imageRoot.append('svg:image');
image.attr({
xmlns: xmlnsNamespaces.svg,
'xlink:href': imageData,
preserveAspectRatio: 'none',
x: 0,
y: 0,
width: canvas.style.width,
height: canvas.style.height
});
}
canvases.each(canvasToImage);
// Chrome / Safari bug workaround - browser apparently loses connection to the defined pattern
// Without the workaround, these browsers 'lose' the filter brush styling (color etc.) after a snapshot
// on a subsequent interaction.
// Firefox works fine without this workaround
window.setTimeout(function () {
d3.selectAll('#filterBarPattern').attr('id', 'filterBarPattern');
}, 60);
};
/***/ }),
/***/ 65789:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var Colorscale = __webpack_require__(26733);
var wrap = (__webpack_require__(83104).wrap);
module.exports = function calc(gd, trace) {
var lineColor;
var cscale;
if (Colorscale.hasColorscale(trace, 'line') && isArrayOrTypedArray(trace.line.color)) {
lineColor = trace.line.color;
cscale = Colorscale.extractOpts(trace.line).colorscale;
Colorscale.calc(gd, trace, {
vals: lineColor,
containerStr: 'line',
cLetter: 'c'
});
} else {
lineColor = constHalf(trace._length);
cscale = [[0, trace.line.color], [1, trace.line.color]];
}
return wrap({
lineColor: lineColor,
cscale: cscale
});
};
function constHalf(len) {
var out = new Array(len);
for (var i = 0; i < len; i++) {
out[i] = 0.5;
}
return out;
}
/***/ }),
/***/ 92304:
/***/ (function(module) {
"use strict";
module.exports = {
maxDimensionCount: 60,
// this cannot be increased without WebGL code refactoring
overdrag: 45,
verticalPadding: 2,
// otherwise, horizontal lines on top or bottom are of lower width
tickDistance: 50,
canvasPixelRatio: 1,
blockLineCount: 5000,
layers: ['contextLineLayer', 'focusLineLayer', 'pickLineLayer'],
axisTitleOffset: 28,
axisExtentOffset: 10,
bar: {
width: 4,
// Visible width of the filter bar
captureWidth: 10,
// Mouse-sensitive width for interaction (Fitts law)
fillColor: 'magenta',
// Color of the filter bar fill
fillOpacity: 1,
// Filter bar fill opacity
snapDuration: 150,
// tween duration in ms for brush snap for ordinal axes
snapRatio: 0.25,
// ratio of bar extension relative to the distance between two adjacent ordinal values
snapClose: 0.01,
// fraction of inter-value distance to snap to the closer one, even if you're not over it
strokeOpacity: 1,
// Filter bar side stroke opacity
strokeWidth: 1,
// Filter bar side stroke width in pixels
handleHeight: 8,
// Height of the filter bar vertical resize areas on top and bottom
handleOpacity: 1,
// Opacity of the filter bar vertical resize areas on top and bottom
handleOverlap: 0 // A larger than 0 value causes overlaps with the filter bar, represented as pixels
},
cn: {
axisExtentText: 'axis-extent-text',
parcoordsLineLayers: 'parcoords-line-layers',
parcoordsLineLayer: 'parcoords-lines',
parcoords: 'parcoords',
parcoordsControlView: 'parcoords-control-view',
yAxis: 'y-axis',
axisOverlays: 'axis-overlays',
axis: 'axis',
axisHeading: 'axis-heading',
axisTitle: 'axis-title',
axisExtent: 'axis-extent',
axisExtentTop: 'axis-extent-top',
axisExtentTopText: 'axis-extent-top-text',
axisExtentBottom: 'axis-extent-bottom',
axisExtentBottomText: 'axis-extent-bottom-text',
axisBrush: 'axis-brush'
},
id: {
filterBarPattern: 'filter-bar-pattern'
}
};
/***/ }),
/***/ 77708:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var colorscaleDefaults = __webpack_require__(47280);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var handleArrayContainerDefaults = __webpack_require__(95631);
var Axes = __webpack_require__(81536);
var attributes = __webpack_require__(99584);
var axisBrush = __webpack_require__(54376);
var maxDimensionCount = (__webpack_require__(92304).maxDimensionCount);
var mergeLength = __webpack_require__(97048);
function handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce) {
var lineColor = coerce('line.color', defaultColor);
if (hasColorscale(traceIn, 'line') && Lib.isArrayOrTypedArray(lineColor)) {
if (lineColor.length) {
coerce('line.colorscale');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'line.',
cLetter: 'c'
});
// TODO: I think it would be better to keep showing lines beyond the last line color
// but I'm not sure what color to give these lines - probably black or white
// depending on the background color?
return lineColor.length;
} else {
traceOut.line.color = defaultColor;
}
}
return Infinity;
}
function dimensionDefaults(dimensionIn, dimensionOut, parentOut, opts) {
function coerce(attr, dflt) {
return Lib.coerce(dimensionIn, dimensionOut, attributes.dimensions, attr, dflt);
}
var values = coerce('values');
var visible = coerce('visible');
if (!(values && values.length)) {
visible = dimensionOut.visible = false;
}
if (visible) {
coerce('label');
coerce('tickvals');
coerce('ticktext');
coerce('tickformat');
var range = coerce('range');
dimensionOut._ax = {
_id: 'y',
type: 'linear',
showexponent: 'all',
exponentformat: 'B',
range: range
};
Axes.setConvert(dimensionOut._ax, opts.layout);
coerce('multiselect');
var constraintRange = coerce('constraintrange');
if (constraintRange) {
dimensionOut.constraintrange = axisBrush.cleanRanges(constraintRange, dimensionOut);
}
}
}
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var dimensionsIn = traceIn.dimensions;
if (Array.isArray(dimensionsIn) && dimensionsIn.length > maxDimensionCount) {
Lib.log('parcoords traces support up to ' + maxDimensionCount + ' dimensions at the moment');
dimensionsIn.splice(maxDimensionCount);
}
var dimensions = handleArrayContainerDefaults(traceIn, traceOut, {
name: 'dimensions',
layout: layout,
handleItemDefaults: dimensionDefaults
});
var len = handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
handleDomainDefaults(traceOut, layout, coerce);
if (!Array.isArray(dimensions) || !dimensions.length) {
traceOut.visible = false;
}
mergeLength(traceOut, dimensions, 'values', len);
// make default font size 10px (default is 12),
// scale linearly with global font size
var fontDflt = {
family: layout.font.family,
size: Math.round(layout.font.size / 1.2),
color: layout.font.color
};
Lib.coerceFont(coerce, 'labelfont', fontDflt);
Lib.coerceFont(coerce, 'tickfont', fontDflt);
Lib.coerceFont(coerce, 'rangefont', fontDflt);
coerce('labelangle');
coerce('labelside');
coerce('unselected.line.color');
coerce('unselected.line.opacity');
};
/***/ }),
/***/ 30808:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var isTypedArray = (__webpack_require__(10923).isTypedArray);
exports.convertTypedArray = function (a) {
return isTypedArray(a) ? Array.prototype.slice.call(a) : a;
};
exports.isOrdinal = function (dimension) {
return !!dimension.tickvals;
};
exports.isVisible = function (dimension) {
return dimension.visible || !('visible' in dimension);
};
/***/ }),
/***/ 8837:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var index = __webpack_require__(44048);
index.plot = __webpack_require__(87572);
module.exports = index;
/***/ }),
/***/ 49000:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var vertexShaderSource = ['precision highp float;', '', 'varying vec4 fragColor;', '', 'attribute vec4 p01_04, p05_08, p09_12, p13_16,', ' p17_20, p21_24, p25_28, p29_32,', ' p33_36, p37_40, p41_44, p45_48,', ' p49_52, p53_56, p57_60, colors;', '', 'uniform mat4 dim0A, dim1A, dim0B, dim1B, dim0C, dim1C, dim0D, dim1D,', ' loA, hiA, loB, hiB, loC, hiC, loD, hiD;', '', 'uniform vec2 resolution, viewBoxPos, viewBoxSize;', 'uniform float maskHeight;', 'uniform float drwLayer; // 0: context, 1: focus, 2: pick', 'uniform vec4 contextColor;', 'uniform sampler2D maskTexture, palette;', '', 'bool isPick = (drwLayer > 1.5);', 'bool isContext = (drwLayer < 0.5);', '', 'const vec4 ZEROS = vec4(0.0, 0.0, 0.0, 0.0);', 'const vec4 UNITS = vec4(1.0, 1.0, 1.0, 1.0);', '', 'float val(mat4 p, mat4 v) {', ' return dot(matrixCompMult(p, v) * UNITS, UNITS);', '}', '', 'float axisY(float ratio, mat4 A, mat4 B, mat4 C, mat4 D) {', ' float y1 = val(A, dim0A) + val(B, dim0B) + val(C, dim0C) + val(D, dim0D);', ' float y2 = val(A, dim1A) + val(B, dim1B) + val(C, dim1C) + val(D, dim1D);', ' return y1 * (1.0 - ratio) + y2 * ratio;', '}', '', 'int iMod(int a, int b) {', ' return a - b * (a / b);', '}', '', 'bool fOutside(float p, float lo, float hi) {', ' return (lo < hi) && (lo > p || p > hi);', '}', '', 'bool vOutside(vec4 p, vec4 lo, vec4 hi) {', ' return (', ' fOutside(p[0], lo[0], hi[0]) ||', ' fOutside(p[1], lo[1], hi[1]) ||', ' fOutside(p[2], lo[2], hi[2]) ||', ' fOutside(p[3], lo[3], hi[3])', ' );', '}', '', 'bool mOutside(mat4 p, mat4 lo, mat4 hi) {', ' return (', ' vOutside(p[0], lo[0], hi[0]) ||', ' vOutside(p[1], lo[1], hi[1]) ||', ' vOutside(p[2], lo[2], hi[2]) ||', ' vOutside(p[3], lo[3], hi[3])', ' );', '}', '', 'bool outsideBoundingBox(mat4 A, mat4 B, mat4 C, mat4 D) {', ' return mOutside(A, loA, hiA) ||', ' mOutside(B, loB, hiB) ||', ' mOutside(C, loC, hiC) ||', ' mOutside(D, loD, hiD);', '}', '', 'bool outsideRasterMask(mat4 A, mat4 B, mat4 C, mat4 D) {', ' mat4 pnts[4];', ' pnts[0] = A;', ' pnts[1] = B;', ' pnts[2] = C;', ' pnts[3] = D;', '', ' for(int i = 0; i < 4; ++i) {', ' for(int j = 0; j < 4; ++j) {', ' for(int k = 0; k < 4; ++k) {', ' if(0 == iMod(', ' int(255.0 * texture2D(maskTexture,', ' vec2(', ' (float(i * 2 + j / 2) + 0.5) / 8.0,', ' (pnts[i][j][k] * (maskHeight - 1.0) + 1.0) / maskHeight', ' ))[3]', ' ) / int(pow(2.0, float(iMod(j * 4 + k, 8)))),', ' 2', ' )) return true;', ' }', ' }', ' }', ' return false;', '}', '', 'vec4 position(bool isContext, float v, mat4 A, mat4 B, mat4 C, mat4 D) {', ' float x = 0.5 * sign(v) + 0.5;', ' float y = axisY(x, A, B, C, D);', ' float z = 1.0 - abs(v);', '', ' z += isContext ? 0.0 : 2.0 * float(', ' outsideBoundingBox(A, B, C, D) ||', ' outsideRasterMask(A, B, C, D)', ' );', '', ' return vec4(', ' 2.0 * (vec2(x, y) * viewBoxSize + viewBoxPos) / resolution - 1.0,', ' z,', ' 1.0', ' );', '}', '', 'void main() {', ' mat4 A = mat4(p01_04, p05_08, p09_12, p13_16);', ' mat4 B = mat4(p17_20, p21_24, p25_28, p29_32);', ' mat4 C = mat4(p33_36, p37_40, p41_44, p45_48);', ' mat4 D = mat4(p49_52, p53_56, p57_60, ZEROS);', '', ' float v = colors[3];', '', ' gl_Position = position(isContext, v, A, B, C, D);', '', ' fragColor =', ' isContext ? vec4(contextColor) :', ' isPick ? vec4(colors.rgb, 1.0) : texture2D(palette, vec2(abs(v), 0.5));', '}'].join('\n');
var fragmentShaderSource = ['precision highp float;', '', 'varying vec4 fragColor;', '', 'void main() {', ' gl_FragColor = fragColor;', '}'].join('\n');
var maxDim = (__webpack_require__(92304).maxDimensionCount);
var Lib = __webpack_require__(10923);
// don't change; otherwise near/far plane lines are lost
var depthLimitEpsilon = 1e-6;
// precision of multiselect is the full range divided into this many parts
var maskHeight = 2048;
var dummyPixel = new Uint8Array(4);
var dataPixel = new Uint8Array(4);
var paletteTextureConfig = {
shape: [256, 1],
format: 'rgba',
type: 'uint8',
mag: 'nearest',
min: 'nearest'
};
function ensureDraw(regl) {
regl.read({
x: 0,
y: 0,
width: 1,
height: 1,
data: dummyPixel
});
}
function clear(regl, x, y, width, height) {
var gl = regl._gl;
gl.enable(gl.SCISSOR_TEST);
gl.scissor(x, y, width, height);
regl.clear({
color: [0, 0, 0, 0],
depth: 1
}); // clearing is done in scissored panel only
}
function renderBlock(regl, glAes, renderState, blockLineCount, sampleCount, item) {
var rafKey = item.key;
function render(blockNumber) {
var count = Math.min(blockLineCount, sampleCount - blockNumber * blockLineCount);
if (blockNumber === 0) {
// stop drawing possibly stale glyphs before clearing
window.cancelAnimationFrame(renderState.currentRafs[rafKey]);
delete renderState.currentRafs[rafKey];
clear(regl, item.scissorX, item.scissorY, item.scissorWidth, item.viewBoxSize[1]);
}
if (renderState.clearOnly) {
return;
}
item.count = 2 * count;
item.offset = 2 * blockNumber * blockLineCount;
glAes(item);
if (blockNumber * blockLineCount + count < sampleCount) {
renderState.currentRafs[rafKey] = window.requestAnimationFrame(function () {
render(blockNumber + 1);
});
}
renderState.drawCompleted = false;
}
if (!renderState.drawCompleted) {
ensureDraw(regl);
renderState.drawCompleted = true;
}
// start with rendering item 0; recursion handles the rest
render(0);
}
function adjustDepth(d) {
// WebGL matrix operations use floats with limited precision, potentially causing a number near a border of [0, 1]
// to end up slightly outside the border. With an epsilon, we reduce the chance that a line gets clipped by the
// near or the far plane.
return Math.max(depthLimitEpsilon, Math.min(1 - depthLimitEpsilon, d));
}
function palette(unitToColor, opacity) {
var result = new Array(256);
for (var i = 0; i < 256; i++) {
result[i] = unitToColor(i / 255).concat(opacity);
}
return result;
}
// Maps the sample index [0...sampleCount - 1] to a range of [0, 1] as the shader expects colors in the [0, 1] range.
// but first it shifts the sample index by 0, 8 or 16 bits depending on rgbIndex [0..2]
// with the end result that each line will be of a unique color, making it possible for the pick handler
// to uniquely identify which line is hovered over (bijective mapping).
// The inverse, i.e. readPixel is invoked from 'parcoords.js'
function calcPickColor(i, rgbIndex) {
return (i >>> 8 * rgbIndex) % 256 / 255;
}
function makePoints(sampleCount, dims, color) {
var points = new Array(sampleCount * (maxDim + 4));
var n = 0;
for (var i = 0; i < sampleCount; i++) {
for (var k = 0; k < maxDim; k++) {
points[n++] = k < dims.length ? dims[k].paddedUnitValues[i] : 0.5;
}
points[n++] = calcPickColor(i, 2);
points[n++] = calcPickColor(i, 1);
points[n++] = calcPickColor(i, 0);
points[n++] = adjustDepth(color[i]);
}
return points;
}
function makeVecAttr(vecIndex, sampleCount, points) {
var pointPairs = new Array(sampleCount * 8);
var n = 0;
for (var i = 0; i < sampleCount; i++) {
for (var j = 0; j < 2; j++) {
for (var k = 0; k < 4; k++) {
var q = vecIndex * 4 + k;
var v = points[i * 64 + q];
if (q === 63 && j === 0) {
v *= -1;
}
pointPairs[n++] = v;
}
}
}
return pointPairs;
}
function pad2(num) {
var s = '0' + num;
return s.substr(s.length - 2);
}
function getAttrName(i) {
return i < maxDim ? 'p' + pad2(i + 1) + '_' + pad2(i + 4) : 'colors';
}
function setAttributes(attributes, sampleCount, points) {
for (var i = 0; i <= maxDim; i += 4) {
attributes[getAttrName(i)](makeVecAttr(i / 4, sampleCount, points));
}
}
function emptyAttributes(regl) {
var attributes = {};
for (var i = 0; i <= maxDim; i += 4) {
attributes[getAttrName(i)] = regl.buffer({
usage: 'dynamic',
type: 'float',
data: new Uint8Array(0)
});
}
return attributes;
}
function makeItem(model, leftmost, rightmost, itemNumber, i0, i1, x, y, panelSizeX, panelSizeY, crossfilterDimensionIndex, drwLayer, constraints, plotGlPixelRatio) {
var dims = [[], []];
for (var k = 0; k < 64; k++) {
dims[0][k] = k === i0 ? 1 : 0;
dims[1][k] = k === i1 ? 1 : 0;
}
x *= plotGlPixelRatio;
y *= plotGlPixelRatio;
panelSizeX *= plotGlPixelRatio;
panelSizeY *= plotGlPixelRatio;
var overdrag = model.lines.canvasOverdrag * plotGlPixelRatio;
var domain = model.domain;
var canvasWidth = model.canvasWidth * plotGlPixelRatio;
var canvasHeight = model.canvasHeight * plotGlPixelRatio;
var padL = model.pad.l * plotGlPixelRatio;
var padB = model.pad.b * plotGlPixelRatio;
var layoutHeight = model.layoutHeight * plotGlPixelRatio;
var layoutWidth = model.layoutWidth * plotGlPixelRatio;
var deselectedLinesColor = model.deselectedLines.color;
var deselectedLinesOpacity = model.deselectedLines.opacity;
var itemModel = Lib.extendFlat({
key: crossfilterDimensionIndex,
resolution: [canvasWidth, canvasHeight],
viewBoxPos: [x + overdrag, y],
viewBoxSize: [panelSizeX, panelSizeY],
i0: i0,
i1: i1,
dim0A: dims[0].slice(0, 16),
dim0B: dims[0].slice(16, 32),
dim0C: dims[0].slice(32, 48),
dim0D: dims[0].slice(48, 64),
dim1A: dims[1].slice(0, 16),
dim1B: dims[1].slice(16, 32),
dim1C: dims[1].slice(32, 48),
dim1D: dims[1].slice(48, 64),
drwLayer: drwLayer,
contextColor: [deselectedLinesColor[0] / 255, deselectedLinesColor[1] / 255, deselectedLinesColor[2] / 255, deselectedLinesOpacity !== 'auto' ? deselectedLinesColor[3] * deselectedLinesOpacity : Math.max(1 / 255, Math.pow(1 / model.lines.color.length, 1 / 3))],
scissorX: (itemNumber === leftmost ? 0 : x + overdrag) + (padL - overdrag) + layoutWidth * domain.x[0],
scissorWidth: (itemNumber === rightmost ? canvasWidth - x + overdrag : panelSizeX + 0.5) + (itemNumber === leftmost ? x + overdrag : 0),
scissorY: y + padB + layoutHeight * domain.y[0],
scissorHeight: panelSizeY,
viewportX: padL - overdrag + layoutWidth * domain.x[0],
viewportY: padB + layoutHeight * domain.y[0],
viewportWidth: canvasWidth,
viewportHeight: canvasHeight
}, constraints);
return itemModel;
}
function expandedPixelRange(bounds) {
var dh = maskHeight - 1;
var a = Math.max(0, Math.floor(bounds[0] * dh), 0);
var b = Math.min(dh, Math.ceil(bounds[1] * dh), dh);
return [Math.min(a, b), Math.max(a, b)];
}
module.exports = function (canvasGL, d) {
// context & pick describe which canvas we're talking about - won't change with new data
var isContext = d.context;
var isPick = d.pick;
var regl = d.regl;
var gl = regl._gl;
var supportedLineWidth = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE);
// ensure here that plotGlPixelRatio is within supported range; otherwise regl throws error
var plotGlPixelRatio = Math.max(supportedLineWidth[0], Math.min(supportedLineWidth[1], d.viewModel.plotGlPixelRatio));
var renderState = {
currentRafs: {},
drawCompleted: true,
clearOnly: false
};
// state to be set by update and used later
var model;
var vm;
var initialDims;
var sampleCount;
var attributes = emptyAttributes(regl);
var maskTexture;
var paletteTexture = regl.texture(paletteTextureConfig);
var prevAxisOrder = [];
update(d);
var glAes = regl({
profile: false,
blend: {
enable: isContext,
func: {
srcRGB: 'src alpha',
dstRGB: 'one minus src alpha',
srcAlpha: 1,
dstAlpha: 1 // 'one minus src alpha'
},
equation: {
rgb: 'add',
alpha: 'add'
},
color: [0, 0, 0, 0]
},
depth: {
enable: !isContext,
mask: true,
func: 'less',
range: [0, 1]
},
// for polygons
cull: {
enable: true,
face: 'back'
},
scissor: {
enable: true,
box: {
x: regl.prop('scissorX'),
y: regl.prop('scissorY'),
width: regl.prop('scissorWidth'),
height: regl.prop('scissorHeight')
}
},
viewport: {
x: regl.prop('viewportX'),
y: regl.prop('viewportY'),
width: regl.prop('viewportWidth'),
height: regl.prop('viewportHeight')
},
dither: false,
vert: vertexShaderSource,
frag: fragmentShaderSource,
primitive: 'lines',
lineWidth: plotGlPixelRatio,
attributes: attributes,
uniforms: {
resolution: regl.prop('resolution'),
viewBoxPos: regl.prop('viewBoxPos'),
viewBoxSize: regl.prop('viewBoxSize'),
dim0A: regl.prop('dim0A'),
dim1A: regl.prop('dim1A'),
dim0B: regl.prop('dim0B'),
dim1B: regl.prop('dim1B'),
dim0C: regl.prop('dim0C'),
dim1C: regl.prop('dim1C'),
dim0D: regl.prop('dim0D'),
dim1D: regl.prop('dim1D'),
loA: regl.prop('loA'),
hiA: regl.prop('hiA'),
loB: regl.prop('loB'),
hiB: regl.prop('hiB'),
loC: regl.prop('loC'),
hiC: regl.prop('hiC'),
loD: regl.prop('loD'),
hiD: regl.prop('hiD'),
palette: paletteTexture,
contextColor: regl.prop('contextColor'),
maskTexture: regl.prop('maskTexture'),
drwLayer: regl.prop('drwLayer'),
maskHeight: regl.prop('maskHeight')
},
offset: regl.prop('offset'),
count: regl.prop('count')
});
function update(dNew) {
model = dNew.model;
vm = dNew.viewModel;
initialDims = vm.dimensions.slice();
sampleCount = initialDims[0] ? initialDims[0].values.length : 0;
var lines = model.lines;
var color = isPick ? lines.color.map(function (_, i) {
return i / lines.color.length;
}) : lines.color;
var points = makePoints(sampleCount, initialDims, color);
setAttributes(attributes, sampleCount, points);
if (!isContext && !isPick) {
paletteTexture = regl.texture(Lib.extendFlat({
data: palette(model.unitToColor, 255)
}, paletteTextureConfig));
}
}
function makeConstraints(isContext) {
var i, j, k;
var limits = [[], []];
for (k = 0; k < 64; k++) {
var p = !isContext && k < initialDims.length ? initialDims[k].brush.filter.getBounds() : [-Infinity, Infinity];
limits[0][k] = p[0];
limits[1][k] = p[1];
}
var len = maskHeight * 8;
var mask = new Array(len);
for (i = 0; i < len; i++) {
mask[i] = 255;
}
if (!isContext) {
for (i = 0; i < initialDims.length; i++) {
var u = i % 8;
var v = (i - u) / 8;
var bitMask = Math.pow(2, u);
var dim = initialDims[i];
var ranges = dim.brush.filter.get();
if (ranges.length < 2) continue; // bail if the bounding box based filter is sufficient
var prevEnd = expandedPixelRange(ranges[0])[1];
for (j = 1; j < ranges.length; j++) {
var nextRange = expandedPixelRange(ranges[j]);
for (k = prevEnd + 1; k < nextRange[0]; k++) {
mask[k * 8 + v] &= ~bitMask;
}
prevEnd = Math.max(prevEnd, nextRange[1]);
}
}
}
var textureData = {
// 8 units x 8 bits = 64 bits, just sufficient for the almost 64 dimensions we support
shape: [8, maskHeight],
format: 'alpha',
type: 'uint8',
mag: 'nearest',
min: 'nearest',
data: mask
};
if (maskTexture) maskTexture(textureData);else maskTexture = regl.texture(textureData);
return {
maskTexture: maskTexture,
maskHeight: maskHeight,
loA: limits[0].slice(0, 16),
loB: limits[0].slice(16, 32),
loC: limits[0].slice(32, 48),
loD: limits[0].slice(48, 64),
hiA: limits[1].slice(0, 16),
hiB: limits[1].slice(16, 32),
hiC: limits[1].slice(32, 48),
hiD: limits[1].slice(48, 64)
};
}
function renderGLParcoords(panels, setChanged, clearOnly) {
var panelCount = panels.length;
var i;
var leftmost;
var rightmost;
var lowestX = Infinity;
var highestX = -Infinity;
for (i = 0; i < panelCount; i++) {
if (panels[i].dim0.canvasX < lowestX) {
lowestX = panels[i].dim0.canvasX;
leftmost = i;
}
if (panels[i].dim1.canvasX > highestX) {
highestX = panels[i].dim1.canvasX;
rightmost = i;
}
}
if (panelCount === 0) {
// clear canvas here, as the panel iteration below will not enter the loop body
clear(regl, 0, 0, model.canvasWidth, model.canvasHeight);
}
var constraints = makeConstraints(isContext);
for (i = 0; i < panelCount; i++) {
var p = panels[i];
var i0 = p.dim0.crossfilterDimensionIndex;
var i1 = p.dim1.crossfilterDimensionIndex;
var x = p.canvasX;
var y = p.canvasY;
var nextX = x + p.panelSizeX;
var plotGlPixelRatio = p.plotGlPixelRatio;
if (setChanged || !prevAxisOrder[i0] || prevAxisOrder[i0][0] !== x || prevAxisOrder[i0][1] !== nextX) {
prevAxisOrder[i0] = [x, nextX];
var item = makeItem(model, leftmost, rightmost, i, i0, i1, x, y, p.panelSizeX, p.panelSizeY, p.dim0.crossfilterDimensionIndex, isContext ? 0 : isPick ? 2 : 1, constraints, plotGlPixelRatio);
renderState.clearOnly = clearOnly;
var blockLineCount = setChanged ? model.lines.blockLineCount : sampleCount;
renderBlock(regl, glAes, renderState, blockLineCount, sampleCount, item);
}
}
}
function readPixel(canvasX, canvasY) {
regl.read({
x: canvasX,
y: canvasY,
width: 1,
height: 1,
data: dataPixel
});
return dataPixel;
}
function readPixels(canvasX, canvasY, width, height) {
var pixelArray = new Uint8Array(4 * width * height);
regl.read({
x: canvasX,
y: canvasY,
width: width,
height: height,
data: pixelArray
});
return pixelArray;
}
function destroy() {
canvasGL.style['pointer-events'] = 'none';
paletteTexture.destroy();
if (maskTexture) maskTexture.destroy();
for (var k in attributes) attributes[k].destroy();
}
return {
render: renderGLParcoords,
readPixel: readPixel,
readPixels: readPixels,
destroy: destroy,
update: update
};
};
/***/ }),
/***/ 97048:
/***/ (function(module) {
"use strict";
/**
* mergeLength: set trace length as the minimum of all dimension data lengths
* and propagates this length into each dimension
*
* @param {object} traceOut: the fullData trace
* @param {Array(object)} dimensions: array of dimension objects
* @param {string} dataAttr: the attribute of each dimension containing the data
* @param {integer} len: an already-existing length from other attributes
*/
module.exports = function (traceOut, dimensions, dataAttr, len) {
if (!len) len = Infinity;
var i, dimi;
for (i = 0; i < dimensions.length; i++) {
dimi = dimensions[i];
if (dimi.visible) len = Math.min(len, dimi[dataAttr].length);
}
if (len === Infinity) len = 0;
traceOut._length = len;
for (i = 0; i < dimensions.length; i++) {
dimi = dimensions[i];
if (dimi.visible) dimi._length = len;
}
return len;
};
/***/ }),
/***/ 2396:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var isArrayOrTypedArray = Lib.isArrayOrTypedArray;
var numberFormat = Lib.numberFormat;
var rgba = __webpack_require__(46952);
var Axes = __webpack_require__(81536);
var strRotate = Lib.strRotate;
var strTranslate = Lib.strTranslate;
var svgTextUtils = __webpack_require__(41536);
var Drawing = __webpack_require__(49348);
var Colorscale = __webpack_require__(26733);
var gup = __webpack_require__(83104);
var keyFun = gup.keyFun;
var repeat = gup.repeat;
var unwrap = gup.unwrap;
var helpers = __webpack_require__(30808);
var c = __webpack_require__(92304);
var brush = __webpack_require__(54376);
var lineLayerMaker = __webpack_require__(49000);
function findExtreme(fn, values, len) {
return Lib.aggNums(fn, null, values, len);
}
function findExtremes(values, len) {
return fixExtremes(findExtreme(Math.min, values, len), findExtreme(Math.max, values, len));
}
function dimensionExtent(dimension) {
var range = dimension.range;
return range ? fixExtremes(range[0], range[1]) : findExtremes(dimension.values, dimension._length);
}
function fixExtremes(lo, hi) {
if (isNaN(lo) || !isFinite(lo)) {
lo = 0;
}
if (isNaN(hi) || !isFinite(hi)) {
hi = 0;
}
// avoid a degenerate (zero-width) domain
if (lo === hi) {
if (lo === 0) {
// no use to multiplying zero, so add/subtract in this case
lo -= 1;
hi += 1;
} else {
// this keeps the range in the order of magnitude of the data
lo *= 0.9;
hi *= 1.1;
}
}
return [lo, hi];
}
function toText(formatter, texts) {
if (texts) {
return function (v, i) {
var text = texts[i];
if (text === null || text === undefined) return formatter(v);
return text;
};
}
return formatter;
}
function domainScale(height, padding, dimension, tickvals, ticktext) {
var extent = dimensionExtent(dimension);
if (tickvals) {
return d3.scale.ordinal().domain(tickvals.map(toText(numberFormat(dimension.tickformat), ticktext))).range(tickvals.map(function (d) {
var unitVal = (d - extent[0]) / (extent[1] - extent[0]);
return height - padding + unitVal * (2 * padding - height);
}));
}
return d3.scale.linear().domain(extent).range([height - padding, padding]);
}
function unitToPaddedPx(height, padding) {
return d3.scale.linear().range([padding, height - padding]);
}
function domainToPaddedUnitScale(dimension, padFraction) {
return d3.scale.linear().domain(dimensionExtent(dimension)).range([padFraction, 1 - padFraction]);
}
function ordinalScale(dimension) {
if (!dimension.tickvals) return;
var extent = dimensionExtent(dimension);
return d3.scale.ordinal().domain(dimension.tickvals).range(dimension.tickvals.map(function (d) {
return (d - extent[0]) / (extent[1] - extent[0]);
}));
}
function unitToColorScale(cscale) {
var colorStops = cscale.map(function (d) {
return d[0];
});
var colorTuples = cscale.map(function (d) {
var RGBA = rgba(d[1]);
return d3.rgb('rgb(' + RGBA[0] + ',' + RGBA[1] + ',' + RGBA[2] + ')');
});
var prop = function (n) {
return function (o) {
return o[n];
};
};
// We can't use d3 color interpolation as we may have non-uniform color palette raster
// (various color stop distances).
var polylinearUnitScales = 'rgb'.split('').map(function (key) {
return d3.scale.linear().clamp(true).domain(colorStops).range(colorTuples.map(prop(key)));
});
return function (d) {
return polylinearUnitScales.map(function (s) {
return s(d);
});
};
}
function someFiltersActive(view) {
return view.dimensions.some(function (p) {
return p.brush.filterSpecified;
});
}
function model(layout, d, i) {
var cd0 = unwrap(d);
var trace = cd0.trace;
var lineColor = helpers.convertTypedArray(cd0.lineColor);
var line = trace.line;
var deselectedLines = {
color: rgba(trace.unselected.line.color),
opacity: trace.unselected.line.opacity
};
var cOpts = Colorscale.extractOpts(line);
var cscale = cOpts.reversescale ? Colorscale.flipScale(cd0.cscale) : cd0.cscale;
var domain = trace.domain;
var dimensions = trace.dimensions;
var width = layout.width;
var labelAngle = trace.labelangle;
var labelSide = trace.labelside;
var labelFont = trace.labelfont;
var tickFont = trace.tickfont;
var rangeFont = trace.rangefont;
var lines = Lib.extendDeepNoArrays({}, line, {
color: lineColor.map(d3.scale.linear().domain(dimensionExtent({
values: lineColor,
range: [cOpts.min, cOpts.max],
_length: trace._length
}))),
blockLineCount: c.blockLineCount,
canvasOverdrag: c.overdrag * c.canvasPixelRatio
});
var groupWidth = Math.floor(width * (domain.x[1] - domain.x[0]));
var groupHeight = Math.floor(layout.height * (domain.y[1] - domain.y[0]));
var pad = layout.margin || {
l: 80,
r: 80,
t: 100,
b: 80
};
var rowContentWidth = groupWidth;
var rowHeight = groupHeight;
return {
key: i,
colCount: dimensions.filter(helpers.isVisible).length,
dimensions: dimensions,
tickDistance: c.tickDistance,
unitToColor: unitToColorScale(cscale),
lines: lines,
deselectedLines: deselectedLines,
labelAngle: labelAngle,
labelSide: labelSide,
labelFont: labelFont,
tickFont: tickFont,
rangeFont: rangeFont,
layoutWidth: width,
layoutHeight: layout.height,
domain: domain,
translateX: domain.x[0] * width,
translateY: layout.height - domain.y[1] * layout.height,
pad: pad,
canvasWidth: rowContentWidth * c.canvasPixelRatio + 2 * lines.canvasOverdrag,
canvasHeight: rowHeight * c.canvasPixelRatio,
width: rowContentWidth,
height: rowHeight,
canvasPixelRatio: c.canvasPixelRatio
};
}
function viewModel(state, callbacks, model) {
var width = model.width;
var height = model.height;
var dimensions = model.dimensions;
var canvasPixelRatio = model.canvasPixelRatio;
var xScale = function (d) {
return width * d / Math.max(1, model.colCount - 1);
};
var unitPad = c.verticalPadding / height;
var _unitToPaddedPx = unitToPaddedPx(height, c.verticalPadding);
var vm = {
key: model.key,
xScale: xScale,
model: model,
inBrushDrag: false // consider factoring it out and putting it in a centralized global-ish gesture state object
};
var uniqueKeys = {};
vm.dimensions = dimensions.filter(helpers.isVisible).map(function (dimension, i) {
var domainToPaddedUnit = domainToPaddedUnitScale(dimension, unitPad);
var foundKey = uniqueKeys[dimension.label];
uniqueKeys[dimension.label] = (foundKey || 0) + 1;
var key = dimension.label + (foundKey ? '__' + foundKey : '');
var specifiedConstraint = dimension.constraintrange;
var filterRangeSpecified = specifiedConstraint && specifiedConstraint.length;
if (filterRangeSpecified && !isArrayOrTypedArray(specifiedConstraint[0])) {
specifiedConstraint = [specifiedConstraint];
}
var filterRange = filterRangeSpecified ? specifiedConstraint.map(function (d) {
return d.map(domainToPaddedUnit);
}) : [[-Infinity, Infinity]];
var brushMove = function () {
var p = vm;
p.focusLayer && p.focusLayer.render(p.panels, true);
var filtersActive = someFiltersActive(p);
if (!state.contextShown() && filtersActive) {
p.contextLayer && p.contextLayer.render(p.panels, true);
state.contextShown(true);
} else if (state.contextShown() && !filtersActive) {
p.contextLayer && p.contextLayer.render(p.panels, true, true);
state.contextShown(false);
}
};
var truncatedValues = dimension.values;
if (truncatedValues.length > dimension._length) {
truncatedValues = truncatedValues.slice(0, dimension._length);
}
var tickvals = dimension.tickvals;
var ticktext;
function makeTickItem(v, i) {
return {
val: v,
text: ticktext[i]
};
}
function sortTickItem(a, b) {
return a.val - b.val;
}
if (isArrayOrTypedArray(tickvals) && tickvals.length) {
if (Lib.isTypedArray(tickvals)) tickvals = Array.from(tickvals);
ticktext = dimension.ticktext;
// ensure ticktext and tickvals have same length
if (!isArrayOrTypedArray(ticktext) || !ticktext.length) {
ticktext = tickvals.map(numberFormat(dimension.tickformat));
} else if (ticktext.length > tickvals.length) {
ticktext = ticktext.slice(0, tickvals.length);
} else if (tickvals.length > ticktext.length) {
tickvals = tickvals.slice(0, ticktext.length);
}
// check if we need to sort tickvals/ticktext
for (var j = 1; j < tickvals.length; j++) {
if (tickvals[j] < tickvals[j - 1]) {
var tickItems = tickvals.map(makeTickItem).sort(sortTickItem);
for (var k = 0; k < tickvals.length; k++) {
tickvals[k] = tickItems[k].val;
ticktext[k] = tickItems[k].text;
}
break;
}
}
} else tickvals = undefined;
truncatedValues = helpers.convertTypedArray(truncatedValues);
return {
key: key,
label: dimension.label,
tickFormat: dimension.tickformat,
tickvals: tickvals,
ticktext: ticktext,
ordinal: helpers.isOrdinal(dimension),
multiselect: dimension.multiselect,
xIndex: i,
crossfilterDimensionIndex: i,
visibleIndex: dimension._index,
height: height,
values: truncatedValues,
paddedUnitValues: truncatedValues.map(domainToPaddedUnit),
unitTickvals: tickvals && tickvals.map(domainToPaddedUnit),
xScale: xScale,
x: xScale(i),
canvasX: xScale(i) * canvasPixelRatio,
unitToPaddedPx: _unitToPaddedPx,
domainScale: domainScale(height, c.verticalPadding, dimension, tickvals, ticktext),
ordinalScale: ordinalScale(dimension),
parent: vm,
model: model,
brush: brush.makeBrush(state, filterRangeSpecified, filterRange, function () {
state.linePickActive(false);
}, brushMove, function (f) {
vm.focusLayer.render(vm.panels, true);
vm.pickLayer && vm.pickLayer.render(vm.panels, true);
state.linePickActive(true);
if (callbacks && callbacks.filterChanged) {
var invScale = domainToPaddedUnit.invert;
// update gd.data as if a Plotly.restyle were fired
var newRanges = f.map(function (r) {
return r.map(invScale).sort(Lib.sorterAsc);
}).sort(function (a, b) {
return a[0] - b[0];
});
callbacks.filterChanged(vm.key, dimension._index, newRanges);
}
})
};
});
return vm;
}
function styleExtentTexts(selection) {
selection.classed(c.cn.axisExtentText, true).attr('text-anchor', 'middle').style('cursor', 'default');
}
function parcoordsInteractionState() {
var linePickActive = true;
var contextShown = false;
return {
linePickActive: function (val) {
return arguments.length ? linePickActive = !!val : linePickActive;
},
contextShown: function (val) {
return arguments.length ? contextShown = !!val : contextShown;
}
};
}
function calcTilt(angle, position) {
var dir = position === 'top' ? 1 : -1;
var radians = angle * Math.PI / 180;
var dx = Math.sin(radians);
var dy = Math.cos(radians);
return {
dir: dir,
dx: dx,
dy: dy,
degrees: angle
};
}
function updatePanelLayout(yAxis, vm, plotGlPixelRatio) {
var panels = vm.panels || (vm.panels = []);
var data = yAxis.data();
for (var i = 0; i < data.length - 1; i++) {
var p = panels[i] || (panels[i] = {});
var dim0 = data[i];
var dim1 = data[i + 1];
p.dim0 = dim0;
p.dim1 = dim1;
p.canvasX = dim0.canvasX;
p.panelSizeX = dim1.canvasX - dim0.canvasX;
p.panelSizeY = vm.model.canvasHeight;
p.y = 0;
p.canvasY = 0;
p.plotGlPixelRatio = plotGlPixelRatio;
}
}
function calcAllTicks(cd) {
for (var i = 0; i < cd.length; i++) {
for (var j = 0; j < cd[i].length; j++) {
var trace = cd[i][j].trace;
var dimensions = trace.dimensions;
for (var k = 0; k < dimensions.length; k++) {
var values = dimensions[k].values;
var dim = dimensions[k]._ax;
if (dim) {
if (!dim.range) {
dim.range = findExtremes(values, trace._length);
} else {
dim.range = fixExtremes(dim.range[0], dim.range[1]);
}
if (!dim.dtick) {
dim.dtick = 0.01 * (Math.abs(dim.range[1] - dim.range[0]) || 1);
}
dim.tickformat = dimensions[k].tickformat;
Axes.calcTicks(dim);
dim.cleanRange();
}
}
}
}
}
function linearFormat(dim, v) {
return Axes.tickText(dim._ax, v, false).text;
}
function extremeText(d, isTop) {
if (d.ordinal) return '';
var domain = d.domainScale.domain();
var v = domain[isTop ? domain.length - 1 : 0];
return linearFormat(d.model.dimensions[d.visibleIndex], v);
}
module.exports = function parcoords(gd, cdModule, layout, callbacks) {
var isStatic = gd._context.staticPlot;
var fullLayout = gd._fullLayout;
var svg = fullLayout._toppaper;
var glContainer = fullLayout._glcontainer;
var plotGlPixelRatio = gd._context.plotGlPixelRatio;
var paperColor = gd._fullLayout.paper_bgcolor;
calcAllTicks(cdModule);
var state = parcoordsInteractionState();
var vm = cdModule.filter(function (d) {
return unwrap(d).trace.visible;
}).map(model.bind(0, layout)).map(viewModel.bind(0, state, callbacks));
glContainer.each(function (d, i) {
return Lib.extendFlat(d, vm[i]);
});
var glLayers = glContainer.selectAll('.gl-canvas').each(function (d) {
// FIXME: figure out how to handle multiple instances
d.viewModel = vm[0];
d.viewModel.plotGlPixelRatio = plotGlPixelRatio;
d.viewModel.paperColor = paperColor;
d.model = d.viewModel ? d.viewModel.model : null;
});
var lastHovered = null;
var pickLayer = glLayers.filter(function (d) {
return d.pick;
});
// emit hover / unhover event
pickLayer.style('pointer-events', isStatic ? 'none' : 'auto').on('mousemove', function (d) {
if (state.linePickActive() && d.lineLayer && callbacks && callbacks.hover) {
var event = d3.event;
var cw = this.width;
var ch = this.height;
var pointer = d3.mouse(this);
var x = pointer[0];
var y = pointer[1];
if (x < 0 || y < 0 || x >= cw || y >= ch) {
return;
}
var pixel = d.lineLayer.readPixel(x, ch - 1 - y);
var found = pixel[3] !== 0;
// inverse of the calcPickColor in `lines.js`; detailed comment there
var curveNumber = found ? pixel[2] + 256 * (pixel[1] + 256 * pixel[0]) : null;
var eventData = {
x: x,
y: y,
clientX: event.clientX,
clientY: event.clientY,
dataIndex: d.model.key,
curveNumber: curveNumber
};
if (curveNumber !== lastHovered) {
// don't unnecessarily repeat the same hit (or miss)
if (found) {
callbacks.hover(eventData);
} else if (callbacks.unhover) {
callbacks.unhover(eventData);
}
lastHovered = curveNumber;
}
}
});
glLayers.style('opacity', function (d) {
return d.pick ? 0 : 1;
});
svg.style('background', 'rgba(255, 255, 255, 0)');
var controlOverlay = svg.selectAll('.' + c.cn.parcoords).data(vm, keyFun);
controlOverlay.exit().remove();
controlOverlay.enter().append('g').classed(c.cn.parcoords, true).style('shape-rendering', 'crispEdges').style('pointer-events', 'none');
controlOverlay.attr('transform', function (d) {
return strTranslate(d.model.translateX, d.model.translateY);
});
var parcoordsControlView = controlOverlay.selectAll('.' + c.cn.parcoordsControlView).data(repeat, keyFun);
parcoordsControlView.enter().append('g').classed(c.cn.parcoordsControlView, true);
parcoordsControlView.attr('transform', function (d) {
return strTranslate(d.model.pad.l, d.model.pad.t);
});
var yAxis = parcoordsControlView.selectAll('.' + c.cn.yAxis).data(function (p) {
return p.dimensions;
}, keyFun);
yAxis.enter().append('g').classed(c.cn.yAxis, true);
parcoordsControlView.each(function (p) {
updatePanelLayout(yAxis, p, plotGlPixelRatio);
});
glLayers.each(function (d) {
if (d.viewModel) {
if (!d.lineLayer || callbacks) {
// recreate in case of having callbacks e.g. restyle. Should we test for callback to be a restyle?
d.lineLayer = lineLayerMaker(this, d);
} else d.lineLayer.update(d);
if (d.key || d.key === 0) d.viewModel[d.key] = d.lineLayer;
var setChanged = !d.context ||
// don't update background
callbacks; // unless there is a callback on the context layer. Should we test the callback?
d.lineLayer.render(d.viewModel.panels, setChanged);
}
});
yAxis.attr('transform', function (d) {
return strTranslate(d.xScale(d.xIndex), 0);
});
// drag column for reordering columns
yAxis.call(d3.behavior.drag().origin(function (d) {
return d;
}).on('drag', function (d) {
var p = d.parent;
state.linePickActive(false);
d.x = Math.max(-c.overdrag, Math.min(d.model.width + c.overdrag, d3.event.x));
d.canvasX = d.x * d.model.canvasPixelRatio;
yAxis.sort(function (a, b) {
return a.x - b.x;
}).each(function (e, i) {
e.xIndex = i;
e.x = d === e ? e.x : e.xScale(e.xIndex);
e.canvasX = e.x * e.model.canvasPixelRatio;
});
updatePanelLayout(yAxis, p, plotGlPixelRatio);
yAxis.filter(function (e) {
return Math.abs(d.xIndex - e.xIndex) !== 0;
}).attr('transform', function (d) {
return strTranslate(d.xScale(d.xIndex), 0);
});
d3.select(this).attr('transform', strTranslate(d.x, 0));
yAxis.each(function (e, i0, i1) {
if (i1 === d.parent.key) p.dimensions[i0] = e;
});
p.contextLayer && p.contextLayer.render(p.panels, false, !someFiltersActive(p));
p.focusLayer.render && p.focusLayer.render(p.panels);
}).on('dragend', function (d) {
var p = d.parent;
d.x = d.xScale(d.xIndex);
d.canvasX = d.x * d.model.canvasPixelRatio;
updatePanelLayout(yAxis, p, plotGlPixelRatio);
d3.select(this).attr('transform', function (d) {
return strTranslate(d.x, 0);
});
p.contextLayer && p.contextLayer.render(p.panels, false, !someFiltersActive(p));
p.focusLayer && p.focusLayer.render(p.panels);
p.pickLayer && p.pickLayer.render(p.panels, true);
state.linePickActive(true);
if (callbacks && callbacks.axesMoved) {
callbacks.axesMoved(p.key, p.dimensions.map(function (e) {
return e.crossfilterDimensionIndex;
}));
}
}));
yAxis.exit().remove();
var axisOverlays = yAxis.selectAll('.' + c.cn.axisOverlays).data(repeat, keyFun);
axisOverlays.enter().append('g').classed(c.cn.axisOverlays, true);
axisOverlays.selectAll('.' + c.cn.axis).remove();
var axis = axisOverlays.selectAll('.' + c.cn.axis).data(repeat, keyFun);
axis.enter().append('g').classed(c.cn.axis, true);
axis.each(function (d) {
var wantedTickCount = d.model.height / d.model.tickDistance;
var scale = d.domainScale;
var sdom = scale.domain();
d3.select(this).call(d3.svg.axis().orient('left').tickSize(4).outerTickSize(2).ticks(wantedTickCount, d.tickFormat) // works for continuous scales only...
.tickValues(d.ordinal ?
// and this works for ordinal scales
sdom : null).tickFormat(function (v) {
return helpers.isOrdinal(d) ? v : linearFormat(d.model.dimensions[d.visibleIndex], v);
}).scale(scale));
Drawing.font(axis.selectAll('text'), d.model.tickFont);
});
axis.selectAll('.domain, .tick>line').attr('fill', 'none').attr('stroke', 'black').attr('stroke-opacity', 0.25).attr('stroke-width', '1px');
axis.selectAll('text').style('text-shadow', svgTextUtils.makeTextShadow(paperColor)).style('cursor', 'default');
var axisHeading = axisOverlays.selectAll('.' + c.cn.axisHeading).data(repeat, keyFun);
axisHeading.enter().append('g').classed(c.cn.axisHeading, true);
var axisTitle = axisHeading.selectAll('.' + c.cn.axisTitle).data(repeat, keyFun);
axisTitle.enter().append('text').classed(c.cn.axisTitle, true).attr('text-anchor', 'middle').style('cursor', 'ew-resize').style('pointer-events', isStatic ? 'none' : 'auto');
axisTitle.text(function (d) {
return d.label;
}).each(function (d) {
var e = d3.select(this);
Drawing.font(e, d.model.labelFont);
svgTextUtils.convertToTspans(e, gd);
}).attr('transform', function (d) {
var tilt = calcTilt(d.model.labelAngle, d.model.labelSide);
var r = c.axisTitleOffset;
return (tilt.dir > 0 ? '' : strTranslate(0, 2 * r + d.model.height)) + strRotate(tilt.degrees) + strTranslate(-r * tilt.dx, -r * tilt.dy);
}).attr('text-anchor', function (d) {
var tilt = calcTilt(d.model.labelAngle, d.model.labelSide);
var adx = Math.abs(tilt.dx);
var ady = Math.abs(tilt.dy);
if (2 * adx > ady) {
return tilt.dir * tilt.dx < 0 ? 'start' : 'end';
} else {
return 'middle';
}
});
var axisExtent = axisOverlays.selectAll('.' + c.cn.axisExtent).data(repeat, keyFun);
axisExtent.enter().append('g').classed(c.cn.axisExtent, true);
var axisExtentTop = axisExtent.selectAll('.' + c.cn.axisExtentTop).data(repeat, keyFun);
axisExtentTop.enter().append('g').classed(c.cn.axisExtentTop, true);
axisExtentTop.attr('transform', strTranslate(0, -c.axisExtentOffset));
var axisExtentTopText = axisExtentTop.selectAll('.' + c.cn.axisExtentTopText).data(repeat, keyFun);
axisExtentTopText.enter().append('text').classed(c.cn.axisExtentTopText, true).call(styleExtentTexts);
axisExtentTopText.text(function (d) {
return extremeText(d, true);
}).each(function (d) {
Drawing.font(d3.select(this), d.model.rangeFont);
});
var axisExtentBottom = axisExtent.selectAll('.' + c.cn.axisExtentBottom).data(repeat, keyFun);
axisExtentBottom.enter().append('g').classed(c.cn.axisExtentBottom, true);
axisExtentBottom.attr('transform', function (d) {
return strTranslate(0, d.model.height + c.axisExtentOffset);
});
var axisExtentBottomText = axisExtentBottom.selectAll('.' + c.cn.axisExtentBottomText).data(repeat, keyFun);
axisExtentBottomText.enter().append('text').classed(c.cn.axisExtentBottomText, true).attr('dy', '0.75em').call(styleExtentTexts);
axisExtentBottomText.text(function (d) {
return extremeText(d, false);
}).each(function (d) {
Drawing.font(d3.select(this), d.model.rangeFont);
});
brush.ensureAxisBrush(axisOverlays, paperColor, gd);
};
/***/ }),
/***/ 87572:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var parcoords = __webpack_require__(2396);
var prepareRegl = __webpack_require__(81976);
var isVisible = (__webpack_require__(30808).isVisible);
var reglPrecompiled = {};
function newIndex(visibleIndices, orig, dim) {
var origIndex = orig.indexOf(dim);
var currentIndex = visibleIndices.indexOf(origIndex);
if (currentIndex === -1) {
// invisible dimensions initially go to the end
currentIndex += orig.length;
}
return currentIndex;
}
function sorter(visibleIndices, orig) {
return function sorter(d1, d2) {
return newIndex(visibleIndices, orig, d1) - newIndex(visibleIndices, orig, d2);
};
}
var exports = module.exports = function plot(gd, cdModule) {
var fullLayout = gd._fullLayout;
var success = prepareRegl(gd, [], reglPrecompiled);
if (!success) return;
var currentDims = {};
var initialDims = {};
var fullIndices = {};
var inputIndices = {};
var size = fullLayout._size;
cdModule.forEach(function (d, i) {
var trace = d[0].trace;
fullIndices[i] = trace.index;
var iIn = inputIndices[i] = trace._fullInput.index;
currentDims[i] = gd.data[iIn].dimensions;
initialDims[i] = gd.data[iIn].dimensions.slice();
});
var filterChanged = function (i, initialDimIndex, newRanges) {
// Have updated `constraintrange` data on `gd.data` and raise `Plotly.restyle` event
// without having to incur heavy UI blocking due to an actual `Plotly.restyle` call
var dim = initialDims[i][initialDimIndex];
var newConstraints = newRanges.map(function (r) {
return r.slice();
});
// Store constraint range in preGUI
// This one doesn't work if it's stored in pieces in _storeDirectGUIEdit
// because it's an array of variable dimensionality. So store the whole
// thing at once manually.
var aStr = 'dimensions[' + initialDimIndex + '].constraintrange';
var preGUI = fullLayout._tracePreGUI[gd._fullData[fullIndices[i]]._fullInput.uid];
if (preGUI[aStr] === undefined) {
var initialVal = dim.constraintrange;
preGUI[aStr] = initialVal || null;
}
var fullDimension = gd._fullData[fullIndices[i]].dimensions[initialDimIndex];
if (!newConstraints.length) {
delete dim.constraintrange;
delete fullDimension.constraintrange;
newConstraints = null;
} else {
if (newConstraints.length === 1) newConstraints = newConstraints[0];
dim.constraintrange = newConstraints;
fullDimension.constraintrange = newConstraints.slice();
// wrap in another array for restyle event data
newConstraints = [newConstraints];
}
var restyleData = {};
restyleData[aStr] = newConstraints;
gd.emit('plotly_restyle', [restyleData, [inputIndices[i]]]);
};
var hover = function (eventData) {
gd.emit('plotly_hover', eventData);
};
var unhover = function (eventData) {
gd.emit('plotly_unhover', eventData);
};
var axesMoved = function (i, visibleIndices) {
// Have updated order data on `gd.data` and raise `Plotly.restyle` event
// without having to incur heavy UI blocking due to an actual `Plotly.restyle` call
// drag&drop sorting of the visible dimensions
var orig = sorter(visibleIndices, initialDims[i].filter(isVisible));
currentDims[i].sort(orig);
// invisible dimensions are not interpreted in the context of drag&drop sorting as an invisible dimension
// cannot be dragged; they're interspersed into their original positions by this subsequent merging step
initialDims[i].filter(function (d) {
return !isVisible(d);
}).sort(function (d) {
// subsequent splicing to be done left to right, otherwise indices may be incorrect
return initialDims[i].indexOf(d);
}).forEach(function (d) {
currentDims[i].splice(currentDims[i].indexOf(d), 1); // remove from the end
currentDims[i].splice(initialDims[i].indexOf(d), 0, d); // insert at original index
});
// TODO: we can't really store this part of the interaction state
// directly as below, since it incudes data arrays. If we want to
// persist column order we may have to do something special for this
// case to just store the order itself.
// Registry.call('_storeDirectGUIEdit',
// gd.data[inputIndices[i]],
// fullLayout._tracePreGUI[gd._fullData[fullIndices[i]]._fullInput.uid],
// {dimensions: currentDims[i]}
// );
gd.emit('plotly_restyle', [{
dimensions: [currentDims[i]]
}, [inputIndices[i]]]);
};
parcoords(gd, cdModule, {
// layout
width: size.w,
height: size.h,
margin: {
t: size.t,
r: size.r,
b: size.b,
l: size.l
}
}, {
// callbacks
filterChanged: filterChanged,
hover: hover,
unhover: unhover,
axesMoved: axesMoved
});
};
exports.reglPrecompiled = reglPrecompiled;
/***/ }),
/***/ 99644:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var baseAttrs = __webpack_require__(6040);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var fontAttrs = __webpack_require__(71936);
var colorAttrs = __webpack_require__(51468);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var extendFlat = (__webpack_require__(55016).extendFlat);
var pattern = (__webpack_require__(9392)/* .pattern */ .c);
var textFontAttrs = fontAttrs({
editType: 'plot',
arrayOk: true,
colorEditType: 'plot',
description: 'Sets the font used for `textinfo`.'
});
module.exports = {
labels: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the sector labels.', 'If `labels` entries are duplicated, we sum associated `values`', 'or simply count occurrences if `values` is not provided.', 'For other array attributes (including color) we use the first', 'non-empty entry among all occurrences of the label.'].join(' ')
},
// equivalent of x0 and dx, if label is missing
label0: {
valType: 'number',
dflt: 0,
editType: 'calc',
description: ['Alternate to `labels`.', 'Builds a numeric set of labels.', 'Use with `dlabel`', 'where `label0` is the starting label and `dlabel` the step.'].join(' ')
},
dlabel: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: 'Sets the label step. See `label0` for more info.'
},
values: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the values of the sectors.', 'If omitted, we count occurrences of each label.'].join(' ')
},
marker: {
colors: {
valType: 'data_array',
// TODO 'color_array' ?
editType: 'calc',
description: ['Sets the color of each sector.', 'If not specified, the default trace color set is used', 'to pick the sector colors.'].join(' ')
},
line: {
color: {
valType: 'color',
dflt: colorAttrs.defaultLine,
arrayOk: true,
editType: 'style',
description: ['Sets the color of the line enclosing each sector.'].join(' ')
},
width: {
valType: 'number',
min: 0,
dflt: 0,
arrayOk: true,
editType: 'style',
description: ['Sets the width (in px) of the line enclosing each sector.'].join(' ')
},
editType: 'calc'
},
pattern: pattern,
editType: 'calc'
},
text: {
valType: 'data_array',
editType: 'plot',
description: ['Sets text elements associated with each sector.', 'If trace `textinfo` contains a *text* flag, these elements will be seen', 'on the chart.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
},
hovertext: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'style',
description: ['Sets hover text elements associated with each sector.', 'If a single string, the same string appears for', 'all data points.', 'If an array of string, the items are mapped in order of', 'this trace\'s sectors.', 'To be seen, trace `hoverinfo` must contain a *text* flag.'].join(' ')
},
// 'see eg:'
// 'https://www.e-education.psu.edu/natureofgeoinfo/sites/www.e-education.psu.edu.natureofgeoinfo/files/image/hisp_pies.gif',
// '(this example involves a map too - may someday be a whole trace type',
// 'of its own. but the point is the size of the whole pie is important.)'
scalegroup: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['If there are multiple pie charts that should be sized according to', 'their totals, link them by providing a non-empty group id here', 'shared by every trace in the same group.'].join(' ')
},
// labels (legend is handled by plots.attributes.showlegend and layout.hiddenlabels)
textinfo: {
valType: 'flaglist',
flags: ['label', 'text', 'value', 'percent'],
extras: ['none'],
editType: 'calc',
description: ['Determines which trace information appear on the graph.'].join(' ')
},
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['label', 'text', 'value', 'percent', 'name']
}),
hovertemplate: hovertemplateAttrs({}, {
keys: ['label', 'color', 'value', 'percent', 'text']
}),
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['label', 'color', 'value', 'percent', 'text']
}),
textposition: {
valType: 'enumerated',
values: ['inside', 'outside', 'auto', 'none'],
dflt: 'auto',
arrayOk: true,
editType: 'plot',
description: ['Specifies the location of the `textinfo`.'].join(' ')
},
textfont: extendFlat({}, textFontAttrs, {
description: 'Sets the font used for `textinfo`.'
}),
insidetextorientation: {
valType: 'enumerated',
values: ['horizontal', 'radial', 'tangential', 'auto'],
dflt: 'auto',
editType: 'plot',
description: ['Controls the orientation of the text inside chart sectors.', 'When set to *auto*, text may be oriented in any direction in order', 'to be as big as possible in the middle of a sector.', 'The *horizontal* option orients text to be parallel with the bottom', 'of the chart, and may make text smaller in order to achieve that goal.', 'The *radial* option orients text along the radius of the sector.', 'The *tangential* option orients text perpendicular to the radius of the sector.'].join(' ')
},
insidetextfont: extendFlat({}, textFontAttrs, {
description: 'Sets the font used for `textinfo` lying inside the sector.'
}),
outsidetextfont: extendFlat({}, textFontAttrs, {
description: 'Sets the font used for `textinfo` lying outside the sector.'
}),
automargin: {
valType: 'boolean',
dflt: false,
editType: 'plot',
description: ['Determines whether outside text labels can push the margins.'].join(' ')
},
title: {
text: {
valType: 'string',
dflt: '',
editType: 'plot',
description: ['Sets the title of the chart.', 'If it is empty, no title is displayed.', 'Note that before the existence of `title.text`, the title\'s', 'contents used to be defined as the `title` attribute itself.', 'This behavior has been deprecated.'].join(' ')
},
font: extendFlat({}, textFontAttrs, {
description: ['Sets the font used for `title`.', 'Note that the title\'s font used to be set', 'by the now deprecated `titlefont` attribute.'].join(' ')
}),
position: {
valType: 'enumerated',
values: ['top left', 'top center', 'top right', 'middle center', 'bottom left', 'bottom center', 'bottom right'],
editType: 'plot',
description: ['Specifies the location of the `title`.', 'Note that the title\'s position used to be set', 'by the now deprecated `titleposition` attribute.'].join(' ')
},
editType: 'plot'
},
// position and shape
domain: domainAttrs({
name: 'pie',
trace: true,
editType: 'calc'
}),
hole: {
valType: 'number',
min: 0,
max: 1,
dflt: 0,
editType: 'calc',
description: ['Sets the fraction of the radius to cut out of the pie.', 'Use this to make a donut chart.'].join(' ')
},
// ordering and direction
sort: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether or not the sectors are reordered', 'from largest to smallest.'].join(' ')
},
direction: {
/**
* there are two common conventions, both of which place the first
* (largest, if sorted) slice with its left edge at 12 o'clock but
* succeeding slices follow either cw or ccw from there.
*
* see http://visage.co/data-visualization-101-pie-charts/
*/
valType: 'enumerated',
values: ['clockwise', 'counterclockwise'],
dflt: 'counterclockwise',
editType: 'calc',
description: ['Specifies the direction at which succeeding sectors follow', 'one another.'].join(' ')
},
rotation: {
valType: 'angle',
dflt: 0,
editType: 'calc',
description: ['Instead of the first slice starting at 12 o\'clock,', 'rotate to some other angle.'].join(' ')
},
pull: {
valType: 'number',
min: 0,
max: 1,
dflt: 0,
arrayOk: true,
editType: 'calc',
description: ['Sets the fraction of larger radius to pull the sectors', 'out from the center. This can be a constant', 'to pull all slices apart from each other equally', 'or an array to highlight one or more slices.'].join(' ')
},
_deprecated: {
title: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['Deprecated in favor of `title.text`.', 'Note that value of `title` is no longer a simple', '*string* but a set of sub-attributes.'].join(' ')
},
titlefont: extendFlat({}, textFontAttrs, {
description: 'Deprecated in favor of `title.font`.'
}),
titleposition: {
valType: 'enumerated',
values: ['top left', 'top center', 'top right', 'middle center', 'bottom left', 'bottom center', 'bottom right'],
editType: 'calc',
description: 'Deprecated in favor of `title.position`.'
}
}
};
/***/ }),
/***/ 1688:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var plots = __webpack_require__(19896);
exports.name = 'pie';
exports.plot = function (gd, traces, transitionOpts, makeOnCompleteCallback) {
plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout);
};
/***/ }),
/***/ 71120:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var tinycolor = __webpack_require__(70336);
var Color = __webpack_require__(9240);
var extendedColorWayList = {};
function calc(gd, trace) {
var cd = [];
var fullLayout = gd._fullLayout;
var hiddenLabels = fullLayout.hiddenlabels || [];
var labels = trace.labels;
var colors = trace.marker.colors || [];
var vals = trace.values;
var len = trace._length;
var hasValues = trace._hasValues && len;
var i, pt;
if (trace.dlabel) {
labels = new Array(len);
for (i = 0; i < len; i++) {
labels[i] = String(trace.label0 + i * trace.dlabel);
}
}
var allThisTraceLabels = {};
var pullColor = makePullColorFn(fullLayout['_' + trace.type + 'colormap']);
var vTotal = 0;
var isAggregated = false;
for (i = 0; i < len; i++) {
var v, label, hidden;
if (hasValues) {
v = vals[i];
if (!isNumeric(v)) continue;
v = +v;
} else v = 1;
label = labels[i];
if (label === undefined || label === '') label = i;
label = String(label);
var thisLabelIndex = allThisTraceLabels[label];
if (thisLabelIndex === undefined) {
allThisTraceLabels[label] = cd.length;
hidden = hiddenLabels.indexOf(label) !== -1;
if (!hidden) vTotal += v;
cd.push({
v: v,
label: label,
color: pullColor(colors[i], label),
i: i,
pts: [i],
hidden: hidden
});
} else {
isAggregated = true;
pt = cd[thisLabelIndex];
pt.v += v;
pt.pts.push(i);
if (!pt.hidden) vTotal += v;
if (pt.color === false && colors[i]) {
pt.color = pullColor(colors[i], label);
}
}
}
// Drop aggregate sums of value 0 or less
cd = cd.filter(function (elem) {
return elem.v >= 0;
});
var shouldSort = trace.type === 'funnelarea' ? isAggregated : trace.sort;
if (shouldSort) cd.sort(function (a, b) {
return b.v - a.v;
});
// include the sum of all values in the first point
if (cd[0]) cd[0].vTotal = vTotal;
return cd;
}
function makePullColorFn(colorMap) {
return function pullColor(color, id) {
if (!color) return false;
color = tinycolor(color);
if (!color.isValid()) return false;
color = Color.addOpacity(color, color.getAlpha());
if (!colorMap[id]) colorMap[id] = color;
return color;
};
}
/*
* `calc` filled in (and collated) explicit colors.
* Now we need to propagate these explicit colors to other traces,
* and fill in default colors.
* This is done after sorting, so we pick defaults
* in the order slices will be displayed
*/
function crossTraceCalc(gd, plotinfo) {
// TODO: should we name the second argument opts?
var desiredType = (plotinfo || {}).type;
if (!desiredType) desiredType = 'pie';
var fullLayout = gd._fullLayout;
var calcdata = gd.calcdata;
var colorWay = fullLayout[desiredType + 'colorway'];
var colorMap = fullLayout['_' + desiredType + 'colormap'];
if (fullLayout['extend' + desiredType + 'colors']) {
colorWay = generateExtendedColors(colorWay, extendedColorWayList);
}
var dfltColorCount = 0;
for (var i = 0; i < calcdata.length; i++) {
var cd = calcdata[i];
var traceType = cd[0].trace.type;
if (traceType !== desiredType) continue;
for (var j = 0; j < cd.length; j++) {
var pt = cd[j];
if (pt.color === false) {
// have we seen this label and assigned a color to it in a previous trace?
if (colorMap[pt.label]) {
pt.color = colorMap[pt.label];
} else {
colorMap[pt.label] = pt.color = colorWay[dfltColorCount % colorWay.length];
dfltColorCount++;
}
}
}
}
}
/**
* pick a default color from the main default set, augmented by
* itself lighter then darker before repeating
*/
function generateExtendedColors(colorList, extendedColorWays) {
var i;
var colorString = JSON.stringify(colorList);
var colors = extendedColorWays[colorString];
if (!colors) {
colors = colorList.slice();
for (i = 0; i < colorList.length; i++) {
colors.push(tinycolor(colorList[i]).lighten(20).toHexString());
}
for (i = 0; i < colorList.length; i++) {
colors.push(tinycolor(colorList[i]).darken(20).toHexString());
}
extendedColorWays[colorString] = colors;
}
return colors;
}
module.exports = {
calc: calc,
crossTraceCalc: crossTraceCalc,
makePullColorFn: makePullColorFn,
generateExtendedColors: generateExtendedColors
};
/***/ }),
/***/ 87048:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(99644);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var handleText = (__webpack_require__(49520).handleText);
var coercePattern = (__webpack_require__(10923).coercePattern);
function handleLabelsAndValues(labels, values) {
var hasLabels = Lib.isArrayOrTypedArray(labels);
var hasValues = Lib.isArrayOrTypedArray(values);
var len = Math.min(hasLabels ? labels.length : Infinity, hasValues ? values.length : Infinity);
if (!isFinite(len)) len = 0;
if (len && hasValues) {
var hasPositive;
for (var i = 0; i < len; i++) {
var v = values[i];
if (isNumeric(v) && v > 0) {
hasPositive = true;
break;
}
}
if (!hasPositive) len = 0;
}
return {
hasLabels: hasLabels,
hasValues: hasValues,
len: len
};
}
function handleMarkerDefaults(traceIn, traceOut, layout, coerce, isPie) {
var lineWidth = coerce('marker.line.width');
if (lineWidth) {
coerce('marker.line.color', isPie ? undefined : layout.paper_bgcolor // case of funnelarea, sunburst, icicle, treemap
);
}
var markerColors = coerce('marker.colors');
coercePattern(coerce, 'marker.pattern', markerColors);
// push the marker colors (with s) to the foreground colors, to work around logic in the drawing pattern code on marker.color (without s, which is okay for a bar trace)
if (traceIn.marker && !traceOut.marker.pattern.fgcolor) traceOut.marker.pattern.fgcolor = traceIn.marker.colors;
if (!traceOut.marker.pattern.bgcolor) traceOut.marker.pattern.bgcolor = layout.paper_bgcolor;
}
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var labels = coerce('labels');
var values = coerce('values');
var res = handleLabelsAndValues(labels, values);
var len = res.len;
traceOut._hasLabels = res.hasLabels;
traceOut._hasValues = res.hasValues;
if (!traceOut._hasLabels && traceOut._hasValues) {
coerce('label0');
coerce('dlabel');
}
if (!len) {
traceOut.visible = false;
return;
}
traceOut._length = len;
handleMarkerDefaults(traceIn, traceOut, layout, coerce, true);
coerce('scalegroup');
// TODO: hole needs to be coerced to the same value within a scaleegroup
var textData = coerce('text');
var textTemplate = coerce('texttemplate');
var textInfo;
if (!textTemplate) textInfo = coerce('textinfo', Lib.isArrayOrTypedArray(textData) ? 'text+percent' : 'percent');
coerce('hovertext');
coerce('hovertemplate');
if (textTemplate || textInfo && textInfo !== 'none') {
var textposition = coerce('textposition');
handleText(traceIn, traceOut, layout, coerce, textposition, {
moduleHasSelected: false,
moduleHasUnselected: false,
moduleHasConstrain: false,
moduleHasCliponaxis: false,
moduleHasTextangle: false,
moduleHasInsideanchor: false
});
var hasBoth = Array.isArray(textposition) || textposition === 'auto';
var hasOutside = hasBoth || textposition === 'outside';
if (hasOutside) {
coerce('automargin');
}
if (textposition === 'inside' || textposition === 'auto' || Array.isArray(textposition)) {
coerce('insidetextorientation');
}
} else if (textInfo === 'none') {
coerce('textposition', 'none');
}
handleDomainDefaults(traceOut, layout, coerce);
var hole = coerce('hole');
var title = coerce('title.text');
if (title) {
var titlePosition = coerce('title.position', hole ? 'middle center' : 'top center');
if (!hole && titlePosition === 'middle center') traceOut.title.position = 'top center';
Lib.coerceFont(coerce, 'title.font', layout.font);
}
coerce('sort');
coerce('direction');
coerce('rotation');
coerce('pull');
}
module.exports = {
handleLabelsAndValues: handleLabelsAndValues,
handleMarkerDefaults: handleMarkerDefaults,
supplyDefaults: supplyDefaults
};
/***/ }),
/***/ 29076:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var appendArrayMultiPointValues = (__webpack_require__(12228).appendArrayMultiPointValues);
// Note: like other eventData routines, this creates the data for hover/unhover/click events
// but it has a different API and goes through a totally different pathway.
// So to ensure it doesn't get misused, it's not attached to the Pie module.
module.exports = function eventData(pt, trace) {
var out = {
curveNumber: trace.index,
pointNumbers: pt.pts,
data: trace._input,
fullData: trace,
label: pt.label,
color: pt.color,
value: pt.v,
percent: pt.percent,
text: pt.text,
bbox: pt.bbox,
// pt.v (and pt.i below) for backward compatibility
v: pt.v
};
// Only include pointNumber if it's unambiguous
if (pt.pts.length === 1) out.pointNumber = out.i = pt.pts[0];
// Add extra data arrays to the output
// notice that this is the multi-point version ('s' on the end!)
// so added data will be arrays matching the pointNumbers array.
appendArrayMultiPointValues(out, trace, pt.pts);
// don't include obsolete fields in new funnelarea traces
if (trace.type === 'funnelarea') {
delete out.v;
delete out.i;
}
return out;
};
/***/ }),
/***/ 19464:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Drawing = __webpack_require__(49348);
var Color = __webpack_require__(9240);
module.exports = function fillOne(s, pt, trace, gd) {
var pattern = trace.marker.pattern;
if (pattern && pattern.shape) {
Drawing.pointStyle(s, trace, gd, pt);
} else {
Color.fill(s, pt.color);
}
};
/***/ }),
/***/ 27760:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
function format(vRounded) {
return vRounded.indexOf('e') !== -1 ? vRounded.replace(/[.]?0+e/, 'e') : vRounded.indexOf('.') !== -1 ? vRounded.replace(/[.]?0+$/, '') : vRounded;
}
exports.formatPiePercent = function formatPiePercent(v, separators) {
var vRounded = format((v * 100).toPrecision(3));
return Lib.numSeparate(vRounded, separators) + '%';
};
exports.formatPieValue = function formatPieValue(v, separators) {
var vRounded = format(v.toPrecision(10));
return Lib.numSeparate(vRounded, separators);
};
exports.getFirstFilled = function getFirstFilled(array, indices) {
if (!Lib.isArrayOrTypedArray(array)) return;
for (var i = 0; i < indices.length; i++) {
var v = array[indices[i]];
if (v || v === 0 || v === '') return v;
}
};
exports.castOption = function castOption(item, indices) {
if (Lib.isArrayOrTypedArray(item)) return exports.getFirstFilled(item, indices);else if (item) return item;
};
exports.getRotationAngle = function (rotation) {
return (rotation === 'auto' ? 0 : rotation) * Math.PI / 180;
};
/***/ }),
/***/ 22584:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(99644),
supplyDefaults: (__webpack_require__(87048).supplyDefaults),
supplyLayoutDefaults: __webpack_require__(28651),
layoutAttributes: __webpack_require__(85216),
calc: (__webpack_require__(71120).calc),
crossTraceCalc: (__webpack_require__(71120).crossTraceCalc),
plot: (__webpack_require__(60476).plot),
style: __webpack_require__(72175),
styleOne: __webpack_require__(72035),
moduleType: 'trace',
name: 'pie',
basePlotModule: __webpack_require__(1688),
categories: ['pie-like', 'pie', 'showLegend'],
meta: {
description: ['A data visualized by the sectors of the pie is set in `values`.', 'The sector labels are set in `labels`.', 'The sector colors are set in `marker.colors`'].join(' ')
}
};
/***/ }),
/***/ 85216:
/***/ (function(module) {
"use strict";
module.exports = {
hiddenlabels: {
valType: 'data_array',
editType: 'calc',
description: ['hiddenlabels is the funnelarea & pie chart analog of', 'visible:\'legendonly\'', 'but it can contain many labels, and can simultaneously', 'hide slices from several pies/funnelarea charts'].join(' ')
},
piecolorway: {
valType: 'colorlist',
editType: 'calc',
description: ['Sets the default pie slice colors. Defaults to the main', '`colorway` used for trace colors. If you specify a new', 'list here it can still be extended with lighter and darker', 'colors, see `extendpiecolors`.'].join(' ')
},
extendpiecolors: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['If `true`, the pie slice colors (whether given by `piecolorway` or', 'inherited from `colorway`) will be extended to three times its', 'original length by first repeating every color 20% lighter then', 'each color 20% darker. This is intended to reduce the likelihood', 'of reusing the same color when you have many slices, but you can', 'set `false` to disable.', 'Colors provided in the trace, using `marker.colors`, are never', 'extended.'].join(' ')
}
};
/***/ }),
/***/ 28651:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(85216);
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
coerce('hiddenlabels');
coerce('piecolorway', layoutOut.colorway);
coerce('extendpiecolors');
};
/***/ }),
/***/ 60476:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Plots = __webpack_require__(19896);
var Fx = __webpack_require__(39184);
var Color = __webpack_require__(9240);
var Drawing = __webpack_require__(49348);
var Lib = __webpack_require__(10923);
var strScale = Lib.strScale;
var strTranslate = Lib.strTranslate;
var svgTextUtils = __webpack_require__(41536);
var uniformText = __webpack_require__(4096);
var recordMinTextSize = uniformText.recordMinTextSize;
var clearMinTextSize = uniformText.clearMinTextSize;
var TEXTPAD = (__webpack_require__(77216).TEXTPAD);
var helpers = __webpack_require__(27760);
var eventData = __webpack_require__(29076);
var isValidTextValue = (__webpack_require__(10923).isValidTextValue);
function plot(gd, cdModule) {
var isStatic = gd._context.staticPlot;
var fullLayout = gd._fullLayout;
var gs = fullLayout._size;
clearMinTextSize('pie', fullLayout);
prerenderTitles(cdModule, gd);
layoutAreas(cdModule, gs);
var plotGroups = Lib.makeTraceGroups(fullLayout._pielayer, cdModule, 'trace').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
setCoords(cd);
// TODO: miter might look better but can sometimes cause problems
// maybe miter with a small-ish stroke-miterlimit?
plotGroup.attr('stroke-linejoin', 'round');
plotGroup.each(function () {
var slices = d3.select(this).selectAll('g.slice').data(cd);
slices.enter().append('g').classed('slice', true);
slices.exit().remove();
var quadrants = [[[], []],
// y<0: x<0, x>=0
[[], []] // y>=0: x<0, x>=0
];
var hasOutsideText = false;
slices.each(function (pt, i) {
if (pt.hidden) {
d3.select(this).selectAll('path,g').remove();
return;
}
// to have consistent event data compared to other traces
pt.pointNumber = pt.i;
pt.curveNumber = trace.index;
quadrants[pt.pxmid[1] < 0 ? 0 : 1][pt.pxmid[0] < 0 ? 0 : 1].push(pt);
var cx = cd0.cx;
var cy = cd0.cy;
var sliceTop = d3.select(this);
var slicePath = sliceTop.selectAll('path.surface').data([pt]);
slicePath.enter().append('path').classed('surface', true).style({
'pointer-events': isStatic ? 'none' : 'all'
});
sliceTop.call(attachFxHandlers, gd, cd);
if (trace.pull) {
var pull = +helpers.castOption(trace.pull, pt.pts) || 0;
if (pull > 0) {
cx += pull * pt.pxmid[0];
cy += pull * pt.pxmid[1];
}
}
pt.cxFinal = cx;
pt.cyFinal = cy;
function arc(start, finish, cw, scale) {
var dx = scale * (finish[0] - start[0]);
var dy = scale * (finish[1] - start[1]);
return 'a' + scale * cd0.r + ',' + scale * cd0.r + ' 0 ' + pt.largeArc + (cw ? ' 1 ' : ' 0 ') + dx + ',' + dy;
}
var hole = trace.hole;
if (pt.v === cd0.vTotal) {
// 100% fails bcs arc start and end are identical
var outerCircle = 'M' + (cx + pt.px0[0]) + ',' + (cy + pt.px0[1]) + arc(pt.px0, pt.pxmid, true, 1) + arc(pt.pxmid, pt.px0, true, 1) + 'Z';
if (hole) {
slicePath.attr('d', 'M' + (cx + hole * pt.px0[0]) + ',' + (cy + hole * pt.px0[1]) + arc(pt.px0, pt.pxmid, false, hole) + arc(pt.pxmid, pt.px0, false, hole) + 'Z' + outerCircle);
} else slicePath.attr('d', outerCircle);
} else {
var outerArc = arc(pt.px0, pt.px1, true, 1);
if (hole) {
var rim = 1 - hole;
slicePath.attr('d', 'M' + (cx + hole * pt.px1[0]) + ',' + (cy + hole * pt.px1[1]) + arc(pt.px1, pt.px0, false, hole) + 'l' + rim * pt.px0[0] + ',' + rim * pt.px0[1] + outerArc + 'Z');
} else {
slicePath.attr('d', 'M' + cx + ',' + cy + 'l' + pt.px0[0] + ',' + pt.px0[1] + outerArc + 'Z');
}
}
// add text
formatSliceLabel(gd, pt, cd0);
var textPosition = helpers.castOption(trace.textposition, pt.pts);
var sliceTextGroup = sliceTop.selectAll('g.slicetext').data(pt.text && textPosition !== 'none' ? [0] : []);
sliceTextGroup.enter().append('g').classed('slicetext', true);
sliceTextGroup.exit().remove();
sliceTextGroup.each(function () {
var sliceText = Lib.ensureSingle(d3.select(this), 'text', '', function (s) {
// prohibit tex interpretation until we can handle
// tex and regular text together
s.attr('data-notex', 1);
});
var font = Lib.ensureUniformFontSize(gd, textPosition === 'outside' ? determineOutsideTextFont(trace, pt, fullLayout.font) : determineInsideTextFont(trace, pt, fullLayout.font));
sliceText.text(pt.text).attr({
class: 'slicetext',
transform: '',
'text-anchor': 'middle'
}).call(Drawing.font, font).call(svgTextUtils.convertToTspans, gd);
// position the text relative to the slice
var textBB = Drawing.bBox(sliceText.node());
var transform;
if (textPosition === 'outside') {
transform = transformOutsideText(textBB, pt);
} else {
transform = transformInsideText(textBB, pt, cd0);
if (textPosition === 'auto' && transform.scale < 1) {
var newFont = Lib.ensureUniformFontSize(gd, trace.outsidetextfont);
sliceText.call(Drawing.font, newFont);
textBB = Drawing.bBox(sliceText.node());
transform = transformOutsideText(textBB, pt);
}
}
var textPosAngle = transform.textPosAngle;
var textXY = textPosAngle === undefined ? pt.pxmid : getCoords(cd0.r, textPosAngle);
transform.targetX = cx + textXY[0] * transform.rCenter + (transform.x || 0);
transform.targetY = cy + textXY[1] * transform.rCenter + (transform.y || 0);
computeTransform(transform, textBB);
// save some stuff to use later ensure no labels overlap
if (transform.outside) {
var targetY = transform.targetY;
pt.yLabelMin = targetY - textBB.height / 2;
pt.yLabelMid = targetY;
pt.yLabelMax = targetY + textBB.height / 2;
pt.labelExtraX = 0;
pt.labelExtraY = 0;
hasOutsideText = true;
}
transform.fontSize = font.size;
recordMinTextSize(trace.type, transform, fullLayout);
cd[i].transform = transform;
Lib.setTransormAndDisplay(sliceText, transform);
});
});
// add the title
var titleTextGroup = d3.select(this).selectAll('g.titletext').data(trace.title.text ? [0] : []);
titleTextGroup.enter().append('g').classed('titletext', true);
titleTextGroup.exit().remove();
titleTextGroup.each(function () {
var titleText = Lib.ensureSingle(d3.select(this), 'text', '', function (s) {
// prohibit tex interpretation as above
s.attr('data-notex', 1);
});
var txt = trace.title.text;
if (trace._meta) {
txt = Lib.templateString(txt, trace._meta);
}
titleText.text(txt).attr({
class: 'titletext',
transform: '',
'text-anchor': 'middle'
}).call(Drawing.font, trace.title.font).call(svgTextUtils.convertToTspans, gd);
var transform;
if (trace.title.position === 'middle center') {
transform = positionTitleInside(cd0);
} else {
transform = positionTitleOutside(cd0, gs);
}
titleText.attr('transform', strTranslate(transform.x, transform.y) + strScale(Math.min(1, transform.scale)) + strTranslate(transform.tx, transform.ty));
});
// now make sure no labels overlap (at least within one pie)
if (hasOutsideText) scootLabels(quadrants, trace);
plotTextLines(slices, trace);
if (hasOutsideText && trace.automargin) {
// TODO if we ever want to improve perf,
// we could reuse the textBB computed above together
// with the sliceText transform info
var traceBbox = Drawing.bBox(plotGroup.node());
var domain = trace.domain;
var vpw = gs.w * (domain.x[1] - domain.x[0]);
var vph = gs.h * (domain.y[1] - domain.y[0]);
var xgap = (0.5 * vpw - cd0.r) / gs.w;
var ygap = (0.5 * vph - cd0.r) / gs.h;
Plots.autoMargin(gd, 'pie.' + trace.uid + '.automargin', {
xl: domain.x[0] - xgap,
xr: domain.x[1] + xgap,
yb: domain.y[0] - ygap,
yt: domain.y[1] + ygap,
l: Math.max(cd0.cx - cd0.r - traceBbox.left, 0),
r: Math.max(traceBbox.right - (cd0.cx + cd0.r), 0),
b: Math.max(traceBbox.bottom - (cd0.cy + cd0.r), 0),
t: Math.max(cd0.cy - cd0.r - traceBbox.top, 0),
pad: 5
});
}
});
});
// This is for a bug in Chrome (as of 2015-07-22, and does not affect FF)
// if insidetextfont and outsidetextfont are different sizes, sometimes the size
// of an "em" gets taken from the wrong element at first so lines are
// spaced wrong. You just have to tell it to try again later and it gets fixed.
// I have no idea why we haven't seen this in other contexts. Also, sometimes
// it gets the initial draw correct but on redraw it gets confused.
setTimeout(function () {
plotGroups.selectAll('tspan').each(function () {
var s = d3.select(this);
if (s.attr('dy')) s.attr('dy', s.attr('dy'));
});
}, 0);
}
// TODO add support for transition
function plotTextLines(slices, trace) {
slices.each(function (pt) {
var sliceTop = d3.select(this);
if (!pt.labelExtraX && !pt.labelExtraY) {
sliceTop.select('path.textline').remove();
return;
}
// first move the text to its new location
var sliceText = sliceTop.select('g.slicetext text');
pt.transform.targetX += pt.labelExtraX;
pt.transform.targetY += pt.labelExtraY;
Lib.setTransormAndDisplay(sliceText, pt.transform);
// then add a line to the new location
var lineStartX = pt.cxFinal + pt.pxmid[0];
var lineStartY = pt.cyFinal + pt.pxmid[1];
var textLinePath = 'M' + lineStartX + ',' + lineStartY;
var finalX = (pt.yLabelMax - pt.yLabelMin) * (pt.pxmid[0] < 0 ? -1 : 1) / 4;
if (pt.labelExtraX) {
var yFromX = pt.labelExtraX * pt.pxmid[1] / pt.pxmid[0];
var yNet = pt.yLabelMid + pt.labelExtraY - (pt.cyFinal + pt.pxmid[1]);
if (Math.abs(yFromX) > Math.abs(yNet)) {
textLinePath += 'l' + yNet * pt.pxmid[0] / pt.pxmid[1] + ',' + yNet + 'H' + (lineStartX + pt.labelExtraX + finalX);
} else {
textLinePath += 'l' + pt.labelExtraX + ',' + yFromX + 'v' + (yNet - yFromX) + 'h' + finalX;
}
} else {
textLinePath += 'V' + (pt.yLabelMid + pt.labelExtraY) + 'h' + finalX;
}
Lib.ensureSingle(sliceTop, 'path', 'textline').call(Color.stroke, trace.outsidetextfont.color).attr({
'stroke-width': Math.min(2, trace.outsidetextfont.size / 8),
d: textLinePath,
fill: 'none'
});
});
}
function attachFxHandlers(sliceTop, gd, cd) {
var cd0 = cd[0];
var cx = cd0.cx;
var cy = cd0.cy;
var trace = cd0.trace;
var isFunnelArea = trace.type === 'funnelarea';
// hover state vars
// have we drawn a hover label, so it should be cleared later
if (!('_hasHoverLabel' in trace)) trace._hasHoverLabel = false;
// have we emitted a hover event, so later an unhover event should be emitted
// note that click events do not depend on this - you can still get them
// with hovermode: false or if you were earlier dragging, then clicked
// in the same slice that you moused up in
if (!('_hasHoverEvent' in trace)) trace._hasHoverEvent = false;
sliceTop.on('mouseover', function (pt) {
// in case fullLayout or fullData has changed without a replot
var fullLayout2 = gd._fullLayout;
var trace2 = gd._fullData[trace.index];
if (gd._dragging || fullLayout2.hovermode === false) return;
var hoverinfo = trace2.hoverinfo;
if (Array.isArray(hoverinfo)) {
// super hacky: we need to pull out the *first* hoverinfo from
// pt.pts, then put it back into an array in a dummy trace
// and call castHoverinfo on that.
// TODO: do we want to have Fx.castHoverinfo somehow handle this?
// it already takes an array for index, for 2D, so this seems tricky.
hoverinfo = Fx.castHoverinfo({
hoverinfo: [helpers.castOption(hoverinfo, pt.pts)],
_module: trace._module
}, fullLayout2, 0);
}
if (hoverinfo === 'all') hoverinfo = 'label+text+value+percent+name';
// in case we dragged over the pie from another subplot,
// or if hover is turned off
if (trace2.hovertemplate || hoverinfo !== 'none' && hoverinfo !== 'skip' && hoverinfo) {
var rInscribed = pt.rInscribed || 0;
var hoverCenterX = cx + pt.pxmid[0] * (1 - rInscribed);
var hoverCenterY = cy + pt.pxmid[1] * (1 - rInscribed);
var separators = fullLayout2.separators;
var text = [];
if (hoverinfo && hoverinfo.indexOf('label') !== -1) text.push(pt.label);
pt.text = helpers.castOption(trace2.hovertext || trace2.text, pt.pts);
if (hoverinfo && hoverinfo.indexOf('text') !== -1) {
var tx = pt.text;
if (Lib.isValidTextValue(tx)) text.push(tx);
}
pt.value = pt.v;
pt.valueLabel = helpers.formatPieValue(pt.v, separators);
if (hoverinfo && hoverinfo.indexOf('value') !== -1) text.push(pt.valueLabel);
pt.percent = pt.v / cd0.vTotal;
pt.percentLabel = helpers.formatPiePercent(pt.percent, separators);
if (hoverinfo && hoverinfo.indexOf('percent') !== -1) text.push(pt.percentLabel);
var hoverLabel = trace2.hoverlabel;
var hoverFont = hoverLabel.font;
var bbox = [];
Fx.loneHover({
trace: trace,
x0: hoverCenterX - rInscribed * cd0.r,
x1: hoverCenterX + rInscribed * cd0.r,
y: hoverCenterY,
_x0: isFunnelArea ? cx + pt.TL[0] : hoverCenterX - rInscribed * cd0.r,
_x1: isFunnelArea ? cx + pt.TR[0] : hoverCenterX + rInscribed * cd0.r,
_y0: isFunnelArea ? cy + pt.TL[1] : hoverCenterY - rInscribed * cd0.r,
_y1: isFunnelArea ? cy + pt.BL[1] : hoverCenterY + rInscribed * cd0.r,
text: text.join('
'),
name: trace2.hovertemplate || hoverinfo.indexOf('name') !== -1 ? trace2.name : undefined,
idealAlign: pt.pxmid[0] < 0 ? 'left' : 'right',
color: helpers.castOption(hoverLabel.bgcolor, pt.pts) || pt.color,
borderColor: helpers.castOption(hoverLabel.bordercolor, pt.pts),
fontFamily: helpers.castOption(hoverFont.family, pt.pts),
fontSize: helpers.castOption(hoverFont.size, pt.pts),
fontColor: helpers.castOption(hoverFont.color, pt.pts),
nameLength: helpers.castOption(hoverLabel.namelength, pt.pts),
textAlign: helpers.castOption(hoverLabel.align, pt.pts),
hovertemplate: helpers.castOption(trace2.hovertemplate, pt.pts),
hovertemplateLabels: pt,
eventData: [eventData(pt, trace2)]
}, {
container: fullLayout2._hoverlayer.node(),
outerContainer: fullLayout2._paper.node(),
gd: gd,
inOut_bbox: bbox
});
pt.bbox = bbox[0];
trace._hasHoverLabel = true;
}
trace._hasHoverEvent = true;
gd.emit('plotly_hover', {
points: [eventData(pt, trace2)],
event: d3.event
});
});
sliceTop.on('mouseout', function (evt) {
var fullLayout2 = gd._fullLayout;
var trace2 = gd._fullData[trace.index];
var pt = d3.select(this).datum();
if (trace._hasHoverEvent) {
evt.originalEvent = d3.event;
gd.emit('plotly_unhover', {
points: [eventData(pt, trace2)],
event: d3.event
});
trace._hasHoverEvent = false;
}
if (trace._hasHoverLabel) {
Fx.loneUnhover(fullLayout2._hoverlayer.node());
trace._hasHoverLabel = false;
}
});
sliceTop.on('click', function (pt) {
// TODO: this does not support right-click. If we want to support it, we
// would likely need to change pie to use dragElement instead of straight
// mapbox event binding. Or perhaps better, make a simple wrapper with the
// right mousedown, mousemove, and mouseup handlers just for a left/right click
// mapbox would use this too.
var fullLayout2 = gd._fullLayout;
var trace2 = gd._fullData[trace.index];
if (gd._dragging || fullLayout2.hovermode === false) return;
gd._hoverdata = [eventData(pt, trace2)];
Fx.click(gd, d3.event);
});
}
function determineOutsideTextFont(trace, pt, layoutFont) {
var color = helpers.castOption(trace.outsidetextfont.color, pt.pts) || helpers.castOption(trace.textfont.color, pt.pts) || layoutFont.color;
var family = helpers.castOption(trace.outsidetextfont.family, pt.pts) || helpers.castOption(trace.textfont.family, pt.pts) || layoutFont.family;
var size = helpers.castOption(trace.outsidetextfont.size, pt.pts) || helpers.castOption(trace.textfont.size, pt.pts) || layoutFont.size;
return {
color: color,
family: family,
size: size
};
}
function determineInsideTextFont(trace, pt, layoutFont) {
var customColor = helpers.castOption(trace.insidetextfont.color, pt.pts);
if (!customColor && trace._input.textfont) {
// Why not simply using trace.textfont? Because if not set, it
// defaults to layout.font which has a default color. But if
// textfont.color and insidetextfont.color don't supply a value,
// a contrasting color shall be used.
customColor = helpers.castOption(trace._input.textfont.color, pt.pts);
}
var family = helpers.castOption(trace.insidetextfont.family, pt.pts) || helpers.castOption(trace.textfont.family, pt.pts) || layoutFont.family;
var size = helpers.castOption(trace.insidetextfont.size, pt.pts) || helpers.castOption(trace.textfont.size, pt.pts) || layoutFont.size;
return {
color: customColor || Color.contrast(pt.color),
family: family,
size: size
};
}
function prerenderTitles(cdModule, gd) {
var cd0, trace;
// Determine the width and height of the title for each pie.
for (var i = 0; i < cdModule.length; i++) {
cd0 = cdModule[i][0];
trace = cd0.trace;
if (trace.title.text) {
var txt = trace.title.text;
if (trace._meta) {
txt = Lib.templateString(txt, trace._meta);
}
var dummyTitle = Drawing.tester.append('text').attr('data-notex', 1).text(txt).call(Drawing.font, trace.title.font).call(svgTextUtils.convertToTspans, gd);
var bBox = Drawing.bBox(dummyTitle.node(), true);
cd0.titleBox = {
width: bBox.width,
height: bBox.height
};
dummyTitle.remove();
}
}
}
function transformInsideText(textBB, pt, cd0) {
var r = cd0.r || pt.rpx1;
var rInscribed = pt.rInscribed;
var isEmpty = pt.startangle === pt.stopangle;
if (isEmpty) {
return {
rCenter: 1 - rInscribed,
scale: 0,
rotate: 0,
textPosAngle: 0
};
}
var ring = pt.ring;
var isCircle = ring === 1 && Math.abs(pt.startangle - pt.stopangle) === Math.PI * 2;
var halfAngle = pt.halfangle;
var midAngle = pt.midangle;
var orientation = cd0.trace.insidetextorientation;
var isHorizontal = orientation === 'horizontal';
var isTangential = orientation === 'tangential';
var isRadial = orientation === 'radial';
var isAuto = orientation === 'auto';
var allTransforms = [];
var newT;
if (!isAuto) {
// max size if text is placed (horizontally) at the top or bottom of the arc
var considerCrossing = function (angle, key) {
if (isCrossing(pt, angle)) {
var dStart = Math.abs(angle - pt.startangle);
var dStop = Math.abs(angle - pt.stopangle);
var closestEdge = dStart < dStop ? dStart : dStop;
if (key === 'tan') {
newT = calcTanTransform(textBB, r, ring, closestEdge, 0);
} else {
// case of 'rad'
newT = calcRadTransform(textBB, r, ring, closestEdge, Math.PI / 2);
}
newT.textPosAngle = angle;
allTransforms.push(newT);
}
};
// to cover all cases with trace.rotation added
var i;
if (isHorizontal || isTangential) {
// top
for (i = 4; i >= -4; i -= 2) considerCrossing(Math.PI * i, 'tan');
// bottom
for (i = 4; i >= -4; i -= 2) considerCrossing(Math.PI * (i + 1), 'tan');
}
if (isHorizontal || isRadial) {
// left
for (i = 4; i >= -4; i -= 2) considerCrossing(Math.PI * (i + 1.5), 'rad');
// right
for (i = 4; i >= -4; i -= 2) considerCrossing(Math.PI * (i + 0.5), 'rad');
}
}
if (isCircle || isAuto || isHorizontal) {
// max size text can be inserted inside without rotating it
// this inscribes the text rectangle in a circle, which is then inscribed
// in the slice, so it will be an underestimate, which some day we may want
// to improve so this case can get more use
var textDiameter = Math.sqrt(textBB.width * textBB.width + textBB.height * textBB.height);
newT = {
scale: rInscribed * r * 2 / textDiameter,
// and the center position and rotation in this case
rCenter: 1 - rInscribed,
rotate: 0
};
newT.textPosAngle = (pt.startangle + pt.stopangle) / 2;
if (newT.scale >= 1) return newT;
allTransforms.push(newT);
}
if (isAuto || isRadial) {
newT = calcRadTransform(textBB, r, ring, halfAngle, midAngle);
newT.textPosAngle = (pt.startangle + pt.stopangle) / 2;
allTransforms.push(newT);
}
if (isAuto || isTangential) {
newT = calcTanTransform(textBB, r, ring, halfAngle, midAngle);
newT.textPosAngle = (pt.startangle + pt.stopangle) / 2;
allTransforms.push(newT);
}
var id = 0;
var maxScale = 0;
for (var k = 0; k < allTransforms.length; k++) {
var s = allTransforms[k].scale;
if (maxScale < s) {
maxScale = s;
id = k;
}
if (!isAuto && maxScale >= 1) {
// respect test order for non-auto options
break;
}
}
return allTransforms[id];
}
function isCrossing(pt, angle) {
var start = pt.startangle;
var stop = pt.stopangle;
return start > angle && angle > stop || start < angle && angle < stop;
}
function calcRadTransform(textBB, r, ring, halfAngle, midAngle) {
r = Math.max(0, r - 2 * TEXTPAD);
// max size if text is rotated radially
var a = textBB.width / textBB.height;
var s = calcMaxHalfSize(a, halfAngle, r, ring);
return {
scale: s * 2 / textBB.height,
rCenter: calcRCenter(a, s / r),
rotate: calcRotate(midAngle)
};
}
function calcTanTransform(textBB, r, ring, halfAngle, midAngle) {
r = Math.max(0, r - 2 * TEXTPAD);
// max size if text is rotated tangentially
var a = textBB.height / textBB.width;
var s = calcMaxHalfSize(a, halfAngle, r, ring);
return {
scale: s * 2 / textBB.width,
rCenter: calcRCenter(a, s / r),
rotate: calcRotate(midAngle + Math.PI / 2)
};
}
function calcRCenter(a, b) {
return Math.cos(b) - a * b;
}
function calcRotate(t) {
return (180 / Math.PI * t + 720) % 180 - 90;
}
function calcMaxHalfSize(a, halfAngle, r, ring) {
var q = a + 1 / (2 * Math.tan(halfAngle));
return r * Math.min(1 / (Math.sqrt(q * q + 0.5) + q), ring / (Math.sqrt(a * a + ring / 2) + a));
}
function getInscribedRadiusFraction(pt, cd0) {
if (pt.v === cd0.vTotal && !cd0.trace.hole) return 1; // special case of 100% with no hole
return Math.min(1 / (1 + 1 / Math.sin(pt.halfangle)), pt.ring / 2);
}
function transformOutsideText(textBB, pt) {
var x = pt.pxmid[0];
var y = pt.pxmid[1];
var dx = textBB.width / 2;
var dy = textBB.height / 2;
if (x < 0) dx *= -1;
if (y < 0) dy *= -1;
return {
scale: 1,
rCenter: 1,
rotate: 0,
x: dx + Math.abs(dy) * (dx > 0 ? 1 : -1) / 2,
y: dy / (1 + x * x / (y * y)),
outside: true
};
}
function positionTitleInside(cd0) {
var textDiameter = Math.sqrt(cd0.titleBox.width * cd0.titleBox.width + cd0.titleBox.height * cd0.titleBox.height);
return {
x: cd0.cx,
y: cd0.cy,
scale: cd0.trace.hole * cd0.r * 2 / textDiameter,
tx: 0,
ty: -cd0.titleBox.height / 2 + cd0.trace.title.font.size
};
}
function positionTitleOutside(cd0, plotSize) {
var scaleX = 1;
var scaleY = 1;
var maxPull;
var trace = cd0.trace;
// position of the baseline point of the text box in the plot, before scaling.
// we anchored the text in the middle, so the baseline is on the bottom middle
// of the first line of text.
var topMiddle = {
x: cd0.cx,
y: cd0.cy
};
// relative translation of the text box after scaling
var translate = {
tx: 0,
ty: 0
};
// we reason below as if the baseline is the top middle point of the text box.
// so we must add the font size to approximate the y-coord. of the top.
// note that this correction must happen after scaling.
translate.ty += trace.title.font.size;
maxPull = getMaxPull(trace);
if (trace.title.position.indexOf('top') !== -1) {
topMiddle.y -= (1 + maxPull) * cd0.r;
translate.ty -= cd0.titleBox.height;
} else if (trace.title.position.indexOf('bottom') !== -1) {
topMiddle.y += (1 + maxPull) * cd0.r;
}
var rx = applyAspectRatio(cd0.r, cd0.trace.aspectratio);
var maxWidth = plotSize.w * (trace.domain.x[1] - trace.domain.x[0]) / 2;
if (trace.title.position.indexOf('left') !== -1) {
// we start the text at the left edge of the pie
maxWidth = maxWidth + rx;
topMiddle.x -= (1 + maxPull) * rx;
translate.tx += cd0.titleBox.width / 2;
} else if (trace.title.position.indexOf('center') !== -1) {
maxWidth *= 2;
} else if (trace.title.position.indexOf('right') !== -1) {
maxWidth = maxWidth + rx;
topMiddle.x += (1 + maxPull) * rx;
translate.tx -= cd0.titleBox.width / 2;
}
scaleX = maxWidth / cd0.titleBox.width;
scaleY = getTitleSpace(cd0, plotSize) / cd0.titleBox.height;
return {
x: topMiddle.x,
y: topMiddle.y,
scale: Math.min(scaleX, scaleY),
tx: translate.tx,
ty: translate.ty
};
}
function applyAspectRatio(x, aspectratio) {
return x / (aspectratio === undefined ? 1 : aspectratio);
}
function getTitleSpace(cd0, plotSize) {
var trace = cd0.trace;
var pieBoxHeight = plotSize.h * (trace.domain.y[1] - trace.domain.y[0]);
// use at most half of the plot for the title
return Math.min(cd0.titleBox.height, pieBoxHeight / 2);
}
function getMaxPull(trace) {
var maxPull = trace.pull;
if (!maxPull) return 0;
var j;
if (Lib.isArrayOrTypedArray(maxPull)) {
maxPull = 0;
for (j = 0; j < trace.pull.length; j++) {
if (trace.pull[j] > maxPull) maxPull = trace.pull[j];
}
}
return maxPull;
}
function scootLabels(quadrants, trace) {
var xHalf, yHalf, equatorFirst, farthestX, farthestY, xDiffSign, yDiffSign, thisQuad, oppositeQuad, wholeSide, i, thisQuadOutside, firstOppositeOutsidePt;
function topFirst(a, b) {
return a.pxmid[1] - b.pxmid[1];
}
function bottomFirst(a, b) {
return b.pxmid[1] - a.pxmid[1];
}
function scootOneLabel(thisPt, prevPt) {
if (!prevPt) prevPt = {};
var prevOuterY = prevPt.labelExtraY + (yHalf ? prevPt.yLabelMax : prevPt.yLabelMin);
var thisInnerY = yHalf ? thisPt.yLabelMin : thisPt.yLabelMax;
var thisOuterY = yHalf ? thisPt.yLabelMax : thisPt.yLabelMin;
var thisSliceOuterY = thisPt.cyFinal + farthestY(thisPt.px0[1], thisPt.px1[1]);
var newExtraY = prevOuterY - thisInnerY;
var xBuffer, i, otherPt, otherOuterY, otherOuterX, newExtraX;
// make sure this label doesn't overlap other labels
// this *only* has us move these labels vertically
if (newExtraY * yDiffSign > 0) thisPt.labelExtraY = newExtraY;
// make sure this label doesn't overlap any slices
if (!Lib.isArrayOrTypedArray(trace.pull)) return; // this can only happen with array pulls
for (i = 0; i < wholeSide.length; i++) {
otherPt = wholeSide[i];
// overlap can only happen if the other point is pulled more than this one
if (otherPt === thisPt || (helpers.castOption(trace.pull, thisPt.pts) || 0) >= (helpers.castOption(trace.pull, otherPt.pts) || 0)) {
continue;
}
if ((thisPt.pxmid[1] - otherPt.pxmid[1]) * yDiffSign > 0) {
// closer to the equator - by construction all of these happen first
// move the text vertically to get away from these slices
otherOuterY = otherPt.cyFinal + farthestY(otherPt.px0[1], otherPt.px1[1]);
newExtraY = otherOuterY - thisInnerY - thisPt.labelExtraY;
if (newExtraY * yDiffSign > 0) thisPt.labelExtraY += newExtraY;
} else if ((thisOuterY + thisPt.labelExtraY - thisSliceOuterY) * yDiffSign > 0) {
// farther from the equator - happens after we've done all the
// vertical moving we're going to do
// move horizontally to get away from these more polar slices
// if we're moving horz. based on a slice that's several slices away from this one
// then we need some extra space for the lines to labels between them
xBuffer = 3 * xDiffSign * Math.abs(i - wholeSide.indexOf(thisPt));
otherOuterX = otherPt.cxFinal + farthestX(otherPt.px0[0], otherPt.px1[0]);
newExtraX = otherOuterX + xBuffer - (thisPt.cxFinal + thisPt.pxmid[0]) - thisPt.labelExtraX;
if (newExtraX * xDiffSign > 0) thisPt.labelExtraX += newExtraX;
}
}
}
for (yHalf = 0; yHalf < 2; yHalf++) {
equatorFirst = yHalf ? topFirst : bottomFirst;
farthestY = yHalf ? Math.max : Math.min;
yDiffSign = yHalf ? 1 : -1;
for (xHalf = 0; xHalf < 2; xHalf++) {
farthestX = xHalf ? Math.max : Math.min;
xDiffSign = xHalf ? 1 : -1;
// first sort the array
// note this is a copy of cd, so cd itself doesn't get sorted
// but we can still modify points in place.
thisQuad = quadrants[yHalf][xHalf];
thisQuad.sort(equatorFirst);
oppositeQuad = quadrants[1 - yHalf][xHalf];
wholeSide = oppositeQuad.concat(thisQuad);
thisQuadOutside = [];
for (i = 0; i < thisQuad.length; i++) {
if (thisQuad[i].yLabelMid !== undefined) thisQuadOutside.push(thisQuad[i]);
}
firstOppositeOutsidePt = false;
for (i = 0; yHalf && i < oppositeQuad.length; i++) {
if (oppositeQuad[i].yLabelMid !== undefined) {
firstOppositeOutsidePt = oppositeQuad[i];
break;
}
}
// each needs to avoid the previous
for (i = 0; i < thisQuadOutside.length; i++) {
var prevPt = i && thisQuadOutside[i - 1];
// bottom half needs to avoid the first label of the top half
// top half we still need to call scootOneLabel on the first slice
// so we can avoid other slices, but we don't pass a prevPt
if (firstOppositeOutsidePt && !i) prevPt = firstOppositeOutsidePt;
scootOneLabel(thisQuadOutside[i], prevPt);
}
}
}
}
function layoutAreas(cdModule, plotSize) {
var scaleGroups = [];
// figure out the center and maximum radius
for (var i = 0; i < cdModule.length; i++) {
var cd0 = cdModule[i][0];
var trace = cd0.trace;
var domain = trace.domain;
var width = plotSize.w * (domain.x[1] - domain.x[0]);
var height = plotSize.h * (domain.y[1] - domain.y[0]);
// leave some space for the title, if it will be displayed outside
if (trace.title.text && trace.title.position !== 'middle center') {
height -= getTitleSpace(cd0, plotSize);
}
var rx = width / 2;
var ry = height / 2;
if (trace.type === 'funnelarea' && !trace.scalegroup) {
ry /= trace.aspectratio;
}
cd0.r = Math.min(rx, ry) / (1 + getMaxPull(trace));
cd0.cx = plotSize.l + plotSize.w * (trace.domain.x[1] + trace.domain.x[0]) / 2;
cd0.cy = plotSize.t + plotSize.h * (1 - trace.domain.y[0]) - height / 2;
if (trace.title.text && trace.title.position.indexOf('bottom') !== -1) {
cd0.cy -= getTitleSpace(cd0, plotSize);
}
if (trace.scalegroup && scaleGroups.indexOf(trace.scalegroup) === -1) {
scaleGroups.push(trace.scalegroup);
}
}
groupScale(cdModule, scaleGroups);
}
function groupScale(cdModule, scaleGroups) {
var cd0, i, trace;
// scale those that are grouped
for (var k = 0; k < scaleGroups.length; k++) {
var min = Infinity;
var g = scaleGroups[k];
for (i = 0; i < cdModule.length; i++) {
cd0 = cdModule[i][0];
trace = cd0.trace;
if (trace.scalegroup === g) {
var area;
if (trace.type === 'pie') {
area = cd0.r * cd0.r;
} else if (trace.type === 'funnelarea') {
var rx, ry;
if (trace.aspectratio > 1) {
rx = cd0.r;
ry = rx / trace.aspectratio;
} else {
ry = cd0.r;
rx = ry * trace.aspectratio;
}
rx *= (1 + trace.baseratio) / 2;
area = rx * ry;
}
min = Math.min(min, area / cd0.vTotal);
}
}
for (i = 0; i < cdModule.length; i++) {
cd0 = cdModule[i][0];
trace = cd0.trace;
if (trace.scalegroup === g) {
var v = min * cd0.vTotal;
if (trace.type === 'funnelarea') {
v /= (1 + trace.baseratio) / 2;
v /= trace.aspectratio;
}
cd0.r = Math.sqrt(v);
}
}
}
}
function setCoords(cd) {
var cd0 = cd[0];
var r = cd0.r;
var trace = cd0.trace;
var currentAngle = helpers.getRotationAngle(trace.rotation);
var angleFactor = 2 * Math.PI / cd0.vTotal;
var firstPt = 'px0';
var lastPt = 'px1';
var i, cdi, currentCoords;
if (trace.direction === 'counterclockwise') {
for (i = 0; i < cd.length; i++) {
if (!cd[i].hidden) break; // find the first non-hidden slice
}
if (i === cd.length) return; // all slices hidden
currentAngle += angleFactor * cd[i].v;
angleFactor *= -1;
firstPt = 'px1';
lastPt = 'px0';
}
currentCoords = getCoords(r, currentAngle);
for (i = 0; i < cd.length; i++) {
cdi = cd[i];
if (cdi.hidden) continue;
cdi[firstPt] = currentCoords;
cdi.startangle = currentAngle;
currentAngle += angleFactor * cdi.v / 2;
cdi.pxmid = getCoords(r, currentAngle);
cdi.midangle = currentAngle;
currentAngle += angleFactor * cdi.v / 2;
currentCoords = getCoords(r, currentAngle);
cdi.stopangle = currentAngle;
cdi[lastPt] = currentCoords;
cdi.largeArc = cdi.v > cd0.vTotal / 2 ? 1 : 0;
cdi.halfangle = Math.PI * Math.min(cdi.v / cd0.vTotal, 0.5);
cdi.ring = 1 - trace.hole;
cdi.rInscribed = getInscribedRadiusFraction(cdi, cd0);
}
}
function getCoords(r, angle) {
return [r * Math.sin(angle), -r * Math.cos(angle)];
}
function formatSliceLabel(gd, pt, cd0) {
var fullLayout = gd._fullLayout;
var trace = cd0.trace;
// look for textemplate
var texttemplate = trace.texttemplate;
// now insert text
var textinfo = trace.textinfo;
if (!texttemplate && textinfo && textinfo !== 'none') {
var parts = textinfo.split('+');
var hasFlag = function (flag) {
return parts.indexOf(flag) !== -1;
};
var hasLabel = hasFlag('label');
var hasText = hasFlag('text');
var hasValue = hasFlag('value');
var hasPercent = hasFlag('percent');
var separators = fullLayout.separators;
var text;
text = hasLabel ? [pt.label] : [];
if (hasText) {
var tx = helpers.getFirstFilled(trace.text, pt.pts);
if (isValidTextValue(tx)) text.push(tx);
}
if (hasValue) text.push(helpers.formatPieValue(pt.v, separators));
if (hasPercent) text.push(helpers.formatPiePercent(pt.v / cd0.vTotal, separators));
pt.text = text.join('
');
}
function makeTemplateVariables(pt) {
return {
label: pt.label,
value: pt.v,
valueLabel: helpers.formatPieValue(pt.v, fullLayout.separators),
percent: pt.v / cd0.vTotal,
percentLabel: helpers.formatPiePercent(pt.v / cd0.vTotal, fullLayout.separators),
color: pt.color,
text: pt.text,
customdata: Lib.castOption(trace, pt.i, 'customdata')
};
}
if (texttemplate) {
var txt = Lib.castOption(trace, pt.i, 'texttemplate');
if (!txt) {
pt.text = '';
} else {
var obj = makeTemplateVariables(pt);
var ptTx = helpers.getFirstFilled(trace.text, pt.pts);
if (isValidTextValue(ptTx) || ptTx === '') obj.text = ptTx;
pt.text = Lib.texttemplateString(txt, obj, gd._fullLayout._d3locale, obj, trace._meta || {});
}
}
}
function computeTransform(transform,
// inout
textBB // in
) {
var a = transform.rotate * Math.PI / 180;
var cosA = Math.cos(a);
var sinA = Math.sin(a);
var midX = (textBB.left + textBB.right) / 2;
var midY = (textBB.top + textBB.bottom) / 2;
transform.textX = midX * cosA - midY * sinA;
transform.textY = midX * sinA + midY * cosA;
transform.noCenter = true;
}
module.exports = {
plot: plot,
formatSliceLabel: formatSliceLabel,
transformInsideText: transformInsideText,
determineInsideTextFont: determineInsideTextFont,
positionTitleOutside: positionTitleOutside,
prerenderTitles: prerenderTitles,
layoutAreas: layoutAreas,
attachFxHandlers: attachFxHandlers,
computeTransform: computeTransform
};
/***/ }),
/***/ 72175:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var styleOne = __webpack_require__(72035);
var resizeText = (__webpack_require__(4096).resizeText);
module.exports = function style(gd) {
var s = gd._fullLayout._pielayer.selectAll('.trace');
resizeText(gd, s, 'pie');
s.each(function (cd) {
var cd0 = cd[0];
var trace = cd0.trace;
var traceSelection = d3.select(this);
traceSelection.style({
opacity: trace.opacity
});
traceSelection.selectAll('path.surface').each(function (pt) {
d3.select(this).call(styleOne, pt, trace, gd);
});
});
};
/***/ }),
/***/ 72035:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Color = __webpack_require__(9240);
var castOption = (__webpack_require__(27760).castOption);
var fillOne = __webpack_require__(19464);
module.exports = function styleOne(s, pt, trace, gd) {
var line = trace.marker.line;
var lineColor = castOption(line.color, pt.pts) || Color.defaultLine;
var lineWidth = castOption(line.width, pt.pts) || 0;
s.call(fillOne, pt, trace, gd).style('stroke-width', lineWidth).call(Color.stroke, lineColor);
};
/***/ }),
/***/ 75736:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterglAttrs = __webpack_require__(49992);
module.exports = {
x: scatterglAttrs.x,
y: scatterglAttrs.y,
xy: {
valType: 'data_array',
editType: 'calc',
description: ['Faster alternative to specifying `x` and `y` separately.', 'If supplied, it must be a typed `Float32Array` array that', 'represents points such that `xy[i * 2] = x[i]` and `xy[i * 2 + 1] = y[i]`'].join(' ')
},
indices: {
valType: 'data_array',
editType: 'calc',
description: ['A sequential value, 0..n, supply it to avoid creating this array inside plotting.', 'If specified, it must be a typed `Int32Array` array.', 'Its length must be equal to or greater than the number of points.', 'For the best performance and memory use, create one large `indices` typed array', 'that is guaranteed to be at least as long as the largest number of points during', 'use, and reuse it on each `Plotly.restyle()` call.'].join(' ')
},
xbounds: {
valType: 'data_array',
editType: 'calc',
description: ['Specify `xbounds` in the shape of `[xMin, xMax] to avoid looping through', 'the `xy` typed array. Use it in conjunction with `xy` and `ybounds` for the performance benefits.'].join(' ')
},
ybounds: {
valType: 'data_array',
editType: 'calc',
description: ['Specify `ybounds` in the shape of `[yMin, yMax] to avoid looping through', 'the `xy` typed array. Use it in conjunction with `xy` and `xbounds` for the performance benefits.'].join(' ')
},
text: scatterglAttrs.text,
marker: {
color: {
valType: 'color',
arrayOk: false,
editType: 'calc',
description: ['Sets the marker fill color. It accepts a specific color.', 'If the color is not fully opaque and there are hundreds of thousands', 'of points, it may cause slower zooming and panning.'].join(' ')
},
opacity: {
valType: 'number',
min: 0,
max: 1,
dflt: 1,
arrayOk: false,
editType: 'calc',
description: ['Sets the marker opacity. The default value is `1` (fully opaque).', 'If the markers are not fully opaque and there are hundreds of thousands', 'of points, it may cause slower zooming and panning.', 'Opacity fades the color even if `blend` is left on `false` even if there', 'is no translucency effect in that case.'].join(' ')
},
blend: {
valType: 'boolean',
dflt: null,
editType: 'calc',
description: ['Determines if colors are blended together for a translucency effect', 'in case `opacity` is specified as a value less then `1`.', 'Setting `blend` to `true` reduces zoom/pan', 'speed if used with large numbers of points.'].join(' ')
},
sizemin: {
valType: 'number',
min: 0.1,
max: 2,
dflt: 0.5,
editType: 'calc',
description: ['Sets the minimum size (in px) of the rendered marker points, effective when', 'the `pointcloud` shows a million or more points.'].join(' ')
},
sizemax: {
valType: 'number',
min: 0.1,
dflt: 20,
editType: 'calc',
description: ['Sets the maximum size (in px) of the rendered marker points.', 'Effective when the `pointcloud` shows only few points.'].join(' ')
},
border: {
color: {
valType: 'color',
arrayOk: false,
editType: 'calc',
description: ['Sets the stroke color. It accepts a specific color.', 'If the color is not fully opaque and there are hundreds of thousands', 'of points, it may cause slower zooming and panning.'].join(' ')
},
arearatio: {
valType: 'number',
min: 0,
max: 1,
dflt: 0,
editType: 'calc',
description: ['Specifies what fraction of the marker area is covered with the', 'border.'].join(' ')
},
editType: 'calc'
},
editType: 'calc'
},
transforms: undefined
};
/***/ }),
/***/ 29684:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createPointCloudRenderer = (__webpack_require__(14656).gl_pointcloud2d);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var str2RGBArray = __webpack_require__(29864);
var findExtremes = (__webpack_require__(66044).findExtremes);
var getTraceColor = __webpack_require__(85600);
function Pointcloud(scene, uid) {
this.scene = scene;
this.uid = uid;
this.type = 'pointcloud';
this.pickXData = [];
this.pickYData = [];
this.xData = [];
this.yData = [];
this.textLabels = [];
this.color = 'rgb(0, 0, 0)';
this.name = '';
this.hoverinfo = 'all';
this.idToIndex = new Int32Array(0);
this.bounds = [0, 0, 0, 0];
this.pointcloudOptions = {
positions: new Float32Array(0),
idToIndex: this.idToIndex,
sizemin: 0.5,
sizemax: 12,
color: [0, 0, 0, 1],
areaRatio: 1,
borderColor: [0, 0, 0, 1]
};
this.pointcloud = createPointCloudRenderer(scene.glplot, this.pointcloudOptions);
this.pointcloud._trace = this; // scene2d requires this prop
}
var proto = Pointcloud.prototype;
proto.handlePick = function (pickResult) {
var index = this.idToIndex[pickResult.pointId];
// prefer the readout from XY, if present
return {
trace: this,
dataCoord: pickResult.dataCoord,
traceCoord: this.pickXYData ? [this.pickXYData[index * 2], this.pickXYData[index * 2 + 1]] : [this.pickXData[index], this.pickYData[index]],
textLabel: isArrayOrTypedArray(this.textLabels) ? this.textLabels[index] : this.textLabels,
color: this.color,
name: this.name,
pointIndex: index,
hoverinfo: this.hoverinfo
};
};
proto.update = function (options) {
this.index = options.index;
this.textLabels = options.text;
this.name = options.name;
this.hoverinfo = options.hoverinfo;
this.bounds = [Infinity, Infinity, -Infinity, -Infinity];
this.updateFast(options);
this.color = getTraceColor(options, {});
};
proto.updateFast = function (options) {
var x = this.xData = this.pickXData = options.x;
var y = this.yData = this.pickYData = options.y;
var xy = this.pickXYData = options.xy;
var userBounds = options.xbounds && options.ybounds;
var index = options.indices;
var len;
var idToIndex;
var positions;
var bounds = this.bounds;
var xx, yy, i;
if (xy) {
positions = xy;
// dividing xy.length by 2 and truncating to integer if xy.length was not even
len = xy.length >>> 1;
if (userBounds) {
bounds[0] = options.xbounds[0];
bounds[2] = options.xbounds[1];
bounds[1] = options.ybounds[0];
bounds[3] = options.ybounds[1];
} else {
for (i = 0; i < len; i++) {
xx = positions[i * 2];
yy = positions[i * 2 + 1];
if (xx < bounds[0]) bounds[0] = xx;
if (xx > bounds[2]) bounds[2] = xx;
if (yy < bounds[1]) bounds[1] = yy;
if (yy > bounds[3]) bounds[3] = yy;
}
}
if (index) {
idToIndex = index;
} else {
idToIndex = new Int32Array(len);
for (i = 0; i < len; i++) {
idToIndex[i] = i;
}
}
} else {
len = x.length;
positions = new Float32Array(2 * len);
idToIndex = new Int32Array(len);
for (i = 0; i < len; i++) {
xx = x[i];
yy = y[i];
idToIndex[i] = i;
positions[i * 2] = xx;
positions[i * 2 + 1] = yy;
if (xx < bounds[0]) bounds[0] = xx;
if (xx > bounds[2]) bounds[2] = xx;
if (yy < bounds[1]) bounds[1] = yy;
if (yy > bounds[3]) bounds[3] = yy;
}
}
this.idToIndex = idToIndex;
this.pointcloudOptions.idToIndex = idToIndex;
this.pointcloudOptions.positions = positions;
var markerColor = str2RGBArray(options.marker.color);
var borderColor = str2RGBArray(options.marker.border.color);
var opacity = options.opacity * options.marker.opacity;
markerColor[3] *= opacity;
this.pointcloudOptions.color = markerColor;
// detect blending from the number of points, if undefined
// because large data with blending hits performance
var blend = options.marker.blend;
if (blend === null) {
var maxPoints = 100;
blend = x.length < maxPoints || y.length < maxPoints;
}
this.pointcloudOptions.blend = blend;
borderColor[3] *= opacity;
this.pointcloudOptions.borderColor = borderColor;
var markerSizeMin = options.marker.sizemin;
var markerSizeMax = Math.max(options.marker.sizemax, options.marker.sizemin);
this.pointcloudOptions.sizeMin = markerSizeMin;
this.pointcloudOptions.sizeMax = markerSizeMax;
this.pointcloudOptions.areaRatio = options.marker.border.arearatio;
this.pointcloud.update(this.pointcloudOptions);
// add item for autorange routine
var xa = this.scene.xaxis;
var ya = this.scene.yaxis;
var pad = markerSizeMax / 2 || 0.5;
options._extremes[xa._id] = findExtremes(xa, [bounds[0], bounds[2]], {
ppad: pad
});
options._extremes[ya._id] = findExtremes(ya, [bounds[1], bounds[3]], {
ppad: pad
});
};
proto.dispose = function () {
this.pointcloud.dispose();
};
function createPointcloud(scene, data) {
var plot = new Pointcloud(scene, data.uid);
plot.update(data);
return plot;
}
module.exports = createPointcloud;
/***/ }),
/***/ 87548:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(75736);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
coerce('x');
coerce('y');
coerce('xbounds');
coerce('ybounds');
if (traceIn.xy && traceIn.xy instanceof Float32Array) {
traceOut.xy = traceIn.xy;
}
if (traceIn.indices && traceIn.indices instanceof Int32Array) {
traceOut.indices = traceIn.indices;
}
coerce('text');
coerce('marker.color', defaultColor);
coerce('marker.opacity');
coerce('marker.blend');
coerce('marker.sizemin');
coerce('marker.sizemax');
coerce('marker.border.color', defaultColor);
coerce('marker.border.arearatio');
// disable 1D transforms - that would defeat the purpose of this trace type, performance!
traceOut._length = null;
};
/***/ }),
/***/ 89012:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var deprecationWarning = ['*pointcloud* trace is deprecated!', 'Please consider switching to the *scattergl* trace type.'].join(' ');
module.exports = {
attributes: __webpack_require__(75736),
supplyDefaults: __webpack_require__(87548),
// reuse the Scatter3D 'dummy' calc step so that legends know what to do
calc: __webpack_require__(95904),
plot: __webpack_require__(29684),
moduleType: 'trace',
name: 'pointcloud',
basePlotModule: __webpack_require__(88768),
categories: ['gl', 'gl2d', 'showLegend'],
meta: {
description: [deprecationWarning, 'The data visualized as a point cloud set in `x` and `y`', 'using the WebGl plotting engine.'].join(' ')
}
};
/***/ }),
/***/ 89388:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var fontAttrs = __webpack_require__(71936);
var baseAttrs = __webpack_require__(6040);
var colorAttrs = __webpack_require__(51468);
var fxAttrs = __webpack_require__(71516);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var colorAttributes = __webpack_require__(99732);
var templatedArray = (__webpack_require__(58056).templatedArray);
var descriptionOnlyNumbers = (__webpack_require__(67724).descriptionOnlyNumbers);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
var attrs = module.exports = overrideAll({
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: [],
arrayOk: false,
description: ['Determines which trace information appear on hover.', 'If `none` or `skip` are set, no information is displayed upon hovering.', 'But, if `none` is set, click and hover events are still fired.', 'Note that this attribute is superseded by `node.hoverinfo` and `node.hoverinfo`', 'for nodes and links respectively.'].join(' ')
}),
hoverlabel: fxAttrs.hoverlabel,
domain: domainAttrs({
name: 'sankey',
trace: true
}),
orientation: {
valType: 'enumerated',
values: ['v', 'h'],
dflt: 'h',
description: 'Sets the orientation of the Sankey diagram.'
},
valueformat: {
valType: 'string',
dflt: '.3s',
description: descriptionOnlyNumbers('value')
},
valuesuffix: {
valType: 'string',
dflt: '',
description: ['Adds a unit to follow the value in the hover tooltip. Add a space if a separation', 'is necessary from the value.'].join(' ')
},
arrangement: {
valType: 'enumerated',
values: ['snap', 'perpendicular', 'freeform', 'fixed'],
dflt: 'snap',
description: ['If value is `snap` (the default), the node arrangement is assisted by automatic snapping of elements to', 'preserve space between nodes specified via `nodepad`.', 'If value is `perpendicular`, the nodes can only move along a line perpendicular to the flow.', 'If value is `freeform`, the nodes can freely move on the plane.', 'If value is `fixed`, the nodes are stationary.'].join(' ')
},
textfont: fontAttrs({
description: 'Sets the font for node labels'
}),
// Remove top-level customdata
customdata: undefined,
node: {
label: {
valType: 'data_array',
dflt: [],
description: 'The shown name of the node.'
},
groups: {
valType: 'info_array',
impliedEdits: {
x: [],
y: []
},
dimensions: 2,
freeLength: true,
dflt: [],
items: {
valType: 'number',
editType: 'calc'
},
description: ['Groups of nodes.', 'Each group is defined by an array with the indices of the nodes it contains.', 'Multiple groups can be specified.'].join(' ')
},
x: {
valType: 'data_array',
dflt: [],
description: 'The normalized horizontal position of the node.'
},
y: {
valType: 'data_array',
dflt: [],
description: 'The normalized vertical position of the node.'
},
color: {
valType: 'color',
arrayOk: true,
description: ['Sets the `node` color. It can be a single value, or an array for specifying color for each `node`.', 'If `node.color` is omitted, then the default `Plotly` color palette will be cycled through', 'to have a variety of colors. These defaults are not fully opaque, to allow some visibility of', 'what is beneath the node.'].join(' ')
},
customdata: {
valType: 'data_array',
editType: 'calc',
description: ['Assigns extra data to each node.'].join(' ')
},
line: {
color: {
valType: 'color',
dflt: colorAttrs.defaultLine,
arrayOk: true,
description: ['Sets the color of the `line` around each `node`.'].join(' ')
},
width: {
valType: 'number',
min: 0,
dflt: 0.5,
arrayOk: true,
description: ['Sets the width (in px) of the `line` around each `node`.'].join(' ')
}
},
pad: {
valType: 'number',
arrayOk: false,
min: 0,
dflt: 20,
description: 'Sets the padding (in px) between the `nodes`.'
},
thickness: {
valType: 'number',
arrayOk: false,
min: 1,
dflt: 20,
description: 'Sets the thickness (in px) of the `nodes`.'
},
hoverinfo: {
valType: 'enumerated',
values: ['all', 'none', 'skip'],
dflt: 'all',
description: ['Determines which trace information appear when hovering nodes.', 'If `none` or `skip` are set, no information is displayed upon hovering.', 'But, if `none` is set, click and hover events are still fired.'].join(' ')
},
hoverlabel: fxAttrs.hoverlabel,
// needs editType override,
hovertemplate: hovertemplateAttrs({}, {
description: 'Variables `sourceLinks` and `targetLinks` are arrays of link objects.',
keys: ['value', 'label']
}),
align: {
valType: 'enumerated',
values: ['justify', 'left', 'right', 'center'],
dflt: 'justify',
description: 'Sets the alignment method used to position the nodes along the horizontal axis.'
},
description: 'The nodes of the Sankey plot.'
},
link: {
arrowlen: {
valType: 'number',
min: 0,
dflt: 0,
description: ['Sets the length (in px) of the links arrow, if 0 no arrow will be drawn.'].join(' ')
},
label: {
valType: 'data_array',
dflt: [],
description: 'The shown name of the link.'
},
color: {
valType: 'color',
arrayOk: true,
description: ['Sets the `link` color. It can be a single value, or an array for specifying color for each `link`.', 'If `link.color` is omitted, then by default, a translucent grey link will be used.'].join(' ')
},
hovercolor: {
valType: 'color',
arrayOk: true,
description: ['Sets the `link` hover color. It can be a single value, or an array for specifying hover colors for', 'each `link`. If `link.hovercolor` is omitted, then by default, links will become slightly more', 'opaque when hovered over.'].join(' ')
},
customdata: {
valType: 'data_array',
editType: 'calc',
description: ['Assigns extra data to each link.'].join(' ')
},
line: {
color: {
valType: 'color',
dflt: colorAttrs.defaultLine,
arrayOk: true,
description: ['Sets the color of the `line` around each `link`.'].join(' ')
},
width: {
valType: 'number',
min: 0,
dflt: 0,
arrayOk: true,
description: ['Sets the width (in px) of the `line` around each `link`.'].join(' ')
}
},
source: {
valType: 'data_array',
dflt: [],
description: 'An integer number `[0..nodes.length - 1]` that represents the source node.'
},
target: {
valType: 'data_array',
dflt: [],
description: 'An integer number `[0..nodes.length - 1]` that represents the target node.'
},
value: {
valType: 'data_array',
dflt: [],
description: 'A numeric value representing the flow volume value.'
},
hoverinfo: {
valType: 'enumerated',
values: ['all', 'none', 'skip'],
dflt: 'all',
description: ['Determines which trace information appear when hovering links.', 'If `none` or `skip` are set, no information is displayed upon hovering.', 'But, if `none` is set, click and hover events are still fired.'].join(' ')
},
hoverlabel: fxAttrs.hoverlabel,
// needs editType override,
hovertemplate: hovertemplateAttrs({}, {
description: 'Variables `source` and `target` are node objects.',
keys: ['value', 'label']
}),
colorscales: templatedArray('concentrationscales', {
editType: 'calc',
label: {
valType: 'string',
editType: 'calc',
description: 'The label of the links to color based on their concentration within a flow.',
dflt: ''
},
cmax: {
valType: 'number',
editType: 'calc',
dflt: 1,
description: 'Sets the upper bound of the color domain.'
},
cmin: {
valType: 'number',
editType: 'calc',
dflt: 0,
description: 'Sets the lower bound of the color domain.'
},
colorscale: extendFlat(colorAttributes().colorscale, {
dflt: [[0, 'white'], [1, 'black']]
})
}),
description: 'The links of the Sankey plot.'
}
}, 'calc', 'nested');
attrs.transforms = undefined;
/***/ }),
/***/ 47488:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var overrideAll = (__webpack_require__(31176).overrideAll);
var getModuleCalcData = (__webpack_require__(49824)/* .getModuleCalcData */ ._M);
var plot = __webpack_require__(89832);
var fxAttrs = __webpack_require__(7024);
var setCursor = __webpack_require__(18792);
var dragElement = __webpack_require__(76364);
var prepSelect = (__webpack_require__(41800).prepSelect);
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
var SANKEY = 'sankey';
exports.name = SANKEY;
exports.baseLayoutAttrOverrides = overrideAll({
hoverlabel: fxAttrs.hoverlabel
}, 'plot', 'nested');
exports.plot = function (gd) {
var calcData = getModuleCalcData(gd.calcdata, SANKEY)[0];
plot(gd, calcData);
exports.updateFx(gd);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
var hadPlot = oldFullLayout._has && oldFullLayout._has(SANKEY);
var hasPlot = newFullLayout._has && newFullLayout._has(SANKEY);
if (hadPlot && !hasPlot) {
oldFullLayout._paperdiv.selectAll('.sankey').remove();
oldFullLayout._paperdiv.selectAll('.bgsankey').remove();
}
};
exports.updateFx = function (gd) {
for (var i = 0; i < gd._fullData.length; i++) {
subplotUpdateFx(gd, i);
}
};
function subplotUpdateFx(gd, index) {
var trace = gd._fullData[index];
var fullLayout = gd._fullLayout;
var dragMode = fullLayout.dragmode;
var cursor = fullLayout.dragmode === 'pan' ? 'move' : 'crosshair';
var bgRect = trace._bgRect;
if (!bgRect) return;
if (dragMode === 'pan' || dragMode === 'zoom') return;
setCursor(bgRect, cursor);
var xaxis = {
_id: 'x',
c2p: Lib.identity,
_offset: trace._sankey.translateX,
_length: trace._sankey.width
};
var yaxis = {
_id: 'y',
c2p: Lib.identity,
_offset: trace._sankey.translateY,
_length: trace._sankey.height
};
// Note: dragOptions is needed to be declared for all dragmodes because
// it's the object that holds persistent selection state.
var dragOptions = {
gd: gd,
element: bgRect.node(),
plotinfo: {
id: index,
xaxis: xaxis,
yaxis: yaxis,
fillRangeItems: Lib.noop
},
subplot: index,
// create mock x/y axes for hover routine
xaxes: [xaxis],
yaxes: [yaxis],
doneFnCompleted: function (selection) {
var traceNow = gd._fullData[index];
var newGroups;
var oldGroups = traceNow.node.groups.slice();
var newGroup = [];
function findNode(pt) {
var nodes = traceNow._sankey.graph.nodes;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].pointNumber === pt) return nodes[i];
}
}
for (var j = 0; j < selection.length; j++) {
var node = findNode(selection[j].pointNumber);
if (!node) continue;
// If the node represents a group
if (node.group) {
// Add all its children to the current selection
for (var k = 0; k < node.childrenNodes.length; k++) {
newGroup.push(node.childrenNodes[k].pointNumber);
}
// Flag group for removal from existing list of groups
oldGroups[node.pointNumber - traceNow.node._count] = false;
} else {
newGroup.push(node.pointNumber);
}
}
newGroups = oldGroups.filter(Boolean).concat([newGroup]);
Registry.call('_guiRestyle', gd, {
'node.groups': [newGroups]
}, index);
}
};
dragOptions.prepFn = function (e, startX, startY) {
prepSelect(e, startX, startY, dragOptions, dragMode);
};
dragElement.init(dragOptions);
}
/***/ }),
/***/ 75:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var tarjan = __webpack_require__(36584);
var Lib = __webpack_require__(10923);
var wrap = (__webpack_require__(83104).wrap);
var isArrayOrTypedArray = Lib.isArrayOrTypedArray;
var isIndex = Lib.isIndex;
var Colorscale = __webpack_require__(26733);
function convertToD3Sankey(trace) {
var nodeSpec = trace.node;
var linkSpec = trace.link;
var links = [];
var hasLinkColorArray = isArrayOrTypedArray(linkSpec.color);
var hasLinkHoverColorArray = isArrayOrTypedArray(linkSpec.hovercolor);
var hasLinkCustomdataArray = isArrayOrTypedArray(linkSpec.customdata);
var linkedNodes = {};
var components = {};
var componentCount = linkSpec.colorscales.length;
var i;
for (i = 0; i < componentCount; i++) {
var cscale = linkSpec.colorscales[i];
var specs = Colorscale.extractScale(cscale, {
cLetter: 'c'
});
var scale = Colorscale.makeColorScaleFunc(specs);
components[cscale.label] = scale;
}
var maxNodeId = 0;
for (i = 0; i < linkSpec.value.length; i++) {
if (linkSpec.source[i] > maxNodeId) maxNodeId = linkSpec.source[i];
if (linkSpec.target[i] > maxNodeId) maxNodeId = linkSpec.target[i];
}
var nodeCount = maxNodeId + 1;
trace.node._count = nodeCount;
// Group nodes
var j;
var groups = trace.node.groups;
var groupLookup = {};
for (i = 0; i < groups.length; i++) {
var group = groups[i];
// Build a lookup table to quickly find in which group a node is
for (j = 0; j < group.length; j++) {
var nodeIndex = group[j];
var groupIndex = nodeCount + i;
if (groupLookup.hasOwnProperty(nodeIndex)) {
Lib.warn('Node ' + nodeIndex + ' is already part of a group.');
} else {
groupLookup[nodeIndex] = groupIndex;
}
}
}
// Process links
var groupedLinks = {
source: [],
target: []
};
for (i = 0; i < linkSpec.value.length; i++) {
var val = linkSpec.value[i];
// remove negative values, but keep zeros with special treatment
var source = linkSpec.source[i];
var target = linkSpec.target[i];
if (!(val > 0 && isIndex(source, nodeCount) && isIndex(target, nodeCount))) {
continue;
}
// Remove links that are within the same group
if (groupLookup.hasOwnProperty(source) && groupLookup.hasOwnProperty(target) && groupLookup[source] === groupLookup[target]) {
continue;
}
// if link targets a node in the group, relink target to that group
if (groupLookup.hasOwnProperty(target)) {
target = groupLookup[target];
}
// if link originates from a node in a group, relink source to that group
if (groupLookup.hasOwnProperty(source)) {
source = groupLookup[source];
}
source = +source;
target = +target;
linkedNodes[source] = linkedNodes[target] = true;
var label = '';
if (linkSpec.label && linkSpec.label[i]) label = linkSpec.label[i];
var concentrationscale = null;
if (label && components.hasOwnProperty(label)) concentrationscale = components[label];
links.push({
pointNumber: i,
label: label,
color: hasLinkColorArray ? linkSpec.color[i] : linkSpec.color,
hovercolor: hasLinkHoverColorArray ? linkSpec.hovercolor[i] : linkSpec.hovercolor,
customdata: hasLinkCustomdataArray ? linkSpec.customdata[i] : linkSpec.customdata,
concentrationscale: concentrationscale,
source: source,
target: target,
value: +val
});
groupedLinks.source.push(source);
groupedLinks.target.push(target);
}
// Process nodes
var totalCount = nodeCount + groups.length;
var hasNodeColorArray = isArrayOrTypedArray(nodeSpec.color);
var hasNodeCustomdataArray = isArrayOrTypedArray(nodeSpec.customdata);
var nodes = [];
for (i = 0; i < totalCount; i++) {
if (!linkedNodes[i]) continue;
var l = nodeSpec.label[i];
nodes.push({
group: i > nodeCount - 1,
childrenNodes: [],
pointNumber: i,
label: l,
color: hasNodeColorArray ? nodeSpec.color[i] : nodeSpec.color,
customdata: hasNodeCustomdataArray ? nodeSpec.customdata[i] : nodeSpec.customdata
});
}
// Check if we have circularity on the resulting graph
var circular = false;
if (circularityPresent(totalCount, groupedLinks.source, groupedLinks.target)) {
circular = true;
}
return {
circular: circular,
links: links,
nodes: nodes,
// Data structure for groups
groups: groups,
groupLookup: groupLookup
};
}
function circularityPresent(nodeLen, sources, targets) {
var nodes = Lib.init2dArray(nodeLen, 0);
for (var i = 0; i < Math.min(sources.length, targets.length); i++) {
if (Lib.isIndex(sources[i], nodeLen) && Lib.isIndex(targets[i], nodeLen)) {
if (sources[i] === targets[i]) {
return true; // self-link which is also a scc of one
}
nodes[sources[i]].push(targets[i]);
}
}
var scc = tarjan(nodes);
// Tarján's strongly connected components algorithm coded by Mikola Lysenko
// returns at least one non-singular component if there's circularity in the graph
return scc.components.some(function (c) {
return c.length > 1;
});
}
module.exports = function calc(gd, trace) {
var result = convertToD3Sankey(trace);
return wrap({
circular: result.circular,
_nodes: result.nodes,
_links: result.links,
// Data structure for grouping
_groups: result.groups,
_groupLookup: result.groupLookup
});
};
/***/ }),
/***/ 14152:
/***/ (function(module) {
"use strict";
module.exports = {
nodeTextOffsetHorizontal: 4,
nodeTextOffsetVertical: 3,
nodePadAcross: 10,
sankeyIterations: 50,
forceIterations: 5,
forceTicksPerFrame: 10,
duration: 500,
ease: 'linear',
cn: {
sankey: 'sankey',
sankeyLinks: 'sankey-links',
sankeyLink: 'sankey-link',
sankeyNodeSet: 'sankey-node-set',
sankeyNode: 'sankey-node',
nodeRect: 'node-rect',
nodeLabel: 'node-label'
}
};
/***/ }),
/***/ 99316:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(89388);
var Color = __webpack_require__(9240);
var tinycolor = __webpack_require__(70336);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var handleHoverLabelDefaults = __webpack_require__(64824);
var Template = __webpack_require__(58056);
var handleArrayContainerDefaults = __webpack_require__(95631);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var hoverlabelDefault = Lib.extendDeep(layout.hoverlabel, traceIn.hoverlabel);
// node attributes
var nodeIn = traceIn.node;
var nodeOut = Template.newContainer(traceOut, 'node');
function coerceNode(attr, dflt) {
return Lib.coerce(nodeIn, nodeOut, attributes.node, attr, dflt);
}
coerceNode('label');
coerceNode('groups');
coerceNode('x');
coerceNode('y');
coerceNode('pad');
coerceNode('thickness');
coerceNode('line.color');
coerceNode('line.width');
coerceNode('hoverinfo', traceIn.hoverinfo);
handleHoverLabelDefaults(nodeIn, nodeOut, coerceNode, hoverlabelDefault);
coerceNode('hovertemplate');
coerceNode('align');
var colors = layout.colorway;
var defaultNodePalette = function (i) {
return colors[i % colors.length];
};
coerceNode('color', nodeOut.label.map(function (d, i) {
return Color.addOpacity(defaultNodePalette(i), 0.8);
}));
coerceNode('customdata');
// link attributes
var linkIn = traceIn.link || {};
var linkOut = Template.newContainer(traceOut, 'link');
function coerceLink(attr, dflt) {
return Lib.coerce(linkIn, linkOut, attributes.link, attr, dflt);
}
coerceLink('label');
coerceLink('arrowlen');
coerceLink('source');
coerceLink('target');
coerceLink('value');
coerceLink('line.color');
coerceLink('line.width');
coerceLink('hoverinfo', traceIn.hoverinfo);
handleHoverLabelDefaults(linkIn, linkOut, coerceLink, hoverlabelDefault);
coerceLink('hovertemplate');
var darkBG = tinycolor(layout.paper_bgcolor).getLuminance() < 0.333;
var defaultLinkColor = darkBG ? 'rgba(255, 255, 255, 0.6)' : 'rgba(0, 0, 0, 0.2)';
var linkColor = coerceLink('color', defaultLinkColor);
function makeDefaultHoverColor(_linkColor) {
var tc = tinycolor(_linkColor);
if (!tc.isValid()) {
// hopefully the user-specified color is valid, but if not that can be caught elsewhere
return _linkColor;
}
var alpha = tc.getAlpha();
if (alpha <= 0.8) {
tc.setAlpha(alpha + 0.2);
} else {
tc = darkBG ? tc.brighten() : tc.darken();
}
return tc.toRgbString();
}
coerceLink('hovercolor', Array.isArray(linkColor) ? linkColor.map(makeDefaultHoverColor) : makeDefaultHoverColor(linkColor));
coerceLink('customdata');
handleArrayContainerDefaults(linkIn, linkOut, {
name: 'colorscales',
handleItemDefaults: concentrationscalesDefaults
});
handleDomainDefaults(traceOut, layout, coerce);
coerce('orientation');
coerce('valueformat');
coerce('valuesuffix');
var dfltArrangement;
if (nodeOut.x.length && nodeOut.y.length) {
dfltArrangement = 'freeform';
}
coerce('arrangement', dfltArrangement);
Lib.coerceFont(coerce, 'textfont', Lib.extendFlat({}, layout.font));
// disable 1D transforms - arrays here are 1D but their lengths/meanings
// don't match, between nodes and links
traceOut._length = null;
};
function concentrationscalesDefaults(In, Out) {
function coerce(attr, dflt) {
return Lib.coerce(In, Out, attributes.link.colorscales, attr, dflt);
}
coerce('label');
coerce('cmin');
coerce('cmax');
coerce('colorscale');
}
/***/ }),
/***/ 76116:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(89388),
supplyDefaults: __webpack_require__(99316),
calc: __webpack_require__(75),
plot: __webpack_require__(89832),
moduleType: 'trace',
name: 'sankey',
basePlotModule: __webpack_require__(47488),
selectPoints: __webpack_require__(80784),
categories: ['noOpacity'],
meta: {
description: ['Sankey plots for network flow data analysis.', 'The nodes are specified in `nodes` and the links between sources and targets in `links`.', 'The colors are set in `nodes[i].color` and `links[i].color`, otherwise defaults are used.'].join(' ')
}
};
/***/ }),
/***/ 89832:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var numberFormat = Lib.numberFormat;
var render = __webpack_require__(30420);
var Fx = __webpack_require__(39184);
var Color = __webpack_require__(9240);
var cn = (__webpack_require__(14152).cn);
var _ = Lib._;
function renderableValuePresent(d) {
return d !== '';
}
function ownTrace(selection, d) {
return selection.filter(function (s) {
return s.key === d.traceId;
});
}
function makeTranslucent(element, alpha) {
d3.select(element).select('path').style('fill-opacity', alpha);
d3.select(element).select('rect').style('fill-opacity', alpha);
}
function makeTextContrasty(element) {
d3.select(element).select('text.name').style('fill', 'black');
}
function relatedLinks(d) {
return function (l) {
return d.node.sourceLinks.indexOf(l.link) !== -1 || d.node.targetLinks.indexOf(l.link) !== -1;
};
}
function relatedNodes(l) {
return function (d) {
return d.node.sourceLinks.indexOf(l.link) !== -1 || d.node.targetLinks.indexOf(l.link) !== -1;
};
}
function nodeHoveredStyle(sankeyNode, d, sankey) {
if (d && sankey) {
ownTrace(sankey, d).selectAll('.' + cn.sankeyLink).filter(relatedLinks(d)).call(linkHoveredStyle.bind(0, d, sankey, false));
}
}
function nodeNonHoveredStyle(sankeyNode, d, sankey) {
if (d && sankey) {
ownTrace(sankey, d).selectAll('.' + cn.sankeyLink).filter(relatedLinks(d)).call(linkNonHoveredStyle.bind(0, d, sankey, false));
}
}
function linkHoveredStyle(d, sankey, visitNodes, sankeyLink) {
sankeyLink.style('fill', function (l) {
if (!l.link.concentrationscale) {
return l.tinyColorHoverHue;
}
}).style('fill-opacity', function (l) {
if (!l.link.concentrationscale) {
return l.tinyColorHoverAlpha;
}
});
sankeyLink.each(function (curLink) {
var label = curLink.link.label;
if (label !== '') {
ownTrace(sankey, d).selectAll('.' + cn.sankeyLink).filter(function (l) {
return l.link.label === label;
}).style('fill', function (l) {
if (!l.link.concentrationscale) {
return l.tinyColorHoverHue;
}
}).style('fill-opacity', function (l) {
if (!l.link.concentrationscale) {
return l.tinyColorHoverAlpha;
}
});
}
});
if (visitNodes) {
ownTrace(sankey, d).selectAll('.' + cn.sankeyNode).filter(relatedNodes(d)).call(nodeHoveredStyle);
}
}
function linkNonHoveredStyle(d, sankey, visitNodes, sankeyLink) {
sankeyLink.style('fill', function (l) {
return l.tinyColorHue;
}).style('fill-opacity', function (l) {
return l.tinyColorAlpha;
});
sankeyLink.each(function (curLink) {
var label = curLink.link.label;
if (label !== '') {
ownTrace(sankey, d).selectAll('.' + cn.sankeyLink).filter(function (l) {
return l.link.label === label;
}).style('fill', function (l) {
return l.tinyColorHue;
}).style('fill-opacity', function (l) {
return l.tinyColorAlpha;
});
}
});
if (visitNodes) {
ownTrace(sankey, d).selectAll(cn.sankeyNode).filter(relatedNodes(d)).call(nodeNonHoveredStyle);
}
}
// does not support array values for now
function castHoverOption(trace, attr) {
var labelOpts = trace.hoverlabel || {};
var val = Lib.nestedProperty(labelOpts, attr).get();
return Array.isArray(val) ? false : val;
}
module.exports = function plot(gd, calcData) {
var fullLayout = gd._fullLayout;
var svg = fullLayout._paper;
var size = fullLayout._size;
// stash initial view
for (var i = 0; i < gd._fullData.length; i++) {
if (!gd._fullData[i].visible) continue;
if (gd._fullData[i].type !== cn.sankey) continue;
if (!gd._fullData[i]._viewInitial) {
var node = gd._fullData[i].node;
gd._fullData[i]._viewInitial = {
node: {
groups: node.groups.slice(),
x: node.x.slice(),
y: node.y.slice()
}
};
}
}
var linkSelect = function (element, d) {
var evt = d.link;
evt.originalEvent = d3.event;
gd._hoverdata = [evt];
Fx.click(gd, {
target: true
});
};
var linkHover = function (element, d, sankey) {
if (gd._fullLayout.hovermode === false) return;
d3.select(element).call(linkHoveredStyle.bind(0, d, sankey, true));
if (d.link.trace.link.hoverinfo !== 'skip') {
d.link.fullData = d.link.trace;
gd.emit('plotly_hover', {
event: d3.event,
points: [d.link]
});
}
};
var sourceLabel = _(gd, 'source:') + ' ';
var targetLabel = _(gd, 'target:') + ' ';
var concentrationLabel = _(gd, 'concentration:') + ' ';
var incomingLabel = _(gd, 'incoming flow count:') + ' ';
var outgoingLabel = _(gd, 'outgoing flow count:') + ' ';
var linkHoverFollow = function (element, d) {
if (gd._fullLayout.hovermode === false) return;
var obj = d.link.trace.link;
if (obj.hoverinfo === 'none' || obj.hoverinfo === 'skip') return;
var hoverItems = [];
function hoverCenterPosition(link) {
var hoverCenterX, hoverCenterY;
if (link.circular) {
hoverCenterX = (link.circularPathData.leftInnerExtent + link.circularPathData.rightInnerExtent) / 2;
hoverCenterY = link.circularPathData.verticalFullExtent;
} else {
hoverCenterX = (link.source.x1 + link.target.x0) / 2;
hoverCenterY = (link.y0 + link.y1) / 2;
}
var center = [hoverCenterX, hoverCenterY];
if (link.trace.orientation === 'v') center.reverse();
center[0] += d.parent.translateX;
center[1] += d.parent.translateY;
return center;
}
// For each related links, create a hoverItem
var anchorIndex = 0;
for (var i = 0; i < d.flow.links.length; i++) {
var link = d.flow.links[i];
if (gd._fullLayout.hovermode === 'closest' && d.link.pointNumber !== link.pointNumber) continue;
if (d.link.pointNumber === link.pointNumber) anchorIndex = i;
link.fullData = link.trace;
obj = d.link.trace.link;
var hoverCenter = hoverCenterPosition(link);
var hovertemplateLabels = {
valueLabel: numberFormat(d.valueFormat)(link.value) + d.valueSuffix
};
hoverItems.push({
x: hoverCenter[0],
y: hoverCenter[1],
name: hovertemplateLabels.valueLabel,
text: [link.label || '', sourceLabel + link.source.label, targetLabel + link.target.label, link.concentrationscale ? concentrationLabel + numberFormat('%0.2f')(link.flow.labelConcentration) : ''].filter(renderableValuePresent).join('
'),
color: castHoverOption(obj, 'bgcolor') || Color.addOpacity(link.color, 1),
borderColor: castHoverOption(obj, 'bordercolor'),
fontFamily: castHoverOption(obj, 'font.family'),
fontSize: castHoverOption(obj, 'font.size'),
fontColor: castHoverOption(obj, 'font.color'),
nameLength: castHoverOption(obj, 'namelength'),
textAlign: castHoverOption(obj, 'align'),
idealAlign: d3.event.x < hoverCenter[0] ? 'right' : 'left',
hovertemplate: obj.hovertemplate,
hovertemplateLabels: hovertemplateLabels,
eventData: [link]
});
}
var tooltips = Fx.loneHover(hoverItems, {
container: fullLayout._hoverlayer.node(),
outerContainer: fullLayout._paper.node(),
gd: gd,
anchorIndex: anchorIndex
});
tooltips.each(function () {
var tooltip = this;
if (!d.link.concentrationscale) {
makeTranslucent(tooltip, 0.65);
}
makeTextContrasty(tooltip);
});
};
var linkUnhover = function (element, d, sankey) {
if (gd._fullLayout.hovermode === false) return;
d3.select(element).call(linkNonHoveredStyle.bind(0, d, sankey, true));
if (d.link.trace.link.hoverinfo !== 'skip') {
d.link.fullData = d.link.trace;
gd.emit('plotly_unhover', {
event: d3.event,
points: [d.link]
});
}
Fx.loneUnhover(fullLayout._hoverlayer.node());
};
var nodeSelect = function (element, d, sankey) {
var evt = d.node;
evt.originalEvent = d3.event;
gd._hoverdata = [evt];
d3.select(element).call(nodeNonHoveredStyle, d, sankey);
Fx.click(gd, {
target: true
});
};
var nodeHover = function (element, d, sankey) {
if (gd._fullLayout.hovermode === false) return;
d3.select(element).call(nodeHoveredStyle, d, sankey);
if (d.node.trace.node.hoverinfo !== 'skip') {
d.node.fullData = d.node.trace;
gd.emit('plotly_hover', {
event: d3.event,
points: [d.node]
});
}
};
var nodeHoverFollow = function (element, d) {
if (gd._fullLayout.hovermode === false) return;
var obj = d.node.trace.node;
if (obj.hoverinfo === 'none' || obj.hoverinfo === 'skip') return;
var nodeRect = d3.select(element).select('.' + cn.nodeRect);
var rootBBox = gd._fullLayout._paperdiv.node().getBoundingClientRect();
var boundingBox = nodeRect.node().getBoundingClientRect();
var hoverCenterX0 = boundingBox.left - 2 - rootBBox.left;
var hoverCenterX1 = boundingBox.right + 2 - rootBBox.left;
var hoverCenterY = boundingBox.top + boundingBox.height / 4 - rootBBox.top;
var hovertemplateLabels = {
valueLabel: numberFormat(d.valueFormat)(d.node.value) + d.valueSuffix
};
d.node.fullData = d.node.trace;
gd._fullLayout._calcInverseTransform(gd);
var scaleX = gd._fullLayout._invScaleX;
var scaleY = gd._fullLayout._invScaleY;
var tooltip = Fx.loneHover({
x0: scaleX * hoverCenterX0,
x1: scaleX * hoverCenterX1,
y: scaleY * hoverCenterY,
name: numberFormat(d.valueFormat)(d.node.value) + d.valueSuffix,
text: [d.node.label, incomingLabel + d.node.targetLinks.length, outgoingLabel + d.node.sourceLinks.length].filter(renderableValuePresent).join('
'),
color: castHoverOption(obj, 'bgcolor') || d.tinyColorHue,
borderColor: castHoverOption(obj, 'bordercolor'),
fontFamily: castHoverOption(obj, 'font.family'),
fontSize: castHoverOption(obj, 'font.size'),
fontColor: castHoverOption(obj, 'font.color'),
nameLength: castHoverOption(obj, 'namelength'),
textAlign: castHoverOption(obj, 'align'),
idealAlign: 'left',
hovertemplate: obj.hovertemplate,
hovertemplateLabels: hovertemplateLabels,
eventData: [d.node]
}, {
container: fullLayout._hoverlayer.node(),
outerContainer: fullLayout._paper.node(),
gd: gd
});
makeTranslucent(tooltip, 0.85);
makeTextContrasty(tooltip);
};
var nodeUnhover = function (element, d, sankey) {
if (gd._fullLayout.hovermode === false) return;
d3.select(element).call(nodeNonHoveredStyle, d, sankey);
if (d.node.trace.node.hoverinfo !== 'skip') {
d.node.fullData = d.node.trace;
gd.emit('plotly_unhover', {
event: d3.event,
points: [d.node]
});
}
Fx.loneUnhover(fullLayout._hoverlayer.node());
};
render(gd, svg, calcData, {
width: size.w,
height: size.h,
margin: {
t: size.t,
r: size.r,
b: size.b,
l: size.l
}
}, {
linkEvents: {
hover: linkHover,
follow: linkHoverFollow,
unhover: linkUnhover,
select: linkSelect
},
nodeEvents: {
hover: nodeHover,
follow: nodeHoverFollow,
unhover: nodeUnhover,
select: nodeSelect
}
});
};
/***/ }),
/***/ 30420:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3Force = __webpack_require__(78016);
var interpolateNumber = (__webpack_require__(78204)/* .interpolateNumber */ .Gz);
var d3 = __webpack_require__(6592);
var d3Sankey = __webpack_require__(33428);
var d3SankeyCircular = __webpack_require__(86192);
var c = __webpack_require__(14152);
var tinycolor = __webpack_require__(70336);
var Color = __webpack_require__(9240);
var Drawing = __webpack_require__(49348);
var Lib = __webpack_require__(10923);
var strTranslate = Lib.strTranslate;
var strRotate = Lib.strRotate;
var gup = __webpack_require__(83104);
var keyFun = gup.keyFun;
var repeat = gup.repeat;
var unwrap = gup.unwrap;
var svgTextUtils = __webpack_require__(41536);
var Registry = __webpack_require__(30364);
var alignmentConstants = __webpack_require__(83784);
var CAP_SHIFT = alignmentConstants.CAP_SHIFT;
var LINE_SPACING = alignmentConstants.LINE_SPACING;
var TEXTPAD = 3;
// view models
function sankeyModel(layout, d, traceIndex) {
var calcData = unwrap(d);
var trace = calcData.trace;
var domain = trace.domain;
var horizontal = trace.orientation === 'h';
var nodePad = trace.node.pad;
var nodeThickness = trace.node.thickness;
var nodeAlign = {
justify: d3Sankey.sankeyJustify,
left: d3Sankey.sankeyLeft,
right: d3Sankey.sankeyRight,
center: d3Sankey.sankeyCenter
}[trace.node.align];
var width = layout.width * (domain.x[1] - domain.x[0]);
var height = layout.height * (domain.y[1] - domain.y[0]);
var nodes = calcData._nodes;
var links = calcData._links;
var circular = calcData.circular;
// Select Sankey generator
var sankey;
if (circular) {
sankey = d3SankeyCircular.sankeyCircular().circularLinkGap(0);
} else {
sankey = d3Sankey.sankey();
}
sankey.iterations(c.sankeyIterations).size(horizontal ? [width, height] : [height, width]).nodeWidth(nodeThickness).nodePadding(nodePad).nodeId(function (d) {
return d.pointNumber;
}).nodeAlign(nodeAlign).nodes(nodes).links(links);
var graph = sankey();
if (sankey.nodePadding() < nodePad) {
Lib.warn('node.pad was reduced to ', sankey.nodePadding(), ' to fit within the figure.');
}
// Counters for nested loops
var i, j, k;
// Create transient nodes for animations
for (var nodePointNumber in calcData._groupLookup) {
var groupIndex = parseInt(calcData._groupLookup[nodePointNumber]);
// Find node representing groupIndex
var groupingNode;
for (i = 0; i < graph.nodes.length; i++) {
if (graph.nodes[i].pointNumber === groupIndex) {
groupingNode = graph.nodes[i];
break;
}
}
// If groupinNode is undefined, no links are targeting this group
if (!groupingNode) continue;
var child = {
pointNumber: parseInt(nodePointNumber),
x0: groupingNode.x0,
x1: groupingNode.x1,
y0: groupingNode.y0,
y1: groupingNode.y1,
partOfGroup: true,
sourceLinks: [],
targetLinks: []
};
graph.nodes.unshift(child);
groupingNode.childrenNodes.unshift(child);
}
function computeLinkConcentrations() {
for (i = 0; i < graph.nodes.length; i++) {
var node = graph.nodes[i];
// Links connecting the same two nodes are part of a flow
var flows = {};
var flowKey;
var link;
for (j = 0; j < node.targetLinks.length; j++) {
link = node.targetLinks[j];
flowKey = link.source.pointNumber + ':' + link.target.pointNumber;
if (!flows.hasOwnProperty(flowKey)) flows[flowKey] = [];
flows[flowKey].push(link);
}
// Compute statistics for each flow
var keys = Object.keys(flows);
for (j = 0; j < keys.length; j++) {
flowKey = keys[j];
var flowLinks = flows[flowKey];
// Find the total size of the flow and total size per label
var total = 0;
var totalPerLabel = {};
for (k = 0; k < flowLinks.length; k++) {
link = flowLinks[k];
if (!totalPerLabel[link.label]) totalPerLabel[link.label] = 0;
totalPerLabel[link.label] += link.value;
total += link.value;
}
// Find the ratio of the link's value and the size of the flow
for (k = 0; k < flowLinks.length; k++) {
link = flowLinks[k];
link.flow = {
value: total,
labelConcentration: totalPerLabel[link.label] / total,
concentration: link.value / total,
links: flowLinks
};
if (link.concentrationscale) {
link.color = tinycolor(link.concentrationscale(link.flow.labelConcentration));
}
}
}
// Gather statistics of all links at current node
var totalOutflow = 0;
for (j = 0; j < node.sourceLinks.length; j++) {
totalOutflow += node.sourceLinks[j].value;
}
for (j = 0; j < node.sourceLinks.length; j++) {
link = node.sourceLinks[j];
link.concentrationOut = link.value / totalOutflow;
}
var totalInflow = 0;
for (j = 0; j < node.targetLinks.length; j++) {
totalInflow += node.targetLinks[j].value;
}
for (j = 0; j < node.targetLinks.length; j++) {
link = node.targetLinks[j];
link.concenrationIn = link.value / totalInflow;
}
}
}
computeLinkConcentrations();
// Push any overlapping nodes down.
function resolveCollisionsTopToBottom(columns) {
columns.forEach(function (nodes) {
var node;
var dy;
var y = 0;
var n = nodes.length;
var i;
nodes.sort(function (a, b) {
return a.y0 - b.y0;
});
for (i = 0; i < n; ++i) {
node = nodes[i];
if (node.y0 >= y) {
// No overlap
} else {
dy = y - node.y0;
if (dy > 1e-6) node.y0 += dy, node.y1 += dy;
}
y = node.y1 + nodePad;
}
});
}
// Group nodes into columns based on their x position
function snapToColumns(nodes) {
// Sort nodes by x position
var orderedNodes = nodes.map(function (n, i) {
return {
x0: n.x0,
index: i
};
}).sort(function (a, b) {
return a.x0 - b.x0;
});
var columns = [];
var colNumber = -1;
var colX; // Position of column
var lastX = -Infinity; // Position of last node
var dx;
for (i = 0; i < orderedNodes.length; i++) {
var node = nodes[orderedNodes[i].index];
// If the node does not overlap with the last one
if (node.x0 > lastX + nodeThickness) {
// Start a new column
colNumber += 1;
colX = node.x0;
}
lastX = node.x0;
// Add node to its associated column
if (!columns[colNumber]) columns[colNumber] = [];
columns[colNumber].push(node);
// Change node's x position to align it with its column
dx = colX - node.x0;
node.x0 += dx, node.x1 += dx;
}
return columns;
}
// Force node position
if (trace.node.x.length && trace.node.y.length) {
for (i = 0; i < Math.min(trace.node.x.length, trace.node.y.length, graph.nodes.length); i++) {
if (trace.node.x[i] && trace.node.y[i]) {
var pos = [trace.node.x[i] * width, trace.node.y[i] * height];
graph.nodes[i].x0 = pos[0] - nodeThickness / 2;
graph.nodes[i].x1 = pos[0] + nodeThickness / 2;
var nodeHeight = graph.nodes[i].y1 - graph.nodes[i].y0;
graph.nodes[i].y0 = pos[1] - nodeHeight / 2;
graph.nodes[i].y1 = pos[1] + nodeHeight / 2;
}
}
if (trace.arrangement === 'snap') {
nodes = graph.nodes;
var columns = snapToColumns(nodes);
resolveCollisionsTopToBottom(columns);
}
// Update links
sankey.update(graph);
}
return {
circular: circular,
key: traceIndex,
trace: trace,
guid: Lib.randstr(),
horizontal: horizontal,
width: width,
height: height,
nodePad: trace.node.pad,
nodeLineColor: trace.node.line.color,
nodeLineWidth: trace.node.line.width,
linkLineColor: trace.link.line.color,
linkLineWidth: trace.link.line.width,
linkArrowLength: trace.link.arrowlen,
valueFormat: trace.valueformat,
valueSuffix: trace.valuesuffix,
textFont: trace.textfont,
translateX: domain.x[0] * layout.width + layout.margin.l,
translateY: layout.height - domain.y[1] * layout.height + layout.margin.t,
dragParallel: horizontal ? height : width,
dragPerpendicular: horizontal ? width : height,
arrangement: trace.arrangement,
sankey: sankey,
graph: graph,
forceLayouts: {},
interactionState: {
dragInProgress: false,
hovered: false
}
};
}
function linkModel(d, l, i) {
var tc = tinycolor(l.color);
var htc = tinycolor(l.hovercolor);
var basicKey = l.source.label + '|' + l.target.label;
var key = basicKey + '__' + i;
// for event data
l.trace = d.trace;
l.curveNumber = d.trace.index;
return {
circular: d.circular,
key: key,
traceId: d.key,
pointNumber: l.pointNumber,
link: l,
tinyColorHue: Color.tinyRGB(tc),
tinyColorAlpha: tc.getAlpha(),
tinyColorHoverHue: Color.tinyRGB(htc),
tinyColorHoverAlpha: htc.getAlpha(),
linkPath: linkPath,
linkLineColor: d.linkLineColor,
linkLineWidth: d.linkLineWidth,
linkArrowLength: d.linkArrowLength,
valueFormat: d.valueFormat,
valueSuffix: d.valueSuffix,
sankey: d.sankey,
parent: d,
interactionState: d.interactionState,
flow: l.flow
};
}
function createCircularClosedPathString(link, arrowLen) {
// Using coordinates computed by d3-sankey-circular
var pathString = '';
var offset = link.width / 2;
var coords = link.circularPathData;
if (link.circularLinkType === 'top') {
// Top path
pathString =
// start at the left of the target node
'M ' + (coords.targetX - arrowLen) + ' ' + (coords.targetY + offset) + ' ' + 'L' + (coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY + offset) + 'A' + (coords.rightLargeArcRadius + offset) + ' ' + (coords.rightSmallArcRadius + offset) + ' 0 0 1 ' + (coords.rightFullExtent - offset - arrowLen) + ' ' + (coords.targetY - coords.rightSmallArcRadius) + 'L' + (coords.rightFullExtent - offset - arrowLen) + ' ' + coords.verticalRightInnerExtent + 'A' + (coords.rightLargeArcRadius + offset) + ' ' + (coords.rightLargeArcRadius + offset) + ' 0 0 1 ' + (coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent - offset) + 'L' + coords.leftInnerExtent + ' ' + (coords.verticalFullExtent - offset) + 'A' + (coords.leftLargeArcRadius + offset) + ' ' + (coords.leftLargeArcRadius + offset) + ' 0 0 1 ' + (coords.leftFullExtent + offset) + ' ' + coords.verticalLeftInnerExtent + 'L' + (coords.leftFullExtent + offset) + ' ' + (coords.sourceY - coords.leftSmallArcRadius) + 'A' + (coords.leftLargeArcRadius + offset) + ' ' + (coords.leftSmallArcRadius + offset) + ' 0 0 1 ' + coords.leftInnerExtent + ' ' + (coords.sourceY + offset) + 'L' + coords.sourceX + ' ' + (coords.sourceY + offset) +
// Walking back
'L' + coords.sourceX + ' ' + (coords.sourceY - offset) + 'L' + coords.leftInnerExtent + ' ' + (coords.sourceY - offset) + 'A' + (coords.leftLargeArcRadius - offset) + ' ' + (coords.leftSmallArcRadius - offset) + ' 0 0 0 ' + (coords.leftFullExtent - offset) + ' ' + (coords.sourceY - coords.leftSmallArcRadius) + 'L' + (coords.leftFullExtent - offset) + ' ' + coords.verticalLeftInnerExtent + 'A' + (coords.leftLargeArcRadius - offset) + ' ' + (coords.leftLargeArcRadius - offset) + ' 0 0 0 ' + coords.leftInnerExtent + ' ' + (coords.verticalFullExtent + offset) + 'L' + (coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent + offset) + 'A' + (coords.rightLargeArcRadius - offset) + ' ' + (coords.rightLargeArcRadius - offset) + ' 0 0 0 ' + (coords.rightFullExtent + offset - arrowLen) + ' ' + coords.verticalRightInnerExtent + 'L' + (coords.rightFullExtent + offset - arrowLen) + ' ' + (coords.targetY - coords.rightSmallArcRadius) + 'A' + (coords.rightLargeArcRadius - offset) + ' ' + (coords.rightSmallArcRadius - offset) + ' 0 0 0 ' + (coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY - offset) + 'L' + (coords.targetX - arrowLen) + ' ' + (coords.targetY - offset) + (arrowLen > 0 ? 'L' + coords.targetX + ' ' + coords.targetY : '') + 'Z';
} else {
// Bottom path
pathString =
// start at the left of the target node
'M ' + (coords.targetX - arrowLen) + ' ' + (coords.targetY - offset) + ' ' + 'L' + (coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY - offset) + 'A' + (coords.rightLargeArcRadius + offset) + ' ' + (coords.rightSmallArcRadius + offset) + ' 0 0 0 ' + (coords.rightFullExtent - offset - arrowLen) + ' ' + (coords.targetY + coords.rightSmallArcRadius) + 'L' + (coords.rightFullExtent - offset - arrowLen) + ' ' + coords.verticalRightInnerExtent + 'A' + (coords.rightLargeArcRadius + offset) + ' ' + (coords.rightLargeArcRadius + offset) + ' 0 0 0 ' + (coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent + offset) + 'L' + coords.leftInnerExtent + ' ' + (coords.verticalFullExtent + offset) + 'A' + (coords.leftLargeArcRadius + offset) + ' ' + (coords.leftLargeArcRadius + offset) + ' 0 0 0 ' + (coords.leftFullExtent + offset) + ' ' + coords.verticalLeftInnerExtent + 'L' + (coords.leftFullExtent + offset) + ' ' + (coords.sourceY + coords.leftSmallArcRadius) + 'A' + (coords.leftLargeArcRadius + offset) + ' ' + (coords.leftSmallArcRadius + offset) + ' 0 0 0 ' + coords.leftInnerExtent + ' ' + (coords.sourceY - offset) + 'L' + coords.sourceX + ' ' + (coords.sourceY - offset) +
// Walking back
'L' + coords.sourceX + ' ' + (coords.sourceY + offset) + 'L' + coords.leftInnerExtent + ' ' + (coords.sourceY + offset) + 'A' + (coords.leftLargeArcRadius - offset) + ' ' + (coords.leftSmallArcRadius - offset) + ' 0 0 1 ' + (coords.leftFullExtent - offset) + ' ' + (coords.sourceY + coords.leftSmallArcRadius) + 'L' + (coords.leftFullExtent - offset) + ' ' + coords.verticalLeftInnerExtent + 'A' + (coords.leftLargeArcRadius - offset) + ' ' + (coords.leftLargeArcRadius - offset) + ' 0 0 1 ' + coords.leftInnerExtent + ' ' + (coords.verticalFullExtent - offset) + 'L' + (coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent - offset) + 'A' + (coords.rightLargeArcRadius - offset) + ' ' + (coords.rightLargeArcRadius - offset) + ' 0 0 1 ' + (coords.rightFullExtent + offset - arrowLen) + ' ' + coords.verticalRightInnerExtent + 'L' + (coords.rightFullExtent + offset - arrowLen) + ' ' + (coords.targetY + coords.rightSmallArcRadius) + 'A' + (coords.rightLargeArcRadius - offset) + ' ' + (coords.rightSmallArcRadius - offset) + ' 0 0 1 ' + (coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY + offset) + 'L' + (coords.targetX - arrowLen) + ' ' + (coords.targetY + offset) + (arrowLen > 0 ? 'L' + coords.targetX + ' ' + coords.targetY : '') + 'Z';
}
return pathString;
}
function linkPath() {
var curvature = 0.5;
function path(d) {
var arrowLen = d.linkArrowLength;
if (d.link.circular) {
return createCircularClosedPathString(d.link, arrowLen);
} else {
var maxArrowLength = Math.abs((d.link.target.x0 - d.link.source.x1) / 2);
if (arrowLen > maxArrowLength) {
arrowLen = maxArrowLength;
}
var x0 = d.link.source.x1;
var x1 = d.link.target.x0 - arrowLen;
var xi = interpolateNumber(x0, x1);
var x2 = xi(curvature);
var x3 = xi(1 - curvature);
var y0a = d.link.y0 - d.link.width / 2;
var y0b = d.link.y0 + d.link.width / 2;
var y1a = d.link.y1 - d.link.width / 2;
var y1b = d.link.y1 + d.link.width / 2;
var start = 'M' + x0 + ',' + y0a;
var upperCurve = 'C' + x2 + ',' + y0a + ' ' + x3 + ',' + y1a + ' ' + x1 + ',' + y1a;
var lowerCurve = 'C' + x3 + ',' + y1b + ' ' + x2 + ',' + y0b + ' ' + x0 + ',' + y0b;
var rightEnd = arrowLen > 0 ? 'L' + (x1 + arrowLen) + ',' + (y1a + d.link.width / 2) : '';
rightEnd += 'L' + x1 + ',' + y1b;
return start + upperCurve + rightEnd + lowerCurve + 'Z';
}
}
return path;
}
function nodeModel(d, n) {
var tc = tinycolor(n.color);
var zoneThicknessPad = c.nodePadAcross;
var zoneLengthPad = d.nodePad / 2;
n.dx = n.x1 - n.x0;
n.dy = n.y1 - n.y0;
var visibleThickness = n.dx;
var visibleLength = Math.max(0.5, n.dy);
var key = 'node_' + n.pointNumber;
// If it's a group, it's mutable and should be unique
if (n.group) {
key = Lib.randstr();
}
// for event data
n.trace = d.trace;
n.curveNumber = d.trace.index;
return {
index: n.pointNumber,
key: key,
partOfGroup: n.partOfGroup || false,
group: n.group,
traceId: d.key,
trace: d.trace,
node: n,
nodePad: d.nodePad,
nodeLineColor: d.nodeLineColor,
nodeLineWidth: d.nodeLineWidth,
textFont: d.textFont,
size: d.horizontal ? d.height : d.width,
visibleWidth: Math.ceil(visibleThickness),
visibleHeight: visibleLength,
zoneX: -zoneThicknessPad,
zoneY: -zoneLengthPad,
zoneWidth: visibleThickness + 2 * zoneThicknessPad,
zoneHeight: visibleLength + 2 * zoneLengthPad,
labelY: d.horizontal ? n.dy / 2 + 1 : n.dx / 2 + 1,
left: n.originalLayer === 1,
sizeAcross: d.width,
forceLayouts: d.forceLayouts,
horizontal: d.horizontal,
darkBackground: tc.getBrightness() <= 128,
tinyColorHue: Color.tinyRGB(tc),
tinyColorAlpha: tc.getAlpha(),
valueFormat: d.valueFormat,
valueSuffix: d.valueSuffix,
sankey: d.sankey,
graph: d.graph,
arrangement: d.arrangement,
uniqueNodeLabelPathId: [d.guid, d.key, key].join('_'),
interactionState: d.interactionState,
figure: d
};
}
// rendering snippets
function updateNodePositions(sankeyNode) {
sankeyNode.attr('transform', function (d) {
return strTranslate(d.node.x0.toFixed(3), d.node.y0.toFixed(3));
});
}
function updateNodeShapes(sankeyNode) {
sankeyNode.call(updateNodePositions);
}
function updateShapes(sankeyNode, sankeyLink) {
sankeyNode.call(updateNodeShapes);
sankeyLink.attr('d', linkPath());
}
function sizeNode(rect) {
rect.attr('width', function (d) {
return d.node.x1 - d.node.x0;
}).attr('height', function (d) {
return d.visibleHeight;
});
}
function salientEnough(d) {
return d.link.width > 1 || d.linkLineWidth > 0;
}
function sankeyTransform(d) {
var offset = strTranslate(d.translateX, d.translateY);
return offset + (d.horizontal ? 'matrix(1 0 0 1 0 0)' : 'matrix(0 1 1 0 0 0)');
}
// event handling
function attachPointerEvents(selection, sankey, eventSet) {
selection.on('.basic', null) // remove any preexisting handlers
.on('mouseover.basic', function (d) {
if (!d.interactionState.dragInProgress && !d.partOfGroup) {
eventSet.hover(this, d, sankey);
d.interactionState.hovered = [this, d];
}
}).on('mousemove.basic', function (d) {
if (!d.interactionState.dragInProgress && !d.partOfGroup) {
eventSet.follow(this, d);
d.interactionState.hovered = [this, d];
}
}).on('mouseout.basic', function (d) {
if (!d.interactionState.dragInProgress && !d.partOfGroup) {
eventSet.unhover(this, d, sankey);
d.interactionState.hovered = false;
}
}).on('click.basic', function (d) {
if (d.interactionState.hovered) {
eventSet.unhover(this, d, sankey);
d.interactionState.hovered = false;
}
if (!d.interactionState.dragInProgress && !d.partOfGroup) {
eventSet.select(this, d, sankey);
}
});
}
function attachDragHandler(sankeyNode, sankeyLink, callbacks, gd) {
var dragBehavior = d3.behavior.drag().origin(function (d) {
return {
x: d.node.x0 + d.visibleWidth / 2,
y: d.node.y0 + d.visibleHeight / 2
};
}).on('dragstart', function (d) {
if (d.arrangement === 'fixed') return;
Lib.ensureSingle(gd._fullLayout._infolayer, 'g', 'dragcover', function (s) {
gd._fullLayout._dragCover = s;
});
Lib.raiseToTop(this);
d.interactionState.dragInProgress = d.node;
saveCurrentDragPosition(d.node);
if (d.interactionState.hovered) {
callbacks.nodeEvents.unhover.apply(0, d.interactionState.hovered);
d.interactionState.hovered = false;
}
if (d.arrangement === 'snap') {
var forceKey = d.traceId + '|' + d.key;
if (d.forceLayouts[forceKey]) {
d.forceLayouts[forceKey].alpha(1);
} else {
// make a forceLayout if needed
attachForce(sankeyNode, forceKey, d, gd);
}
startForce(sankeyNode, sankeyLink, d, forceKey, gd);
}
}).on('drag', function (d) {
if (d.arrangement === 'fixed') return;
var x = d3.event.x;
var y = d3.event.y;
if (d.arrangement === 'snap') {
d.node.x0 = x - d.visibleWidth / 2;
d.node.x1 = x + d.visibleWidth / 2;
d.node.y0 = y - d.visibleHeight / 2;
d.node.y1 = y + d.visibleHeight / 2;
} else {
if (d.arrangement === 'freeform') {
d.node.x0 = x - d.visibleWidth / 2;
d.node.x1 = x + d.visibleWidth / 2;
}
y = Math.max(0, Math.min(d.size - d.visibleHeight / 2, y));
d.node.y0 = y - d.visibleHeight / 2;
d.node.y1 = y + d.visibleHeight / 2;
}
saveCurrentDragPosition(d.node);
if (d.arrangement !== 'snap') {
d.sankey.update(d.graph);
updateShapes(sankeyNode.filter(sameLayer(d)), sankeyLink);
}
}).on('dragend', function (d) {
if (d.arrangement === 'fixed') return;
d.interactionState.dragInProgress = false;
for (var i = 0; i < d.node.childrenNodes.length; i++) {
d.node.childrenNodes[i].x = d.node.x;
d.node.childrenNodes[i].y = d.node.y;
}
if (d.arrangement !== 'snap') persistFinalNodePositions(d, gd);
});
sankeyNode.on('.drag', null) // remove possible previous handlers
.call(dragBehavior);
}
function attachForce(sankeyNode, forceKey, d, gd) {
// Attach force to nodes in the same column (same x coordinate)
switchToForceFormat(d.graph.nodes);
var nodes = d.graph.nodes.filter(function (n) {
return n.originalX === d.node.originalX;
})
// Filter out children
.filter(function (n) {
return !n.partOfGroup;
});
d.forceLayouts[forceKey] = d3Force.forceSimulation(nodes).alphaDecay(0).force('collide', d3Force.forceCollide().radius(function (n) {
return n.dy / 2 + d.nodePad / 2;
}).strength(1).iterations(c.forceIterations)).force('constrain', snappingForce(sankeyNode, forceKey, nodes, d, gd)).stop();
}
function startForce(sankeyNode, sankeyLink, d, forceKey, gd) {
window.requestAnimationFrame(function faster() {
var i;
for (i = 0; i < c.forceTicksPerFrame; i++) {
d.forceLayouts[forceKey].tick();
}
var nodes = d.graph.nodes;
switchToSankeyFormat(nodes);
d.sankey.update(d.graph);
updateShapes(sankeyNode.filter(sameLayer(d)), sankeyLink);
if (d.forceLayouts[forceKey].alpha() > 0) {
window.requestAnimationFrame(faster);
} else {
// Make sure the final x position is equal to its original value
// because the force simulation will have numerical error
var x = d.node.originalX;
d.node.x0 = x - d.visibleWidth / 2;
d.node.x1 = x + d.visibleWidth / 2;
persistFinalNodePositions(d, gd);
}
});
}
function snappingForce(sankeyNode, forceKey, nodes, d) {
return function _snappingForce() {
var maxVelocity = 0;
for (var i = 0; i < nodes.length; i++) {
var n = nodes[i];
if (n === d.interactionState.dragInProgress) {
// constrain node position to the dragging pointer
n.x = n.lastDraggedX;
n.y = n.lastDraggedY;
} else {
n.vx = (n.originalX - n.x) / c.forceTicksPerFrame; // snap to layer
n.y = Math.min(d.size - n.dy / 2, Math.max(n.dy / 2, n.y)); // constrain to extent
}
maxVelocity = Math.max(maxVelocity, Math.abs(n.vx), Math.abs(n.vy));
}
if (!d.interactionState.dragInProgress && maxVelocity < 0.1 && d.forceLayouts[forceKey].alpha() > 0) {
d.forceLayouts[forceKey].alpha(0); // This will stop the animation loop
}
};
}
// basic data utilities
function persistFinalNodePositions(d, gd) {
var x = [];
var y = [];
for (var i = 0; i < d.graph.nodes.length; i++) {
var nodeX = (d.graph.nodes[i].x0 + d.graph.nodes[i].x1) / 2;
var nodeY = (d.graph.nodes[i].y0 + d.graph.nodes[i].y1) / 2;
x.push(nodeX / d.figure.width);
y.push(nodeY / d.figure.height);
}
Registry.call('_guiRestyle', gd, {
'node.x': [x],
'node.y': [y]
}, d.trace.index).then(function () {
if (gd._fullLayout._dragCover) gd._fullLayout._dragCover.remove();
});
}
function persistOriginalPlace(nodes) {
var distinctLayerPositions = [];
var i;
for (i = 0; i < nodes.length; i++) {
nodes[i].originalX = (nodes[i].x0 + nodes[i].x1) / 2;
nodes[i].originalY = (nodes[i].y0 + nodes[i].y1) / 2;
if (distinctLayerPositions.indexOf(nodes[i].originalX) === -1) {
distinctLayerPositions.push(nodes[i].originalX);
}
}
distinctLayerPositions.sort(function (a, b) {
return a - b;
});
for (i = 0; i < nodes.length; i++) {
nodes[i].originalLayerIndex = distinctLayerPositions.indexOf(nodes[i].originalX);
nodes[i].originalLayer = nodes[i].originalLayerIndex / (distinctLayerPositions.length - 1);
}
}
function saveCurrentDragPosition(d) {
d.lastDraggedX = d.x0 + d.dx / 2;
d.lastDraggedY = d.y0 + d.dy / 2;
}
function sameLayer(d) {
return function (n) {
return n.node.originalX === d.node.originalX;
};
}
function switchToForceFormat(nodes) {
// force uses x, y as centers
for (var i = 0; i < nodes.length; i++) {
nodes[i].y = (nodes[i].y0 + nodes[i].y1) / 2;
nodes[i].x = (nodes[i].x0 + nodes[i].x1) / 2;
}
}
function switchToSankeyFormat(nodes) {
// sankey uses x0, x1, y0, y1
for (var i = 0; i < nodes.length; i++) {
nodes[i].y0 = nodes[i].y - nodes[i].dy / 2;
nodes[i].y1 = nodes[i].y0 + nodes[i].dy;
nodes[i].x0 = nodes[i].x - nodes[i].dx / 2;
nodes[i].x1 = nodes[i].x0 + nodes[i].dx;
}
}
// scene graph
module.exports = function (gd, svg, calcData, layout, callbacks) {
var isStatic = gd._context.staticPlot;
// To prevent animation on first render
var firstRender = false;
Lib.ensureSingle(gd._fullLayout._infolayer, 'g', 'first-render', function () {
firstRender = true;
});
// To prevent animation on dragging
var dragcover = gd._fullLayout._dragCover;
var styledData = calcData.filter(function (d) {
return unwrap(d).trace.visible;
}).map(sankeyModel.bind(null, layout));
var sankey = svg.selectAll('.' + c.cn.sankey).data(styledData, keyFun);
sankey.exit().remove();
sankey.enter().append('g').classed(c.cn.sankey, true).style('box-sizing', 'content-box').style('position', 'absolute').style('left', 0).style('shape-rendering', 'geometricPrecision').style('pointer-events', isStatic ? 'none' : 'auto').attr('transform', sankeyTransform);
sankey.each(function (d, i) {
gd._fullData[i]._sankey = d;
// Create dragbox if missing
var dragboxClassName = 'bgsankey-' + d.trace.uid + '-' + i;
Lib.ensureSingle(gd._fullLayout._draggers, 'rect', dragboxClassName);
gd._fullData[i]._bgRect = d3.select('.' + dragboxClassName);
// Style dragbox
gd._fullData[i]._bgRect.style('pointer-events', isStatic ? 'none' : 'all').attr('width', d.width).attr('height', d.height).attr('x', d.translateX).attr('y', d.translateY).classed('bgsankey', true).style({
fill: 'transparent',
'stroke-width': 0
});
});
sankey.transition().ease(c.ease).duration(c.duration).attr('transform', sankeyTransform);
var sankeyLinks = sankey.selectAll('.' + c.cn.sankeyLinks).data(repeat, keyFun);
sankeyLinks.enter().append('g').classed(c.cn.sankeyLinks, true).style('fill', 'none');
var sankeyLink = sankeyLinks.selectAll('.' + c.cn.sankeyLink).data(function (d) {
var links = d.graph.links;
return links.filter(function (l) {
return l.value;
}).map(linkModel.bind(null, d));
}, keyFun);
sankeyLink.enter().append('path').classed(c.cn.sankeyLink, true).call(attachPointerEvents, sankey, callbacks.linkEvents);
sankeyLink.style('stroke', function (d) {
return salientEnough(d) ? Color.tinyRGB(tinycolor(d.linkLineColor)) : d.tinyColorHue;
}).style('stroke-opacity', function (d) {
return salientEnough(d) ? Color.opacity(d.linkLineColor) : d.tinyColorAlpha;
}).style('fill', function (d) {
return d.tinyColorHue;
}).style('fill-opacity', function (d) {
return d.tinyColorAlpha;
}).style('stroke-width', function (d) {
return salientEnough(d) ? d.linkLineWidth : 1;
}).attr('d', linkPath());
sankeyLink.style('opacity', function () {
return gd._context.staticPlot || firstRender || dragcover ? 1 : 0;
}).transition().ease(c.ease).duration(c.duration).style('opacity', 1);
sankeyLink.exit().transition().ease(c.ease).duration(c.duration).style('opacity', 0).remove();
var sankeyNodeSet = sankey.selectAll('.' + c.cn.sankeyNodeSet).data(repeat, keyFun);
sankeyNodeSet.enter().append('g').classed(c.cn.sankeyNodeSet, true);
sankeyNodeSet.style('cursor', function (d) {
switch (d.arrangement) {
case 'fixed':
return 'default';
case 'perpendicular':
return 'ns-resize';
default:
return 'move';
}
});
var sankeyNode = sankeyNodeSet.selectAll('.' + c.cn.sankeyNode).data(function (d) {
var nodes = d.graph.nodes;
persistOriginalPlace(nodes);
return nodes.map(nodeModel.bind(null, d));
}, keyFun);
sankeyNode.enter().append('g').classed(c.cn.sankeyNode, true).call(updateNodePositions).style('opacity', function (n) {
return (gd._context.staticPlot || firstRender) && !n.partOfGroup ? 1 : 0;
});
sankeyNode.call(attachPointerEvents, sankey, callbacks.nodeEvents).call(attachDragHandler, sankeyLink, callbacks, gd); // has to be here as it binds sankeyLink
sankeyNode.transition().ease(c.ease).duration(c.duration).call(updateNodePositions).style('opacity', function (n) {
return n.partOfGroup ? 0 : 1;
});
sankeyNode.exit().transition().ease(c.ease).duration(c.duration).style('opacity', 0).remove();
var nodeRect = sankeyNode.selectAll('.' + c.cn.nodeRect).data(repeat);
nodeRect.enter().append('rect').classed(c.cn.nodeRect, true).call(sizeNode);
nodeRect.style('stroke-width', function (d) {
return d.nodeLineWidth;
}).style('stroke', function (d) {
return Color.tinyRGB(tinycolor(d.nodeLineColor));
}).style('stroke-opacity', function (d) {
return Color.opacity(d.nodeLineColor);
}).style('fill', function (d) {
return d.tinyColorHue;
}).style('fill-opacity', function (d) {
return d.tinyColorAlpha;
});
nodeRect.transition().ease(c.ease).duration(c.duration).call(sizeNode);
var nodeLabel = sankeyNode.selectAll('.' + c.cn.nodeLabel).data(repeat);
nodeLabel.enter().append('text').classed(c.cn.nodeLabel, true).style('cursor', 'default');
nodeLabel.attr('data-notex', 1) // prohibit tex interpretation until we can handle tex and regular text together
.text(function (d) {
return d.node.label;
}).each(function (d) {
var e = d3.select(this);
Drawing.font(e, d.textFont);
svgTextUtils.convertToTspans(e, gd);
}).style('text-shadow', svgTextUtils.makeTextShadow(gd._fullLayout.paper_bgcolor)).attr('text-anchor', function (d) {
return d.horizontal && d.left ? 'end' : 'start';
}).attr('transform', function (d) {
var e = d3.select(this);
// how much to shift a multi-line label to center it vertically.
var nLines = svgTextUtils.lineCount(e);
var blockHeight = d.textFont.size * ((nLines - 1) * LINE_SPACING - CAP_SHIFT);
var posX = d.nodeLineWidth / 2 + TEXTPAD;
var posY = ((d.horizontal ? d.visibleHeight : d.visibleWidth) - blockHeight) / 2;
if (d.horizontal) {
if (d.left) {
posX = -posX;
} else {
posX += d.visibleWidth;
}
}
var flipText = d.horizontal ? '' : 'scale(-1,1)' + strRotate(90);
return strTranslate(d.horizontal ? posX : posY, d.horizontal ? posY : posX) + flipText;
});
nodeLabel.transition().ease(c.ease).duration(c.duration);
};
/***/ }),
/***/ 80784:
/***/ (function(module) {
"use strict";
module.exports = function selectPoints(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var selection = [];
var fullData = cd[0].trace;
var nodes = fullData._sankey.graph.nodes;
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.partOfGroup) continue; // Those are invisible
// Position of node's centroid
var pos = [(node.x0 + node.x1) / 2, (node.y0 + node.y1) / 2];
// Swap x and y if trace is vertical
if (fullData.orientation === 'v') pos.reverse();
if (selectionTester && selectionTester.contains(pos, false, i, searchInfo)) {
selection.push({
pointNumber: node.pointNumber
// TODO: add eventData
});
}
}
return selection;
};
/***/ }),
/***/ 67368:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
// arrayOk attributes, merge them into calcdata array
module.exports = function arraysToCalcdata(cd, trace) {
// so each point knows which index it originally came from
for (var i = 0; i < cd.length; i++) cd[i].i = i;
Lib.mergeArray(trace.text, cd, 'tx');
Lib.mergeArray(trace.texttemplate, cd, 'txt');
Lib.mergeArray(trace.hovertext, cd, 'htx');
Lib.mergeArray(trace.customdata, cd, 'data');
Lib.mergeArray(trace.textposition, cd, 'tp');
if (trace.textfont) {
Lib.mergeArrayCastPositive(trace.textfont.size, cd, 'ts');
Lib.mergeArray(trace.textfont.color, cd, 'tc');
Lib.mergeArray(trace.textfont.family, cd, 'tf');
}
var marker = trace.marker;
if (marker) {
Lib.mergeArrayCastPositive(marker.size, cd, 'ms');
Lib.mergeArrayCastPositive(marker.opacity, cd, 'mo');
Lib.mergeArray(marker.symbol, cd, 'mx');
Lib.mergeArray(marker.angle, cd, 'ma');
Lib.mergeArray(marker.standoff, cd, 'mf');
Lib.mergeArray(marker.color, cd, 'mc');
var markerLine = marker.line;
if (marker.line) {
Lib.mergeArray(markerLine.color, cd, 'mlc');
Lib.mergeArrayCastPositive(markerLine.width, cd, 'mlw');
}
var markerGradient = marker.gradient;
if (markerGradient && markerGradient.type !== 'none') {
Lib.mergeArray(markerGradient.type, cd, 'mgt');
Lib.mergeArray(markerGradient.color, cd, 'mgc');
}
}
};
/***/ }),
/***/ 49992:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var colorScaleAttrs = __webpack_require__(99732);
var fontAttrs = __webpack_require__(71936);
var dash = (__webpack_require__(9392)/* .dash */ .u);
var pattern = (__webpack_require__(9392)/* .pattern */ .c);
var Drawing = __webpack_require__(49348);
var constants = __webpack_require__(5892);
var extendFlat = (__webpack_require__(55016).extendFlat);
var makeFillcolorAttr = __webpack_require__(94352);
function axisPeriod(axis) {
return {
valType: 'any',
dflt: 0,
editType: 'calc',
description: ['Only relevant when the axis `type` is *date*.', 'Sets the period positioning in milliseconds or *M* on the ' + axis + ' axis.', 'Special values in the form of *M* could be used to declare', 'the number of months. In this case `n` must be a positive integer.'].join(' ')
};
}
function axisPeriod0(axis) {
return {
valType: 'any',
editType: 'calc',
description: ['Only relevant when the axis `type` is *date*.', 'Sets the base for period positioning in milliseconds or date string on the ' + axis + ' axis.', 'When `' + axis + 'period` is round number of weeks,', 'the `' + axis + 'period0` by default would be on a Sunday i.e. 2000-01-02,', 'otherwise it would be at 2000-01-01.'].join(' ')
};
}
function axisPeriodAlignment(axis) {
return {
valType: 'enumerated',
values: ['start', 'middle', 'end'],
dflt: 'middle',
editType: 'calc',
description: ['Only relevant when the axis `type` is *date*.', 'Sets the alignment of data points on the ' + axis + ' axis.'].join(' ')
};
}
module.exports = {
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
anim: true,
description: 'Sets the x coordinates.'
},
x0: {
valType: 'any',
dflt: 0,
editType: 'calc+clearAxisTypes',
anim: true,
description: ['Alternate to `x`.', 'Builds a linear space of x coordinates.', 'Use with `dx`', 'where `x0` is the starting coordinate and `dx` the step.'].join(' ')
},
dx: {
valType: 'number',
dflt: 1,
editType: 'calc',
anim: true,
description: ['Sets the x coordinate step.', 'See `x0` for more info.'].join(' ')
},
y: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
anim: true,
description: 'Sets the y coordinates.'
},
y0: {
valType: 'any',
dflt: 0,
editType: 'calc+clearAxisTypes',
anim: true,
description: ['Alternate to `y`.', 'Builds a linear space of y coordinates.', 'Use with `dy`', 'where `y0` is the starting coordinate and `dy` the step.'].join(' ')
},
dy: {
valType: 'number',
dflt: 1,
editType: 'calc',
anim: true,
description: ['Sets the y coordinate step.', 'See `y0` for more info.'].join(' ')
},
xperiod: axisPeriod('x'),
yperiod: axisPeriod('y'),
xperiod0: axisPeriod0('x0'),
yperiod0: axisPeriod0('y0'),
xperiodalignment: axisPeriodAlignment('x'),
yperiodalignment: axisPeriodAlignment('y'),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
offsetgroup: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['Set several traces linked to the same position axis', 'or matching axes to the same', 'offsetgroup where bars of the same position coordinate will line up.'].join(' ')
},
alignmentgroup: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['Set several traces linked to the same position axis', 'or matching axes to the same', 'alignmentgroup. This controls whether bars compute their positional', 'range dependently or independently.'].join(' ')
},
stackgroup: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['Set several scatter traces (on the same subplot) to the same', 'stackgroup in order to add their y values (or their x values if', '`orientation` is *h*). If blank or omitted this trace will not be', 'stacked. Stacking also turns `fill` on by default, using *tonexty*', '(*tonextx*) if `orientation` is *h* (*v*) and sets the default', '`mode` to *lines* irrespective of point count.', 'You can only stack on a numeric (linear or log) axis.', 'Traces in a `stackgroup` will only fill to (or be filled to) other', 'traces in the same group. With multiple `stackgroup`s or some', 'traces stacked and some not, if fill-linked traces are not already', 'consecutive, the later ones will be pushed down in the drawing order.'].join(' ')
},
orientation: {
valType: 'enumerated',
values: ['v', 'h'],
editType: 'calc',
description: ['Only relevant in the following cases:', '1. when `scattermode` is set to *group*.', '2. when `stackgroup` is used, and only the first', '`orientation` found in the `stackgroup` will be used - including', 'if `visible` is *legendonly* but not if it is `false`. Sets the', 'stacking direction. With *v* (*h*), the y (x) values of subsequent', 'traces are added. Also affects the default value of `fill`.'].join(' ')
},
groupnorm: {
valType: 'enumerated',
values: ['', 'fraction', 'percent'],
dflt: '',
editType: 'calc',
description: ['Only relevant when `stackgroup` is used, and only the first', '`groupnorm` found in the `stackgroup` will be used - including', 'if `visible` is *legendonly* but not if it is `false`.', 'Sets the normalization for the sum of this `stackgroup`.', 'With *fraction*, the value of each trace at each location is', 'divided by the sum of all trace values at that location.', '*percent* is the same but multiplied by 100 to show percentages.', 'If there are multiple subplots, or multiple `stackgroup`s on one', 'subplot, each will be normalized within its own set.'].join(' ')
},
stackgaps: {
valType: 'enumerated',
values: ['infer zero', 'interpolate'],
dflt: 'infer zero',
editType: 'calc',
description: ['Only relevant when `stackgroup` is used, and only the first', '`stackgaps` found in the `stackgroup` will be used - including', 'if `visible` is *legendonly* but not if it is `false`.', 'Determines how we handle locations at which other traces in this', 'group have data but this one does not.', 'With *infer zero* we insert a zero at these locations.', 'With *interpolate* we linearly interpolate between existing', 'values, and extrapolate a constant beyond the existing values.'
// TODO - implement interrupt mode
// '*interrupt* omits this trace from the stack at this location by',
// 'dropping abruptly, midway between the existing and missing locations.'
].join(' ')
},
text: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'calc',
description: ['Sets text elements associated with each (x,y) pair.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (x,y) coordinates.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
},
texttemplate: texttemplateAttrs({}, {}),
hovertext: {
valType: 'string',
dflt: '',
arrayOk: true,
editType: 'style',
description: ['Sets hover text elements associated with each (x,y) pair.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (x,y) coordinates.', 'To be seen, trace `hoverinfo` must contain a *text* flag.'].join(' ')
},
mode: {
valType: 'flaglist',
flags: ['lines', 'markers', 'text'],
extras: ['none'],
editType: 'calc',
description: ['Determines the drawing mode for this scatter trace.', 'If the provided `mode` includes *text* then the `text` elements', 'appear at the coordinates. Otherwise, the `text` elements', 'appear on hover.', 'If there are less than ' + constants.PTS_LINESONLY + ' points', 'and the trace is not stacked', 'then the default is *lines+markers*. Otherwise, *lines*.'].join(' ')
},
hoveron: {
valType: 'flaglist',
flags: ['points', 'fills'],
editType: 'style',
description: ['Do the hover effects highlight individual points (markers or', 'line points) or do they highlight filled regions?', 'If the fill is *toself* or *tonext* and there are no markers', 'or text, then the default is *fills*, otherwise it is *points*.'].join(' ')
},
hovertemplate: hovertemplateAttrs({}, {
keys: constants.eventDataKeys
}),
line: {
color: {
valType: 'color',
editType: 'style',
anim: true,
description: 'Sets the line color.'
},
width: {
valType: 'number',
min: 0,
dflt: 2,
editType: 'style',
anim: true,
description: 'Sets the line width (in px).'
},
shape: {
valType: 'enumerated',
values: ['linear', 'spline', 'hv', 'vh', 'hvh', 'vhv'],
dflt: 'linear',
editType: 'plot',
description: ['Determines the line shape.', 'With *spline* the lines are drawn using spline interpolation.', 'The other available values correspond to step-wise line shapes.'].join(' ')
},
smoothing: {
valType: 'number',
min: 0,
max: 1.3,
dflt: 1,
editType: 'plot',
description: ['Has an effect only if `shape` is set to *spline*', 'Sets the amount of smoothing.', '*0* corresponds to no smoothing (equivalent to a *linear* shape).'].join(' ')
},
dash: extendFlat({}, dash, {
editType: 'style'
}),
backoff: {
// we want to have a similar option for the start of the line
valType: 'number',
min: 0,
dflt: 'auto',
arrayOk: true,
editType: 'plot',
description: ['Sets the line back off from the end point of the nth line segment (in px).', 'This option is useful e.g. to avoid overlap with arrowhead markers.', 'With *auto* the lines would trim before markers if `marker.angleref` is set to *previous*.'].join(' ')
},
simplify: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: ['Simplifies lines by removing nearly-collinear points. When transitioning', 'lines, it may be desirable to disable this so that the number of points', 'along the resulting SVG path is unaffected.'].join(' ')
},
editType: 'plot'
},
connectgaps: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['Determines whether or not gaps', '(i.e. {nan} or missing values)', 'in the provided data arrays are connected.'].join(' ')
},
cliponaxis: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: ['Determines whether or not markers and text nodes', 'are clipped about the subplot axes.', 'To show markers and text nodes above axis lines and tick labels,', 'make sure to set `xaxis.layer` and `yaxis.layer` to *below traces*.'].join(' ')
},
fill: {
valType: 'enumerated',
values: ['none', 'tozeroy', 'tozerox', 'tonexty', 'tonextx', 'toself', 'tonext'],
editType: 'calc',
description: ['Sets the area to fill with a solid color.', 'Defaults to *none* unless this trace is stacked, then it gets', '*tonexty* (*tonextx*) if `orientation` is *v* (*h*)', 'Use with `fillcolor` if not *none*.', '*tozerox* and *tozeroy* fill to x=0 and y=0 respectively.', '*tonextx* and *tonexty* fill between the endpoints of this', 'trace and the endpoints of the trace before it, connecting those', 'endpoints with straight lines (to make a stacked area graph);', 'if there is no trace before it, they behave like *tozerox* and', '*tozeroy*.', '*toself* connects the endpoints of the trace (or each segment', 'of the trace if it has gaps) into a closed shape.', '*tonext* fills the space between two traces if one completely', 'encloses the other (eg consecutive contour lines), and behaves like', '*toself* if there is no trace before it. *tonext* should not be', 'used if one trace does not enclose the other.', 'Traces in a `stackgroup` will only fill to (or be filled to) other', 'traces in the same group. With multiple `stackgroup`s or some', 'traces stacked and some not, if fill-linked traces are not already', 'consecutive, the later ones will be pushed down in the drawing order.'].join(' ')
},
fillcolor: makeFillcolorAttr(true),
fillgradient: extendFlat({
type: {
valType: 'enumerated',
values: ['radial', 'horizontal', 'vertical', 'none'],
dflt: 'none',
editType: 'calc',
description: ['Sets the type/orientation of the color gradient for the fill.', 'Defaults to *none*.'].join(' ')
},
start: {
valType: 'number',
editType: 'calc',
description: ['Sets the gradient start value.', 'It is given as the absolute position on the axis determined by', 'the orientiation. E.g., if orientation is *horizontal*, the', 'gradient will be horizontal and start from the x-position', 'given by start. If omitted, the gradient starts at the lowest', 'value of the trace along the respective axis.', 'Ignored if orientation is *radial*.'].join(' ')
},
stop: {
valType: 'number',
editType: 'calc',
description: ['Sets the gradient end value.', 'It is given as the absolute position on the axis determined by', 'the orientiation. E.g., if orientation is *horizontal*, the', 'gradient will be horizontal and end at the x-position', 'given by end. If omitted, the gradient ends at the highest', 'value of the trace along the respective axis.', 'Ignored if orientation is *radial*.'].join(' ')
},
colorscale: {
valType: 'colorscale',
editType: 'style',
description: ['Sets the fill gradient colors as a color scale.', 'The color scale is interpreted as a gradient', 'applied in the direction specified by *orientation*,', 'from the lowest to the highest value of the scatter', 'plot along that axis, or from the center to the most', 'distant point from it, if orientation is *radial*.'].join(' ')
},
editType: 'calc',
description: ['Sets a fill gradient.', 'If not specified, the fillcolor is used instead.'].join(' ')
}),
fillpattern: pattern,
marker: extendFlat({
symbol: {
valType: 'enumerated',
values: Drawing.symbolList,
dflt: 'circle',
arrayOk: true,
editType: 'style',
description: ['Sets the marker symbol type.', 'Adding 100 is equivalent to appending *-open* to a symbol name.', 'Adding 200 is equivalent to appending *-dot* to a symbol name.', 'Adding 300 is equivalent to appending *-open-dot*', 'or *dot-open* to a symbol name.'].join(' ')
},
opacity: {
valType: 'number',
min: 0,
max: 1,
arrayOk: true,
editType: 'style',
anim: true,
description: 'Sets the marker opacity.'
},
angle: {
valType: 'angle',
dflt: 0,
arrayOk: true,
editType: 'plot',
anim: false,
// TODO: possibly set to true in future
description: ['Sets the marker angle in respect to `angleref`.'].join(' ')
},
angleref: {
valType: 'enumerated',
values: ['previous', 'up'],
dflt: 'up',
editType: 'plot',
anim: false,
description: ['Sets the reference for marker angle.', 'With *previous*, angle 0 points along the line from the previous point to this one.', 'With *up*, angle 0 points toward the top of the screen.'].join(' ')
},
standoff: {
valType: 'number',
min: 0,
dflt: 0,
arrayOk: true,
editType: 'plot',
anim: true,
description: ['Moves the marker away from the data point in the direction of `angle` (in px).', 'This can be useful for example if you have another marker at this', 'location and you want to point an arrowhead marker at it.'].join(' ')
},
size: {
valType: 'number',
min: 0,
dflt: 6,
arrayOk: true,
editType: 'calc',
anim: true,
description: 'Sets the marker size (in px).'
},
maxdisplayed: {
valType: 'number',
min: 0,
dflt: 0,
editType: 'plot',
description: ['Sets a maximum number of points to be drawn on the graph.', '*0* corresponds to no limit.'].join(' ')
},
sizeref: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: ['Has an effect only if `marker.size` is set to a numerical array.', 'Sets the scale factor used to determine the rendered size of', 'marker points. Use with `sizemin` and `sizemode`.'].join(' ')
},
sizemin: {
valType: 'number',
min: 0,
dflt: 0,
editType: 'calc',
description: ['Has an effect only if `marker.size` is set to a numerical array.', 'Sets the minimum size (in px) of the rendered marker points.'].join(' ')
},
sizemode: {
valType: 'enumerated',
values: ['diameter', 'area'],
dflt: 'diameter',
editType: 'calc',
description: ['Has an effect only if `marker.size` is set to a numerical array.', 'Sets the rule for which the data in `size` is converted', 'to pixels.'].join(' ')
},
line: extendFlat({
width: {
valType: 'number',
min: 0,
arrayOk: true,
editType: 'style',
anim: true,
description: 'Sets the width (in px) of the lines bounding the marker points.'
},
editType: 'calc'
}, colorScaleAttrs('marker.line', {
anim: true
})),
gradient: {
type: {
valType: 'enumerated',
values: ['radial', 'horizontal', 'vertical', 'none'],
arrayOk: true,
dflt: 'none',
editType: 'calc',
description: ['Sets the type of gradient used to fill the markers'].join(' ')
},
color: {
valType: 'color',
arrayOk: true,
editType: 'calc',
description: ['Sets the final color of the gradient fill:', 'the center color for radial, the right for horizontal,', 'or the bottom for vertical.'].join(' ')
},
editType: 'calc'
},
editType: 'calc'
}, colorScaleAttrs('marker', {
anim: true
})),
selected: {
marker: {
opacity: {
valType: 'number',
min: 0,
max: 1,
editType: 'style',
description: 'Sets the marker opacity of selected points.'
},
color: {
valType: 'color',
editType: 'style',
description: 'Sets the marker color of selected points.'
},
size: {
valType: 'number',
min: 0,
editType: 'style',
description: 'Sets the marker size of selected points.'
},
editType: 'style'
},
textfont: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the text font color of selected points.'
},
editType: 'style'
},
editType: 'style'
},
unselected: {
marker: {
opacity: {
valType: 'number',
min: 0,
max: 1,
editType: 'style',
description: 'Sets the marker opacity of unselected points, applied only when a selection exists.'
},
color: {
valType: 'color',
editType: 'style',
description: 'Sets the marker color of unselected points, applied only when a selection exists.'
},
size: {
valType: 'number',
min: 0,
editType: 'style',
description: 'Sets the marker size of unselected points, applied only when a selection exists.'
},
editType: 'style'
},
textfont: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the text font color of unselected points, applied only when a selection exists.'
},
editType: 'style'
},
editType: 'style'
},
textposition: {
valType: 'enumerated',
values: ['top left', 'top center', 'top right', 'middle left', 'middle center', 'middle right', 'bottom left', 'bottom center', 'bottom right'],
dflt: 'middle center',
arrayOk: true,
editType: 'calc',
description: ['Sets the positions of the `text` elements', 'with respects to the (x,y) coordinates.'].join(' ')
},
textfont: fontAttrs({
editType: 'calc',
colorEditType: 'style',
arrayOk: true,
description: 'Sets the text font.'
}),
zorder: {
valType: 'integer',
dflt: 0,
editType: 'plot',
description: ['Sets the layer on which this trace is displayed, relative to', 'other SVG traces on the same subplot. SVG traces with higher `zorder`', 'appear in front of those with lower `zorder`.'].join(' ')
}
};
/***/ }),
/***/ 43792:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var Axes = __webpack_require__(81536);
var alignPeriod = __webpack_require__(82260);
var BADNUM = (__webpack_require__(41752).BADNUM);
var subTypes = __webpack_require__(76640);
var calcColorscale = __webpack_require__(67536);
var arraysToCalcdata = __webpack_require__(67368);
var calcSelection = __webpack_require__(62496);
function calc(gd, trace) {
var fullLayout = gd._fullLayout;
var xa = trace._xA = Axes.getFromId(gd, trace.xaxis || 'x', 'x');
var ya = trace._yA = Axes.getFromId(gd, trace.yaxis || 'y', 'y');
var origX = xa.makeCalcdata(trace, 'x');
var origY = ya.makeCalcdata(trace, 'y');
var xObj = alignPeriod(trace, xa, 'x', origX);
var yObj = alignPeriod(trace, ya, 'y', origY);
var x = xObj.vals;
var y = yObj.vals;
var serieslen = trace._length;
var cd = new Array(serieslen);
var ids = trace.ids;
var stackGroupOpts = getStackOpts(trace, fullLayout, xa, ya);
var interpolateGaps = false;
var isV, i, j, k, interpolate, vali;
setFirstScatter(fullLayout, trace);
var xAttr = 'x';
var yAttr = 'y';
var posAttr;
if (stackGroupOpts) {
Lib.pushUnique(stackGroupOpts.traceIndices, trace._expandedIndex);
isV = stackGroupOpts.orientation === 'v';
// size, like we use for bar
if (isV) {
yAttr = 's';
posAttr = 'x';
} else {
xAttr = 's';
posAttr = 'y';
}
interpolate = stackGroupOpts.stackgaps === 'interpolate';
} else {
var ppad = calcMarkerSize(trace, serieslen);
calcAxisExpansion(gd, trace, xa, ya, x, y, ppad);
}
var hasPeriodX = !!trace.xperiodalignment;
var hasPeriodY = !!trace.yperiodalignment;
for (i = 0; i < serieslen; i++) {
var cdi = cd[i] = {};
var xValid = isNumeric(x[i]);
var yValid = isNumeric(y[i]);
if (xValid && yValid) {
cdi[xAttr] = x[i];
cdi[yAttr] = y[i];
if (hasPeriodX) {
cdi.orig_x = origX[i]; // used by hover
cdi.xEnd = xObj.ends[i];
cdi.xStart = xObj.starts[i];
}
if (hasPeriodY) {
cdi.orig_y = origY[i]; // used by hover
cdi.yEnd = yObj.ends[i];
cdi.yStart = yObj.starts[i];
}
} else if (stackGroupOpts && (isV ? xValid : yValid)) {
// if we're stacking we need to hold on to all valid positions
// even with invalid sizes
cdi[posAttr] = isV ? x[i] : y[i];
cdi.gap = true;
if (interpolate) {
cdi.s = BADNUM;
interpolateGaps = true;
} else {
cdi.s = 0;
}
} else {
cdi[xAttr] = cdi[yAttr] = BADNUM;
}
if (ids) {
cdi.id = String(ids[i]);
}
}
arraysToCalcdata(cd, trace);
calcColorscale(gd, trace);
calcSelection(cd, trace);
if (stackGroupOpts) {
// remove bad positions and sort
// note that original indices get added to cd in arraysToCalcdata
i = 0;
while (i < cd.length) {
if (cd[i][posAttr] === BADNUM) {
cd.splice(i, 1);
} else i++;
}
Lib.sort(cd, function (a, b) {
return a[posAttr] - b[posAttr] || a.i - b.i;
});
if (interpolateGaps) {
// first fill the beginning with constant from the first point
i = 0;
while (i < cd.length - 1 && cd[i].gap) {
i++;
}
vali = cd[i].s;
if (!vali) vali = cd[i].s = 0; // in case of no data AT ALL in this trace - use 0
for (j = 0; j < i; j++) {
cd[j].s = vali;
}
// then fill the end with constant from the last point
k = cd.length - 1;
while (k > i && cd[k].gap) {
k--;
}
vali = cd[k].s;
for (j = cd.length - 1; j > k; j--) {
cd[j].s = vali;
}
// now interpolate internal gaps linearly
while (i < k) {
i++;
if (cd[i].gap) {
j = i + 1;
while (cd[j].gap) {
j++;
}
var pos0 = cd[i - 1][posAttr];
var size0 = cd[i - 1].s;
var m = (cd[j].s - size0) / (cd[j][posAttr] - pos0);
while (i < j) {
cd[i].s = size0 + (cd[i][posAttr] - pos0) * m;
i++;
}
}
}
}
}
return cd;
}
function calcAxisExpansion(gd, trace, xa, ya, x, y, ppad) {
var serieslen = trace._length;
var fullLayout = gd._fullLayout;
var xId = xa._id;
var yId = ya._id;
var firstScatter = fullLayout._firstScatter[firstScatterGroup(trace)] === trace.uid;
var stackOrientation = (getStackOpts(trace, fullLayout, xa, ya) || {}).orientation;
var fill = trace.fill;
// cancel minimum tick spacings (only applies to bars and boxes)
xa._minDtick = 0;
ya._minDtick = 0;
// check whether bounds should be tight, padded, extended to zero...
// most cases both should be padded on both ends, so start with that.
var xOptions = {
padded: true
};
var yOptions = {
padded: true
};
if (ppad) {
xOptions.ppad = yOptions.ppad = ppad;
}
// TODO: text size
var openEnded = serieslen < 2 || x[0] !== x[serieslen - 1] || y[0] !== y[serieslen - 1];
if (openEnded && (fill === 'tozerox' || fill === 'tonextx' && (firstScatter || stackOrientation === 'h'))) {
// include zero (tight) and extremes (padded) if fill to zero
// (unless the shape is closed, then it's just filling the shape regardless)
xOptions.tozero = true;
} else if (!(trace.error_y || {}).visible && (
// if no error bars, markers or text, or fill to y=0 remove x padding
fill === 'tonexty' || fill === 'tozeroy' || !subTypes.hasMarkers(trace) && !subTypes.hasText(trace))) {
xOptions.padded = false;
xOptions.ppad = 0;
}
if (openEnded && (fill === 'tozeroy' || fill === 'tonexty' && (firstScatter || stackOrientation === 'v'))) {
// now check for y - rather different logic, though still mostly padded both ends
// include zero (tight) and extremes (padded) if fill to zero
// (unless the shape is closed, then it's just filling the shape regardless)
yOptions.tozero = true;
} else if (fill === 'tonextx' || fill === 'tozerox') {
// tight y: any x fill
yOptions.padded = false;
}
// N.B. asymmetric splom traces call this with blank {} xa or ya
if (xId) trace._extremes[xId] = Axes.findExtremes(xa, x, xOptions);
if (yId) trace._extremes[yId] = Axes.findExtremes(ya, y, yOptions);
}
function calcMarkerSize(trace, serieslen) {
if (!subTypes.hasMarkers(trace)) return;
// Treat size like x or y arrays --- Run d2c
// this needs to go before ppad computation
var marker = trace.marker;
var sizeref = 1.6 * (trace.marker.sizeref || 1);
var markerTrans;
if (trace.marker.sizemode === 'area') {
markerTrans = function (v) {
return Math.max(Math.sqrt((v || 0) / sizeref), 3);
};
} else {
markerTrans = function (v) {
return Math.max((v || 0) / sizeref, 3);
};
}
if (Lib.isArrayOrTypedArray(marker.size)) {
// I tried auto-type but category and dates dont make much sense.
var ax = {
type: 'linear'
};
Axes.setConvert(ax);
var s = ax.makeCalcdata(trace.marker, 'size');
var sizeOut = new Array(serieslen);
for (var i = 0; i < serieslen; i++) {
sizeOut[i] = markerTrans(s[i]);
}
return sizeOut;
} else {
return markerTrans(marker.size);
}
}
/**
* mark the first scatter trace for each subplot
* note that scatter and scattergl each get their own first trace
* note also that I'm doing this during calc rather than supplyDefaults
* so I don't need to worry about transforms, but if we ever do
* per-trace calc this will get confused.
*/
function setFirstScatter(fullLayout, trace) {
var group = firstScatterGroup(trace);
var firstScatter = fullLayout._firstScatter;
if (!firstScatter[group]) firstScatter[group] = trace.uid;
}
function firstScatterGroup(trace) {
var stackGroup = trace.stackgroup;
return trace.xaxis + trace.yaxis + trace.type + (stackGroup ? '-' + stackGroup : '');
}
function getStackOpts(trace, fullLayout, xa, ya) {
var stackGroup = trace.stackgroup;
if (!stackGroup) return;
var stackOpts = fullLayout._scatterStackOpts[xa._id + ya._id][stackGroup];
var stackAx = stackOpts.orientation === 'v' ? ya : xa;
// Allow stacking only on numeric axes
// calc is a little late to be figuring this out, but during supplyDefaults
// we don't know the axis type yet
if (stackAx.type === 'linear' || stackAx.type === 'log') return stackOpts;
}
module.exports = {
calc: calc,
calcMarkerSize: calcMarkerSize,
calcAxisExpansion: calcAxisExpansion,
setFirstScatter: setFirstScatter,
getStackOpts: getStackOpts
};
/***/ }),
/***/ 62496:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
module.exports = function calcSelection(cd, trace) {
if (Lib.isArrayOrTypedArray(trace.selectedpoints)) {
Lib.tagSelected(cd, trace);
}
};
/***/ }),
/***/ 67536:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var calcColorscale = __webpack_require__(60416);
var subTypes = __webpack_require__(76640);
module.exports = function calcMarkerColorscale(gd, trace) {
if (subTypes.hasLines(trace) && hasColorscale(trace, 'line')) {
calcColorscale(gd, trace, {
vals: trace.line.color,
containerStr: 'line',
cLetter: 'c'
});
}
if (subTypes.hasMarkers(trace)) {
if (hasColorscale(trace, 'marker')) {
calcColorscale(gd, trace, {
vals: trace.marker.color,
containerStr: 'marker',
cLetter: 'c'
});
}
if (hasColorscale(trace, 'marker.line')) {
calcColorscale(gd, trace, {
vals: trace.marker.line.color,
containerStr: 'marker.line',
cLetter: 'c'
});
}
}
};
/***/ }),
/***/ 5892:
/***/ (function(module) {
"use strict";
module.exports = {
PTS_LINESONLY: 20,
// fixed parameters of clustering and clipping algorithms
// fraction of clustering tolerance "so close we don't even consider it a new point"
minTolerance: 0.2,
// how fast does clustering tolerance increase as you get away from the visible region
toleranceGrowth: 10,
// number of viewport sizes away from the visible region
// at which we clip all lines to the perimeter
maxScreensAway: 20,
eventDataKeys: []
};
/***/ }),
/***/ 2104:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var calc = __webpack_require__(43792);
var setGroupPositions = (__webpack_require__(2616).setGroupPositions);
function groupCrossTraceCalc(gd, plotinfo) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var fullLayout = gd._fullLayout;
var fullTraces = gd._fullData;
var calcTraces = gd.calcdata;
var calcTracesHorz = [];
var calcTracesVert = [];
for (var i = 0; i < fullTraces.length; i++) {
var fullTrace = fullTraces[i];
if (fullTrace.visible === true && fullTrace.type === 'scatter' && fullTrace.xaxis === xa._id && fullTrace.yaxis === ya._id) {
if (fullTrace.orientation === 'h') {
calcTracesHorz.push(calcTraces[i]);
} else if (fullTrace.orientation === 'v') {
// check for v since certain scatter traces may not have an orientation
calcTracesVert.push(calcTraces[i]);
}
}
}
var opts = {
mode: fullLayout.scattermode,
gap: fullLayout.scattergap
};
setGroupPositions(gd, xa, ya, calcTracesVert, opts);
setGroupPositions(gd, ya, xa, calcTracesHorz, opts);
}
/*
* Scatter stacking & normalization calculations
* runs per subplot, and can handle multiple stacking groups
*/
module.exports = function crossTraceCalc(gd, plotinfo) {
if (gd._fullLayout.scattermode === 'group') {
groupCrossTraceCalc(gd, plotinfo);
}
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var subplot = xa._id + ya._id;
var subplotStackOpts = gd._fullLayout._scatterStackOpts[subplot];
if (!subplotStackOpts) return;
var calcTraces = gd.calcdata;
var i, j, k, i2, cd, cd0, posj, sumj, norm;
var groupOpts, interpolate, groupnorm, posAttr, valAttr;
var hasAnyBlanks;
for (var stackGroup in subplotStackOpts) {
groupOpts = subplotStackOpts[stackGroup];
var indices = groupOpts.traceIndices;
// can get here with no indices if the stack axis is non-numeric
if (!indices.length) continue;
interpolate = groupOpts.stackgaps === 'interpolate';
groupnorm = groupOpts.groupnorm;
if (groupOpts.orientation === 'v') {
posAttr = 'x';
valAttr = 'y';
} else {
posAttr = 'y';
valAttr = 'x';
}
hasAnyBlanks = new Array(indices.length);
for (i = 0; i < hasAnyBlanks.length; i++) {
hasAnyBlanks[i] = false;
}
// Collect the complete set of all positions across ALL traces.
// Start with the first trace, then interleave items from later traces
// as needed.
// Fill in mising items as we go.
cd0 = calcTraces[indices[0]];
var allPositions = new Array(cd0.length);
for (i = 0; i < cd0.length; i++) {
allPositions[i] = cd0[i][posAttr];
}
for (i = 1; i < indices.length; i++) {
cd = calcTraces[indices[i]];
for (j = k = 0; j < cd.length; j++) {
posj = cd[j][posAttr];
for (; posj > allPositions[k] && k < allPositions.length; k++) {
// the current trace is missing a position from some previous trace(s)
insertBlank(cd, j, allPositions[k], i, hasAnyBlanks, interpolate, posAttr);
j++;
}
if (posj !== allPositions[k]) {
// previous trace(s) are missing a position from the current trace
for (i2 = 0; i2 < i; i2++) {
insertBlank(calcTraces[indices[i2]], k, posj, i2, hasAnyBlanks, interpolate, posAttr);
}
allPositions.splice(k, 0, posj);
}
k++;
}
for (; k < allPositions.length; k++) {
insertBlank(cd, j, allPositions[k], i, hasAnyBlanks, interpolate, posAttr);
j++;
}
}
var serieslen = allPositions.length;
// stack (and normalize)!
for (j = 0; j < cd0.length; j++) {
sumj = cd0[j][valAttr] = cd0[j].s;
for (i = 1; i < indices.length; i++) {
cd = calcTraces[indices[i]];
cd[0].trace._rawLength = cd[0].trace._length;
cd[0].trace._length = serieslen;
sumj += cd[j].s;
cd[j][valAttr] = sumj;
}
if (groupnorm) {
norm = (groupnorm === 'fraction' ? sumj : sumj / 100) || 1;
for (i = 0; i < indices.length; i++) {
var cdj = calcTraces[indices[i]][j];
cdj[valAttr] /= norm;
cdj.sNorm = cdj.s / norm;
}
}
}
// autorange
for (i = 0; i < indices.length; i++) {
cd = calcTraces[indices[i]];
var trace = cd[0].trace;
var ppad = calc.calcMarkerSize(trace, trace._rawLength);
var arrayPad = Array.isArray(ppad);
if (ppad && hasAnyBlanks[i] || arrayPad) {
var ppadRaw = ppad;
ppad = new Array(serieslen);
for (j = 0; j < serieslen; j++) {
ppad[j] = cd[j].gap ? 0 : arrayPad ? ppadRaw[cd[j].i] : ppadRaw;
}
}
var x = new Array(serieslen);
var y = new Array(serieslen);
for (j = 0; j < serieslen; j++) {
x[j] = cd[j].x;
y[j] = cd[j].y;
}
calc.calcAxisExpansion(gd, trace, xa, ya, x, y, ppad);
// while we're here (in a loop over all traces in the stack)
// record the orientation, so hover can find it easily
cd[0].t.orientation = groupOpts.orientation;
}
}
};
function insertBlank(calcTrace, index, position, traceIndex, hasAnyBlanks, interpolate, posAttr) {
hasAnyBlanks[traceIndex] = true;
var newEntry = {
i: null,
gap: true,
s: 0
};
newEntry[posAttr] = position;
calcTrace.splice(index, 0, newEntry);
// Even if we're not interpolating, if one trace has multiple
// values at the same position and this trace only has one value there,
// we just duplicate that one value rather than insert a zero.
// We also make it look like a real point - because it's ambiguous which
// one really is the real one!
if (index && position === calcTrace[index - 1][posAttr]) {
var prevEntry = calcTrace[index - 1];
newEntry.s = prevEntry.s;
// TODO is it going to cause any problems to have multiple
// calcdata points with the same index?
newEntry.i = prevEntry.i;
newEntry.gap = prevEntry.gap;
} else if (interpolate) {
newEntry.s = getInterp(calcTrace, index, position, posAttr);
}
if (!index) {
// t and trace need to stay on the first cd entry
calcTrace[0].t = calcTrace[1].t;
calcTrace[0].trace = calcTrace[1].trace;
delete calcTrace[1].t;
delete calcTrace[1].trace;
}
}
function getInterp(calcTrace, index, position, posAttr) {
var pt0 = calcTrace[index - 1];
var pt1 = calcTrace[index + 1];
if (!pt1) return pt0.s;
if (!pt0) return pt1.s;
return pt0.s + (pt1.s - pt0.s) * (position - pt0[posAttr]) / (pt1[posAttr] - pt0[posAttr]);
}
/***/ }),
/***/ 83472:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleGroupingDefaults = __webpack_require__(8584);
var attributes = __webpack_require__(49992);
// remove opacity for any trace that has a fill or is filled to
module.exports = function crossTraceDefaults(fullData, fullLayout) {
var traceIn, traceOut, i;
function coerce(attr) {
return Lib.coerce(traceOut._input, traceOut, attributes, attr);
}
if (fullLayout.scattermode === 'group') {
for (i = 0; i < fullData.length; i++) {
traceOut = fullData[i];
if (traceOut.type === 'scatter') {
traceIn = traceOut._input;
handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce);
}
}
}
for (i = 0; i < fullData.length; i++) {
var tracei = fullData[i];
if (tracei.type !== 'scatter') continue;
var filli = tracei.fill;
if (filli === 'none' || filli === 'toself') continue;
tracei.opacity = undefined;
if (filli === 'tonexty' || filli === 'tonextx') {
for (var j = i - 1; j >= 0; j--) {
var tracej = fullData[j];
if (tracej.type === 'scatter' && tracej.xaxis === tracei.xaxis && tracej.yaxis === tracei.yaxis) {
tracej.opacity = undefined;
break;
}
}
}
}
};
/***/ }),
/***/ 92404:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
var attributes = __webpack_require__(49992);
var constants = __webpack_require__(5892);
var subTypes = __webpack_require__(76640);
var handleXYDefaults = __webpack_require__(88376);
var handlePeriodDefaults = __webpack_require__(98632);
var handleStackDefaults = __webpack_require__(82064);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleLineShapeDefaults = __webpack_require__(95580);
var handleTextDefaults = __webpack_require__(52960);
var handleFillColorDefaults = __webpack_require__(73168);
var coercePattern = (__webpack_require__(10923).coercePattern);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleXYDefaults(traceIn, traceOut, layout, coerce);
if (!len) traceOut.visible = false;
if (!traceOut.visible) return;
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');
coerce('zorder');
var stackGroupOpts = handleStackDefaults(traceIn, traceOut, layout, coerce);
if (layout.scattermode === 'group' && traceOut.orientation === undefined) {
coerce('orientation', 'v');
}
var defaultMode = !stackGroupOpts && len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines';
coerce('text');
coerce('hovertext');
coerce('mode', defaultMode);
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
gradient: true
});
}
if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
backoff: true
});
handleLineShapeDefaults(traceIn, traceOut, coerce);
coerce('connectgaps');
coerce('line.simplify');
}
if (subTypes.hasText(traceOut)) {
coerce('texttemplate');
handleTextDefaults(traceIn, traceOut, layout, coerce);
}
var dfltHoverOn = [];
if (subTypes.hasMarkers(traceOut) || subTypes.hasText(traceOut)) {
coerce('cliponaxis');
coerce('marker.maxdisplayed');
dfltHoverOn.push('points');
}
// It's possible for this default to be changed by a later trace.
// We handle that case in some hacky code inside handleStackDefaults.
coerce('fill', stackGroupOpts ? stackGroupOpts.fillDflt : 'none');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce, {
moduleHasFillgradient: true
});
if (!subTypes.hasLines(traceOut)) handleLineShapeDefaults(traceIn, traceOut, coerce);
coercePattern(coerce, 'fillpattern', traceOut.fillcolor, false);
}
var lineColor = (traceOut.line || {}).color;
var markerColor = (traceOut.marker || {}).color;
if (traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
dfltHoverOn.push('fills');
}
coerce('hoveron', dfltHoverOn.join('+') || 'points');
if (traceOut.hoveron !== 'fills') coerce('hovertemplate');
var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults');
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || markerColor || defaultColor, {
axis: 'y'
});
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || markerColor || defaultColor, {
axis: 'x',
inherit: 'y'
});
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 94352:
/***/ (function(module) {
"use strict";
module.exports = function makeFillcolorAttr(hasFillgradient) {
return {
valType: 'color',
editType: 'style',
anim: true,
description: ['Sets the fill color.', 'Defaults to a half-transparent variant of the line color,', 'marker color, or marker line color, whichever is available.' + (hasFillgradient ? ' If fillgradient is specified, fillcolor is ignored except for setting the background color of the hover label, if any.' : '')].join(' ')
};
};
/***/ }),
/***/ 73168:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Color = __webpack_require__(9240);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
function averageColors(colorscale) {
var color = Color.interpolate(colorscale[0][1], colorscale[1][1], 0.5);
for (var i = 2; i < colorscale.length; i++) {
var averageColorI = Color.interpolate(colorscale[i - 1][1], colorscale[i][1], 0.5);
color = Color.interpolate(color, averageColorI, colorscale[i - 1][0] / colorscale[i][0]);
}
return color;
}
module.exports = function fillColorDefaults(traceIn, traceOut, defaultColor, coerce, opts) {
if (!opts) opts = {};
var inheritColorFromMarker = false;
if (traceOut.marker) {
// don't try to inherit a color array
var markerColor = traceOut.marker.color;
var markerLineColor = (traceOut.marker.line || {}).color;
if (markerColor && !isArrayOrTypedArray(markerColor)) {
inheritColorFromMarker = markerColor;
} else if (markerLineColor && !isArrayOrTypedArray(markerLineColor)) {
inheritColorFromMarker = markerLineColor;
}
}
var averageGradientColor;
if (opts.moduleHasFillgradient) {
var gradientOrientation = coerce('fillgradient.type');
if (gradientOrientation !== 'none') {
coerce('fillgradient.start');
coerce('fillgradient.stop');
var gradientColorscale = coerce('fillgradient.colorscale');
// if a fillgradient is specified, we use the average gradient color
// to specify fillcolor after all other more specific candidates
// are considered, but before the global default color.
// fillcolor affects the background color of the hoverlabel in this case.
if (gradientColorscale) {
averageGradientColor = averageColors(gradientColorscale);
}
}
}
coerce('fillcolor', Color.addOpacity((traceOut.line || {}).color || inheritColorFromMarker || averageGradientColor || defaultColor, 0.5));
};
/***/ }),
/***/ 23400:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
module.exports = function formatLabels(cdi, trace, fullLayout) {
var labels = {};
var mockGd = {
_fullLayout: fullLayout
};
var xa = Axes.getFromTrace(mockGd, trace, 'x');
var ya = Axes.getFromTrace(mockGd, trace, 'y');
var x = cdi.orig_x;
if (x === undefined) x = cdi.x;
var y = cdi.orig_y;
if (y === undefined) y = cdi.y;
labels.xLabel = Axes.tickText(xa, xa.c2l(x), true).text;
labels.yLabel = Axes.tickText(ya, ya.c2l(y), true).text;
return labels;
};
/***/ }),
/***/ 85600:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Color = __webpack_require__(9240);
var subtypes = __webpack_require__(76640);
module.exports = function getTraceColor(trace, di) {
var lc, tc;
// TODO: text modes
if (trace.mode === 'lines') {
lc = trace.line.color;
return lc && Color.opacity(lc) ? lc : trace.fillcolor;
} else if (trace.mode === 'none') {
return trace.fill ? trace.fillcolor : '';
} else {
var mc = di.mcc || (trace.marker || {}).color;
var mlc = di.mlcc || ((trace.marker || {}).line || {}).color;
tc = mc && Color.opacity(mc) ? mc : mlc && Color.opacity(mlc) && (di.mlw || ((trace.marker || {}).line || {}).width) ? mlc : '';
if (tc) {
// make sure the points aren't TOO transparent
if (Color.opacity(tc) < 0.3) {
return Color.addOpacity(tc, 0.3);
} else return tc;
} else {
lc = (trace.line || {}).color;
return lc && Color.opacity(lc) && subtypes.hasLines(trace) && trace.line.width ? lc : trace.fillcolor;
}
}
};
/***/ }),
/***/ 8584:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var getAxisGroup = (__webpack_require__(76908).getAxisGroup);
module.exports = function handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce) {
var orientation = traceOut.orientation;
// N.B. grouping is done across all trace types that support it
var posAxId = traceOut[{
v: 'x',
h: 'y'
}[orientation] + 'axis'];
var groupId = getAxisGroup(fullLayout, posAxId) + orientation;
var alignmentOpts = fullLayout._alignmentOpts || {};
var alignmentgroup = coerce('alignmentgroup');
var alignmentGroups = alignmentOpts[groupId];
if (!alignmentGroups) alignmentGroups = alignmentOpts[groupId] = {};
var alignmentGroupOpts = alignmentGroups[alignmentgroup];
if (alignmentGroupOpts) {
alignmentGroupOpts.traces.push(traceOut);
} else {
alignmentGroupOpts = alignmentGroups[alignmentgroup] = {
traces: [traceOut],
alignmentIndex: Object.keys(alignmentGroups).length,
offsetGroups: {}
};
}
var offsetgroup = coerce('offsetgroup');
var offsetGroups = alignmentGroupOpts.offsetGroups;
var offsetGroupOpts = offsetGroups[offsetgroup];
if (offsetgroup) {
if (!offsetGroupOpts) {
offsetGroupOpts = offsetGroups[offsetgroup] = {
offsetIndex: Object.keys(offsetGroups).length
};
}
traceOut._offsetIndex = offsetGroupOpts.offsetIndex;
}
};
/***/ }),
/***/ 98064:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Fx = __webpack_require__(39184);
var Registry = __webpack_require__(30364);
var getTraceColor = __webpack_require__(85600);
var Color = __webpack_require__(9240);
var fillText = Lib.fillText;
module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var trace = cd[0].trace;
var xa = pointData.xa;
var ya = pointData.ya;
var xpx = xa.c2p(xval);
var ypx = ya.c2p(yval);
var pt = [xpx, ypx];
var hoveron = trace.hoveron || '';
var minRad = trace.mode.indexOf('markers') !== -1 ? 3 : 0.5;
var xPeriod = !!trace.xperiodalignment;
var yPeriod = !!trace.yperiodalignment;
// look for points to hover on first, then take fills only if we
// didn't find a point
if (hoveron.indexOf('points') !== -1) {
// dx and dy are used in compare modes - here we want to always
// prioritize the closest data point, at least as long as markers are
// the same size or nonexistent, but still try to prioritize small markers too.
var dx = function (di) {
if (xPeriod) {
var x0 = xa.c2p(di.xStart);
var x1 = xa.c2p(di.xEnd);
return xpx >= Math.min(x0, x1) && xpx <= Math.max(x0, x1) ? 0 : Infinity;
}
var rad = Math.max(3, di.mrc || 0);
var kink = 1 - 1 / rad;
var dxRaw = Math.abs(xa.c2p(di.x) - xpx);
return dxRaw < rad ? kink * dxRaw / rad : dxRaw - rad + kink;
};
var dy = function (di) {
if (yPeriod) {
var y0 = ya.c2p(di.yStart);
var y1 = ya.c2p(di.yEnd);
return ypx >= Math.min(y0, y1) && ypx <= Math.max(y0, y1) ? 0 : Infinity;
}
var rad = Math.max(3, di.mrc || 0);
var kink = 1 - 1 / rad;
var dyRaw = Math.abs(ya.c2p(di.y) - ypx);
return dyRaw < rad ? kink * dyRaw / rad : dyRaw - rad + kink;
};
// scatter points: d.mrc is the calculated marker radius
// adjust the distance so if you're inside the marker it
// always will show up regardless of point size, but
// prioritize smaller points
var dxy = function (di) {
var rad = Math.max(minRad, di.mrc || 0);
var dx = xa.c2p(di.x) - xpx;
var dy = ya.c2p(di.y) - ypx;
return Math.max(Math.sqrt(dx * dx + dy * dy) - rad, 1 - minRad / rad);
};
var distfn = Fx.getDistanceFunction(hovermode, dx, dy, dxy);
Fx.getClosest(cd, distfn, pointData);
// skip the rest (for this trace) if we didn't find a close point
if (pointData.index !== false) {
// the closest data point
var di = cd[pointData.index];
var xc = xa.c2p(di.x, true);
var yc = ya.c2p(di.y, true);
var rad = di.mrc || 1;
// now we're done using the whole `calcdata` array, replace the
// index with the original index (in case of inserted point from
// stacked area)
pointData.index = di.i;
var orientation = cd[0].t.orientation;
// TODO: for scatter and bar, option to show (sub)totals and
// raw data? Currently stacked and/or normalized bars just show
// the normalized individual sizes, so that's what I'm doing here
// for now.
var sizeVal = orientation && (di.sNorm || di.s);
var xLabelVal = orientation === 'h' ? sizeVal : di.orig_x !== undefined ? di.orig_x : di.x;
var yLabelVal = orientation === 'v' ? sizeVal : di.orig_y !== undefined ? di.orig_y : di.y;
Lib.extendFlat(pointData, {
color: getTraceColor(trace, di),
x0: xc - rad,
x1: xc + rad,
xLabelVal: xLabelVal,
y0: yc - rad,
y1: yc + rad,
yLabelVal: yLabelVal,
spikeDistance: dxy(di),
hovertemplate: trace.hovertemplate
});
fillText(di, trace, pointData);
Registry.getComponentMethod('errorbars', 'hoverInfo')(di, trace, pointData);
return [pointData];
}
}
function isHoverPointInFillElement(el) {
// Uses SVGElement.isPointInFill to accurately determine wether
// the hover point / cursor is contained in the fill, taking
// curved or jagged edges into account, which the Polygon-based
// approach does not.
if (!el) {
return false;
}
var svgElement = el.node();
try {
var domPoint = new DOMPoint(pt[0], pt[1]);
return svgElement.isPointInFill(domPoint);
} catch (TypeError) {
var svgPoint = svgElement.ownerSVGElement.createSVGPoint();
svgPoint.x = pt[0];
svgPoint.y = pt[1];
return svgElement.isPointInFill(svgPoint);
}
}
function getHoverLabelPosition(polygons) {
// Uses Polygon s to determine the left- and right-most x-coordinates
// of the subshape of the fill that contains the hover point / cursor.
// Doing this with the SVGElement directly is quite tricky, so this falls
// back to the existing relatively simple code, accepting some small inaccuracies
// of label positioning for curved/jagged edges.
var i;
var polygonsIn = [];
var xmin = Infinity;
var xmax = -Infinity;
var ymin = Infinity;
var ymax = -Infinity;
var yPos;
for (i = 0; i < polygons.length; i++) {
var polygon = polygons[i];
// This is not going to work right for curved or jagged edges, it will
// act as though they're straight.
if (polygon.contains(pt)) {
polygonsIn.push(polygon);
ymin = Math.min(ymin, polygon.ymin);
ymax = Math.max(ymax, polygon.ymax);
}
}
// The above found no polygon that contains the cursor, but we know that
// the cursor must be inside the fill as determined by the SVGElement
// (so we are probably close to a curved/jagged edge...).
if (polygonsIn.length === 0) {
return null;
}
// constrain ymin/max to the visible plot, so the label goes
// at the middle of the piece you can see
ymin = Math.max(ymin, 0);
ymax = Math.min(ymax, ya._length);
yPos = (ymin + ymax) / 2;
// find the overall left-most and right-most points of the
// polygon(s) we're inside at their combined vertical midpoint.
// This is where we will draw the hover label.
// Note that this might not be the vertical midpoint of the
// whole trace, if it's disjoint.
var j, pts, xAtYPos, x0, x1, y0, y1;
for (i = 0; i < polygonsIn.length; i++) {
pts = polygonsIn[i].pts;
for (j = 1; j < pts.length; j++) {
y0 = pts[j - 1][1];
y1 = pts[j][1];
if (y0 > yPos !== y1 >= yPos) {
x0 = pts[j - 1][0];
x1 = pts[j][0];
if (y1 - y0) {
xAtYPos = x0 + (x1 - x0) * (yPos - y0) / (y1 - y0);
xmin = Math.min(xmin, xAtYPos);
xmax = Math.max(xmax, xAtYPos);
}
}
}
}
// constrain xmin/max to the visible plot now too
xmin = Math.max(xmin, 0);
xmax = Math.min(xmax, xa._length);
return {
x0: xmin,
x1: xmax,
y0: yPos,
y1: yPos
};
}
// even if hoveron is 'fills', only use it if we have a fill element too
if (hoveron.indexOf('fills') !== -1 && trace._fillElement) {
var inside = isHoverPointInFillElement(trace._fillElement) && !isHoverPointInFillElement(trace._fillExclusionElement);
if (inside) {
var hoverLabelCoords = getHoverLabelPosition(trace._polygons);
// getHoverLabelPosition may return null if the cursor / hover point is not contained
// in any of the trace's polygons, which can happen close to curved edges. in that
// case we fall back to displaying the hover label at the cursor position.
if (hoverLabelCoords === null) {
hoverLabelCoords = {
x0: pt[0],
x1: pt[0],
y0: pt[1],
y1: pt[1]
};
}
// get only fill or line color for the hover color
var color = Color.defaultLine;
if (Color.opacity(trace.fillcolor)) color = trace.fillcolor;else if (Color.opacity((trace.line || {}).color)) {
color = trace.line.color;
}
Lib.extendFlat(pointData, {
// never let a 2D override 1D type as closest point
// also: no spikeDistance, it's not allowed for fills
distance: pointData.maxHoverDistance,
x0: hoverLabelCoords.x0,
x1: hoverLabelCoords.x1,
y0: hoverLabelCoords.y0,
y1: hoverLabelCoords.y1,
color: color,
hovertemplate: false
});
delete pointData.index;
if (trace.text && !Lib.isArrayOrTypedArray(trace.text)) {
pointData.text = String(trace.text);
} else pointData.text = trace.name;
return [pointData];
}
}
};
/***/ }),
/***/ 15336:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var subtypes = __webpack_require__(76640);
module.exports = {
hasLines: subtypes.hasLines,
hasMarkers: subtypes.hasMarkers,
hasText: subtypes.hasText,
isBubble: subtypes.isBubble,
attributes: __webpack_require__(49992),
layoutAttributes: __webpack_require__(32284),
supplyDefaults: __webpack_require__(92404),
crossTraceDefaults: __webpack_require__(83472),
supplyLayoutDefaults: __webpack_require__(33960),
calc: (__webpack_require__(43792).calc),
crossTraceCalc: __webpack_require__(2104),
arraysToCalcdata: __webpack_require__(67368),
plot: __webpack_require__(93440),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(23400),
style: (__webpack_require__(53651).style),
styleOnSelect: (__webpack_require__(53651).styleOnSelect),
hoverPoints: __webpack_require__(98064),
selectPoints: __webpack_require__(37400),
animatable: true,
moduleType: 'trace',
name: 'scatter',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', 'symbols', 'errorBarsOK', 'showLegend', 'scatter-like', 'zoomScale'],
meta: {
description: ['The scatter trace type encompasses line charts, scatter charts, text charts, and bubble charts.', 'The data visualized as scatter point or lines is set in `x` and `y`.', 'Text (appearing either on the chart or on hover only) is via `text`.', 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`', 'to numerical arrays.'].join(' ')
}
};
/***/ }),
/***/ 32284:
/***/ (function(module) {
"use strict";
module.exports = {
scattermode: {
valType: 'enumerated',
values: ['group', 'overlay'],
dflt: 'overlay',
editType: 'calc',
description: ['Determines how scatter points at the same location coordinate', 'are displayed on the graph.', 'With *group*, the scatter points are plotted next to one another', 'centered around the shared location.', 'With *overlay*, the scatter points are plotted over one another,', 'you might need to reduce *opacity* to see multiple scatter points.'].join(' ')
},
scattergap: {
valType: 'number',
min: 0,
max: 1,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between scatter points of', 'adjacent location coordinates.', 'Defaults to `bargap`.'].join(' ')
}
};
/***/ }),
/***/ 33960:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(32284);
module.exports = function (layoutIn, layoutOut) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
var groupBarmode = layoutOut.barmode === 'group';
if (layoutOut.scattermode === 'group') {
coerce('scattergap', groupBarmode ? layoutOut.bargap : 0.2);
}
};
/***/ }),
/***/ 53360:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var colorscaleDefaults = __webpack_require__(47280);
module.exports = function lineDefaults(traceIn, traceOut, defaultColor, layout, coerce, opts) {
if (!opts) opts = {};
var markerColor = (traceIn.marker || {}).color;
if (markerColor && markerColor._inputArray) markerColor = markerColor._inputArray;
coerce('line.color', defaultColor);
if (hasColorscale(traceIn, 'line')) {
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'line.',
cLetter: 'c'
});
} else {
var lineColorDflt = (isArrayOrTypedArray(markerColor) ? false : markerColor) || defaultColor;
coerce('line.color', lineColorDflt);
}
coerce('line.width');
if (!opts.noDash) coerce('line.dash');
if (opts.backoff) coerce('line.backoff');
};
/***/ }),
/***/ 22216:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Drawing = __webpack_require__(49348);
var numConstants = __webpack_require__(41752);
var BADNUM = numConstants.BADNUM;
var LOG_CLIP = numConstants.LOG_CLIP;
var LOG_CLIP_PLUS = LOG_CLIP + 0.5;
var LOG_CLIP_MINUS = LOG_CLIP - 0.5;
var Lib = __webpack_require__(10923);
var segmentsIntersect = Lib.segmentsIntersect;
var constrain = Lib.constrain;
var constants = __webpack_require__(5892);
module.exports = function linePoints(d, opts) {
var trace = opts.trace || {};
var xa = opts.xaxis;
var ya = opts.yaxis;
var xLog = xa.type === 'log';
var yLog = ya.type === 'log';
var xLen = xa._length;
var yLen = ya._length;
var backoff = opts.backoff;
var marker = trace.marker;
var connectGaps = opts.connectGaps;
var baseTolerance = opts.baseTolerance;
var shape = opts.shape;
var linear = shape === 'linear';
var fill = trace.fill && trace.fill !== 'none';
var segments = [];
var minTolerance = constants.minTolerance;
var len = d.length;
var pts = new Array(len);
var pti = 0;
var i;
// pt variables are pixel coordinates [x,y] of one point
// these four are the outputs of clustering on a line
var clusterStartPt, clusterEndPt, clusterHighPt, clusterLowPt;
// "this" is the next point we're considering adding to the cluster
var thisPt;
// did we encounter the high point first, then a low point, or vice versa?
var clusterHighFirst;
// the first two points in the cluster determine its unit vector
// so the second is always in the "High" direction
var clusterUnitVector;
// the pixel delta from clusterStartPt
var thisVector;
// val variables are (signed) pixel distances along the cluster vector
var clusterRefDist, clusterHighVal, clusterLowVal, thisVal;
// deviation variables are (signed) pixel distances normal to the cluster vector
var clusterMinDeviation, clusterMaxDeviation, thisDeviation;
// turn one calcdata point into pixel coordinates
function getPt(index) {
var di = d[index];
if (!di) return false;
var x = opts.linearized ? xa.l2p(di.x) : xa.c2p(di.x);
var y = opts.linearized ? ya.l2p(di.y) : ya.c2p(di.y);
// if non-positive log values, set them VERY far off-screen
// so the line looks essentially straight from the previous point.
if (x === BADNUM) {
if (xLog) x = xa.c2p(di.x, true);
if (x === BADNUM) return false;
// If BOTH were bad log values, make the line follow a constant
// exponent rather than a constant slope
if (yLog && y === BADNUM) {
x *= Math.abs(xa._m * yLen * (xa._m > 0 ? LOG_CLIP_PLUS : LOG_CLIP_MINUS) / (ya._m * xLen * (ya._m > 0 ? LOG_CLIP_PLUS : LOG_CLIP_MINUS)));
}
x *= 1000;
}
if (y === BADNUM) {
if (yLog) y = ya.c2p(di.y, true);
if (y === BADNUM) return false;
y *= 1000;
}
return [x, y];
}
function crossesViewport(xFrac0, yFrac0, xFrac1, yFrac1) {
var dx = xFrac1 - xFrac0;
var dy = yFrac1 - yFrac0;
var dx0 = 0.5 - xFrac0;
var dy0 = 0.5 - yFrac0;
var norm2 = dx * dx + dy * dy;
var dot = dx * dx0 + dy * dy0;
if (dot > 0 && dot < norm2) {
var cross = dx0 * dy - dy0 * dx;
if (cross * cross < norm2) return true;
}
}
var latestXFrac, latestYFrac;
// if we're off-screen, increase tolerance over baseTolerance
function getTolerance(pt, nextPt) {
var xFrac = pt[0] / xLen;
var yFrac = pt[1] / yLen;
var offScreenFraction = Math.max(0, -xFrac, xFrac - 1, -yFrac, yFrac - 1);
if (offScreenFraction && latestXFrac !== undefined && crossesViewport(xFrac, yFrac, latestXFrac, latestYFrac)) {
offScreenFraction = 0;
}
if (offScreenFraction && nextPt && crossesViewport(xFrac, yFrac, nextPt[0] / xLen, nextPt[1] / yLen)) {
offScreenFraction = 0;
}
return (1 + constants.toleranceGrowth * offScreenFraction) * baseTolerance;
}
function ptDist(pt1, pt2) {
var dx = pt1[0] - pt2[0];
var dy = pt1[1] - pt2[1];
return Math.sqrt(dx * dx + dy * dy);
}
// last bit of filtering: clip paths that are VERY far off-screen
// so we don't get near the browser's hard limit (+/- 2^29 px in Chrome and FF)
var maxScreensAway = constants.maxScreensAway;
// find the intersections between the segment from pt1 to pt2
// and the large rectangle maxScreensAway around the viewport
// if one of pt1 and pt2 is inside and the other outside, there
// will be only one intersection.
// if both are outside there will be 0 or 2 intersections
// (or 1 if it's right at a corner - we'll treat that like 0)
// returns an array of intersection pts
var xEdge0 = -xLen * maxScreensAway;
var xEdge1 = xLen * (1 + maxScreensAway);
var yEdge0 = -yLen * maxScreensAway;
var yEdge1 = yLen * (1 + maxScreensAway);
var edges = [[xEdge0, yEdge0, xEdge1, yEdge0], [xEdge1, yEdge0, xEdge1, yEdge1], [xEdge1, yEdge1, xEdge0, yEdge1], [xEdge0, yEdge1, xEdge0, yEdge0]];
var xEdge, yEdge, lastXEdge, lastYEdge, lastFarPt, edgePt;
// for linear line shape, edge intersections should be linearly interpolated
// spline uses this too, which isn't precisely correct but is actually pretty
// good, because Catmull-Rom weights far-away points less in creating the curvature
function getLinearEdgeIntersections(pt1, pt2) {
var out = [];
var ptCount = 0;
for (var i = 0; i < 4; i++) {
var edge = edges[i];
var ptInt = segmentsIntersect(pt1[0], pt1[1], pt2[0], pt2[1], edge[0], edge[1], edge[2], edge[3]);
if (ptInt && (!ptCount || Math.abs(ptInt.x - out[0][0]) > 1 || Math.abs(ptInt.y - out[0][1]) > 1)) {
ptInt = [ptInt.x, ptInt.y];
// if we have 2 intersections, make sure the closest one to pt1 comes first
if (ptCount && ptDist(ptInt, pt1) < ptDist(out[0], pt1)) out.unshift(ptInt);else out.push(ptInt);
ptCount++;
}
}
return out;
}
function onlyConstrainedPoint(pt) {
if (pt[0] < xEdge0 || pt[0] > xEdge1 || pt[1] < yEdge0 || pt[1] > yEdge1) {
return [constrain(pt[0], xEdge0, xEdge1), constrain(pt[1], yEdge0, yEdge1)];
}
}
function sameEdge(pt1, pt2) {
if (pt1[0] === pt2[0] && (pt1[0] === xEdge0 || pt1[0] === xEdge1)) return true;
if (pt1[1] === pt2[1] && (pt1[1] === yEdge0 || pt1[1] === yEdge1)) return true;
}
// for line shapes hv and vh, movement in the two dimensions is decoupled,
// so all we need to do is constrain each dimension independently
function getHVEdgeIntersections(pt1, pt2) {
var out = [];
var ptInt1 = onlyConstrainedPoint(pt1);
var ptInt2 = onlyConstrainedPoint(pt2);
if (ptInt1 && ptInt2 && sameEdge(ptInt1, ptInt2)) return out;
if (ptInt1) out.push(ptInt1);
if (ptInt2) out.push(ptInt2);
return out;
}
// hvh and vhv we sometimes have to move one of the intersection points
// out BEYOND the clipping rect, by a maximum of a factor of 2, so that
// the midpoint line is drawn in the right place
function getABAEdgeIntersections(dim, limit0, limit1) {
return function (pt1, pt2) {
var ptInt1 = onlyConstrainedPoint(pt1);
var ptInt2 = onlyConstrainedPoint(pt2);
var out = [];
if (ptInt1 && ptInt2 && sameEdge(ptInt1, ptInt2)) return out;
if (ptInt1) out.push(ptInt1);
if (ptInt2) out.push(ptInt2);
var midShift = 2 * Lib.constrain((pt1[dim] + pt2[dim]) / 2, limit0, limit1) - ((ptInt1 || pt1)[dim] + (ptInt2 || pt2)[dim]);
if (midShift) {
var ptToAlter;
if (ptInt1 && ptInt2) {
ptToAlter = midShift > 0 === ptInt1[dim] > ptInt2[dim] ? ptInt1 : ptInt2;
} else ptToAlter = ptInt1 || ptInt2;
ptToAlter[dim] += midShift;
}
return out;
};
}
var getEdgeIntersections;
if (shape === 'linear' || shape === 'spline') {
getEdgeIntersections = getLinearEdgeIntersections;
} else if (shape === 'hv' || shape === 'vh') {
getEdgeIntersections = getHVEdgeIntersections;
} else if (shape === 'hvh') getEdgeIntersections = getABAEdgeIntersections(0, xEdge0, xEdge1);else if (shape === 'vhv') getEdgeIntersections = getABAEdgeIntersections(1, yEdge0, yEdge1);
// a segment pt1->pt2 entirely outside the nearby region:
// find the corner it gets closest to touching
function getClosestCorner(pt1, pt2) {
var dx = pt2[0] - pt1[0];
var m = (pt2[1] - pt1[1]) / dx;
var b = (pt1[1] * pt2[0] - pt2[1] * pt1[0]) / dx;
if (b > 0) return [m > 0 ? xEdge0 : xEdge1, yEdge1];else return [m > 0 ? xEdge1 : xEdge0, yEdge0];
}
function updateEdge(pt) {
var x = pt[0];
var y = pt[1];
var xSame = x === pts[pti - 1][0];
var ySame = y === pts[pti - 1][1];
// duplicate point?
if (xSame && ySame) return;
if (pti > 1) {
// backtracking along an edge?
var xSame2 = x === pts[pti - 2][0];
var ySame2 = y === pts[pti - 2][1];
if (xSame && (x === xEdge0 || x === xEdge1) && xSame2) {
if (ySame2) pti--; // backtracking exactly - drop prev pt and don't add
else pts[pti - 1] = pt; // not exact: replace the prev pt
} else if (ySame && (y === yEdge0 || y === yEdge1) && ySame2) {
if (xSame2) pti--;else pts[pti - 1] = pt;
} else pts[pti++] = pt;
} else pts[pti++] = pt;
}
function updateEdgesForReentry(pt) {
// if we're outside the nearby region and going back in,
// we may need to loop around a corner point
if (pts[pti - 1][0] !== pt[0] && pts[pti - 1][1] !== pt[1]) {
updateEdge([lastXEdge, lastYEdge]);
}
updateEdge(pt);
lastFarPt = null;
lastXEdge = lastYEdge = 0;
}
var arrayMarker = Lib.isArrayOrTypedArray(marker);
function addPt(pt) {
if (pt && backoff) {
pt.i = i;
pt.d = d;
pt.trace = trace;
pt.marker = arrayMarker ? marker[pt.i] : marker;
pt.backoff = backoff;
}
latestXFrac = pt[0] / xLen;
latestYFrac = pt[1] / yLen;
// Are we more than maxScreensAway off-screen any direction?
// if so, clip to this box, but in such a way that on-screen
// drawing is unchanged
xEdge = pt[0] < xEdge0 ? xEdge0 : pt[0] > xEdge1 ? xEdge1 : 0;
yEdge = pt[1] < yEdge0 ? yEdge0 : pt[1] > yEdge1 ? yEdge1 : 0;
if (xEdge || yEdge) {
if (!pti) {
// to get fills right - if first point is far, push it toward the
// screen in whichever direction(s) are far
pts[pti++] = [xEdge || pt[0], yEdge || pt[1]];
} else if (lastFarPt) {
// both this point and the last are outside the nearby region
// check if we're crossing the nearby region
var intersections = getEdgeIntersections(lastFarPt, pt);
if (intersections.length > 1) {
updateEdgesForReentry(intersections[0]);
pts[pti++] = intersections[1];
}
} else {
// we're leaving the nearby region - add the point where we left it
edgePt = getEdgeIntersections(pts[pti - 1], pt)[0];
pts[pti++] = edgePt;
}
var lastPt = pts[pti - 1];
if (xEdge && yEdge && (lastPt[0] !== xEdge || lastPt[1] !== yEdge)) {
// we've gone out beyond a new corner: add the corner too
// so that the next point will take the right winding
if (lastFarPt) {
if (lastXEdge !== xEdge && lastYEdge !== yEdge) {
if (lastXEdge && lastYEdge) {
// we've gone around to an opposite corner - we
// need to add the correct extra corner
// in order to get the right winding
updateEdge(getClosestCorner(lastFarPt, pt));
} else {
// we're coming from a far edge - the extra corner
// we need is determined uniquely by the sectors
updateEdge([lastXEdge || xEdge, lastYEdge || yEdge]);
}
} else if (lastXEdge && lastYEdge) {
updateEdge([lastXEdge, lastYEdge]);
}
}
updateEdge([xEdge, yEdge]);
} else if (lastXEdge - xEdge && lastYEdge - yEdge) {
// we're coming from an edge or far corner to an edge - again the
// extra corner we need is uniquely determined by the sectors
updateEdge([xEdge || lastXEdge, yEdge || lastYEdge]);
}
lastFarPt = pt;
lastXEdge = xEdge;
lastYEdge = yEdge;
} else {
if (lastFarPt) {
// this point is in range but the previous wasn't: add its entry pt first
updateEdgesForReentry(getEdgeIntersections(lastFarPt, pt)[0]);
}
pts[pti++] = pt;
}
}
// loop over ALL points in this trace
for (i = 0; i < len; i++) {
clusterStartPt = getPt(i);
if (!clusterStartPt) continue;
pti = 0;
lastFarPt = null;
addPt(clusterStartPt);
// loop over one segment of the trace
for (i++; i < len; i++) {
clusterHighPt = getPt(i);
if (!clusterHighPt) {
if (connectGaps) continue;else break;
}
// can't decimate if nonlinear line shape
// TODO: we *could* decimate [hv]{2,3} shapes if we restricted clusters to horz or vert again
// but spline would be verrry awkward to decimate
if (!linear || !opts.simplify) {
addPt(clusterHighPt);
continue;
}
var nextPt = getPt(i + 1);
clusterRefDist = ptDist(clusterHighPt, clusterStartPt);
// #3147 - always include the very first and last points for fills
if (!(fill && (pti === 0 || pti === len - 1)) && clusterRefDist < getTolerance(clusterHighPt, nextPt) * minTolerance) continue;
clusterUnitVector = [(clusterHighPt[0] - clusterStartPt[0]) / clusterRefDist, (clusterHighPt[1] - clusterStartPt[1]) / clusterRefDist];
clusterLowPt = clusterStartPt;
clusterHighVal = clusterRefDist;
clusterLowVal = clusterMinDeviation = clusterMaxDeviation = 0;
clusterHighFirst = false;
clusterEndPt = clusterHighPt;
// loop over one cluster of points that collapse onto one line
for (i++; i < d.length; i++) {
thisPt = nextPt;
nextPt = getPt(i + 1);
if (!thisPt) {
if (connectGaps) continue;else break;
}
thisVector = [thisPt[0] - clusterStartPt[0], thisPt[1] - clusterStartPt[1]];
// cross product (or dot with normal to the cluster vector)
thisDeviation = thisVector[0] * clusterUnitVector[1] - thisVector[1] * clusterUnitVector[0];
clusterMinDeviation = Math.min(clusterMinDeviation, thisDeviation);
clusterMaxDeviation = Math.max(clusterMaxDeviation, thisDeviation);
if (clusterMaxDeviation - clusterMinDeviation > getTolerance(thisPt, nextPt)) break;
clusterEndPt = thisPt;
thisVal = thisVector[0] * clusterUnitVector[0] + thisVector[1] * clusterUnitVector[1];
if (thisVal > clusterHighVal) {
clusterHighVal = thisVal;
clusterHighPt = thisPt;
clusterHighFirst = false;
} else if (thisVal < clusterLowVal) {
clusterLowVal = thisVal;
clusterLowPt = thisPt;
clusterHighFirst = true;
}
}
// insert this cluster into pts
// we've already inserted the start pt, now check if we have high and low pts
if (clusterHighFirst) {
addPt(clusterHighPt);
if (clusterEndPt !== clusterLowPt) addPt(clusterLowPt);
} else {
if (clusterLowPt !== clusterStartPt) addPt(clusterLowPt);
if (clusterEndPt !== clusterHighPt) addPt(clusterHighPt);
}
// and finally insert the end pt
addPt(clusterEndPt);
// have we reached the end of this segment?
if (i >= d.length || !thisPt) break;
// otherwise we have an out-of-cluster point to insert as next clusterStartPt
addPt(thisPt);
clusterStartPt = thisPt;
}
// to get fills right - repeat what we did at the start
if (lastFarPt) updateEdge([lastXEdge || lastFarPt[0], lastYEdge || lastFarPt[1]]);
segments.push(pts.slice(0, pti));
}
var lastShapeChar = shape.slice(shape.length - 1);
if (backoff && lastShapeChar !== 'h' && lastShapeChar !== 'v') {
var trimmed = false;
var n = -1;
var newSegments = [];
for (var j = 0; j < segments.length; j++) {
for (var k = 0; k < segments[j].length - 1; k++) {
var start = segments[j][k];
var end = segments[j][k + 1];
var xy = Drawing.applyBackoff(end, start);
if (xy[0] !== end[0] || xy[1] !== end[1]) {
trimmed = true;
}
if (!newSegments[n + 1]) {
n++;
newSegments[n] = [start, [xy[0], xy[1]]];
}
}
}
return trimmed ? newSegments : segments;
}
return segments;
};
/***/ }),
/***/ 95580:
/***/ (function(module) {
"use strict";
// common to 'scatter' and 'scatterternary'
module.exports = function handleLineShapeDefaults(traceIn, traceOut, coerce) {
var shape = coerce('line.shape');
if (shape === 'spline') coerce('line.smoothing');
};
/***/ }),
/***/ 84732:
/***/ (function(module) {
"use strict";
var LINKEDFILLS = {
tonextx: 1,
tonexty: 1,
tonext: 1
};
module.exports = function linkTraces(gd, plotinfo, cdscatter) {
var trace, i, group, prevtrace, groupIndex;
// first sort traces to keep stacks & filled-together groups together
var groupIndices = {};
var needsSort = false;
var prevGroupIndex = -1;
var nextGroupIndex = 0;
var prevUnstackedGroupIndex = -1;
for (i = 0; i < cdscatter.length; i++) {
trace = cdscatter[i][0].trace;
group = trace.stackgroup || '';
if (group) {
if (group in groupIndices) {
groupIndex = groupIndices[group];
} else {
groupIndex = groupIndices[group] = nextGroupIndex;
nextGroupIndex++;
}
} else if (trace.fill in LINKEDFILLS && prevUnstackedGroupIndex >= 0) {
groupIndex = prevUnstackedGroupIndex;
} else {
groupIndex = prevUnstackedGroupIndex = nextGroupIndex;
nextGroupIndex++;
}
if (groupIndex < prevGroupIndex) needsSort = true;
trace._groupIndex = prevGroupIndex = groupIndex;
}
var cdscatterSorted = cdscatter.slice();
if (needsSort) {
cdscatterSorted.sort(function (a, b) {
var traceA = a[0].trace;
var traceB = b[0].trace;
return traceA._groupIndex - traceB._groupIndex || traceA.index - traceB.index;
});
}
// now link traces to each other
var prevtraces = {};
for (i = 0; i < cdscatterSorted.length; i++) {
trace = cdscatterSorted[i][0].trace;
group = trace.stackgroup || '';
// Note: The check which ensures all cdscatter here are for the same axis and
// are either cartesian or scatterternary has been removed. This code assumes
// the passed scattertraces have been filtered to the proper plot types and
// the proper subplots.
if (trace.visible === true) {
trace._nexttrace = null;
if (trace.fill in LINKEDFILLS) {
prevtrace = prevtraces[group];
trace._prevtrace = prevtrace || null;
if (prevtrace) {
prevtrace._nexttrace = trace;
}
}
trace._ownfill = trace.fill && (trace.fill.substr(0, 6) === 'tozero' || trace.fill === 'toself' || trace.fill.substr(0, 2) === 'to' && !trace._prevtrace);
prevtraces[group] = trace;
} else {
trace._prevtrace = trace._nexttrace = trace._ownfill = null;
}
}
return cdscatterSorted;
};
/***/ }),
/***/ 84036:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
// used in the drawing step for 'scatter' and 'scattegeo' and
// in the convert step for 'scatter3d'
module.exports = function makeBubbleSizeFn(trace, factor) {
if (!factor) {
factor = 2;
}
var marker = trace.marker;
var sizeRef = marker.sizeref || 1;
var sizeMin = marker.sizemin || 0;
// for bubble charts, allow scaling the provided value linearly
// and by area or diameter.
// Note this only applies to the array-value sizes
var baseFn = marker.sizemode === 'area' ? function (v) {
return Math.sqrt(v / sizeRef);
} : function (v) {
return v / sizeRef;
};
// TODO add support for position/negative bubbles?
// TODO add 'sizeoffset' attribute?
return function (v) {
var baseSize = baseFn(v / factor);
// don't show non-numeric and negative sizes
return isNumeric(baseSize) && baseSize > 0 ? Math.max(baseSize, sizeMin) : 0;
};
};
/***/ }),
/***/ 71416:
/***/ (function(module) {
"use strict";
module.exports = {
container: 'marker',
min: 'cmin',
max: 'cmax'
};
/***/ }),
/***/ 1092:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Color = __webpack_require__(9240);
var hasColorscale = (__webpack_require__(44456).hasColorscale);
var colorscaleDefaults = __webpack_require__(47280);
var subTypes = __webpack_require__(76640);
/*
* opts: object of flags to control features not all marker users support
* noLine: caller does not support marker lines
* gradient: caller supports gradients
* noSelect: caller does not support selected/unselected attribute containers
*/
module.exports = function markerDefaults(traceIn, traceOut, defaultColor, layout, coerce, opts) {
var isBubble = subTypes.isBubble(traceIn);
var lineColor = (traceIn.line || {}).color;
var defaultMLC;
opts = opts || {};
// marker.color inherit from line.color (even if line.color is an array)
if (lineColor) defaultColor = lineColor;
coerce('marker.symbol');
coerce('marker.opacity', isBubble ? 0.7 : 1);
coerce('marker.size');
if (!opts.noAngle) {
coerce('marker.angle');
if (!opts.noAngleRef) {
coerce('marker.angleref');
}
if (!opts.noStandOff) {
coerce('marker.standoff');
}
}
coerce('marker.color', defaultColor);
if (hasColorscale(traceIn, 'marker')) {
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'marker.',
cLetter: 'c'
});
}
if (!opts.noSelect) {
coerce('selected.marker.color');
coerce('unselected.marker.color');
coerce('selected.marker.size');
coerce('unselected.marker.size');
}
if (!opts.noLine) {
// if there's a line with a different color than the marker, use
// that line color as the default marker line color
// (except when it's an array)
// mostly this is for transparent markers to behave nicely
if (lineColor && !Array.isArray(lineColor) && traceOut.marker.color !== lineColor) {
defaultMLC = lineColor;
} else if (isBubble) defaultMLC = Color.background;else defaultMLC = Color.defaultLine;
coerce('marker.line.color', defaultMLC);
if (hasColorscale(traceIn, 'marker.line')) {
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'marker.line.',
cLetter: 'c'
});
}
coerce('marker.line.width', isBubble ? 1 : 0);
}
if (isBubble) {
coerce('marker.sizeref');
coerce('marker.sizemin');
coerce('marker.sizemode');
}
if (opts.gradient) {
var gradientType = coerce('marker.gradient.type');
if (gradientType !== 'none') {
coerce('marker.gradient.color');
}
}
};
/***/ }),
/***/ 98632:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var dateTick0 = (__webpack_require__(10923).dateTick0);
var numConstants = __webpack_require__(41752);
var ONEWEEK = numConstants.ONEWEEK;
function getPeriod0Dflt(period, calendar) {
if (period % ONEWEEK === 0) {
return dateTick0(calendar, 1); // Sunday
}
return dateTick0(calendar, 0);
}
module.exports = function handlePeriodDefaults(traceIn, traceOut, layout, coerce, opts) {
if (!opts) {
opts = {
x: true,
y: true
};
}
if (opts.x) {
var xperiod = coerce('xperiod');
if (xperiod) {
coerce('xperiod0', getPeriod0Dflt(xperiod, traceOut.xcalendar));
coerce('xperiodalignment');
}
}
if (opts.y) {
var yperiod = coerce('yperiod');
if (yperiod) {
coerce('yperiod0', getPeriod0Dflt(yperiod, traceOut.ycalendar));
coerce('yperiodalignment');
}
}
};
/***/ }),
/***/ 93440:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var ensureSingle = Lib.ensureSingle;
var identity = Lib.identity;
var Drawing = __webpack_require__(49348);
var subTypes = __webpack_require__(76640);
var linePoints = __webpack_require__(22216);
var linkTraces = __webpack_require__(84732);
var polygonTester = (__webpack_require__(52592).tester);
module.exports = function plot(gd, plotinfo, cdscatter, scatterLayer, transitionOpts, makeOnCompleteCallback) {
var join, onComplete;
// If transition config is provided, then it is only a partial replot and traces not
// updated are removed.
var isFullReplot = !transitionOpts;
var hasTransition = !!transitionOpts && transitionOpts.duration > 0;
// Link traces so the z-order of fill layers is correct
var cdscatterSorted = linkTraces(gd, plotinfo, cdscatter);
join = scatterLayer.selectAll('g.trace').data(cdscatterSorted, function (d) {
return d[0].trace.uid;
});
// Append new traces:
join.enter().append('g').attr('class', function (d) {
return 'trace scatter trace' + d[0].trace.uid;
}).style('stroke-miterlimit', 2);
join.order();
createFills(gd, join, plotinfo);
if (hasTransition) {
if (makeOnCompleteCallback) {
// If it was passed a callback to register completion, make a callback. If
// this is created, then it must be executed on completion, otherwise the
// pos-transition redraw will not execute:
onComplete = makeOnCompleteCallback();
}
var transition = d3.transition().duration(transitionOpts.duration).ease(transitionOpts.easing).each('end', function () {
onComplete && onComplete();
}).each('interrupt', function () {
onComplete && onComplete();
});
transition.each(function () {
// Must run the selection again since otherwise enters/updates get grouped together
// and these get executed out of order. Except we need them in order!
scatterLayer.selectAll('g.trace').each(function (d, i) {
plotOne(gd, i, plotinfo, d, cdscatterSorted, this, transitionOpts);
});
});
} else {
join.each(function (d, i) {
plotOne(gd, i, plotinfo, d, cdscatterSorted, this, transitionOpts);
});
}
if (isFullReplot) {
join.exit().remove();
}
// remove paths that didn't get used
scatterLayer.selectAll('path:not([d])').remove();
};
function createFills(gd, traceJoin, plotinfo) {
traceJoin.each(function (d) {
var fills = ensureSingle(d3.select(this), 'g', 'fills');
Drawing.setClipUrl(fills, plotinfo.layerClipId, gd);
var trace = d[0].trace;
var fillData = [];
if (trace._ownfill) fillData.push('_ownFill');
if (trace._nexttrace) fillData.push('_nextFill');
var fillJoin = fills.selectAll('g').data(fillData, identity);
fillJoin.enter().append('g');
fillJoin.exit().each(function (d) {
trace[d] = null;
}).remove();
fillJoin.order().each(function (d) {
// make a path element inside the fill group, just so
// we can give it its own data later on and the group can
// keep its simple '_*Fill' data
trace[d] = ensureSingle(d3.select(this), 'path', 'js-fill');
});
});
}
function plotOne(gd, idx, plotinfo, cdscatter, cdscatterAll, element, transitionOpts) {
var isStatic = gd._context.staticPlot;
var i;
// Since this has been reorganized and we're executing this on individual traces,
// we need to pass it the full list of cdscatter as well as this trace's index (idx)
// since it does an internal n^2 loop over comparisons with other traces:
selectMarkers(gd, idx, plotinfo, cdscatter, cdscatterAll);
var hasTransition = !!transitionOpts && transitionOpts.duration > 0;
function transition(selection) {
return hasTransition ? selection.transition() : selection;
}
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var trace = cdscatter[0].trace;
var line = trace.line;
var tr = d3.select(element);
var errorBarGroup = ensureSingle(tr, 'g', 'errorbars');
var lines = ensureSingle(tr, 'g', 'lines');
var points = ensureSingle(tr, 'g', 'points');
var text = ensureSingle(tr, 'g', 'text');
// error bars are at the bottom
Registry.getComponentMethod('errorbars', 'plot')(gd, errorBarGroup, plotinfo, transitionOpts);
if (trace.visible !== true) return;
transition(tr).style('opacity', trace.opacity);
// BUILD LINES AND FILLS
var ownFillEl3, tonext;
var ownFillDir = trace.fill.charAt(trace.fill.length - 1);
if (ownFillDir !== 'x' && ownFillDir !== 'y') ownFillDir = '';
var fillAxisIndex, fillAxisZero;
if (ownFillDir === 'y') {
fillAxisIndex = 1;
fillAxisZero = ya.c2p(0, true);
} else if (ownFillDir === 'x') {
fillAxisIndex = 0;
fillAxisZero = xa.c2p(0, true);
}
// store node for tweaking by selectPoints
cdscatter[0][plotinfo.isRangePlot ? 'nodeRangePlot3' : 'node3'] = tr;
var prevRevpath = '';
var prevPolygons = [];
var prevtrace = trace._prevtrace;
var prevFillsegments = null;
var prevFillElement = null;
if (prevtrace) {
prevRevpath = prevtrace._prevRevpath || '';
tonext = prevtrace._nextFill;
prevPolygons = prevtrace._ownPolygons;
prevFillsegments = prevtrace._fillsegments;
prevFillElement = prevtrace._fillElement;
}
var thispath;
var thisrevpath;
// fullpath is all paths for this curve, joined together straight
// across gaps, for filling
var fullpath = '';
// revpath is fullpath reversed, for fill-to-next
var revpath = '';
// functions for converting a point array to a path
var pathfn, revpathbase, revpathfn;
// variables used before and after the data join
var pt0, lastSegment, pt1;
// thisPolygons always contains only the polygons of this trace only
// whereas trace._polygons may be extended to include those of the previous
// trace as well for exclusion during hover detection
var thisPolygons = [];
trace._polygons = [];
var fillsegments = [];
// initialize line join data / method
var segments = [];
var makeUpdate = Lib.noop;
ownFillEl3 = trace._ownFill;
if (subTypes.hasLines(trace) || trace.fill !== 'none') {
if (tonext) {
// This tells .style which trace to use for fill information:
tonext.datum(cdscatter);
}
if (['hv', 'vh', 'hvh', 'vhv'].indexOf(line.shape) !== -1) {
pathfn = Drawing.steps(line.shape);
revpathbase = Drawing.steps(line.shape.split('').reverse().join(''));
} else if (line.shape === 'spline') {
pathfn = revpathbase = function (pts) {
var pLast = pts[pts.length - 1];
if (pts.length > 1 && pts[0][0] === pLast[0] && pts[0][1] === pLast[1]) {
// identical start and end points: treat it as a
// closed curve so we don't get a kink
return Drawing.smoothclosed(pts.slice(1), line.smoothing);
} else {
return Drawing.smoothopen(pts, line.smoothing);
}
};
} else {
pathfn = revpathbase = function (pts) {
return 'M' + pts.join('L');
};
}
revpathfn = function (pts) {
// note: this is destructive (reverses pts in place) so can't use pts after this
return revpathbase(pts.reverse());
};
segments = linePoints(cdscatter, {
xaxis: xa,
yaxis: ya,
trace: trace,
connectGaps: trace.connectgaps,
baseTolerance: Math.max(line.width || 1, 3) / 4,
shape: line.shape,
backoff: line.backoff,
simplify: line.simplify,
fill: trace.fill
});
// since we already have the pixel segments here, use them to make
// polygons for hover on fill; we first merge segments where the fill
// is connected into "fillsegments"; the actual polygon construction
// is deferred to later to distinguish between self and tonext/tozero fills.
// TODO: can we skip this if hoveron!=fills? That would mean we
// need to redraw when you change hoveron...
fillsegments = new Array(segments.length);
var fillsegmentCount = 0;
for (i = 0; i < segments.length; i++) {
var curpoints;
var pts = segments[i];
if (!curpoints || !ownFillDir) {
curpoints = pts.slice();
fillsegments[fillsegmentCount] = curpoints;
fillsegmentCount++;
} else {
curpoints.push.apply(curpoints, pts);
}
}
trace._fillElement = null;
trace._fillExclusionElement = prevFillElement;
trace._fillsegments = fillsegments.slice(0, fillsegmentCount);
fillsegments = trace._fillsegments;
if (segments.length) {
pt0 = segments[0][0].slice();
lastSegment = segments[segments.length - 1];
pt1 = lastSegment[lastSegment.length - 1].slice();
}
makeUpdate = function (isEnter) {
return function (pts) {
thispath = pathfn(pts);
thisrevpath = revpathfn(pts); // side-effect: reverses input
// calculate SVG path over all segments for fills
if (!fullpath) {
fullpath = thispath;
revpath = thisrevpath;
} else if (ownFillDir) {
// for fills with fill direction: ignore gaps
fullpath += 'L' + thispath.substr(1);
revpath = thisrevpath + ('L' + revpath.substr(1));
} else {
fullpath += 'Z' + thispath;
revpath = thisrevpath + 'Z' + revpath;
}
// actual lines get drawn here, with gaps between segments if requested
if (subTypes.hasLines(trace)) {
var el = d3.select(this);
// This makes the coloring work correctly:
el.datum(cdscatter);
if (isEnter) {
transition(el.style('opacity', 0).attr('d', thispath).call(Drawing.lineGroupStyle)).style('opacity', 1);
} else {
var sel = transition(el);
sel.attr('d', thispath);
Drawing.singleLineStyle(cdscatter, sel);
}
}
};
};
}
var lineJoin = lines.selectAll('.js-line').data(segments);
transition(lineJoin.exit()).style('opacity', 0).remove();
lineJoin.each(makeUpdate(false));
lineJoin.enter().append('path').classed('js-line', true).style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke').call(Drawing.lineGroupStyle).each(makeUpdate(true));
Drawing.setClipUrl(lineJoin, plotinfo.layerClipId, gd);
function clearFill(selection) {
transition(selection).attr('d', 'M0,0Z');
}
// helper functions to create polygons for hoveron fill detection
var makeSelfPolygons = function () {
var polygons = new Array(fillsegments.length);
for (i = 0; i < fillsegments.length; i++) {
polygons[i] = polygonTester(fillsegments[i]);
}
return polygons;
};
var makePolygonsToPrevious = function (prevFillsegments) {
var polygons, i;
if (!prevFillsegments || prevFillsegments.length === 0) {
// if there are no fill segments of a previous trace, stretch the
// polygon to the relevant axis
polygons = new Array(fillsegments.length);
for (i = 0; i < fillsegments.length; i++) {
var pt0 = fillsegments[i][0].slice();
var pt1 = fillsegments[i][fillsegments[i].length - 1].slice();
pt0[fillAxisIndex] = pt1[fillAxisIndex] = fillAxisZero;
var zeropoints = [pt1, pt0];
var polypoints = zeropoints.concat(fillsegments[i]);
polygons[i] = polygonTester(polypoints);
}
} else {
// if there are more than one previous fill segment, the
// way that fills work is to "self" fill all but the last segments
// of the previous and then fill from the new trace to the last
// segment of the previous.
polygons = new Array(prevFillsegments.length - 1 + fillsegments.length);
for (i = 0; i < prevFillsegments.length - 1; i++) {
polygons[i] = polygonTester(prevFillsegments[i]);
}
var reversedPrevFillsegment = prevFillsegments[prevFillsegments.length - 1].slice();
reversedPrevFillsegment.reverse();
for (i = 0; i < fillsegments.length; i++) {
polygons[prevFillsegments.length - 1 + i] = polygonTester(fillsegments[i].concat(reversedPrevFillsegment));
}
}
return polygons;
};
// draw fills and create hover detection polygons
if (segments.length) {
if (ownFillEl3) {
ownFillEl3.datum(cdscatter);
if (pt0 && pt1) {
// TODO(2023-12-10): this is always true if segments is not empty (?)
if (ownFillDir) {
pt0[fillAxisIndex] = pt1[fillAxisIndex] = fillAxisZero;
// fill to zero: full trace path, plus extension of
// the endpoints to the appropriate axis
// For the sake of animations, wrap the points around so that
// the points on the axes are the first two points. Otherwise
// animations get a little crazy if the number of points changes.
transition(ownFillEl3).attr('d', 'M' + pt1 + 'L' + pt0 + 'L' + fullpath.substr(1)).call(Drawing.singleFillStyle, gd);
// create hover polygons that extend to the axis as well.
thisPolygons = makePolygonsToPrevious(null); // polygon to axis
} else {
// fill to self: just join the path to itself
transition(ownFillEl3).attr('d', fullpath + 'Z').call(Drawing.singleFillStyle, gd);
// and simply emit hover polygons for each segment
thisPolygons = makeSelfPolygons();
}
}
trace._polygons = thisPolygons;
trace._fillElement = ownFillEl3;
} else if (tonext) {
if (trace.fill.substr(0, 6) === 'tonext' && fullpath && prevRevpath) {
// fill to next: full trace path, plus the previous path reversed
if (trace.fill === 'tonext') {
// tonext: for use by concentric shapes, like manually constructed
// contours, we just add the two paths closed on themselves.
// This makes strange results if one path is *not* entirely
// inside the other, but then that is a strange usage.
transition(tonext).attr('d', fullpath + 'Z' + prevRevpath + 'Z').call(Drawing.singleFillStyle, gd);
// and simply emit hover polygons for each segment
thisPolygons = makeSelfPolygons();
// we add the polygons of the previous trace which causes hover
// detection to ignore points contained in them.
trace._polygons = thisPolygons.concat(prevPolygons); // this does not modify thisPolygons, on purpose
} else {
// tonextx/y: for now just connect endpoints with lines. This is
// the correct behavior if the endpoints are at the same value of
// y/x, but if they *aren't*, we should ideally do more complicated
// things depending on whether the new endpoint projects onto the
// existing curve or off the end of it
transition(tonext).attr('d', fullpath + 'L' + prevRevpath.substr(1) + 'Z').call(Drawing.singleFillStyle, gd);
// create hover polygons that extend to the previous trace.
thisPolygons = makePolygonsToPrevious(prevFillsegments);
// in this case our polygons do not cover that of previous traces,
// so must not include previous trace polygons for hover detection.
trace._polygons = thisPolygons;
}
trace._fillElement = tonext;
} else {
clearFill(tonext);
}
}
trace._prevRevpath = revpath;
} else {
if (ownFillEl3) clearFill(ownFillEl3);else if (tonext) clearFill(tonext);
trace._prevRevpath = null;
}
trace._ownPolygons = thisPolygons;
function visFilter(d) {
return d.filter(function (v) {
return !v.gap && v.vis;
});
}
function visFilterWithGaps(d) {
return d.filter(function (v) {
return v.vis;
});
}
function gapFilter(d) {
return d.filter(function (v) {
return !v.gap;
});
}
function keyFunc(d) {
return d.id;
}
// Returns a function if the trace is keyed, otherwise returns undefined
function getKeyFunc(trace) {
if (trace.ids) {
return keyFunc;
}
}
function hideFilter() {
return false;
}
function makePoints(points, text, cdscatter) {
var join, selection, hasNode;
var trace = cdscatter[0].trace;
var showMarkers = subTypes.hasMarkers(trace);
var showText = subTypes.hasText(trace);
var keyFunc = getKeyFunc(trace);
var markerFilter = hideFilter;
var textFilter = hideFilter;
if (showMarkers || showText) {
var showFilter = identity;
// if we're stacking, "infer zero" gap mode gets markers in the
// gap points - because we've inferred a zero there - but other
// modes (currently "interpolate", later "interrupt" hopefully)
// we don't draw generated markers
var stackGroup = trace.stackgroup;
var isInferZero = stackGroup && gd._fullLayout._scatterStackOpts[xa._id + ya._id][stackGroup].stackgaps === 'infer zero';
if (trace.marker.maxdisplayed || trace._needsCull) {
showFilter = isInferZero ? visFilterWithGaps : visFilter;
} else if (stackGroup && !isInferZero) {
showFilter = gapFilter;
}
if (showMarkers) markerFilter = showFilter;
if (showText) textFilter = showFilter;
}
// marker points
selection = points.selectAll('path.point');
join = selection.data(markerFilter, keyFunc);
var enter = join.enter().append('path').classed('point', true);
if (hasTransition) {
enter.call(Drawing.pointStyle, trace, gd).call(Drawing.translatePoints, xa, ya).style('opacity', 0).transition().style('opacity', 1);
}
join.order();
var styleFns;
if (showMarkers) {
styleFns = Drawing.makePointStyleFns(trace);
}
join.each(function (d) {
var el = d3.select(this);
var sel = transition(el);
hasNode = Drawing.translatePoint(d, sel, xa, ya);
if (hasNode) {
Drawing.singlePointStyle(d, sel, trace, styleFns, gd);
if (plotinfo.layerClipId) {
Drawing.hideOutsideRangePoint(d, sel, xa, ya, trace.xcalendar, trace.ycalendar);
}
if (trace.customdata) {
el.classed('plotly-customdata', d.data !== null && d.data !== undefined);
}
} else {
sel.remove();
}
});
if (hasTransition) {
join.exit().transition().style('opacity', 0).remove();
} else {
join.exit().remove();
}
// text points
selection = text.selectAll('g');
join = selection.data(textFilter, keyFunc);
// each text needs to go in its own 'g' in case
// it gets converted to mathjax
join.enter().append('g').classed('textpoint', true).append('text');
join.order();
join.each(function (d) {
var g = d3.select(this);
var sel = transition(g.select('text'));
hasNode = Drawing.translatePoint(d, sel, xa, ya);
if (hasNode) {
if (plotinfo.layerClipId) {
Drawing.hideOutsideRangePoint(d, g, xa, ya, trace.xcalendar, trace.ycalendar);
}
} else {
g.remove();
}
});
join.selectAll('text').call(Drawing.textPointStyle, trace, gd).each(function (d) {
// This just *has* to be totally custom because of SVG text positioning :(
// It's obviously copied from translatePoint; we just can't use that
var x = xa.c2p(d.x);
var y = ya.c2p(d.y);
d3.select(this).selectAll('tspan.line').each(function () {
transition(d3.select(this)).attr({
x: x,
y: y
});
});
});
join.exit().remove();
}
points.datum(cdscatter);
text.datum(cdscatter);
makePoints(points, text, cdscatter);
// lastly, clip points groups of `cliponaxis !== false` traces
// on `plotinfo._hasClipOnAxisFalse === true` subplots
var hasClipOnAxisFalse = trace.cliponaxis === false;
var clipUrl = hasClipOnAxisFalse ? null : plotinfo.layerClipId;
Drawing.setClipUrl(points, clipUrl, gd);
Drawing.setClipUrl(text, clipUrl, gd);
}
function selectMarkers(gd, idx, plotinfo, cdscatter, cdscatterAll) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var xr = d3.extent(Lib.simpleMap(xa.range, xa.r2c));
var yr = d3.extent(Lib.simpleMap(ya.range, ya.r2c));
var trace = cdscatter[0].trace;
if (!subTypes.hasMarkers(trace)) return;
// if marker.maxdisplayed is used, select a maximum of
// mnum markers to show, from the set that are in the viewport
var mnum = trace.marker.maxdisplayed;
// TODO: remove some as we get away from the viewport?
if (mnum === 0) return;
var cd = cdscatter.filter(function (v) {
return v.x >= xr[0] && v.x <= xr[1] && v.y >= yr[0] && v.y <= yr[1];
});
var inc = Math.ceil(cd.length / mnum);
var tnum = 0;
cdscatterAll.forEach(function (cdj, j) {
var tracei = cdj[0].trace;
if (subTypes.hasMarkers(tracei) && tracei.marker.maxdisplayed > 0 && j < idx) {
tnum++;
}
});
// if multiple traces use maxdisplayed, stagger which markers we
// display this formula offsets successive traces by 1/3 of the
// increment, adding an extra small amount after each triplet so
// it's not quite periodic
var i0 = Math.round(tnum * inc / 3 + Math.floor(tnum / 3) * inc / 7.1);
// for error bars: save in cd which markers to show
// so we don't have to repeat this
cdscatter.forEach(function (v) {
delete v.vis;
});
cd.forEach(function (v, i) {
if (Math.round((i + i0) % inc) === 0) v.vis = true;
});
}
/***/ }),
/***/ 37400:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var subtypes = __webpack_require__(76640);
module.exports = function selectPoints(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var selection = [];
var trace = cd[0].trace;
var i;
var di;
var x;
var y;
var hasOnlyLines = !subtypes.hasMarkers(trace) && !subtypes.hasText(trace);
if (hasOnlyLines) return [];
if (selectionTester === false) {
// clear selection
for (i = 0; i < cd.length; i++) {
cd[i].selected = 0;
}
} else {
for (i = 0; i < cd.length; i++) {
di = cd[i];
x = xa.c2p(di.x);
y = ya.c2p(di.y);
if (di.i !== null && selectionTester.contains([x, y], false, i, searchInfo)) {
selection.push({
pointNumber: di.i,
x: xa.c2d(di.x),
y: ya.c2d(di.y)
});
di.selected = 1;
} else {
di.selected = 0;
}
}
}
return selection;
};
/***/ }),
/***/ 82064:
/***/ (function(module) {
"use strict";
var perStackAttrs = ['orientation', 'groupnorm', 'stackgaps'];
module.exports = function handleStackDefaults(traceIn, traceOut, layout, coerce) {
var stackOpts = layout._scatterStackOpts;
var stackGroup = coerce('stackgroup');
if (stackGroup) {
// use independent stacking options per subplot
var subplot = traceOut.xaxis + traceOut.yaxis;
var subplotStackOpts = stackOpts[subplot];
if (!subplotStackOpts) subplotStackOpts = stackOpts[subplot] = {};
var groupOpts = subplotStackOpts[stackGroup];
var firstTrace = false;
if (groupOpts) {
groupOpts.traces.push(traceOut);
} else {
groupOpts = subplotStackOpts[stackGroup] = {
// keep track of trace indices for use during stacking calculations
// this will be filled in during `calc` and used during `crossTraceCalc`
// so it's OK if we don't recreate it during a non-calc edit
traceIndices: [],
// Hold on to the whole set of prior traces
// First one is most important, so we can clear defaults
// there if we find explicit values only in later traces.
// We're only going to *use* the values stored in groupOpts,
// but for the editor and validate we want things self-consistent
// The full set of traces is used only to fix `fill` default if
// we find `orientation: 'h'` beyond the first trace
traces: [traceOut]
};
firstTrace = true;
}
// TODO: how is this going to work with groupby transforms?
// in principle it should be OK I guess, as long as explicit group styles
// don't override explicit base-trace styles?
var dflts = {
orientation: traceOut.x && !traceOut.y ? 'h' : 'v'
};
for (var i = 0; i < perStackAttrs.length; i++) {
var attr = perStackAttrs[i];
var attrFound = attr + 'Found';
if (!groupOpts[attrFound]) {
var traceHasAttr = traceIn[attr] !== undefined;
var isOrientation = attr === 'orientation';
if (traceHasAttr || firstTrace) {
groupOpts[attr] = coerce(attr, dflts[attr]);
if (isOrientation) {
groupOpts.fillDflt = groupOpts[attr] === 'h' ? 'tonextx' : 'tonexty';
}
if (traceHasAttr) {
// Note: this will show a value here even if it's invalid
// in which case it will revert to default.
groupOpts[attrFound] = true;
// Note: only one trace in the stack will get a _fullData
// entry for a given stack-wide attribute. If no traces
// (or the first trace) specify that attribute, the
// first trace will get it. If the first trace does NOT
// specify it but some later trace does, then it gets
// removed from the first trace and only included in the
// one that specified it. This is mostly important for
// editors (that want to see the full values to know
// what settings are available) and Plotly.react diffing.
// Editors may want to use fullLayout._scatterStackOpts
// directly and make these settings available from all
// traces in the stack... then set the new value into
// the first trace, and clear all later traces.
if (!firstTrace) {
delete groupOpts.traces[0][attr];
// orientation can affect default fill of previous traces
if (isOrientation) {
for (var j = 0; j < groupOpts.traces.length - 1; j++) {
var trace2 = groupOpts.traces[j];
if (trace2._input.fill !== trace2.fill) {
trace2.fill = groupOpts.fillDflt;
}
}
}
}
}
}
}
}
return groupOpts;
}
};
/***/ }),
/***/ 53651:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Drawing = __webpack_require__(49348);
var Registry = __webpack_require__(30364);
function style(gd) {
var s = d3.select(gd).selectAll('g.trace.scatter');
s.style('opacity', function (d) {
return d[0].trace.opacity;
});
s.selectAll('g.points').each(function (d) {
var sel = d3.select(this);
var trace = d.trace || d[0].trace;
stylePoints(sel, trace, gd);
});
s.selectAll('g.text').each(function (d) {
var sel = d3.select(this);
var trace = d.trace || d[0].trace;
styleText(sel, trace, gd);
});
s.selectAll('g.trace path.js-line').call(Drawing.lineGroupStyle);
s.selectAll('g.trace path.js-fill').call(Drawing.fillGroupStyle, gd, false);
Registry.getComponentMethod('errorbars', 'style')(s);
}
function stylePoints(sel, trace, gd) {
Drawing.pointStyle(sel.selectAll('path.point'), trace, gd);
}
function styleText(sel, trace, gd) {
Drawing.textPointStyle(sel.selectAll('text'), trace, gd);
}
function styleOnSelect(gd, cd, sel) {
var trace = cd[0].trace;
if (trace.selectedpoints) {
Drawing.selectedPointStyle(sel.selectAll('path.point'), trace);
Drawing.selectedTextStyle(sel.selectAll('text'), trace);
} else {
stylePoints(sel, trace, gd);
styleText(sel, trace, gd);
}
}
module.exports = {
style: style,
stylePoints: stylePoints,
styleText: styleText,
styleOnSelect: styleOnSelect
};
/***/ }),
/***/ 76640:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var isTypedArraySpec = (__webpack_require__(2764).isTypedArraySpec);
module.exports = {
hasLines: function (trace) {
return trace.visible && trace.mode && trace.mode.indexOf('lines') !== -1;
},
hasMarkers: function (trace) {
return trace.visible && (trace.mode && trace.mode.indexOf('markers') !== -1 ||
// until splom implements 'mode'
trace.type === 'splom');
},
hasText: function (trace) {
return trace.visible && trace.mode && trace.mode.indexOf('text') !== -1;
},
isBubble: function (trace) {
var marker = trace.marker;
return Lib.isPlainObject(marker) && (Lib.isArrayOrTypedArray(marker.size) || isTypedArraySpec(marker.size));
}
};
/***/ }),
/***/ 52960:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
/*
* opts: object of flags to control features not all text users support
* noSelect: caller does not support selected/unselected attribute containers
*/
module.exports = function (traceIn, traceOut, layout, coerce, opts) {
opts = opts || {};
coerce('textposition');
Lib.coerceFont(coerce, 'textfont', opts.font || layout.font);
if (!opts.noSelect) {
coerce('selected.textfont.color');
coerce('unselected.textfont.color');
}
};
/***/ }),
/***/ 88376:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
module.exports = function handleXYDefaults(traceIn, traceOut, layout, coerce) {
var x = coerce('x');
var y = coerce('y');
var len;
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x', 'y'], layout);
if (x) {
var xlen = Lib.minRowLength(x);
if (y) {
len = Math.min(xlen, Lib.minRowLength(y));
} else {
len = xlen;
coerce('y0');
coerce('dy');
}
} else {
if (!y) return 0;
len = Lib.minRowLength(y);
coerce('x0');
coerce('dx');
}
traceOut._length = len;
return len;
};
/***/ }),
/***/ 81704:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterAttrs = __webpack_require__(49992);
var colorAttributes = __webpack_require__(99732);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var baseAttrs = __webpack_require__(6040);
var DASHES = __webpack_require__(71088);
var MARKER_SYMBOLS = __webpack_require__(81024);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
var sortObjectKeys = __webpack_require__(78184);
var scatterLineAttrs = scatterAttrs.line;
var scatterMarkerAttrs = scatterAttrs.marker;
var scatterMarkerLineAttrs = scatterMarkerAttrs.line;
var lineAttrs = extendFlat({
width: scatterLineAttrs.width,
dash: {
valType: 'enumerated',
values: sortObjectKeys(DASHES),
dflt: 'solid',
description: 'Sets the dash style of the lines.'
}
}, colorAttributes('line'));
function makeProjectionAttr(axLetter) {
return {
show: {
valType: 'boolean',
dflt: false,
description: ['Sets whether or not projections are shown along the', axLetter, 'axis.'].join(' ')
},
opacity: {
valType: 'number',
min: 0,
max: 1,
dflt: 1,
description: 'Sets the projection color.'
},
scale: {
valType: 'number',
min: 0,
max: 10,
dflt: 2 / 3,
description: ['Sets the scale factor determining the size of the', 'projection marker points.'].join(' ')
}
};
}
var attrs = module.exports = overrideAll({
x: scatterAttrs.x,
y: scatterAttrs.y,
z: {
valType: 'data_array',
description: 'Sets the z coordinates.'
},
text: extendFlat({}, scatterAttrs.text, {
description: ['Sets text elements associated with each (x,y,z) triplet.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (x,y,z) coordinates.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
}),
texttemplate: texttemplateAttrs({}, {}),
hovertext: extendFlat({}, scatterAttrs.hovertext, {
description: ['Sets text elements associated with each (x,y,z) triplet.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (x,y,z) coordinates.', 'To be seen, trace `hoverinfo` must contain a *text* flag.'].join(' ')
}),
hovertemplate: hovertemplateAttrs(),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z'),
mode: extendFlat({}, scatterAttrs.mode,
// shouldn't this be on-par with 2D?
{
dflt: 'lines+markers'
}),
surfaceaxis: {
valType: 'enumerated',
values: [-1, 0, 1, 2],
dflt: -1,
description: ['If *-1*, the scatter points are not fill with a surface', 'If *0*, *1*, *2*, the scatter points are filled with', 'a Delaunay surface about the x, y, z respectively.'].join(' ')
},
surfacecolor: {
valType: 'color',
description: 'Sets the surface fill color.'
},
projection: {
x: makeProjectionAttr('x'),
y: makeProjectionAttr('y'),
z: makeProjectionAttr('z')
},
connectgaps: scatterAttrs.connectgaps,
line: lineAttrs,
marker: extendFlat({
// Parity with scatter.js?
symbol: {
valType: 'enumerated',
values: sortObjectKeys(MARKER_SYMBOLS),
dflt: 'circle',
arrayOk: true,
description: 'Sets the marker symbol type.'
},
size: extendFlat({}, scatterMarkerAttrs.size, {
dflt: 8
}),
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
opacity: extendFlat({}, scatterMarkerAttrs.opacity, {
arrayOk: false,
description: ['Sets the marker opacity.', 'Note that the marker opacity for scatter3d traces', 'must be a scalar value for performance reasons.', 'To set a blending opacity value', '(i.e. which is not transparent), set *marker.color*', 'to an rgba color and use its alpha channel.'].join(' ')
}),
colorbar: scatterMarkerAttrs.colorbar,
line: extendFlat({
width: extendFlat({}, scatterMarkerLineAttrs.width, {
arrayOk: false
})
}, colorAttributes('marker.line'))
}, colorAttributes('marker')),
textposition: extendFlat({}, scatterAttrs.textposition, {
dflt: 'top center'
}),
textfont: {
color: scatterAttrs.textfont.color,
size: scatterAttrs.textfont.size,
family: extendFlat({}, scatterAttrs.textfont.family, {
arrayOk: false
})
},
opacity: baseAttrs.opacity,
hoverinfo: extendFlat({}, baseAttrs.hoverinfo)
}, 'calc', 'nested');
attrs.x.editType = attrs.y.editType = attrs.z.editType = 'calc+clearAxisTypes';
/***/ }),
/***/ 95904:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var arraysToCalcdata = __webpack_require__(67368);
var calcColorscale = __webpack_require__(67536);
/**
* This is a kludge to put the array attributes into
* calcdata the way Scatter.plot does, so that legends and
* popovers know what to do with them.
*/
module.exports = function calc(gd, trace) {
var cd = [{
x: false,
y: false,
trace: trace,
t: {}
}];
arraysToCalcdata(cd, trace);
calcColorscale(gd, trace);
return cd;
};
/***/ }),
/***/ 90292:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
function calculateAxisErrors(data, params, scaleFactor, axis) {
if (!params || !params.visible) return null;
var computeError = Registry.getComponentMethod('errorbars', 'makeComputeError')(params);
var result = new Array(data.length);
for (var i = 0; i < data.length; i++) {
var errors = computeError(+data[i], i);
if (axis.type === 'log') {
var point = axis.c2l(data[i]);
var min = data[i] - errors[0];
var max = data[i] + errors[1];
result[i] = [(axis.c2l(min, true) - point) * scaleFactor, (axis.c2l(max, true) - point) * scaleFactor];
// Keep track of the lower error bound which isn't negative!
if (min > 0) {
var lower = axis.c2l(min);
if (!axis._lowerLogErrorBound) axis._lowerLogErrorBound = lower;
axis._lowerErrorBound = Math.min(axis._lowerLogErrorBound, lower);
}
} else {
result[i] = [-errors[0] * scaleFactor, errors[1] * scaleFactor];
}
}
return result;
}
function dataLength(array) {
for (var i = 0; i < array.length; i++) {
if (array[i]) return array[i].length;
}
return 0;
}
function calculateErrors(data, scaleFactor, sceneLayout) {
var errors = [calculateAxisErrors(data.x, data.error_x, scaleFactor[0], sceneLayout.xaxis), calculateAxisErrors(data.y, data.error_y, scaleFactor[1], sceneLayout.yaxis), calculateAxisErrors(data.z, data.error_z, scaleFactor[2], sceneLayout.zaxis)];
var n = dataLength(errors);
if (n === 0) return null;
var errorBounds = new Array(n);
for (var i = 0; i < n; i++) {
var bound = [[0, 0, 0], [0, 0, 0]];
for (var j = 0; j < 3; j++) {
if (errors[j]) {
for (var k = 0; k < 2; k++) {
bound[k][j] = errors[j][i][k];
}
}
}
errorBounds[i] = bound;
}
return errorBounds;
}
module.exports = calculateErrors;
/***/ }),
/***/ 65636:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createLinePlot = (__webpack_require__(14656).gl_line3d);
var createScatterPlot = (__webpack_require__(14656).gl_scatter3d);
var createErrorBars = (__webpack_require__(14656).gl_error3d);
var createMesh = (__webpack_require__(14656).gl_mesh3d);
var triangulate = (__webpack_require__(14656).delaunay_triangulate);
var Lib = __webpack_require__(10923);
var str2RgbaArray = __webpack_require__(29864);
var formatColor = (__webpack_require__(13396).formatColor);
var makeBubbleSizeFn = __webpack_require__(84036);
var DASH_PATTERNS = __webpack_require__(71088);
var MARKER_SYMBOLS = __webpack_require__(81024);
var Axes = __webpack_require__(81536);
var appendArrayPointValue = (__webpack_require__(12228).appendArrayPointValue);
var calculateError = __webpack_require__(90292);
function LineWithMarkers(scene, uid) {
this.scene = scene;
this.uid = uid;
this.linePlot = null;
this.scatterPlot = null;
this.errorBars = null;
this.textMarkers = null;
this.delaunayMesh = null;
this.color = null;
this.mode = '';
this.dataPoints = [];
this.axesBounds = [[-Infinity, -Infinity, -Infinity], [Infinity, Infinity, Infinity]];
this.textLabels = null;
this.data = null;
}
var proto = LineWithMarkers.prototype;
proto.handlePick = function (selection) {
if (selection.object && (selection.object === this.linePlot || selection.object === this.delaunayMesh || selection.object === this.textMarkers || selection.object === this.scatterPlot)) {
var ind = selection.index = selection.data.index;
if (selection.object.highlight) {
selection.object.highlight(null);
}
if (this.scatterPlot) {
selection.object = this.scatterPlot;
this.scatterPlot.highlight(selection.data);
}
selection.textLabel = '';
if (this.textLabels) {
if (Lib.isArrayOrTypedArray(this.textLabels)) {
if (this.textLabels[ind] || this.textLabels[ind] === 0) {
selection.textLabel = this.textLabels[ind];
}
} else {
selection.textLabel = this.textLabels;
}
}
selection.traceCoordinate = [this.data.x[ind], this.data.y[ind], this.data.z[ind]];
return true;
}
};
function constructDelaunay(points, color, axis) {
var u = (axis + 1) % 3;
var v = (axis + 2) % 3;
var filteredPoints = [];
var filteredIds = [];
var i;
for (i = 0; i < points.length; ++i) {
var p = points[i];
if (isNaN(p[u]) || !isFinite(p[u]) || isNaN(p[v]) || !isFinite(p[v])) {
continue;
}
filteredPoints.push([p[u], p[v]]);
filteredIds.push(i);
}
var cells = triangulate(filteredPoints);
for (i = 0; i < cells.length; ++i) {
var c = cells[i];
for (var j = 0; j < c.length; ++j) {
c[j] = filteredIds[c[j]];
}
}
return {
positions: points,
cells: cells,
meshColor: color
};
}
function calculateErrorParams(errors) {
var capSize = [0.0, 0.0, 0.0];
var color = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
var lineWidth = [1.0, 1.0, 1.0];
for (var i = 0; i < 3; i++) {
var e = errors[i];
if (e && e.copy_zstyle !== false && errors[2].visible !== false) e = errors[2];
if (!e || !e.visible) continue;
capSize[i] = e.width / 2; // ballpark rescaling
color[i] = str2RgbaArray(e.color);
lineWidth[i] = e.thickness;
}
return {
capSize: capSize,
color: color,
lineWidth: lineWidth
};
}
function parseAlignmentX(a) {
if (a === null || a === undefined) return 0;
return a.indexOf('left') > -1 ? -1 : a.indexOf('right') > -1 ? 1 : 0;
}
function parseAlignmentY(a) {
if (a === null || a === undefined) return 0;
return a.indexOf('top') > -1 ? -1 : a.indexOf('bottom') > -1 ? 1 : 0;
}
function calculateTextOffset(tp) {
// Read out text properties
var defaultAlignmentX = 0;
var defaultAlignmentY = 0;
var textOffset = [defaultAlignmentX, defaultAlignmentY];
if (Array.isArray(tp)) {
for (var i = 0; i < tp.length; i++) {
textOffset[i] = [defaultAlignmentX, defaultAlignmentY];
if (tp[i]) {
textOffset[i][0] = parseAlignmentX(tp[i]);
textOffset[i][1] = parseAlignmentY(tp[i]);
}
}
} else {
textOffset[0] = parseAlignmentX(tp);
textOffset[1] = parseAlignmentY(tp);
}
return textOffset;
}
function calculateSize(sizeIn, sizeFn) {
// rough parity with Plotly 2D markers
return sizeFn(sizeIn * 4);
}
function calculateSymbol(symbolIn) {
return MARKER_SYMBOLS[symbolIn];
}
function formatParam(paramIn, len, calculate, dflt, extraFn) {
var paramOut = null;
if (Lib.isArrayOrTypedArray(paramIn)) {
paramOut = [];
for (var i = 0; i < len; i++) {
if (paramIn[i] === undefined) paramOut[i] = dflt;else paramOut[i] = calculate(paramIn[i], extraFn);
}
} else paramOut = calculate(paramIn, Lib.identity);
return paramOut;
}
function convertPlotlyOptions(scene, data) {
var points = [];
var sceneLayout = scene.fullSceneLayout;
var scaleFactor = scene.dataScale;
var xaxis = sceneLayout.xaxis;
var yaxis = sceneLayout.yaxis;
var zaxis = sceneLayout.zaxis;
var marker = data.marker;
var line = data.line;
var x = data.x || [];
var y = data.y || [];
var z = data.z || [];
var len = x.length;
var xcalendar = data.xcalendar;
var ycalendar = data.ycalendar;
var zcalendar = data.zcalendar;
var xc, yc, zc;
var params, i;
var text;
// Convert points
for (i = 0; i < len; i++) {
// sanitize numbers and apply transforms based on axes.type
xc = xaxis.d2l(x[i], 0, xcalendar) * scaleFactor[0];
yc = yaxis.d2l(y[i], 0, ycalendar) * scaleFactor[1];
zc = zaxis.d2l(z[i], 0, zcalendar) * scaleFactor[2];
points[i] = [xc, yc, zc];
}
// convert text
if (Array.isArray(data.text)) {
text = data.text;
} else if (Lib.isTypedArray(data.text)) {
text = Array.from(data.text);
} else if (data.text !== undefined) {
text = new Array(len);
for (i = 0; i < len; i++) text[i] = data.text;
}
function formatter(axName, val) {
var ax = sceneLayout[axName];
return Axes.tickText(ax, ax.d2l(val), true).text;
}
// check texttemplate
var texttemplate = data.texttemplate;
if (texttemplate) {
var fullLayout = scene.fullLayout;
var d3locale = fullLayout._d3locale;
var isArray = Array.isArray(texttemplate);
var N = isArray ? Math.min(texttemplate.length, len) : len;
var txt = isArray ? function (i) {
return texttemplate[i];
} : function () {
return texttemplate;
};
text = new Array(N);
for (i = 0; i < N; i++) {
var d = {
x: x[i],
y: y[i],
z: z[i]
};
var labels = {
xLabel: formatter('xaxis', x[i]),
yLabel: formatter('yaxis', y[i]),
zLabel: formatter('zaxis', z[i])
};
var pointValues = {};
appendArrayPointValue(pointValues, data, i);
var meta = data._meta || {};
text[i] = Lib.texttemplateString(txt(i), labels, d3locale, pointValues, d, meta);
}
}
// Build object parameters
params = {
position: points,
mode: data.mode,
text: text
};
if ('line' in data) {
params.lineColor = formatColor(line, 1, len);
params.lineWidth = line.width;
params.lineDashes = line.dash;
}
if ('marker' in data) {
var sizeFn = makeBubbleSizeFn(data);
params.scatterColor = formatColor(marker, 1, len);
params.scatterSize = formatParam(marker.size, len, calculateSize, 20, sizeFn);
params.scatterMarker = formatParam(marker.symbol, len, calculateSymbol, '●');
params.scatterLineWidth = marker.line.width; // arrayOk === false
params.scatterLineColor = formatColor(marker.line, 1, len);
params.scatterAngle = 0;
}
if ('textposition' in data) {
params.textOffset = calculateTextOffset(data.textposition);
params.textColor = formatColor(data.textfont, 1, len);
params.textSize = formatParam(data.textfont.size, len, Lib.identity, 12);
params.textFont = data.textfont.family; // arrayOk === false
params.textAngle = 0;
}
var dims = ['x', 'y', 'z'];
params.project = [false, false, false];
params.projectScale = [1, 1, 1];
params.projectOpacity = [1, 1, 1];
for (i = 0; i < 3; ++i) {
var projection = data.projection[dims[i]];
if (params.project[i] = projection.show) {
params.projectOpacity[i] = projection.opacity;
params.projectScale[i] = projection.scale;
}
}
params.errorBounds = calculateError(data, scaleFactor, sceneLayout);
var errorParams = calculateErrorParams([data.error_x, data.error_y, data.error_z]);
params.errorColor = errorParams.color;
params.errorLineWidth = errorParams.lineWidth;
params.errorCapSize = errorParams.capSize;
params.delaunayAxis = data.surfaceaxis;
params.delaunayColor = str2RgbaArray(data.surfacecolor);
return params;
}
function _arrayToColor(color) {
if (Lib.isArrayOrTypedArray(color)) {
var c = color[0];
if (Lib.isArrayOrTypedArray(c)) color = c;
return 'rgb(' + color.slice(0, 3).map(function (x) {
return Math.round(x * 255);
}) + ')';
}
return null;
}
function arrayToColor(colors) {
if (!Lib.isArrayOrTypedArray(colors)) {
return null;
}
if (colors.length === 4 && typeof colors[0] === 'number') {
return _arrayToColor(colors);
}
return colors.map(_arrayToColor);
}
proto.update = function (data) {
var gl = this.scene.glplot.gl;
var lineOptions;
var scatterOptions;
var errorOptions;
var textOptions;
var dashPattern = DASH_PATTERNS.solid;
// Save data
this.data = data;
// Run data conversion
var options = convertPlotlyOptions(this.scene, data);
if ('mode' in options) {
this.mode = options.mode;
}
if ('lineDashes' in options) {
if (options.lineDashes in DASH_PATTERNS) {
dashPattern = DASH_PATTERNS[options.lineDashes];
}
}
this.color = arrayToColor(options.scatterColor) || arrayToColor(options.lineColor);
// Save data points
this.dataPoints = options.position;
lineOptions = {
gl: this.scene.glplot.gl,
position: options.position,
color: options.lineColor,
lineWidth: options.lineWidth || 1,
dashes: dashPattern[0],
dashScale: dashPattern[1],
opacity: data.opacity,
connectGaps: data.connectgaps
};
if (this.mode.indexOf('lines') !== -1) {
if (this.linePlot) this.linePlot.update(lineOptions);else {
this.linePlot = createLinePlot(lineOptions);
this.linePlot._trace = this;
this.scene.glplot.add(this.linePlot);
}
} else if (this.linePlot) {
this.scene.glplot.remove(this.linePlot);
this.linePlot.dispose();
this.linePlot = null;
}
// N.B. marker.opacity must be a scalar for performance
var scatterOpacity = data.opacity;
if (data.marker && data.marker.opacity !== undefined) scatterOpacity *= data.marker.opacity;
scatterOptions = {
gl: this.scene.glplot.gl,
position: options.position,
color: options.scatterColor,
size: options.scatterSize,
glyph: options.scatterMarker,
opacity: scatterOpacity,
orthographic: true,
lineWidth: options.scatterLineWidth,
lineColor: options.scatterLineColor,
project: options.project,
projectScale: options.projectScale,
projectOpacity: options.projectOpacity
};
if (this.mode.indexOf('markers') !== -1) {
if (this.scatterPlot) this.scatterPlot.update(scatterOptions);else {
this.scatterPlot = createScatterPlot(scatterOptions);
this.scatterPlot._trace = this;
this.scatterPlot.highlightScale = 1;
this.scene.glplot.add(this.scatterPlot);
}
} else if (this.scatterPlot) {
this.scene.glplot.remove(this.scatterPlot);
this.scatterPlot.dispose();
this.scatterPlot = null;
}
textOptions = {
gl: this.scene.glplot.gl,
position: options.position,
glyph: options.text,
color: options.textColor,
size: options.textSize,
angle: options.textAngle,
alignment: options.textOffset,
font: options.textFont,
orthographic: true,
lineWidth: 0,
project: false,
opacity: data.opacity
};
this.textLabels = data.hovertext || data.text;
if (this.mode.indexOf('text') !== -1) {
if (this.textMarkers) this.textMarkers.update(textOptions);else {
this.textMarkers = createScatterPlot(textOptions);
this.textMarkers._trace = this;
this.textMarkers.highlightScale = 1;
this.scene.glplot.add(this.textMarkers);
}
} else if (this.textMarkers) {
this.scene.glplot.remove(this.textMarkers);
this.textMarkers.dispose();
this.textMarkers = null;
}
errorOptions = {
gl: this.scene.glplot.gl,
position: options.position,
color: options.errorColor,
error: options.errorBounds,
lineWidth: options.errorLineWidth,
capSize: options.errorCapSize,
opacity: data.opacity
};
if (this.errorBars) {
if (options.errorBounds) {
this.errorBars.update(errorOptions);
} else {
this.scene.glplot.remove(this.errorBars);
this.errorBars.dispose();
this.errorBars = null;
}
} else if (options.errorBounds) {
this.errorBars = createErrorBars(errorOptions);
this.errorBars._trace = this;
this.scene.glplot.add(this.errorBars);
}
if (options.delaunayAxis >= 0) {
var delaunayOptions = constructDelaunay(options.position, options.delaunayColor, options.delaunayAxis);
delaunayOptions.opacity = data.opacity;
if (this.delaunayMesh) {
this.delaunayMesh.update(delaunayOptions);
} else {
delaunayOptions.gl = gl;
this.delaunayMesh = createMesh(delaunayOptions);
this.delaunayMesh._trace = this;
this.scene.glplot.add(this.delaunayMesh);
}
} else if (this.delaunayMesh) {
this.scene.glplot.remove(this.delaunayMesh);
this.delaunayMesh.dispose();
this.delaunayMesh = null;
}
};
proto.dispose = function () {
if (this.linePlot) {
this.scene.glplot.remove(this.linePlot);
this.linePlot.dispose();
}
if (this.scatterPlot) {
this.scene.glplot.remove(this.scatterPlot);
this.scatterPlot.dispose();
}
if (this.errorBars) {
this.scene.glplot.remove(this.errorBars);
this.errorBars.dispose();
}
if (this.textMarkers) {
this.scene.glplot.remove(this.textMarkers);
this.textMarkers.dispose();
}
if (this.delaunayMesh) {
this.scene.glplot.remove(this.delaunayMesh);
this.delaunayMesh.dispose();
}
};
function createLineWithMarkers(scene, data) {
var plot = new LineWithMarkers(scene, data.uid);
plot.update(data);
return plot;
}
module.exports = createLineWithMarkers;
/***/ }),
/***/ 39044:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var subTypes = __webpack_require__(76640);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleTextDefaults = __webpack_require__(52960);
var attributes = __webpack_require__(81704);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleXYZDefaults(traceIn, traceOut, coerce, layout);
if (!len) {
traceOut.visible = false;
return;
}
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('xhoverformat');
coerce('yhoverformat');
coerce('zhoverformat');
coerce('mode');
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
noSelect: true,
noAngle: true
});
}
if (subTypes.hasLines(traceOut)) {
coerce('connectgaps');
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
}
if (subTypes.hasText(traceOut)) {
coerce('texttemplate');
handleTextDefaults(traceIn, traceOut, layout, coerce, {
noSelect: true
});
}
var lineColor = (traceOut.line || {}).color;
var markerColor = (traceOut.marker || {}).color;
if (coerce('surfaceaxis') >= 0) coerce('surfacecolor', lineColor || markerColor);
var dims = ['x', 'y', 'z'];
for (var i = 0; i < 3; ++i) {
var projection = 'projection.' + dims[i];
if (coerce(projection + '.show')) {
coerce(projection + '.opacity');
coerce(projection + '.scale');
}
}
var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults');
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || markerColor || defaultColor, {
axis: 'z'
});
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || markerColor || defaultColor, {
axis: 'y',
inherit: 'z'
});
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || markerColor || defaultColor, {
axis: 'x',
inherit: 'z'
});
};
function handleXYZDefaults(traceIn, traceOut, coerce, layout) {
var len = 0;
var x = coerce('x');
var y = coerce('y');
var z = coerce('z');
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x', 'y', 'z'], layout);
if (x && y && z) {
// TODO: what happens if one is missing?
len = Math.min(x.length, y.length, z.length);
traceOut._length = traceOut._xlength = traceOut._ylength = traceOut._zlength = len;
}
return len;
}
/***/ }),
/***/ 46588:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
plot: __webpack_require__(65636),
attributes: __webpack_require__(81704),
markerSymbols: __webpack_require__(81024),
supplyDefaults: __webpack_require__(39044),
colorbar: [{
container: 'marker',
min: 'cmin',
max: 'cmax'
}, {
container: 'line',
min: 'cmin',
max: 'cmax'
}],
calc: __webpack_require__(95904),
moduleType: 'trace',
name: 'scatter3d',
basePlotModule: __webpack_require__(26544),
categories: ['gl3d', 'symbols', 'showLegend', 'scatter-like'],
meta: {
hrName: 'scatter_3d',
description: ['The data visualized as scatter point or lines in 3D dimension', 'is set in `x`, `y`, `z`.', 'Text (appearing either on the chart or on hover only) is via `text`.', 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`', 'Projections are achieved via `projection`.', 'Surface fills are achieved via `surfaceaxis`.'].join(' ')
}
};
/***/ }),
/***/ 74712:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var makeFillcolorAttr = __webpack_require__(94352);
var scatterAttrs = __webpack_require__(49992);
var baseAttrs = __webpack_require__(6040);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var colorScaleAttrs = __webpack_require__(99732);
var extendFlat = (__webpack_require__(55016).extendFlat);
var scatterMarkerAttrs = scatterAttrs.marker;
var scatterLineAttrs = scatterAttrs.line;
var scatterMarkerLineAttrs = scatterMarkerAttrs.line;
module.exports = {
carpet: {
valType: 'string',
editType: 'calc',
description: ['An identifier for this carpet, so that `scattercarpet` and', '`contourcarpet` traces can specify a carpet plot on which', 'they lie'].join(' ')
},
a: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the a-axis coordinates.'
},
b: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the b-axis coordinates.'
},
mode: extendFlat({}, scatterAttrs.mode, {
dflt: 'markers'
}),
text: extendFlat({}, scatterAttrs.text, {
description: ['Sets text elements associated with each (a,b) point.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of strings, the items are mapped in order to the', 'the data points in (a,b).', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
}),
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['a', 'b', 'text']
}),
hovertext: extendFlat({}, scatterAttrs.hovertext, {
description: ['Sets hover text elements associated with each (a,b) point.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of strings, the items are mapped in order to the', 'the data points in (a,b).', 'To be seen, trace `hoverinfo` must contain a *text* flag.'].join(' ')
}),
line: {
color: scatterLineAttrs.color,
width: scatterLineAttrs.width,
dash: scatterLineAttrs.dash,
backoff: scatterLineAttrs.backoff,
shape: extendFlat({}, scatterLineAttrs.shape, {
values: ['linear', 'spline']
}),
smoothing: scatterLineAttrs.smoothing,
editType: 'calc'
},
connectgaps: scatterAttrs.connectgaps,
fill: extendFlat({}, scatterAttrs.fill, {
values: ['none', 'toself', 'tonext'],
dflt: 'none',
description: ['Sets the area to fill with a solid color.', 'Use with `fillcolor` if not *none*.', 'scatterternary has a subset of the options available to scatter.', '*toself* connects the endpoints of the trace (or each segment', 'of the trace if it has gaps) into a closed shape.', '*tonext* fills the space between two traces if one completely', 'encloses the other (eg consecutive contour lines), and behaves like', '*toself* if there is no trace before it. *tonext* should not be', 'used if one trace does not enclose the other.'].join(' ')
}),
fillcolor: makeFillcolorAttr(),
marker: extendFlat({
symbol: scatterMarkerAttrs.symbol,
opacity: scatterMarkerAttrs.opacity,
maxdisplayed: scatterMarkerAttrs.maxdisplayed,
angle: scatterMarkerAttrs.angle,
angleref: scatterMarkerAttrs.angleref,
standoff: scatterMarkerAttrs.standoff,
size: scatterMarkerAttrs.size,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
line: extendFlat({
width: scatterMarkerLineAttrs.width,
editType: 'calc'
}, colorScaleAttrs('marker.line')),
gradient: scatterMarkerAttrs.gradient,
editType: 'calc'
}, colorScaleAttrs('marker')),
textfont: scatterAttrs.textfont,
textposition: scatterAttrs.textposition,
selected: scatterAttrs.selected,
unselected: scatterAttrs.unselected,
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['a', 'b', 'text', 'name']
}),
hoveron: scatterAttrs.hoveron,
hovertemplate: hovertemplateAttrs(),
zorder: scatterAttrs.zorder
};
/***/ }),
/***/ 76360:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var calcColorscale = __webpack_require__(67536);
var arraysToCalcdata = __webpack_require__(67368);
var calcSelection = __webpack_require__(62496);
var calcMarkerSize = (__webpack_require__(43792).calcMarkerSize);
var lookupCarpet = __webpack_require__(62952);
module.exports = function calc(gd, trace) {
var carpet = trace._carpetTrace = lookupCarpet(gd, trace);
if (!carpet || !carpet.visible || carpet.visible === 'legendonly') return;
var i;
// Transfer this over from carpet before plotting since this is a necessary
// condition in order for cartesian to actually plot this trace:
trace.xaxis = carpet.xaxis;
trace.yaxis = carpet.yaxis;
// make the calcdata array
var serieslen = trace._length;
var cd = new Array(serieslen);
var a, b;
var needsCull = false;
for (i = 0; i < serieslen; i++) {
a = trace.a[i];
b = trace.b[i];
if (isNumeric(a) && isNumeric(b)) {
var xy = carpet.ab2xy(+a, +b, true);
var visible = carpet.isVisible(+a, +b);
if (!visible) needsCull = true;
cd[i] = {
x: xy[0],
y: xy[1],
a: a,
b: b,
vis: visible
};
} else cd[i] = {
x: false,
y: false
};
}
trace._needsCull = needsCull;
cd[0].carpet = carpet;
cd[0].trace = trace;
calcMarkerSize(trace, serieslen);
calcColorscale(gd, trace);
arraysToCalcdata(cd, trace);
calcSelection(cd, trace);
return cd;
};
/***/ }),
/***/ 7464:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var constants = __webpack_require__(5892);
var subTypes = __webpack_require__(76640);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleLineShapeDefaults = __webpack_require__(95580);
var handleTextDefaults = __webpack_require__(52960);
var handleFillColorDefaults = __webpack_require__(73168);
var attributes = __webpack_require__(74712);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
coerce('carpet');
// XXX: Don't hard code this
traceOut.xaxis = 'x';
traceOut.yaxis = 'y';
var a = coerce('a');
var b = coerce('b');
var len = Math.min(a.length, b.length);
if (!len) {
traceOut.visible = false;
return;
}
traceOut._length = len;
coerce('text');
coerce('texttemplate');
coerce('hovertext');
var defaultMode = len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines';
coerce('mode', defaultMode);
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
gradient: true
});
}
if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
backoff: true
});
handleLineShapeDefaults(traceIn, traceOut, coerce);
coerce('connectgaps');
}
if (subTypes.hasText(traceOut)) {
handleTextDefaults(traceIn, traceOut, layout, coerce);
}
var dfltHoverOn = [];
if (subTypes.hasMarkers(traceOut) || subTypes.hasText(traceOut)) {
coerce('marker.maxdisplayed');
dfltHoverOn.push('points');
}
coerce('fill');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
if (!subTypes.hasLines(traceOut)) handleLineShapeDefaults(traceIn, traceOut, coerce);
}
if (traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
dfltHoverOn.push('fills');
}
var hoverOn = coerce('hoveron', dfltHoverOn.join('+') || 'points');
if (hoverOn !== 'fills') coerce('hovertemplate');
coerce('zorder');
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 45852:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt, trace, cd, pointNumber) {
var cdi = cd[pointNumber];
out.a = cdi.a;
out.b = cdi.b;
out.y = cdi.y;
return out;
};
/***/ }),
/***/ 85112:
/***/ (function(module) {
"use strict";
module.exports = function formatLabels(cdi, trace) {
var labels = {};
var carpet = trace._carpet;
var ij = carpet.ab2ij([cdi.a, cdi.b]);
var i0 = Math.floor(ij[0]);
var ti = ij[0] - i0;
var j0 = Math.floor(ij[1]);
var tj = ij[1] - j0;
var xy = carpet.evalxy([], i0, j0, ti, tj);
labels.yLabel = xy[1].toFixed(3);
return labels;
};
/***/ }),
/***/ 63728:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterHover = __webpack_require__(98064);
var fillText = (__webpack_require__(10923).fillText);
module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
var scatterPointData = scatterHover(pointData, xval, yval, hovermode);
if (!scatterPointData || scatterPointData[0].index === false) return;
var newPointData = scatterPointData[0];
// if hovering on a fill, we don't show any point data so the label is
// unchanged from what scatter gives us - except that it needs to
// be constrained to the trianglular plot area, not just the rectangular
// area defined by the synthetic x and y axes
// TODO: in some cases the vertical middle of the shape is not within
// the triangular viewport at all, so the label can become disconnected
// from the shape entirely. But calculating what portion of the shape
// is actually visible, as constrained by the diagonal axis lines, is not
// so easy and anyway we lost the information we would have needed to do
// this inside scatterHover.
if (newPointData.index === undefined) {
var yFracUp = 1 - newPointData.y0 / pointData.ya._length;
var xLen = pointData.xa._length;
var xMin = xLen * yFracUp / 2;
var xMax = xLen - xMin;
newPointData.x0 = Math.max(Math.min(newPointData.x0, xMax), xMin);
newPointData.x1 = Math.max(Math.min(newPointData.x1, xMax), xMin);
return scatterPointData;
}
var cdi = newPointData.cd[newPointData.index];
newPointData.a = cdi.a;
newPointData.b = cdi.b;
newPointData.xLabelVal = undefined;
newPointData.yLabelVal = undefined;
// TODO: nice formatting, and label by axis title, for a, b, and c?
var trace = newPointData.trace;
var carpet = trace._carpet;
var labels = trace._module.formatLabels(cdi, trace);
newPointData.yLabel = labels.yLabel;
delete newPointData.text;
var text = [];
function textPart(ax, val) {
var prefix;
if (ax.labelprefix && ax.labelprefix.length > 0) {
prefix = ax.labelprefix.replace(/ = $/, '');
} else {
prefix = ax._hovertitle;
}
text.push(prefix + ': ' + val.toFixed(3) + ax.labelsuffix);
}
if (!trace.hovertemplate) {
var hoverinfo = cdi.hi || trace.hoverinfo;
var parts = hoverinfo.split('+');
if (parts.indexOf('all') !== -1) parts = ['a', 'b', 'text'];
if (parts.indexOf('a') !== -1) textPart(carpet.aaxis, cdi.a);
if (parts.indexOf('b') !== -1) textPart(carpet.baxis, cdi.b);
text.push('y: ' + newPointData.yLabel);
if (parts.indexOf('text') !== -1) {
fillText(cdi, trace, text);
}
newPointData.extraText = text.join('
');
}
return scatterPointData;
};
/***/ }),
/***/ 19776:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(74712),
supplyDefaults: __webpack_require__(7464),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(85112),
calc: __webpack_require__(76360),
plot: __webpack_require__(82472),
style: (__webpack_require__(53651).style),
styleOnSelect: (__webpack_require__(53651).styleOnSelect),
hoverPoints: __webpack_require__(63728),
selectPoints: __webpack_require__(37400),
eventData: __webpack_require__(45852),
moduleType: 'trace',
name: 'scattercarpet',
basePlotModule: __webpack_require__(34316),
categories: ['svg', 'carpet', 'symbols', 'showLegend', 'carpetDependent', 'zoomScale'],
meta: {
hrName: 'scatter_carpet',
description: ['Plots a scatter trace on either the first carpet axis or the', 'carpet axis with a matching `carpet` attribute.'].join(' ')
}
};
/***/ }),
/***/ 82472:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterPlot = __webpack_require__(93440);
var Axes = __webpack_require__(81536);
var Drawing = __webpack_require__(49348);
module.exports = function plot(gd, plotinfoproxy, data, layer) {
var i, trace, node;
var carpet = data[0][0].carpet;
var xaxis = Axes.getFromId(gd, carpet.xaxis || 'x');
var yaxis = Axes.getFromId(gd, carpet.yaxis || 'y');
// mimic cartesian plotinfo
var plotinfo = {
xaxis: xaxis,
yaxis: yaxis,
plot: plotinfoproxy.plot
};
for (i = 0; i < data.length; i++) {
trace = data[i][0].trace;
trace._xA = xaxis;
trace._yA = yaxis;
}
scatterPlot(gd, plotinfo, data, layer);
for (i = 0; i < data.length; i++) {
trace = data[i][0].trace;
// Note: .select is adequate but seems to mutate the node data,
// which is at least a bit surprising and causes problems elsewhere
node = layer.selectAll('g.trace' + trace.uid + ' .js-line');
// Note: it would be more efficient if this didn't need to be applied
// separately to all scattercarpet traces, but that would require
// lots of reorganization of scatter traces that is otherwise not
// necessary. That makes this a potential optimization.
Drawing.setClipUrl(node, data[i][0].carpet._clipPathId, gd);
}
};
/***/ }),
/***/ 88804:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var makeFillcolorAttr = __webpack_require__(94352);
var scatterAttrs = __webpack_require__(49992);
var baseAttrs = __webpack_require__(6040);
var colorAttributes = __webpack_require__(99732);
var dash = (__webpack_require__(9392)/* .dash */ .u);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
var scatterMarkerAttrs = scatterAttrs.marker;
var scatterLineAttrs = scatterAttrs.line;
var scatterMarkerLineAttrs = scatterMarkerAttrs.line;
module.exports = overrideAll({
lon: {
valType: 'data_array',
description: 'Sets the longitude coordinates (in degrees East).'
},
lat: {
valType: 'data_array',
description: 'Sets the latitude coordinates (in degrees North).'
},
locations: {
valType: 'data_array',
description: ['Sets the coordinates via location IDs or names.', 'Coordinates correspond to the centroid of each location given.', 'See `locationmode` for more info.'].join(' ')
},
locationmode: {
valType: 'enumerated',
values: ['ISO-3', 'USA-states', 'country names', 'geojson-id'],
dflt: 'ISO-3',
description: ['Determines the set of locations used to match entries in `locations`', 'to regions on the map.', 'Values *ISO-3*, *USA-states*, *country names* correspond to features on', 'the base map and value *geojson-id* corresponds to features from a custom', 'GeoJSON linked to the `geojson` attribute.'].join(' ')
},
geojson: {
valType: 'any',
editType: 'calc',
description: ['Sets optional GeoJSON data associated with this trace.', 'If not given, the features on the base map are used when `locations` is set.', 'It can be set as a valid GeoJSON object or as a URL string.', 'Note that we only accept GeoJSONs of type *FeatureCollection* or *Feature*', 'with geometries of type *Polygon* or *MultiPolygon*.'
// TODO add topojson support with additional 'topojsonobject' attr?
// https://github.com/topojson/topojson-specification/blob/master/README.md
].join(' ')
},
featureidkey: {
valType: 'string',
editType: 'calc',
dflt: 'id',
description: ['Sets the key in GeoJSON features which is used as id to match the items', 'included in the `locations` array.', 'Only has an effect when `geojson` is set.', 'Support nested property, for example *properties.name*.'].join(' ')
},
mode: extendFlat({}, scatterAttrs.mode, {
dflt: 'markers'
}),
text: extendFlat({}, scatterAttrs.text, {
description: ['Sets text elements associated with each (lon,lat) pair', 'or item in `locations`.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (lon,lat) or `locations` coordinates.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
}),
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['lat', 'lon', 'location', 'text']
}),
hovertext: extendFlat({}, scatterAttrs.hovertext, {
description: ['Sets hover text elements associated with each (lon,lat) pair', 'or item in `locations`.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (lon,lat) or `locations` coordinates.', 'To be seen, trace `hoverinfo` must contain a *text* flag.'].join(' ')
}),
textfont: scatterAttrs.textfont,
textposition: scatterAttrs.textposition,
line: {
color: scatterLineAttrs.color,
width: scatterLineAttrs.width,
dash: dash
},
connectgaps: scatterAttrs.connectgaps,
marker: extendFlat({
symbol: scatterMarkerAttrs.symbol,
opacity: scatterMarkerAttrs.opacity,
angle: scatterMarkerAttrs.angle,
angleref: extendFlat({}, scatterMarkerAttrs.angleref, {
values: ['previous', 'up', 'north'],
description: ['Sets the reference for marker angle.', 'With *previous*, angle 0 points along the line from the previous point to this one.', 'With *up*, angle 0 points toward the top of the screen.', 'With *north*, angle 0 points north based on the current map projection.'].join(' ')
}),
standoff: scatterMarkerAttrs.standoff,
size: scatterMarkerAttrs.size,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
colorbar: scatterMarkerAttrs.colorbar,
line: extendFlat({
width: scatterMarkerLineAttrs.width
}, colorAttributes('marker.line')),
gradient: scatterMarkerAttrs.gradient
}, colorAttributes('marker')),
fill: {
valType: 'enumerated',
values: ['none', 'toself'],
dflt: 'none',
description: ['Sets the area to fill with a solid color.', 'Use with `fillcolor` if not *none*.', '*toself* connects the endpoints of the trace (or each segment', 'of the trace if it has gaps) into a closed shape.'].join(' ')
},
fillcolor: makeFillcolorAttr(),
selected: scatterAttrs.selected,
unselected: scatterAttrs.unselected,
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['lon', 'lat', 'location', 'text', 'name']
}),
hovertemplate: hovertemplateAttrs()
}, 'calc', 'nested');
/***/ }),
/***/ 14248:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var BADNUM = (__webpack_require__(41752).BADNUM);
var calcMarkerColorscale = __webpack_require__(67536);
var arraysToCalcdata = __webpack_require__(67368);
var calcSelection = __webpack_require__(62496);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var _ = (__webpack_require__(10923)._);
function isNonBlankString(v) {
return v && typeof v === 'string';
}
module.exports = function calc(gd, trace) {
var hasLocationData = isArrayOrTypedArray(trace.locations);
var len = hasLocationData ? trace.locations.length : trace._length;
var calcTrace = new Array(len);
var isValidLoc;
if (trace.geojson) {
isValidLoc = function (v) {
return isNonBlankString(v) || isNumeric(v);
};
} else {
isValidLoc = isNonBlankString;
}
for (var i = 0; i < len; i++) {
var calcPt = calcTrace[i] = {};
if (hasLocationData) {
var loc = trace.locations[i];
calcPt.loc = isValidLoc(loc) ? loc : null;
} else {
var lon = trace.lon[i];
var lat = trace.lat[i];
if (isNumeric(lon) && isNumeric(lat)) calcPt.lonlat = [+lon, +lat];else calcPt.lonlat = [BADNUM, BADNUM];
}
}
arraysToCalcdata(calcTrace, trace);
calcMarkerColorscale(gd, trace);
calcSelection(calcTrace, trace);
if (len) {
calcTrace[0].t = {
labels: {
lat: _(gd, 'lat:') + ' ',
lon: _(gd, 'lon:') + ' '
}
};
}
return calcTrace;
};
/***/ }),
/***/ 70064:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var subTypes = __webpack_require__(76640);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleTextDefaults = __webpack_require__(52960);
var handleFillColorDefaults = __webpack_require__(73168);
var attributes = __webpack_require__(88804);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var locations = coerce('locations');
var len;
if (locations && locations.length) {
var geojson = coerce('geojson');
var locationmodeDflt;
if (typeof geojson === 'string' && geojson !== '' || Lib.isPlainObject(geojson)) {
locationmodeDflt = 'geojson-id';
}
var locationMode = coerce('locationmode', locationmodeDflt);
if (locationMode === 'geojson-id') {
coerce('featureidkey');
}
len = locations.length;
} else {
var lon = coerce('lon') || [];
var lat = coerce('lat') || [];
len = Math.min(lon.length, lat.length);
}
if (!len) {
traceOut.visible = false;
return;
}
traceOut._length = len;
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('mode');
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
gradient: true
});
}
if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
coerce('connectgaps');
}
if (subTypes.hasText(traceOut)) {
coerce('texttemplate');
handleTextDefaults(traceIn, traceOut, layout, coerce);
}
coerce('fill');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
}
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 95476:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt, trace, cd, pointNumber) {
out.lon = pt.lon;
out.lat = pt.lat;
out.location = pt.loc ? pt.loc : null;
// include feature properties from input geojson
var cdi = cd[pointNumber];
if (cdi.fIn && cdi.fIn.properties) {
out.properties = cdi.fIn.properties;
}
return out;
};
/***/ }),
/***/ 62264:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
module.exports = function formatLabels(cdi, trace, fullLayout) {
var labels = {};
var geo = fullLayout[trace.geo]._subplot;
var ax = geo.mockAxis;
var lonlat = cdi.lonlat;
labels.lonLabel = Axes.tickText(ax, ax.c2l(lonlat[0]), true).text;
labels.latLabel = Axes.tickText(ax, ax.c2l(lonlat[1]), true).text;
return labels;
};
/***/ }),
/***/ 96757:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Fx = __webpack_require__(39184);
var BADNUM = (__webpack_require__(41752).BADNUM);
var getTraceColor = __webpack_require__(85600);
var fillText = (__webpack_require__(10923).fillText);
var attributes = __webpack_require__(88804);
module.exports = function hoverPoints(pointData, xval, yval) {
var cd = pointData.cd;
var trace = cd[0].trace;
var xa = pointData.xa;
var ya = pointData.ya;
var geo = pointData.subplot;
var isLonLatOverEdges = geo.projection.isLonLatOverEdges;
var project = geo.project;
function distFn(d) {
var lonlat = d.lonlat;
if (lonlat[0] === BADNUM) return Infinity;
if (isLonLatOverEdges(lonlat)) return Infinity;
var pt = project(lonlat);
var px = project([xval, yval]);
var dx = Math.abs(pt[0] - px[0]);
var dy = Math.abs(pt[1] - px[1]);
var rad = Math.max(3, d.mrc || 0);
// N.B. d.mrc is the calculated marker radius
// which is only set for trace with 'markers' mode.
return Math.max(Math.sqrt(dx * dx + dy * dy) - rad, 1 - 3 / rad);
}
Fx.getClosest(cd, distFn, pointData);
// skip the rest (for this trace) if we didn't find a close point
if (pointData.index === false) return;
var di = cd[pointData.index];
var lonlat = di.lonlat;
var pos = [xa.c2p(lonlat), ya.c2p(lonlat)];
var rad = di.mrc || 1;
pointData.x0 = pos[0] - rad;
pointData.x1 = pos[0] + rad;
pointData.y0 = pos[1] - rad;
pointData.y1 = pos[1] + rad;
pointData.loc = di.loc;
pointData.lon = lonlat[0];
pointData.lat = lonlat[1];
var fullLayout = {};
fullLayout[trace.geo] = {
_subplot: geo
};
var labels = trace._module.formatLabels(di, trace, fullLayout);
pointData.lonLabel = labels.lonLabel;
pointData.latLabel = labels.latLabel;
pointData.color = getTraceColor(trace, di);
pointData.extraText = getExtraText(trace, di, pointData, cd[0].t.labels);
pointData.hovertemplate = trace.hovertemplate;
return [pointData];
};
function getExtraText(trace, pt, pointData, labels) {
if (trace.hovertemplate) return;
var hoverinfo = pt.hi || trace.hoverinfo;
var parts = hoverinfo === 'all' ? attributes.hoverinfo.flags : hoverinfo.split('+');
var hasLocation = parts.indexOf('location') !== -1 && Array.isArray(trace.locations);
var hasLon = parts.indexOf('lon') !== -1;
var hasLat = parts.indexOf('lat') !== -1;
var hasText = parts.indexOf('text') !== -1;
var text = [];
function format(val) {
return val + '\u00B0';
}
if (hasLocation) {
text.push(pt.loc);
} else if (hasLon && hasLat) {
text.push('(' + format(pointData.latLabel) + ', ' + format(pointData.lonLabel) + ')');
} else if (hasLon) {
text.push(labels.lon + format(pointData.lonLabel));
} else if (hasLat) {
text.push(labels.lat + format(pointData.latLabel));
}
if (hasText) {
fillText(pt, trace, text);
}
return text.join('
');
}
/***/ }),
/***/ 9528:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(88804),
supplyDefaults: __webpack_require__(70064),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(62264),
calc: __webpack_require__(14248),
calcGeoJSON: (__webpack_require__(12484).calcGeoJSON),
plot: (__webpack_require__(12484).plot),
style: __webpack_require__(53388),
styleOnSelect: (__webpack_require__(53651).styleOnSelect),
hoverPoints: __webpack_require__(96757),
eventData: __webpack_require__(95476),
selectPoints: __webpack_require__(45640),
moduleType: 'trace',
name: 'scattergeo',
basePlotModule: __webpack_require__(28224),
categories: ['geo', 'symbols', 'showLegend', 'scatter-like'],
meta: {
hrName: 'scatter_geo',
description: ['The data visualized as scatter point or lines on a geographic map', 'is provided either by longitude/latitude pairs in `lon` and `lat`', 'respectively or by geographic location IDs or names in `locations`.'].join(' ')
}
};
/***/ }),
/***/ 12484:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var getTopojsonFeatures = (__webpack_require__(27052).getTopojsonFeatures);
var geoJsonUtils = __webpack_require__(23308);
var geoUtils = __webpack_require__(89096);
var findExtremes = (__webpack_require__(66044).findExtremes);
var BADNUM = (__webpack_require__(41752).BADNUM);
var calcMarkerSize = (__webpack_require__(43792).calcMarkerSize);
var subTypes = __webpack_require__(76640);
var style = __webpack_require__(53388);
function plot(gd, geo, calcData) {
var scatterLayer = geo.layers.frontplot.select('.scatterlayer');
var gTraces = Lib.makeTraceGroups(scatterLayer, calcData, 'trace scattergeo');
function removeBADNUM(d, node) {
if (d.lonlat[0] === BADNUM) {
d3.select(node).remove();
}
}
// TODO find a way to order the inner nodes on update
gTraces.selectAll('*').remove();
gTraces.each(function (calcTrace) {
var s = d3.select(this);
var trace = calcTrace[0].trace;
if (subTypes.hasLines(trace) || trace.fill !== 'none') {
var lineCoords = geoJsonUtils.calcTraceToLineCoords(calcTrace);
var lineData = trace.fill !== 'none' ? geoJsonUtils.makePolygon(lineCoords) : geoJsonUtils.makeLine(lineCoords);
s.selectAll('path.js-line').data([{
geojson: lineData,
trace: trace
}]).enter().append('path').classed('js-line', true).style('stroke-miterlimit', 2);
}
if (subTypes.hasMarkers(trace)) {
s.selectAll('path.point').data(Lib.identity).enter().append('path').classed('point', true).each(function (calcPt) {
removeBADNUM(calcPt, this);
});
}
if (subTypes.hasText(trace)) {
s.selectAll('g').data(Lib.identity).enter().append('g').append('text').each(function (calcPt) {
removeBADNUM(calcPt, this);
});
}
// call style here within topojson request callback
style(gd, calcTrace);
});
}
function calcGeoJSON(calcTrace, fullLayout) {
var trace = calcTrace[0].trace;
var geoLayout = fullLayout[trace.geo];
var geo = geoLayout._subplot;
var len = trace._length;
var i, calcPt;
if (Lib.isArrayOrTypedArray(trace.locations)) {
var locationmode = trace.locationmode;
var features = locationmode === 'geojson-id' ? geoUtils.extractTraceFeature(calcTrace) : getTopojsonFeatures(trace, geo.topojson);
for (i = 0; i < len; i++) {
calcPt = calcTrace[i];
var feature = locationmode === 'geojson-id' ? calcPt.fOut : geoUtils.locationToFeature(locationmode, calcPt.loc, features);
calcPt.lonlat = feature ? feature.properties.ct : [BADNUM, BADNUM];
}
}
var opts = {
padded: true
};
var lonArray;
var latArray;
if (geoLayout.fitbounds === 'geojson' && trace.locationmode === 'geojson-id') {
var bboxGeojson = geoUtils.computeBbox(geoUtils.getTraceGeojson(trace));
lonArray = [bboxGeojson[0], bboxGeojson[2]];
latArray = [bboxGeojson[1], bboxGeojson[3]];
} else {
lonArray = new Array(len);
latArray = new Array(len);
for (i = 0; i < len; i++) {
calcPt = calcTrace[i];
lonArray[i] = calcPt.lonlat[0];
latArray[i] = calcPt.lonlat[1];
}
opts.ppad = calcMarkerSize(trace, len);
}
trace._extremes.lon = findExtremes(geoLayout.lonaxis._ax, lonArray, opts);
trace._extremes.lat = findExtremes(geoLayout.lataxis._ax, latArray, opts);
}
module.exports = {
calcGeoJSON: calcGeoJSON,
plot: plot
};
/***/ }),
/***/ 45640:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var subtypes = __webpack_require__(76640);
var BADNUM = (__webpack_require__(41752).BADNUM);
module.exports = function selectPoints(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var selection = [];
var trace = cd[0].trace;
var di, lonlat, x, y, i;
var hasOnlyLines = !subtypes.hasMarkers(trace) && !subtypes.hasText(trace);
if (hasOnlyLines) return [];
if (selectionTester === false) {
for (i = 0; i < cd.length; i++) {
cd[i].selected = 0;
}
} else {
for (i = 0; i < cd.length; i++) {
di = cd[i];
lonlat = di.lonlat;
// some projection types can't handle BADNUMs
if (lonlat[0] === BADNUM) continue;
x = xa.c2p(lonlat);
y = ya.c2p(lonlat);
if (selectionTester.contains([x, y], null, i, searchInfo)) {
selection.push({
pointNumber: i,
lon: lonlat[0],
lat: lonlat[1]
});
di.selected = 1;
} else {
di.selected = 0;
}
}
}
return selection;
};
/***/ }),
/***/ 53388:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Drawing = __webpack_require__(49348);
var Color = __webpack_require__(9240);
var scatterStyle = __webpack_require__(53651);
var stylePoints = scatterStyle.stylePoints;
var styleText = scatterStyle.styleText;
module.exports = function style(gd, calcTrace) {
if (calcTrace) styleTrace(gd, calcTrace);
};
function styleTrace(gd, calcTrace) {
var trace = calcTrace[0].trace;
var s = calcTrace[0].node3;
s.style('opacity', calcTrace[0].trace.opacity);
stylePoints(s, trace, gd);
styleText(s, trace, gd);
// this part is incompatible with Drawing.lineGroupStyle
s.selectAll('path.js-line').style('fill', 'none').each(function (d) {
var path = d3.select(this);
var trace = d.trace;
var line = trace.line || {};
path.call(Color.stroke, line.color).call(Drawing.dashLine, line.dash || '', line.width || 0);
if (trace.fill !== 'none') {
path.call(Color.fill, trace.fillcolor);
}
});
}
/***/ }),
/***/ 9824:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var baseAttrs = __webpack_require__(6040);
var makeFillcolorAttr = __webpack_require__(94352);
var scatterAttrs = __webpack_require__(49992);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var colorScaleAttrs = __webpack_require__(99732);
var sortObjectKeys = __webpack_require__(78184);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
var DASHES = (__webpack_require__(57932).DASHES);
var scatterLineAttrs = scatterAttrs.line;
var scatterMarkerAttrs = scatterAttrs.marker;
var scatterMarkerLineAttrs = scatterMarkerAttrs.line;
var attrs = module.exports = overrideAll({
x: scatterAttrs.x,
x0: scatterAttrs.x0,
dx: scatterAttrs.dx,
y: scatterAttrs.y,
y0: scatterAttrs.y0,
dy: scatterAttrs.dy,
xperiod: scatterAttrs.xperiod,
yperiod: scatterAttrs.yperiod,
xperiod0: scatterAttrs.xperiod0,
yperiod0: scatterAttrs.yperiod0,
xperiodalignment: scatterAttrs.xperiodalignment,
yperiodalignment: scatterAttrs.yperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
text: scatterAttrs.text,
hovertext: scatterAttrs.hovertext,
textposition: scatterAttrs.textposition,
textfont: scatterAttrs.textfont,
mode: {
valType: 'flaglist',
flags: ['lines', 'markers', 'text'],
extras: ['none'],
description: ['Determines the drawing mode for this scatter trace.'].join(' ')
},
line: {
color: scatterLineAttrs.color,
width: scatterLineAttrs.width,
shape: {
valType: 'enumerated',
values: ['linear', 'hv', 'vh', 'hvh', 'vhv'],
dflt: 'linear',
editType: 'plot',
description: ['Determines the line shape.', 'The values correspond to step-wise line shapes.'].join(' ')
},
dash: {
valType: 'enumerated',
values: sortObjectKeys(DASHES),
dflt: 'solid',
description: 'Sets the style of the lines.'
}
},
marker: extendFlat({}, colorScaleAttrs('marker'), {
symbol: scatterMarkerAttrs.symbol,
angle: scatterMarkerAttrs.angle,
size: scatterMarkerAttrs.size,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
opacity: scatterMarkerAttrs.opacity,
colorbar: scatterMarkerAttrs.colorbar,
line: extendFlat({}, colorScaleAttrs('marker.line'), {
width: scatterMarkerLineAttrs.width
})
}),
connectgaps: scatterAttrs.connectgaps,
fill: extendFlat({}, scatterAttrs.fill, {
dflt: 'none'
}),
fillcolor: makeFillcolorAttr(),
// no hoveron
selected: {
marker: scatterAttrs.selected.marker,
textfont: scatterAttrs.selected.textfont
},
unselected: {
marker: scatterAttrs.unselected.marker,
textfont: scatterAttrs.unselected.textfont
},
opacity: baseAttrs.opacity
}, 'calc', 'nested');
attrs.x.editType = attrs.y.editType = attrs.x0.editType = attrs.y0.editType = 'calc+clearAxisTypes';
attrs.hovertemplate = scatterAttrs.hovertemplate;
attrs.texttemplate = scatterAttrs.texttemplate;
/***/ }),
/***/ 52824:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hover = __webpack_require__(62236);
module.exports = {
moduleType: 'trace',
name: 'scattergl',
basePlotModule: __webpack_require__(34316),
categories: ['gl', 'regl', 'cartesian', 'symbols', 'errorBarsOK', 'showLegend', 'scatter-like'],
attributes: __webpack_require__(9824),
supplyDefaults: __webpack_require__(46316),
crossTraceDefaults: __webpack_require__(83472),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(23372),
calc: __webpack_require__(64504),
hoverPoints: hover.hoverPoints,
selectPoints: __webpack_require__(32432),
meta: {
hrName: 'scatter_gl',
description: ['The data visualized as scatter point or lines is set in `x` and `y`', 'using the WebGL plotting engine.', 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`', 'to a numerical arrays.'].join(' ')
}
};
/***/ }),
/***/ 64504:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var cluster = __webpack_require__(16516);
var Lib = __webpack_require__(10923);
var AxisIDs = __webpack_require__(21504);
var findExtremes = (__webpack_require__(66044).findExtremes);
var alignPeriod = __webpack_require__(82260);
var scatterCalc = __webpack_require__(43792);
var calcMarkerSize = scatterCalc.calcMarkerSize;
var calcAxisExpansion = scatterCalc.calcAxisExpansion;
var setFirstScatter = scatterCalc.setFirstScatter;
var calcColorscale = __webpack_require__(67536);
var convert = __webpack_require__(69447);
var sceneUpdate = __webpack_require__(83632);
var BADNUM = (__webpack_require__(41752).BADNUM);
var TOO_MANY_POINTS = (__webpack_require__(57932).TOO_MANY_POINTS);
module.exports = function calc(gd, trace) {
var fullLayout = gd._fullLayout;
var xa = trace._xA = AxisIDs.getFromId(gd, trace.xaxis, 'x');
var ya = trace._yA = AxisIDs.getFromId(gd, trace.yaxis, 'y');
var subplot = fullLayout._plots[trace.xaxis + trace.yaxis];
var len = trace._length;
var hasTooManyPoints = len >= TOO_MANY_POINTS;
var len2 = len * 2;
var stash = {};
var i;
var origX = xa.makeCalcdata(trace, 'x');
var origY = ya.makeCalcdata(trace, 'y');
var xObj = alignPeriod(trace, xa, 'x', origX);
var yObj = alignPeriod(trace, ya, 'y', origY);
var x = xObj.vals;
var y = yObj.vals;
trace._x = x;
trace._y = y;
if (trace.xperiodalignment) {
trace._origX = origX;
trace._xStarts = xObj.starts;
trace._xEnds = xObj.ends;
}
if (trace.yperiodalignment) {
trace._origY = origY;
trace._yStarts = yObj.starts;
trace._yEnds = yObj.ends;
}
// we need hi-precision for scatter2d,
// regl-scatter2d uses NaNs for bad/missing values
var positions = new Array(len2);
var _ids = new Array(len);
for (i = 0; i < len; i++) {
positions[i * 2] = x[i] === BADNUM ? NaN : x[i];
positions[i * 2 + 1] = y[i] === BADNUM ? NaN : y[i];
// Pre-compute ids.
_ids[i] = i;
}
if (xa.type === 'log') {
for (i = 0; i < len2; i += 2) {
positions[i] = xa.c2l(positions[i]);
}
}
if (ya.type === 'log') {
for (i = 1; i < len2; i += 2) {
positions[i] = ya.c2l(positions[i]);
}
}
// we don't build a tree for log axes since it takes long to convert log2px
// and it is also
if (hasTooManyPoints && xa.type !== 'log' && ya.type !== 'log') {
// FIXME: delegate this to webworker
stash.tree = cluster(positions);
} else {
stash.ids = _ids;
}
// create scene options and scene
calcColorscale(gd, trace);
var opts = sceneOptions(gd, subplot, trace, positions, x, y);
var scene = sceneUpdate(gd, subplot);
// Reuse SVG scatter axis expansion routine.
// For graphs with very large number of points and array marker.size,
// use average marker size instead to speed things up.
setFirstScatter(fullLayout, trace);
var ppad;
if (!hasTooManyPoints) {
ppad = calcMarkerSize(trace, len);
} else if (opts.marker) {
ppad = opts.marker.sizeAvg || Math.max(opts.marker.size, 3);
}
calcAxisExpansion(gd, trace, xa, ya, x, y, ppad);
if (opts.errorX) expandForErrorBars(trace, xa, opts.errorX);
if (opts.errorY) expandForErrorBars(trace, ya, opts.errorY);
// set flags to create scene renderers
if (opts.fill && !scene.fill2d) scene.fill2d = true;
if (opts.marker && !scene.scatter2d) scene.scatter2d = true;
if (opts.line && !scene.line2d) scene.line2d = true;
if ((opts.errorX || opts.errorY) && !scene.error2d) scene.error2d = true;
if (opts.text && !scene.glText) scene.glText = true;
if (opts.marker) opts.marker.snap = len;
scene.lineOptions.push(opts.line);
scene.errorXOptions.push(opts.errorX);
scene.errorYOptions.push(opts.errorY);
scene.fillOptions.push(opts.fill);
scene.markerOptions.push(opts.marker);
scene.markerSelectedOptions.push(opts.markerSel);
scene.markerUnselectedOptions.push(opts.markerUnsel);
scene.textOptions.push(opts.text);
scene.textSelectedOptions.push(opts.textSel);
scene.textUnselectedOptions.push(opts.textUnsel);
scene.selectBatch.push([]);
scene.unselectBatch.push([]);
stash._scene = scene;
stash.index = scene.count;
stash.x = x;
stash.y = y;
stash.positions = positions;
scene.count++;
return [{
x: false,
y: false,
t: stash,
trace: trace
}];
};
function expandForErrorBars(trace, ax, opts) {
var extremes = trace._extremes[ax._id];
var errExt = findExtremes(ax, opts._bnds, {
padded: true
});
extremes.min = extremes.min.concat(errExt.min);
extremes.max = extremes.max.concat(errExt.max);
}
function sceneOptions(gd, subplot, trace, positions, x, y) {
var opts = convert.style(gd, trace);
if (opts.marker) {
opts.marker.positions = positions;
}
if (opts.line && positions.length > 1) {
Lib.extendFlat(opts.line, convert.linePositions(gd, trace, positions));
}
if (opts.errorX || opts.errorY) {
var errors = convert.errorBarPositions(gd, trace, positions, x, y);
if (opts.errorX) {
Lib.extendFlat(opts.errorX, errors.x);
}
if (opts.errorY) {
Lib.extendFlat(opts.errorY, errors.y);
}
}
if (opts.text) {
Lib.extendFlat(opts.text, {
positions: positions
}, convert.textPosition(gd, trace, opts.text, opts.marker));
Lib.extendFlat(opts.textSel, {
positions: positions
}, convert.textPosition(gd, trace, opts.text, opts.markerSel));
Lib.extendFlat(opts.textUnsel, {
positions: positions
}, convert.textPosition(gd, trace, opts.text, opts.markerUnsel));
}
return opts;
}
/***/ }),
/***/ 57932:
/***/ (function(module) {
"use strict";
var SYMBOL_SIZE = 20;
module.exports = {
TOO_MANY_POINTS: 1e5,
SYMBOL_SDF_SIZE: 200,
SYMBOL_SIZE: SYMBOL_SIZE,
SYMBOL_STROKE: SYMBOL_SIZE / 20,
DOT_RE: /-dot/,
OPEN_RE: /-open/,
DASHES: {
solid: [1],
dot: [1, 1],
dash: [4, 1],
longdash: [8, 1],
dashdot: [4, 1, 1, 1],
longdashdot: [8, 1, 1, 1]
}
};
/***/ }),
/***/ 69447:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var svgSdf = __webpack_require__(92408);
var rgba = __webpack_require__(80608);
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var isArrayOrTypedArray = Lib.isArrayOrTypedArray;
var Drawing = __webpack_require__(49348);
var AxisIDs = __webpack_require__(21504);
var formatColor = (__webpack_require__(13396).formatColor);
var subTypes = __webpack_require__(76640);
var makeBubbleSizeFn = __webpack_require__(84036);
var helpers = __webpack_require__(69968);
var constants = __webpack_require__(57932);
var DESELECTDIM = (__webpack_require__(1172).DESELECTDIM);
var TEXTOFFSETSIGN = {
start: 1,
left: 1,
end: -1,
right: -1,
middle: 0,
center: 0,
bottom: 1,
top: -1
};
var appendArrayPointValue = (__webpack_require__(12228).appendArrayPointValue);
function convertStyle(gd, trace) {
var i;
var opts = {
marker: undefined,
markerSel: undefined,
markerUnsel: undefined,
line: undefined,
fill: undefined,
errorX: undefined,
errorY: undefined,
text: undefined,
textSel: undefined,
textUnsel: undefined
};
var plotGlPixelRatio = gd._context.plotGlPixelRatio;
if (trace.visible !== true) return opts;
if (subTypes.hasText(trace)) {
opts.text = convertTextStyle(gd, trace);
opts.textSel = convertTextSelection(gd, trace, trace.selected);
opts.textUnsel = convertTextSelection(gd, trace, trace.unselected);
}
if (subTypes.hasMarkers(trace)) {
opts.marker = convertMarkerStyle(gd, trace);
opts.markerSel = convertMarkerSelection(gd, trace, trace.selected);
opts.markerUnsel = convertMarkerSelection(gd, trace, trace.unselected);
if (!trace.unselected && isArrayOrTypedArray(trace.marker.opacity)) {
var mo = trace.marker.opacity;
opts.markerUnsel.opacity = new Array(mo.length);
for (i = 0; i < mo.length; i++) {
opts.markerUnsel.opacity[i] = DESELECTDIM * mo[i];
}
}
}
if (subTypes.hasLines(trace)) {
opts.line = {
overlay: true,
thickness: trace.line.width * plotGlPixelRatio,
color: trace.line.color,
opacity: trace.opacity
};
var dashes = (constants.DASHES[trace.line.dash] || [1]).slice();
for (i = 0; i < dashes.length; ++i) {
dashes[i] *= trace.line.width * plotGlPixelRatio;
}
opts.line.dashes = dashes;
}
if (trace.error_x && trace.error_x.visible) {
opts.errorX = convertErrorBarStyle(trace, trace.error_x, plotGlPixelRatio);
}
if (trace.error_y && trace.error_y.visible) {
opts.errorY = convertErrorBarStyle(trace, trace.error_y, plotGlPixelRatio);
}
if (!!trace.fill && trace.fill !== 'none') {
opts.fill = {
closed: true,
fill: trace.fillcolor,
thickness: 0
};
}
return opts;
}
function convertTextStyle(gd, trace) {
var fullLayout = gd._fullLayout;
var count = trace._length;
var textfontIn = trace.textfont;
var textpositionIn = trace.textposition;
var textPos = isArrayOrTypedArray(textpositionIn) ? textpositionIn : [textpositionIn];
var tfc = textfontIn.color;
var tfs = textfontIn.size;
var tff = textfontIn.family;
var optsOut = {};
var i;
var plotGlPixelRatio = gd._context.plotGlPixelRatio;
var texttemplate = trace.texttemplate;
if (texttemplate) {
optsOut.text = [];
var d3locale = fullLayout._d3locale;
var isArray = Array.isArray(texttemplate);
var N = isArray ? Math.min(texttemplate.length, count) : count;
var txt = isArray ? function (i) {
return texttemplate[i];
} : function () {
return texttemplate;
};
for (i = 0; i < N; i++) {
var d = {
i: i
};
var labels = trace._module.formatLabels(d, trace, fullLayout);
var pointValues = {};
appendArrayPointValue(pointValues, trace, i);
var meta = trace._meta || {};
optsOut.text.push(Lib.texttemplateString(txt(i), labels, d3locale, pointValues, d, meta));
}
} else {
if (isArrayOrTypedArray(trace.text) && trace.text.length < count) {
// if text array is shorter, we'll need to append to it, so let's slice to prevent mutating
optsOut.text = trace.text.slice();
} else {
optsOut.text = trace.text;
}
}
// pad text array with empty strings
if (isArrayOrTypedArray(optsOut.text)) {
for (i = optsOut.text.length; i < count; i++) {
optsOut.text[i] = '';
}
}
optsOut.opacity = trace.opacity;
optsOut.font = {};
optsOut.align = [];
optsOut.baseline = [];
for (i = 0; i < textPos.length; i++) {
var tp = textPos[i].split(/\s+/);
switch (tp[1]) {
case 'left':
optsOut.align.push('right');
break;
case 'right':
optsOut.align.push('left');
break;
default:
optsOut.align.push(tp[1]);
}
switch (tp[0]) {
case 'top':
optsOut.baseline.push('bottom');
break;
case 'bottom':
optsOut.baseline.push('top');
break;
default:
optsOut.baseline.push(tp[0]);
}
}
if (isArrayOrTypedArray(tfc)) {
optsOut.color = new Array(count);
for (i = 0; i < count; i++) {
optsOut.color[i] = tfc[i];
}
} else {
optsOut.color = tfc;
}
if (isArrayOrTypedArray(tfs) || isArrayOrTypedArray(tff)) {
// if any textfont param is array - make render a batch
optsOut.font = new Array(count);
for (i = 0; i < count; i++) {
var fonti = optsOut.font[i] = {};
fonti.size = (Lib.isTypedArray(tfs) ? tfs[i] : isArrayOrTypedArray(tfs) ? isNumeric(tfs[i]) ? tfs[i] : 0 : tfs) * plotGlPixelRatio;
fonti.family = isArrayOrTypedArray(tff) ? tff[i] : tff;
}
} else {
// if both are single values, make render fast single-value
optsOut.font = {
size: tfs * plotGlPixelRatio,
family: tff
};
}
return optsOut;
}
function convertMarkerStyle(gd, trace) {
var count = trace._length;
var optsIn = trace.marker;
var optsOut = {};
var i;
var multiSymbol = isArrayOrTypedArray(optsIn.symbol);
var multiAngle = isArrayOrTypedArray(optsIn.angle);
var multiColor = isArrayOrTypedArray(optsIn.color);
var multiLineColor = isArrayOrTypedArray(optsIn.line.color);
var multiOpacity = isArrayOrTypedArray(optsIn.opacity);
var multiSize = isArrayOrTypedArray(optsIn.size);
var multiLineWidth = isArrayOrTypedArray(optsIn.line.width);
var isOpen;
if (!multiSymbol) isOpen = helpers.isOpenSymbol(optsIn.symbol);
// prepare colors
if (multiSymbol || multiColor || multiLineColor || multiOpacity || multiAngle) {
optsOut.symbols = new Array(count);
optsOut.angles = new Array(count);
optsOut.colors = new Array(count);
optsOut.borderColors = new Array(count);
var symbols = optsIn.symbol;
var angles = optsIn.angle;
var colors = formatColor(optsIn, optsIn.opacity, count);
var borderColors = formatColor(optsIn.line, optsIn.opacity, count);
if (!isArrayOrTypedArray(borderColors[0])) {
var borderColor = borderColors;
borderColors = Array(count);
for (i = 0; i < count; i++) {
borderColors[i] = borderColor;
}
}
if (!isArrayOrTypedArray(colors[0])) {
var color = colors;
colors = Array(count);
for (i = 0; i < count; i++) {
colors[i] = color;
}
}
if (!isArrayOrTypedArray(symbols)) {
var symbol = symbols;
symbols = Array(count);
for (i = 0; i < count; i++) {
symbols[i] = symbol;
}
}
if (!isArrayOrTypedArray(angles)) {
var angle = angles;
angles = Array(count);
for (i = 0; i < count; i++) {
angles[i] = angle;
}
}
optsOut.symbols = symbols;
optsOut.angles = angles;
optsOut.colors = colors;
optsOut.borderColors = borderColors;
for (i = 0; i < count; i++) {
if (multiSymbol) {
isOpen = helpers.isOpenSymbol(optsIn.symbol[i]);
}
if (isOpen) {
borderColors[i] = colors[i].slice();
colors[i] = colors[i].slice();
colors[i][3] = 0;
}
}
optsOut.opacity = trace.opacity;
optsOut.markers = new Array(count);
for (i = 0; i < count; i++) {
optsOut.markers[i] = getSymbolSdf({
mx: optsOut.symbols[i],
ma: optsOut.angles[i]
}, trace);
}
} else {
if (isOpen) {
optsOut.color = rgba(optsIn.color, 'uint8');
optsOut.color[3] = 0;
optsOut.borderColor = rgba(optsIn.color, 'uint8');
} else {
optsOut.color = rgba(optsIn.color, 'uint8');
optsOut.borderColor = rgba(optsIn.line.color, 'uint8');
}
optsOut.opacity = trace.opacity * optsIn.opacity;
optsOut.marker = getSymbolSdf({
mx: optsIn.symbol,
ma: optsIn.angle
}, trace);
}
// prepare sizes
var sizeFactor = 1;
var markerSizeFunc = makeBubbleSizeFn(trace, sizeFactor);
var s;
if (multiSize || multiLineWidth) {
var sizes = optsOut.sizes = new Array(count);
var borderSizes = optsOut.borderSizes = new Array(count);
var sizeTotal = 0;
var sizeAvg;
if (multiSize) {
for (i = 0; i < count; i++) {
sizes[i] = markerSizeFunc(optsIn.size[i]);
sizeTotal += sizes[i];
}
sizeAvg = sizeTotal / count;
} else {
s = markerSizeFunc(optsIn.size);
for (i = 0; i < count; i++) {
sizes[i] = s;
}
}
// See https://github.com/plotly/plotly.js/pull/1781#discussion_r121820798
if (multiLineWidth) {
for (i = 0; i < count; i++) {
borderSizes[i] = optsIn.line.width[i];
}
} else {
s = optsIn.line.width;
for (i = 0; i < count; i++) {
borderSizes[i] = s;
}
}
optsOut.sizeAvg = sizeAvg;
} else {
optsOut.size = markerSizeFunc(optsIn && optsIn.size || 10);
optsOut.borderSizes = markerSizeFunc(optsIn.line.width);
}
return optsOut;
}
function convertMarkerSelection(gd, trace, target) {
var optsIn = trace.marker;
var optsOut = {};
if (!target) return optsOut;
if (target.marker && target.marker.symbol) {
optsOut = convertMarkerStyle(gd, Lib.extendFlat({}, optsIn, target.marker));
} else if (target.marker) {
if (target.marker.size) optsOut.size = target.marker.size;
if (target.marker.color) optsOut.colors = target.marker.color;
if (target.marker.opacity !== undefined) optsOut.opacity = target.marker.opacity;
}
return optsOut;
}
function convertTextSelection(gd, trace, target) {
var optsOut = {};
if (!target) return optsOut;
if (target.textfont) {
var optsIn = {
opacity: 1,
text: trace.text,
texttemplate: trace.texttemplate,
textposition: trace.textposition,
textfont: Lib.extendFlat({}, trace.textfont)
};
if (target.textfont) {
Lib.extendFlat(optsIn.textfont, target.textfont);
}
optsOut = convertTextStyle(gd, optsIn);
}
return optsOut;
}
function convertErrorBarStyle(trace, target, plotGlPixelRatio) {
var optsOut = {
capSize: target.width * 2 * plotGlPixelRatio,
lineWidth: target.thickness * plotGlPixelRatio,
color: target.color
};
if (target.copy_ystyle) {
optsOut = trace.error_y;
}
return optsOut;
}
var SYMBOL_SDF_SIZE = constants.SYMBOL_SDF_SIZE;
var SYMBOL_SIZE = constants.SYMBOL_SIZE;
var SYMBOL_STROKE = constants.SYMBOL_STROKE;
var SYMBOL_SDF = {};
var SYMBOL_SVG_CIRCLE = Drawing.symbolFuncs[0](SYMBOL_SIZE * 0.05);
function getSymbolSdf(d, trace) {
var symbol = d.mx;
if (symbol === 'circle') return null;
var symbolPath, symbolSdf;
var symbolNumber = Drawing.symbolNumber(symbol);
var symbolFunc = Drawing.symbolFuncs[symbolNumber % 100];
var symbolNoDot = !!Drawing.symbolNoDot[symbolNumber % 100];
var symbolNoFill = !!Drawing.symbolNoFill[symbolNumber % 100];
var isDot = helpers.isDotSymbol(symbol);
// until we may handle angles in shader?
if (d.ma) symbol += '_' + d.ma;
// get symbol sdf from cache or generate it
if (SYMBOL_SDF[symbol]) return SYMBOL_SDF[symbol];
var angle = Drawing.getMarkerAngle(d, trace);
if (isDot && !symbolNoDot) {
symbolPath = symbolFunc(SYMBOL_SIZE * 1.1, angle) + SYMBOL_SVG_CIRCLE;
} else {
symbolPath = symbolFunc(SYMBOL_SIZE, angle);
}
symbolSdf = svgSdf(symbolPath, {
w: SYMBOL_SDF_SIZE,
h: SYMBOL_SDF_SIZE,
viewBox: [-SYMBOL_SIZE, -SYMBOL_SIZE, SYMBOL_SIZE, SYMBOL_SIZE],
stroke: symbolNoFill ? SYMBOL_STROKE : -SYMBOL_STROKE
});
SYMBOL_SDF[symbol] = symbolSdf;
return symbolSdf || null;
}
function convertLinePositions(gd, trace, positions) {
var len = positions.length;
var count = len / 2;
var linePositions;
var i;
if (subTypes.hasLines(trace) && count) {
if (trace.line.shape === 'hv') {
linePositions = [];
for (i = 0; i < count - 1; i++) {
if (isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1])) {
linePositions.push(NaN, NaN, NaN, NaN);
} else {
linePositions.push(positions[i * 2], positions[i * 2 + 1]);
if (!isNaN(positions[i * 2 + 2]) && !isNaN(positions[i * 2 + 3])) {
linePositions.push(positions[i * 2 + 2], positions[i * 2 + 1]);
} else {
linePositions.push(NaN, NaN);
}
}
}
linePositions.push(positions[len - 2], positions[len - 1]);
} else if (trace.line.shape === 'hvh') {
linePositions = [];
for (i = 0; i < count - 1; i++) {
if (isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1]) || isNaN(positions[i * 2 + 2]) || isNaN(positions[i * 2 + 3])) {
if (!isNaN(positions[i * 2]) && !isNaN(positions[i * 2 + 1])) {
linePositions.push(positions[i * 2], positions[i * 2 + 1]);
} else {
linePositions.push(NaN, NaN);
}
linePositions.push(NaN, NaN);
} else {
var midPtX = (positions[i * 2] + positions[i * 2 + 2]) / 2;
linePositions.push(positions[i * 2], positions[i * 2 + 1], midPtX, positions[i * 2 + 1], midPtX, positions[i * 2 + 3]);
}
}
linePositions.push(positions[len - 2], positions[len - 1]);
} else if (trace.line.shape === 'vhv') {
linePositions = [];
for (i = 0; i < count - 1; i++) {
if (isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1]) || isNaN(positions[i * 2 + 2]) || isNaN(positions[i * 2 + 3])) {
if (!isNaN(positions[i * 2]) && !isNaN(positions[i * 2 + 1])) {
linePositions.push(positions[i * 2], positions[i * 2 + 1]);
} else {
linePositions.push(NaN, NaN);
}
linePositions.push(NaN, NaN);
} else {
var midPtY = (positions[i * 2 + 1] + positions[i * 2 + 3]) / 2;
linePositions.push(positions[i * 2], positions[i * 2 + 1], positions[i * 2], midPtY, positions[i * 2 + 2], midPtY);
}
}
linePositions.push(positions[len - 2], positions[len - 1]);
} else if (trace.line.shape === 'vh') {
linePositions = [];
for (i = 0; i < count - 1; i++) {
if (isNaN(positions[i * 2]) || isNaN(positions[i * 2 + 1])) {
linePositions.push(NaN, NaN, NaN, NaN);
} else {
linePositions.push(positions[i * 2], positions[i * 2 + 1]);
if (!isNaN(positions[i * 2 + 2]) && !isNaN(positions[i * 2 + 3])) {
linePositions.push(positions[i * 2], positions[i * 2 + 3]);
} else {
linePositions.push(NaN, NaN);
}
}
}
linePositions.push(positions[len - 2], positions[len - 1]);
} else {
linePositions = positions;
}
}
// If we have data with gaps, we ought to use rect joins
// FIXME: get rid of this
var hasNaN = false;
for (i = 0; i < linePositions.length; i++) {
if (isNaN(linePositions[i])) {
hasNaN = true;
break;
}
}
var join = hasNaN || linePositions.length > constants.TOO_MANY_POINTS ? 'rect' : subTypes.hasMarkers(trace) ? 'rect' : 'round';
// fill gaps
if (hasNaN && trace.connectgaps) {
var lastX = linePositions[0];
var lastY = linePositions[1];
for (i = 0; i < linePositions.length; i += 2) {
if (isNaN(linePositions[i]) || isNaN(linePositions[i + 1])) {
linePositions[i] = lastX;
linePositions[i + 1] = lastY;
} else {
lastX = linePositions[i];
lastY = linePositions[i + 1];
}
}
}
return {
join: join,
positions: linePositions
};
}
function convertErrorBarPositions(gd, trace, positions, x, y) {
var makeComputeError = Registry.getComponentMethod('errorbars', 'makeComputeError');
var xa = AxisIDs.getFromId(gd, trace.xaxis, 'x');
var ya = AxisIDs.getFromId(gd, trace.yaxis, 'y');
var count = positions.length / 2;
var out = {};
function convertOneAxis(coords, ax) {
var axLetter = ax._id.charAt(0);
var opts = trace['error_' + axLetter];
if (opts && opts.visible && (ax.type === 'linear' || ax.type === 'log')) {
var computeError = makeComputeError(opts);
var pOffset = {
x: 0,
y: 1
}[axLetter];
var eOffset = {
x: [0, 1, 2, 3],
y: [2, 3, 0, 1]
}[axLetter];
var errors = new Float64Array(4 * count);
var minShoe = Infinity;
var maxHat = -Infinity;
for (var i = 0, j = 0; i < count; i++, j += 4) {
var dc = coords[i];
if (isNumeric(dc)) {
var dl = positions[i * 2 + pOffset];
var vals = computeError(dc, i);
var lv = vals[0];
var hv = vals[1];
if (isNumeric(lv) && isNumeric(hv)) {
var shoe = dc - lv;
var hat = dc + hv;
errors[j + eOffset[0]] = dl - ax.c2l(shoe);
errors[j + eOffset[1]] = ax.c2l(hat) - dl;
errors[j + eOffset[2]] = 0;
errors[j + eOffset[3]] = 0;
minShoe = Math.min(minShoe, dc - lv);
maxHat = Math.max(maxHat, dc + hv);
}
}
}
out[axLetter] = {
positions: positions,
errors: errors,
_bnds: [minShoe, maxHat]
};
}
}
convertOneAxis(x, xa);
convertOneAxis(y, ya);
return out;
}
function convertTextPosition(gd, trace, textOpts, markerOpts) {
var count = trace._length;
var out = {};
var i;
// corresponds to textPointPosition from component.drawing
if (subTypes.hasMarkers(trace)) {
var fontOpts = textOpts.font;
var align = textOpts.align;
var baseline = textOpts.baseline;
out.offset = new Array(count);
for (i = 0; i < count; i++) {
var ms = markerOpts.sizes ? markerOpts.sizes[i] : markerOpts.size;
var fs = isArrayOrTypedArray(fontOpts) ? fontOpts[i].size : fontOpts.size;
var a = isArrayOrTypedArray(align) ? align.length > 1 ? align[i] : align[0] : align;
var b = isArrayOrTypedArray(baseline) ? baseline.length > 1 ? baseline[i] : baseline[0] : baseline;
var hSign = TEXTOFFSETSIGN[a];
var vSign = TEXTOFFSETSIGN[b];
var xPad = ms ? ms / 0.8 + 1 : 0;
var yPad = -vSign * xPad - vSign * 0.5;
out.offset[i] = [hSign * xPad / fs, yPad / fs];
}
}
return out;
}
module.exports = {
style: convertStyle,
markerStyle: convertMarkerStyle,
markerSelection: convertMarkerSelection,
linePositions: convertLinePositions,
errorBarPositions: convertErrorBarPositions,
textPosition: convertTextPosition
};
/***/ }),
/***/ 46316:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
var helpers = __webpack_require__(69968);
var attributes = __webpack_require__(9824);
var constants = __webpack_require__(5892);
var subTypes = __webpack_require__(76640);
var handleXYDefaults = __webpack_require__(88376);
var handlePeriodDefaults = __webpack_require__(98632);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleFillColorDefaults = __webpack_require__(73168);
var handleTextDefaults = __webpack_require__(52960);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var isOpen = traceIn.marker ? helpers.isOpenSymbol(traceIn.marker.symbol) : false;
var isBubble = subTypes.isBubble(traceIn);
var len = handleXYDefaults(traceIn, traceOut, layout, coerce);
if (!len) {
traceOut.visible = false;
return;
}
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');
var defaultMode = len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines';
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('mode', defaultMode);
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
noAngleRef: true,
noStandOff: true
});
coerce('marker.line.width', isOpen || isBubble ? 1 : 0);
}
if (subTypes.hasLines(traceOut)) {
coerce('connectgaps');
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
coerce('line.shape');
}
if (subTypes.hasText(traceOut)) {
coerce('texttemplate');
handleTextDefaults(traceIn, traceOut, layout, coerce);
}
var lineColor = (traceOut.line || {}).color;
var markerColor = (traceOut.marker || {}).color;
coerce('fill');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
}
var errorBarsSupplyDefaults = Registry.getComponentMethod('errorbars', 'supplyDefaults');
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || markerColor || defaultColor, {
axis: 'y'
});
errorBarsSupplyDefaults(traceIn, traceOut, lineColor || markerColor || defaultColor, {
axis: 'x',
inherit: 'y'
});
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 86396:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Color = __webpack_require__(9240);
var DESELECTDIM = (__webpack_require__(1172).DESELECTDIM);
function styleTextSelection(cd) {
var cd0 = cd[0];
var trace = cd0.trace;
var stash = cd0.t;
var scene = stash._scene;
var index = stash.index;
var els = scene.selectBatch[index];
var unels = scene.unselectBatch[index];
var baseOpts = scene.textOptions[index];
var selOpts = scene.textSelectedOptions[index] || {};
var unselOpts = scene.textUnselectedOptions[index] || {};
var opts = Lib.extendFlat({}, baseOpts);
var i, j;
if (els.length || unels.length) {
var stc = selOpts.color;
var utc = unselOpts.color;
var base = baseOpts.color;
var hasArrayBase = Lib.isArrayOrTypedArray(base);
opts.color = new Array(trace._length);
for (i = 0; i < els.length; i++) {
j = els[i];
opts.color[j] = stc || (hasArrayBase ? base[j] : base);
}
for (i = 0; i < unels.length; i++) {
j = unels[i];
var basej = hasArrayBase ? base[j] : base;
opts.color[j] = utc ? utc : stc ? basej : Color.addOpacity(basej, DESELECTDIM);
}
}
scene.glText[index].update(opts);
}
module.exports = {
styleTextSelection: styleTextSelection
};
/***/ }),
/***/ 23372:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterFormatLabels = __webpack_require__(23400);
module.exports = function formatLabels(cdi, trace, fullLayout) {
var i = cdi.i;
if (!('x' in cdi)) cdi.x = trace._x[i];
if (!('y' in cdi)) cdi.y = trace._y[i];
return scatterFormatLabels(cdi, trace, fullLayout);
};
/***/ }),
/***/ 69968:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var constants = __webpack_require__(57932);
exports.isOpenSymbol = function (symbol) {
return typeof symbol === 'string' ? constants.OPEN_RE.test(symbol) : symbol % 200 > 100;
};
exports.isDotSymbol = function (symbol) {
return typeof symbol === 'string' ? constants.DOT_RE.test(symbol) : symbol > 200;
};
/***/ }),
/***/ 62236:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var getTraceColor = __webpack_require__(85600);
function hoverPoints(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var stash = cd[0].t;
var trace = cd[0].trace;
var xa = pointData.xa;
var ya = pointData.ya;
var x = stash.x;
var y = stash.y;
var xpx = xa.c2p(xval);
var ypx = ya.c2p(yval);
var maxDistance = pointData.distance;
var ids;
// FIXME: make sure this is a proper way to calc search radius
if (stash.tree) {
var xl = xa.p2c(xpx - maxDistance);
var xr = xa.p2c(xpx + maxDistance);
var yl = ya.p2c(ypx - maxDistance);
var yr = ya.p2c(ypx + maxDistance);
if (hovermode === 'x') {
ids = stash.tree.range(Math.min(xl, xr), Math.min(ya._rl[0], ya._rl[1]), Math.max(xl, xr), Math.max(ya._rl[0], ya._rl[1]));
} else {
ids = stash.tree.range(Math.min(xl, xr), Math.min(yl, yr), Math.max(xl, xr), Math.max(yl, yr));
}
} else {
ids = stash.ids;
}
// pick the id closest to the point
// note that point possibly may not be found
var k, closestId, ptx, pty, i, dx, dy, dist, dxy;
var minDist = maxDistance;
if (hovermode === 'x') {
var xPeriod = !!trace.xperiodalignment;
var yPeriod = !!trace.yperiodalignment;
for (i = 0; i < ids.length; i++) {
k = ids[i];
ptx = x[k];
dx = Math.abs(xa.c2p(ptx) - xpx);
if (xPeriod) {
var x0 = xa.c2p(trace._xStarts[k]);
var x1 = xa.c2p(trace._xEnds[k]);
dx = xpx >= Math.min(x0, x1) && xpx <= Math.max(x0, x1) ? 0 : Infinity;
}
if (dx < minDist) {
minDist = dx;
pty = y[k];
dy = ya.c2p(pty) - ypx;
if (yPeriod) {
var y0 = ya.c2p(trace._yStarts[k]);
var y1 = ya.c2p(trace._yEnds[k]);
dy = ypx >= Math.min(y0, y1) && ypx <= Math.max(y0, y1) ? 0 : Infinity;
}
dxy = Math.sqrt(dx * dx + dy * dy);
closestId = ids[i];
}
}
} else {
for (i = ids.length - 1; i > -1; i--) {
k = ids[i];
ptx = x[k];
pty = y[k];
dx = xa.c2p(ptx) - xpx;
dy = ya.c2p(pty) - ypx;
dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
minDist = dxy = dist;
closestId = k;
}
}
}
pointData.index = closestId;
pointData.distance = minDist;
pointData.dxy = dxy;
if (closestId === undefined) return [pointData];
return [calcHover(pointData, x, y, trace)];
}
function calcHover(pointData, x, y, trace) {
var xa = pointData.xa;
var ya = pointData.ya;
var minDist = pointData.distance;
var dxy = pointData.dxy;
var id = pointData.index;
// the closest data point
var di = {
pointNumber: id,
x: x[id],
y: y[id]
};
// that is single-item arrays_to_calcdata excerpt, since we are doing it for a single point and we don't have to do it beforehead for 1e6 points
di.tx = Lib.isArrayOrTypedArray(trace.text) ? trace.text[id] : trace.text;
di.htx = Array.isArray(trace.hovertext) ? trace.hovertext[id] : trace.hovertext;
di.data = Array.isArray(trace.customdata) ? trace.customdata[id] : trace.customdata;
di.tp = Array.isArray(trace.textposition) ? trace.textposition[id] : trace.textposition;
var font = trace.textfont;
if (font) {
di.ts = Lib.isArrayOrTypedArray(font.size) ? font.size[id] : font.size;
di.tc = Array.isArray(font.color) ? font.color[id] : font.color;
di.tf = Array.isArray(font.family) ? font.family[id] : font.family;
}
var marker = trace.marker;
if (marker) {
di.ms = Lib.isArrayOrTypedArray(marker.size) ? marker.size[id] : marker.size;
di.mo = Lib.isArrayOrTypedArray(marker.opacity) ? marker.opacity[id] : marker.opacity;
di.mx = Lib.isArrayOrTypedArray(marker.symbol) ? marker.symbol[id] : marker.symbol;
di.ma = Lib.isArrayOrTypedArray(marker.angle) ? marker.angle[id] : marker.angle;
di.mc = Lib.isArrayOrTypedArray(marker.color) ? marker.color[id] : marker.color;
}
var line = marker && marker.line;
if (line) {
di.mlc = Array.isArray(line.color) ? line.color[id] : line.color;
di.mlw = Lib.isArrayOrTypedArray(line.width) ? line.width[id] : line.width;
}
var grad = marker && marker.gradient;
if (grad && grad.type !== 'none') {
di.mgt = Array.isArray(grad.type) ? grad.type[id] : grad.type;
di.mgc = Array.isArray(grad.color) ? grad.color[id] : grad.color;
}
var xp = xa.c2p(di.x, true);
var yp = ya.c2p(di.y, true);
var rad = di.mrc || 1;
var hoverlabel = trace.hoverlabel;
if (hoverlabel) {
di.hbg = Array.isArray(hoverlabel.bgcolor) ? hoverlabel.bgcolor[id] : hoverlabel.bgcolor;
di.hbc = Array.isArray(hoverlabel.bordercolor) ? hoverlabel.bordercolor[id] : hoverlabel.bordercolor;
di.hts = Lib.isArrayOrTypedArray(hoverlabel.font.size) ? hoverlabel.font.size[id] : hoverlabel.font.size;
di.htc = Array.isArray(hoverlabel.font.color) ? hoverlabel.font.color[id] : hoverlabel.font.color;
di.htf = Array.isArray(hoverlabel.font.family) ? hoverlabel.font.family[id] : hoverlabel.font.family;
di.hnl = Lib.isArrayOrTypedArray(hoverlabel.namelength) ? hoverlabel.namelength[id] : hoverlabel.namelength;
}
var hoverinfo = trace.hoverinfo;
if (hoverinfo) {
di.hi = Array.isArray(hoverinfo) ? hoverinfo[id] : hoverinfo;
}
var hovertemplate = trace.hovertemplate;
if (hovertemplate) {
di.ht = Array.isArray(hovertemplate) ? hovertemplate[id] : hovertemplate;
}
var fakeCd = {};
fakeCd[pointData.index] = di;
var origX = trace._origX;
var origY = trace._origY;
var pointData2 = Lib.extendFlat({}, pointData, {
color: getTraceColor(trace, di),
x0: xp - rad,
x1: xp + rad,
xLabelVal: origX ? origX[id] : di.x,
y0: yp - rad,
y1: yp + rad,
yLabelVal: origY ? origY[id] : di.y,
cd: fakeCd,
distance: minDist,
spikeDistance: dxy,
hovertemplate: di.ht
});
if (di.htx) pointData2.text = di.htx;else if (di.tx) pointData2.text = di.tx;else if (trace.text) pointData2.text = trace.text;
Lib.fillText(di, trace, pointData2);
Registry.getComponentMethod('errorbars', 'hoverInfo')(di, trace, pointData2);
return pointData2;
}
module.exports = {
hoverPoints: hoverPoints,
calcHover: calcHover
};
/***/ }),
/***/ 67120:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var index = __webpack_require__(52824);
index.plot = __webpack_require__(45496);
module.exports = index;
/***/ }),
/***/ 45496:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createScatter = __webpack_require__(86360);
var createLine = __webpack_require__(54368);
var createError = __webpack_require__(75912);
var Text = __webpack_require__(61872);
var Lib = __webpack_require__(10923);
var selectMode = (__webpack_require__(6168).selectMode);
var prepareRegl = __webpack_require__(81976);
var subTypes = __webpack_require__(76640);
var linkTraces = __webpack_require__(84732);
var styleTextSelection = (__webpack_require__(86396).styleTextSelection);
var reglPrecompiled = {};
function getViewport(fullLayout, xaxis, yaxis, plotGlPixelRatio) {
var gs = fullLayout._size;
var width = fullLayout.width * plotGlPixelRatio;
var height = fullLayout.height * plotGlPixelRatio;
var l = gs.l * plotGlPixelRatio;
var b = gs.b * plotGlPixelRatio;
var r = gs.r * plotGlPixelRatio;
var t = gs.t * plotGlPixelRatio;
var w = gs.w * plotGlPixelRatio;
var h = gs.h * plotGlPixelRatio;
return [l + xaxis.domain[0] * w, b + yaxis.domain[0] * h, width - r - (1 - xaxis.domain[1]) * w, height - t - (1 - yaxis.domain[1]) * h];
}
var exports = module.exports = function plot(gd, subplot, cdata) {
if (!cdata.length) return;
var fullLayout = gd._fullLayout;
var scene = subplot._scene;
var xaxis = subplot.xaxis;
var yaxis = subplot.yaxis;
var i, j;
// we may have more subplots than initialized data due to Axes.getSubplots method
if (!scene) return;
var success = prepareRegl(gd, ['ANGLE_instanced_arrays', 'OES_element_index_uint'], reglPrecompiled);
if (!success) {
scene.init();
return;
}
var count = scene.count;
var regl = fullLayout._glcanvas.data()[0].regl;
// that is needed for fills
linkTraces(gd, subplot, cdata);
if (scene.dirty) {
if ((scene.line2d || scene.error2d) && !(scene.scatter2d || scene.fill2d || scene.glText)) {
// Fixes shared WebGL context drawing lines only case
regl.clear({});
}
// make sure scenes are created
if (scene.error2d === true) {
scene.error2d = createError(regl);
}
if (scene.line2d === true) {
scene.line2d = createLine(regl);
}
if (scene.scatter2d === true) {
scene.scatter2d = createScatter(regl);
}
if (scene.fill2d === true) {
scene.fill2d = createLine(regl);
}
if (scene.glText === true) {
scene.glText = new Array(count);
for (i = 0; i < count; i++) {
scene.glText[i] = new Text(regl);
}
}
// update main marker options
if (scene.glText) {
if (count > scene.glText.length) {
// add gl text marker
var textsToAdd = count - scene.glText.length;
for (i = 0; i < textsToAdd; i++) {
scene.glText.push(new Text(regl));
}
} else if (count < scene.glText.length) {
// remove gl text marker
var textsToRemove = scene.glText.length - count;
var removedTexts = scene.glText.splice(count, textsToRemove);
removedTexts.forEach(function (text) {
text.destroy();
});
}
for (i = 0; i < count; i++) {
scene.glText[i].update(scene.textOptions[i]);
}
}
if (scene.line2d) {
scene.line2d.update(scene.lineOptions);
scene.lineOptions = scene.lineOptions.map(function (lineOptions) {
if (lineOptions && lineOptions.positions) {
var srcPos = lineOptions.positions;
var firstptdef = 0;
while (firstptdef < srcPos.length && (isNaN(srcPos[firstptdef]) || isNaN(srcPos[firstptdef + 1]))) {
firstptdef += 2;
}
var lastptdef = srcPos.length - 2;
while (lastptdef > firstptdef && (isNaN(srcPos[lastptdef]) || isNaN(srcPos[lastptdef + 1]))) {
lastptdef -= 2;
}
lineOptions.positions = srcPos.slice(firstptdef, lastptdef + 2);
}
return lineOptions;
});
scene.line2d.update(scene.lineOptions);
}
if (scene.error2d) {
var errorBatch = (scene.errorXOptions || []).concat(scene.errorYOptions || []);
scene.error2d.update(errorBatch);
}
if (scene.scatter2d) {
scene.scatter2d.update(scene.markerOptions);
}
// fill requires linked traces, so we generate it's positions here
scene.fillOrder = Lib.repeat(null, count);
if (scene.fill2d) {
scene.fillOptions = scene.fillOptions.map(function (fillOptions, i) {
var cdscatter = cdata[i];
if (!fillOptions || !cdscatter || !cdscatter[0] || !cdscatter[0].trace) return;
var cd = cdscatter[0];
var trace = cd.trace;
var stash = cd.t;
var lineOptions = scene.lineOptions[i];
var last, j;
var fillData = [];
if (trace._ownfill) fillData.push(i);
if (trace._nexttrace) fillData.push(i + 1);
if (fillData.length) scene.fillOrder[i] = fillData;
var pos = [];
var srcPos = lineOptions && lineOptions.positions || stash.positions;
var firstptdef, lastptdef;
if (trace.fill === 'tozeroy') {
firstptdef = 0;
while (firstptdef < srcPos.length && isNaN(srcPos[firstptdef + 1])) {
firstptdef += 2;
}
lastptdef = srcPos.length - 2;
while (lastptdef > firstptdef && isNaN(srcPos[lastptdef + 1])) {
lastptdef -= 2;
}
if (srcPos[firstptdef + 1] !== 0) {
pos = [srcPos[firstptdef], 0];
}
pos = pos.concat(srcPos.slice(firstptdef, lastptdef + 2));
if (srcPos[lastptdef + 1] !== 0) {
pos = pos.concat([srcPos[lastptdef], 0]);
}
} else if (trace.fill === 'tozerox') {
firstptdef = 0;
while (firstptdef < srcPos.length && isNaN(srcPos[firstptdef])) {
firstptdef += 2;
}
lastptdef = srcPos.length - 2;
while (lastptdef > firstptdef && isNaN(srcPos[lastptdef])) {
lastptdef -= 2;
}
if (srcPos[firstptdef] !== 0) {
pos = [0, srcPos[firstptdef + 1]];
}
pos = pos.concat(srcPos.slice(firstptdef, lastptdef + 2));
if (srcPos[lastptdef] !== 0) {
pos = pos.concat([0, srcPos[lastptdef + 1]]);
}
} else if (trace.fill === 'toself' || trace.fill === 'tonext') {
pos = [];
last = 0;
fillOptions.splitNull = true;
for (j = 0; j < srcPos.length; j += 2) {
if (isNaN(srcPos[j]) || isNaN(srcPos[j + 1])) {
pos = pos.concat(srcPos.slice(last, j));
pos.push(srcPos[last], srcPos[last + 1]);
pos.push(null, null); // keep null to mark end of polygon
last = j + 2;
}
}
pos = pos.concat(srcPos.slice(last));
if (last) {
pos.push(srcPos[last], srcPos[last + 1]);
}
} else {
var nextTrace = trace._nexttrace;
if (nextTrace) {
var nextOptions = scene.lineOptions[i + 1];
if (nextOptions) {
var nextPos = nextOptions.positions;
if (trace.fill === 'tonexty') {
pos = srcPos.slice();
for (i = Math.floor(nextPos.length / 2); i--;) {
var xx = nextPos[i * 2];
var yy = nextPos[i * 2 + 1];
if (isNaN(xx) || isNaN(yy)) continue;
pos.push(xx, yy);
}
fillOptions.fill = nextTrace.fillcolor;
}
}
}
}
// detect prev trace positions to exclude from current fill
if (trace._prevtrace && trace._prevtrace.fill === 'tonext') {
var prevLinePos = scene.lineOptions[i - 1].positions;
// FIXME: likely this logic should be tested better
var offset = pos.length / 2;
last = offset;
var hole = [last];
for (j = 0; j < prevLinePos.length; j += 2) {
if (isNaN(prevLinePos[j]) || isNaN(prevLinePos[j + 1])) {
hole.push(j / 2 + offset + 1);
last = j + 2;
}
}
pos = pos.concat(prevLinePos);
fillOptions.hole = hole;
}
fillOptions.fillmode = trace.fill;
fillOptions.opacity = trace.opacity;
fillOptions.positions = pos;
return fillOptions;
});
scene.fill2d.update(scene.fillOptions);
}
}
// form batch arrays, and check for selected points
var dragmode = fullLayout.dragmode;
var isSelectMode = selectMode(dragmode);
var clickSelectEnabled = fullLayout.clickmode.indexOf('select') > -1;
for (i = 0; i < count; i++) {
var cd0 = cdata[i][0];
var trace = cd0.trace;
var stash = cd0.t;
var index = stash.index;
var len = trace._length;
var x = stash.x;
var y = stash.y;
if (trace.selectedpoints || isSelectMode || clickSelectEnabled) {
if (!isSelectMode) isSelectMode = true;
// regenerate scene batch, if traces number changed during selection
if (trace.selectedpoints) {
var selPts = scene.selectBatch[index] = Lib.selIndices2selPoints(trace);
var selDict = {};
for (j = 0; j < selPts.length; j++) {
selDict[selPts[j]] = 1;
}
var unselPts = [];
for (j = 0; j < len; j++) {
if (!selDict[j]) unselPts.push(j);
}
scene.unselectBatch[index] = unselPts;
}
// precalculate px coords since we are not going to pan during select
// TODO, could do better here e.g.
// - spin that in a webworker
// - compute selection from polygons in data coordinates
// (maybe just for linear axes)
var xpx = stash.xpx = new Array(len);
var ypx = stash.ypx = new Array(len);
for (j = 0; j < len; j++) {
xpx[j] = xaxis.c2p(x[j]);
ypx[j] = yaxis.c2p(y[j]);
}
} else {
stash.xpx = stash.ypx = null;
}
}
if (isSelectMode) {
// create scatter instance by cloning scatter2d
if (!scene.select2d) {
scene.select2d = createScatter(fullLayout._glcanvas.data()[1].regl);
}
// use unselected styles on 'context' canvas
if (scene.scatter2d) {
var unselOpts = new Array(count);
for (i = 0; i < count; i++) {
unselOpts[i] = scene.selectBatch[i].length || scene.unselectBatch[i].length ? scene.markerUnselectedOptions[i] : {};
}
scene.scatter2d.update(unselOpts);
}
// use selected style on 'focus' canvas
if (scene.select2d) {
scene.select2d.update(scene.markerOptions);
scene.select2d.update(scene.markerSelectedOptions);
}
if (scene.glText) {
cdata.forEach(function (cdscatter) {
var trace = ((cdscatter || [])[0] || {}).trace || {};
if (subTypes.hasText(trace)) {
styleTextSelection(cdscatter);
}
});
}
} else {
// reset 'context' scatter2d opts to base opts,
// thus unsetting markerUnselectedOptions from selection
if (scene.scatter2d) {
scene.scatter2d.update(scene.markerOptions);
}
}
// provide viewport and range
var vpRange0 = {
viewport: getViewport(fullLayout, xaxis, yaxis, gd._context.plotGlPixelRatio),
// TODO do we need those fallbacks?
range: [(xaxis._rl || xaxis.range)[0], (yaxis._rl || yaxis.range)[0], (xaxis._rl || xaxis.range)[1], (yaxis._rl || yaxis.range)[1]]
};
var vpRange = Lib.repeat(vpRange0, scene.count);
// upload viewport/range data to GPU
if (scene.fill2d) {
scene.fill2d.update(vpRange);
}
if (scene.line2d) {
scene.line2d.update(vpRange);
}
if (scene.error2d) {
scene.error2d.update(vpRange.concat(vpRange));
}
if (scene.scatter2d) {
scene.scatter2d.update(vpRange);
}
if (scene.select2d) {
scene.select2d.update(vpRange);
}
if (scene.glText) {
scene.glText.forEach(function (text) {
text.update(vpRange0);
});
}
};
exports.reglPrecompiled = reglPrecompiled;
/***/ }),
/***/ 83632:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
// make sure scene exists on subplot, return it
module.exports = function sceneUpdate(gd, subplot) {
var scene = subplot._scene;
var resetOpts = {
// number of traces in subplot, since scene:subplot -> 1:1
count: 0,
// whether scene requires init hook in plot call (dirty plot call)
dirty: true,
// last used options
lineOptions: [],
fillOptions: [],
markerOptions: [],
markerSelectedOptions: [],
markerUnselectedOptions: [],
errorXOptions: [],
errorYOptions: [],
textOptions: [],
textSelectedOptions: [],
textUnselectedOptions: [],
// selection batches
selectBatch: [],
unselectBatch: []
};
// regl- component stubs, initialized in dirty plot call
var initOpts = {
fill2d: false,
scatter2d: false,
error2d: false,
line2d: false,
glText: false,
select2d: false
};
if (!subplot._scene) {
scene = subplot._scene = {};
scene.init = function init() {
Lib.extendFlat(scene, initOpts, resetOpts);
};
scene.init();
// apply new option to all regl components (used on drag)
scene.update = function update(opt) {
var opts = Lib.repeat(opt, scene.count);
if (scene.fill2d) scene.fill2d.update(opts);
if (scene.scatter2d) scene.scatter2d.update(opts);
if (scene.line2d) scene.line2d.update(opts);
if (scene.error2d) scene.error2d.update(opts.concat(opts));
if (scene.select2d) scene.select2d.update(opts);
if (scene.glText) {
for (var i = 0; i < scene.count; i++) {
scene.glText[i].update(opt);
}
}
};
// draw traces in proper order
scene.draw = function draw() {
var count = scene.count;
var fill2d = scene.fill2d;
var error2d = scene.error2d;
var line2d = scene.line2d;
var scatter2d = scene.scatter2d;
var glText = scene.glText;
var select2d = scene.select2d;
var selectBatch = scene.selectBatch;
var unselectBatch = scene.unselectBatch;
for (var i = 0; i < count; i++) {
if (fill2d && scene.fillOrder[i]) {
fill2d.draw(scene.fillOrder[i]);
}
if (line2d && scene.lineOptions[i]) {
line2d.draw(i);
}
if (error2d) {
if (scene.errorXOptions[i]) error2d.draw(i);
if (scene.errorYOptions[i]) error2d.draw(i + count);
}
if (scatter2d && scene.markerOptions[i]) {
if (unselectBatch[i].length) {
var arg = Lib.repeat([], scene.count);
arg[i] = unselectBatch[i];
scatter2d.draw(arg);
} else if (!selectBatch[i].length) {
scatter2d.draw(i);
}
}
if (glText[i] && scene.textOptions[i]) {
glText[i].render();
}
}
if (select2d) {
select2d.draw(selectBatch);
}
scene.dirty = false;
};
// remove scene resources
scene.destroy = function destroy() {
if (scene.fill2d && scene.fill2d.destroy) scene.fill2d.destroy();
if (scene.scatter2d && scene.scatter2d.destroy) scene.scatter2d.destroy();
if (scene.error2d && scene.error2d.destroy) scene.error2d.destroy();
if (scene.line2d && scene.line2d.destroy) scene.line2d.destroy();
if (scene.select2d && scene.select2d.destroy) scene.select2d.destroy();
if (scene.glText) {
scene.glText.forEach(function (text) {
if (text.destroy) text.destroy();
});
}
scene.lineOptions = null;
scene.fillOptions = null;
scene.markerOptions = null;
scene.markerSelectedOptions = null;
scene.markerUnselectedOptions = null;
scene.errorXOptions = null;
scene.errorYOptions = null;
scene.textOptions = null;
scene.textSelectedOptions = null;
scene.textUnselectedOptions = null;
scene.selectBatch = null;
scene.unselectBatch = null;
// we can't just delete _scene, because `destroy` is called in the
// middle of supplyDefaults, before relinkPrivateKeys which will put it back.
subplot._scene = null;
};
}
// in case if we have scene from the last calc - reset data
if (!scene.dirty) {
Lib.extendFlat(scene, resetOpts);
}
return scene;
};
/***/ }),
/***/ 32432:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var subTypes = __webpack_require__(76640);
var styleTextSelection = (__webpack_require__(86396).styleTextSelection);
module.exports = function select(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var selection = [];
var trace = cd[0].trace;
var stash = cd[0].t;
var len = trace._length;
var x = stash.x;
var y = stash.y;
var scene = stash._scene;
var index = stash.index;
if (!scene) return selection;
var hasText = subTypes.hasText(trace);
var hasMarkers = subTypes.hasMarkers(trace);
var hasOnlyLines = !hasMarkers && !hasText;
if (trace.visible !== true || hasOnlyLines) return selection;
var els = [];
var unels = [];
// degenerate polygon does not enable selection
// filter out points by visible scatter ones
if (selectionTester !== false && !selectionTester.degenerate) {
for (var i = 0; i < len; i++) {
if (selectionTester.contains([stash.xpx[i], stash.ypx[i]], false, i, searchInfo)) {
els.push(i);
selection.push({
pointNumber: i,
x: xa.c2d(x[i]),
y: ya.c2d(y[i])
});
} else {
unels.push(i);
}
}
}
if (hasMarkers) {
var scatter2d = scene.scatter2d;
if (!els.length && !unels.length) {
// reset to base styles when clearing
var baseOpts = new Array(scene.count);
baseOpts[index] = scene.markerOptions[index];
scatter2d.update.apply(scatter2d, baseOpts);
} else if (!scene.selectBatch[index].length && !scene.unselectBatch[index].length) {
// set unselected styles on 'context' canvas (if not done already)
var unselOpts = new Array(scene.count);
unselOpts[index] = scene.markerUnselectedOptions[index];
scatter2d.update.apply(scatter2d, unselOpts);
}
}
scene.selectBatch[index] = els;
scene.unselectBatch[index] = unels;
if (hasText) {
styleTextSelection(cd);
}
return selection;
};
/***/ }),
/***/ 91940:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var makeFillcolorAttr = __webpack_require__(94352);
var scatterGeoAttrs = __webpack_require__(88804);
var scatterAttrs = __webpack_require__(49992);
var mapboxAttrs = __webpack_require__(24576);
var baseAttrs = __webpack_require__(6040);
var colorScaleAttrs = __webpack_require__(99732);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
var mapboxLayoutAtributes = __webpack_require__(24576);
var lineAttrs = scatterGeoAttrs.line;
var markerAttrs = scatterGeoAttrs.marker;
module.exports = overrideAll({
lon: scatterGeoAttrs.lon,
lat: scatterGeoAttrs.lat,
cluster: {
enabled: {
valType: 'boolean',
description: 'Determines whether clustering is enabled or disabled.'
},
maxzoom: extendFlat({}, mapboxLayoutAtributes.layers.maxzoom, {
description: ['Sets the maximum zoom level.', 'At zoom levels equal to or greater than this, points will never be clustered.'].join(' ')
}),
step: {
valType: 'number',
arrayOk: true,
dflt: -1,
min: -1,
description: ['Sets how many points it takes to create a cluster or advance to the next cluster step.', 'Use this in conjunction with arrays for `size` and / or `color`.', 'If an integer, steps start at multiples of this number.', 'If an array, each step extends from the given value until one less than the next value.'].join(' ')
},
size: {
valType: 'number',
arrayOk: true,
dflt: 20,
min: 0,
description: ['Sets the size for each cluster step.'].join(' ')
},
color: {
valType: 'color',
arrayOk: true,
description: ['Sets the color for each cluster step.'].join(' ')
},
opacity: extendFlat({}, markerAttrs.opacity, {
dflt: 1
})
},
// locations
// locationmode
mode: extendFlat({}, scatterAttrs.mode, {
dflt: 'markers',
description: ['Determines the drawing mode for this scatter trace.', 'If the provided `mode` includes *text* then the `text` elements', 'appear at the coordinates. Otherwise, the `text` elements', 'appear on hover.'].join(' ')
}),
text: extendFlat({}, scatterAttrs.text, {
description: ['Sets text elements associated with each (lon,lat) pair', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (lon,lat) coordinates.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
}),
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['lat', 'lon', 'text']
}),
hovertext: extendFlat({}, scatterAttrs.hovertext, {
description: ['Sets hover text elements associated with each (lon,lat) pair', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (lon,lat) coordinates.', 'To be seen, trace `hoverinfo` must contain a *text* flag.'].join(' ')
}),
line: {
color: lineAttrs.color,
width: lineAttrs.width
// TODO
// dash: dash
},
connectgaps: scatterAttrs.connectgaps,
marker: extendFlat({
symbol: {
valType: 'string',
dflt: 'circle',
arrayOk: true,
description: ['Sets the marker symbol.', 'Full list: https://www.mapbox.com/maki-icons/', 'Note that the array `marker.color` and `marker.size`', 'are only available for *circle* symbols.'].join(' ')
},
angle: {
valType: 'number',
dflt: 'auto',
arrayOk: true,
description: ['Sets the marker orientation from true North, in degrees clockwise.', 'When using the *auto* default, no rotation would be applied', 'in perspective views which is different from using a zero angle.'].join(' ')
},
allowoverlap: {
valType: 'boolean',
dflt: false,
description: ['Flag to draw all symbols, even if they overlap.'].join(' ')
},
opacity: markerAttrs.opacity,
size: markerAttrs.size,
sizeref: markerAttrs.sizeref,
sizemin: markerAttrs.sizemin,
sizemode: markerAttrs.sizemode
}, colorScaleAttrs('marker')
// line
),
fill: scatterGeoAttrs.fill,
fillcolor: makeFillcolorAttr(),
textfont: mapboxAttrs.layers.symbol.textfont,
textposition: mapboxAttrs.layers.symbol.textposition,
below: {
valType: 'string',
description: ['Determines if this scattermapbox trace\'s layers are to be inserted', 'before the layer with the specified ID.', 'By default, scattermapbox layers are inserted', 'above all the base layers.', 'To place the scattermapbox layers above every other layer, set `below` to *\'\'*.'].join(' ')
},
selected: {
marker: scatterAttrs.selected.marker
},
unselected: {
marker: scatterAttrs.unselected.marker
},
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['lon', 'lat', 'text', 'name']
}),
hovertemplate: hovertemplateAttrs()
}, 'calc', 'nested');
/***/ }),
/***/ 8136:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var BADNUM = (__webpack_require__(41752).BADNUM);
var geoJsonUtils = __webpack_require__(23308);
var Colorscale = __webpack_require__(26733);
var Drawing = __webpack_require__(49348);
var makeBubbleSizeFn = __webpack_require__(84036);
var subTypes = __webpack_require__(76640);
var convertTextOpts = __webpack_require__(31144);
var appendArrayPointValue = (__webpack_require__(12228).appendArrayPointValue);
var NEWLINES = (__webpack_require__(41536).NEWLINES);
var BR_TAG_ALL = (__webpack_require__(41536).BR_TAG_ALL);
module.exports = function convert(gd, calcTrace) {
var trace = calcTrace[0].trace;
var isVisible = trace.visible === true && trace._length !== 0;
var hasFill = trace.fill !== 'none';
var hasLines = subTypes.hasLines(trace);
var hasMarkers = subTypes.hasMarkers(trace);
var hasText = subTypes.hasText(trace);
var hasCircles = hasMarkers && trace.marker.symbol === 'circle';
var hasSymbols = hasMarkers && trace.marker.symbol !== 'circle';
var hasCluster = trace.cluster && trace.cluster.enabled;
var fill = initContainer('fill');
var line = initContainer('line');
var circle = initContainer('circle');
var symbol = initContainer('symbol');
var opts = {
fill: fill,
line: line,
circle: circle,
symbol: symbol
};
// early return if not visible or placeholder
if (!isVisible) return opts;
// fill layer and line layer use the same coords
var lineCoords;
if (hasFill || hasLines) {
lineCoords = geoJsonUtils.calcTraceToLineCoords(calcTrace);
}
if (hasFill) {
fill.geojson = geoJsonUtils.makePolygon(lineCoords);
fill.layout.visibility = 'visible';
Lib.extendFlat(fill.paint, {
'fill-color': trace.fillcolor
});
}
if (hasLines) {
line.geojson = geoJsonUtils.makeLine(lineCoords);
line.layout.visibility = 'visible';
Lib.extendFlat(line.paint, {
'line-width': trace.line.width,
'line-color': trace.line.color,
'line-opacity': trace.opacity
});
// TODO convert line.dash into line-dasharray
}
if (hasCircles) {
var circleOpts = makeCircleOpts(calcTrace);
circle.geojson = circleOpts.geojson;
circle.layout.visibility = 'visible';
if (hasCluster) {
circle.filter = ['!', ['has', 'point_count']];
opts.cluster = {
type: 'circle',
filter: ['has', 'point_count'],
layout: {
visibility: 'visible'
},
paint: {
'circle-color': arrayifyAttribute(trace.cluster.color, trace.cluster.step),
'circle-radius': arrayifyAttribute(trace.cluster.size, trace.cluster.step),
'circle-opacity': arrayifyAttribute(trace.cluster.opacity, trace.cluster.step)
}
};
opts.clusterCount = {
type: 'symbol',
filter: ['has', 'point_count'],
paint: {},
layout: {
'text-field': '{point_count_abbreviated}',
'text-font': ['Open Sans Regular', 'Arial Unicode MS Regular'],
'text-size': 12
}
};
}
Lib.extendFlat(circle.paint, {
'circle-color': circleOpts.mcc,
'circle-radius': circleOpts.mrc,
'circle-opacity': circleOpts.mo
});
}
if (hasCircles && hasCluster) {
circle.filter = ['!', ['has', 'point_count']];
}
if (hasSymbols || hasText) {
symbol.geojson = makeSymbolGeoJSON(calcTrace, gd);
Lib.extendFlat(symbol.layout, {
visibility: 'visible',
'icon-image': '{symbol}-15',
'text-field': '{text}'
});
if (hasSymbols) {
Lib.extendFlat(symbol.layout, {
'icon-size': trace.marker.size / 10
});
if ('angle' in trace.marker && trace.marker.angle !== 'auto') {
Lib.extendFlat(symbol.layout, {
// unfortunately cant use {angle} do to this issue:
// https://github.com/mapbox/mapbox-gl-js/issues/873
'icon-rotate': {
type: 'identity',
property: 'angle'
},
'icon-rotation-alignment': 'map'
});
}
symbol.layout['icon-allow-overlap'] = trace.marker.allowoverlap;
Lib.extendFlat(symbol.paint, {
'icon-opacity': trace.opacity * trace.marker.opacity,
// TODO does not work ??
'icon-color': trace.marker.color
});
}
if (hasText) {
var iconSize = (trace.marker || {}).size;
var textOpts = convertTextOpts(trace.textposition, iconSize);
// all data-driven below !!
Lib.extendFlat(symbol.layout, {
'text-size': trace.textfont.size,
'text-anchor': textOpts.anchor,
'text-offset': textOpts.offset,
'text-font': trace.textfont.family.split(', ')
});
Lib.extendFlat(symbol.paint, {
'text-color': trace.textfont.color,
'text-opacity': trace.opacity
});
}
}
return opts;
};
function initContainer(type) {
return {
type: type,
geojson: geoJsonUtils.makeBlank(),
layout: {
visibility: 'none'
},
filter: null,
paint: {}
};
}
function makeCircleOpts(calcTrace) {
var trace = calcTrace[0].trace;
var marker = trace.marker;
var selectedpoints = trace.selectedpoints;
var arrayColor = Lib.isArrayOrTypedArray(marker.color);
var arraySize = Lib.isArrayOrTypedArray(marker.size);
var arrayOpacity = Lib.isArrayOrTypedArray(marker.opacity);
var i;
function addTraceOpacity(o) {
return trace.opacity * o;
}
function size2radius(s) {
return s / 2;
}
var colorFn;
if (arrayColor) {
if (Colorscale.hasColorscale(trace, 'marker')) {
colorFn = Colorscale.makeColorScaleFuncFromTrace(marker);
} else {
colorFn = Lib.identity;
}
}
var sizeFn;
if (arraySize) {
sizeFn = makeBubbleSizeFn(trace);
}
var opacityFn;
if (arrayOpacity) {
opacityFn = function (mo) {
var mo2 = isNumeric(mo) ? +Lib.constrain(mo, 0, 1) : 0;
return addTraceOpacity(mo2);
};
}
var features = [];
for (i = 0; i < calcTrace.length; i++) {
var calcPt = calcTrace[i];
var lonlat = calcPt.lonlat;
if (isBADNUM(lonlat)) continue;
var props = {};
if (colorFn) props.mcc = calcPt.mcc = colorFn(calcPt.mc);
if (sizeFn) props.mrc = calcPt.mrc = sizeFn(calcPt.ms);
if (opacityFn) props.mo = opacityFn(calcPt.mo);
if (selectedpoints) props.selected = calcPt.selected || 0;
features.push({
type: 'Feature',
id: i + 1,
geometry: {
type: 'Point',
coordinates: lonlat
},
properties: props
});
}
var fns;
if (selectedpoints) {
fns = Drawing.makeSelectedPointStyleFns(trace);
for (i = 0; i < features.length; i++) {
var d = features[i].properties;
if (fns.selectedOpacityFn) {
d.mo = addTraceOpacity(fns.selectedOpacityFn(d));
}
if (fns.selectedColorFn) {
d.mcc = fns.selectedColorFn(d);
}
if (fns.selectedSizeFn) {
d.mrc = fns.selectedSizeFn(d);
}
}
}
return {
geojson: {
type: 'FeatureCollection',
features: features
},
mcc: arrayColor || fns && fns.selectedColorFn ? {
type: 'identity',
property: 'mcc'
} : marker.color,
mrc: arraySize || fns && fns.selectedSizeFn ? {
type: 'identity',
property: 'mrc'
} : size2radius(marker.size),
mo: arrayOpacity || fns && fns.selectedOpacityFn ? {
type: 'identity',
property: 'mo'
} : addTraceOpacity(marker.opacity)
};
}
function makeSymbolGeoJSON(calcTrace, gd) {
var fullLayout = gd._fullLayout;
var trace = calcTrace[0].trace;
var marker = trace.marker || {};
var symbol = marker.symbol;
var angle = marker.angle;
var fillSymbol = symbol !== 'circle' ? getFillFunc(symbol) : blankFillFunc;
var fillAngle = angle !== 'auto' ? getFillFunc(angle, true) : blankFillFunc;
var fillText = subTypes.hasText(trace) ? getFillFunc(trace.text) : blankFillFunc;
var features = [];
for (var i = 0; i < calcTrace.length; i++) {
var calcPt = calcTrace[i];
if (isBADNUM(calcPt.lonlat)) continue;
var texttemplate = trace.texttemplate;
var text;
if (texttemplate) {
var tt = Array.isArray(texttemplate) ? texttemplate[i] || '' : texttemplate;
var labels = trace._module.formatLabels(calcPt, trace, fullLayout);
var pointValues = {};
appendArrayPointValue(pointValues, trace, calcPt.i);
var meta = trace._meta || {};
text = Lib.texttemplateString(tt, labels, fullLayout._d3locale, pointValues, calcPt, meta);
} else {
text = fillText(i);
}
if (text) {
text = text.replace(NEWLINES, '').replace(BR_TAG_ALL, '\n');
}
features.push({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: calcPt.lonlat
},
properties: {
symbol: fillSymbol(i),
angle: fillAngle(i),
text: text
}
});
}
return {
type: 'FeatureCollection',
features: features
};
}
function getFillFunc(attr, numeric) {
if (Lib.isArrayOrTypedArray(attr)) {
if (numeric) {
return function (i) {
return isNumeric(attr[i]) ? +attr[i] : 0;
};
}
return function (i) {
return attr[i];
};
} else if (attr) {
return function () {
return attr;
};
} else {
return blankFillFunc;
}
}
function blankFillFunc() {
return '';
}
// only need to check lon (OR lat)
function isBADNUM(lonlat) {
return lonlat[0] === BADNUM;
}
function arrayifyAttribute(values, step) {
var newAttribute;
if (Lib.isArrayOrTypedArray(values) && Lib.isArrayOrTypedArray(step)) {
newAttribute = ['step', ['get', 'point_count'], values[0]];
for (var idx = 1; idx < values.length; idx++) {
newAttribute.push(step[idx - 1], values[idx]);
}
} else {
newAttribute = values;
}
return newAttribute;
}
/***/ }),
/***/ 79240:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var subTypes = __webpack_require__(76640);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleTextDefaults = __webpack_require__(52960);
var handleFillColorDefaults = __webpack_require__(73168);
var attributes = __webpack_require__(91940);
// Must use one of the following fonts as the family, else default to 'Open Sans Regular'
// See https://github.com/openmaptiles/fonts/blob/gh-pages/fontstacks.json
var supportedFonts = ['Metropolis Black Italic', 'Metropolis Black', 'Metropolis Bold Italic', 'Metropolis Bold', 'Metropolis Extra Bold Italic', 'Metropolis Extra Bold', 'Metropolis Extra Light Italic', 'Metropolis Extra Light', 'Metropolis Light Italic', 'Metropolis Light', 'Metropolis Medium Italic', 'Metropolis Medium', 'Metropolis Regular Italic', 'Metropolis Regular', 'Metropolis Semi Bold Italic', 'Metropolis Semi Bold', 'Metropolis Thin Italic', 'Metropolis Thin', 'Open Sans Bold Italic', 'Open Sans Bold', 'Open Sans Extra Bold Italic', 'Open Sans Extra Bold', 'Open Sans Italic', 'Open Sans Light Italic', 'Open Sans Light', 'Open Sans Regular', 'Open Sans Semibold Italic', 'Open Sans Semibold', 'Klokantech Noto Sans Bold', 'Klokantech Noto Sans CJK Bold', 'Klokantech Noto Sans CJK Regular', 'Klokantech Noto Sans Italic', 'Klokantech Noto Sans Regular'];
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
function coerce2(attr, dflt) {
return Lib.coerce2(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleLonLatDefaults(traceIn, traceOut, coerce);
if (!len) {
traceOut.visible = false;
return;
}
coerce('text');
coerce('texttemplate');
coerce('hovertext');
coerce('hovertemplate');
coerce('mode');
coerce('below');
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
noLine: true,
noAngle: true
});
coerce('marker.allowoverlap');
coerce('marker.angle');
// array marker.size and marker.color are only supported with circles
var marker = traceOut.marker;
if (marker.symbol !== 'circle') {
if (Lib.isArrayOrTypedArray(marker.size)) marker.size = marker.size[0];
if (Lib.isArrayOrTypedArray(marker.color)) marker.color = marker.color[0];
}
}
if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
noDash: true
});
coerce('connectgaps');
}
var clusterMaxzoom = coerce2('cluster.maxzoom');
var clusterStep = coerce2('cluster.step');
var clusterColor = coerce2('cluster.color', traceOut.marker && traceOut.marker.color || defaultColor);
var clusterSize = coerce2('cluster.size');
var clusterOpacity = coerce2('cluster.opacity');
var clusterEnabledDflt = clusterMaxzoom !== false || clusterStep !== false || clusterColor !== false || clusterSize !== false || clusterOpacity !== false;
coerce('cluster.enabled', clusterEnabledDflt);
if (subTypes.hasText(traceOut)) {
handleTextDefaults(traceIn, traceOut, layout, coerce, {
noSelect: true,
font: {
family: supportedFonts.indexOf(layout.font.family) !== -1 ? layout.font.family : 'Open Sans Regular',
size: layout.font.size,
color: layout.font.color
}
});
}
coerce('fill');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
}
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
function handleLonLatDefaults(traceIn, traceOut, coerce) {
var lon = coerce('lon') || [];
var lat = coerce('lat') || [];
var len = Math.min(lon.length, lat.length);
traceOut._length = len;
return len;
}
/***/ }),
/***/ 6476:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt) {
out.lon = pt.lon;
out.lat = pt.lat;
return out;
};
/***/ }),
/***/ 43300:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
module.exports = function formatLabels(cdi, trace, fullLayout) {
var labels = {};
var subplot = fullLayout[trace.subplot]._subplot;
var ax = subplot.mockAxis;
var lonlat = cdi.lonlat;
labels.lonLabel = Axes.tickText(ax, ax.c2l(lonlat[0]), true).text;
labels.latLabel = Axes.tickText(ax, ax.c2l(lonlat[1]), true).text;
return labels;
};
/***/ }),
/***/ 55348:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Fx = __webpack_require__(39184);
var Lib = __webpack_require__(10923);
var getTraceColor = __webpack_require__(85600);
var fillText = Lib.fillText;
var BADNUM = (__webpack_require__(41752).BADNUM);
var LAYER_PREFIX = (__webpack_require__(11376).traceLayerPrefix);
function hoverPoints(pointData, xval, yval) {
var cd = pointData.cd;
var trace = cd[0].trace;
var xa = pointData.xa;
var ya = pointData.ya;
var subplot = pointData.subplot;
var clusteredPointsIds = [];
var layer = LAYER_PREFIX + trace.uid + '-circle';
var hasCluster = trace.cluster && trace.cluster.enabled;
if (hasCluster) {
var elems = subplot.map.queryRenderedFeatures(null, {
layers: [layer]
});
clusteredPointsIds = elems.map(function (elem) {
return elem.id;
});
}
// compute winding number about [-180, 180] globe
var winding = xval >= 0 ? Math.floor((xval + 180) / 360) : Math.ceil((xval - 180) / 360);
// shift longitude to [-180, 180] to determine closest point
var lonShift = winding * 360;
var xval2 = xval - lonShift;
function distFn(d) {
var lonlat = d.lonlat;
if (lonlat[0] === BADNUM) return Infinity;
if (hasCluster && clusteredPointsIds.indexOf(d.i + 1) === -1) return Infinity;
var lon = Lib.modHalf(lonlat[0], 360);
var lat = lonlat[1];
var pt = subplot.project([lon, lat]);
var dx = pt.x - xa.c2p([xval2, lat]);
var dy = pt.y - ya.c2p([lon, yval]);
var rad = Math.max(3, d.mrc || 0);
return Math.max(Math.sqrt(dx * dx + dy * dy) - rad, 1 - 3 / rad);
}
Fx.getClosest(cd, distFn, pointData);
// skip the rest (for this trace) if we didn't find a close point
if (pointData.index === false) return;
var di = cd[pointData.index];
var lonlat = di.lonlat;
var lonlatShifted = [Lib.modHalf(lonlat[0], 360) + lonShift, lonlat[1]];
// shift labels back to original winded globe
var xc = xa.c2p(lonlatShifted);
var yc = ya.c2p(lonlatShifted);
var rad = di.mrc || 1;
pointData.x0 = xc - rad;
pointData.x1 = xc + rad;
pointData.y0 = yc - rad;
pointData.y1 = yc + rad;
var fullLayout = {};
fullLayout[trace.subplot] = {
_subplot: subplot
};
var labels = trace._module.formatLabels(di, trace, fullLayout);
pointData.lonLabel = labels.lonLabel;
pointData.latLabel = labels.latLabel;
pointData.color = getTraceColor(trace, di);
pointData.extraText = getExtraText(trace, di, cd[0].t.labels);
pointData.hovertemplate = trace.hovertemplate;
return [pointData];
}
function getExtraText(trace, di, labels) {
if (trace.hovertemplate) return;
var hoverinfo = di.hi || trace.hoverinfo;
var parts = hoverinfo.split('+');
var isAll = parts.indexOf('all') !== -1;
var hasLon = parts.indexOf('lon') !== -1;
var hasLat = parts.indexOf('lat') !== -1;
var lonlat = di.lonlat;
var text = [];
// TODO should we use a mock axis to format hover?
// If so, we'll need to make precision be zoom-level dependent
function format(v) {
return v + '\u00B0';
}
if (isAll || hasLon && hasLat) {
text.push('(' + format(lonlat[1]) + ', ' + format(lonlat[0]) + ')');
} else if (hasLon) {
text.push(labels.lon + format(lonlat[0]));
} else if (hasLat) {
text.push(labels.lat + format(lonlat[1]));
}
if (isAll || parts.indexOf('text') !== -1) {
fillText(di, trace, text);
}
return text.join('
');
}
module.exports = {
hoverPoints: hoverPoints,
getExtraText: getExtraText
};
/***/ }),
/***/ 79804:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(91940),
supplyDefaults: __webpack_require__(79240),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(43300),
calc: __webpack_require__(14248),
plot: __webpack_require__(6660),
hoverPoints: (__webpack_require__(55348).hoverPoints),
eventData: __webpack_require__(6476),
selectPoints: __webpack_require__(85304),
styleOnSelect: function (_, cd) {
if (cd) {
var trace = cd[0].trace;
trace._glTrace.update(cd);
}
},
moduleType: 'trace',
name: 'scattermapbox',
basePlotModule: __webpack_require__(90419),
categories: ['mapbox', 'gl', 'symbols', 'showLegend', 'scatter-like'],
meta: {
hrName: 'scatter_mapbox',
description: ['The data visualized as scatter point, lines or marker symbols', 'on a Mapbox GL geographic map', 'is provided by longitude/latitude pairs in `lon` and `lat`.'].join(' ')
}
};
/***/ }),
/***/ 6660:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var convert = __webpack_require__(8136);
var LAYER_PREFIX = (__webpack_require__(11376).traceLayerPrefix);
var ORDER = {
cluster: ['cluster', 'clusterCount', 'circle'],
nonCluster: ['fill', 'line', 'circle', 'symbol']
};
function ScatterMapbox(subplot, uid, clusterEnabled, isHidden) {
this.type = 'scattermapbox';
this.subplot = subplot;
this.uid = uid;
this.clusterEnabled = clusterEnabled;
this.isHidden = isHidden;
this.sourceIds = {
fill: 'source-' + uid + '-fill',
line: 'source-' + uid + '-line',
circle: 'source-' + uid + '-circle',
symbol: 'source-' + uid + '-symbol',
cluster: 'source-' + uid + '-circle',
clusterCount: 'source-' + uid + '-circle'
};
this.layerIds = {
fill: LAYER_PREFIX + uid + '-fill',
line: LAYER_PREFIX + uid + '-line',
circle: LAYER_PREFIX + uid + '-circle',
symbol: LAYER_PREFIX + uid + '-symbol',
cluster: LAYER_PREFIX + uid + '-cluster',
clusterCount: LAYER_PREFIX + uid + '-cluster-count'
};
// We could merge the 'fill' source with the 'line' source and
// the 'circle' source with the 'symbol' source if ever having
// for up-to 4 sources per 'scattermapbox' traces becomes a problem.
// previous 'below' value,
// need this to update it properly
this.below = null;
}
var proto = ScatterMapbox.prototype;
proto.addSource = function (k, opts, cluster) {
var sourceOpts = {
type: 'geojson',
data: opts.geojson
};
if (cluster && cluster.enabled) {
Lib.extendFlat(sourceOpts, {
cluster: true,
clusterMaxZoom: cluster.maxzoom
});
}
var isSourceExists = this.subplot.map.getSource(this.sourceIds[k]);
if (isSourceExists) {
isSourceExists.setData(opts.geojson);
} else {
this.subplot.map.addSource(this.sourceIds[k], sourceOpts);
}
};
proto.setSourceData = function (k, opts) {
this.subplot.map.getSource(this.sourceIds[k]).setData(opts.geojson);
};
proto.addLayer = function (k, opts, below) {
var source = {
type: opts.type,
id: this.layerIds[k],
source: this.sourceIds[k],
layout: opts.layout,
paint: opts.paint
};
if (opts.filter) {
source.filter = opts.filter;
}
var currentLayerId = this.layerIds[k];
var layerExist;
var layers = this.subplot.getMapLayers();
for (var i = 0; i < layers.length; i++) {
if (layers[i].id === currentLayerId) {
layerExist = true;
break;
}
}
if (layerExist) {
this.subplot.setOptions(currentLayerId, 'setLayoutProperty', source.layout);
if (source.layout.visibility === 'visible') {
this.subplot.setOptions(currentLayerId, 'setPaintProperty', source.paint);
}
} else {
this.subplot.addLayer(source, below);
}
};
proto.update = function update(calcTrace) {
var trace = calcTrace[0].trace;
var subplot = this.subplot;
var map = subplot.map;
var optsAll = convert(subplot.gd, calcTrace);
var below = subplot.belowLookup['trace-' + this.uid];
var hasCluster = !!(trace.cluster && trace.cluster.enabled);
var hadCluster = !!this.clusterEnabled;
var lThis = this;
function addCluster(noSource) {
if (!noSource) lThis.addSource('circle', optsAll.circle, trace.cluster);
var order = ORDER.cluster;
for (var i = 0; i < order.length; i++) {
var k = order[i];
var opts = optsAll[k];
lThis.addLayer(k, opts, below);
}
}
function removeCluster(noSource) {
var order = ORDER.cluster;
for (var i = order.length - 1; i >= 0; i--) {
var k = order[i];
map.removeLayer(lThis.layerIds[k]);
}
if (!noSource) map.removeSource(lThis.sourceIds.circle);
}
function addNonCluster(noSource) {
var order = ORDER.nonCluster;
for (var i = 0; i < order.length; i++) {
var k = order[i];
var opts = optsAll[k];
if (!noSource) lThis.addSource(k, opts);
lThis.addLayer(k, opts, below);
}
}
function removeNonCluster(noSource) {
var order = ORDER.nonCluster;
for (var i = order.length - 1; i >= 0; i--) {
var k = order[i];
map.removeLayer(lThis.layerIds[k]);
if (!noSource) map.removeSource(lThis.sourceIds[k]);
}
}
function remove(noSource) {
if (hadCluster) removeCluster(noSource);else removeNonCluster(noSource);
}
function add(noSource) {
if (hasCluster) addCluster(noSource);else addNonCluster(noSource);
}
function repaint() {
var order = hasCluster ? ORDER.cluster : ORDER.nonCluster;
for (var i = 0; i < order.length; i++) {
var k = order[i];
var opts = optsAll[k];
if (!opts) continue;
subplot.setOptions(lThis.layerIds[k], 'setLayoutProperty', opts.layout);
if (opts.layout.visibility === 'visible') {
if (k !== 'cluster') {
lThis.setSourceData(k, opts);
}
subplot.setOptions(lThis.layerIds[k], 'setPaintProperty', opts.paint);
}
}
}
var wasHidden = this.isHidden;
var isHidden = trace.visible !== true;
if (isHidden) {
if (!wasHidden) remove();
} else if (wasHidden) {
if (!isHidden) add();
} else if (hadCluster !== hasCluster) {
remove();
add();
} else if (this.below !== below) {
remove(true);
add(true);
repaint();
} else {
repaint();
}
this.clusterEnabled = hasCluster;
this.isHidden = isHidden;
this.below = below;
// link ref for quick update during selections
calcTrace[0].trace._glTrace = this;
};
proto.dispose = function dispose() {
var map = this.subplot.map;
var order = this.clusterEnabled ? ORDER.cluster : ORDER.nonCluster;
for (var i = order.length - 1; i >= 0; i--) {
var k = order[i];
map.removeLayer(this.layerIds[k]);
map.removeSource(this.sourceIds[k]);
}
};
module.exports = function createScatterMapbox(subplot, calcTrace) {
var trace = calcTrace[0].trace;
var hasCluster = trace.cluster && trace.cluster.enabled;
var isHidden = trace.visible !== true;
var scatterMapbox = new ScatterMapbox(subplot, trace.uid, hasCluster, isHidden);
var optsAll = convert(subplot.gd, calcTrace);
var below = scatterMapbox.below = subplot.belowLookup['trace-' + trace.uid];
var i, k, opts;
if (hasCluster) {
scatterMapbox.addSource('circle', optsAll.circle, trace.cluster);
for (i = 0; i < ORDER.cluster.length; i++) {
k = ORDER.cluster[i];
opts = optsAll[k];
scatterMapbox.addLayer(k, opts, below);
}
} else {
for (i = 0; i < ORDER.nonCluster.length; i++) {
k = ORDER.nonCluster[i];
opts = optsAll[k];
scatterMapbox.addSource(k, opts, trace.cluster);
scatterMapbox.addLayer(k, opts, below);
}
}
// link ref for quick update during selections
calcTrace[0].trace._glTrace = scatterMapbox;
return scatterMapbox;
};
/***/ }),
/***/ 85304:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var subtypes = __webpack_require__(76640);
var BADNUM = (__webpack_require__(41752).BADNUM);
module.exports = function selectPoints(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var selection = [];
var trace = cd[0].trace;
var i;
if (!subtypes.hasMarkers(trace)) return [];
if (selectionTester === false) {
for (i = 0; i < cd.length; i++) {
cd[i].selected = 0;
}
} else {
for (i = 0; i < cd.length; i++) {
var di = cd[i];
var lonlat = di.lonlat;
if (lonlat[0] !== BADNUM) {
var lonlat2 = [Lib.modHalf(lonlat[0], 360), lonlat[1]];
var xy = [xa.c2p(lonlat2), ya.c2p(lonlat2)];
if (selectionTester.contains(xy, null, i, searchInfo)) {
selection.push({
pointNumber: i,
lon: lonlat[0],
lat: lonlat[1]
});
di.selected = 1;
} else {
di.selected = 0;
}
}
}
}
return selection;
};
/***/ }),
/***/ 97736:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var extendFlat = (__webpack_require__(55016).extendFlat);
var makeFillcolorAttr = __webpack_require__(94352);
var scatterAttrs = __webpack_require__(49992);
var baseAttrs = __webpack_require__(6040);
var lineAttrs = scatterAttrs.line;
module.exports = {
mode: scatterAttrs.mode,
r: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: 'Sets the radial coordinates'
},
theta: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: 'Sets the angular coordinates'
},
r0: {
valType: 'any',
dflt: 0,
editType: 'calc+clearAxisTypes',
description: ['Alternate to `r`.', 'Builds a linear space of r coordinates.', 'Use with `dr`', 'where `r0` is the starting coordinate and `dr` the step.'].join(' ')
},
dr: {
valType: 'number',
dflt: 1,
editType: 'calc',
description: 'Sets the r coordinate step.'
},
theta0: {
valType: 'any',
dflt: 0,
editType: 'calc+clearAxisTypes',
description: ['Alternate to `theta`.', 'Builds a linear space of theta coordinates.', 'Use with `dtheta`', 'where `theta0` is the starting coordinate and `dtheta` the step.'].join(' ')
},
dtheta: {
valType: 'number',
editType: 'calc',
description: ['Sets the theta coordinate step.', 'By default, the `dtheta` step equals the subplot\'s period divided', 'by the length of the `r` coordinates.'].join(' ')
},
thetaunit: {
valType: 'enumerated',
values: ['radians', 'degrees', 'gradians'],
dflt: 'degrees',
editType: 'calc+clearAxisTypes',
description: ['Sets the unit of input *theta* values.', 'Has an effect only when on *linear* angular axes.'].join(' ')
},
text: scatterAttrs.text,
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['r', 'theta', 'text']
}),
hovertext: scatterAttrs.hovertext,
line: {
color: lineAttrs.color,
width: lineAttrs.width,
dash: lineAttrs.dash,
backoff: lineAttrs.backoff,
shape: extendFlat({}, lineAttrs.shape, {
values: ['linear', 'spline']
}),
smoothing: lineAttrs.smoothing,
editType: 'calc'
},
connectgaps: scatterAttrs.connectgaps,
marker: scatterAttrs.marker,
cliponaxis: extendFlat({}, scatterAttrs.cliponaxis, {
dflt: false
}),
textposition: scatterAttrs.textposition,
textfont: scatterAttrs.textfont,
fill: extendFlat({}, scatterAttrs.fill, {
values: ['none', 'toself', 'tonext'],
dflt: 'none',
description: ['Sets the area to fill with a solid color.', 'Use with `fillcolor` if not *none*.', 'scatterpolar has a subset of the options available to scatter.', '*toself* connects the endpoints of the trace (or each segment', 'of the trace if it has gaps) into a closed shape.', '*tonext* fills the space between two traces if one completely', 'encloses the other (eg consecutive contour lines), and behaves like', '*toself* if there is no trace before it. *tonext* should not be', 'used if one trace does not enclose the other.'].join(' ')
}),
fillcolor: makeFillcolorAttr(),
// TODO error bars
// https://stackoverflow.com/a/26597487/4068492
// error_x (error_r, error_theta)
// error_y
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['r', 'theta', 'text', 'name']
}),
hoveron: scatterAttrs.hoveron,
hovertemplate: hovertemplateAttrs(),
selected: scatterAttrs.selected,
unselected: scatterAttrs.unselected
};
/***/ }),
/***/ 81072:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var BADNUM = (__webpack_require__(41752).BADNUM);
var Axes = __webpack_require__(81536);
var calcColorscale = __webpack_require__(67536);
var arraysToCalcdata = __webpack_require__(67368);
var calcSelection = __webpack_require__(62496);
var calcMarkerSize = (__webpack_require__(43792).calcMarkerSize);
module.exports = function calc(gd, trace) {
var fullLayout = gd._fullLayout;
var subplotId = trace.subplot;
var radialAxis = fullLayout[subplotId].radialaxis;
var angularAxis = fullLayout[subplotId].angularaxis;
var rArray = radialAxis.makeCalcdata(trace, 'r');
var thetaArray = angularAxis.makeCalcdata(trace, 'theta');
var len = trace._length;
var cd = new Array(len);
for (var i = 0; i < len; i++) {
var r = rArray[i];
var theta = thetaArray[i];
var cdi = cd[i] = {};
if (isNumeric(r) && isNumeric(theta)) {
cdi.r = r;
cdi.theta = theta;
} else {
cdi.r = BADNUM;
}
}
var ppad = calcMarkerSize(trace, len);
trace._extremes.x = Axes.findExtremes(radialAxis, rArray, {
ppad: ppad
});
calcColorscale(gd, trace);
arraysToCalcdata(cd, trace);
calcSelection(cd, trace);
return cd;
};
/***/ }),
/***/ 36392:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var subTypes = __webpack_require__(76640);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleLineShapeDefaults = __webpack_require__(95580);
var handleTextDefaults = __webpack_require__(52960);
var handleFillColorDefaults = __webpack_require__(73168);
var PTS_LINESONLY = (__webpack_require__(5892).PTS_LINESONLY);
var attributes = __webpack_require__(97736);
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleRThetaDefaults(traceIn, traceOut, layout, coerce);
if (!len) {
traceOut.visible = false;
return;
}
coerce('thetaunit');
coerce('mode', len < PTS_LINESONLY ? 'lines+markers' : 'lines');
coerce('text');
coerce('hovertext');
if (traceOut.hoveron !== 'fills') coerce('hovertemplate');
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
gradient: true
});
}
if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
backoff: true
});
handleLineShapeDefaults(traceIn, traceOut, coerce);
coerce('connectgaps');
}
if (subTypes.hasText(traceOut)) {
coerce('texttemplate');
handleTextDefaults(traceIn, traceOut, layout, coerce);
}
var dfltHoverOn = [];
if (subTypes.hasMarkers(traceOut) || subTypes.hasText(traceOut)) {
coerce('cliponaxis');
coerce('marker.maxdisplayed');
dfltHoverOn.push('points');
}
coerce('fill');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
if (!subTypes.hasLines(traceOut)) handleLineShapeDefaults(traceIn, traceOut, coerce);
}
if (traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
dfltHoverOn.push('fills');
}
coerce('hoveron', dfltHoverOn.join('+') || 'points');
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
}
function handleRThetaDefaults(traceIn, traceOut, layout, coerce) {
var r = coerce('r');
var theta = coerce('theta');
// TODO: handle this case outside supply defaults step
if (Lib.isTypedArray(r)) {
traceOut.r = r = Array.from(r);
}
if (Lib.isTypedArray(theta)) {
traceOut.theta = theta = Array.from(theta);
}
var len;
if (r) {
if (theta) {
len = Math.min(r.length, theta.length);
} else {
len = r.length;
coerce('theta0');
coerce('dtheta');
}
} else {
if (!theta) return 0;
len = traceOut.theta.length;
coerce('r0');
coerce('dr');
}
traceOut._length = len;
return len;
}
module.exports = {
handleRThetaDefaults: handleRThetaDefaults,
supplyDefaults: supplyDefaults
};
/***/ }),
/***/ 94944:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Axes = __webpack_require__(81536);
module.exports = function formatLabels(cdi, trace, fullLayout) {
var labels = {};
var subplot = fullLayout[trace.subplot]._subplot;
var radialAxis;
var angularAxis;
// for scatterpolargl texttemplate, _subplot is NOT defined, this takes part during the convert step
// TODO we should consider moving the texttemplate formatting logic to the plot step
if (!subplot) {
subplot = fullLayout[trace.subplot];
radialAxis = subplot.radialaxis;
angularAxis = subplot.angularaxis;
} else {
radialAxis = subplot.radialAxis;
angularAxis = subplot.angularAxis;
}
var rVal = radialAxis.c2l(cdi.r);
labels.rLabel = Axes.tickText(radialAxis, rVal, true).text;
// N.B here the ° sign is part of the formatted value for thetaunit:'degrees'
var thetaVal = angularAxis.thetaunit === 'degrees' ? Lib.rad2deg(cdi.theta) : cdi.theta;
labels.thetaLabel = Axes.tickText(angularAxis, thetaVal, true).text;
return labels;
};
/***/ }),
/***/ 87116:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterHover = __webpack_require__(98064);
function hoverPoints(pointData, xval, yval, hovermode) {
var scatterPointData = scatterHover(pointData, xval, yval, hovermode);
if (!scatterPointData || scatterPointData[0].index === false) return;
var newPointData = scatterPointData[0];
// hovering on fill case
if (newPointData.index === undefined) {
return scatterPointData;
}
var subplot = pointData.subplot;
var cdi = newPointData.cd[newPointData.index];
var trace = newPointData.trace;
if (!subplot.isPtInside(cdi)) return;
newPointData.xLabelVal = undefined;
newPointData.yLabelVal = undefined;
makeHoverPointText(cdi, trace, subplot, newPointData);
newPointData.hovertemplate = trace.hovertemplate;
return scatterPointData;
}
function makeHoverPointText(cdi, trace, subplot, pointData) {
var radialAxis = subplot.radialAxis;
var angularAxis = subplot.angularAxis;
radialAxis._hovertitle = 'r';
angularAxis._hovertitle = 'θ';
var fullLayout = {};
fullLayout[trace.subplot] = {
_subplot: subplot
};
var labels = trace._module.formatLabels(cdi, trace, fullLayout);
pointData.rLabel = labels.rLabel;
pointData.thetaLabel = labels.thetaLabel;
var hoverinfo = cdi.hi || trace.hoverinfo;
var text = [];
function textPart(ax, val) {
text.push(ax._hovertitle + ': ' + val);
}
if (!trace.hovertemplate) {
var parts = hoverinfo.split('+');
if (parts.indexOf('all') !== -1) parts = ['r', 'theta', 'text'];
if (parts.indexOf('r') !== -1) textPart(radialAxis, pointData.rLabel);
if (parts.indexOf('theta') !== -1) textPart(angularAxis, pointData.thetaLabel);
if (parts.indexOf('text') !== -1 && pointData.text) {
text.push(pointData.text);
delete pointData.text;
}
pointData.extraText = text.join('
');
}
}
module.exports = {
hoverPoints: hoverPoints,
makeHoverPointText: makeHoverPointText
};
/***/ }),
/***/ 89920:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'scatterpolar',
basePlotModule: __webpack_require__(18176),
categories: ['polar', 'symbols', 'showLegend', 'scatter-like'],
attributes: __webpack_require__(97736),
supplyDefaults: (__webpack_require__(36392).supplyDefaults),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(94944),
calc: __webpack_require__(81072),
plot: __webpack_require__(85876),
style: (__webpack_require__(53651).style),
styleOnSelect: (__webpack_require__(53651).styleOnSelect),
hoverPoints: (__webpack_require__(87116).hoverPoints),
selectPoints: __webpack_require__(37400),
meta: {
hrName: 'scatter_polar',
description: ['The scatterpolar trace type encompasses line charts, scatter charts, text charts, and bubble charts', 'in polar coordinates.', 'The data visualized as scatter point or lines is set in', '`r` (radial) and `theta` (angular) coordinates', 'Text (appearing either on the chart or on hover only) is via `text`.', 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`', 'to numerical arrays.'].join(' ')
}
};
/***/ }),
/***/ 85876:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterPlot = __webpack_require__(93440);
var BADNUM = (__webpack_require__(41752).BADNUM);
module.exports = function plot(gd, subplot, moduleCalcData) {
var mlayer = subplot.layers.frontplot.select('g.scatterlayer');
var xa = subplot.xaxis;
var ya = subplot.yaxis;
var plotinfo = {
xaxis: xa,
yaxis: ya,
plot: subplot.framework,
layerClipId: subplot._hasClipOnAxisFalse ? subplot.clipIds.forTraces : null
};
var radialAxis = subplot.radialAxis;
var angularAxis = subplot.angularAxis;
// convert:
// 'c' (r,theta) -> 'geometric' (r,theta) -> (x,y)
for (var i = 0; i < moduleCalcData.length; i++) {
var cdi = moduleCalcData[i];
for (var j = 0; j < cdi.length; j++) {
if (j === 0) {
cdi[0].trace._xA = xa;
cdi[0].trace._yA = ya;
}
var cd = cdi[j];
var r = cd.r;
if (r === BADNUM) {
cd.x = cd.y = BADNUM;
} else {
var rg = radialAxis.c2g(r);
var thetag = angularAxis.c2g(cd.theta);
cd.x = rg * Math.cos(thetag);
cd.y = rg * Math.sin(thetag);
}
}
}
scatterPlot(gd, plotinfo, moduleCalcData, mlayer);
};
/***/ }),
/***/ 67236:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterPolarAttrs = __webpack_require__(97736);
var scatterGlAttrs = __webpack_require__(9824);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
module.exports = {
mode: scatterPolarAttrs.mode,
r: scatterPolarAttrs.r,
theta: scatterPolarAttrs.theta,
r0: scatterPolarAttrs.r0,
dr: scatterPolarAttrs.dr,
theta0: scatterPolarAttrs.theta0,
dtheta: scatterPolarAttrs.dtheta,
thetaunit: scatterPolarAttrs.thetaunit,
text: scatterPolarAttrs.text,
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['r', 'theta', 'text']
}),
hovertext: scatterPolarAttrs.hovertext,
hovertemplate: scatterPolarAttrs.hovertemplate,
line: {
color: scatterGlAttrs.line.color,
width: scatterGlAttrs.line.width,
dash: scatterGlAttrs.line.dash,
editType: 'calc'
},
connectgaps: scatterGlAttrs.connectgaps,
marker: scatterGlAttrs.marker,
// no cliponaxis
fill: scatterGlAttrs.fill,
fillcolor: scatterGlAttrs.fillcolor,
textposition: scatterGlAttrs.textposition,
textfont: scatterGlAttrs.textfont,
hoverinfo: scatterPolarAttrs.hoverinfo,
// no hoveron
selected: scatterPolarAttrs.selected,
unselected: scatterPolarAttrs.unselected
};
/***/ }),
/***/ 31288:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'scatterpolargl',
basePlotModule: __webpack_require__(18176),
categories: ['gl', 'regl', 'polar', 'symbols', 'showLegend', 'scatter-like'],
attributes: __webpack_require__(67236),
supplyDefaults: __webpack_require__(17744),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(72600),
calc: __webpack_require__(90596),
hoverPoints: (__webpack_require__(58064).hoverPoints),
selectPoints: __webpack_require__(32432),
meta: {
hrName: 'scatter_polar_gl',
description: ['The scatterpolargl trace type encompasses line charts, scatter charts, and bubble charts', 'in polar coordinates using the WebGL plotting engine.', 'The data visualized as scatter point or lines is set in', '`r` (radial) and `theta` (angular) coordinates', 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`', 'to numerical arrays.'].join(' ')
}
};
/***/ }),
/***/ 90596:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var calcColorscale = __webpack_require__(67536);
var calcMarkerSize = (__webpack_require__(43792).calcMarkerSize);
var convert = __webpack_require__(69447);
var Axes = __webpack_require__(81536);
var TOO_MANY_POINTS = (__webpack_require__(57932).TOO_MANY_POINTS);
module.exports = function calc(gd, trace) {
var fullLayout = gd._fullLayout;
var subplotId = trace.subplot;
var radialAxis = fullLayout[subplotId].radialaxis;
var angularAxis = fullLayout[subplotId].angularaxis;
var rArray = trace._r = radialAxis.makeCalcdata(trace, 'r');
var thetaArray = trace._theta = angularAxis.makeCalcdata(trace, 'theta');
var len = trace._length;
var stash = {};
if (len < rArray.length) rArray = rArray.slice(0, len);
if (len < thetaArray.length) thetaArray = thetaArray.slice(0, len);
stash.r = rArray;
stash.theta = thetaArray;
calcColorscale(gd, trace);
// only compute 'style' options in calc, as position options
// depend on the radial range and must be set in plot
var opts = stash.opts = convert.style(gd, trace);
// For graphs with very large number of points and array marker.size,
// use average marker size instead to speed things up.
var ppad;
if (len < TOO_MANY_POINTS) {
ppad = calcMarkerSize(trace, len);
} else if (opts.marker) {
ppad = 2 * (opts.marker.sizeAvg || Math.max(opts.marker.size, 3));
}
trace._extremes.x = Axes.findExtremes(radialAxis, rArray, {
ppad: ppad
});
return [{
x: false,
y: false,
t: stash,
trace: trace
}];
};
/***/ }),
/***/ 17744:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var subTypes = __webpack_require__(76640);
var handleRThetaDefaults = (__webpack_require__(36392).handleRThetaDefaults);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleTextDefaults = __webpack_require__(52960);
var handleFillColorDefaults = __webpack_require__(73168);
var PTS_LINESONLY = (__webpack_require__(5892).PTS_LINESONLY);
var attributes = __webpack_require__(67236);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleRThetaDefaults(traceIn, traceOut, layout, coerce);
if (!len) {
traceOut.visible = false;
return;
}
coerce('thetaunit');
coerce('mode', len < PTS_LINESONLY ? 'lines+markers' : 'lines');
coerce('text');
coerce('hovertext');
if (traceOut.hoveron !== 'fills') coerce('hovertemplate');
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
noAngleRef: true,
noStandOff: true
});
}
if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
coerce('connectgaps');
}
if (subTypes.hasText(traceOut)) {
coerce('texttemplate');
handleTextDefaults(traceIn, traceOut, layout, coerce);
}
coerce('fill');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
}
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 72600:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterPolarFormatLabels = __webpack_require__(94944);
module.exports = function formatLabels(cdi, trace, fullLayout) {
var i = cdi.i;
if (!('r' in cdi)) cdi.r = trace._r[i];
if (!('theta' in cdi)) cdi.theta = trace._theta[i];
return scatterPolarFormatLabels(cdi, trace, fullLayout);
};
/***/ }),
/***/ 58064:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hover = __webpack_require__(62236);
var makeHoverPointText = (__webpack_require__(87116).makeHoverPointText);
function hoverPoints(pointData, xval, yval, hovermode) {
var cd = pointData.cd;
var stash = cd[0].t;
var rArray = stash.r;
var thetaArray = stash.theta;
var scatterPointData = hover.hoverPoints(pointData, xval, yval, hovermode);
if (!scatterPointData || scatterPointData[0].index === false) return;
var newPointData = scatterPointData[0];
if (newPointData.index === undefined) {
return scatterPointData;
}
var subplot = pointData.subplot;
var cdi = newPointData.cd[newPointData.index];
var trace = newPointData.trace;
// augment pointData with r/theta param
cdi.r = rArray[newPointData.index];
cdi.theta = thetaArray[newPointData.index];
if (!subplot.isPtInside(cdi)) return;
newPointData.xLabelVal = undefined;
newPointData.yLabelVal = undefined;
makeHoverPointText(cdi, trace, subplot, newPointData);
return scatterPointData;
}
module.exports = {
hoverPoints: hoverPoints
};
/***/ }),
/***/ 61972:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var index = __webpack_require__(31288);
index.plot = __webpack_require__(31256);
module.exports = index;
/***/ }),
/***/ 31256:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var cluster = __webpack_require__(16516);
var isNumeric = __webpack_require__(88120);
var scatterglPlot = __webpack_require__(45496);
var sceneUpdate = __webpack_require__(83632);
var convert = __webpack_require__(69447);
var Lib = __webpack_require__(10923);
var TOO_MANY_POINTS = (__webpack_require__(57932).TOO_MANY_POINTS);
var reglPrecompiled = {};
module.exports = function plot(gd, subplot, cdata) {
if (!cdata.length) return;
var radialAxis = subplot.radialAxis;
var angularAxis = subplot.angularAxis;
var scene = sceneUpdate(gd, subplot);
cdata.forEach(function (cdscatter) {
if (!cdscatter || !cdscatter[0] || !cdscatter[0].trace) return;
var cd = cdscatter[0];
var trace = cd.trace;
var stash = cd.t;
var len = trace._length;
var rArray = stash.r;
var thetaArray = stash.theta;
var opts = stash.opts;
var i;
var subRArray = rArray.slice();
var subThetaArray = thetaArray.slice();
// filter out by range
for (i = 0; i < rArray.length; i++) {
if (!subplot.isPtInside({
r: rArray[i],
theta: thetaArray[i]
})) {
subRArray[i] = NaN;
subThetaArray[i] = NaN;
}
}
var positions = new Array(len * 2);
var x = Array(len);
var y = Array(len);
for (i = 0; i < len; i++) {
var r = subRArray[i];
var xx, yy;
if (isNumeric(r)) {
var rg = radialAxis.c2g(r);
var thetag = angularAxis.c2g(subThetaArray[i], trace.thetaunit);
xx = rg * Math.cos(thetag);
yy = rg * Math.sin(thetag);
} else {
xx = yy = NaN;
}
x[i] = positions[i * 2] = xx;
y[i] = positions[i * 2 + 1] = yy;
}
stash.tree = cluster(positions);
// FIXME: see scattergl.js#109
if (opts.marker && len >= TOO_MANY_POINTS) {
opts.marker.cluster = stash.tree;
}
if (opts.marker) {
opts.markerSel.positions = opts.markerUnsel.positions = opts.marker.positions = positions;
}
if (opts.line && positions.length > 1) {
Lib.extendFlat(opts.line, convert.linePositions(gd, trace, positions));
}
if (opts.text) {
Lib.extendFlat(opts.text, {
positions: positions
}, convert.textPosition(gd, trace, opts.text, opts.marker));
Lib.extendFlat(opts.textSel, {
positions: positions
}, convert.textPosition(gd, trace, opts.text, opts.markerSel));
Lib.extendFlat(opts.textUnsel, {
positions: positions
}, convert.textPosition(gd, trace, opts.text, opts.markerUnsel));
}
if (opts.fill && !scene.fill2d) scene.fill2d = true;
if (opts.marker && !scene.scatter2d) scene.scatter2d = true;
if (opts.line && !scene.line2d) scene.line2d = true;
if (opts.text && !scene.glText) scene.glText = true;
scene.lineOptions.push(opts.line);
scene.fillOptions.push(opts.fill);
scene.markerOptions.push(opts.marker);
scene.markerSelectedOptions.push(opts.markerSel);
scene.markerUnselectedOptions.push(opts.markerUnsel);
scene.textOptions.push(opts.text);
scene.textSelectedOptions.push(opts.textSel);
scene.textUnselectedOptions.push(opts.textUnsel);
scene.selectBatch.push([]);
scene.unselectBatch.push([]);
stash.x = x;
stash.y = y;
stash.rawx = x;
stash.rawy = y;
stash.r = rArray;
stash.theta = thetaArray;
stash.positions = positions;
stash._scene = scene;
stash.index = scene.count;
scene.count++;
});
return scatterglPlot(gd, subplot, cdata);
};
module.exports.reglPrecompiled = reglPrecompiled;
/***/ }),
/***/ 79344:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var extendFlat = (__webpack_require__(55016).extendFlat);
var makeFillcolorAttr = __webpack_require__(94352);
var scatterAttrs = __webpack_require__(49992);
var baseAttrs = __webpack_require__(6040);
var lineAttrs = scatterAttrs.line;
module.exports = {
mode: scatterAttrs.mode,
real: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the real component of the data, in units of normalized impedance', 'such that real=1, imag=0 is the center of the chart.'].join(' ')
},
imag: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: ['Sets the imaginary component of the data, in units of normalized impedance', 'such that real=1, imag=0 is the center of the chart.'].join(' ')
},
text: scatterAttrs.text,
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['real', 'imag', 'text']
}),
hovertext: scatterAttrs.hovertext,
line: {
color: lineAttrs.color,
width: lineAttrs.width,
dash: lineAttrs.dash,
backoff: lineAttrs.backoff,
shape: extendFlat({}, lineAttrs.shape, {
values: ['linear', 'spline']
}),
smoothing: lineAttrs.smoothing,
editType: 'calc'
},
connectgaps: scatterAttrs.connectgaps,
marker: scatterAttrs.marker,
cliponaxis: extendFlat({}, scatterAttrs.cliponaxis, {
dflt: false
}),
textposition: scatterAttrs.textposition,
textfont: scatterAttrs.textfont,
fill: extendFlat({}, scatterAttrs.fill, {
values: ['none', 'toself', 'tonext'],
dflt: 'none',
description: ['Sets the area to fill with a solid color.', 'Use with `fillcolor` if not *none*.', 'scattersmith has a subset of the options available to scatter.', '*toself* connects the endpoints of the trace (or each segment', 'of the trace if it has gaps) into a closed shape.', '*tonext* fills the space between two traces if one completely', 'encloses the other (eg consecutive contour lines), and behaves like', '*toself* if there is no trace before it. *tonext* should not be', 'used if one trace does not enclose the other.'].join(' ')
}),
fillcolor: makeFillcolorAttr(),
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['real', 'imag', 'text', 'name']
}),
hoveron: scatterAttrs.hoveron,
hovertemplate: hovertemplateAttrs(),
selected: scatterAttrs.selected,
unselected: scatterAttrs.unselected
};
/***/ }),
/***/ 77198:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var BADNUM = (__webpack_require__(41752).BADNUM);
var calcColorscale = __webpack_require__(67536);
var arraysToCalcdata = __webpack_require__(67368);
var calcSelection = __webpack_require__(62496);
var calcMarkerSize = (__webpack_require__(43792).calcMarkerSize);
module.exports = function calc(gd, trace) {
var fullLayout = gd._fullLayout;
var subplotId = trace.subplot;
var realAxis = fullLayout[subplotId].realaxis;
var imaginaryAxis = fullLayout[subplotId].imaginaryaxis;
var realArray = realAxis.makeCalcdata(trace, 'real');
var imagArray = imaginaryAxis.makeCalcdata(trace, 'imag');
var len = trace._length;
var cd = new Array(len);
for (var i = 0; i < len; i++) {
var real = realArray[i];
var imag = imagArray[i];
var cdi = cd[i] = {};
if (isNumeric(real) && isNumeric(imag)) {
cdi.real = real;
cdi.imag = imag;
} else {
cdi.real = BADNUM;
}
}
calcMarkerSize(trace, len);
calcColorscale(gd, trace);
arraysToCalcdata(cd, trace);
calcSelection(cd, trace);
return cd;
};
/***/ }),
/***/ 79752:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var subTypes = __webpack_require__(76640);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleLineShapeDefaults = __webpack_require__(95580);
var handleTextDefaults = __webpack_require__(52960);
var handleFillColorDefaults = __webpack_require__(73168);
var PTS_LINESONLY = (__webpack_require__(5892).PTS_LINESONLY);
var attributes = __webpack_require__(79344);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleRealImagDefaults(traceIn, traceOut, layout, coerce);
if (!len) {
traceOut.visible = false;
return;
}
coerce('mode', len < PTS_LINESONLY ? 'lines+markers' : 'lines');
coerce('text');
coerce('hovertext');
if (traceOut.hoveron !== 'fills') coerce('hovertemplate');
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
gradient: true
});
}
if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
backoff: true
});
handleLineShapeDefaults(traceIn, traceOut, coerce);
coerce('connectgaps');
}
if (subTypes.hasText(traceOut)) {
coerce('texttemplate');
handleTextDefaults(traceIn, traceOut, layout, coerce);
}
var dfltHoverOn = [];
if (subTypes.hasMarkers(traceOut) || subTypes.hasText(traceOut)) {
coerce('cliponaxis');
coerce('marker.maxdisplayed');
dfltHoverOn.push('points');
}
coerce('fill');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
if (!subTypes.hasLines(traceOut)) handleLineShapeDefaults(traceIn, traceOut, coerce);
}
if (traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
dfltHoverOn.push('fills');
}
coerce('hoveron', dfltHoverOn.join('+') || 'points');
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
function handleRealImagDefaults(traceIn, traceOut, layout, coerce) {
var real = coerce('real');
var imag = coerce('imag');
var len;
if (real && imag) {
len = Math.min(real.length, imag.length);
}
// TODO: handle this case outside supply defaults step
if (Lib.isTypedArray(real)) {
traceOut.real = real = Array.from(real);
}
if (Lib.isTypedArray(imag)) {
traceOut.imag = imag = Array.from(imag);
}
traceOut._length = len;
return len;
}
/***/ }),
/***/ 8864:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
module.exports = function formatLabels(cdi, trace, fullLayout) {
var labels = {};
var subplot = fullLayout[trace.subplot]._subplot;
labels.realLabel = Axes.tickText(subplot.radialAxis, cdi.real, true).text;
labels.imagLabel = Axes.tickText(subplot.angularAxis, cdi.imag, true).text;
return labels;
};
/***/ }),
/***/ 18840:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterHover = __webpack_require__(98064);
function hoverPoints(pointData, xval, yval, hovermode) {
var scatterPointData = scatterHover(pointData, xval, yval, hovermode);
if (!scatterPointData || scatterPointData[0].index === false) return;
var newPointData = scatterPointData[0];
// hovering on fill case
if (newPointData.index === undefined) {
return scatterPointData;
}
var subplot = pointData.subplot;
var cdi = newPointData.cd[newPointData.index];
var trace = newPointData.trace;
if (!subplot.isPtInside(cdi)) return;
newPointData.xLabelVal = undefined;
newPointData.yLabelVal = undefined;
makeHoverPointText(cdi, trace, subplot, newPointData);
newPointData.hovertemplate = trace.hovertemplate;
return scatterPointData;
}
function makeHoverPointText(cdi, trace, subplot, pointData) {
var realAxis = subplot.radialAxis;
var imaginaryAxis = subplot.angularAxis;
realAxis._hovertitle = 'real';
imaginaryAxis._hovertitle = 'imag';
var fullLayout = {};
fullLayout[trace.subplot] = {
_subplot: subplot
};
var labels = trace._module.formatLabels(cdi, trace, fullLayout);
pointData.realLabel = labels.realLabel;
pointData.imagLabel = labels.imagLabel;
var hoverinfo = cdi.hi || trace.hoverinfo;
var text = [];
function textPart(ax, val) {
text.push(ax._hovertitle + ': ' + val);
}
if (!trace.hovertemplate) {
var parts = hoverinfo.split('+');
if (parts.indexOf('all') !== -1) parts = ['real', 'imag', 'text'];
if (parts.indexOf('real') !== -1) textPart(realAxis, pointData.realLabel);
if (parts.indexOf('imag') !== -1) textPart(imaginaryAxis, pointData.imagLabel);
if (parts.indexOf('text') !== -1 && pointData.text) {
text.push(pointData.text);
delete pointData.text;
}
pointData.extraText = text.join('
');
}
}
module.exports = {
hoverPoints: hoverPoints,
makeHoverPointText: makeHoverPointText
};
/***/ }),
/***/ 7116:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'scattersmith',
basePlotModule: __webpack_require__(27316),
categories: ['smith', 'symbols', 'showLegend', 'scatter-like'],
attributes: __webpack_require__(79344),
supplyDefaults: __webpack_require__(79752),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(8864),
calc: __webpack_require__(77198),
plot: __webpack_require__(83256),
style: (__webpack_require__(53651).style),
styleOnSelect: (__webpack_require__(53651).styleOnSelect),
hoverPoints: (__webpack_require__(18840).hoverPoints),
selectPoints: __webpack_require__(37400),
meta: {
hrName: 'scatter_smith',
description: [
// TODO: improve me!
'The scattersmith trace type encompasses line charts, scatter charts, text charts, and bubble charts', 'in smith coordinates.', 'The data visualized as scatter point or lines is set in', '`real` and `imag` (imaginary) coordinates', 'Text (appearing either on the chart or on hover only) is via `text`.', 'Bubble charts are achieved by setting `marker.size` and/or `marker.color`', 'to numerical arrays.'].join(' ')
}
};
/***/ }),
/***/ 83256:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterPlot = __webpack_require__(93440);
var BADNUM = (__webpack_require__(41752).BADNUM);
var helpers = __webpack_require__(55148);
var smith = helpers.smith;
module.exports = function plot(gd, subplot, moduleCalcData) {
var mlayer = subplot.layers.frontplot.select('g.scatterlayer');
var xa = subplot.xaxis;
var ya = subplot.yaxis;
var plotinfo = {
xaxis: xa,
yaxis: ya,
plot: subplot.framework,
layerClipId: subplot._hasClipOnAxisFalse ? subplot.clipIds.forTraces : null
};
// convert:
// 'c' (real,imag) -> (x,y)
for (var i = 0; i < moduleCalcData.length; i++) {
var cdi = moduleCalcData[i];
for (var j = 0; j < cdi.length; j++) {
if (j === 0) {
cdi[0].trace._xA = xa;
cdi[0].trace._yA = ya;
}
var cd = cdi[j];
var real = cd.real;
if (real === BADNUM) {
cd.x = cd.y = BADNUM;
} else {
var t = smith([real, cd.imag]);
cd.x = t[0];
cd.y = t[1];
}
}
}
scatterPlot(gd, plotinfo, moduleCalcData, mlayer);
};
/***/ }),
/***/ 22075:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var makeFillcolorAttr = __webpack_require__(94352);
var scatterAttrs = __webpack_require__(49992);
var baseAttrs = __webpack_require__(6040);
var colorScaleAttrs = __webpack_require__(99732);
var dash = (__webpack_require__(9392)/* .dash */ .u);
var extendFlat = (__webpack_require__(55016).extendFlat);
var scatterMarkerAttrs = scatterAttrs.marker;
var scatterLineAttrs = scatterAttrs.line;
var scatterMarkerLineAttrs = scatterMarkerAttrs.line;
module.exports = {
a: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the quantity of component `a` in each data point.', 'If `a`, `b`, and `c` are all provided, they need not be', 'normalized, only the relative values matter. If only two', 'arrays are provided they must be normalized to match', '`ternary.sum`.'].join(' ')
},
b: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the quantity of component `a` in each data point.', 'If `a`, `b`, and `c` are all provided, they need not be', 'normalized, only the relative values matter. If only two', 'arrays are provided they must be normalized to match', '`ternary.sum`.'].join(' ')
},
c: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the quantity of component `a` in each data point.', 'If `a`, `b`, and `c` are all provided, they need not be', 'normalized, only the relative values matter. If only two', 'arrays are provided they must be normalized to match', '`ternary.sum`.'].join(' ')
},
sum: {
valType: 'number',
dflt: 0,
min: 0,
editType: 'calc',
description: ['The number each triplet should sum to,', 'if only two of `a`, `b`, and `c` are provided.', 'This overrides `ternary.sum` to normalize this specific', 'trace, but does not affect the values displayed on the axes.', '0 (or missing) means to use ternary.sum'].join(' ')
},
mode: extendFlat({}, scatterAttrs.mode, {
dflt: 'markers'
}),
text: extendFlat({}, scatterAttrs.text, {
description: ['Sets text elements associated with each (a,b,c) point.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of strings, the items are mapped in order to the', 'the data points in (a,b,c).', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
}),
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: ['a', 'b', 'c', 'text']
}),
hovertext: extendFlat({}, scatterAttrs.hovertext, {
description: ['Sets hover text elements associated with each (a,b,c) point.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of strings, the items are mapped in order to the', 'the data points in (a,b,c).', 'To be seen, trace `hoverinfo` must contain a *text* flag.'].join(' ')
}),
line: {
color: scatterLineAttrs.color,
width: scatterLineAttrs.width,
dash: dash,
backoff: scatterLineAttrs.backoff,
shape: extendFlat({}, scatterLineAttrs.shape, {
values: ['linear', 'spline']
}),
smoothing: scatterLineAttrs.smoothing,
editType: 'calc'
},
connectgaps: scatterAttrs.connectgaps,
cliponaxis: scatterAttrs.cliponaxis,
fill: extendFlat({}, scatterAttrs.fill, {
values: ['none', 'toself', 'tonext'],
dflt: 'none',
description: ['Sets the area to fill with a solid color.', 'Use with `fillcolor` if not *none*.', 'scatterternary has a subset of the options available to scatter.', '*toself* connects the endpoints of the trace (or each segment', 'of the trace if it has gaps) into a closed shape.', '*tonext* fills the space between two traces if one completely', 'encloses the other (eg consecutive contour lines), and behaves like', '*toself* if there is no trace before it. *tonext* should not be', 'used if one trace does not enclose the other.'].join(' ')
}),
fillcolor: makeFillcolorAttr(),
marker: extendFlat({
symbol: scatterMarkerAttrs.symbol,
opacity: scatterMarkerAttrs.opacity,
angle: scatterMarkerAttrs.angle,
angleref: scatterMarkerAttrs.angleref,
standoff: scatterMarkerAttrs.standoff,
maxdisplayed: scatterMarkerAttrs.maxdisplayed,
size: scatterMarkerAttrs.size,
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
line: extendFlat({
width: scatterMarkerLineAttrs.width,
editType: 'calc'
}, colorScaleAttrs('marker.line')),
gradient: scatterMarkerAttrs.gradient,
editType: 'calc'
}, colorScaleAttrs('marker')),
textfont: scatterAttrs.textfont,
textposition: scatterAttrs.textposition,
selected: scatterAttrs.selected,
unselected: scatterAttrs.unselected,
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['a', 'b', 'c', 'text', 'name']
}),
hoveron: scatterAttrs.hoveron,
hovertemplate: hovertemplateAttrs()
};
/***/ }),
/***/ 11520:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var isNumeric = __webpack_require__(88120);
var calcColorscale = __webpack_require__(67536);
var arraysToCalcdata = __webpack_require__(67368);
var calcSelection = __webpack_require__(62496);
var calcMarkerSize = (__webpack_require__(43792).calcMarkerSize);
var dataArrays = ['a', 'b', 'c'];
var arraysToFill = {
a: ['b', 'c'],
b: ['a', 'c'],
c: ['a', 'b']
};
module.exports = function calc(gd, trace) {
var ternary = gd._fullLayout[trace.subplot];
var displaySum = ternary.sum;
var normSum = trace.sum || displaySum;
var arrays = {
a: trace.a,
b: trace.b,
c: trace.c
};
var i, j, dataArray, newArray, fillArray1, fillArray2;
// fill in one missing component
for (i = 0; i < dataArrays.length; i++) {
dataArray = dataArrays[i];
if (arrays[dataArray]) continue;
fillArray1 = arrays[arraysToFill[dataArray][0]];
fillArray2 = arrays[arraysToFill[dataArray][1]];
newArray = new Array(fillArray1.length);
for (j = 0; j < fillArray1.length; j++) {
newArray[j] = normSum - fillArray1[j] - fillArray2[j];
}
arrays[dataArray] = newArray;
}
// make the calcdata array
var serieslen = trace._length;
var cd = new Array(serieslen);
var a, b, c, norm, x, y;
for (i = 0; i < serieslen; i++) {
a = arrays.a[i];
b = arrays.b[i];
c = arrays.c[i];
if (isNumeric(a) && isNumeric(b) && isNumeric(c)) {
a = +a;
b = +b;
c = +c;
norm = displaySum / (a + b + c);
if (norm !== 1) {
a *= norm;
b *= norm;
c *= norm;
}
// map a, b, c onto x and y where the full scale of y
// is [0, sum], and x is [-sum, sum]
// TODO: this makes `a` always the top, `b` the bottom left,
// and `c` the bottom right. Do we want options to rearrange
// these?
y = a;
x = c - b;
cd[i] = {
x: x,
y: y,
a: a,
b: b,
c: c
};
} else cd[i] = {
x: false,
y: false
};
}
calcMarkerSize(trace, serieslen);
calcColorscale(gd, trace);
arraysToCalcdata(cd, trace);
calcSelection(cd, trace);
return cd;
};
/***/ }),
/***/ 71092:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var constants = __webpack_require__(5892);
var subTypes = __webpack_require__(76640);
var handleMarkerDefaults = __webpack_require__(1092);
var handleLineDefaults = __webpack_require__(53360);
var handleLineShapeDefaults = __webpack_require__(95580);
var handleTextDefaults = __webpack_require__(52960);
var handleFillColorDefaults = __webpack_require__(73168);
var attributes = __webpack_require__(22075);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var a = coerce('a');
var b = coerce('b');
var c = coerce('c');
var len;
// allow any one array to be missing, len is the minimum length of those
// present. Note that after coerce data_array's are either Arrays (which
// are truthy even if empty) or undefined. As in scatter, an empty array
// is different from undefined, because it can signify that this data is
// not known yet but expected in the future
if (a) {
len = a.length;
if (b) {
len = Math.min(len, b.length);
if (c) len = Math.min(len, c.length);
} else if (c) len = Math.min(len, c.length);else len = 0;
} else if (b && c) {
len = Math.min(b.length, c.length);
}
if (!len) {
traceOut.visible = false;
return;
}
traceOut._length = len;
coerce('sum');
coerce('text');
coerce('hovertext');
if (traceOut.hoveron !== 'fills') coerce('hovertemplate');
var defaultMode = len < constants.PTS_LINESONLY ? 'lines+markers' : 'lines';
coerce('mode', defaultMode);
if (subTypes.hasMarkers(traceOut)) {
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
gradient: true
});
}
if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
backoff: true
});
handleLineShapeDefaults(traceIn, traceOut, coerce);
coerce('connectgaps');
}
if (subTypes.hasText(traceOut)) {
coerce('texttemplate');
handleTextDefaults(traceIn, traceOut, layout, coerce);
}
var dfltHoverOn = [];
if (subTypes.hasMarkers(traceOut) || subTypes.hasText(traceOut)) {
coerce('cliponaxis');
coerce('marker.maxdisplayed');
dfltHoverOn.push('points');
}
coerce('fill');
if (traceOut.fill !== 'none') {
handleFillColorDefaults(traceIn, traceOut, defaultColor, coerce);
if (!subTypes.hasLines(traceOut)) handleLineShapeDefaults(traceIn, traceOut, coerce);
}
if (traceOut.fill === 'tonext' || traceOut.fill === 'toself') {
dfltHoverOn.push('fills');
}
coerce('hoveron', dfltHoverOn.join('+') || 'points');
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
/***/ }),
/***/ 55104:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt, trace, cd, pointNumber) {
if (pt.xa) out.xaxis = pt.xa;
if (pt.ya) out.yaxis = pt.ya;
if (cd[pointNumber]) {
var cdi = cd[pointNumber];
// N.B. These are the normalized coordinates.
out.a = cdi.a;
out.b = cdi.b;
out.c = cdi.c;
} else {
// for fill-hover only
out.a = pt.a;
out.b = pt.b;
out.c = pt.c;
}
return out;
};
/***/ }),
/***/ 49155:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
module.exports = function formatLabels(cdi, trace, fullLayout) {
var labels = {};
var subplot = fullLayout[trace.subplot]._subplot;
labels.aLabel = Axes.tickText(subplot.aaxis, cdi.a, true).text;
labels.bLabel = Axes.tickText(subplot.baxis, cdi.b, true).text;
labels.cLabel = Axes.tickText(subplot.caxis, cdi.c, true).text;
return labels;
};
/***/ }),
/***/ 16616:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterHover = __webpack_require__(98064);
module.exports = function hoverPoints(pointData, xval, yval, hovermode) {
var scatterPointData = scatterHover(pointData, xval, yval, hovermode);
if (!scatterPointData || scatterPointData[0].index === false) return;
var newPointData = scatterPointData[0];
// if hovering on a fill, we don't show any point data so the label is
// unchanged from what scatter gives us - except that it needs to
// be constrained to the trianglular plot area, not just the rectangular
// area defined by the synthetic x and y axes
// TODO: in some cases the vertical middle of the shape is not within
// the triangular viewport at all, so the label can become disconnected
// from the shape entirely. But calculating what portion of the shape
// is actually visible, as constrained by the diagonal axis lines, is not
// so easy and anyway we lost the information we would have needed to do
// this inside scatterHover.
if (newPointData.index === undefined) {
var yFracUp = 1 - newPointData.y0 / pointData.ya._length;
var xLen = pointData.xa._length;
var xMin = xLen * yFracUp / 2;
var xMax = xLen - xMin;
newPointData.x0 = Math.max(Math.min(newPointData.x0, xMax), xMin);
newPointData.x1 = Math.max(Math.min(newPointData.x1, xMax), xMin);
return scatterPointData;
}
var cdi = newPointData.cd[newPointData.index];
var trace = newPointData.trace;
var subplot = newPointData.subplot;
newPointData.a = cdi.a;
newPointData.b = cdi.b;
newPointData.c = cdi.c;
newPointData.xLabelVal = undefined;
newPointData.yLabelVal = undefined;
var fullLayout = {};
fullLayout[trace.subplot] = {
_subplot: subplot
};
var labels = trace._module.formatLabels(cdi, trace, fullLayout);
newPointData.aLabel = labels.aLabel;
newPointData.bLabel = labels.bLabel;
newPointData.cLabel = labels.cLabel;
var hoverinfo = cdi.hi || trace.hoverinfo;
var text = [];
function textPart(ax, val) {
text.push(ax._hovertitle + ': ' + val);
}
if (!trace.hovertemplate) {
var parts = hoverinfo.split('+');
if (parts.indexOf('all') !== -1) parts = ['a', 'b', 'c'];
if (parts.indexOf('a') !== -1) textPart(subplot.aaxis, newPointData.aLabel);
if (parts.indexOf('b') !== -1) textPart(subplot.baxis, newPointData.bLabel);
if (parts.indexOf('c') !== -1) textPart(subplot.caxis, newPointData.cLabel);
}
newPointData.extraText = text.join('
');
newPointData.hovertemplate = trace.hovertemplate;
return scatterPointData;
};
/***/ }),
/***/ 87112:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(22075),
supplyDefaults: __webpack_require__(71092),
colorbar: __webpack_require__(71416),
formatLabels: __webpack_require__(49155),
calc: __webpack_require__(11520),
plot: __webpack_require__(5380),
style: (__webpack_require__(53651).style),
styleOnSelect: (__webpack_require__(53651).styleOnSelect),
hoverPoints: __webpack_require__(16616),
selectPoints: __webpack_require__(37400),
eventData: __webpack_require__(55104),
moduleType: 'trace',
name: 'scatterternary',
basePlotModule: __webpack_require__(35800),
categories: ['ternary', 'symbols', 'showLegend', 'scatter-like'],
meta: {
hrName: 'scatter_ternary',
description: ['Provides similar functionality to the *scatter* type but on a ternary phase diagram.', 'The data is provided by at least two arrays out of `a`, `b`, `c` triplets.'].join(' ')
}
};
/***/ }),
/***/ 5380:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterPlot = __webpack_require__(93440);
module.exports = function plot(gd, ternary, moduleCalcData) {
var plotContainer = ternary.plotContainer;
// remove all nodes inside the scatter layer
plotContainer.select('.scatterlayer').selectAll('*').remove();
// mimic cartesian plotinfo
var xa = ternary.xaxis;
var ya = ternary.yaxis;
var plotinfo = {
xaxis: xa,
yaxis: ya,
plot: plotContainer,
layerClipId: ternary._hasClipOnAxisFalse ? ternary.clipIdRelative : null
};
var scatterLayer = ternary.layers.frontplot.select('g.scatterlayer');
for (var i = 0; i < moduleCalcData.length; i++) {
var cdi = moduleCalcData[i];
if (cdi.length) {
cdi[0].trace._xA = xa;
cdi[0].trace._yA = ya;
}
}
scatterPlot(gd, plotinfo, moduleCalcData, scatterLayer);
};
/***/ }),
/***/ 74584:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var scatterAttrs = __webpack_require__(49992);
var colorScaleAttrs = __webpack_require__(99732);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var scatterGlAttrs = __webpack_require__(9824);
var cartesianIdRegex = (__webpack_require__(48188).idRegex);
var templatedArray = (__webpack_require__(58056).templatedArray);
var extendFlat = (__webpack_require__(55016).extendFlat);
var scatterMarkerAttrs = scatterAttrs.marker;
var scatterMarkerLineAttrs = scatterMarkerAttrs.line;
var markerLineAttrs = extendFlat(colorScaleAttrs('marker.line', {
editTypeOverride: 'calc'
}), {
width: extendFlat({}, scatterMarkerLineAttrs.width, {
editType: 'calc'
}),
editType: 'calc'
});
var markerAttrs = extendFlat(colorScaleAttrs('marker'), {
symbol: scatterMarkerAttrs.symbol,
angle: scatterMarkerAttrs.angle,
size: extendFlat({}, scatterMarkerAttrs.size, {
editType: 'markerSize'
}),
sizeref: scatterMarkerAttrs.sizeref,
sizemin: scatterMarkerAttrs.sizemin,
sizemode: scatterMarkerAttrs.sizemode,
opacity: scatterMarkerAttrs.opacity,
colorbar: scatterMarkerAttrs.colorbar,
line: markerLineAttrs,
editType: 'calc'
});
markerAttrs.color.editType = markerAttrs.cmin.editType = markerAttrs.cmax.editType = 'style';
function makeAxesValObject(axLetter) {
return {
valType: 'info_array',
freeLength: true,
editType: 'calc',
items: {
valType: 'subplotid',
regex: cartesianIdRegex[axLetter],
editType: 'plot'
},
description: ['Sets the list of ' + axLetter + ' axes', 'corresponding to dimensions of this splom trace.', 'By default, a splom will match the first N ' + axLetter + 'axes', 'where N is the number of input dimensions.', 'Note that, in case where `diagonal.visible` is false and `showupperhalf`', 'or `showlowerhalf` is false, this splom trace will generate', 'one less x-axis and one less y-axis.'].join(' ')
};
}
module.exports = {
dimensions: templatedArray('dimension', {
visible: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether or not this dimension is shown on the graph.', 'Note that even visible false dimension contribute to the', 'default grid generate by this splom trace.'].join(' ')
},
label: {
valType: 'string',
editType: 'calc',
description: 'Sets the label corresponding to this splom dimension.'
},
values: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: 'Sets the dimension values to be plotted.'
},
axis: {
type: {
valType: 'enumerated',
values: ['linear', 'log', 'date', 'category'],
editType: 'calc+clearAxisTypes',
description: ['Sets the axis type for this dimension\'s generated', 'x and y axes.', 'Note that the axis `type` values set in layout take', 'precedence over this attribute.'].join(' ')
},
// TODO make 'true' the default in v3?
matches: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['Determines whether or not the x & y axes generated by this', 'dimension match.', 'Equivalent to setting the `matches` axis attribute in the layout', 'with the correct axis id.'].join(' ')
},
editType: 'calc+clearAxisTypes'
},
// TODO should add an attribute to pin down x only vars and y only vars
// like https://seaborn.pydata.org/generated/seaborn.pairplot.html
// x_vars and y_vars
// maybe more axis defaulting option e.g. `showgrid: false`
editType: 'calc+clearAxisTypes'
}),
// mode: {}, (only 'markers' for now)
text: extendFlat({}, scatterGlAttrs.text, {
description: ['Sets text elements associated with each (x,y) pair to appear on hover.', 'If a single string, the same string appears over', 'all the data points.', 'If an array of string, the items are mapped in order to the', 'this trace\'s (x,y) coordinates.'].join(' ')
}),
hovertext: extendFlat({}, scatterGlAttrs.hovertext, {
description: 'Same as `text`.'
}),
hovertemplate: hovertemplateAttrs(),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
marker: markerAttrs,
xaxes: makeAxesValObject('x'),
yaxes: makeAxesValObject('y'),
diagonal: {
visible: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether or not subplots on the diagonal are displayed.'].join(' ')
},
// type: 'scattergl' | 'histogram' | 'box' | 'violin'
// ...
// more options
editType: 'calc'
},
showupperhalf: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether or not subplots on the upper half', 'from the diagonal are displayed.'].join(' ')
},
showlowerhalf: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether or not subplots on the lower half', 'from the diagonal are displayed.'].join(' ')
},
selected: {
marker: scatterGlAttrs.selected.marker,
editType: 'calc'
},
unselected: {
marker: scatterGlAttrs.unselected.marker,
editType: 'calc'
},
opacity: scatterGlAttrs.opacity
};
/***/ }),
/***/ 36384:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Grid = __webpack_require__(22936);
module.exports = {
moduleType: 'trace',
name: 'splom',
categories: ['gl', 'regl', 'cartesian', 'symbols', 'showLegend', 'scatter-like'],
attributes: __webpack_require__(74584),
supplyDefaults: __webpack_require__(72872),
colorbar: __webpack_require__(71416),
calc: __webpack_require__(79200),
plot: __webpack_require__(77432),
hoverPoints: (__webpack_require__(55516).hoverPoints),
selectPoints: __webpack_require__(21696),
editStyle: __webpack_require__(89952),
meta: {
description: ['Splom traces generate scatter plot matrix visualizations.', 'Each splom `dimensions` items correspond to a generated axis.', 'Values for each of those dimensions are set in `dimensions[i].values`.', 'Splom traces support all `scattergl` marker style attributes.', 'Specify `layout.grid` attributes and/or layout x-axis and y-axis attributes', 'for more control over the axis positioning and style. '].join(' ')
}
};
// splom traces use the 'grid' component to generate their axes,
// register it here
Registry.register(Grid);
/***/ }),
/***/ 20796:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createLine = __webpack_require__(54368);
var Registry = __webpack_require__(30364);
var prepareRegl = __webpack_require__(81976);
var getModuleCalcData = (__webpack_require__(49824)/* .getModuleCalcData */ ._M);
var Cartesian = __webpack_require__(34316);
var getFromId = (__webpack_require__(21504).getFromId);
var shouldShowZeroLine = (__webpack_require__(81536).shouldShowZeroLine);
var SPLOM = 'splom';
var reglPrecompiled = {};
function plot(gd) {
var fullLayout = gd._fullLayout;
var _module = Registry.getModule(SPLOM);
var splomCalcData = getModuleCalcData(gd.calcdata, _module)[0];
var success = prepareRegl(gd, ['ANGLE_instanced_arrays', 'OES_element_index_uint'], reglPrecompiled);
if (!success) return;
if (fullLayout._hasOnlyLargeSploms) {
updateGrid(gd);
}
_module.plot(gd, {}, splomCalcData);
}
function drag(gd) {
var cd = gd.calcdata;
var fullLayout = gd._fullLayout;
if (fullLayout._hasOnlyLargeSploms) {
updateGrid(gd);
}
for (var i = 0; i < cd.length; i++) {
var cd0 = cd[i][0];
var trace = cd0.trace;
var scene = fullLayout._splomScenes[trace.uid];
if (trace.type === 'splom' && scene && scene.matrix) {
dragOne(gd, trace, scene);
}
}
}
function dragOne(gd, trace, scene) {
var visibleLength = scene.matrixOptions.data.length;
var visibleDims = trace._visibleDims;
var ranges = scene.viewOpts.ranges = new Array(visibleLength);
for (var k = 0; k < visibleDims.length; k++) {
var i = visibleDims[k];
var rng = ranges[k] = new Array(4);
var xa = getFromId(gd, trace._diag[i][0]);
if (xa) {
rng[0] = xa.r2l(xa.range[0]);
rng[2] = xa.r2l(xa.range[1]);
}
var ya = getFromId(gd, trace._diag[i][1]);
if (ya) {
rng[1] = ya.r2l(ya.range[0]);
rng[3] = ya.r2l(ya.range[1]);
}
}
if (scene.selectBatch.length || scene.unselectBatch.length) {
scene.matrix.update({
ranges: ranges
}, {
ranges: ranges
});
} else {
scene.matrix.update({
ranges: ranges
});
}
}
function updateGrid(gd) {
var fullLayout = gd._fullLayout;
var regl = fullLayout._glcanvas.data()[0].regl;
var splomGrid = fullLayout._splomGrid;
if (!splomGrid) {
splomGrid = fullLayout._splomGrid = createLine(regl);
}
splomGrid.update(makeGridData(gd));
}
function makeGridData(gd) {
var plotGlPixelRatio = gd._context.plotGlPixelRatio;
var fullLayout = gd._fullLayout;
var gs = fullLayout._size;
var fullView = [0, 0, fullLayout.width * plotGlPixelRatio, fullLayout.height * plotGlPixelRatio];
var lookup = {};
var k;
function push(prefix, ax, x0, x1, y0, y1) {
x0 *= plotGlPixelRatio;
x1 *= plotGlPixelRatio;
y0 *= plotGlPixelRatio;
y1 *= plotGlPixelRatio;
var lcolor = ax[prefix + 'color'];
var lwidth = ax[prefix + 'width'];
var key = String(lcolor + lwidth);
if (key in lookup) {
lookup[key].data.push(NaN, NaN, x0, x1, y0, y1);
} else {
lookup[key] = {
data: [x0, x1, y0, y1],
join: 'rect',
thickness: lwidth * plotGlPixelRatio,
color: lcolor,
viewport: fullView,
range: fullView,
overlay: false
};
}
}
for (k in fullLayout._splomSubplots) {
var sp = fullLayout._plots[k];
var xa = sp.xaxis;
var ya = sp.yaxis;
var xVals = xa._gridVals;
var yVals = ya._gridVals;
var xOffset = xa._offset;
var xLength = xa._length;
var yLength = ya._length;
// ya.l2p assumes top-to-bottom coordinate system (a la SVG),
// we need to compute bottom-to-top offsets and slopes:
var yOffset = gs.b + ya.domain[0] * gs.h;
var ym = -ya._m;
var yb = -ym * ya.r2l(ya.range[0], ya.calendar);
var x, y;
if (xa.showgrid) {
for (k = 0; k < xVals.length; k++) {
x = xOffset + xa.l2p(xVals[k].x);
push('grid', xa, x, yOffset, x, yOffset + yLength);
}
}
if (ya.showgrid) {
for (k = 0; k < yVals.length; k++) {
y = yOffset + yb + ym * yVals[k].x;
push('grid', ya, xOffset, y, xOffset + xLength, y);
}
}
if (shouldShowZeroLine(gd, xa, ya)) {
x = xOffset + xa.l2p(0);
push('zeroline', xa, x, yOffset, x, yOffset + yLength);
}
if (shouldShowZeroLine(gd, ya, xa)) {
y = yOffset + yb + 0;
push('zeroline', ya, xOffset, y, xOffset + xLength, y);
}
}
var gridBatches = [];
for (k in lookup) {
gridBatches.push(lookup[k]);
}
return gridBatches;
}
function clean(newFullData, newFullLayout, oldFullData, oldFullLayout) {
var lookup = {};
var i;
if (oldFullLayout._splomScenes) {
for (i = 0; i < newFullData.length; i++) {
var newTrace = newFullData[i];
if (newTrace.type === 'splom') {
lookup[newTrace.uid] = 1;
}
}
for (i = 0; i < oldFullData.length; i++) {
var oldTrace = oldFullData[i];
if (!lookup[oldTrace.uid]) {
var scene = oldFullLayout._splomScenes[oldTrace.uid];
if (scene && scene.destroy) scene.destroy();
// must first set scene to null in order to get garbage collected
oldFullLayout._splomScenes[oldTrace.uid] = null;
delete oldFullLayout._splomScenes[oldTrace.uid];
}
}
}
if (Object.keys(oldFullLayout._splomScenes || {}).length === 0) {
delete oldFullLayout._splomScenes;
}
if (oldFullLayout._splomGrid && !newFullLayout._hasOnlyLargeSploms && oldFullLayout._hasOnlyLargeSploms) {
// must first set scene to null in order to get garbage collected
oldFullLayout._splomGrid.destroy();
oldFullLayout._splomGrid = null;
delete oldFullLayout._splomGrid;
}
Cartesian.clean(newFullData, newFullLayout, oldFullData, oldFullLayout);
}
module.exports = {
name: SPLOM,
attr: Cartesian.attr,
attrRegex: Cartesian.attrRegex,
layoutAttributes: Cartesian.layoutAttributes,
supplyLayoutDefaults: Cartesian.supplyLayoutDefaults,
drawFramework: Cartesian.drawFramework,
plot: plot,
drag: drag,
updateGrid: updateGrid,
clean: clean,
updateFx: Cartesian.updateFx,
toSVG: Cartesian.toSVG,
reglPrecompiled: reglPrecompiled
};
/***/ }),
/***/ 79200:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var AxisIDs = __webpack_require__(21504);
var calcMarkerSize = (__webpack_require__(43792).calcMarkerSize);
var calcAxisExpansion = (__webpack_require__(43792).calcAxisExpansion);
var calcColorscale = __webpack_require__(67536);
var convertMarkerSelection = (__webpack_require__(69447).markerSelection);
var convertMarkerStyle = (__webpack_require__(69447).markerStyle);
var sceneUpdate = __webpack_require__(62348);
var BADNUM = (__webpack_require__(41752).BADNUM);
var TOO_MANY_POINTS = (__webpack_require__(57932).TOO_MANY_POINTS);
module.exports = function calc(gd, trace) {
var dimensions = trace.dimensions;
var commonLength = trace._length;
var opts = {};
// 'c' for calculated, 'l' for linear,
// only differ here for log axes, pass ldata to createMatrix as 'data'
var cdata = opts.cdata = [];
var ldata = opts.data = [];
// keep track of visible dimensions
var visibleDims = trace._visibleDims = [];
var i, k, dim, xa, ya;
function makeCalcdata(ax, dim) {
// call makeCalcdata with fake input
var ccol = ax.makeCalcdata({
v: dim.values,
vcalendar: trace.calendar
}, 'v');
for (var j = 0; j < ccol.length; j++) {
ccol[j] = ccol[j] === BADNUM ? NaN : ccol[j];
}
cdata.push(ccol);
ldata.push(ax.type === 'log' ? Lib.simpleMap(ccol, ax.c2l) : ccol);
}
for (i = 0; i < dimensions.length; i++) {
dim = dimensions[i];
if (dim.visible) {
xa = AxisIDs.getFromId(gd, trace._diag[i][0]);
ya = AxisIDs.getFromId(gd, trace._diag[i][1]);
// if corresponding x & y axes don't have matching types, skip dim
if (xa && ya && xa.type !== ya.type) {
Lib.log('Skipping splom dimension ' + i + ' with conflicting axis types');
continue;
}
if (xa) {
makeCalcdata(xa, dim);
if (ya && ya.type === 'category') {
ya._categories = xa._categories.slice();
}
} else {
// should not make it here, if both xa and ya undefined
makeCalcdata(ya, dim);
}
visibleDims.push(i);
}
}
calcColorscale(gd, trace);
Lib.extendFlat(opts, convertMarkerStyle(gd, trace));
var visibleLength = cdata.length;
var hasTooManyPoints = visibleLength * commonLength > TOO_MANY_POINTS;
// Reuse SVG scatter axis expansion routine.
// For graphs with very large number of points and array marker.size,
// use average marker size instead to speed things up.
var ppad;
if (hasTooManyPoints) {
ppad = opts.sizeAvg || Math.max(opts.size, 3);
} else {
ppad = calcMarkerSize(trace, commonLength);
}
for (k = 0; k < visibleDims.length; k++) {
i = visibleDims[k];
dim = dimensions[i];
xa = AxisIDs.getFromId(gd, trace._diag[i][0]) || {};
ya = AxisIDs.getFromId(gd, trace._diag[i][1]) || {};
calcAxisExpansion(gd, trace, xa, ya, cdata[k], cdata[k], ppad);
}
var scene = sceneUpdate(gd, trace);
if (!scene.matrix) scene.matrix = true;
scene.matrixOptions = opts;
scene.selectedOptions = convertMarkerSelection(gd, trace, trace.selected);
scene.unselectedOptions = convertMarkerSelection(gd, trace, trace.unselected);
return [{
x: false,
y: false,
t: {},
trace: trace
}];
};
/***/ }),
/***/ 72872:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleArrayContainerDefaults = __webpack_require__(95631);
var attributes = __webpack_require__(74584);
var subTypes = __webpack_require__(76640);
var handleMarkerDefaults = __webpack_require__(1092);
var mergeLength = __webpack_require__(97048);
var isOpenSymbol = (__webpack_require__(69968).isOpenSymbol);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var dimensions = handleArrayContainerDefaults(traceIn, traceOut, {
name: 'dimensions',
handleItemDefaults: dimensionDefaults
});
var showDiag = coerce('diagonal.visible');
var showUpper = coerce('showupperhalf');
var showLower = coerce('showlowerhalf');
var dimLength = mergeLength(traceOut, dimensions, 'values');
if (!dimLength || !showDiag && !showUpper && !showLower) {
traceOut.visible = false;
return;
}
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('xhoverformat');
coerce('yhoverformat');
handleMarkerDefaults(traceIn, traceOut, defaultColor, layout, coerce, {
noAngleRef: true,
noStandOff: true
});
var isOpen = isOpenSymbol(traceOut.marker.symbol);
var isBubble = subTypes.isBubble(traceOut);
coerce('marker.line.width', isOpen || isBubble ? 1 : 0);
handleAxisDefaults(traceIn, traceOut, layout, coerce);
Lib.coerceSelectionMarkerOpacity(traceOut, coerce);
};
function dimensionDefaults(dimIn, dimOut) {
function coerce(attr, dflt) {
return Lib.coerce(dimIn, dimOut, attributes.dimensions, attr, dflt);
}
coerce('label');
var values = coerce('values');
if (!(values && values.length)) dimOut.visible = false;else coerce('visible');
coerce('axis.type');
coerce('axis.matches');
}
function handleAxisDefaults(traceIn, traceOut, layout, coerce) {
var dimensions = traceOut.dimensions;
var dimLength = dimensions.length;
var showUpper = traceOut.showupperhalf;
var showLower = traceOut.showlowerhalf;
var showDiag = traceOut.diagonal.visible;
var i, j;
var xAxesDflt = new Array(dimLength);
var yAxesDflt = new Array(dimLength);
for (i = 0; i < dimLength; i++) {
var suffix = i ? i + 1 : '';
xAxesDflt[i] = 'x' + suffix;
yAxesDflt[i] = 'y' + suffix;
}
var xaxes = coerce('xaxes', xAxesDflt);
var yaxes = coerce('yaxes', yAxesDflt);
// build list of [x,y] axis corresponding to each dimensions[i],
// very useful for passing options to regl-splom
var diag = traceOut._diag = new Array(dimLength);
// lookup for 'drawn' x|y axes, to avoid costly indexOf downstream
traceOut._xaxes = {};
traceOut._yaxes = {};
// list of 'drawn' x|y axes, use to generate list of subplots
var xList = [];
var yList = [];
function fillAxisStashes(axId, counterAxId, dim, list) {
if (!axId) return;
var axLetter = axId.charAt(0);
var stash = layout._splomAxes[axLetter];
traceOut['_' + axLetter + 'axes'][axId] = 1;
list.push(axId);
if (!(axId in stash)) {
var s = stash[axId] = {};
if (dim) {
s.label = dim.label || '';
if (dim.visible && dim.axis) {
if (dim.axis.type) s.type = dim.axis.type;
if (dim.axis.matches) s.matches = counterAxId;
}
}
}
}
// cases where showDiag and showLower or showUpper are false
// no special treatment as the 'drawn' x-axes and y-axes no longer match
// the dimensions items and xaxes|yaxes 1-to-1
var mustShiftX = !showDiag && !showLower;
var mustShiftY = !showDiag && !showUpper;
traceOut._axesDim = {};
for (i = 0; i < dimLength; i++) {
var dim = dimensions[i];
var i0 = i === 0;
var iN = i === dimLength - 1;
var xaId = i0 && mustShiftX || iN && mustShiftY ? undefined : xaxes[i];
var yaId = i0 && mustShiftY || iN && mustShiftX ? undefined : yaxes[i];
fillAxisStashes(xaId, yaId, dim, xList);
fillAxisStashes(yaId, xaId, dim, yList);
diag[i] = [xaId, yaId];
traceOut._axesDim[xaId] = i;
traceOut._axesDim[yaId] = i;
}
// fill in splom subplot keys
for (i = 0; i < xList.length; i++) {
for (j = 0; j < yList.length; j++) {
var id = xList[i] + yList[j];
if (i > j && showUpper) {
layout._splomSubplots[id] = 1;
} else if (i < j && showLower) {
layout._splomSubplots[id] = 1;
} else if (i === j && (showDiag || !showLower || !showUpper)) {
// need to include diagonal subplots when
// hiding one half and the diagonal
layout._splomSubplots[id] = 1;
}
}
}
// when lower half is omitted, or when just the diagonal is gone,
// override grid default to make sure axes remain on
// the left/bottom of the plot area
if (!showLower || !showDiag && showUpper && showLower) {
layout._splomGridDflt.xside = 'bottom';
layout._splomGridDflt.yside = 'left';
}
}
/***/ }),
/***/ 89952:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var calcColorscale = __webpack_require__(67536);
var convertMarkerStyle = (__webpack_require__(69447).markerStyle);
module.exports = function editStyle(gd, cd0) {
var trace = cd0.trace;
var scene = gd._fullLayout._splomScenes[trace.uid];
if (scene) {
calcColorscale(gd, trace);
Lib.extendFlat(scene.matrixOptions, convertMarkerStyle(gd, trace));
// TODO [un]selected styles?
var opts = Lib.extendFlat({}, scene.matrixOptions, scene.viewOpts);
// TODO this is too long for arrayOk attributes!
scene.matrix.update(opts, null);
}
};
/***/ }),
/***/ 43860:
/***/ (function(__unused_webpack_module, exports) {
"use strict";
exports.getDimIndex = function getDimIndex(trace, ax) {
var axId = ax._id;
var axLetter = axId.charAt(0);
var ind = {
x: 0,
y: 1
}[axLetter];
var visibleDims = trace._visibleDims;
for (var k = 0; k < visibleDims.length; k++) {
var i = visibleDims[k];
if (trace._diag[i][ind] === axId) return k;
}
return false;
};
/***/ }),
/***/ 55516:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var helpers = __webpack_require__(43860);
var calcHover = (__webpack_require__(62236).calcHover);
var getFromId = (__webpack_require__(81536).getFromId);
var extendFlat = (__webpack_require__(55016).extendFlat);
function hoverPoints(pointData, xval, yval, hovermode, opts) {
if (!opts) opts = {};
var hovermodeHasX = (hovermode || '').charAt(0) === 'x';
var hovermodeHasY = (hovermode || '').charAt(0) === 'y';
var points = _hoverPoints(pointData, xval, yval);
if ((hovermodeHasX || hovermodeHasY) && opts.hoversubplots === 'axis' && points[0]) {
var subplotsWith = (hovermodeHasX ? pointData.xa : pointData.ya)._subplotsWith;
var gd = opts.gd;
var _pointData = extendFlat({}, pointData);
for (var i = 0; i < subplotsWith.length; i++) {
var spId = subplotsWith[i];
if (hovermodeHasY) {
_pointData.xa = getFromId(gd, spId, 'x');
} else {
// hovermodeHasX
_pointData.ya = getFromId(gd, spId, 'y');
}
var axisHoversubplots = hovermodeHasX || hovermodeHasY;
var newPoints = _hoverPoints(_pointData, xval, yval, axisHoversubplots);
points = points.concat(newPoints);
}
}
return points;
}
function _hoverPoints(pointData, xval, yval, axisHoversubplots) {
var cd = pointData.cd;
var trace = cd[0].trace;
var scene = pointData.scene;
var cdata = scene.matrixOptions.cdata;
var xa = pointData.xa;
var ya = pointData.ya;
var xpx = xa.c2p(xval);
var ypx = ya.c2p(yval);
var maxDistance = pointData.distance;
var xi = helpers.getDimIndex(trace, xa);
var yi = helpers.getDimIndex(trace, ya);
if (xi === false || yi === false) return [pointData];
var x = cdata[xi];
var y = cdata[yi];
var id, dxy;
var minDist = maxDistance;
for (var i = 0; i < x.length; i++) {
if (axisHoversubplots && i !== pointData.index) continue;
var ptx = x[i];
var pty = y[i];
var dx = xa.c2p(ptx) - xpx;
var dy = ya.c2p(pty) - ypx;
var dist = Math.sqrt(dx * dx + dy * dy);
if (axisHoversubplots || dist < minDist) {
minDist = dxy = dist;
id = i;
}
}
pointData.index = id;
pointData.distance = minDist;
pointData.dxy = dxy;
if (id === undefined) return [pointData];
return [calcHover(pointData, x, y, trace)];
}
module.exports = {
hoverPoints: hoverPoints
};
/***/ }),
/***/ 56752:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var index = __webpack_require__(36384);
index.basePlotModule = __webpack_require__(20796), module.exports = index;
/***/ }),
/***/ 77432:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createMatrix = __webpack_require__(87208);
var Lib = __webpack_require__(10923);
var AxisIDs = __webpack_require__(21504);
var selectMode = (__webpack_require__(6168).selectMode);
module.exports = function plot(gd, _, splomCalcData) {
if (!splomCalcData.length) return;
for (var i = 0; i < splomCalcData.length; i++) {
plotOne(gd, splomCalcData[i][0]);
}
};
function plotOne(gd, cd0) {
var fullLayout = gd._fullLayout;
var gs = fullLayout._size;
var trace = cd0.trace;
var stash = cd0.t;
var scene = fullLayout._splomScenes[trace.uid];
var matrixOpts = scene.matrixOptions;
var cdata = matrixOpts.cdata;
var regl = fullLayout._glcanvas.data()[0].regl;
var dragmode = fullLayout.dragmode;
var xa, ya;
var i, j, k;
if (cdata.length === 0) return;
// augment options with proper upper/lower halves
// regl-splom's default grid starts from bottom-left
matrixOpts.lower = trace.showupperhalf;
matrixOpts.upper = trace.showlowerhalf;
matrixOpts.diagonal = trace.diagonal.visible;
var visibleDims = trace._visibleDims;
var visibleLength = cdata.length;
var viewOpts = scene.viewOpts = {};
viewOpts.ranges = new Array(visibleLength);
viewOpts.domains = new Array(visibleLength);
for (k = 0; k < visibleDims.length; k++) {
i = visibleDims[k];
var rng = viewOpts.ranges[k] = new Array(4);
var dmn = viewOpts.domains[k] = new Array(4);
xa = AxisIDs.getFromId(gd, trace._diag[i][0]);
if (xa) {
rng[0] = xa._rl[0];
rng[2] = xa._rl[1];
dmn[0] = xa.domain[0];
dmn[2] = xa.domain[1];
}
ya = AxisIDs.getFromId(gd, trace._diag[i][1]);
if (ya) {
rng[1] = ya._rl[0];
rng[3] = ya._rl[1];
dmn[1] = ya.domain[0];
dmn[3] = ya.domain[1];
}
}
var plotGlPixelRatio = gd._context.plotGlPixelRatio;
var l = gs.l * plotGlPixelRatio;
var b = gs.b * plotGlPixelRatio;
var w = gs.w * plotGlPixelRatio;
var h = gs.h * plotGlPixelRatio;
viewOpts.viewport = [l, b, w + l, h + b];
if (scene.matrix === true) {
scene.matrix = createMatrix(regl);
}
var clickSelectEnabled = fullLayout.clickmode.indexOf('select') > -1;
var isSelectMode = selectMode(dragmode) || !!trace.selectedpoints || clickSelectEnabled;
var needsBaseUpdate = true;
if (isSelectMode) {
var commonLength = trace._length;
// regenerate scene batch, if traces number changed during selection
if (trace.selectedpoints) {
scene.selectBatch = trace.selectedpoints;
var selPts = trace.selectedpoints;
var selDict = {};
for (i = 0; i < selPts.length; i++) {
selDict[selPts[i]] = true;
}
var unselPts = [];
for (i = 0; i < commonLength; i++) {
if (!selDict[i]) unselPts.push(i);
}
scene.unselectBatch = unselPts;
}
// precalculate px coords since we are not going to pan during select
var xpx = stash.xpx = new Array(visibleLength);
var ypx = stash.ypx = new Array(visibleLength);
for (k = 0; k < visibleDims.length; k++) {
i = visibleDims[k];
xa = AxisIDs.getFromId(gd, trace._diag[i][0]);
if (xa) {
xpx[k] = new Array(commonLength);
for (j = 0; j < commonLength; j++) {
xpx[k][j] = xa.c2p(cdata[k][j]);
}
}
ya = AxisIDs.getFromId(gd, trace._diag[i][1]);
if (ya) {
ypx[k] = new Array(commonLength);
for (j = 0; j < commonLength; j++) {
ypx[k][j] = ya.c2p(cdata[k][j]);
}
}
}
if (scene.selectBatch.length || scene.unselectBatch.length) {
var unselOpts = Lib.extendFlat({}, matrixOpts, scene.unselectedOptions, viewOpts);
var selOpts = Lib.extendFlat({}, matrixOpts, scene.selectedOptions, viewOpts);
scene.matrix.update(unselOpts, selOpts);
needsBaseUpdate = false;
}
} else {
stash.xpx = stash.ypx = null;
}
if (needsBaseUpdate) {
var opts = Lib.extendFlat({}, matrixOpts, viewOpts);
scene.matrix.update(opts, null);
}
}
/***/ }),
/***/ 62348:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
module.exports = function sceneUpdate(gd, trace) {
var fullLayout = gd._fullLayout;
var uid = trace.uid;
// must place ref to 'scene' in fullLayout, so that:
// - it can be relinked properly on updates
// - it can be destroyed properly when needed
var splomScenes = fullLayout._splomScenes;
if (!splomScenes) splomScenes = fullLayout._splomScenes = {};
var reset = {
dirty: true,
selectBatch: [],
unselectBatch: []
};
var first = {
matrix: false,
selectBatch: [],
unselectBatch: []
};
var scene = splomScenes[trace.uid];
if (!scene) {
scene = splomScenes[uid] = Lib.extendFlat({}, reset, first);
scene.draw = function draw() {
if (scene.matrix && scene.matrix.draw) {
if (scene.selectBatch.length || scene.unselectBatch.length) {
scene.matrix.draw(scene.unselectBatch, scene.selectBatch);
} else {
scene.matrix.draw();
}
}
scene.dirty = false;
};
// remove scene resources
scene.destroy = function destroy() {
if (scene.matrix && scene.matrix.destroy) {
scene.matrix.destroy();
}
scene.matrixOptions = null;
scene.selectBatch = null;
scene.unselectBatch = null;
scene = null;
};
}
// In case if we have scene from the last calc - reset data
if (!scene.dirty) {
Lib.extendFlat(scene, reset);
}
return scene;
};
/***/ }),
/***/ 21696:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var pushUnique = Lib.pushUnique;
var subTypes = __webpack_require__(76640);
var helpers = __webpack_require__(43860);
module.exports = function select(searchInfo, selectionTester) {
var cd = searchInfo.cd;
var trace = cd[0].trace;
var stash = cd[0].t;
var scene = searchInfo.scene;
var cdata = scene.matrixOptions.cdata;
var xa = searchInfo.xaxis;
var ya = searchInfo.yaxis;
var selection = [];
if (!scene) return selection;
var hasOnlyLines = !subTypes.hasMarkers(trace) && !subTypes.hasText(trace);
if (trace.visible !== true || hasOnlyLines) return selection;
var xi = helpers.getDimIndex(trace, xa);
var yi = helpers.getDimIndex(trace, ya);
if (xi === false || yi === false) return selection;
var xpx = stash.xpx[xi];
var ypx = stash.ypx[yi];
var x = cdata[xi];
var y = cdata[yi];
var els = (searchInfo.scene.selectBatch || []).slice();
var unels = [];
// degenerate polygon does not enable selection
// filter out points by visible scatter ones
if (selectionTester !== false && !selectionTester.degenerate) {
for (var i = 0; i < x.length; i++) {
if (selectionTester.contains([xpx[i], ypx[i]], null, i, searchInfo)) {
selection.push({
pointNumber: i,
x: x[i],
y: y[i]
});
pushUnique(els, i);
} else if (els.indexOf(i) !== -1) {
pushUnique(els, i);
} else {
unels.push(i);
}
}
}
var matrixOpts = scene.matrixOptions;
if (!els.length && !unels.length) {
scene.matrix.update(matrixOpts, null);
} else if (!scene.selectBatch.length && !scene.unselectBatch.length) {
scene.matrix.update(scene.unselectedOptions, Lib.extendFlat({}, matrixOpts, scene.selectedOptions, scene.viewOpts));
}
scene.selectBatch = els;
scene.unselectBatch = unels;
return selection;
};
/***/ }),
/***/ 36852:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorScaleAttrs = __webpack_require__(99732);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var mesh3dAttrs = __webpack_require__(13000);
var baseAttrs = __webpack_require__(6040);
var extendFlat = (__webpack_require__(55016).extendFlat);
var attrs = {
x: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: 'Sets the x coordinates of the vector field.'
},
y: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: 'Sets the y coordinates of the vector field.'
},
z: {
valType: 'data_array',
editType: 'calc+clearAxisTypes',
description: 'Sets the z coordinates of the vector field.'
},
u: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the x components of the vector field.'
},
v: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the y components of the vector field.'
},
w: {
valType: 'data_array',
editType: 'calc',
description: 'Sets the z components of the vector field.'
},
starts: {
x: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the x components of the starting position of the streamtubes'].join(' ')
},
y: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the y components of the starting position of the streamtubes'].join(' ')
},
z: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the z components of the starting position of the streamtubes'].join(' ')
},
editType: 'calc'
},
maxdisplayed: {
valType: 'integer',
min: 0,
dflt: 1000,
editType: 'calc',
description: ['The maximum number of displayed segments in a streamtube.'].join(' ')
},
// TODO
//
// Should add 'absolute' (like cone traces have), but currently gl-streamtube3d's
// `absoluteTubeSize` doesn't behave well enough for our needs.
//
// 'fixed' would be a nice addition to plot stream 'lines', see
// https://github.com/plotly/plotly.js/commit/812be20750e21e0a1831975001c248d365850f73#r29129877
//
// sizemode: {
// valType: 'enumerated',
// values: ['scaled', 'absolute', 'fixed'],
// dflt: 'scaled',
// editType: 'calc',
// description: [
// 'Sets the mode by which the streamtubes are sized.'
// ].join(' ')
// },
sizeref: {
valType: 'number',
editType: 'calc',
min: 0,
dflt: 1,
description: ['The scaling factor for the streamtubes.', 'The default is 1, which avoids two max divergence tubes from touching', 'at adjacent starting positions.'].join(' ')
},
text: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['Sets a text element associated with this trace.', 'If trace `hoverinfo` contains a *text* flag,', 'this text element will be seen in all hover labels.', 'Note that streamtube traces do not support array `text` values.'].join(' ')
},
hovertext: {
valType: 'string',
dflt: '',
editType: 'calc',
description: 'Same as `text`.'
},
hovertemplate: hovertemplateAttrs({
editType: 'calc'
}, {
keys: ['tubex', 'tubey', 'tubez', 'tubeu', 'tubev', 'tubew', 'norm', 'divergence']
}),
uhoverformat: axisHoverFormat('u', 1),
vhoverformat: axisHoverFormat('v', 1),
whoverformat: axisHoverFormat('w', 1),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z'),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
};
extendFlat(attrs, colorScaleAttrs('', {
colorAttr: 'u/v/w norm',
showScaleDflt: true,
editTypeOverride: 'calc'
}));
var fromMesh3d = ['opacity', 'lightposition', 'lighting'];
fromMesh3d.forEach(function (k) {
attrs[k] = mesh3dAttrs[k];
});
attrs.hoverinfo = extendFlat({}, baseAttrs.hoverinfo, {
editType: 'calc',
flags: ['x', 'y', 'z', 'u', 'v', 'w', 'norm', 'divergence', 'text', 'name'],
dflt: 'x+y+z+norm+text+name'
});
attrs.transforms = undefined;
module.exports = attrs;
/***/ }),
/***/ 84720:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var colorscaleCalc = __webpack_require__(60416);
function calc(gd, trace) {
trace._len = Math.min(trace.u.length, trace.v.length, trace.w.length, trace.x.length, trace.y.length, trace.z.length);
trace._u = filter(trace.u, trace._len);
trace._v = filter(trace.v, trace._len);
trace._w = filter(trace.w, trace._len);
trace._x = filter(trace.x, trace._len);
trace._y = filter(trace.y, trace._len);
trace._z = filter(trace.z, trace._len);
var grid = processGrid(trace);
trace._gridFill = grid.fill;
trace._Xs = grid.Xs;
trace._Ys = grid.Ys;
trace._Zs = grid.Zs;
trace._len = grid.len;
var slen = 0;
var startx, starty, startz;
if (trace.starts) {
startx = filter(trace.starts.x || []);
starty = filter(trace.starts.y || []);
startz = filter(trace.starts.z || []);
slen = Math.min(startx.length, starty.length, startz.length);
}
trace._startsX = startx || [];
trace._startsY = starty || [];
trace._startsZ = startz || [];
var normMax = 0;
var normMin = Infinity;
var i;
for (i = 0; i < trace._len; i++) {
var u = trace._u[i];
var v = trace._v[i];
var w = trace._w[i];
var norm = Math.sqrt(u * u + v * v + w * w);
normMax = Math.max(normMax, norm);
normMin = Math.min(normMin, norm);
}
colorscaleCalc(gd, trace, {
vals: [normMin, normMax],
containerStr: '',
cLetter: 'c'
});
for (i = 0; i < slen; i++) {
var sx = startx[i];
grid.xMax = Math.max(grid.xMax, sx);
grid.xMin = Math.min(grid.xMin, sx);
var sy = starty[i];
grid.yMax = Math.max(grid.yMax, sy);
grid.yMin = Math.min(grid.yMin, sy);
var sz = startz[i];
grid.zMax = Math.max(grid.zMax, sz);
grid.zMin = Math.min(grid.zMin, sz);
}
trace._slen = slen;
trace._normMax = normMax;
trace._xbnds = [grid.xMin, grid.xMax];
trace._ybnds = [grid.yMin, grid.yMax];
trace._zbnds = [grid.zMin, grid.zMax];
}
function processGrid(trace) {
var x = trace._x;
var y = trace._y;
var z = trace._z;
var len = trace._len;
var i, j, k;
var xMax = -Infinity;
var xMin = Infinity;
var yMax = -Infinity;
var yMin = Infinity;
var zMax = -Infinity;
var zMin = Infinity;
var gridFill = '';
var filledX;
var filledY;
var filledZ;
var firstX, lastX;
var firstY, lastY;
var firstZ, lastZ;
if (len) {
firstX = x[0];
firstY = y[0];
firstZ = z[0];
}
if (len > 1) {
lastX = x[len - 1];
lastY = y[len - 1];
lastZ = z[len - 1];
}
for (i = 0; i < len; i++) {
xMax = Math.max(xMax, x[i]);
xMin = Math.min(xMin, x[i]);
yMax = Math.max(yMax, y[i]);
yMin = Math.min(yMin, y[i]);
zMax = Math.max(zMax, z[i]);
zMin = Math.min(zMin, z[i]);
if (!filledX && x[i] !== firstX) {
filledX = true;
gridFill += 'x';
}
if (!filledY && y[i] !== firstY) {
filledY = true;
gridFill += 'y';
}
if (!filledZ && z[i] !== firstZ) {
filledZ = true;
gridFill += 'z';
}
}
// fill if not filled - case of having dimension(s) with one item
if (!filledX) gridFill += 'x';
if (!filledY) gridFill += 'y';
if (!filledZ) gridFill += 'z';
var Xs = distinctVals(trace._x);
var Ys = distinctVals(trace._y);
var Zs = distinctVals(trace._z);
gridFill = gridFill.replace('x', (firstX > lastX ? '-' : '+') + 'x');
gridFill = gridFill.replace('y', (firstY > lastY ? '-' : '+') + 'y');
gridFill = gridFill.replace('z', (firstZ > lastZ ? '-' : '+') + 'z');
var empty = function () {
len = 0;
Xs = [];
Ys = [];
Zs = [];
};
// Over-specified mesh case, this would error in tube2mesh
if (!len || len < Xs.length * Ys.length * Zs.length) empty();
var getArray = function (c) {
return c === 'x' ? x : c === 'y' ? y : z;
};
var getVals = function (c) {
return c === 'x' ? Xs : c === 'y' ? Ys : Zs;
};
var getDir = function (c) {
return c[len - 1] < c[0] ? -1 : 1;
};
var arrK = getArray(gridFill[1]);
var arrJ = getArray(gridFill[3]);
var arrI = getArray(gridFill[5]);
var nk = getVals(gridFill[1]).length;
var nj = getVals(gridFill[3]).length;
var ni = getVals(gridFill[5]).length;
var arbitrary = false;
var getIndex = function (_i, _j, _k) {
return nk * (nj * _i + _j) + _k;
};
var dirK = getDir(getArray(gridFill[1]));
var dirJ = getDir(getArray(gridFill[3]));
var dirI = getDir(getArray(gridFill[5]));
for (i = 0; i < ni - 1; i++) {
for (j = 0; j < nj - 1; j++) {
for (k = 0; k < nk - 1; k++) {
var q000 = getIndex(i, j, k);
var q001 = getIndex(i, j, k + 1);
var q010 = getIndex(i, j + 1, k);
var q100 = getIndex(i + 1, j, k);
if (!(arrK[q000] * dirK < arrK[q001] * dirK) || !(arrJ[q000] * dirJ < arrJ[q010] * dirJ) || !(arrI[q000] * dirI < arrI[q100] * dirI)) {
arbitrary = true;
}
if (arbitrary) break;
}
if (arbitrary) break;
}
if (arbitrary) break;
}
if (arbitrary) {
Lib.warn('Encountered arbitrary coordinates! Unable to input data grid.');
empty();
}
return {
xMin: xMin,
yMin: yMin,
zMin: zMin,
xMax: xMax,
yMax: yMax,
zMax: zMax,
Xs: Xs,
Ys: Ys,
Zs: Zs,
len: len,
fill: gridFill
};
}
function distinctVals(col) {
return Lib.distinctVals(col).vals;
}
function filter(arr, len) {
if (len === undefined) len = arr.length;
// no need for casting typed arrays to numbers
if (Lib.isTypedArray(arr)) return arr.subarray(0, len);
var values = [];
for (var i = 0; i < len; i++) {
values[i] = +arr[i];
}
return values;
}
module.exports = {
calc: calc,
filter: filter,
processGrid: processGrid
};
/***/ }),
/***/ 36140:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var tube2mesh = (__webpack_require__(14656).gl_streamtube3d);
var createTubeMesh = tube2mesh.createTubeMesh;
var Lib = __webpack_require__(10923);
var parseColorScale = (__webpack_require__(13396).parseColorScale);
var extractOpts = (__webpack_require__(26733).extractOpts);
var zip3 = __webpack_require__(90644);
var axisName2scaleIndex = {
xaxis: 0,
yaxis: 1,
zaxis: 2
};
function Streamtube(scene, uid) {
this.scene = scene;
this.uid = uid;
this.mesh = null;
this.data = null;
}
var proto = Streamtube.prototype;
proto.handlePick = function (selection) {
var sceneLayout = this.scene.fullSceneLayout;
var dataScale = this.scene.dataScale;
function fromDataScale(v, axisName) {
var ax = sceneLayout[axisName];
var scale = dataScale[axisName2scaleIndex[axisName]];
return ax.l2c(v) / scale;
}
if (selection.object === this.mesh) {
var pos = selection.data.position;
var uvx = selection.data.velocity;
selection.traceCoordinate = [fromDataScale(pos[0], 'xaxis'), fromDataScale(pos[1], 'yaxis'), fromDataScale(pos[2], 'zaxis'), fromDataScale(uvx[0], 'xaxis'), fromDataScale(uvx[1], 'yaxis'), fromDataScale(uvx[2], 'zaxis'),
// u/v/w norm
selection.data.intensity * this.data._normMax,
// divergence
selection.data.divergence];
selection.textLabel = this.data.hovertext || this.data.text;
return true;
}
};
function getDfltStartingPositions(vec) {
var len = vec.length;
var s;
if (len > 2) {
s = vec.slice(1, len - 1);
} else if (len === 2) {
s = [(vec[0] + vec[1]) / 2];
} else {
s = vec;
}
return s;
}
function getBoundPads(vec) {
var len = vec.length;
if (len === 1) {
return [0.5, 0.5];
} else {
return [vec[1] - vec[0], vec[len - 1] - vec[len - 2]];
}
}
function convert(scene, trace) {
var sceneLayout = scene.fullSceneLayout;
var dataScale = scene.dataScale;
var len = trace._len;
var tubeOpts = {};
function toDataCoords(arr, axisName) {
var ax = sceneLayout[axisName];
var scale = dataScale[axisName2scaleIndex[axisName]];
return Lib.simpleMap(arr, function (v) {
return ax.d2l(v) * scale;
});
}
tubeOpts.vectors = zip3(toDataCoords(trace._u, 'xaxis'), toDataCoords(trace._v, 'yaxis'), toDataCoords(trace._w, 'zaxis'), len);
// Over-specified mesh case, this would error in tube2mesh
if (!len) {
return {
positions: [],
cells: []
};
}
var meshx = toDataCoords(trace._Xs, 'xaxis');
var meshy = toDataCoords(trace._Ys, 'yaxis');
var meshz = toDataCoords(trace._Zs, 'zaxis');
tubeOpts.meshgrid = [meshx, meshy, meshz];
tubeOpts.gridFill = trace._gridFill;
var slen = trace._slen;
if (slen) {
tubeOpts.startingPositions = zip3(toDataCoords(trace._startsX, 'xaxis'), toDataCoords(trace._startsY, 'yaxis'), toDataCoords(trace._startsZ, 'zaxis'));
} else {
// Default starting positions:
//
// if len>2, cut xz plane at min-y,
// takes all x/y/z pts on that plane except those on the edges
// to generate "well-defined" tubes,
//
// if len=2, take position halfway between two the pts,
//
// if len=1, take that pt
var sy0 = meshy[0];
var sx = getDfltStartingPositions(meshx);
var sz = getDfltStartingPositions(meshz);
var startingPositions = new Array(sx.length * sz.length);
var m = 0;
for (var i = 0; i < sx.length; i++) {
for (var k = 0; k < sz.length; k++) {
startingPositions[m++] = [sx[i], sy0, sz[k]];
}
}
tubeOpts.startingPositions = startingPositions;
}
tubeOpts.colormap = parseColorScale(trace);
tubeOpts.tubeSize = trace.sizeref;
tubeOpts.maxLength = trace.maxdisplayed;
// add some padding around the bounds
// to e.g. allow tubes starting from a slice of the x/y/z mesh
// to go beyond bounds a little bit w/o getting clipped
var xbnds = toDataCoords(trace._xbnds, 'xaxis');
var ybnds = toDataCoords(trace._ybnds, 'yaxis');
var zbnds = toDataCoords(trace._zbnds, 'zaxis');
var xpads = getBoundPads(meshx);
var ypads = getBoundPads(meshy);
var zpads = getBoundPads(meshz);
var bounds = [[xbnds[0] - xpads[0], ybnds[0] - ypads[0], zbnds[0] - zpads[0]], [xbnds[1] + xpads[1], ybnds[1] + ypads[1], zbnds[1] + zpads[1]]];
var meshData = tube2mesh(tubeOpts, bounds);
// N.B. cmin/cmax correspond to the min/max vector norm
// in the u/v/w arrays, which in general is NOT equal to max
// intensity that colors the tubes.
var cOpts = extractOpts(trace);
meshData.vertexIntensityBounds = [cOpts.min / trace._normMax, cOpts.max / trace._normMax];
// pass gl-mesh3d lighting attributes
var lp = trace.lightposition;
meshData.lightPosition = [lp.x, lp.y, lp.z];
meshData.ambient = trace.lighting.ambient;
meshData.diffuse = trace.lighting.diffuse;
meshData.specular = trace.lighting.specular;
meshData.roughness = trace.lighting.roughness;
meshData.fresnel = trace.lighting.fresnel;
meshData.opacity = trace.opacity;
// stash autorange pad value
trace._pad = meshData.tubeScale * trace.sizeref * 2;
return meshData;
}
proto.update = function (data) {
this.data = data;
var meshData = convert(this.scene, data);
this.mesh.update(meshData);
};
proto.dispose = function () {
this.scene.glplot.remove(this.mesh);
this.mesh.dispose();
};
function createStreamtubeTrace(scene, data) {
var gl = scene.glplot.gl;
var meshData = convert(scene, data);
var mesh = createTubeMesh(gl, meshData);
var streamtube = new Streamtube(scene, data.uid);
streamtube.mesh = mesh;
streamtube.data = data;
mesh._trace = streamtube;
scene.glplot.add(mesh);
return streamtube;
}
module.exports = createStreamtubeTrace;
/***/ }),
/***/ 85435:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(36852);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var u = coerce('u');
var v = coerce('v');
var w = coerce('w');
var x = coerce('x');
var y = coerce('y');
var z = coerce('z');
if (!u || !u.length || !v || !v.length || !w || !w.length || !x || !x.length || !y || !y.length || !z || !z.length) {
traceOut.visible = false;
return;
}
coerce('starts.x');
coerce('starts.y');
coerce('starts.z');
coerce('maxdisplayed');
coerce('sizeref');
coerce('lighting.ambient');
coerce('lighting.diffuse');
coerce('lighting.specular');
coerce('lighting.roughness');
coerce('lighting.fresnel');
coerce('lightposition.x');
coerce('lightposition.y');
coerce('lightposition.z');
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'c'
});
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('uhoverformat');
coerce('vhoverformat');
coerce('whoverformat');
coerce('xhoverformat');
coerce('yhoverformat');
coerce('zhoverformat');
// disable 1D transforms (for now)
// x/y/z and u/v/w have matching lengths,
// but they don't have to match with starts.(x|y|z)
traceOut._length = null;
};
/***/ }),
/***/ 63000:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'streamtube',
basePlotModule: __webpack_require__(26544),
categories: ['gl3d', 'showLegend'],
attributes: __webpack_require__(36852),
supplyDefaults: __webpack_require__(85435),
colorbar: {
min: 'cmin',
max: 'cmax'
},
calc: (__webpack_require__(84720).calc),
plot: __webpack_require__(36140),
eventData: function (out, pt) {
out.tubex = out.x;
out.tubey = out.y;
out.tubez = out.z;
out.tubeu = pt.traceCoordinate[3];
out.tubev = pt.traceCoordinate[4];
out.tubew = pt.traceCoordinate[5];
out.norm = pt.traceCoordinate[6];
out.divergence = pt.traceCoordinate[7];
// Does not correspond to input x/y/z, so delete them
delete out.x;
delete out.y;
delete out.z;
return out;
},
meta: {
description: ['Use a streamtube trace to visualize flow in a vector field.', '', 'Specify a vector field using 6 1D arrays of equal length,', '3 position arrays `x`, `y` and `z`', 'and 3 vector component arrays `u`, `v`, and `w`.', '', 'By default, the tubes\' starting positions will be cut from the vector field\'s', 'x-z plane at its minimum y value.', 'To specify your own starting position, use attributes `starts.x`, `starts.y`', 'and `starts.z`.', 'The color is encoded by the norm of (u, v, w), and the local radius', 'by the divergence of (u, v, w).'].join(' ')
}
};
/***/ }),
/***/ 36404:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var baseAttrs = __webpack_require__(6040);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var colorScaleAttrs = __webpack_require__(99732);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var pieAttrs = __webpack_require__(99644);
var constants = __webpack_require__(3580);
var extendFlat = (__webpack_require__(55016).extendFlat);
var pattern = (__webpack_require__(9392)/* .pattern */ .c);
module.exports = {
labels: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the labels of each of the sectors.'].join(' ')
},
parents: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the parent sectors for each of the sectors.', 'Empty string items \'\' are understood to reference', 'the root node in the hierarchy.', 'If `ids` is filled, `parents` items are understood to be "ids" themselves.', 'When `ids` is not set, plotly attempts to find matching items in `labels`,', 'but beware they must be unique.'].join(' ')
},
values: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the values associated with each of the sectors.', 'Use with `branchvalues` to determine how the values are summed.'].join(' ')
},
branchvalues: {
valType: 'enumerated',
values: ['remainder', 'total'],
dflt: 'remainder',
editType: 'calc',
description: ['Determines how the items in `values` are summed.', 'When set to *total*, items in `values` are taken to be value of all its descendants.', 'When set to *remainder*, items in `values` corresponding to the root and the branches sectors', 'are taken to be the extra part not part of the sum of the values at their leaves.'].join(' ')
},
count: {
valType: 'flaglist',
flags: ['branches', 'leaves'],
dflt: 'leaves',
editType: 'calc',
description: ['Determines default for `values` when it is not provided,', 'by inferring a 1 for each of the *leaves* and/or *branches*, otherwise 0.'].join(' ')
},
level: {
valType: 'any',
editType: 'plot',
anim: true,
description: ['Sets the level from which this trace hierarchy is rendered.', 'Set `level` to `\'\'` to start from the root node in the hierarchy.', 'Must be an "id" if `ids` is filled in, otherwise plotly attempts to find a matching', 'item in `labels`.'].join(' ')
},
maxdepth: {
valType: 'integer',
editType: 'plot',
dflt: -1,
description: ['Sets the number of rendered sectors from any given `level`.', 'Set `maxdepth` to *-1* to render all the levels in the hierarchy.'].join(' ')
},
marker: extendFlat({
colors: {
valType: 'data_array',
editType: 'calc',
description: ['Sets the color of each sector of this trace.', 'If not specified, the default trace color set is used', 'to pick the sector colors.'].join(' ')
},
// colorinheritance: {
// valType: 'enumerated',
// values: ['per-branch', 'per-label', false]
// },
line: {
color: extendFlat({}, pieAttrs.marker.line.color, {
dflt: null,
description: ['Sets the color of the line enclosing each sector.', 'Defaults to the `paper_bgcolor` value.'].join(' ')
}),
width: extendFlat({}, pieAttrs.marker.line.width, {
dflt: 1
}),
editType: 'calc'
},
pattern: pattern,
editType: 'calc'
}, colorScaleAttrs('marker', {
colorAttr: 'colors',
anim: false // TODO: set to anim: true?
})),
leaf: {
opacity: {
valType: 'number',
editType: 'style',
min: 0,
max: 1,
description: ['Sets the opacity of the leaves. With colorscale', 'it is defaulted to 1; otherwise it is defaulted to 0.7'].join(' ')
},
editType: 'plot'
},
text: pieAttrs.text,
textinfo: {
valType: 'flaglist',
flags: ['label', 'text', 'value', 'current path', 'percent root', 'percent entry', 'percent parent'],
extras: ['none'],
editType: 'plot',
description: ['Determines which trace information appear on the graph.'].join(' ')
},
// TODO: incorporate `label` and `value` in the eventData
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: constants.eventDataKeys.concat(['label', 'value'])
}),
hovertext: pieAttrs.hovertext,
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['label', 'text', 'value', 'name', 'current path', 'percent root', 'percent entry', 'percent parent'],
dflt: 'label+text+value+name'
}),
hovertemplate: hovertemplateAttrs({}, {
keys: constants.eventDataKeys
}),
textfont: pieAttrs.textfont,
insidetextorientation: pieAttrs.insidetextorientation,
insidetextfont: pieAttrs.insidetextfont,
outsidetextfont: extendFlat({}, pieAttrs.outsidetextfont, {
description: ['Sets the font used for `textinfo` lying outside the sector.', 'This option refers to the root of the hierarchy', 'presented at the center of a sunburst graph.', 'Please note that if a hierarchy has multiple root nodes,', 'this option won\'t have any effect and `insidetextfont` would be used.'].join(' ')
}),
rotation: {
valType: 'angle',
dflt: 0,
editType: 'plot',
description: ['Rotates the whole diagram counterclockwise by some angle.', 'By default the first slice starts at 3 o\'clock.'].join(' ')
},
sort: pieAttrs.sort,
root: {
color: {
valType: 'color',
editType: 'calc',
dflt: 'rgba(0,0,0,0)',
description: ['sets the color of the root node for a sunburst/treemap/icicle trace.', 'this has no effect when a colorscale is used to set the markers.'].join(' ')
},
editType: 'calc'
},
domain: domainAttrs({
name: 'sunburst',
trace: true,
editType: 'calc'
})
};
/***/ }),
/***/ 35260:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var plots = __webpack_require__(19896);
exports.name = 'sunburst';
exports.plot = function (gd, traces, transitionOpts, makeOnCompleteCallback) {
plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout);
};
/***/ }),
/***/ 45780:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var d3Hierarchy = __webpack_require__(89332);
var isNumeric = __webpack_require__(88120);
var Lib = __webpack_require__(10923);
var makeColorScaleFn = (__webpack_require__(26733).makeColorScaleFuncFromTrace);
var makePullColorFn = (__webpack_require__(71120).makePullColorFn);
var generateExtendedColors = (__webpack_require__(71120).generateExtendedColors);
var colorscaleCalc = (__webpack_require__(26733).calc);
var ALMOST_EQUAL = (__webpack_require__(41752).ALMOST_EQUAL);
var sunburstExtendedColorWays = {};
var treemapExtendedColorWays = {};
var icicleExtendedColorWays = {};
exports.calc = function (gd, trace) {
var fullLayout = gd._fullLayout;
var ids = trace.ids;
var hasIds = Lib.isArrayOrTypedArray(ids);
var labels = trace.labels;
var parents = trace.parents;
var values = trace.values;
var hasValues = Lib.isArrayOrTypedArray(values);
var cd = [];
var parent2children = {};
var refs = {};
var addToLookup = function (parent, v) {
if (parent2children[parent]) parent2children[parent].push(v);else parent2children[parent] = [v];
refs[v] = 1;
};
// treat number `0` as valid
var isValidKey = function (k) {
return k || typeof k === 'number';
};
var isValidVal = function (i) {
return !hasValues || isNumeric(values[i]) && values[i] >= 0;
};
var len;
var isValid;
var getId;
if (hasIds) {
len = Math.min(ids.length, parents.length);
isValid = function (i) {
return isValidKey(ids[i]) && isValidVal(i);
};
getId = function (i) {
return String(ids[i]);
};
} else {
len = Math.min(labels.length, parents.length);
isValid = function (i) {
return isValidKey(labels[i]) && isValidVal(i);
};
// TODO We could allow some label / parent duplication
//
// From AJ:
// It would work OK for one level
// (multiple rows with the same name and different parents -
// or even the same parent) but if that name is then used as a parent
// which one is it?
getId = function (i) {
return String(labels[i]);
};
}
if (hasValues) len = Math.min(len, values.length);
for (var i = 0; i < len; i++) {
if (isValid(i)) {
var id = getId(i);
var pid = isValidKey(parents[i]) ? String(parents[i]) : '';
var cdi = {
i: i,
id: id,
pid: pid,
label: isValidKey(labels[i]) ? String(labels[i]) : ''
};
if (hasValues) cdi.v = +values[i];
cd.push(cdi);
addToLookup(pid, id);
}
}
if (!parent2children['']) {
var impliedRoots = [];
var k;
for (k in parent2children) {
if (!refs[k]) {
impliedRoots.push(k);
}
}
// if an `id` has no ref in the `parents` array,
// take it as being the root node
if (impliedRoots.length === 1) {
k = impliedRoots[0];
cd.unshift({
hasImpliedRoot: true,
id: k,
pid: '',
label: k
});
} else {
return Lib.warn(['Multiple implied roots, cannot build', trace.type, 'hierarchy of', trace.name + '.', 'These roots include:', impliedRoots.join(', ')].join(' '));
}
} else if (parent2children[''].length > 1) {
var dummyId = Lib.randstr();
// if multiple rows linked to the root node,
// add dummy "root of roots" node to make d3 build the hierarchy successfully
for (var j = 0; j < cd.length; j++) {
if (cd[j].pid === '') {
cd[j].pid = dummyId;
}
}
cd.unshift({
hasMultipleRoots: true,
id: dummyId,
pid: '',
label: ''
});
}
// TODO might be better to replace stratify() with our own algorithm
var root;
try {
root = d3Hierarchy.stratify().id(function (d) {
return d.id;
}).parentId(function (d) {
return d.pid;
})(cd);
} catch (e) {
return Lib.warn(['Failed to build', trace.type, 'hierarchy of', trace.name + '.', 'Error:', e.message].join(' '));
}
var hierarchy = d3Hierarchy.hierarchy(root);
var failed = false;
if (hasValues) {
switch (trace.branchvalues) {
case 'remainder':
hierarchy.sum(function (d) {
return d.data.v;
});
break;
case 'total':
hierarchy.each(function (d) {
var cdi = d.data.data;
var v = cdi.v;
if (d.children) {
var partialSum = d.children.reduce(function (a, c) {
return a + c.data.data.v;
}, 0);
// N.B. we must fill in `value` for generated sectors
// with the partialSum to compute the correct partition
if (cdi.hasImpliedRoot || cdi.hasMultipleRoots) {
v = partialSum;
}
if (v < partialSum * ALMOST_EQUAL) {
failed = true;
return Lib.warn(['Total value for node', d.data.data.id, 'of', trace.name, 'is smaller than the sum of its children.', '\nparent value =', v, '\nchildren sum =', partialSum].join(' '));
}
}
d.value = v;
});
break;
}
} else {
countDescendants(hierarchy, trace, {
branches: trace.count.indexOf('branches') !== -1,
leaves: trace.count.indexOf('leaves') !== -1
});
}
if (failed) return;
// TODO add way to sort by height also?
if (trace.sort) {
hierarchy.sort(function (a, b) {
return b.value - a.value;
});
}
var pullColor;
var scaleColor;
var colors = trace.marker.colors || [];
var hasColors = !!colors.length;
if (trace._hasColorscale) {
if (!hasColors) {
colors = hasValues ? trace.values : trace._values;
}
colorscaleCalc(gd, trace, {
vals: colors,
containerStr: 'marker',
cLetter: 'c'
});
scaleColor = makeColorScaleFn(trace.marker);
} else {
pullColor = makePullColorFn(fullLayout['_' + trace.type + 'colormap']);
}
// TODO keep track of 'root-children' (i.e. branch) for hover info etc.
hierarchy.each(function (d) {
var cdi = d.data.data;
// N.B. this mutates items in `cd`
cdi.color = trace._hasColorscale ? scaleColor(colors[cdi.i]) : pullColor(colors[cdi.i], cdi.id);
});
cd[0].hierarchy = hierarchy;
return cd;
};
/*
* `calc` filled in (and collated) explicit colors.
* Now we need to propagate these explicit colors to other traces,
* and fill in default colors.
* This is done after sorting, so we pick defaults
* in the order slices will be displayed
*/
exports._runCrossTraceCalc = function (desiredType, gd) {
var fullLayout = gd._fullLayout;
var calcdata = gd.calcdata;
var colorWay = fullLayout[desiredType + 'colorway'];
var colorMap = fullLayout['_' + desiredType + 'colormap'];
if (fullLayout['extend' + desiredType + 'colors']) {
colorWay = generateExtendedColors(colorWay, desiredType === 'icicle' ? icicleExtendedColorWays : desiredType === 'treemap' ? treemapExtendedColorWays : sunburstExtendedColorWays);
}
var dfltColorCount = 0;
var rootColor;
function pickColor(d) {
var cdi = d.data.data;
var id = cdi.id;
if (cdi.color === false) {
if (colorMap[id]) {
// have we seen this label and assigned a color to it in a previous trace?
cdi.color = colorMap[id];
} else if (d.parent) {
if (d.parent.parent) {
// from third-level on, inherit from parent
cdi.color = d.parent.data.data.color;
} else {
// pick new color for second level
colorMap[id] = cdi.color = colorWay[dfltColorCount % colorWay.length];
dfltColorCount++;
}
} else {
// set root color. no coloring by default.
cdi.color = rootColor;
}
}
}
for (var i = 0; i < calcdata.length; i++) {
var cd = calcdata[i];
var cd0 = cd[0];
if (cd0.trace.type === desiredType && cd0.hierarchy) {
rootColor = cd0.trace.root.color;
cd0.hierarchy.each(pickColor);
}
}
};
exports.crossTraceCalc = function (gd) {
return exports._runCrossTraceCalc('sunburst', gd);
};
function countDescendants(node, trace, opts) {
var nChild = 0;
var children = node.children;
if (children) {
var len = children.length;
for (var i = 0; i < len; i++) {
nChild += countDescendants(children[i], trace, opts);
}
if (opts.branches) nChild++; // count this branch
} else {
if (opts.leaves) nChild++; // count this leaf
}
// save to the node
node.value = node.data.data.value = nChild;
// save to the trace
if (!trace._values) trace._values = [];
trace._values[node.data.data.i] = nChild;
return nChild;
}
/***/ }),
/***/ 3580:
/***/ (function(module) {
"use strict";
module.exports = {
CLICK_TRANSITION_TIME: 750,
CLICK_TRANSITION_EASING: 'linear',
eventDataKeys: [
// string
'currentPath', 'root', 'entry',
// no need to add 'parent' here
// percentages i.e. ratios
'percentRoot', 'percentEntry', 'percentParent']
};
/***/ }),
/***/ 27304:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(36404);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var handleText = (__webpack_require__(49520).handleText);
var handleMarkerDefaults = (__webpack_require__(87048).handleMarkerDefaults);
var Colorscale = __webpack_require__(26733);
var hasColorscale = Colorscale.hasColorscale;
var colorscaleDefaults = Colorscale.handleDefaults;
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var labels = coerce('labels');
var parents = coerce('parents');
if (!labels || !labels.length || !parents || !parents.length) {
traceOut.visible = false;
return;
}
var vals = coerce('values');
if (vals && vals.length) {
coerce('branchvalues');
} else {
coerce('count');
}
coerce('level');
coerce('maxdepth');
handleMarkerDefaults(traceIn, traceOut, layout, coerce);
var withColorscale = traceOut._hasColorscale = hasColorscale(traceIn, 'marker', 'colors') || (traceIn.marker || {}).coloraxis // N.B. special logic to consider "values" colorscales
;
if (withColorscale) {
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'marker.',
cLetter: 'c'
});
}
coerce('leaf.opacity', withColorscale ? 1 : 0.7);
var text = coerce('text');
coerce('texttemplate');
if (!traceOut.texttemplate) coerce('textinfo', Lib.isArrayOrTypedArray(text) ? 'text+label' : 'label');
coerce('hovertext');
coerce('hovertemplate');
var textposition = 'auto';
handleText(traceIn, traceOut, layout, coerce, textposition, {
moduleHasSelected: false,
moduleHasUnselected: false,
moduleHasConstrain: false,
moduleHasCliponaxis: false,
moduleHasTextangle: false,
moduleHasInsideanchor: false
});
coerce('insidetextorientation');
coerce('sort');
coerce('rotation');
coerce('root.color');
handleDomainDefaults(traceOut, layout, coerce);
// do not support transforms for now
traceOut._length = null;
};
/***/ }),
/***/ 81136:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Drawing = __webpack_require__(49348);
var Color = __webpack_require__(9240);
module.exports = function fillOne(s, pt, trace, gd, fadedColor) {
var cdi = pt.data.data;
var ptNumber = cdi.i;
var color = fadedColor || cdi.color;
if (ptNumber >= 0) {
pt.i = cdi.i;
var marker = trace.marker;
if (marker.pattern) {
if (!marker.colors || !marker.pattern.shape) {
marker.color = color;
pt.color = color;
}
} else {
marker.color = color;
pt.color = color;
}
Drawing.pointStyle(s, trace, gd, pt);
} else {
Color.fill(s, color);
}
};
/***/ }),
/***/ 58528:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Registry = __webpack_require__(30364);
var appendArrayPointValue = (__webpack_require__(12228).appendArrayPointValue);
var Fx = __webpack_require__(39184);
var Lib = __webpack_require__(10923);
var Events = __webpack_require__(50200);
var helpers = __webpack_require__(54844);
var pieHelpers = __webpack_require__(27760);
var formatValue = pieHelpers.formatPieValue;
module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) {
var cd0 = cd[0];
var trace = cd0.trace;
var hierarchy = cd0.hierarchy;
var isSunburst = trace.type === 'sunburst';
var isTreemapOrIcicle = trace.type === 'treemap' || trace.type === 'icicle';
// hover state vars
// have we drawn a hover label, so it should be cleared later
if (!('_hasHoverLabel' in trace)) trace._hasHoverLabel = false;
// have we emitted a hover event, so later an unhover event should be emitted
// note that click events do not depend on this - you can still get them
// with hovermode: false or if you were earlier dragging, then clicked
// in the same slice that you moused up in
if (!('_hasHoverEvent' in trace)) trace._hasHoverEvent = false;
var onMouseOver = function (pt) {
var fullLayoutNow = gd._fullLayout;
if (gd._dragging || fullLayoutNow.hovermode === false) return;
var traceNow = gd._fullData[trace.index];
var cdi = pt.data.data;
var ptNumber = cdi.i;
var isRoot = helpers.isHierarchyRoot(pt);
var parent = helpers.getParent(hierarchy, pt);
var val = helpers.getValue(pt);
var _cast = function (astr) {
return Lib.castOption(traceNow, ptNumber, astr);
};
var hovertemplate = _cast('hovertemplate');
var hoverinfo = Fx.castHoverinfo(traceNow, fullLayoutNow, ptNumber);
var separators = fullLayoutNow.separators;
var eventData;
if (hovertemplate || hoverinfo && hoverinfo !== 'none' && hoverinfo !== 'skip') {
var hoverCenterX;
var hoverCenterY;
if (isSunburst) {
hoverCenterX = cd0.cx + pt.pxmid[0] * (1 - pt.rInscribed);
hoverCenterY = cd0.cy + pt.pxmid[1] * (1 - pt.rInscribed);
}
if (isTreemapOrIcicle) {
hoverCenterX = pt._hoverX;
hoverCenterY = pt._hoverY;
}
var hoverPt = {};
var parts = [];
var thisText = [];
var hasFlag = function (flag) {
return parts.indexOf(flag) !== -1;
};
if (hoverinfo) {
parts = hoverinfo === 'all' ? traceNow._module.attributes.hoverinfo.flags : hoverinfo.split('+');
}
hoverPt.label = cdi.label;
if (hasFlag('label') && hoverPt.label) thisText.push(hoverPt.label);
if (cdi.hasOwnProperty('v')) {
hoverPt.value = cdi.v;
hoverPt.valueLabel = formatValue(hoverPt.value, separators);
if (hasFlag('value')) thisText.push(hoverPt.valueLabel);
}
hoverPt.currentPath = pt.currentPath = helpers.getPath(pt.data);
if (hasFlag('current path') && !isRoot) {
thisText.push(hoverPt.currentPath);
}
var tx;
var allPercents = [];
var insertPercent = function () {
if (allPercents.indexOf(tx) === -1) {
// no need to add redundant info
thisText.push(tx);
allPercents.push(tx);
}
};
hoverPt.percentParent = pt.percentParent = val / helpers.getValue(parent);
hoverPt.parent = pt.parentString = helpers.getPtLabel(parent);
if (hasFlag('percent parent')) {
tx = helpers.formatPercent(hoverPt.percentParent, separators) + ' of ' + hoverPt.parent;
insertPercent();
}
hoverPt.percentEntry = pt.percentEntry = val / helpers.getValue(entry);
hoverPt.entry = pt.entry = helpers.getPtLabel(entry);
if (hasFlag('percent entry') && !isRoot && !pt.onPathbar) {
tx = helpers.formatPercent(hoverPt.percentEntry, separators) + ' of ' + hoverPt.entry;
insertPercent();
}
hoverPt.percentRoot = pt.percentRoot = val / helpers.getValue(hierarchy);
hoverPt.root = pt.root = helpers.getPtLabel(hierarchy);
if (hasFlag('percent root') && !isRoot) {
tx = helpers.formatPercent(hoverPt.percentRoot, separators) + ' of ' + hoverPt.root;
insertPercent();
}
hoverPt.text = _cast('hovertext') || _cast('text');
if (hasFlag('text')) {
tx = hoverPt.text;
if (Lib.isValidTextValue(tx)) thisText.push(tx);
}
eventData = [makeEventData(pt, traceNow, opts.eventDataKeys)];
var hoverItems = {
trace: traceNow,
y: hoverCenterY,
_x0: pt._x0,
_x1: pt._x1,
_y0: pt._y0,
_y1: pt._y1,
text: thisText.join('
'),
name: hovertemplate || hasFlag('name') ? traceNow.name : undefined,
color: _cast('hoverlabel.bgcolor') || cdi.color,
borderColor: _cast('hoverlabel.bordercolor'),
fontFamily: _cast('hoverlabel.font.family'),
fontSize: _cast('hoverlabel.font.size'),
fontColor: _cast('hoverlabel.font.color'),
nameLength: _cast('hoverlabel.namelength'),
textAlign: _cast('hoverlabel.align'),
hovertemplate: hovertemplate,
hovertemplateLabels: hoverPt,
eventData: eventData
};
if (isSunburst) {
hoverItems.x0 = hoverCenterX - pt.rInscribed * pt.rpx1;
hoverItems.x1 = hoverCenterX + pt.rInscribed * pt.rpx1;
hoverItems.idealAlign = pt.pxmid[0] < 0 ? 'left' : 'right';
}
if (isTreemapOrIcicle) {
hoverItems.x = hoverCenterX;
hoverItems.idealAlign = hoverCenterX < 0 ? 'left' : 'right';
}
var bbox = [];
Fx.loneHover(hoverItems, {
container: fullLayoutNow._hoverlayer.node(),
outerContainer: fullLayoutNow._paper.node(),
gd: gd,
inOut_bbox: bbox
});
eventData[0].bbox = bbox[0];
trace._hasHoverLabel = true;
}
if (isTreemapOrIcicle) {
var slice = sliceTop.select('path.surface');
opts.styleOne(slice, pt, traceNow, gd, {
hovered: true
});
}
trace._hasHoverEvent = true;
gd.emit('plotly_hover', {
points: eventData || [makeEventData(pt, traceNow, opts.eventDataKeys)],
event: d3.event
});
};
var onMouseOut = function (evt) {
var fullLayoutNow = gd._fullLayout;
var traceNow = gd._fullData[trace.index];
var pt = d3.select(this).datum();
if (trace._hasHoverEvent) {
evt.originalEvent = d3.event;
gd.emit('plotly_unhover', {
points: [makeEventData(pt, traceNow, opts.eventDataKeys)],
event: d3.event
});
trace._hasHoverEvent = false;
}
if (trace._hasHoverLabel) {
Fx.loneUnhover(fullLayoutNow._hoverlayer.node());
trace._hasHoverLabel = false;
}
if (isTreemapOrIcicle) {
var slice = sliceTop.select('path.surface');
opts.styleOne(slice, pt, traceNow, gd, {
hovered: false
});
}
};
var onClick = function (pt) {
// TODO: this does not support right-click. If we want to support it, we
// would likely need to change pie to use dragElement instead of straight
// mapbox event binding. Or perhaps better, make a simple wrapper with the
// right mousedown, mousemove, and mouseup handlers just for a left/right click
// mapbox would use this too.
var fullLayoutNow = gd._fullLayout;
var traceNow = gd._fullData[trace.index];
var noTransition = isSunburst && (helpers.isHierarchyRoot(pt) || helpers.isLeaf(pt));
var id = helpers.getPtId(pt);
var nextEntry = helpers.isEntry(pt) ? helpers.findEntryWithChild(hierarchy, id) : helpers.findEntryWithLevel(hierarchy, id);
var nextLevel = helpers.getPtId(nextEntry);
var typeClickEvtData = {
points: [makeEventData(pt, traceNow, opts.eventDataKeys)],
event: d3.event
};
if (!noTransition) typeClickEvtData.nextLevel = nextLevel;
var clickVal = Events.triggerHandler(gd, 'plotly_' + trace.type + 'click', typeClickEvtData);
if (clickVal !== false && fullLayoutNow.hovermode) {
gd._hoverdata = [makeEventData(pt, traceNow, opts.eventDataKeys)];
Fx.click(gd, d3.event);
}
// if click does not trigger a transition, we're done!
if (noTransition) return;
// if custom handler returns false, we're done!
if (clickVal === false) return;
// skip if triggered from dragging a nearby cartesian subplot
if (gd._dragging) return;
// skip during transitions, to avoid potential bugs
// we could remove this check later
if (gd._transitioning) return;
// store 'old' level in guiEdit stash, so that subsequent Plotly.react
// calls with the same uirevision can start from the same entry
Registry.call('_storeDirectGUIEdit', traceNow, fullLayoutNow._tracePreGUI[traceNow.uid], {
level: traceNow.level
});
var frame = {
data: [{
level: nextLevel
}],
traces: [trace.index]
};
var animOpts = {
frame: {
redraw: false,
duration: opts.transitionTime
},
transition: {
duration: opts.transitionTime,
easing: opts.transitionEasing
},
mode: 'immediate',
fromcurrent: true
};
Fx.loneUnhover(fullLayoutNow._hoverlayer.node());
Registry.call('animate', gd, frame, animOpts);
};
sliceTop.on('mouseover', onMouseOver);
sliceTop.on('mouseout', onMouseOut);
sliceTop.on('click', onClick);
};
function makeEventData(pt, trace, keys) {
var cdi = pt.data.data;
var out = {
curveNumber: trace.index,
pointNumber: cdi.i,
data: trace._input,
fullData: trace
// TODO more things like 'children', 'siblings', 'hierarchy?
};
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (key in pt) out[key] = pt[key];
}
// handle special case of parent
if ('parentString' in pt && !helpers.isHierarchyRoot(pt)) out.parent = pt.parentString;
appendArrayPointValue(out, trace, cdi.i);
return out;
}
/***/ }),
/***/ 54844:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Color = __webpack_require__(9240);
var setCursor = __webpack_require__(18792);
var pieHelpers = __webpack_require__(27760);
exports.findEntryWithLevel = function (hierarchy, level) {
var out;
if (level) {
hierarchy.eachAfter(function (pt) {
if (exports.getPtId(pt) === level) {
return out = pt.copy();
}
});
}
return out || hierarchy;
};
exports.findEntryWithChild = function (hierarchy, childId) {
var out;
hierarchy.eachAfter(function (pt) {
var children = pt.children || [];
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (exports.getPtId(child) === childId) {
return out = pt.copy();
}
}
});
return out || hierarchy;
};
exports.isEntry = function (pt) {
return !pt.parent;
};
exports.isLeaf = function (pt) {
return !pt.children;
};
exports.getPtId = function (pt) {
return pt.data.data.id;
};
exports.getPtLabel = function (pt) {
return pt.data.data.label;
};
exports.getValue = function (d) {
return d.value;
};
exports.isHierarchyRoot = function (pt) {
return getParentId(pt) === '';
};
exports.setSliceCursor = function (sliceTop, gd, opts) {
var hide = opts.isTransitioning;
if (!hide) {
var pt = sliceTop.datum();
hide = opts.hideOnRoot && exports.isHierarchyRoot(pt) || opts.hideOnLeaves && exports.isLeaf(pt);
}
setCursor(sliceTop, hide ? null : 'pointer');
};
function determineOutsideTextFont(trace, pt, layoutFont) {
return {
color: exports.getOutsideTextFontKey('color', trace, pt, layoutFont),
family: exports.getOutsideTextFontKey('family', trace, pt, layoutFont),
size: exports.getOutsideTextFontKey('size', trace, pt, layoutFont)
};
}
function determineInsideTextFont(trace, pt, layoutFont, opts) {
var onPathbar = (opts || {}).onPathbar;
var cdi = pt.data.data;
var ptNumber = cdi.i;
var customColor = Lib.castOption(trace, ptNumber, (onPathbar ? 'pathbar.textfont' : 'insidetextfont') + '.color');
if (!customColor && trace._input.textfont) {
// Why not simply using trace.textfont? Because if not set, it
// defaults to layout.font which has a default color. But if
// textfont.color and insidetextfont.color don't supply a value,
// a contrasting color shall be used.
customColor = Lib.castOption(trace._input, ptNumber, 'textfont.color');
}
return {
color: customColor || Color.contrast(cdi.color),
family: exports.getInsideTextFontKey('family', trace, pt, layoutFont, opts),
size: exports.getInsideTextFontKey('size', trace, pt, layoutFont, opts)
};
}
exports.getInsideTextFontKey = function (keyStr, trace, pt, layoutFont, opts) {
var onPathbar = (opts || {}).onPathbar;
var cont = onPathbar ? 'pathbar.textfont' : 'insidetextfont';
var ptNumber = pt.data.data.i;
return Lib.castOption(trace, ptNumber, cont + '.' + keyStr) || Lib.castOption(trace, ptNumber, 'textfont.' + keyStr) || layoutFont.size;
};
exports.getOutsideTextFontKey = function (keyStr, trace, pt, layoutFont) {
var ptNumber = pt.data.data.i;
return Lib.castOption(trace, ptNumber, 'outsidetextfont.' + keyStr) || Lib.castOption(trace, ptNumber, 'textfont.' + keyStr) || layoutFont.size;
};
exports.isOutsideText = function (trace, pt) {
return !trace._hasColorscale && exports.isHierarchyRoot(pt);
};
exports.determineTextFont = function (trace, pt, layoutFont, opts) {
return exports.isOutsideText(trace, pt) ? determineOutsideTextFont(trace, pt, layoutFont) : determineInsideTextFont(trace, pt, layoutFont, opts);
};
exports.hasTransition = function (transitionOpts) {
// We could optimize hasTransition per trace,
// as sunburst, treemap & icicle have no cross-trace logic!
return !!(transitionOpts && transitionOpts.duration > 0);
};
exports.getMaxDepth = function (trace) {
return trace.maxdepth >= 0 ? trace.maxdepth : Infinity;
};
exports.isHeader = function (pt, trace) {
// it is only used in treemap.
return !(exports.isLeaf(pt) || pt.depth === trace._maxDepth - 1);
};
function getParentId(pt) {
return pt.data.data.pid;
}
exports.getParent = function (hierarchy, pt) {
return exports.findEntryWithLevel(hierarchy, getParentId(pt));
};
exports.listPath = function (d, keyStr) {
var parent = d.parent;
if (!parent) return [];
var list = keyStr ? [parent.data[keyStr]] : [parent];
return exports.listPath(parent, keyStr).concat(list);
};
exports.getPath = function (d) {
return exports.listPath(d, 'label').join('/') + '/';
};
exports.formatValue = pieHelpers.formatPieValue;
// TODO: should combine the two in a separate PR - Also please note Lib.formatPercent should support separators.
exports.formatPercent = function (v, separators) {
var tx = Lib.formatPercent(v, 0); // use funnel(area) version
if (tx === '0%') tx = pieHelpers.formatPiePercent(v, separators); // use pie version
return tx;
};
/***/ }),
/***/ 18136:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'sunburst',
basePlotModule: __webpack_require__(35260),
categories: [],
animatable: true,
attributes: __webpack_require__(36404),
layoutAttributes: __webpack_require__(88304),
supplyDefaults: __webpack_require__(27304),
supplyLayoutDefaults: __webpack_require__(97212),
calc: (__webpack_require__(45780).calc),
crossTraceCalc: (__webpack_require__(45780).crossTraceCalc),
plot: (__webpack_require__(35384).plot),
style: (__webpack_require__(74468).style),
colorbar: __webpack_require__(71416),
meta: {
description: ['Visualize hierarchal data spanning outward radially from root to leaves.', 'The sunburst sectors are determined by the entries in *labels* or *ids*', 'and in *parents*.'].join(' ')
}
};
/***/ }),
/***/ 88304:
/***/ (function(module) {
"use strict";
module.exports = {
sunburstcolorway: {
valType: 'colorlist',
editType: 'calc',
description: ['Sets the default sunburst slice colors. Defaults to the main', '`colorway` used for trace colors. If you specify a new', 'list here it can still be extended with lighter and darker', 'colors, see `extendsunburstcolors`.'].join(' ')
},
extendsunburstcolors: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['If `true`, the sunburst slice colors (whether given by `sunburstcolorway` or', 'inherited from `colorway`) will be extended to three times its', 'original length by first repeating every color 20% lighter then', 'each color 20% darker. This is intended to reduce the likelihood', 'of reusing the same color when you have many slices, but you can', 'set `false` to disable.', 'Colors provided in the trace, using `marker.colors`, are never', 'extended.'].join(' ')
}
};
/***/ }),
/***/ 97212:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(88304);
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
coerce('sunburstcolorway', layoutOut.colorway);
coerce('extendsunburstcolors');
};
/***/ }),
/***/ 35384:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var d3Hierarchy = __webpack_require__(89332);
var interpolate = (__webpack_require__(78204)/* .interpolate */ .qy);
var Drawing = __webpack_require__(49348);
var Lib = __webpack_require__(10923);
var svgTextUtils = __webpack_require__(41536);
var uniformText = __webpack_require__(4096);
var recordMinTextSize = uniformText.recordMinTextSize;
var clearMinTextSize = uniformText.clearMinTextSize;
var piePlot = __webpack_require__(60476);
var getRotationAngle = (__webpack_require__(27760).getRotationAngle);
var computeTransform = piePlot.computeTransform;
var transformInsideText = piePlot.transformInsideText;
var styleOne = (__webpack_require__(74468).styleOne);
var resizeText = (__webpack_require__(21212).resizeText);
var attachFxHandlers = __webpack_require__(58528);
var constants = __webpack_require__(3580);
var helpers = __webpack_require__(54844);
exports.plot = function (gd, cdmodule, transitionOpts, makeOnCompleteCallback) {
var fullLayout = gd._fullLayout;
var layer = fullLayout._sunburstlayer;
var join, onComplete;
// If transition config is provided, then it is only a partial replot and traces not
// updated are removed.
var isFullReplot = !transitionOpts;
var hasTransition = !fullLayout.uniformtext.mode && helpers.hasTransition(transitionOpts);
clearMinTextSize('sunburst', fullLayout);
join = layer.selectAll('g.trace.sunburst').data(cdmodule, function (cd) {
return cd[0].trace.uid;
});
// using same 'stroke-linejoin' as pie traces
join.enter().append('g').classed('trace', true).classed('sunburst', true).attr('stroke-linejoin', 'round');
join.order();
if (hasTransition) {
if (makeOnCompleteCallback) {
// If it was passed a callback to register completion, make a callback. If
// this is created, then it must be executed on completion, otherwise the
// pos-transition redraw will not execute:
onComplete = makeOnCompleteCallback();
}
var transition = d3.transition().duration(transitionOpts.duration).ease(transitionOpts.easing).each('end', function () {
onComplete && onComplete();
}).each('interrupt', function () {
onComplete && onComplete();
});
transition.each(function () {
// Must run the selection again since otherwise enters/updates get grouped together
// and these get executed out of order. Except we need them in order!
layer.selectAll('g.trace').each(function (cd) {
plotOne(gd, cd, this, transitionOpts);
});
});
} else {
join.each(function (cd) {
plotOne(gd, cd, this, transitionOpts);
});
if (fullLayout.uniformtext.mode) {
resizeText(gd, fullLayout._sunburstlayer.selectAll('.trace'), 'sunburst');
}
}
if (isFullReplot) {
join.exit().remove();
}
};
function plotOne(gd, cd, element, transitionOpts) {
var isStatic = gd._context.staticPlot;
var fullLayout = gd._fullLayout;
var hasTransition = !fullLayout.uniformtext.mode && helpers.hasTransition(transitionOpts);
var gTrace = d3.select(element);
var slices = gTrace.selectAll('g.slice');
var cd0 = cd[0];
var trace = cd0.trace;
var hierarchy = cd0.hierarchy;
var entry = helpers.findEntryWithLevel(hierarchy, trace.level);
var maxDepth = helpers.getMaxDepth(trace);
var gs = fullLayout._size;
var domain = trace.domain;
var vpw = gs.w * (domain.x[1] - domain.x[0]);
var vph = gs.h * (domain.y[1] - domain.y[0]);
var rMax = 0.5 * Math.min(vpw, vph);
var cx = cd0.cx = gs.l + gs.w * (domain.x[1] + domain.x[0]) / 2;
var cy = cd0.cy = gs.t + gs.h * (1 - domain.y[0]) - vph / 2;
if (!entry) {
return slices.remove();
}
// previous root 'pt' (can be empty)
var prevEntry = null;
// stash of 'previous' position data used by tweening functions
var prevLookup = {};
if (hasTransition) {
// Important: do this before binding new sliceData!
slices.each(function (pt) {
prevLookup[helpers.getPtId(pt)] = {
rpx0: pt.rpx0,
rpx1: pt.rpx1,
x0: pt.x0,
x1: pt.x1,
transform: pt.transform
};
if (!prevEntry && helpers.isEntry(pt)) {
prevEntry = pt;
}
});
}
// N.B. slice data isn't the calcdata,
// grab corresponding calcdata item in sliceData[i].data.data
var sliceData = partition(entry).descendants();
var maxHeight = entry.height + 1;
var yOffset = 0;
var cutoff = maxDepth;
// N.B. handle multiple-root special case
if (cd0.hasMultipleRoots && helpers.isHierarchyRoot(entry)) {
sliceData = sliceData.slice(1);
maxHeight -= 1;
yOffset = 1;
cutoff += 1;
}
// filter out slices that won't show up on graph
sliceData = sliceData.filter(function (pt) {
return pt.y1 <= cutoff;
});
var baseX = getRotationAngle(trace.rotation);
if (baseX) {
sliceData.forEach(function (pt) {
pt.x0 += baseX;
pt.x1 += baseX;
});
}
// partition span ('y') to sector radial px value
var maxY = Math.min(maxHeight, maxDepth);
var y2rpx = function (y) {
return (y - yOffset) / maxY * rMax;
};
// (radial px value, partition angle ('x')) to px [x,y]
var rx2px = function (r, x) {
return [r * Math.cos(x), -r * Math.sin(x)];
};
// slice path generation fn
var pathSlice = function (d) {
return Lib.pathAnnulus(d.rpx0, d.rpx1, d.x0, d.x1, cx, cy);
};
// slice text translate x/y
var getTargetX = function (d) {
return cx + getTextXY(d)[0] * (d.transform.rCenter || 0) + (d.transform.x || 0);
};
var getTargetY = function (d) {
return cy + getTextXY(d)[1] * (d.transform.rCenter || 0) + (d.transform.y || 0);
};
slices = slices.data(sliceData, helpers.getPtId);
slices.enter().append('g').classed('slice', true);
if (hasTransition) {
slices.exit().transition().each(function () {
var sliceTop = d3.select(this);
var slicePath = sliceTop.select('path.surface');
slicePath.transition().attrTween('d', function (pt2) {
var interp = makeExitSliceInterpolator(pt2);
return function (t) {
return pathSlice(interp(t));
};
});
var sliceTextGroup = sliceTop.select('g.slicetext');
sliceTextGroup.attr('opacity', 0);
}).remove();
} else {
slices.exit().remove();
}
slices.order();
// next x1 (i.e. sector end angle) of previous entry
var nextX1ofPrevEntry = null;
if (hasTransition && prevEntry) {
var prevEntryId = helpers.getPtId(prevEntry);
slices.each(function (pt) {
if (nextX1ofPrevEntry === null && helpers.getPtId(pt) === prevEntryId) {
nextX1ofPrevEntry = pt.x1;
}
});
}
var updateSlices = slices;
if (hasTransition) {
updateSlices = updateSlices.transition().each('end', function () {
// N.B. gd._transitioning is (still) *true* by the time
// transition updates get here
var sliceTop = d3.select(this);
helpers.setSliceCursor(sliceTop, gd, {
hideOnRoot: true,
hideOnLeaves: true,
isTransitioning: false
});
});
}
updateSlices.each(function (pt) {
var sliceTop = d3.select(this);
var slicePath = Lib.ensureSingle(sliceTop, 'path', 'surface', function (s) {
s.style('pointer-events', isStatic ? 'none' : 'all');
});
pt.rpx0 = y2rpx(pt.y0);
pt.rpx1 = y2rpx(pt.y1);
pt.xmid = (pt.x0 + pt.x1) / 2;
pt.pxmid = rx2px(pt.rpx1, pt.xmid);
pt.midangle = -(pt.xmid - Math.PI / 2);
pt.startangle = -(pt.x0 - Math.PI / 2);
pt.stopangle = -(pt.x1 - Math.PI / 2);
pt.halfangle = 0.5 * Math.min(Lib.angleDelta(pt.x0, pt.x1) || Math.PI, Math.PI);
pt.ring = 1 - pt.rpx0 / pt.rpx1;
pt.rInscribed = getInscribedRadiusFraction(pt, trace);
if (hasTransition) {
slicePath.transition().attrTween('d', function (pt2) {
var interp = makeUpdateSliceInterpolator(pt2);
return function (t) {
return pathSlice(interp(t));
};
});
} else {
slicePath.attr('d', pathSlice);
}
sliceTop.call(attachFxHandlers, entry, gd, cd, {
eventDataKeys: constants.eventDataKeys,
transitionTime: constants.CLICK_TRANSITION_TIME,
transitionEasing: constants.CLICK_TRANSITION_EASING
}).call(helpers.setSliceCursor, gd, {
hideOnRoot: true,
hideOnLeaves: true,
isTransitioning: gd._transitioning
});
slicePath.call(styleOne, pt, trace, gd);
var sliceTextGroup = Lib.ensureSingle(sliceTop, 'g', 'slicetext');
var sliceText = Lib.ensureSingle(sliceTextGroup, 'text', '', function (s) {
// prohibit tex interpretation until we can handle
// tex and regular text together
s.attr('data-notex', 1);
});
var font = Lib.ensureUniformFontSize(gd, helpers.determineTextFont(trace, pt, fullLayout.font));
sliceText.text(exports.formatSliceLabel(pt, entry, trace, cd, fullLayout)).classed('slicetext', true).attr('text-anchor', 'middle').call(Drawing.font, font).call(svgTextUtils.convertToTspans, gd);
// position the text relative to the slice
var textBB = Drawing.bBox(sliceText.node());
pt.transform = transformInsideText(textBB, pt, cd0);
pt.transform.targetX = getTargetX(pt);
pt.transform.targetY = getTargetY(pt);
var strTransform = function (d, textBB) {
var transform = d.transform;
computeTransform(transform, textBB);
transform.fontSize = font.size;
recordMinTextSize(trace.type, transform, fullLayout);
return Lib.getTextTransform(transform);
};
if (hasTransition) {
sliceText.transition().attrTween('transform', function (pt2) {
var interp = makeUpdateTextInterpolator(pt2);
return function (t) {
return strTransform(interp(t), textBB);
};
});
} else {
sliceText.attr('transform', strTransform(pt, textBB));
}
});
function makeExitSliceInterpolator(pt) {
var id = helpers.getPtId(pt);
var prev = prevLookup[id];
var entryPrev = prevLookup[helpers.getPtId(entry)];
var next;
if (entryPrev) {
var a = (pt.x1 > entryPrev.x1 ? 2 * Math.PI : 0) + baseX;
// if pt to remove:
// - if 'below' where the root-node used to be: shrink it radially inward
// - otherwise, collapse it clockwise or counterclockwise which ever is shortest to theta=0
next = pt.rpx1 < entryPrev.rpx1 ? {
x0: pt.x0,
x1: pt.x1,
rpx0: 0,
rpx1: 0
} : {
x0: a,
x1: a,
rpx0: pt.rpx0,
rpx1: pt.rpx1
};
} else {
// this happens when maxdepth is set, when leaves must
// be removed and the rootPt is new (i.e. does not have a 'prev' object)
var parent;
var parentId = helpers.getPtId(pt.parent);
slices.each(function (pt2) {
if (helpers.getPtId(pt2) === parentId) {
return parent = pt2;
}
});
var parentChildren = parent.children;
var ci;
parentChildren.forEach(function (pt2, i) {
if (helpers.getPtId(pt2) === id) {
return ci = i;
}
});
var n = parentChildren.length;
var interp = interpolate(parent.x0, parent.x1);
next = {
rpx0: rMax,
rpx1: rMax,
x0: interp(ci / n),
x1: interp((ci + 1) / n)
};
}
return interpolate(prev, next);
}
function makeUpdateSliceInterpolator(pt) {
var prev0 = prevLookup[helpers.getPtId(pt)];
var prev;
var next = {
x0: pt.x0,
x1: pt.x1,
rpx0: pt.rpx0,
rpx1: pt.rpx1
};
if (prev0) {
// if pt already on graph, this is easy
prev = prev0;
} else {
// for new pts:
if (prevEntry) {
// if trace was visible before
if (pt.parent) {
if (nextX1ofPrevEntry) {
// if new branch, twist it in clockwise or
// counterclockwise which ever is shorter to
// its final angle
var a = (pt.x1 > nextX1ofPrevEntry ? 2 * Math.PI : 0) + baseX;
prev = {
x0: a,
x1: a
};
} else {
// if new leaf (when maxdepth is set),
// grow it radially and angularly from
// its parent node
prev = {
rpx0: rMax,
rpx1: rMax
};
Lib.extendFlat(prev, interpX0X1FromParent(pt));
}
} else {
// if new root-node, grow it radially
prev = {
rpx0: 0,
rpx1: 0
};
}
} else {
// start sector of new traces from theta=0
prev = {
x0: baseX,
x1: baseX
};
}
}
return interpolate(prev, next);
}
function makeUpdateTextInterpolator(pt) {
var prev0 = prevLookup[helpers.getPtId(pt)];
var prev;
var transform = pt.transform;
if (prev0) {
prev = prev0;
} else {
prev = {
rpx1: pt.rpx1,
transform: {
textPosAngle: transform.textPosAngle,
scale: 0,
rotate: transform.rotate,
rCenter: transform.rCenter,
x: transform.x,
y: transform.y
}
};
// for new pts:
if (prevEntry) {
// if trace was visible before
if (pt.parent) {
if (nextX1ofPrevEntry) {
// if new branch, twist it in clockwise or
// counterclockwise which ever is shorter to
// its final angle
var a = pt.x1 > nextX1ofPrevEntry ? 2 * Math.PI : 0;
prev.x0 = prev.x1 = a;
} else {
// if leaf
Lib.extendFlat(prev, interpX0X1FromParent(pt));
}
} else {
// if new root-node
prev.x0 = prev.x1 = baseX;
}
} else {
// on new traces
prev.x0 = prev.x1 = baseX;
}
}
var textPosAngleFn = interpolate(prev.transform.textPosAngle, pt.transform.textPosAngle);
var rpx1Fn = interpolate(prev.rpx1, pt.rpx1);
var x0Fn = interpolate(prev.x0, pt.x0);
var x1Fn = interpolate(prev.x1, pt.x1);
var scaleFn = interpolate(prev.transform.scale, transform.scale);
var rotateFn = interpolate(prev.transform.rotate, transform.rotate);
// smooth out start/end from entry, to try to keep text inside sector
// while keeping transition smooth
var pow = transform.rCenter === 0 ? 3 : prev.transform.rCenter === 0 ? 1 / 3 : 1;
var _rCenterFn = interpolate(prev.transform.rCenter, transform.rCenter);
var rCenterFn = function (t) {
return _rCenterFn(Math.pow(t, pow));
};
return function (t) {
var rpx1 = rpx1Fn(t);
var x0 = x0Fn(t);
var x1 = x1Fn(t);
var rCenter = rCenterFn(t);
var pxmid = rx2px(rpx1, (x0 + x1) / 2);
var textPosAngle = textPosAngleFn(t);
var d = {
pxmid: pxmid,
rpx1: rpx1,
transform: {
textPosAngle: textPosAngle,
rCenter: rCenter,
x: transform.x,
y: transform.y
}
};
recordMinTextSize(trace.type, transform, fullLayout);
return {
transform: {
targetX: getTargetX(d),
targetY: getTargetY(d),
scale: scaleFn(t),
rotate: rotateFn(t),
rCenter: rCenter
}
};
};
}
function interpX0X1FromParent(pt) {
var parent = pt.parent;
var parentPrev = prevLookup[helpers.getPtId(parent)];
var out = {};
if (parentPrev) {
// if parent is visible
var parentChildren = parent.children;
var ci = parentChildren.indexOf(pt);
var n = parentChildren.length;
var interp = interpolate(parentPrev.x0, parentPrev.x1);
out.x0 = interp(ci / n);
out.x1 = interp(ci / n);
} else {
// w/o visible parent
// TODO !!! HOW ???
out.x0 = out.x1 = 0;
}
return out;
}
}
// x[0-1] keys are angles [radians]
// y[0-1] keys are hierarchy heights [integers]
function partition(entry) {
return d3Hierarchy.partition().size([2 * Math.PI, entry.height + 1])(entry);
}
exports.formatSliceLabel = function (pt, entry, trace, cd, fullLayout) {
var texttemplate = trace.texttemplate;
var textinfo = trace.textinfo;
if (!texttemplate && (!textinfo || textinfo === 'none')) {
return '';
}
var separators = fullLayout.separators;
var cd0 = cd[0];
var cdi = pt.data.data;
var hierarchy = cd0.hierarchy;
var isRoot = helpers.isHierarchyRoot(pt);
var parent = helpers.getParent(hierarchy, pt);
var val = helpers.getValue(pt);
if (!texttemplate) {
var parts = textinfo.split('+');
var hasFlag = function (flag) {
return parts.indexOf(flag) !== -1;
};
var thisText = [];
var tx;
if (hasFlag('label') && cdi.label) {
thisText.push(cdi.label);
}
if (cdi.hasOwnProperty('v') && hasFlag('value')) {
thisText.push(helpers.formatValue(cdi.v, separators));
}
if (!isRoot) {
if (hasFlag('current path')) {
thisText.push(helpers.getPath(pt.data));
}
var nPercent = 0;
if (hasFlag('percent parent')) nPercent++;
if (hasFlag('percent entry')) nPercent++;
if (hasFlag('percent root')) nPercent++;
var hasMultiplePercents = nPercent > 1;
if (nPercent) {
var percent;
var addPercent = function (key) {
tx = helpers.formatPercent(percent, separators);
if (hasMultiplePercents) tx += ' of ' + key;
thisText.push(tx);
};
if (hasFlag('percent parent') && !isRoot) {
percent = val / helpers.getValue(parent);
addPercent('parent');
}
if (hasFlag('percent entry')) {
percent = val / helpers.getValue(entry);
addPercent('entry');
}
if (hasFlag('percent root')) {
percent = val / helpers.getValue(hierarchy);
addPercent('root');
}
}
}
if (hasFlag('text')) {
tx = Lib.castOption(trace, cdi.i, 'text');
if (Lib.isValidTextValue(tx)) thisText.push(tx);
}
return thisText.join('
');
}
var txt = Lib.castOption(trace, cdi.i, 'texttemplate');
if (!txt) return '';
var obj = {};
if (cdi.label) obj.label = cdi.label;
if (cdi.hasOwnProperty('v')) {
obj.value = cdi.v;
obj.valueLabel = helpers.formatValue(cdi.v, separators);
}
obj.currentPath = helpers.getPath(pt.data);
if (!isRoot) {
obj.percentParent = val / helpers.getValue(parent);
obj.percentParentLabel = helpers.formatPercent(obj.percentParent, separators);
obj.parent = helpers.getPtLabel(parent);
}
obj.percentEntry = val / helpers.getValue(entry);
obj.percentEntryLabel = helpers.formatPercent(obj.percentEntry, separators);
obj.entry = helpers.getPtLabel(entry);
obj.percentRoot = val / helpers.getValue(hierarchy);
obj.percentRootLabel = helpers.formatPercent(obj.percentRoot, separators);
obj.root = helpers.getPtLabel(hierarchy);
if (cdi.hasOwnProperty('color')) {
obj.color = cdi.color;
}
var ptTx = Lib.castOption(trace, cdi.i, 'text');
if (Lib.isValidTextValue(ptTx) || ptTx === '') obj.text = ptTx;
obj.customdata = Lib.castOption(trace, cdi.i, 'customdata');
return Lib.texttemplateString(txt, obj, fullLayout._d3locale, obj, trace._meta || {});
};
function getInscribedRadiusFraction(pt) {
if (pt.rpx0 === 0 && Lib.isFullCircle([pt.x0, pt.x1])) {
// special case of 100% with no hole
return 1;
} else {
return Math.max(0, Math.min(1 / (1 + 1 / Math.sin(pt.halfangle)), pt.ring / 2));
}
}
function getTextXY(d) {
return getCoords(d.rpx1, d.transform.textPosAngle);
}
function getCoords(r, angle) {
return [r * Math.sin(angle), -r * Math.cos(angle)];
}
/***/ }),
/***/ 74468:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Color = __webpack_require__(9240);
var Lib = __webpack_require__(10923);
var resizeText = (__webpack_require__(4096).resizeText);
var fillOne = __webpack_require__(81136);
function style(gd) {
var s = gd._fullLayout._sunburstlayer.selectAll('.trace');
resizeText(gd, s, 'sunburst');
s.each(function (cd) {
var gTrace = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
gTrace.style('opacity', trace.opacity);
gTrace.selectAll('path.surface').each(function (pt) {
d3.select(this).call(styleOne, pt, trace, gd);
});
});
}
function styleOne(s, pt, trace, gd) {
var cdi = pt.data.data;
var isLeaf = !pt.children;
var ptNumber = cdi.i;
var lineColor = Lib.castOption(trace, ptNumber, 'marker.line.color') || Color.defaultLine;
var lineWidth = Lib.castOption(trace, ptNumber, 'marker.line.width') || 0;
s.call(fillOne, pt, trace, gd).style('stroke-width', lineWidth).call(Color.stroke, lineColor).style('opacity', isLeaf ? trace.leaf.opacity : null);
}
module.exports = {
style: style,
styleOne: styleOne
};
/***/ }),
/***/ 32004:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Color = __webpack_require__(9240);
var colorScaleAttrs = __webpack_require__(99732);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var baseAttrs = __webpack_require__(6040);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
function makeContourProjAttr(axLetter) {
return {
valType: 'boolean',
dflt: false,
description: ['Determines whether or not these contour lines are projected', 'on the', axLetter, 'plane.', 'If `highlight` is set to *true* (the default), the projected', 'lines are shown on hover.', 'If `show` is set to *true*, the projected lines are shown', 'in permanence.'].join(' ')
};
}
function makeContourAttr(axLetter) {
return {
show: {
valType: 'boolean',
dflt: false,
description: ['Determines whether or not contour lines about the', axLetter, 'dimension are drawn.'].join(' ')
},
start: {
valType: 'number',
dflt: null,
editType: 'plot',
// impliedEdits: {'^autocontour': false},
description: ['Sets the starting contour level value.', 'Must be less than `contours.end`'].join(' ')
},
end: {
valType: 'number',
dflt: null,
editType: 'plot',
// impliedEdits: {'^autocontour': false},
description: ['Sets the end contour level value.', 'Must be more than `contours.start`'].join(' ')
},
size: {
valType: 'number',
dflt: null,
min: 0,
editType: 'plot',
// impliedEdits: {'^autocontour': false},
description: ['Sets the step between each contour level.', 'Must be positive.'].join(' ')
},
project: {
x: makeContourProjAttr('x'),
y: makeContourProjAttr('y'),
z: makeContourProjAttr('z')
},
color: {
valType: 'color',
dflt: Color.defaultLine,
description: 'Sets the color of the contour lines.'
},
usecolormap: {
valType: 'boolean',
dflt: false,
description: ['An alternate to *color*.', 'Determines whether or not the contour lines are colored using', 'the trace *colorscale*.'].join(' ')
},
width: {
valType: 'number',
min: 1,
max: 16,
dflt: 2,
description: 'Sets the width of the contour lines.'
},
highlight: {
valType: 'boolean',
dflt: true,
description: ['Determines whether or not contour lines about the', axLetter, 'dimension are highlighted on hover.'].join(' ')
},
highlightcolor: {
valType: 'color',
dflt: Color.defaultLine,
description: 'Sets the color of the highlighted contour lines.'
},
highlightwidth: {
valType: 'number',
min: 1,
max: 16,
dflt: 2,
description: 'Sets the width of the highlighted contour lines.'
}
};
}
var attrs = module.exports = overrideAll(extendFlat({
z: {
valType: 'data_array',
description: 'Sets the z coordinates.'
},
x: {
valType: 'data_array',
description: 'Sets the x coordinates.'
},
y: {
valType: 'data_array',
description: 'Sets the y coordinates.'
},
text: {
valType: 'string',
dflt: '',
arrayOk: true,
description: ['Sets the text elements associated with each z value.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.'].join(' ')
},
hovertext: {
valType: 'string',
dflt: '',
arrayOk: true,
description: 'Same as `text`.'
},
hovertemplate: hovertemplateAttrs(),
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
zhoverformat: axisHoverFormat('z'),
connectgaps: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['Determines whether or not gaps', '(i.e. {nan} or missing values)', 'in the `z` data are filled in.'].join(' ')
},
surfacecolor: {
valType: 'data_array',
description: ['Sets the surface color values,', 'used for setting a color scale independent of `z`.'].join(' ')
}
}, colorScaleAttrs('', {
colorAttr: 'z or surfacecolor',
showScaleDflt: true,
autoColorDflt: false,
editTypeOverride: 'calc'
}), {
contours: {
x: makeContourAttr('x'),
y: makeContourAttr('y'),
z: makeContourAttr('z')
},
hidesurface: {
valType: 'boolean',
dflt: false,
description: ['Determines whether or not a surface is drawn.', 'For example, set `hidesurface` to *false*', '`contours.x.show` to *true* and', '`contours.y.show` to *true* to draw a wire frame plot.'].join(' ')
},
lightposition: {
x: {
valType: 'number',
min: -1e5,
max: 1e5,
dflt: 10,
description: 'Numeric vector, representing the X coordinate for each vertex.'
},
y: {
valType: 'number',
min: -1e5,
max: 1e5,
dflt: 1e4,
description: 'Numeric vector, representing the Y coordinate for each vertex.'
},
z: {
valType: 'number',
min: -1e5,
max: 1e5,
dflt: 0,
description: 'Numeric vector, representing the Z coordinate for each vertex.'
}
},
lighting: {
ambient: {
valType: 'number',
min: 0.00,
max: 1.0,
dflt: 0.8,
description: 'Ambient light increases overall color visibility but can wash out the image.'
},
diffuse: {
valType: 'number',
min: 0.00,
max: 1.00,
dflt: 0.8,
description: 'Represents the extent that incident rays are reflected in a range of angles.'
},
specular: {
valType: 'number',
min: 0.00,
max: 2.00,
dflt: 0.05,
description: 'Represents the level that incident rays are reflected in a single direction, causing shine.'
},
roughness: {
valType: 'number',
min: 0.00,
max: 1.00,
dflt: 0.5,
description: 'Alters specular reflection; the rougher the surface, the wider and less contrasty the shine.'
},
fresnel: {
valType: 'number',
min: 0.00,
max: 5.00,
dflt: 0.2,
description: ['Represents the reflectance as a dependency of the viewing angle; e.g. paper is reflective', 'when viewing it from the edge of the paper (almost 90 degrees), causing shine.'].join(' ')
}
},
opacity: {
valType: 'number',
min: 0,
max: 1,
dflt: 1,
description: ['Sets the opacity of the surface.', 'Please note that in the case of using high `opacity` values for example a value', 'greater than or equal to 0.5 on two surfaces (and 0.25 with four surfaces), an', 'overlay of multiple transparent surfaces may not perfectly be sorted in depth by the', 'webgl API. This behavior may be improved in the near future and is subject to change.'].join(' ')
},
opacityscale: {
valType: 'any',
editType: 'calc',
description: ['Sets the opacityscale.', 'The opacityscale must be an array containing', 'arrays mapping a normalized value to an opacity value.', 'At minimum, a mapping for the lowest (0) and highest (1)', 'values are required. For example,', '`[[0, 1], [0.5, 0.2], [1, 1]]` means that higher/lower values would have', 'higher opacity values and those in the middle would be more transparent', 'Alternatively, `opacityscale` may be a palette name string', 'of the following list: \'min\', \'max\', \'extremes\' and \'uniform\'.', 'The default is \'uniform\'.'].join(' ')
},
_deprecated: {
zauto: extendFlat({}, colorScaleAttrs.zauto, {
description: 'Obsolete. Use `cauto` instead.'
}),
zmin: extendFlat({}, colorScaleAttrs.zmin, {
description: 'Obsolete. Use `cmin` instead.'
}),
zmax: extendFlat({}, colorScaleAttrs.zmax, {
description: 'Obsolete. Use `cmax` instead.'
})
},
hoverinfo: extendFlat({}, baseAttrs.hoverinfo),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
}), 'calc', 'nested');
attrs.x.editType = attrs.y.editType = attrs.z.editType = 'calc+clearAxisTypes';
attrs.transforms = undefined;
/***/ }),
/***/ 29016:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorscaleCalc = __webpack_require__(60416);
// Compute auto-z and autocolorscale if applicable
module.exports = function calc(gd, trace) {
if (trace.surfacecolor) {
colorscaleCalc(gd, trace, {
vals: trace.surfacecolor,
containerStr: '',
cLetter: 'c'
});
} else {
colorscaleCalc(gd, trace, {
vals: trace.z,
containerStr: '',
cLetter: 'c'
});
}
};
/***/ }),
/***/ 52712:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createSurface = (__webpack_require__(14656).gl_surface3d);
var ndarray = (__webpack_require__(14656).ndarray);
var ndarrayInterp2d = (__webpack_require__(14656).ndarray_linear_interpolate).d2;
var interp2d = __webpack_require__(5912);
var findEmpties = __webpack_require__(4648);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var parseColorScale = (__webpack_require__(13396).parseColorScale);
var str2RgbaArray = __webpack_require__(29864);
var extractOpts = (__webpack_require__(26733).extractOpts);
function SurfaceTrace(scene, surface, uid) {
this.scene = scene;
this.uid = uid;
this.surface = surface;
this.data = null;
this.showContour = [false, false, false];
this.contourStart = [null, null, null];
this.contourEnd = [null, null, null];
this.contourSize = [0, 0, 0];
this.minValues = [Infinity, Infinity, Infinity];
this.maxValues = [-Infinity, -Infinity, -Infinity];
this.dataScaleX = 1.0;
this.dataScaleY = 1.0;
this.refineData = true;
this.objectOffset = [0, 0, 0];
}
var proto = SurfaceTrace.prototype;
proto.getXat = function (a, b, calendar, axis) {
var v = !isArrayOrTypedArray(this.data.x) ? a : isArrayOrTypedArray(this.data.x[0]) ? this.data.x[b][a] : this.data.x[a];
return calendar === undefined ? v : axis.d2l(v, 0, calendar);
};
proto.getYat = function (a, b, calendar, axis) {
var v = !isArrayOrTypedArray(this.data.y) ? b : isArrayOrTypedArray(this.data.y[0]) ? this.data.y[b][a] : this.data.y[b];
return calendar === undefined ? v : axis.d2l(v, 0, calendar);
};
proto.getZat = function (a, b, calendar, axis) {
var v = this.data.z[b][a];
if (v === null && this.data.connectgaps && this.data._interpolatedZ) {
v = this.data._interpolatedZ[b][a];
}
return calendar === undefined ? v : axis.d2l(v, 0, calendar);
};
proto.handlePick = function (selection) {
if (selection.object === this.surface) {
var xRatio = (selection.data.index[0] - 1) / this.dataScaleX - 1;
var yRatio = (selection.data.index[1] - 1) / this.dataScaleY - 1;
var j = Math.max(Math.min(Math.round(xRatio), this.data.z[0].length - 1), 0);
var k = Math.max(Math.min(Math.round(yRatio), this.data._ylength - 1), 0);
selection.index = [j, k];
selection.traceCoordinate = [this.getXat(j, k), this.getYat(j, k), this.getZat(j, k)];
selection.dataCoordinate = [this.getXat(j, k, this.data.xcalendar, this.scene.fullSceneLayout.xaxis), this.getYat(j, k, this.data.ycalendar, this.scene.fullSceneLayout.yaxis), this.getZat(j, k, this.data.zcalendar, this.scene.fullSceneLayout.zaxis)];
for (var i = 0; i < 3; i++) {
var v = selection.dataCoordinate[i];
if (v !== null && v !== undefined) {
selection.dataCoordinate[i] *= this.scene.dataScale[i];
}
}
var text = this.data.hovertext || this.data.text;
if (isArrayOrTypedArray(text) && text[k] && text[k][j] !== undefined) {
selection.textLabel = text[k][j];
} else if (text) {
selection.textLabel = text;
} else {
selection.textLabel = '';
}
selection.data.dataCoordinate = selection.dataCoordinate.slice();
this.surface.highlight(selection.data);
// Snap spikes to data coordinate
this.scene.glplot.spikes.position = selection.dataCoordinate;
return true;
}
};
function isColormapCircular(colormap) {
var first = colormap[0].rgb;
var last = colormap[colormap.length - 1].rgb;
return first[0] === last[0] && first[1] === last[1] && first[2] === last[2] && first[3] === last[3];
}
var shortPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999];
function getPow(a, b) {
if (a < b) return 0;
var n = 0;
while (Math.floor(a % b) === 0) {
a /= b;
n++;
}
return n;
}
function getFactors(a) {
var powers = [];
for (var i = 0; i < shortPrimes.length; i++) {
var b = shortPrimes[i];
powers.push(getPow(a, b));
}
return powers;
}
function smallestDivisor(a) {
var A = getFactors(a);
var result = a;
for (var i = 0; i < shortPrimes.length; i++) {
if (A[i] > 0) {
result = shortPrimes[i];
break;
}
}
return result;
}
function leastCommonMultiple(a, b) {
if (a < 1 || b < 1) return undefined;
var A = getFactors(a);
var B = getFactors(b);
var n = 1;
for (var i = 0; i < shortPrimes.length; i++) {
n *= Math.pow(shortPrimes[i], Math.max(A[i], B[i]));
}
return n;
}
function arrayLCM(A) {
if (A.length === 0) return undefined;
var n = 1;
for (var i = 0; i < A.length; i++) {
n = leastCommonMultiple(n, A[i]);
}
return n;
}
proto.calcXnums = function (xlen) {
var i;
var nums = [];
for (i = 1; i < xlen; i++) {
var a = this.getXat(i - 1, 0);
var b = this.getXat(i, 0);
if (b !== a && a !== undefined && a !== null && b !== undefined && b !== null) {
nums[i - 1] = Math.abs(b - a);
} else {
nums[i - 1] = 0;
}
}
var totalDist = 0;
for (i = 1; i < xlen; i++) {
totalDist += nums[i - 1];
}
for (i = 1; i < xlen; i++) {
if (nums[i - 1] === 0) {
nums[i - 1] = 1;
} else {
nums[i - 1] = Math.round(totalDist / nums[i - 1]);
}
}
return nums;
};
proto.calcYnums = function (ylen) {
var i;
var nums = [];
for (i = 1; i < ylen; i++) {
var a = this.getYat(0, i - 1);
var b = this.getYat(0, i);
if (b !== a && a !== undefined && a !== null && b !== undefined && b !== null) {
nums[i - 1] = Math.abs(b - a);
} else {
nums[i - 1] = 0;
}
}
var totalDist = 0;
for (i = 1; i < ylen; i++) {
totalDist += nums[i - 1];
}
for (i = 1; i < ylen; i++) {
if (nums[i - 1] === 0) {
nums[i - 1] = 1;
} else {
nums[i - 1] = Math.round(totalDist / nums[i - 1]);
}
}
return nums;
};
var highlyComposites = [1, 2, 4, 6, 12, 24, 36, 48, 60, 120, 180, 240, 360, 720, 840, 1260];
var MIN_RESOLUTION = highlyComposites[9];
var MAX_RESOLUTION = highlyComposites[13];
proto.estimateScale = function (resSrc, axis) {
var nums = axis === 0 ? this.calcXnums(resSrc) : this.calcYnums(resSrc);
var resDst = 1 + arrayLCM(nums);
while (resDst < MIN_RESOLUTION) {
resDst *= 2;
}
while (resDst > MAX_RESOLUTION) {
resDst--;
resDst /= smallestDivisor(resDst);
resDst++;
if (resDst < MIN_RESOLUTION) {
// resDst = MIN_RESOLUTION; // option 1: use min resolution
resDst = MAX_RESOLUTION; // option 2: use max resolution
}
}
var scale = Math.round(resDst / resSrc);
return scale > 1 ? scale : 1;
};
// based on Mikola Lysenko's ndarray-homography
// see https://github.com/scijs/ndarray-homography
function fnHomography(out, inp, X) {
var w = X[8] + X[2] * inp[0] + X[5] * inp[1];
out[0] = (X[6] + X[0] * inp[0] + X[3] * inp[1]) / w;
out[1] = (X[7] + X[1] * inp[0] + X[4] * inp[1]) / w;
return out;
}
function homography(dest, src, X) {
warp(dest, src, fnHomography, X);
return dest;
}
// based on Mikola Lysenko's ndarray-warp
// see https://github.com/scijs/ndarray-warp
function warp(dest, src, func, X) {
var warped = [0, 0];
var ni = dest.shape[0];
var nj = dest.shape[1];
for (var i = 0; i < ni; i++) {
for (var j = 0; j < nj; j++) {
func(warped, [i, j], X);
dest.set(i, j, ndarrayInterp2d(src, warped[0], warped[1]));
}
}
return dest;
}
proto.refineCoords = function (coords) {
var scaleW = this.dataScaleX;
var scaleH = this.dataScaleY;
var width = coords[0].shape[0];
var height = coords[0].shape[1];
var newWidth = Math.floor(coords[0].shape[0] * scaleW + 1) | 0;
var newHeight = Math.floor(coords[0].shape[1] * scaleH + 1) | 0;
// Pad coords by +1
var padWidth = 1 + width + 1;
var padHeight = 1 + height + 1;
var padImg = ndarray(new Float32Array(padWidth * padHeight), [padWidth, padHeight]);
var X = [1 / scaleW, 0, 0, 0, 1 / scaleH, 0, 0, 0, 1];
for (var i = 0; i < coords.length; ++i) {
this.surface.padField(padImg, coords[i]);
var scaledImg = ndarray(new Float32Array(newWidth * newHeight), [newWidth, newHeight]);
homography(scaledImg, padImg, X);
coords[i] = scaledImg;
}
};
function insertIfNewLevel(arr, newValue) {
var found = false;
for (var k = 0; k < arr.length; k++) {
if (newValue === arr[k]) {
found = true;
break;
}
}
if (found === false) arr.push(newValue);
}
proto.setContourLevels = function () {
var newLevels = [[], [], []];
var useNewLevels = [false, false, false];
var needsUpdate = false;
var i, j, value;
for (i = 0; i < 3; ++i) {
if (this.showContour[i]) {
needsUpdate = true;
if (this.contourSize[i] > 0 && this.contourStart[i] !== null && this.contourEnd[i] !== null && this.contourEnd[i] > this.contourStart[i]) {
useNewLevels[i] = true;
for (j = this.contourStart[i]; j < this.contourEnd[i]; j += this.contourSize[i]) {
value = j * this.scene.dataScale[i];
insertIfNewLevel(newLevels[i], value);
}
}
}
}
if (needsUpdate) {
var allLevels = [[], [], []];
for (i = 0; i < 3; ++i) {
if (this.showContour[i]) {
allLevels[i] = useNewLevels[i] ? newLevels[i] : this.scene.contourLevels[i];
}
}
this.surface.update({
levels: allLevels
});
}
};
proto.update = function (data) {
var scene = this.scene;
var sceneLayout = scene.fullSceneLayout;
var surface = this.surface;
var colormap = parseColorScale(data);
var scaleFactor = scene.dataScale;
var xlen = data.z[0].length;
var ylen = data._ylength;
var contourLevels = scene.contourLevels;
// Save data
this.data = data;
/*
* Fill and transpose zdata.
* Consistent with 'heatmap' and 'contour', plotly 'surface'
* 'z' are such that sub-arrays correspond to y-coords
* and that the sub-array entries correspond to a x-coords,
* which is the transpose of 'gl-surface-plot'.
*/
var i, j, k, v;
var rawCoords = [];
for (i = 0; i < 3; i++) {
rawCoords[i] = [];
for (j = 0; j < xlen; j++) {
rawCoords[i][j] = [];
/*
for(k = 0; k < ylen; k++) {
rawCoords[i][j][k] = undefined;
}
*/
}
}
// coords x, y & z
for (j = 0; j < xlen; j++) {
for (k = 0; k < ylen; k++) {
rawCoords[0][j][k] = this.getXat(j, k, data.xcalendar, sceneLayout.xaxis);
rawCoords[1][j][k] = this.getYat(j, k, data.ycalendar, sceneLayout.yaxis);
rawCoords[2][j][k] = this.getZat(j, k, data.zcalendar, sceneLayout.zaxis);
}
}
if (data.connectgaps) {
data._emptypoints = findEmpties(rawCoords[2]);
interp2d(rawCoords[2], data._emptypoints);
data._interpolatedZ = [];
for (j = 0; j < xlen; j++) {
data._interpolatedZ[j] = [];
for (k = 0; k < ylen; k++) {
data._interpolatedZ[j][k] = rawCoords[2][j][k];
}
}
}
// Note: log axes are not defined in surfaces yet.
// but they could be defined here...
for (i = 0; i < 3; i++) {
for (j = 0; j < xlen; j++) {
for (k = 0; k < ylen; k++) {
v = rawCoords[i][j][k];
if (v === null || v === undefined) {
rawCoords[i][j][k] = NaN;
} else {
v = rawCoords[i][j][k] *= scaleFactor[i];
}
}
}
}
for (i = 0; i < 3; i++) {
for (j = 0; j < xlen; j++) {
for (k = 0; k < ylen; k++) {
v = rawCoords[i][j][k];
if (v !== null && v !== undefined) {
if (this.minValues[i] > v) {
this.minValues[i] = v;
}
if (this.maxValues[i] < v) {
this.maxValues[i] = v;
}
}
}
}
}
for (i = 0; i < 3; i++) {
this.objectOffset[i] = 0.5 * (this.minValues[i] + this.maxValues[i]);
}
for (i = 0; i < 3; i++) {
for (j = 0; j < xlen; j++) {
for (k = 0; k < ylen; k++) {
v = rawCoords[i][j][k];
if (v !== null && v !== undefined) {
rawCoords[i][j][k] -= this.objectOffset[i];
}
}
}
}
// convert processed raw data to Float32 matrices
var coords = [ndarray(new Float32Array(xlen * ylen), [xlen, ylen]), ndarray(new Float32Array(xlen * ylen), [xlen, ylen]), ndarray(new Float32Array(xlen * ylen), [xlen, ylen])];
for (i = 0; i < 3; i++) {
for (j = 0; j < xlen; j++) {
for (k = 0; k < ylen; k++) {
coords[i].set(j, k, rawCoords[i][j][k]);
}
}
}
rawCoords = []; // free memory
var params = {
colormap: colormap,
levels: [[], [], []],
showContour: [true, true, true],
showSurface: !data.hidesurface,
contourProject: [[false, false, false], [false, false, false], [false, false, false]],
contourWidth: [1, 1, 1],
contourColor: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]],
contourTint: [1, 1, 1],
dynamicColor: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]],
dynamicWidth: [1, 1, 1],
dynamicTint: [1, 1, 1],
opacityscale: data.opacityscale,
opacity: data.opacity
};
var cOpts = extractOpts(data);
params.intensityBounds = [cOpts.min, cOpts.max];
// Refine surface color if necessary
if (data.surfacecolor) {
var intensity = ndarray(new Float32Array(xlen * ylen), [xlen, ylen]);
for (j = 0; j < xlen; j++) {
for (k = 0; k < ylen; k++) {
intensity.set(j, k, data.surfacecolor[k][j]);
}
}
coords.push(intensity);
} else {
// when 'z' is used as 'intensity',
// we must scale its value
params.intensityBounds[0] *= scaleFactor[2];
params.intensityBounds[1] *= scaleFactor[2];
}
if (MAX_RESOLUTION < coords[0].shape[0] || MAX_RESOLUTION < coords[0].shape[1]) {
this.refineData = false;
}
if (this.refineData === true) {
this.dataScaleX = this.estimateScale(coords[0].shape[0], 0);
this.dataScaleY = this.estimateScale(coords[0].shape[1], 1);
if (this.dataScaleX !== 1 || this.dataScaleY !== 1) {
this.refineCoords(coords);
}
}
if (data.surfacecolor) {
params.intensity = coords.pop();
}
var highlightEnable = [true, true, true];
var axis = ['x', 'y', 'z'];
for (i = 0; i < 3; ++i) {
var contourParams = data.contours[axis[i]];
highlightEnable[i] = contourParams.highlight;
params.showContour[i] = contourParams.show || contourParams.highlight;
if (!params.showContour[i]) continue;
params.contourProject[i] = [contourParams.project.x, contourParams.project.y, contourParams.project.z];
if (contourParams.show) {
this.showContour[i] = true;
params.levels[i] = contourLevels[i];
surface.highlightColor[i] = params.contourColor[i] = str2RgbaArray(contourParams.color);
if (contourParams.usecolormap) {
surface.highlightTint[i] = params.contourTint[i] = 0;
} else {
surface.highlightTint[i] = params.contourTint[i] = 1;
}
params.contourWidth[i] = contourParams.width;
this.contourStart[i] = contourParams.start;
this.contourEnd[i] = contourParams.end;
this.contourSize[i] = contourParams.size;
} else {
this.showContour[i] = false;
this.contourStart[i] = null;
this.contourEnd[i] = null;
this.contourSize[i] = 0;
}
if (contourParams.highlight) {
params.dynamicColor[i] = str2RgbaArray(contourParams.highlightcolor);
params.dynamicWidth[i] = contourParams.highlightwidth;
}
}
// see https://github.com/plotly/plotly.js/issues/940
if (isColormapCircular(colormap)) {
params.vertexColor = true;
}
params.objectOffset = this.objectOffset;
params.coords = coords;
surface.update(params);
surface.visible = data.visible;
surface.enableDynamic = highlightEnable;
surface.enableHighlight = highlightEnable;
surface.snapToData = true;
if ('lighting' in data) {
surface.ambientLight = data.lighting.ambient;
surface.diffuseLight = data.lighting.diffuse;
surface.specularLight = data.lighting.specular;
surface.roughness = data.lighting.roughness;
surface.fresnel = data.lighting.fresnel;
}
if ('lightposition' in data) {
surface.lightPosition = [data.lightposition.x, data.lightposition.y, data.lightposition.z];
}
};
proto.dispose = function () {
this.scene.glplot.remove(this.surface);
this.surface.dispose();
};
function createSurfaceTrace(scene, data) {
var gl = scene.glplot.gl;
var surface = createSurface({
gl: gl
});
var result = new SurfaceTrace(scene, surface, data.uid);
surface._trace = result;
result.update(data);
scene.glplot.add(surface);
return result;
}
module.exports = createSurfaceTrace;
/***/ }),
/***/ 19127:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Registry = __webpack_require__(30364);
var Lib = __webpack_require__(10923);
var colorscaleDefaults = __webpack_require__(47280);
var attributes = __webpack_require__(32004);
var MIN = 0.1; // Note: often we don't want the data cube to be disappeared
function createWave(n, minOpacity) {
var arr = [];
var steps = 32; // Max: 256
for (var i = 0; i < steps; i++) {
var u = i / (steps - 1);
var v = minOpacity + (1 - minOpacity) * (1 - Math.pow(Math.sin(n * u * Math.PI), 2));
arr.push([u, Math.max(0, Math.min(1, v))]);
}
return arr;
}
function isValidScaleArray(scl) {
var highestVal = 0;
if (!Array.isArray(scl) || scl.length < 2) return false;
if (!scl[0] || !scl[scl.length - 1]) return false;
if (+scl[0][0] !== 0 || +scl[scl.length - 1][0] !== 1) return false;
for (var i = 0; i < scl.length; i++) {
var si = scl[i];
if (si.length !== 2 || +si[0] < highestVal) {
return false;
}
highestVal = +si[0];
}
return true;
}
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
var i, j;
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var x = coerce('x');
var y = coerce('y');
var z = coerce('z');
if (!z || !z.length || (x ? x.length < 1 : false) || (y ? y.length < 1 : false)) {
traceOut.visible = false;
return;
}
traceOut._xlength = Array.isArray(x) && Lib.isArrayOrTypedArray(x[0]) ? z.length : z[0].length;
traceOut._ylength = z.length;
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleTraceDefaults');
handleCalendarDefaults(traceIn, traceOut, ['x', 'y', 'z'], layout);
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
coerce('xhoverformat');
coerce('yhoverformat');
coerce('zhoverformat');
// Coerce remaining properties
['lighting.ambient', 'lighting.diffuse', 'lighting.specular', 'lighting.roughness', 'lighting.fresnel', 'lightposition.x', 'lightposition.y', 'lightposition.z', 'hidesurface', 'connectgaps', 'opacity'].forEach(function (x) {
coerce(x);
});
var surfaceColor = coerce('surfacecolor');
var dims = ['x', 'y', 'z'];
for (i = 0; i < 3; ++i) {
var contourDim = 'contours.' + dims[i];
var show = coerce(contourDim + '.show');
var highlight = coerce(contourDim + '.highlight');
if (show || highlight) {
for (j = 0; j < 3; ++j) {
coerce(contourDim + '.project.' + dims[j]);
}
}
if (show) {
coerce(contourDim + '.color');
coerce(contourDim + '.width');
coerce(contourDim + '.usecolormap');
}
if (highlight) {
coerce(contourDim + '.highlightcolor');
coerce(contourDim + '.highlightwidth');
}
coerce(contourDim + '.start');
coerce(contourDim + '.end');
coerce(contourDim + '.size');
}
// backward compatibility block
if (!surfaceColor) {
mapLegacy(traceIn, 'zmin', 'cmin');
mapLegacy(traceIn, 'zmax', 'cmax');
mapLegacy(traceIn, 'zauto', 'cauto');
}
// TODO if contours.?.usecolormap are false and hidesurface is true
// the colorbar shouldn't be shown by default
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: '',
cLetter: 'c'
});
opacityscaleDefaults(traceIn, traceOut, layout, coerce);
// disable 1D transforms - currently surface does NOT support column data like heatmap does
// you can use mesh3d for this use case, but not surface
traceOut._length = null;
}
function opacityscaleDefaults(traceIn, traceOut, layout, coerce) {
var opacityscale = coerce('opacityscale');
if (opacityscale === 'max') {
traceOut.opacityscale = [[0, MIN], [1, 1]];
} else if (opacityscale === 'min') {
traceOut.opacityscale = [[0, 1], [1, MIN]];
} else if (opacityscale === 'extremes') {
traceOut.opacityscale = createWave(1, MIN);
} else if (!isValidScaleArray(opacityscale)) {
traceOut.opacityscale = undefined;
}
}
function mapLegacy(traceIn, oldAttr, newAttr) {
if (oldAttr in traceIn && !(newAttr in traceIn)) {
traceIn[newAttr] = traceIn[oldAttr];
}
}
module.exports = {
supplyDefaults: supplyDefaults,
opacityscaleDefaults: opacityscaleDefaults
};
/***/ }),
/***/ 7816:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(32004),
supplyDefaults: (__webpack_require__(19127).supplyDefaults),
colorbar: {
min: 'cmin',
max: 'cmax'
},
calc: __webpack_require__(29016),
plot: __webpack_require__(52712),
moduleType: 'trace',
name: 'surface',
basePlotModule: __webpack_require__(26544),
categories: ['gl3d', '2dMap', 'showLegend'],
meta: {
description: ['The data the describes the coordinates of the surface is set in `z`.', 'Data in `z` should be a {2D array}.', 'Coordinates in `x` and `y` can either be 1D {arrays}', 'or {2D arrays} (e.g. to graph parametric surfaces).', 'If not provided in `x` and `y`, the x and y coordinates are assumed', 'to be linear starting at 0 with a unit step.', 'The color scale corresponds to the `z` values by default.', 'For custom color scales, use `surfacecolor` which should be a {2D array},', 'where its bounds can be controlled using `cmin` and `cmax`.'].join(' ')
}
};
/***/ }),
/***/ 80812:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var annAttrs = __webpack_require__(5104);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
var fontAttrs = __webpack_require__(71936);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var descriptionOnlyNumbers = (__webpack_require__(67724).descriptionOnlyNumbers);
var attrs = module.exports = overrideAll({
domain: domainAttrs({
name: 'table',
trace: true
}),
columnwidth: {
valType: 'number',
arrayOk: true,
dflt: null,
description: ['The width of columns expressed as a ratio. Columns fill the available width', 'in proportion of their specified column widths.'].join(' ')
},
columnorder: {
valType: 'data_array',
description: ['Specifies the rendered order of the data columns; for example, a value `2` at position `0`', 'means that column index `0` in the data will be rendered as the', 'third column, as columns have an index base of zero.'].join(' ')
},
header: {
values: {
valType: 'data_array',
dflt: [],
description: ['Header cell values. `values[m][n]` represents the value of the `n`th point in column `m`,', 'therefore the `values[m]` vector length for all columns must be the same (longer vectors', 'will be truncated). Each value must be a finite number or a string.'].join(' ')
},
format: {
valType: 'data_array',
dflt: [],
description: descriptionOnlyNumbers('cell value')
},
prefix: {
valType: 'string',
arrayOk: true,
dflt: null,
description: 'Prefix for cell values.'
},
suffix: {
valType: 'string',
arrayOk: true,
dflt: null,
description: 'Suffix for cell values.'
},
height: {
valType: 'number',
dflt: 28,
description: 'The height of cells.'
},
align: extendFlat({}, annAttrs.align, {
arrayOk: true
}),
line: {
width: {
valType: 'number',
arrayOk: true,
dflt: 1
},
color: {
valType: 'color',
arrayOk: true,
dflt: 'grey'
}
},
fill: {
color: {
valType: 'color',
arrayOk: true,
dflt: 'white',
description: ['Sets the cell fill color. It accepts either a specific color', 'or an array of colors or a 2D array of colors.'].join(' ')
}
},
font: extendFlat({}, fontAttrs({
arrayOk: true
}))
},
cells: {
values: {
valType: 'data_array',
dflt: [],
description: ['Cell values. `values[m][n]` represents the value of the `n`th point in column `m`,', 'therefore the `values[m]` vector length for all columns must be the same (longer vectors', 'will be truncated). Each value must be a finite number or a string.'].join(' ')
},
format: {
valType: 'data_array',
dflt: [],
description: descriptionOnlyNumbers('cell value')
},
prefix: {
valType: 'string',
arrayOk: true,
dflt: null,
description: 'Prefix for cell values.'
},
suffix: {
valType: 'string',
arrayOk: true,
dflt: null,
description: 'Suffix for cell values.'
},
height: {
valType: 'number',
dflt: 20,
description: 'The height of cells.'
},
align: extendFlat({}, annAttrs.align, {
arrayOk: true
}),
line: {
width: {
valType: 'number',
arrayOk: true,
dflt: 1
},
color: {
valType: 'color',
arrayOk: true,
dflt: 'grey'
}
},
fill: {
color: {
valType: 'color',
arrayOk: true,
dflt: 'white',
description: ['Sets the cell fill color. It accepts either a specific color', 'or an array of colors or a 2D array of colors.'].join(' ')
}
},
font: extendFlat({}, fontAttrs({
arrayOk: true
}))
}
}, 'calc', 'from-root');
attrs.transforms = undefined;
/***/ }),
/***/ 25088:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var getModuleCalcData = (__webpack_require__(49824)/* .getModuleCalcData */ ._M);
var tablePlot = __webpack_require__(65424);
var TABLE = 'table';
exports.name = TABLE;
exports.plot = function (gd) {
var calcData = getModuleCalcData(gd.calcdata, TABLE)[0];
if (calcData.length) tablePlot(gd, calcData);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
var hadTable = oldFullLayout._has && oldFullLayout._has(TABLE);
var hasTable = newFullLayout._has && newFullLayout._has(TABLE);
if (hadTable && !hasTable) {
oldFullLayout._paperdiv.selectAll('.table').remove();
}
};
/***/ }),
/***/ 61612:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var wrap = (__webpack_require__(83104).wrap);
module.exports = function calc() {
// we don't actually need to include the trace here, since that will be added
// by Plots.doCalcdata, and that's all we actually need later.
return wrap({});
};
/***/ }),
/***/ 52920:
/***/ (function(module) {
"use strict";
module.exports = {
cellPad: 8,
columnExtentOffset: 10,
columnTitleOffset: 28,
emptyHeaderHeight: 16,
latexCheck: /^\$.*\$$/,
goldenRatio: 1.618,
lineBreaker: '
',
maxDimensionCount: 60,
overdrag: 45,
releaseTransitionDuration: 120,
releaseTransitionEase: 'cubic-out',
scrollbarCaptureWidth: 18,
scrollbarHideDelay: 1000,
scrollbarHideDuration: 1000,
scrollbarOffset: 5,
scrollbarWidth: 8,
transitionDuration: 100,
transitionEase: 'cubic-out',
uplift: 5,
wrapSpacer: ' ',
wrapSplitCharacter: ' ',
cn: {
// general class names
table: 'table',
tableControlView: 'table-control-view',
scrollBackground: 'scroll-background',
yColumn: 'y-column',
columnBlock: 'column-block',
scrollAreaClip: 'scroll-area-clip',
scrollAreaClipRect: 'scroll-area-clip-rect',
columnBoundary: 'column-boundary',
columnBoundaryClippath: 'column-boundary-clippath',
columnBoundaryRect: 'column-boundary-rect',
columnCells: 'column-cells',
columnCell: 'column-cell',
cellRect: 'cell-rect',
cellText: 'cell-text',
cellTextHolder: 'cell-text-holder',
// scroll related class names
scrollbarKit: 'scrollbar-kit',
scrollbar: 'scrollbar',
scrollbarSlider: 'scrollbar-slider',
scrollbarGlyph: 'scrollbar-glyph',
scrollbarCaptureZone: 'scrollbar-capture-zone'
}
};
/***/ }),
/***/ 93968:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var c = __webpack_require__(52920);
var extendFlat = (__webpack_require__(55016).extendFlat);
var isNumeric = __webpack_require__(88120);
var isTypedArray = (__webpack_require__(2764).isTypedArray);
var isArrayOrTypedArray = (__webpack_require__(2764).isArrayOrTypedArray);
// pure functions, don't alter but passes on `gd` and parts of `trace` without deep copying
module.exports = function calc(gd, trace) {
var cellsValues = squareStringMatrix(trace.cells.values);
var slicer = function (a) {
return a.slice(trace.header.values.length, a.length);
};
var headerValuesIn = squareStringMatrix(trace.header.values);
if (headerValuesIn.length && !headerValuesIn[0].length) {
headerValuesIn[0] = [''];
headerValuesIn = squareStringMatrix(headerValuesIn);
}
var headerValues = headerValuesIn.concat(slicer(cellsValues).map(function () {
return emptyStrings((headerValuesIn[0] || ['']).length);
}));
var domain = trace.domain;
var groupWidth = Math.floor(gd._fullLayout._size.w * (domain.x[1] - domain.x[0]));
var groupHeight = Math.floor(gd._fullLayout._size.h * (domain.y[1] - domain.y[0]));
var headerRowHeights = trace.header.values.length ? headerValues[0].map(function () {
return trace.header.height;
}) : [c.emptyHeaderHeight];
var rowHeights = cellsValues.length ? cellsValues[0].map(function () {
return trace.cells.height;
}) : [];
var headerHeight = headerRowHeights.reduce(sum, 0);
var scrollHeight = groupHeight - headerHeight;
var minimumFillHeight = scrollHeight + c.uplift;
var anchorToRowBlock = makeAnchorToRowBlock(rowHeights, minimumFillHeight);
var anchorToHeaderRowBlock = makeAnchorToRowBlock(headerRowHeights, headerHeight);
var headerRowBlocks = makeRowBlock(anchorToHeaderRowBlock, []);
var rowBlocks = makeRowBlock(anchorToRowBlock, headerRowBlocks);
var uniqueKeys = {};
var columnOrder = trace._fullInput.columnorder;
if (isArrayOrTypedArray(columnOrder)) columnOrder = Array.from(columnOrder);
columnOrder = columnOrder.concat(slicer(cellsValues.map(function (d, i) {
return i;
})));
var columnWidths = headerValues.map(function (d, i) {
var value = isArrayOrTypedArray(trace.columnwidth) ? trace.columnwidth[Math.min(i, trace.columnwidth.length - 1)] : trace.columnwidth;
return isNumeric(value) ? Number(value) : 1;
});
var totalColumnWidths = columnWidths.reduce(sum, 0);
// fit columns in the available vertical space as there's no vertical scrolling now
columnWidths = columnWidths.map(function (d) {
return d / totalColumnWidths * groupWidth;
});
var maxLineWidth = Math.max(arrayMax(trace.header.line.width), arrayMax(trace.cells.line.width));
var calcdata = {
// include staticPlot in the key so if it changes we delete and redraw
key: trace.uid + gd._context.staticPlot,
translateX: domain.x[0] * gd._fullLayout._size.w,
translateY: gd._fullLayout._size.h * (1 - domain.y[1]),
size: gd._fullLayout._size,
width: groupWidth,
maxLineWidth: maxLineWidth,
height: groupHeight,
columnOrder: columnOrder,
// will be mutated on column move, todo use in callback
groupHeight: groupHeight,
rowBlocks: rowBlocks,
headerRowBlocks: headerRowBlocks,
scrollY: 0,
// will be mutated on scroll
cells: extendFlat({}, trace.cells, {
values: cellsValues
}),
headerCells: extendFlat({}, trace.header, {
values: headerValues
}),
gdColumns: headerValues.map(function (d) {
return d[0];
}),
gdColumnsOriginalOrder: headerValues.map(function (d) {
return d[0];
}),
prevPages: [0, 0],
scrollbarState: {
scrollbarScrollInProgress: false
},
columns: headerValues.map(function (label, i) {
var foundKey = uniqueKeys[label];
uniqueKeys[label] = (foundKey || 0) + 1;
var key = label + '__' + uniqueKeys[label];
return {
key: key,
label: label,
specIndex: i,
xIndex: columnOrder[i],
xScale: xScale,
x: undefined,
// initialized below
calcdata: undefined,
// initialized below
columnWidth: columnWidths[i]
};
})
};
calcdata.columns.forEach(function (col) {
col.calcdata = calcdata;
col.x = xScale(col);
});
return calcdata;
};
function arrayMax(maybeArray) {
if (isArrayOrTypedArray(maybeArray)) {
var max = 0;
for (var i = 0; i < maybeArray.length; i++) {
max = Math.max(max, arrayMax(maybeArray[i]));
}
return max;
}
return maybeArray;
}
function sum(a, b) {
return a + b;
}
// fill matrix in place to equal lengths
// and ensure it's uniformly 2D
function squareStringMatrix(matrixIn) {
var matrix = matrixIn.slice();
var minLen = Infinity;
var maxLen = 0;
var i;
for (i = 0; i < matrix.length; i++) {
if (isTypedArray(matrix[i])) matrix[i] = Array.from(matrix[i]);else if (!isArrayOrTypedArray(matrix[i])) matrix[i] = [matrix[i]];
minLen = Math.min(minLen, matrix[i].length);
maxLen = Math.max(maxLen, matrix[i].length);
}
if (minLen !== maxLen) {
for (i = 0; i < matrix.length; i++) {
var padLen = maxLen - matrix[i].length;
if (padLen) matrix[i] = matrix[i].concat(emptyStrings(padLen));
}
}
return matrix;
}
function emptyStrings(len) {
var padArray = new Array(len);
for (var j = 0; j < len; j++) padArray[j] = '';
return padArray;
}
function xScale(d) {
return d.calcdata.columns.reduce(function (prev, next) {
return next.xIndex < d.xIndex ? prev + next.columnWidth : prev;
}, 0);
}
function makeRowBlock(anchorToRowBlock, auxiliary) {
var blockAnchorKeys = Object.keys(anchorToRowBlock);
return blockAnchorKeys.map(function (k) {
return extendFlat({}, anchorToRowBlock[k], {
auxiliaryBlocks: auxiliary
});
});
}
function makeAnchorToRowBlock(rowHeights, minimumFillHeight) {
var anchorToRowBlock = {};
var currentRowHeight;
var currentAnchor = 0;
var currentBlockHeight = 0;
var currentBlock = makeIdentity();
var currentFirstRowIndex = 0;
var blockCounter = 0;
for (var i = 0; i < rowHeights.length; i++) {
currentRowHeight = rowHeights[i];
currentBlock.rows.push({
rowIndex: i,
rowHeight: currentRowHeight
});
currentBlockHeight += currentRowHeight;
if (currentBlockHeight >= minimumFillHeight || i === rowHeights.length - 1) {
anchorToRowBlock[currentAnchor] = currentBlock;
currentBlock.key = blockCounter++;
currentBlock.firstRowIndex = currentFirstRowIndex;
currentBlock.lastRowIndex = i;
currentBlock = makeIdentity();
currentAnchor += currentBlockHeight;
currentFirstRowIndex = i + 1;
currentBlockHeight = 0;
}
}
return anchorToRowBlock;
}
function makeIdentity() {
return {
firstRowIndex: null,
lastRowIndex: null,
rows: []
};
}
/***/ }),
/***/ 28660:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var extendFlat = (__webpack_require__(55016).extendFlat);
// pure functions, don't alter but passes on `gd` and parts of `trace` without deep copying
exports.splitToPanels = function (d) {
var prevPages = [0, 0];
var headerPanel = extendFlat({}, d, {
key: 'header',
type: 'header',
page: 0,
prevPages: prevPages,
currentRepaint: [null, null],
dragHandle: true,
values: d.calcdata.headerCells.values[d.specIndex],
rowBlocks: d.calcdata.headerRowBlocks,
calcdata: extendFlat({}, d.calcdata, {
cells: d.calcdata.headerCells
})
});
var revolverPanel1 = extendFlat({}, d, {
key: 'cells1',
type: 'cells',
page: 0,
prevPages: prevPages,
currentRepaint: [null, null],
dragHandle: false,
values: d.calcdata.cells.values[d.specIndex],
rowBlocks: d.calcdata.rowBlocks
});
var revolverPanel2 = extendFlat({}, d, {
key: 'cells2',
type: 'cells',
page: 1,
prevPages: prevPages,
currentRepaint: [null, null],
dragHandle: false,
values: d.calcdata.cells.values[d.specIndex],
rowBlocks: d.calcdata.rowBlocks
});
// order due to SVG using painter's algo:
return [revolverPanel1, revolverPanel2, headerPanel];
};
exports.splitToCells = function (d) {
var fromTo = rowFromTo(d);
return (d.values || []).slice(fromTo[0], fromTo[1]).map(function (v, i) {
// By keeping identical key, a DOM node removal, creation and addition is spared, important when visible
// grid has a lot of elements (quadratic with xcol/ycol count).
// But it has to be busted when `svgUtil.convertToTspans` is used as it reshapes cell subtrees asynchronously,
// and by that time the user may have scrolled away, resulting in stale overwrites. The real solution will be
// to turn `svgUtil.convertToTspans` into a cancelable request, in which case no key busting is needed.
var buster = typeof v === 'string' && v.match(/[<$&> ]/) ? '_keybuster_' + Math.random() : '';
return {
// keyWithinBlock: /*fromTo[0] + */i, // optimized future version - no busting
// keyWithinBlock: fromTo[0] + i, // initial always-unoptimized version - janky scrolling with 5+ columns
keyWithinBlock: i + buster,
// current compromise: regular content is very fast; async content is possible
key: fromTo[0] + i,
column: d,
calcdata: d.calcdata,
page: d.page,
rowBlocks: d.rowBlocks,
value: v
};
});
};
function rowFromTo(d) {
var rowBlock = d.rowBlocks[d.page];
// fixme rowBlock truthiness check is due to ugly hack of placing 2nd panel as d.page = -1
var rowFrom = rowBlock ? rowBlock.rows[0].rowIndex : 0;
var rowTo = rowBlock ? rowFrom + rowBlock.rows.length : 0;
return [rowFrom, rowTo];
}
/***/ }),
/***/ 41696:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(80812);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
function defaultColumnOrder(traceOut, coerce) {
var specifiedColumnOrder = traceOut.columnorder || [];
var commonLength = traceOut.header.values.length;
var truncated = specifiedColumnOrder.slice(0, commonLength);
var sorted = truncated.slice().sort(function (a, b) {
return a - b;
});
var oneStepped = truncated.map(function (d) {
return sorted.indexOf(d);
});
for (var i = oneStepped.length; i < commonLength; i++) {
oneStepped.push(i);
}
coerce('columnorder', oneStepped);
}
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
handleDomainDefaults(traceOut, layout, coerce);
coerce('columnwidth');
coerce('header.values');
coerce('header.format');
coerce('header.align');
coerce('header.prefix');
coerce('header.suffix');
coerce('header.height');
coerce('header.line.width');
coerce('header.line.color');
coerce('header.fill.color');
Lib.coerceFont(coerce, 'header.font', Lib.extendFlat({}, layout.font));
defaultColumnOrder(traceOut, coerce);
coerce('cells.values');
coerce('cells.format');
coerce('cells.align');
coerce('cells.prefix');
coerce('cells.suffix');
coerce('cells.height');
coerce('cells.line.width');
coerce('cells.line.color');
coerce('cells.fill.color');
Lib.coerceFont(coerce, 'cells.font', Lib.extendFlat({}, layout.font));
// disable 1D transforms
traceOut._length = null;
};
/***/ }),
/***/ 20768:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(80812),
supplyDefaults: __webpack_require__(41696),
calc: __webpack_require__(61612),
plot: __webpack_require__(65424),
moduleType: 'trace',
name: 'table',
basePlotModule: __webpack_require__(25088),
categories: ['noOpacity'],
meta: {
description: ['Table view for detailed data viewing.', 'The data are arranged in a grid of rows and columns.', 'Most styling can be specified for columns, rows or individual cells.', 'Table is using a column-major order, ie. the grid is represented as a vector of column vectors.'].join(' ')
}
};
/***/ }),
/***/ 65424:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var c = __webpack_require__(52920);
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var numberFormat = Lib.numberFormat;
var gup = __webpack_require__(83104);
var Drawing = __webpack_require__(49348);
var svgUtil = __webpack_require__(41536);
var raiseToTop = (__webpack_require__(10923).raiseToTop);
var strTranslate = (__webpack_require__(10923).strTranslate);
var cancelEeaseColumn = (__webpack_require__(10923).cancelTransition);
var prepareData = __webpack_require__(93968);
var splitData = __webpack_require__(28660);
var Color = __webpack_require__(9240);
module.exports = function plot(gd, wrappedTraceHolders) {
var dynamic = !gd._context.staticPlot;
var table = gd._fullLayout._paper.selectAll('.' + c.cn.table).data(wrappedTraceHolders.map(function (wrappedTraceHolder) {
var traceHolder = gup.unwrap(wrappedTraceHolder);
var trace = traceHolder.trace;
return prepareData(gd, trace);
}), gup.keyFun);
table.exit().remove();
table.enter().append('g').classed(c.cn.table, true).attr('overflow', 'visible').style('box-sizing', 'content-box').style('position', 'absolute').style('left', 0).style('overflow', 'visible').style('shape-rendering', 'crispEdges').style('pointer-events', 'all');
table.attr('width', function (d) {
return d.width + d.size.l + d.size.r;
}).attr('height', function (d) {
return d.height + d.size.t + d.size.b;
}).attr('transform', function (d) {
return strTranslate(d.translateX, d.translateY);
});
var tableControlView = table.selectAll('.' + c.cn.tableControlView).data(gup.repeat, gup.keyFun);
var cvEnter = tableControlView.enter().append('g').classed(c.cn.tableControlView, true).style('box-sizing', 'content-box');
if (dynamic) {
var wheelEvent = 'onwheel' in document ? 'wheel' : 'mousewheel';
cvEnter.on('mousemove', function (d) {
tableControlView.filter(function (dd) {
return d === dd;
}).call(renderScrollbarKit, gd);
}).on(wheelEvent, function (d) {
if (d.scrollbarState.wheeling) return;
d.scrollbarState.wheeling = true;
var newY = d.scrollY + d3.event.deltaY;
var noChange = makeDragRow(gd, tableControlView, null, newY)(d);
if (!noChange) {
d3.event.stopPropagation();
d3.event.preventDefault();
}
d.scrollbarState.wheeling = false;
}).call(renderScrollbarKit, gd, true);
}
tableControlView.attr('transform', function (d) {
return strTranslate(d.size.l, d.size.t);
});
// scrollBackground merely ensures that mouse events are captured even on crazy fast scrollwheeling
// otherwise rendering glitches may occur
var scrollBackground = tableControlView.selectAll('.' + c.cn.scrollBackground).data(gup.repeat, gup.keyFun);
scrollBackground.enter().append('rect').classed(c.cn.scrollBackground, true).attr('fill', 'none');
scrollBackground.attr('width', function (d) {
return d.width;
}).attr('height', function (d) {
return d.height;
});
tableControlView.each(function (d) {
Drawing.setClipUrl(d3.select(this), scrollAreaBottomClipKey(gd, d), gd);
});
var yColumn = tableControlView.selectAll('.' + c.cn.yColumn).data(function (vm) {
return vm.columns;
}, gup.keyFun);
yColumn.enter().append('g').classed(c.cn.yColumn, true);
yColumn.exit().remove();
yColumn.attr('transform', function (d) {
return strTranslate(d.x, 0);
});
if (dynamic) {
yColumn.call(d3.behavior.drag().origin(function (d) {
var movedColumn = d3.select(this);
easeColumn(movedColumn, d, -c.uplift);
raiseToTop(this);
d.calcdata.columnDragInProgress = true;
renderScrollbarKit(tableControlView.filter(function (dd) {
return d.calcdata.key === dd.key;
}), gd);
return d;
}).on('drag', function (d) {
var movedColumn = d3.select(this);
var getter = function (dd) {
return (d === dd ? d3.event.x : dd.x) + dd.columnWidth / 2;
};
d.x = Math.max(-c.overdrag, Math.min(d.calcdata.width + c.overdrag - d.columnWidth, d3.event.x));
var sortableColumns = flatData(yColumn).filter(function (dd) {
return dd.calcdata.key === d.calcdata.key;
});
var newOrder = sortableColumns.sort(function (a, b) {
return getter(a) - getter(b);
});
newOrder.forEach(function (dd, i) {
dd.xIndex = i;
dd.x = d === dd ? dd.x : dd.xScale(dd);
});
yColumn.filter(function (dd) {
return d !== dd;
}).transition().ease(c.transitionEase).duration(c.transitionDuration).attr('transform', function (d) {
return strTranslate(d.x, 0);
});
movedColumn.call(cancelEeaseColumn).attr('transform', strTranslate(d.x, -c.uplift));
}).on('dragend', function (d) {
var movedColumn = d3.select(this);
var p = d.calcdata;
d.x = d.xScale(d);
d.calcdata.columnDragInProgress = false;
easeColumn(movedColumn, d, 0);
columnMoved(gd, p, p.columns.map(function (dd) {
return dd.xIndex;
}));
}));
}
yColumn.each(function (d) {
Drawing.setClipUrl(d3.select(this), columnBoundaryClipKey(gd, d), gd);
});
var columnBlock = yColumn.selectAll('.' + c.cn.columnBlock).data(splitData.splitToPanels, gup.keyFun);
columnBlock.enter().append('g').classed(c.cn.columnBlock, true).attr('id', function (d) {
return d.key;
});
columnBlock.style('cursor', function (d) {
return d.dragHandle ? 'ew-resize' : d.calcdata.scrollbarState.barWiggleRoom ? 'ns-resize' : 'default';
});
var headerColumnBlock = columnBlock.filter(headerBlock);
var cellsColumnBlock = columnBlock.filter(cellsBlock);
if (dynamic) {
cellsColumnBlock.call(d3.behavior.drag().origin(function (d) {
d3.event.stopPropagation();
return d;
}).on('drag', makeDragRow(gd, tableControlView, -1)).on('dragend', function () {
// fixme emit plotly notification
}));
}
// initial rendering: header is rendered first, as it may may have async LaTeX (show header first)
// but blocks are _entered_ the way they are due to painter's algo (header on top)
renderColumnCellTree(gd, tableControlView, headerColumnBlock, columnBlock);
renderColumnCellTree(gd, tableControlView, cellsColumnBlock, columnBlock);
var scrollAreaClip = tableControlView.selectAll('.' + c.cn.scrollAreaClip).data(gup.repeat, gup.keyFun);
scrollAreaClip.enter().append('clipPath').classed(c.cn.scrollAreaClip, true).attr('id', function (d) {
return scrollAreaBottomClipKey(gd, d);
});
var scrollAreaClipRect = scrollAreaClip.selectAll('.' + c.cn.scrollAreaClipRect).data(gup.repeat, gup.keyFun);
scrollAreaClipRect.enter().append('rect').classed(c.cn.scrollAreaClipRect, true).attr('x', -c.overdrag).attr('y', -c.uplift).attr('fill', 'none');
scrollAreaClipRect.attr('width', function (d) {
return d.width + 2 * c.overdrag;
}).attr('height', function (d) {
return d.height + c.uplift;
});
var columnBoundary = yColumn.selectAll('.' + c.cn.columnBoundary).data(gup.repeat, gup.keyFun);
columnBoundary.enter().append('g').classed(c.cn.columnBoundary, true);
var columnBoundaryClippath = yColumn.selectAll('.' + c.cn.columnBoundaryClippath).data(gup.repeat, gup.keyFun);
// SVG spec doesn't mandate wrapping into a and doesn't seem to cause a speed difference
columnBoundaryClippath.enter().append('clipPath').classed(c.cn.columnBoundaryClippath, true);
columnBoundaryClippath.attr('id', function (d) {
return columnBoundaryClipKey(gd, d);
});
var columnBoundaryRect = columnBoundaryClippath.selectAll('.' + c.cn.columnBoundaryRect).data(gup.repeat, gup.keyFun);
columnBoundaryRect.enter().append('rect').classed(c.cn.columnBoundaryRect, true).attr('fill', 'none');
columnBoundaryRect.attr('width', function (d) {
return d.columnWidth + 2 * roundHalfWidth(d);
}).attr('height', function (d) {
return d.calcdata.height + 2 * roundHalfWidth(d) + c.uplift;
}).attr('x', function (d) {
return -roundHalfWidth(d);
}).attr('y', function (d) {
return -roundHalfWidth(d);
});
updateBlockYPosition(null, cellsColumnBlock, tableControlView);
};
function roundHalfWidth(d) {
return Math.ceil(d.calcdata.maxLineWidth / 2);
}
function scrollAreaBottomClipKey(gd, d) {
return 'clip' + gd._fullLayout._uid + '_scrollAreaBottomClip_' + d.key;
}
function columnBoundaryClipKey(gd, d) {
return 'clip' + gd._fullLayout._uid + '_columnBoundaryClippath_' + d.calcdata.key + '_' + d.specIndex;
}
function flatData(selection) {
return [].concat.apply([], selection.map(function (g) {
return g;
})).map(function (g) {
return g.__data__;
});
}
function renderScrollbarKit(tableControlView, gd, bypassVisibleBar) {
function calcTotalHeight(d) {
var blocks = d.rowBlocks;
return firstRowAnchor(blocks, blocks.length - 1) + (blocks.length ? rowsHeight(blocks[blocks.length - 1], Infinity) : 1);
}
var scrollbarKit = tableControlView.selectAll('.' + c.cn.scrollbarKit).data(gup.repeat, gup.keyFun);
scrollbarKit.enter().append('g').classed(c.cn.scrollbarKit, true).style('shape-rendering', 'geometricPrecision');
scrollbarKit.each(function (d) {
var s = d.scrollbarState;
s.totalHeight = calcTotalHeight(d);
s.scrollableAreaHeight = d.groupHeight - headerHeight(d);
s.currentlyVisibleHeight = Math.min(s.totalHeight, s.scrollableAreaHeight);
s.ratio = s.currentlyVisibleHeight / s.totalHeight;
s.barLength = Math.max(s.ratio * s.currentlyVisibleHeight, c.goldenRatio * c.scrollbarWidth);
s.barWiggleRoom = s.currentlyVisibleHeight - s.barLength;
s.wiggleRoom = Math.max(0, s.totalHeight - s.scrollableAreaHeight);
s.topY = s.barWiggleRoom === 0 ? 0 : d.scrollY / s.wiggleRoom * s.barWiggleRoom;
s.bottomY = s.topY + s.barLength;
s.dragMultiplier = s.wiggleRoom / s.barWiggleRoom;
}).attr('transform', function (d) {
var xPosition = d.width + c.scrollbarWidth / 2 + c.scrollbarOffset;
return strTranslate(xPosition, headerHeight(d));
});
var scrollbar = scrollbarKit.selectAll('.' + c.cn.scrollbar).data(gup.repeat, gup.keyFun);
scrollbar.enter().append('g').classed(c.cn.scrollbar, true);
var scrollbarSlider = scrollbar.selectAll('.' + c.cn.scrollbarSlider).data(gup.repeat, gup.keyFun);
scrollbarSlider.enter().append('g').classed(c.cn.scrollbarSlider, true);
scrollbarSlider.attr('transform', function (d) {
return strTranslate(0, d.scrollbarState.topY || 0);
});
var scrollbarGlyph = scrollbarSlider.selectAll('.' + c.cn.scrollbarGlyph).data(gup.repeat, gup.keyFun);
scrollbarGlyph.enter().append('line').classed(c.cn.scrollbarGlyph, true).attr('stroke', 'black').attr('stroke-width', c.scrollbarWidth).attr('stroke-linecap', 'round').attr('y1', c.scrollbarWidth / 2);
scrollbarGlyph.attr('y2', function (d) {
return d.scrollbarState.barLength - c.scrollbarWidth / 2;
}).attr('stroke-opacity', function (d) {
return d.columnDragInProgress || !d.scrollbarState.barWiggleRoom || bypassVisibleBar ? 0 : 0.4;
});
// cancel transition: possible pending (also, delayed) transition
scrollbarGlyph.transition().delay(0).duration(0);
scrollbarGlyph.transition().delay(c.scrollbarHideDelay).duration(c.scrollbarHideDuration).attr('stroke-opacity', 0);
var scrollbarCaptureZone = scrollbar.selectAll('.' + c.cn.scrollbarCaptureZone).data(gup.repeat, gup.keyFun);
scrollbarCaptureZone.enter().append('line').classed(c.cn.scrollbarCaptureZone, true).attr('stroke', 'white').attr('stroke-opacity', 0.01) // some browser might get rid of a 0 opacity element
.attr('stroke-width', c.scrollbarCaptureWidth).attr('stroke-linecap', 'butt').attr('y1', 0).on('mousedown', function (d) {
var y = d3.event.y;
var bbox = this.getBoundingClientRect();
var s = d.scrollbarState;
var pixelVal = y - bbox.top;
var inverseScale = d3.scale.linear().domain([0, s.scrollableAreaHeight]).range([0, s.totalHeight]).clamp(true);
if (!(s.topY <= pixelVal && pixelVal <= s.bottomY)) {
makeDragRow(gd, tableControlView, null, inverseScale(pixelVal - s.barLength / 2))(d);
}
}).call(d3.behavior.drag().origin(function (d) {
d3.event.stopPropagation();
d.scrollbarState.scrollbarScrollInProgress = true;
return d;
}).on('drag', makeDragRow(gd, tableControlView)).on('dragend', function () {
// fixme emit Plotly event
}));
scrollbarCaptureZone.attr('y2', function (d) {
return d.scrollbarState.scrollableAreaHeight;
});
// Remove scroll glyph and capture zone on static plots
// as they don't render properly when converted to PDF
// in the Chrome PDF viewer
// https://github.com/plotly/streambed/issues/11618
if (gd._context.staticPlot) {
scrollbarGlyph.remove();
scrollbarCaptureZone.remove();
}
}
function renderColumnCellTree(gd, tableControlView, columnBlock, allColumnBlock) {
// fixme this perf hotspot
// this is performance critical code as scrolling calls it on every revolver switch
// it appears sufficiently fast but there are plenty of low-hanging fruits for performance optimization
var columnCells = renderColumnCells(columnBlock);
var columnCell = renderColumnCell(columnCells);
supplyStylingValues(columnCell);
var cellRect = renderCellRect(columnCell);
sizeAndStyleRect(cellRect);
var cellTextHolder = renderCellTextHolder(columnCell);
var cellText = renderCellText(cellTextHolder);
setFont(cellText);
populateCellText(cellText, tableControlView, allColumnBlock, gd);
// doing this at the end when text, and text stlying are set
setCellHeightAndPositionY(columnCell);
}
function renderColumnCells(columnBlock) {
var columnCells = columnBlock.selectAll('.' + c.cn.columnCells).data(gup.repeat, gup.keyFun);
columnCells.enter().append('g').classed(c.cn.columnCells, true);
columnCells.exit().remove();
return columnCells;
}
function renderColumnCell(columnCells) {
var columnCell = columnCells.selectAll('.' + c.cn.columnCell).data(splitData.splitToCells, function (d) {
return d.keyWithinBlock;
});
columnCell.enter().append('g').classed(c.cn.columnCell, true);
columnCell.exit().remove();
return columnCell;
}
function renderCellRect(columnCell) {
var cellRect = columnCell.selectAll('.' + c.cn.cellRect).data(gup.repeat, function (d) {
return d.keyWithinBlock;
});
cellRect.enter().append('rect').classed(c.cn.cellRect, true);
return cellRect;
}
function renderCellText(cellTextHolder) {
var cellText = cellTextHolder.selectAll('.' + c.cn.cellText).data(gup.repeat, function (d) {
return d.keyWithinBlock;
});
cellText.enter().append('text').classed(c.cn.cellText, true).style('cursor', function () {
return 'auto';
}).on('mousedown', function () {
d3.event.stopPropagation();
});
return cellText;
}
function renderCellTextHolder(columnCell) {
var cellTextHolder = columnCell.selectAll('.' + c.cn.cellTextHolder).data(gup.repeat, function (d) {
return d.keyWithinBlock;
});
cellTextHolder.enter().append('g').classed(c.cn.cellTextHolder, true).style('shape-rendering', 'geometricPrecision');
return cellTextHolder;
}
function supplyStylingValues(columnCell) {
columnCell.each(function (d, i) {
var spec = d.calcdata.cells.font;
var col = d.column.specIndex;
var font = {
size: gridPick(spec.size, col, i),
color: gridPick(spec.color, col, i),
family: gridPick(spec.family, col, i)
};
d.rowNumber = d.key;
d.align = gridPick(d.calcdata.cells.align, col, i);
d.cellBorderWidth = gridPick(d.calcdata.cells.line.width, col, i);
d.font = font;
});
}
function setFont(cellText) {
cellText.each(function (d) {
Drawing.font(d3.select(this), d.font);
});
}
function sizeAndStyleRect(cellRect) {
cellRect.attr('width', function (d) {
return d.column.columnWidth;
}).attr('stroke-width', function (d) {
return d.cellBorderWidth;
}).each(function (d) {
var atomicSelection = d3.select(this);
Color.stroke(atomicSelection, gridPick(d.calcdata.cells.line.color, d.column.specIndex, d.rowNumber));
Color.fill(atomicSelection, gridPick(d.calcdata.cells.fill.color, d.column.specIndex, d.rowNumber));
});
}
function populateCellText(cellText, tableControlView, allColumnBlock, gd) {
cellText.text(function (d) {
var col = d.column.specIndex;
var row = d.rowNumber;
var userSuppliedContent = d.value;
var stringSupplied = typeof userSuppliedContent === 'string';
var hasBreaks = stringSupplied && userSuppliedContent.match(/
/i);
var userBrokenText = !stringSupplied || hasBreaks;
d.mayHaveMarkup = stringSupplied && userSuppliedContent.match(/[<&>]/);
var latex = isLatex(userSuppliedContent);
d.latex = latex;
var prefix = latex ? '' : gridPick(d.calcdata.cells.prefix, col, row) || '';
var suffix = latex ? '' : gridPick(d.calcdata.cells.suffix, col, row) || '';
var format = latex ? null : gridPick(d.calcdata.cells.format, col, row) || null;
var prefixSuffixedText = prefix + (format ? numberFormat(format)(d.value) : d.value) + suffix;
var hasWrapSplitCharacter;
d.wrappingNeeded = !d.wrapped && !userBrokenText && !latex && (hasWrapSplitCharacter = hasWrapCharacter(prefixSuffixedText));
d.cellHeightMayIncrease = hasBreaks || latex || d.mayHaveMarkup || (hasWrapSplitCharacter === void 0 ? hasWrapCharacter(prefixSuffixedText) : hasWrapSplitCharacter);
d.needsConvertToTspans = d.mayHaveMarkup || d.wrappingNeeded || d.latex;
var textToRender;
if (d.wrappingNeeded) {
var hrefPreservedText = c.wrapSplitCharacter === ' ' ? prefixSuffixedText.replace(/ pTop) {
pages.push(blockIndex);
}
pTop += rowsHeight;
// consider this nice final optimization; put it in `for` condition - caveat, currently the
// block.allRowsHeight relies on being invalidated, so enabling this opt may not be safe
// if(pages.length > 1) break;
}
return pages;
}
function updateBlockYPosition(gd, cellsColumnBlock, tableControlView) {
var d = flatData(cellsColumnBlock)[0];
if (d === undefined) return;
var blocks = d.rowBlocks;
var calcdata = d.calcdata;
var bottom = firstRowAnchor(blocks, blocks.length);
var scrollHeight = d.calcdata.groupHeight - headerHeight(d);
var scrollY = calcdata.scrollY = Math.max(0, Math.min(bottom - scrollHeight, calcdata.scrollY));
var pages = findPagesAndCacheHeights(blocks, scrollY, scrollHeight);
if (pages.length === 1) {
if (pages[0] === blocks.length - 1) {
pages.unshift(pages[0] - 1);
} else {
pages.push(pages[0] + 1);
}
}
// make phased out page jump by 2 while leaving stationary page intact
if (pages[0] % 2) {
pages.reverse();
}
cellsColumnBlock.each(function (d, i) {
// these values will also be needed when a block is translated again due to growing cell height
d.page = pages[i];
d.scrollY = scrollY;
});
cellsColumnBlock.attr('transform', function (d) {
var yTranslate = firstRowAnchor(d.rowBlocks, d.page) - d.scrollY;
return strTranslate(0, yTranslate);
});
// conditionally rerendering panel 0 and 1
if (gd) {
conditionalPanelRerender(gd, tableControlView, cellsColumnBlock, pages, d.prevPages, d, 0);
conditionalPanelRerender(gd, tableControlView, cellsColumnBlock, pages, d.prevPages, d, 1);
renderScrollbarKit(tableControlView, gd);
}
}
function makeDragRow(gd, allTableControlView, optionalMultiplier, optionalPosition) {
return function dragRow(eventD) {
// may come from whichever DOM event target: drag, wheel, bar... eventD corresponds to event target
var d = eventD.calcdata ? eventD.calcdata : eventD;
var tableControlView = allTableControlView.filter(function (dd) {
return d.key === dd.key;
});
var multiplier = optionalMultiplier || d.scrollbarState.dragMultiplier;
var initialScrollY = d.scrollY;
d.scrollY = optionalPosition === void 0 ? d.scrollY + multiplier * d3.event.dy : optionalPosition;
var cellsColumnBlock = tableControlView.selectAll('.' + c.cn.yColumn).selectAll('.' + c.cn.columnBlock).filter(cellsBlock);
updateBlockYPosition(gd, cellsColumnBlock, tableControlView);
// return false if we've "used" the scroll, ie it did something,
// so the event shouldn't bubble (if appropriate)
return d.scrollY === initialScrollY;
};
}
function conditionalPanelRerender(gd, tableControlView, cellsColumnBlock, pages, prevPages, d, revolverIndex) {
var shouldComponentUpdate = pages[revolverIndex] !== prevPages[revolverIndex];
if (shouldComponentUpdate) {
clearTimeout(d.currentRepaint[revolverIndex]);
d.currentRepaint[revolverIndex] = setTimeout(function () {
// setTimeout might lag rendering but yields a smoother scroll, because fast scrolling makes
// some repaints invisible ie. wasteful (DOM work blocks the main thread)
var toRerender = cellsColumnBlock.filter(function (d, i) {
return i === revolverIndex && pages[i] !== prevPages[i];
});
renderColumnCellTree(gd, tableControlView, toRerender, cellsColumnBlock);
prevPages[revolverIndex] = pages[revolverIndex];
});
}
}
function wrapTextMaker(columnBlock, element, tableControlView, gd) {
return function wrapText() {
var cellTextHolder = d3.select(element.parentNode);
cellTextHolder.each(function (d) {
var fragments = d.fragments;
cellTextHolder.selectAll('tspan.line').each(function (dd, i) {
fragments[i].width = this.getComputedTextLength();
});
// last element is only for measuring the separator character, so it's ignored:
var separatorLength = fragments[fragments.length - 1].width;
var rest = fragments.slice(0, -1);
var currentRow = [];
var currentAddition, currentAdditionLength;
var currentRowLength = 0;
var rowLengthLimit = d.column.columnWidth - 2 * c.cellPad;
d.value = '';
while (rest.length) {
currentAddition = rest.shift();
currentAdditionLength = currentAddition.width + separatorLength;
if (currentRowLength + currentAdditionLength > rowLengthLimit) {
d.value += currentRow.join(c.wrapSpacer) + c.lineBreaker;
currentRow = [];
currentRowLength = 0;
}
currentRow.push(currentAddition.text);
currentRowLength += currentAdditionLength;
}
if (currentRowLength) {
d.value += currentRow.join(c.wrapSpacer);
}
d.wrapped = true;
});
// the pre-wrapped text was rendered only for the text measurements
cellTextHolder.selectAll('tspan.line').remove();
// resupply text, now wrapped
populateCellText(cellTextHolder.select('.' + c.cn.cellText), tableControlView, columnBlock, gd);
d3.select(element.parentNode.parentNode).call(setCellHeightAndPositionY);
};
}
function updateYPositionMaker(columnBlock, element, tableControlView, gd, d) {
return function updateYPosition() {
if (d.settledY) return;
var cellTextHolder = d3.select(element.parentNode);
var l = getBlock(d);
var rowIndex = d.key - l.firstRowIndex;
var declaredRowHeight = l.rows[rowIndex].rowHeight;
var requiredHeight = d.cellHeightMayIncrease ? element.parentNode.getBoundingClientRect().height + 2 * c.cellPad : declaredRowHeight;
var finalHeight = Math.max(requiredHeight, declaredRowHeight);
var increase = finalHeight - l.rows[rowIndex].rowHeight;
if (increase) {
// current row height increased
l.rows[rowIndex].rowHeight = finalHeight;
columnBlock.selectAll('.' + c.cn.columnCell).call(setCellHeightAndPositionY);
updateBlockYPosition(null, columnBlock.filter(cellsBlock), 0);
// if d.column.type === 'header', then the scrollbar has to be pushed downward to the scrollable area
// if d.column.type === 'cells', it can still be relevant if total scrolling content height is less than the
// scrollable window, as increases to row heights may need scrollbar updates
renderScrollbarKit(tableControlView, gd, true);
}
cellTextHolder.attr('transform', function () {
// this code block is only invoked for items where d.cellHeightMayIncrease is truthy
var element = this;
var columnCellElement = element.parentNode;
var box = columnCellElement.getBoundingClientRect();
var rectBox = d3.select(element.parentNode).select('.' + c.cn.cellRect).node().getBoundingClientRect();
var currentTransform = element.transform.baseVal.consolidate();
var yPosition = rectBox.top - box.top + (currentTransform ? currentTransform.matrix.f : c.cellPad);
return strTranslate(xPosition(d, d3.select(element.parentNode).select('.' + c.cn.cellTextHolder).node().getBoundingClientRect().width), yPosition);
});
d.settledY = true;
};
}
function xPosition(d, optionalWidth) {
switch (d.align) {
case 'left':
return c.cellPad;
case 'right':
return d.column.columnWidth - (optionalWidth || 0) - c.cellPad;
case 'center':
return (d.column.columnWidth - (optionalWidth || 0)) / 2;
default:
return c.cellPad;
}
}
function setCellHeightAndPositionY(columnCell) {
columnCell.attr('transform', function (d) {
var headerHeight = d.rowBlocks[0].auxiliaryBlocks.reduce(function (p, n) {
return p + rowsHeight(n, Infinity);
}, 0);
var l = getBlock(d);
var rowAnchor = rowsHeight(l, d.key);
var yOffset = rowAnchor + headerHeight;
return strTranslate(0, yOffset);
}).selectAll('.' + c.cn.cellRect).attr('height', function (d) {
return getRow(getBlock(d), d.key).rowHeight;
});
}
function firstRowAnchor(blocks, page) {
var total = 0;
for (var i = page - 1; i >= 0; i--) {
total += allRowsHeight(blocks[i]);
}
return total;
}
function rowsHeight(rowBlock, key) {
var total = 0;
for (var i = 0; i < rowBlock.rows.length && rowBlock.rows[i].rowIndex < key; i++) {
total += rowBlock.rows[i].rowHeight;
}
return total;
}
function allRowsHeight(rowBlock) {
var cached = rowBlock.allRowsHeight;
if (cached !== void 0) {
return cached;
}
var total = 0;
for (var i = 0; i < rowBlock.rows.length; i++) {
total += rowBlock.rows[i].rowHeight;
}
rowBlock.allRowsHeight = total;
return total;
}
function getBlock(d) {
return d.rowBlocks[d.page];
}
function getRow(l, i) {
return l.rows[i - l.firstRowIndex];
}
/***/ }),
/***/ 36468:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var colorScaleAttrs = __webpack_require__(99732);
var domainAttrs = (__webpack_require__(55124)/* .attributes */ .u);
var pieAttrs = __webpack_require__(99644);
var sunburstAttrs = __webpack_require__(36404);
var constants = __webpack_require__(73220);
var extendFlat = (__webpack_require__(55016).extendFlat);
var pattern = (__webpack_require__(9392)/* .pattern */ .c);
module.exports = {
labels: sunburstAttrs.labels,
parents: sunburstAttrs.parents,
values: sunburstAttrs.values,
branchvalues: sunburstAttrs.branchvalues,
count: sunburstAttrs.count,
level: sunburstAttrs.level,
maxdepth: sunburstAttrs.maxdepth,
tiling: {
packing: {
valType: 'enumerated',
values: ['squarify', 'binary', 'dice', 'slice', 'slice-dice', 'dice-slice'],
dflt: 'squarify',
editType: 'plot',
description: ['Determines d3 treemap solver.', 'For more info please refer to https://github.com/d3/d3-hierarchy#treemap-tiling'].join(' ')
},
squarifyratio: {
valType: 'number',
min: 1,
dflt: 1,
editType: 'plot',
description: ['When using *squarify* `packing` algorithm, according to https://github.com/d3/d3-hierarchy/blob/v3.1.1/README.md#squarify_ratio', 'this option specifies the desired aspect ratio of the generated rectangles.', 'The ratio must be specified as a number greater than or equal to one.', 'Note that the orientation of the generated rectangles (tall or wide)', 'is not implied by the ratio; for example, a ratio of two will attempt', 'to produce a mixture of rectangles whose width:height ratio is either 2:1 or 1:2.', 'When using *squarify*, unlike d3 which uses the Golden Ratio i.e. 1.618034,', 'Plotly applies 1 to increase squares in treemap layouts.'].join(' ')
},
flip: {
valType: 'flaglist',
flags: ['x', 'y'],
dflt: '',
editType: 'plot',
description: ['Determines if the positions obtained from solver are flipped on each axis.'].join(' ')
},
pad: {
valType: 'number',
min: 0,
dflt: 3,
editType: 'plot',
description: ['Sets the inner padding (in px).'].join(' ')
},
editType: 'calc'
},
marker: extendFlat({
pad: {
t: {
valType: 'number',
min: 0,
editType: 'plot',
description: ['Sets the padding form the top (in px).'].join(' ')
},
l: {
valType: 'number',
min: 0,
editType: 'plot',
description: ['Sets the padding form the left (in px).'].join(' ')
},
r: {
valType: 'number',
min: 0,
editType: 'plot',
description: ['Sets the padding form the right (in px).'].join(' ')
},
b: {
valType: 'number',
min: 0,
editType: 'plot',
description: ['Sets the padding form the bottom (in px).'].join(' ')
},
editType: 'calc'
},
colors: sunburstAttrs.marker.colors,
pattern: pattern,
depthfade: {
valType: 'enumerated',
values: [true, false, 'reversed'],
editType: 'style',
description: ['Determines if the sector colors are faded towards', 'the background from the leaves up to the headers.', 'This option is unavailable when a `colorscale` is present,', 'defaults to false when `marker.colors` is set,', 'but otherwise defaults to true.', 'When set to *reversed*, the fading direction is inverted,', 'that is the top elements within hierarchy are drawn with fully saturated colors', 'while the leaves are faded towards the background color.'].join(' ')
},
line: sunburstAttrs.marker.line,
cornerradius: {
valType: 'number',
min: 0,
dflt: 0,
editType: 'plot',
description: ['Sets the maximum rounding of corners (in px).'].join(' ')
},
editType: 'calc'
}, colorScaleAttrs('marker', {
colorAttr: 'colors',
anim: false // TODO: set to anim: true?
})),
pathbar: {
visible: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: ['Determines if the path bar is drawn', 'i.e. outside the trace `domain` and', 'with one pixel gap.'].join(' ')
},
side: {
valType: 'enumerated',
values: ['top', 'bottom'],
dflt: 'top',
editType: 'plot',
description: ['Determines on which side of the the treemap the', '`pathbar` should be presented.'].join(' ')
},
edgeshape: {
valType: 'enumerated',
values: ['>', '<', '|', '/', '\\'],
dflt: '>',
editType: 'plot',
description: ['Determines which shape is used for edges between `barpath` labels.'].join(' ')
},
thickness: {
valType: 'number',
min: 12,
editType: 'plot',
description: ['Sets the thickness of `pathbar` (in px). If not specified the `pathbar.textfont.size` is used', 'with 3 pixles extra padding on each side.'].join(' ')
},
textfont: extendFlat({}, pieAttrs.textfont, {
description: 'Sets the font used inside `pathbar`.'
}),
editType: 'calc'
},
text: pieAttrs.text,
textinfo: sunburstAttrs.textinfo,
// TODO: incorporate `label` and `value` in the eventData
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: constants.eventDataKeys.concat(['label', 'value'])
}),
hovertext: pieAttrs.hovertext,
hoverinfo: sunburstAttrs.hoverinfo,
hovertemplate: hovertemplateAttrs({}, {
keys: constants.eventDataKeys
}),
textfont: pieAttrs.textfont,
insidetextfont: pieAttrs.insidetextfont,
outsidetextfont: extendFlat({}, pieAttrs.outsidetextfont, {
description: ['Sets the font used for `textinfo` lying outside the sector.', 'This option refers to the root of the hierarchy', 'presented on top left corner of a treemap graph.', 'Please note that if a hierarchy has multiple root nodes,', 'this option won\'t have any effect and `insidetextfont` would be used.'].join(' ')
}),
textposition: {
valType: 'enumerated',
values: ['top left', 'top center', 'top right', 'middle left', 'middle center', 'middle right', 'bottom left', 'bottom center', 'bottom right'],
dflt: 'top left',
editType: 'plot',
description: ['Sets the positions of the `text` elements.'].join(' ')
},
sort: pieAttrs.sort,
root: sunburstAttrs.root,
domain: domainAttrs({
name: 'treemap',
trace: true,
editType: 'calc'
})
};
/***/ }),
/***/ 53088:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var plots = __webpack_require__(19896);
exports.name = 'treemap';
exports.plot = function (gd, traces, transitionOpts, makeOnCompleteCallback) {
plots.plotBasePlot(exports.name, gd, traces, transitionOpts, makeOnCompleteCallback);
};
exports.clean = function (newFullData, newFullLayout, oldFullData, oldFullLayout) {
plots.cleanBasePlot(exports.name, newFullData, newFullLayout, oldFullData, oldFullLayout);
};
/***/ }),
/***/ 88844:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var calc = __webpack_require__(45780);
exports.r = function (gd, trace) {
return calc.calc(gd, trace);
};
exports.q = function (gd) {
return calc._runCrossTraceCalc('treemap', gd);
};
/***/ }),
/***/ 73220:
/***/ (function(module) {
"use strict";
module.exports = {
CLICK_TRANSITION_TIME: 750,
CLICK_TRANSITION_EASING: 'poly',
eventDataKeys: [
// string
'currentPath', 'root', 'entry',
// no need to add 'parent' here
// percentages i.e. ratios
'percentRoot', 'percentEntry', 'percentParent'],
gapWithPathbar: 1 // i.e. one pixel
};
/***/ }),
/***/ 95616:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(36468);
var Color = __webpack_require__(9240);
var handleDomainDefaults = (__webpack_require__(55124)/* .defaults */ .Q);
var handleText = (__webpack_require__(49520).handleText);
var TEXTPAD = (__webpack_require__(77216).TEXTPAD);
var handleMarkerDefaults = (__webpack_require__(87048).handleMarkerDefaults);
var Colorscale = __webpack_require__(26733);
var hasColorscale = Colorscale.hasColorscale;
var colorscaleDefaults = Colorscale.handleDefaults;
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var labels = coerce('labels');
var parents = coerce('parents');
if (!labels || !labels.length || !parents || !parents.length) {
traceOut.visible = false;
return;
}
var vals = coerce('values');
if (vals && vals.length) {
coerce('branchvalues');
} else {
coerce('count');
}
coerce('level');
coerce('maxdepth');
var packing = coerce('tiling.packing');
if (packing === 'squarify') {
coerce('tiling.squarifyratio');
}
coerce('tiling.flip');
coerce('tiling.pad');
var text = coerce('text');
coerce('texttemplate');
if (!traceOut.texttemplate) coerce('textinfo', Lib.isArrayOrTypedArray(text) ? 'text+label' : 'label');
coerce('hovertext');
coerce('hovertemplate');
var hasPathbar = coerce('pathbar.visible');
var textposition = 'auto';
handleText(traceIn, traceOut, layout, coerce, textposition, {
hasPathbar: hasPathbar,
moduleHasSelected: false,
moduleHasUnselected: false,
moduleHasConstrain: false,
moduleHasCliponaxis: false,
moduleHasTextangle: false,
moduleHasInsideanchor: false
});
coerce('textposition');
var bottomText = traceOut.textposition.indexOf('bottom') !== -1;
handleMarkerDefaults(traceIn, traceOut, layout, coerce);
var withColorscale = traceOut._hasColorscale = hasColorscale(traceIn, 'marker', 'colors') || (traceIn.marker || {}).coloraxis // N.B. special logic to consider "values" colorscales
;
if (withColorscale) {
colorscaleDefaults(traceIn, traceOut, layout, coerce, {
prefix: 'marker.',
cLetter: 'c'
});
} else {
coerce('marker.depthfade', !(traceOut.marker.colors || []).length);
}
var headerSize = traceOut.textfont.size * 2;
coerce('marker.pad.t', bottomText ? headerSize / 4 : headerSize);
coerce('marker.pad.l', headerSize / 4);
coerce('marker.pad.r', headerSize / 4);
coerce('marker.pad.b', bottomText ? headerSize : headerSize / 4);
coerce('marker.cornerradius');
traceOut._hovered = {
marker: {
line: {
width: 2,
color: Color.contrast(layout.paper_bgcolor)
}
}
};
if (hasPathbar) {
// This works even for multi-line labels as treemap pathbar trim out line breaks
coerce('pathbar.thickness', traceOut.pathbar.textfont.size + 2 * TEXTPAD);
coerce('pathbar.side');
coerce('pathbar.edgeshape');
}
coerce('sort');
coerce('root.color');
handleDomainDefaults(traceOut, layout, coerce);
// do not support transforms for now
traceOut._length = null;
};
/***/ }),
/***/ 62148:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var helpers = __webpack_require__(54844);
var uniformText = __webpack_require__(4096);
var clearMinTextSize = uniformText.clearMinTextSize;
var resizeText = (__webpack_require__(21212).resizeText);
var plotOne = __webpack_require__(82856);
module.exports = function _plot(gd, cdmodule, transitionOpts, makeOnCompleteCallback, opts) {
var type = opts.type;
var drawDescendants = opts.drawDescendants;
var fullLayout = gd._fullLayout;
var layer = fullLayout['_' + type + 'layer'];
var join, onComplete;
// If transition config is provided, then it is only a partial replot and traces not
// updated are removed.
var isFullReplot = !transitionOpts;
clearMinTextSize(type, fullLayout);
join = layer.selectAll('g.trace.' + type).data(cdmodule, function (cd) {
return cd[0].trace.uid;
});
join.enter().append('g').classed('trace', true).classed(type, true);
join.order();
if (!fullLayout.uniformtext.mode && helpers.hasTransition(transitionOpts)) {
if (makeOnCompleteCallback) {
// If it was passed a callback to register completion, make a callback. If
// this is created, then it must be executed on completion, otherwise the
// pos-transition redraw will not execute:
onComplete = makeOnCompleteCallback();
}
var transition = d3.transition().duration(transitionOpts.duration).ease(transitionOpts.easing).each('end', function () {
onComplete && onComplete();
}).each('interrupt', function () {
onComplete && onComplete();
});
transition.each(function () {
// Must run the selection again since otherwise enters/updates get grouped together
// and these get executed out of order. Except we need them in order!
layer.selectAll('g.trace').each(function (cd) {
plotOne(gd, cd, this, transitionOpts, drawDescendants);
});
});
} else {
join.each(function (cd) {
plotOne(gd, cd, this, transitionOpts, drawDescendants);
});
if (fullLayout.uniformtext.mode) {
resizeText(gd, layer.selectAll('.trace'), type);
}
}
if (isFullReplot) {
join.exit().remove();
}
};
/***/ }),
/***/ 17512:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var svgTextUtils = __webpack_require__(41536);
var partition = __webpack_require__(55600);
var styleOne = (__webpack_require__(39624).styleOne);
var constants = __webpack_require__(73220);
var helpers = __webpack_require__(54844);
var attachFxHandlers = __webpack_require__(58528);
var onPathbar = true; // for Ancestors
module.exports = function drawAncestors(gd, cd, entry, slices, opts) {
var barDifY = opts.barDifY;
var width = opts.width;
var height = opts.height;
var viewX = opts.viewX;
var viewY = opts.viewY;
var pathSlice = opts.pathSlice;
var toMoveInsideSlice = opts.toMoveInsideSlice;
var strTransform = opts.strTransform;
var hasTransition = opts.hasTransition;
var handleSlicesExit = opts.handleSlicesExit;
var makeUpdateSliceInterpolator = opts.makeUpdateSliceInterpolator;
var makeUpdateTextInterpolator = opts.makeUpdateTextInterpolator;
var refRect = {};
var isStatic = gd._context.staticPlot;
var fullLayout = gd._fullLayout;
var cd0 = cd[0];
var trace = cd0.trace;
var hierarchy = cd0.hierarchy;
var eachWidth = width / trace._entryDepth;
var pathIds = helpers.listPath(entry.data, 'id');
var sliceData = partition(hierarchy.copy(), [width, height], {
packing: 'dice',
pad: {
inner: 0,
top: 0,
left: 0,
right: 0,
bottom: 0
}
}).descendants();
// edit slices that show up on graph
sliceData = sliceData.filter(function (pt) {
var level = pathIds.indexOf(pt.data.id);
if (level === -1) return false;
pt.x0 = eachWidth * level;
pt.x1 = eachWidth * (level + 1);
pt.y0 = barDifY;
pt.y1 = barDifY + height;
pt.onPathbar = true;
return true;
});
sliceData.reverse();
slices = slices.data(sliceData, helpers.getPtId);
slices.enter().append('g').classed('pathbar', true);
handleSlicesExit(slices, onPathbar, refRect, [width, height], pathSlice);
slices.order();
var updateSlices = slices;
if (hasTransition) {
updateSlices = updateSlices.transition().each('end', function () {
// N.B. gd._transitioning is (still) *true* by the time
// transition updates get here
var sliceTop = d3.select(this);
helpers.setSliceCursor(sliceTop, gd, {
hideOnRoot: false,
hideOnLeaves: false,
isTransitioning: false
});
});
}
updateSlices.each(function (pt) {
// for bbox
pt._x0 = viewX(pt.x0);
pt._x1 = viewX(pt.x1);
pt._y0 = viewY(pt.y0);
pt._y1 = viewY(pt.y1);
pt._hoverX = viewX(pt.x1 - Math.min(width, height) / 2);
pt._hoverY = viewY(pt.y1 - height / 2);
var sliceTop = d3.select(this);
var slicePath = Lib.ensureSingle(sliceTop, 'path', 'surface', function (s) {
s.style('pointer-events', isStatic ? 'none' : 'all');
});
if (hasTransition) {
slicePath.transition().attrTween('d', function (pt2) {
var interp = makeUpdateSliceInterpolator(pt2, onPathbar, refRect, [width, height]);
return function (t) {
return pathSlice(interp(t));
};
});
} else {
slicePath.attr('d', pathSlice);
}
sliceTop.call(attachFxHandlers, entry, gd, cd, {
styleOne: styleOne,
eventDataKeys: constants.eventDataKeys,
transitionTime: constants.CLICK_TRANSITION_TIME,
transitionEasing: constants.CLICK_TRANSITION_EASING
}).call(helpers.setSliceCursor, gd, {
hideOnRoot: false,
hideOnLeaves: false,
isTransitioning: gd._transitioning
});
slicePath.call(styleOne, pt, trace, gd, {
hovered: false
});
pt._text = (helpers.getPtLabel(pt) || '').split('
').join(' ') || '';
var sliceTextGroup = Lib.ensureSingle(sliceTop, 'g', 'slicetext');
var sliceText = Lib.ensureSingle(sliceTextGroup, 'text', '', function (s) {
// prohibit tex interpretation until we can handle
// tex and regular text together
s.attr('data-notex', 1);
});
var font = Lib.ensureUniformFontSize(gd, helpers.determineTextFont(trace, pt, fullLayout.font, {
onPathbar: true
}));
sliceText.text(pt._text || ' ') // use one space character instead of a blank string to avoid jumps during transition
.classed('slicetext', true).attr('text-anchor', 'start').call(Drawing.font, font).call(svgTextUtils.convertToTspans, gd);
pt.textBB = Drawing.bBox(sliceText.node());
pt.transform = toMoveInsideSlice(pt, {
fontSize: font.size,
onPathbar: true
});
pt.transform.fontSize = font.size;
if (hasTransition) {
sliceText.transition().attrTween('transform', function (pt2) {
var interp = makeUpdateTextInterpolator(pt2, onPathbar, refRect, [width, height]);
return function (t) {
return strTransform(interp(t));
};
});
} else {
sliceText.attr('transform', strTransform(pt));
}
});
};
/***/ }),
/***/ 48988:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var svgTextUtils = __webpack_require__(41536);
var partition = __webpack_require__(55600);
var styleOne = (__webpack_require__(39624).styleOne);
var constants = __webpack_require__(73220);
var helpers = __webpack_require__(54844);
var attachFxHandlers = __webpack_require__(58528);
var formatSliceLabel = (__webpack_require__(35384).formatSliceLabel);
var onPathbar = false; // for Descendants
module.exports = function drawDescendants(gd, cd, entry, slices, opts) {
var width = opts.width;
var height = opts.height;
var viewX = opts.viewX;
var viewY = opts.viewY;
var pathSlice = opts.pathSlice;
var toMoveInsideSlice = opts.toMoveInsideSlice;
var strTransform = opts.strTransform;
var hasTransition = opts.hasTransition;
var handleSlicesExit = opts.handleSlicesExit;
var makeUpdateSliceInterpolator = opts.makeUpdateSliceInterpolator;
var makeUpdateTextInterpolator = opts.makeUpdateTextInterpolator;
var prevEntry = opts.prevEntry;
var refRect = {};
var isStatic = gd._context.staticPlot;
var fullLayout = gd._fullLayout;
var cd0 = cd[0];
var trace = cd0.trace;
var hasLeft = trace.textposition.indexOf('left') !== -1;
var hasRight = trace.textposition.indexOf('right') !== -1;
var hasBottom = trace.textposition.indexOf('bottom') !== -1;
var noRoomForHeader = !hasBottom && !trace.marker.pad.t || hasBottom && !trace.marker.pad.b;
// N.B. slice data isn't the calcdata,
// grab corresponding calcdata item in sliceData[i].data.data
var allData = partition(entry, [width, height], {
packing: trace.tiling.packing,
squarifyratio: trace.tiling.squarifyratio,
flipX: trace.tiling.flip.indexOf('x') > -1,
flipY: trace.tiling.flip.indexOf('y') > -1,
pad: {
inner: trace.tiling.pad,
top: trace.marker.pad.t,
left: trace.marker.pad.l,
right: trace.marker.pad.r,
bottom: trace.marker.pad.b
}
});
var sliceData = allData.descendants();
var minVisibleDepth = Infinity;
var maxVisibleDepth = -Infinity;
sliceData.forEach(function (pt) {
var depth = pt.depth;
if (depth >= trace._maxDepth) {
// hide slices that won't show up on graph
pt.x0 = pt.x1 = (pt.x0 + pt.x1) / 2;
pt.y0 = pt.y1 = (pt.y0 + pt.y1) / 2;
} else {
minVisibleDepth = Math.min(minVisibleDepth, depth);
maxVisibleDepth = Math.max(maxVisibleDepth, depth);
}
});
slices = slices.data(sliceData, helpers.getPtId);
trace._maxVisibleLayers = isFinite(maxVisibleDepth) ? maxVisibleDepth - minVisibleDepth + 1 : 0;
slices.enter().append('g').classed('slice', true);
handleSlicesExit(slices, onPathbar, refRect, [width, height], pathSlice);
slices.order();
// next coords of previous entry
var nextOfPrevEntry = null;
if (hasTransition && prevEntry) {
var prevEntryId = helpers.getPtId(prevEntry);
slices.each(function (pt) {
if (nextOfPrevEntry === null && helpers.getPtId(pt) === prevEntryId) {
nextOfPrevEntry = {
x0: pt.x0,
x1: pt.x1,
y0: pt.y0,
y1: pt.y1
};
}
});
}
var getRefRect = function () {
return nextOfPrevEntry || {
x0: 0,
x1: width,
y0: 0,
y1: height
};
};
var updateSlices = slices;
if (hasTransition) {
updateSlices = updateSlices.transition().each('end', function () {
// N.B. gd._transitioning is (still) *true* by the time
// transition updates get here
var sliceTop = d3.select(this);
helpers.setSliceCursor(sliceTop, gd, {
hideOnRoot: true,
hideOnLeaves: false,
isTransitioning: false
});
});
}
updateSlices.each(function (pt) {
var isHeader = helpers.isHeader(pt, trace);
// for bbox
pt._x0 = viewX(pt.x0);
pt._x1 = viewX(pt.x1);
pt._y0 = viewY(pt.y0);
pt._y1 = viewY(pt.y1);
pt._hoverX = viewX(pt.x1 - trace.marker.pad.r), pt._hoverY = hasBottom ? viewY(pt.y1 - trace.marker.pad.b / 2) : viewY(pt.y0 + trace.marker.pad.t / 2);
var sliceTop = d3.select(this);
var slicePath = Lib.ensureSingle(sliceTop, 'path', 'surface', function (s) {
s.style('pointer-events', isStatic ? 'none' : 'all');
});
if (hasTransition) {
slicePath.transition().attrTween('d', function (pt2) {
var interp = makeUpdateSliceInterpolator(pt2, onPathbar, getRefRect(), [width, height]);
return function (t) {
return pathSlice(interp(t));
};
});
} else {
slicePath.attr('d', pathSlice);
}
sliceTop.call(attachFxHandlers, entry, gd, cd, {
styleOne: styleOne,
eventDataKeys: constants.eventDataKeys,
transitionTime: constants.CLICK_TRANSITION_TIME,
transitionEasing: constants.CLICK_TRANSITION_EASING
}).call(helpers.setSliceCursor, gd, {
isTransitioning: gd._transitioning
});
slicePath.call(styleOne, pt, trace, gd, {
hovered: false
});
if (pt.x0 === pt.x1 || pt.y0 === pt.y1) {
pt._text = '';
} else {
if (isHeader) {
pt._text = noRoomForHeader ? '' : helpers.getPtLabel(pt) || '';
} else {
pt._text = formatSliceLabel(pt, entry, trace, cd, fullLayout) || '';
}
}
var sliceTextGroup = Lib.ensureSingle(sliceTop, 'g', 'slicetext');
var sliceText = Lib.ensureSingle(sliceTextGroup, 'text', '', function (s) {
// prohibit tex interpretation until we can handle
// tex and regular text together
s.attr('data-notex', 1);
});
var font = Lib.ensureUniformFontSize(gd, helpers.determineTextFont(trace, pt, fullLayout.font));
var text = pt._text || ' '; // use one space character instead of a blank string to avoid jumps during transition
var singleLineHeader = isHeader && text.indexOf('
') === -1;
sliceText.text(text).classed('slicetext', true).attr('text-anchor', hasRight ? 'end' : hasLeft || singleLineHeader ? 'start' : 'middle').call(Drawing.font, font).call(svgTextUtils.convertToTspans, gd);
pt.textBB = Drawing.bBox(sliceText.node());
pt.transform = toMoveInsideSlice(pt, {
fontSize: font.size,
isHeader: isHeader
});
pt.transform.fontSize = font.size;
if (hasTransition) {
sliceText.transition().attrTween('transform', function (pt2) {
var interp = makeUpdateTextInterpolator(pt2, onPathbar, getRefRect(), [width, height]);
return function (t) {
return strTransform(interp(t));
};
});
} else {
sliceText.attr('transform', strTransform(pt));
}
});
return nextOfPrevEntry;
};
/***/ }),
/***/ 57984:
/***/ (function(module) {
"use strict";
module.exports = function flipTree(node, size, opts) {
var tmp;
if (opts.swapXY) {
// swap x0 and y0
tmp = node.x0;
node.x0 = node.y0;
node.y0 = tmp;
// swap x1 and y1
tmp = node.x1;
node.x1 = node.y1;
node.y1 = tmp;
}
if (opts.flipX) {
tmp = node.x0;
node.x0 = size[0] - node.x1;
node.x1 = size[0] - tmp;
}
if (opts.flipY) {
tmp = node.y0;
node.y0 = size[1] - node.y1;
node.y1 = size[1] - tmp;
}
var children = node.children;
if (children) {
for (var i = 0; i < children.length; i++) {
flipTree(children[i], size, opts);
}
}
};
/***/ }),
/***/ 67592:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
moduleType: 'trace',
name: 'treemap',
basePlotModule: __webpack_require__(53088),
categories: [],
animatable: true,
attributes: __webpack_require__(36468),
layoutAttributes: __webpack_require__(85652),
supplyDefaults: __webpack_require__(95616),
supplyLayoutDefaults: __webpack_require__(74924),
calc: (__webpack_require__(88844)/* .calc */ .r),
crossTraceCalc: (__webpack_require__(88844)/* .crossTraceCalc */ .q),
plot: __webpack_require__(21440),
style: (__webpack_require__(39624).style),
colorbar: __webpack_require__(71416),
meta: {
description: ['Visualize hierarchal data from leaves (and/or outer branches) towards root', 'with rectangles. The treemap sectors are determined by the entries in', '*labels* or *ids* and in *parents*.'].join(' ')
}
};
/***/ }),
/***/ 85652:
/***/ (function(module) {
"use strict";
module.exports = {
treemapcolorway: {
valType: 'colorlist',
editType: 'calc',
description: ['Sets the default treemap slice colors. Defaults to the main', '`colorway` used for trace colors. If you specify a new', 'list here it can still be extended with lighter and darker', 'colors, see `extendtreemapcolors`.'].join(' ')
},
extendtreemapcolors: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['If `true`, the treemap slice colors (whether given by `treemapcolorway` or', 'inherited from `colorway`) will be extended to three times its', 'original length by first repeating every color 20% lighter then', 'each color 20% darker. This is intended to reduce the likelihood', 'of reusing the same color when you have many slices, but you can', 'set `false` to disable.', 'Colors provided in the trace, using `marker.colors`, are never', 'extended.'].join(' ')
}
};
/***/ }),
/***/ 74924:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(85652);
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
coerce('treemapcolorway', layoutOut.colorway);
coerce('extendtreemapcolors');
};
/***/ }),
/***/ 55600:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3Hierarchy = __webpack_require__(89332);
var flipTree = __webpack_require__(57984);
module.exports = function partition(entry, size, opts) {
var flipX = opts.flipX;
var flipY = opts.flipY;
var swapXY = opts.packing === 'dice-slice';
var top = opts.pad[flipY ? 'bottom' : 'top'];
var left = opts.pad[flipX ? 'right' : 'left'];
var right = opts.pad[flipX ? 'left' : 'right'];
var bottom = opts.pad[flipY ? 'top' : 'bottom'];
var tmp;
if (swapXY) {
tmp = left;
left = top;
top = tmp;
tmp = right;
right = bottom;
bottom = tmp;
}
var result = d3Hierarchy.treemap().tile(getTilingMethod(opts.packing, opts.squarifyratio)).paddingInner(opts.pad.inner).paddingLeft(left).paddingRight(right).paddingTop(top).paddingBottom(bottom).size(swapXY ? [size[1], size[0]] : size)(entry);
if (swapXY || flipX || flipY) {
flipTree(result, size, {
swapXY: swapXY,
flipX: flipX,
flipY: flipY
});
}
return result;
};
function getTilingMethod(key, squarifyratio) {
switch (key) {
case 'squarify':
return d3Hierarchy.treemapSquarify.ratio(squarifyratio);
case 'binary':
return d3Hierarchy.treemapBinary;
case 'dice':
return d3Hierarchy.treemapDice;
case 'slice':
return d3Hierarchy.treemapSlice;
default:
// i.e. 'slice-dice' | 'dice-slice'
return d3Hierarchy.treemapSliceDice;
}
}
/***/ }),
/***/ 21440:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var draw = __webpack_require__(62148);
var drawDescendants = __webpack_require__(48988);
module.exports = function _plot(gd, cdmodule, transitionOpts, makeOnCompleteCallback) {
return draw(gd, cdmodule, transitionOpts, makeOnCompleteCallback, {
type: 'treemap',
drawDescendants: drawDescendants
});
};
/***/ }),
/***/ 82856:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var interpolate = (__webpack_require__(78204)/* .interpolate */ .qy);
var helpers = __webpack_require__(54844);
var Lib = __webpack_require__(10923);
var TEXTPAD = (__webpack_require__(77216).TEXTPAD);
var barPlot = __webpack_require__(39176);
var toMoveInsideBar = barPlot.toMoveInsideBar;
var uniformText = __webpack_require__(4096);
var recordMinTextSize = uniformText.recordMinTextSize;
var constants = __webpack_require__(73220);
var drawAncestors = __webpack_require__(17512);
function getKey(pt) {
return helpers.isHierarchyRoot(pt) ? '' :
// don't use the dummyId
helpers.getPtId(pt);
}
module.exports = function plotOne(gd, cd, element, transitionOpts, drawDescendants) {
var fullLayout = gd._fullLayout;
var cd0 = cd[0];
var trace = cd0.trace;
var type = trace.type;
var isIcicle = type === 'icicle';
var hierarchy = cd0.hierarchy;
var entry = helpers.findEntryWithLevel(hierarchy, trace.level);
var gTrace = d3.select(element);
var selAncestors = gTrace.selectAll('g.pathbar');
var selDescendants = gTrace.selectAll('g.slice');
if (!entry) {
selAncestors.remove();
selDescendants.remove();
return;
}
var isRoot = helpers.isHierarchyRoot(entry);
var hasTransition = !fullLayout.uniformtext.mode && helpers.hasTransition(transitionOpts);
var maxDepth = helpers.getMaxDepth(trace);
var hasVisibleDepth = function (pt) {
return pt.data.depth - entry.data.depth < maxDepth;
};
var gs = fullLayout._size;
var domain = trace.domain;
var vpw = gs.w * (domain.x[1] - domain.x[0]);
var vph = gs.h * (domain.y[1] - domain.y[0]);
var barW = vpw;
var barH = trace.pathbar.thickness;
var barPad = trace.marker.line.width + constants.gapWithPathbar;
var barDifY = !trace.pathbar.visible ? 0 : trace.pathbar.side.indexOf('bottom') > -1 ? vph + barPad : -(barH + barPad);
var pathbarOrigin = {
x0: barW,
// slide to the right
x1: barW,
y0: barDifY,
y1: barDifY + barH
};
var findClosestEdge = function (pt, ref, size) {
var e = trace.tiling.pad;
var isLeftOfRect = function (x) {
return x - e <= ref.x0;
};
var isRightOfRect = function (x) {
return x + e >= ref.x1;
};
var isBottomOfRect = function (y) {
return y - e <= ref.y0;
};
var isTopOfRect = function (y) {
return y + e >= ref.y1;
};
if (pt.x0 === ref.x0 && pt.x1 === ref.x1 && pt.y0 === ref.y0 && pt.y1 === ref.y1) {
return {
x0: pt.x0,
x1: pt.x1,
y0: pt.y0,
y1: pt.y1
};
}
return {
x0: isLeftOfRect(pt.x0 - e) ? 0 : isRightOfRect(pt.x0 - e) ? size[0] : pt.x0,
x1: isLeftOfRect(pt.x1 + e) ? 0 : isRightOfRect(pt.x1 + e) ? size[0] : pt.x1,
y0: isBottomOfRect(pt.y0 - e) ? 0 : isTopOfRect(pt.y0 - e) ? size[1] : pt.y0,
y1: isBottomOfRect(pt.y1 + e) ? 0 : isTopOfRect(pt.y1 + e) ? size[1] : pt.y1
};
};
// stash of 'previous' position data used by tweening functions
var prevEntry = null;
var prevLookupPathbar = {};
var prevLookupSlices = {};
var nextOfPrevEntry = null;
var getPrev = function (pt, onPathbar) {
return onPathbar ? prevLookupPathbar[getKey(pt)] : prevLookupSlices[getKey(pt)];
};
var getOrigin = function (pt, onPathbar, refRect, size) {
if (onPathbar) {
return prevLookupPathbar[getKey(hierarchy)] || pathbarOrigin;
} else {
var ref = prevLookupSlices[trace.level] || refRect;
if (hasVisibleDepth(pt)) {
// case of an empty object - happens when maxdepth is set
return findClosestEdge(pt, ref, size);
}
}
return {};
};
// N.B. handle multiple-root special case
if (cd0.hasMultipleRoots && isRoot) {
maxDepth++;
}
trace._maxDepth = maxDepth;
trace._backgroundColor = fullLayout.paper_bgcolor;
trace._entryDepth = entry.data.depth;
trace._atRootLevel = isRoot;
var cenX = -vpw / 2 + gs.l + gs.w * (domain.x[1] + domain.x[0]) / 2;
var cenY = -vph / 2 + gs.t + gs.h * (1 - (domain.y[1] + domain.y[0]) / 2);
var viewMapX = function (x) {
return cenX + x;
};
var viewMapY = function (y) {
return cenY + y;
};
var barY0 = viewMapY(0);
var barX0 = viewMapX(0);
var viewBarX = function (x) {
return barX0 + x;
};
var viewBarY = function (y) {
return barY0 + y;
};
function pos(x, y) {
return x + ',' + y;
}
var xStart = viewBarX(0);
var limitX0 = function (p) {
p.x = Math.max(xStart, p.x);
};
var edgeshape = trace.pathbar.edgeshape;
// pathbar(directory) path generation fn
var pathAncestor = function (d) {
var _x0 = viewBarX(Math.max(Math.min(d.x0, d.x0), 0));
var _x1 = viewBarX(Math.min(Math.max(d.x1, d.x1), barW));
var _y0 = viewBarY(d.y0);
var _y1 = viewBarY(d.y1);
var halfH = barH / 2;
var pL = {};
var pR = {};
pL.x = _x0;
pR.x = _x1;
pL.y = pR.y = (_y0 + _y1) / 2;
var pA = {
x: _x0,
y: _y0
};
var pB = {
x: _x1,
y: _y0
};
var pC = {
x: _x1,
y: _y1
};
var pD = {
x: _x0,
y: _y1
};
if (edgeshape === '>') {
pA.x -= halfH;
pB.x -= halfH;
pC.x -= halfH;
pD.x -= halfH;
} else if (edgeshape === '/') {
pC.x -= halfH;
pD.x -= halfH;
pL.x -= halfH / 2;
pR.x -= halfH / 2;
} else if (edgeshape === '\\') {
pA.x -= halfH;
pB.x -= halfH;
pL.x -= halfH / 2;
pR.x -= halfH / 2;
} else if (edgeshape === '<') {
pL.x -= halfH;
pR.x -= halfH;
}
limitX0(pA);
limitX0(pD);
limitX0(pL);
limitX0(pB);
limitX0(pC);
limitX0(pR);
return 'M' + pos(pA.x, pA.y) + 'L' + pos(pB.x, pB.y) + 'L' + pos(pR.x, pR.y) + 'L' + pos(pC.x, pC.y) + 'L' + pos(pD.x, pD.y) + 'L' + pos(pL.x, pL.y) + 'Z';
};
// Note that `pad` is just an integer for `icicle`` traces where
// `pad` is a hashmap for treemap: pad.t, pad.b, pad.l, and pad.r
var pad = trace[isIcicle ? 'tiling' : 'marker'].pad;
var hasFlag = function (f) {
return trace.textposition.indexOf(f) !== -1;
};
var hasTop = hasFlag('top');
var hasLeft = hasFlag('left');
var hasRight = hasFlag('right');
var hasBottom = hasFlag('bottom');
// slice path generation fn
var pathDescendant = function (d) {
var _x0 = viewMapX(d.x0);
var _x1 = viewMapX(d.x1);
var _y0 = viewMapY(d.y0);
var _y1 = viewMapY(d.y1);
var dx = _x1 - _x0;
var dy = _y1 - _y0;
if (!dx || !dy) return '';
var cornerradius = trace.marker.cornerradius || 0;
var r = Math.min(cornerradius, dx / 2, dy / 2);
if (r && d.data && d.data.data && d.data.data.label) {
if (hasTop) r = Math.min(r, pad.t);
if (hasLeft) r = Math.min(r, pad.l);
if (hasRight) r = Math.min(r, pad.r);
if (hasBottom) r = Math.min(r, pad.b);
}
var arc = function (rx, ry) {
return r ? 'a' + pos(r, r) + ' 0 0 1 ' + pos(rx, ry) : '';
};
return 'M' + pos(_x0, _y0 + r) + arc(r, -r) + 'L' + pos(_x1 - r, _y0) + arc(r, r) + 'L' + pos(_x1, _y1 - r) + arc(-r, r) + 'L' + pos(_x0 + r, _y1) + arc(-r, -r) + 'Z';
};
var toMoveInsideSlice = function (pt, opts) {
var x0 = pt.x0;
var x1 = pt.x1;
var y0 = pt.y0;
var y1 = pt.y1;
var textBB = pt.textBB;
var _hasTop = hasTop || opts.isHeader && !hasBottom;
var anchor = _hasTop ? 'start' : hasBottom ? 'end' : 'middle';
var _hasRight = hasFlag('right');
var _hasLeft = hasFlag('left') || opts.onPathbar;
var leftToRight = _hasLeft ? -1 : _hasRight ? 1 : 0;
if (opts.isHeader) {
x0 += (isIcicle ? pad : pad.l) - TEXTPAD;
x1 -= (isIcicle ? pad : pad.r) - TEXTPAD;
if (x0 >= x1) {
var mid = (x0 + x1) / 2;
x0 = mid;
x1 = mid;
}
// limit the drawing area for headers
var limY;
if (hasBottom) {
limY = y1 - (isIcicle ? pad : pad.b);
if (y0 < limY && limY < y1) y0 = limY;
} else {
limY = y0 + (isIcicle ? pad : pad.t);
if (y0 < limY && limY < y1) y1 = limY;
}
}
// position the text relative to the slice
var transform = toMoveInsideBar(x0, x1, y0, y1, textBB, {
isHorizontal: false,
constrained: true,
angle: 0,
anchor: anchor,
leftToRight: leftToRight
});
transform.fontSize = opts.fontSize;
transform.targetX = viewMapX(transform.targetX);
transform.targetY = viewMapY(transform.targetY);
if (isNaN(transform.targetX) || isNaN(transform.targetY)) {
return {};
}
if (x0 !== x1 && y0 !== y1) {
recordMinTextSize(trace.type, transform, fullLayout);
}
return {
scale: transform.scale,
rotate: transform.rotate,
textX: transform.textX,
textY: transform.textY,
anchorX: transform.anchorX,
anchorY: transform.anchorY,
targetX: transform.targetX,
targetY: transform.targetY
};
};
var interpFromParent = function (pt, onPathbar) {
var parentPrev;
var i = 0;
var Q = pt;
while (!parentPrev && i < maxDepth) {
// loop to find a parent/grandParent on the previous graph
i++;
Q = Q.parent;
if (Q) {
parentPrev = getPrev(Q, onPathbar);
} else i = maxDepth;
}
return parentPrev || {};
};
var makeExitSliceInterpolator = function (pt, onPathbar, refRect, size) {
var prev = getPrev(pt, onPathbar);
var next;
if (onPathbar) {
next = pathbarOrigin;
} else {
var entryPrev = getPrev(entry, onPathbar);
if (entryPrev) {
// 'entryPrev' is here has the previous coordinates of the entry
// node, which corresponds to the last "clicked" node when zooming in
next = findClosestEdge(pt, entryPrev, size);
} else {
// this happens when maxdepth is set, when leaves must
// be removed and the entry is new (i.e. does not have a 'prev' object)
next = {};
}
}
return interpolate(prev, next);
};
var makeUpdateSliceInterpolator = function (pt, onPathbar, refRect, size, opts) {
var prev0 = getPrev(pt, onPathbar);
var prev;
if (prev0) {
// if pt already on graph, this is easy
prev = prev0;
} else {
// for new pts:
if (onPathbar) {
prev = pathbarOrigin;
} else {
if (prevEntry) {
// if trace was visible before
if (pt.parent) {
var ref = nextOfPrevEntry || refRect;
if (ref && !onPathbar) {
prev = findClosestEdge(pt, ref, size);
} else {
// if new leaf (when maxdepth is set),
// grow it from its parent node
prev = {};
Lib.extendFlat(prev, interpFromParent(pt, onPathbar));
}
} else {
prev = Lib.extendFlat({}, pt);
if (isIcicle) {
if (opts.orientation === 'h') {
if (opts.flipX) prev.x0 = pt.x1;else prev.x1 = 0;
} else {
if (opts.flipY) prev.y0 = pt.y1;else prev.y1 = 0;
}
}
}
} else {
prev = {};
}
}
}
return interpolate(prev, {
x0: pt.x0,
x1: pt.x1,
y0: pt.y0,
y1: pt.y1
});
};
var makeUpdateTextInterpolator = function (pt, onPathbar, refRect, size) {
var prev0 = getPrev(pt, onPathbar);
var prev = {};
var origin = getOrigin(pt, onPathbar, refRect, size);
Lib.extendFlat(prev, {
transform: toMoveInsideSlice({
x0: origin.x0,
x1: origin.x1,
y0: origin.y0,
y1: origin.y1,
textBB: pt.textBB,
_text: pt._text
}, {
isHeader: helpers.isHeader(pt, trace)
})
});
if (prev0) {
// if pt already on graph, this is easy
prev = prev0;
} else {
// for new pts:
if (pt.parent) {
Lib.extendFlat(prev, interpFromParent(pt, onPathbar));
}
}
var transform = pt.transform;
if (pt.x0 !== pt.x1 && pt.y0 !== pt.y1) {
recordMinTextSize(trace.type, transform, fullLayout);
}
return interpolate(prev, {
transform: {
scale: transform.scale,
rotate: transform.rotate,
textX: transform.textX,
textY: transform.textY,
anchorX: transform.anchorX,
anchorY: transform.anchorY,
targetX: transform.targetX,
targetY: transform.targetY
}
});
};
var handleSlicesExit = function (slices, onPathbar, refRect, size, pathSlice) {
var width = size[0];
var height = size[1];
if (hasTransition) {
slices.exit().transition().each(function () {
var sliceTop = d3.select(this);
var slicePath = sliceTop.select('path.surface');
slicePath.transition().attrTween('d', function (pt2) {
var interp = makeExitSliceInterpolator(pt2, onPathbar, refRect, [width, height]);
return function (t) {
return pathSlice(interp(t));
};
});
var sliceTextGroup = sliceTop.select('g.slicetext');
sliceTextGroup.attr('opacity', 0);
}).remove();
} else {
slices.exit().remove();
}
};
var strTransform = function (d) {
var transform = d.transform;
if (d.x0 !== d.x1 && d.y0 !== d.y1) {
recordMinTextSize(trace.type, transform, fullLayout);
}
return Lib.getTextTransform({
textX: transform.textX,
textY: transform.textY,
anchorX: transform.anchorX,
anchorY: transform.anchorY,
targetX: transform.targetX,
targetY: transform.targetY,
scale: transform.scale,
rotate: transform.rotate
});
};
if (hasTransition) {
// Important: do this before binding new sliceData!
selAncestors.each(function (pt) {
prevLookupPathbar[getKey(pt)] = {
x0: pt.x0,
x1: pt.x1,
y0: pt.y0,
y1: pt.y1
};
if (pt.transform) {
prevLookupPathbar[getKey(pt)].transform = {
textX: pt.transform.textX,
textY: pt.transform.textY,
anchorX: pt.transform.anchorX,
anchorY: pt.transform.anchorY,
targetX: pt.transform.targetX,
targetY: pt.transform.targetY,
scale: pt.transform.scale,
rotate: pt.transform.rotate
};
}
});
selDescendants.each(function (pt) {
prevLookupSlices[getKey(pt)] = {
x0: pt.x0,
x1: pt.x1,
y0: pt.y0,
y1: pt.y1
};
if (pt.transform) {
prevLookupSlices[getKey(pt)].transform = {
textX: pt.transform.textX,
textY: pt.transform.textY,
anchorX: pt.transform.anchorX,
anchorY: pt.transform.anchorY,
targetX: pt.transform.targetX,
targetY: pt.transform.targetY,
scale: pt.transform.scale,
rotate: pt.transform.rotate
};
}
if (!prevEntry && helpers.isEntry(pt)) {
prevEntry = pt;
}
});
}
nextOfPrevEntry = drawDescendants(gd, cd, entry, selDescendants, {
width: vpw,
height: vph,
viewX: viewMapX,
viewY: viewMapY,
pathSlice: pathDescendant,
toMoveInsideSlice: toMoveInsideSlice,
prevEntry: prevEntry,
makeUpdateSliceInterpolator: makeUpdateSliceInterpolator,
makeUpdateTextInterpolator: makeUpdateTextInterpolator,
handleSlicesExit: handleSlicesExit,
hasTransition: hasTransition,
strTransform: strTransform
});
if (trace.pathbar.visible) {
drawAncestors(gd, cd, entry, selAncestors, {
barDifY: barDifY,
width: barW,
height: barH,
viewX: viewBarX,
viewY: viewBarY,
pathSlice: pathAncestor,
toMoveInsideSlice: toMoveInsideSlice,
makeUpdateSliceInterpolator: makeUpdateSliceInterpolator,
makeUpdateTextInterpolator: makeUpdateTextInterpolator,
handleSlicesExit: handleSlicesExit,
hasTransition: hasTransition,
strTransform: strTransform
});
} else {
selAncestors.remove();
}
};
/***/ }),
/***/ 39624:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Color = __webpack_require__(9240);
var Lib = __webpack_require__(10923);
var helpers = __webpack_require__(54844);
var resizeText = (__webpack_require__(4096).resizeText);
var fillOne = __webpack_require__(81136);
function style(gd) {
var s = gd._fullLayout._treemaplayer.selectAll('.trace');
resizeText(gd, s, 'treemap');
s.each(function (cd) {
var gTrace = d3.select(this);
var cd0 = cd[0];
var trace = cd0.trace;
gTrace.style('opacity', trace.opacity);
gTrace.selectAll('path.surface').each(function (pt) {
d3.select(this).call(styleOne, pt, trace, gd, {
hovered: false
});
});
});
}
function styleOne(s, pt, trace, gd, opts) {
var hovered = (opts || {}).hovered;
var cdi = pt.data.data;
var ptNumber = cdi.i;
var lineColor;
var lineWidth;
var fillColor = cdi.color;
var isRoot = helpers.isHierarchyRoot(pt);
var opacity = 1;
if (hovered) {
lineColor = trace._hovered.marker.line.color;
lineWidth = trace._hovered.marker.line.width;
} else {
if (isRoot && fillColor === trace.root.color) {
opacity = 100;
lineColor = 'rgba(0,0,0,0)';
lineWidth = 0;
} else {
lineColor = Lib.castOption(trace, ptNumber, 'marker.line.color') || Color.defaultLine;
lineWidth = Lib.castOption(trace, ptNumber, 'marker.line.width') || 0;
if (!trace._hasColorscale && !pt.onPathbar) {
var depthfade = trace.marker.depthfade;
if (depthfade) {
var fadedColor = Color.combine(Color.addOpacity(trace._backgroundColor, 0.75), fillColor);
var n;
if (depthfade === true) {
var maxDepth = helpers.getMaxDepth(trace);
if (isFinite(maxDepth)) {
if (helpers.isLeaf(pt)) {
n = 0;
} else {
n = trace._maxVisibleLayers - (pt.data.depth - trace._entryDepth);
}
} else {
n = pt.data.height + 1;
}
} else {
// i.e. case of depthfade === 'reversed'
n = pt.data.depth - trace._entryDepth;
if (!trace._atRootLevel) n++;
}
if (n > 0) {
for (var i = 0; i < n; i++) {
var ratio = 0.5 * i / n;
fillColor = Color.combine(Color.addOpacity(fadedColor, ratio), fillColor);
}
}
}
}
}
}
s.call(fillOne, pt, trace, gd, fillColor).style('stroke-width', lineWidth).call(Color.stroke, lineColor).style('opacity', opacity);
}
module.exports = {
style: style,
styleOne: styleOne
};
/***/ }),
/***/ 62808:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var boxAttrs = __webpack_require__(12292);
var extendFlat = (__webpack_require__(55016).extendFlat);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
module.exports = {
y: boxAttrs.y,
x: boxAttrs.x,
x0: boxAttrs.x0,
y0: boxAttrs.y0,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
name: extendFlat({}, boxAttrs.name, {
description: ['Sets the trace name.', 'The trace name appears as the legend item and on hover.', 'For violin traces, the name will also be used for the position', 'coordinate, if `x` and `x0` (`y` and `y0` if horizontal) are', 'missing and the position axis is categorical.', 'Note that the trace name is also used as a default value', 'for attribute `scalegroup` (please see its description for details).'].join(' ')
}),
orientation: extendFlat({}, boxAttrs.orientation, {
description: ['Sets the orientation of the violin(s).', 'If *v* (*h*), the distribution is visualized along', 'the vertical (horizontal).'].join(' ')
}),
bandwidth: {
valType: 'number',
min: 0,
editType: 'calc',
description: ['Sets the bandwidth used to compute the kernel density estimate.', 'By default, the bandwidth is determined by Silverman\'s rule of thumb.'].join(' ')
},
scalegroup: {
valType: 'string',
dflt: '',
editType: 'calc',
description: ['If there are multiple violins that should be sized according to', 'to some metric (see `scalemode`), link them by providing a non-empty group id here', 'shared by every trace in the same group.', 'If a violin\'s `width` is undefined, `scalegroup` will default to the trace\'s name.', 'In this case, violins with the same names will be linked together'].join(' ')
},
scalemode: {
valType: 'enumerated',
values: ['width', 'count'],
dflt: 'width',
editType: 'calc',
description: ['Sets the metric by which the width of each violin is determined.', '*width* means each violin has the same (max) width', '*count* means the violins are scaled by the number of sample points making', 'up each violin.'].join(' ')
},
spanmode: {
valType: 'enumerated',
values: ['soft', 'hard', 'manual'],
dflt: 'soft',
editType: 'calc',
description: ['Sets the method by which the span in data space where the density function will be computed.', '*soft* means the span goes from the sample\'s minimum value minus two bandwidths', 'to the sample\'s maximum value plus two bandwidths.', '*hard* means the span goes from the sample\'s minimum to its maximum value.', 'For custom span settings, use mode *manual* and fill in the `span` attribute.'].join(' ')
},
span: {
valType: 'info_array',
items: [{
valType: 'any',
editType: 'calc'
}, {
valType: 'any',
editType: 'calc'
}],
editType: 'calc',
description: ['Sets the span in data space for which the density function will be computed.', 'Has an effect only when `spanmode` is set to *manual*.'].join(' ')
},
line: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the color of line bounding the violin(s).'
},
width: {
valType: 'number',
min: 0,
dflt: 2,
editType: 'style',
description: 'Sets the width (in px) of line bounding the violin(s).'
},
editType: 'plot'
},
fillcolor: boxAttrs.fillcolor,
points: extendFlat({}, boxAttrs.boxpoints, {
description: ['If *outliers*, only the sample points lying outside the whiskers', 'are shown', 'If *suspectedoutliers*, the outlier points are shown and', 'points either less than 4*Q1-3*Q3 or greater than 4*Q3-3*Q1', 'are highlighted (see `outliercolor`)', 'If *all*, all sample points are shown', 'If *false*, only the violins are shown with no sample points.', 'Defaults to *suspectedoutliers* when `marker.outliercolor` or', '`marker.line.outliercolor` is set,', 'otherwise defaults to *outliers*.'].join(' ')
}),
jitter: extendFlat({}, boxAttrs.jitter, {
description: ['Sets the amount of jitter in the sample points drawn.', 'If *0*, the sample points align along the distribution axis.', 'If *1*, the sample points are drawn in a random jitter of width', 'equal to the width of the violins.'].join(' ')
}),
pointpos: extendFlat({}, boxAttrs.pointpos, {
description: ['Sets the position of the sample points in relation to the violins.', 'If *0*, the sample points are places over the center of the violins.', 'Positive (negative) values correspond to positions to the', 'right (left) for vertical violins and above (below) for horizontal violins.'].join(' ')
}),
width: extendFlat({}, boxAttrs.width, {
description: ['Sets the width of the violin in data coordinates.', 'If *0* (default value) the width is automatically selected based on the positions', 'of other violin traces in the same subplot.'].join(' ')
}),
marker: boxAttrs.marker,
text: boxAttrs.text,
hovertext: boxAttrs.hovertext,
hovertemplate: boxAttrs.hovertemplate,
quartilemethod: boxAttrs.quartilemethod,
box: {
visible: {
valType: 'boolean',
dflt: false,
editType: 'plot',
description: ['Determines if an miniature box plot is drawn inside the violins. '].join(' ')
},
width: {
valType: 'number',
min: 0,
max: 1,
dflt: 0.25,
editType: 'plot',
description: ['Sets the width of the inner box plots relative to', 'the violins\' width.', 'For example, with 1, the inner box plots are as wide as the violins.'].join(' ')
},
fillcolor: {
valType: 'color',
editType: 'style',
description: 'Sets the inner box plot fill color.'
},
line: {
color: {
valType: 'color',
editType: 'style',
description: 'Sets the inner box plot bounding line color.'
},
width: {
valType: 'number',
min: 0,
editType: 'style',
description: 'Sets the inner box plot bounding line width.'
},
editType: 'style'
},
editType: 'plot'
},
meanline: {
visible: {
valType: 'boolean',
dflt: false,
editType: 'plot',
description: ['Determines if a line corresponding to the sample\'s mean is shown', 'inside the violins.', 'If `box.visible` is turned on, the mean line is drawn inside the inner box.', 'Otherwise, the mean line is drawn from one side of the violin to other.'].join(' ')
},
color: {
valType: 'color',
editType: 'style',
description: 'Sets the mean line color.'
},
width: {
valType: 'number',
min: 0,
editType: 'style',
description: 'Sets the mean line width.'
},
editType: 'plot'
},
side: {
valType: 'enumerated',
values: ['both', 'positive', 'negative'],
dflt: 'both',
editType: 'calc',
description: ['Determines on which side of the position value the density function making up', 'one half of a violin is plotted.', 'Useful when comparing two violin traces under *overlay* mode, where one trace', 'has `side` set to *positive* and the other to *negative*.'].join(' ')
},
offsetgroup: boxAttrs.offsetgroup,
alignmentgroup: boxAttrs.alignmentgroup,
selected: boxAttrs.selected,
unselected: boxAttrs.unselected,
hoveron: {
valType: 'flaglist',
flags: ['violins', 'points', 'kde'],
dflt: 'violins+points+kde',
extras: ['all'],
editType: 'style',
description: ['Do the hover effects highlight individual violins', 'or sample points or the kernel density estimate or any combination of them?'].join(' ')
},
zorder: boxAttrs.zorder
};
/***/ }),
/***/ 87100:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Axes = __webpack_require__(81536);
var boxCalc = __webpack_require__(75816);
var helpers = __webpack_require__(55596);
var BADNUM = (__webpack_require__(41752).BADNUM);
module.exports = function calc(gd, trace) {
var cd = boxCalc(gd, trace);
if (cd[0].t.empty) return cd;
var fullLayout = gd._fullLayout;
var valAxis = Axes.getFromId(gd, trace[trace.orientation === 'h' ? 'xaxis' : 'yaxis']);
var spanMin = Infinity;
var spanMax = -Infinity;
var maxKDE = 0;
var maxCount = 0;
for (var i = 0; i < cd.length; i++) {
var cdi = cd[i];
var vals = cdi.pts.map(helpers.extractVal);
var bandwidth = cdi.bandwidth = calcBandwidth(trace, cdi, vals);
var span = cdi.span = calcSpan(trace, cdi, valAxis, bandwidth);
if (cdi.min === cdi.max && bandwidth === 0) {
// if span is zero and bandwidth is zero, we want a violin with zero width
span = cdi.span = [cdi.min, cdi.max];
cdi.density = [{
v: 1,
t: span[0]
}];
cdi.bandwidth = bandwidth;
maxKDE = Math.max(maxKDE, 1);
} else {
// step that well covers the bandwidth and is multiple of span distance
var dist = span[1] - span[0];
var n = Math.ceil(dist / (bandwidth / 3));
var step = dist / n;
if (!isFinite(step) || !isFinite(n)) {
Lib.error('Something went wrong with computing the violin span');
cd[0].t.empty = true;
return cd;
}
var kde = helpers.makeKDE(cdi, trace, vals);
cdi.density = new Array(n);
for (var k = 0, t = span[0]; t < span[1] + step / 2; k++, t += step) {
var v = kde(t);
cdi.density[k] = {
v: v,
t: t
};
maxKDE = Math.max(maxKDE, v);
}
}
maxCount = Math.max(maxCount, vals.length);
spanMin = Math.min(spanMin, span[0]);
spanMax = Math.max(spanMax, span[1]);
}
var extremes = Axes.findExtremes(valAxis, [spanMin, spanMax], {
padded: true
});
trace._extremes[valAxis._id] = extremes;
if (trace.width) {
cd[0].t.maxKDE = maxKDE;
} else {
var violinScaleGroupStats = fullLayout._violinScaleGroupStats;
var scaleGroup = trace.scalegroup;
var groupStats = violinScaleGroupStats[scaleGroup];
if (groupStats) {
groupStats.maxKDE = Math.max(groupStats.maxKDE, maxKDE);
groupStats.maxCount = Math.max(groupStats.maxCount, maxCount);
} else {
violinScaleGroupStats[scaleGroup] = {
maxKDE: maxKDE,
maxCount: maxCount
};
}
}
cd[0].t.labels.kde = Lib._(gd, 'kde:');
return cd;
};
// Default to Silveman's rule of thumb
// - https://stats.stackexchange.com/a/6671
// - https://en.wikipedia.org/wiki/Kernel_density_estimation#A_rule-of-thumb_bandwidth_estimator
// - https://github.com/statsmodels/statsmodels/blob/master/statsmodels/nonparametric/bandwidths.py
function silvermanRule(len, ssd, iqr) {
var a = Math.min(ssd, iqr / 1.349);
return 1.059 * a * Math.pow(len, -0.2);
}
function calcBandwidth(trace, cdi, vals) {
var span = cdi.max - cdi.min;
// If span is zero
if (!span) {
if (trace.bandwidth) {
return trace.bandwidth;
} else {
// if span is zero and no bandwidth is specified
// it returns zero bandwidth which is a special case
return 0;
}
}
// Limit how small the bandwidth can be.
//
// Silverman's rule of thumb can be "very" small
// when IQR does a poor job at describing the spread
// of the distribution.
// We also want to limit custom bandwidths
// to not blow up kde computations.
if (trace.bandwidth) {
return Math.max(trace.bandwidth, span / 1e4);
} else {
var len = vals.length;
var ssd = Lib.stdev(vals, len - 1, cdi.mean);
return Math.max(silvermanRule(len, ssd, cdi.q3 - cdi.q1), span / 100);
}
}
function calcSpan(trace, cdi, valAxis, bandwidth) {
var spanmode = trace.spanmode;
var spanIn = trace.span || [];
var spanTight = [cdi.min, cdi.max];
var spanLoose = [cdi.min - 2 * bandwidth, cdi.max + 2 * bandwidth];
var spanOut;
function calcSpanItem(index) {
var s = spanIn[index];
var sc = valAxis.type === 'multicategory' ? valAxis.r2c(s) : valAxis.d2c(s, 0, trace[cdi.valLetter + 'calendar']);
return sc === BADNUM ? spanLoose[index] : sc;
}
if (spanmode === 'soft') {
spanOut = spanLoose;
} else if (spanmode === 'hard') {
spanOut = spanTight;
} else {
spanOut = [calcSpanItem(0), calcSpanItem(1)];
}
// to reuse the equal-range-item block
var dummyAx = {
type: 'linear',
range: spanOut
};
Axes.setConvert(dummyAx);
dummyAx.cleanRange();
return spanOut;
}
/***/ }),
/***/ 57848:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var setPositionOffset = (__webpack_require__(67872).setPositionOffset);
var orientations = ['v', 'h'];
module.exports = function crossTraceCalc(gd, plotinfo) {
var calcdata = gd.calcdata;
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
for (var i = 0; i < orientations.length; i++) {
var orientation = orientations[i];
var posAxis = orientation === 'h' ? ya : xa;
var violinList = [];
for (var j = 0; j < calcdata.length; j++) {
var cd = calcdata[j];
var t = cd[0].t;
var trace = cd[0].trace;
if (trace.visible === true && trace.type === 'violin' && !t.empty && trace.orientation === orientation && trace.xaxis === xa._id && trace.yaxis === ya._id) {
violinList.push(j);
}
}
setPositionOffset('violin', gd, violinList, posAxis);
}
};
/***/ }),
/***/ 85792:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Color = __webpack_require__(9240);
var boxDefaults = __webpack_require__(18024);
var attributes = __webpack_require__(62808);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
function coerce2(attr, dflt) {
return Lib.coerce2(traceIn, traceOut, attributes, attr, dflt);
}
boxDefaults.handleSampleDefaults(traceIn, traceOut, coerce, layout);
if (traceOut.visible === false) return;
coerce('bandwidth');
coerce('side');
var width = coerce('width');
if (!width) {
coerce('scalegroup', traceOut.name);
coerce('scalemode');
}
var span = coerce('span');
var spanmodeDflt;
if (Array.isArray(span)) spanmodeDflt = 'manual';
coerce('spanmode', spanmodeDflt);
var lineColor = coerce('line.color', (traceIn.marker || {}).color || defaultColor);
var lineWidth = coerce('line.width');
var fillColor = coerce('fillcolor', Color.addOpacity(traceOut.line.color, 0.5));
boxDefaults.handlePointsDefaults(traceIn, traceOut, coerce, {
prefix: ''
});
var boxWidth = coerce2('box.width');
var boxFillColor = coerce2('box.fillcolor', fillColor);
var boxLineColor = coerce2('box.line.color', lineColor);
var boxLineWidth = coerce2('box.line.width', lineWidth);
var boxVisible = coerce('box.visible', Boolean(boxWidth || boxFillColor || boxLineColor || boxLineWidth));
if (!boxVisible) traceOut.box = {
visible: false
};
var meanLineColor = coerce2('meanline.color', lineColor);
var meanLineWidth = coerce2('meanline.width', lineWidth);
var meanLineVisible = coerce('meanline.visible', Boolean(meanLineColor || meanLineWidth));
if (!meanLineVisible) traceOut.meanline = {
visible: false
};
coerce('quartilemethod');
coerce('zorder');
};
/***/ }),
/***/ 55596:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
// Maybe add kernels more down the road,
// but note that the default `spanmode: 'soft'` bounds might have
// to become kernel-dependent
var kernels = {
gaussian: function (v) {
return 1 / Math.sqrt(2 * Math.PI) * Math.exp(-0.5 * v * v);
}
};
exports.makeKDE = function (calcItem, trace, vals) {
var len = vals.length;
var kernel = kernels.gaussian;
var bandwidth = calcItem.bandwidth;
var factor = 1 / (len * bandwidth);
// don't use Lib.aggNums to skip isNumeric checks
return function (x) {
var sum = 0;
for (var i = 0; i < len; i++) {
sum += kernel((x - vals[i]) / bandwidth);
}
return factor * sum;
};
};
exports.getPositionOnKdePath = function (calcItem, trace, valuePx) {
var posLetter, valLetter;
if (trace.orientation === 'h') {
posLetter = 'y';
valLetter = 'x';
} else {
posLetter = 'x';
valLetter = 'y';
}
var pointOnPath = Lib.findPointOnPath(calcItem.path, valuePx, valLetter, {
pathLength: calcItem.pathLength
});
var posCenterPx = calcItem.posCenterPx;
var posOnPath0 = pointOnPath[posLetter];
var posOnPath1 = trace.side === 'both' ? 2 * posCenterPx - posOnPath0 : posCenterPx;
return [posOnPath0, posOnPath1];
};
exports.getKdeValue = function (calcItem, trace, valueDist) {
var vals = calcItem.pts.map(exports.extractVal);
var kde = exports.makeKDE(calcItem, trace, vals);
return kde(valueDist) / calcItem.posDensityScale;
};
exports.extractVal = function (o) {
return o.v;
};
/***/ }),
/***/ 5468:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Color = __webpack_require__(9240);
var Lib = __webpack_require__(10923);
var Axes = __webpack_require__(81536);
var boxHoverPoints = __webpack_require__(69616);
var helpers = __webpack_require__(55596);
module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) {
if (!opts) opts = {};
var hoverLayer = opts.hoverLayer;
var cd = pointData.cd;
var trace = cd[0].trace;
var hoveron = trace.hoveron;
var hasHoveronViolins = hoveron.indexOf('violins') !== -1;
var hasHoveronKDE = hoveron.indexOf('kde') !== -1;
var closeData = [];
var closePtData;
var violinLineAttrs;
if (hasHoveronViolins || hasHoveronKDE) {
var closeBoxData = boxHoverPoints.hoverOnBoxes(pointData, xval, yval, hovermode);
if (hasHoveronKDE && closeBoxData.length > 0) {
var xa = pointData.xa;
var ya = pointData.ya;
var pLetter, vLetter, pAxis, vAxis, vVal;
if (trace.orientation === 'h') {
vVal = xval;
pLetter = 'y';
pAxis = ya;
vLetter = 'x';
vAxis = xa;
} else {
vVal = yval;
pLetter = 'x';
pAxis = xa;
vLetter = 'y';
vAxis = ya;
}
var di = cd[pointData.index];
if (vVal >= di.span[0] && vVal <= di.span[1]) {
var kdePointData = Lib.extendFlat({}, pointData);
var vValPx = vAxis.c2p(vVal, true);
var kdeVal = helpers.getKdeValue(di, trace, vVal);
var pOnPath = helpers.getPositionOnKdePath(di, trace, vValPx);
var paOffset = pAxis._offset;
var paLength = pAxis._length;
kdePointData[pLetter + '0'] = pOnPath[0];
kdePointData[pLetter + '1'] = pOnPath[1];
kdePointData[vLetter + '0'] = kdePointData[vLetter + '1'] = vValPx;
kdePointData[vLetter + 'Label'] = vLetter + ': ' + Axes.hoverLabelText(vAxis, vVal, trace[vLetter + 'hoverformat']) + ', ' + cd[0].t.labels.kde + ' ' + kdeVal.toFixed(3);
// move the spike to the KDE point
var medId = 0;
for (var k = 0; k < closeBoxData.length; k++) {
if (closeBoxData[k].attr === 'med') {
medId = k;
break;
}
}
kdePointData.spikeDistance = closeBoxData[medId].spikeDistance;
var spikePosAttr = pLetter + 'Spike';
kdePointData[spikePosAttr] = closeBoxData[medId][spikePosAttr];
closeBoxData[medId].spikeDistance = undefined;
closeBoxData[medId][spikePosAttr] = undefined;
// no hovertemplate support yet
kdePointData.hovertemplate = false;
closeData.push(kdePointData);
violinLineAttrs = {};
violinLineAttrs[pLetter + '1'] = Lib.constrain(paOffset + pOnPath[0], paOffset, paOffset + paLength);
violinLineAttrs[pLetter + '2'] = Lib.constrain(paOffset + pOnPath[1], paOffset, paOffset + paLength);
violinLineAttrs[vLetter + '1'] = violinLineAttrs[vLetter + '2'] = vAxis._offset + vValPx;
}
}
if (hasHoveronViolins) {
closeData = closeData.concat(closeBoxData);
}
}
if (hoveron.indexOf('points') !== -1) {
closePtData = boxHoverPoints.hoverOnPoints(pointData, xval, yval);
}
// update violin line (if any)
var violinLine = hoverLayer.selectAll('.violinline-' + trace.uid).data(violinLineAttrs ? [0] : []);
violinLine.enter().append('line').classed('violinline-' + trace.uid, true).attr('stroke-width', 1.5);
violinLine.exit().remove();
violinLine.attr(violinLineAttrs).call(Color.stroke, pointData.color);
// same combine logic as box hoverPoints
if (hovermode === 'closest') {
if (closePtData) return [closePtData];
return closeData;
}
if (closePtData) {
closeData.push(closePtData);
return closeData;
}
return closeData;
};
/***/ }),
/***/ 7032:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(62808),
layoutAttributes: __webpack_require__(45984),
supplyDefaults: __webpack_require__(85792),
crossTraceDefaults: (__webpack_require__(18024).crossTraceDefaults),
supplyLayoutDefaults: __webpack_require__(52692),
calc: __webpack_require__(87100),
crossTraceCalc: __webpack_require__(57848),
plot: __webpack_require__(72240),
style: __webpack_require__(55160),
styleOnSelect: (__webpack_require__(53651).styleOnSelect),
hoverPoints: __webpack_require__(5468),
selectPoints: __webpack_require__(5496),
moduleType: 'trace',
name: 'violin',
basePlotModule: __webpack_require__(34316),
categories: ['cartesian', 'svg', 'symbols', 'oriented', 'box-violin', 'showLegend', 'violinLayout', 'zoomScale'],
meta: {
description: ['In vertical (horizontal) violin plots,', 'statistics are computed using `y` (`x`) values.', 'By supplying an `x` (`y`) array, one violin per distinct x (y) value', 'is drawn', 'If no `x` (`y`) {array} is provided, a single violin is drawn.', 'That violin position is then positioned with', 'with `name` or with `x0` (`y0`) if provided.'].join(' ')
}
};
/***/ }),
/***/ 45984:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var boxLayoutAttrs = __webpack_require__(62352);
var extendFlat = (__webpack_require__(10923).extendFlat);
module.exports = {
violinmode: extendFlat({}, boxLayoutAttrs.boxmode, {
description: ['Determines how violins at the same location coordinate', 'are displayed on the graph.', 'If *group*, the violins are plotted next to one another', 'centered around the shared location.', 'If *overlay*, the violins are plotted over one another,', 'you might need to set *opacity* to see them multiple violins.', 'Has no effect on traces that have *width* set.'].join(' ')
}),
violingap: extendFlat({}, boxLayoutAttrs.boxgap, {
description: ['Sets the gap (in plot fraction) between violins of', 'adjacent location coordinates.', 'Has no effect on traces that have *width* set.'].join(' ')
}),
violingroupgap: extendFlat({}, boxLayoutAttrs.boxgroupgap, {
description: ['Sets the gap (in plot fraction) between violins of', 'the same location coordinate.', 'Has no effect on traces that have *width* set.'].join(' ')
})
};
/***/ }),
/***/ 52692:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(45984);
var boxLayoutDefaults = __webpack_require__(15428);
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
boxLayoutDefaults._supply(layoutIn, layoutOut, fullData, coerce, 'violin');
};
/***/ }),
/***/ 72240:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var boxPlot = __webpack_require__(46448);
var linePoints = __webpack_require__(22216);
var helpers = __webpack_require__(55596);
module.exports = function plot(gd, plotinfo, cdViolins, violinLayer) {
var isStatic = gd._context.staticPlot;
var fullLayout = gd._fullLayout;
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
function makePath(pts, trace) {
var segments = linePoints(pts, {
xaxis: xa,
yaxis: ya,
trace: trace,
connectGaps: true,
baseTolerance: 0.75,
shape: 'spline',
simplify: true,
linearized: true
});
return Drawing.smoothopen(segments[0], 1);
}
Lib.makeTraceGroups(violinLayer, cdViolins, 'trace violins').each(function (cd) {
var plotGroup = d3.select(this);
var cd0 = cd[0];
var t = cd0.t;
var trace = cd0.trace;
if (trace.visible !== true || t.empty) {
plotGroup.remove();
return;
}
var bPos = t.bPos;
var bdPos = t.bdPos;
var valAxis = plotinfo[t.valLetter + 'axis'];
var posAxis = plotinfo[t.posLetter + 'axis'];
var hasBothSides = trace.side === 'both';
var hasPositiveSide = hasBothSides || trace.side === 'positive';
var hasNegativeSide = hasBothSides || trace.side === 'negative';
var violins = plotGroup.selectAll('path.violin').data(Lib.identity);
violins.enter().append('path').style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke').attr('class', 'violin');
violins.exit().remove();
violins.each(function (d) {
var pathSel = d3.select(this);
var density = d.density;
var len = density.length;
var posCenter = posAxis.c2l(d.pos + bPos, true);
var posCenterPx = posAxis.l2p(posCenter);
var scale;
if (trace.width) {
scale = t.maxKDE / bdPos;
} else {
var groupStats = fullLayout._violinScaleGroupStats[trace.scalegroup];
scale = trace.scalemode === 'count' ? groupStats.maxKDE / bdPos * (groupStats.maxCount / d.pts.length) : groupStats.maxKDE / bdPos;
}
var pathPos, pathNeg, path;
var i, k, pts, pt;
if (hasPositiveSide) {
pts = new Array(len);
for (i = 0; i < len; i++) {
pt = pts[i] = {};
pt[t.posLetter] = posCenter + density[i].v / scale;
pt[t.valLetter] = valAxis.c2l(density[i].t, true);
}
pathPos = makePath(pts, trace);
}
if (hasNegativeSide) {
pts = new Array(len);
for (k = 0, i = len - 1; k < len; k++, i--) {
pt = pts[k] = {};
pt[t.posLetter] = posCenter - density[i].v / scale;
pt[t.valLetter] = valAxis.c2l(density[i].t, true);
}
pathNeg = makePath(pts, trace);
}
if (hasBothSides) {
path = pathPos + 'L' + pathNeg.substr(1) + 'Z';
} else {
var startPt = [posCenterPx, valAxis.c2p(density[0].t)];
var endPt = [posCenterPx, valAxis.c2p(density[len - 1].t)];
if (trace.orientation === 'h') {
startPt.reverse();
endPt.reverse();
}
if (hasPositiveSide) {
path = 'M' + startPt + 'L' + pathPos.substr(1) + 'L' + endPt;
} else {
path = 'M' + endPt + 'L' + pathNeg.substr(1) + 'L' + startPt;
}
}
pathSel.attr('d', path);
// save a few things used in getPositionOnKdePath, getKdeValue
// on hover and for meanline draw block below
d.posCenterPx = posCenterPx;
d.posDensityScale = scale * bdPos;
d.path = pathSel.node();
d.pathLength = d.path.getTotalLength() / (hasBothSides ? 2 : 1);
});
var boxAttrs = trace.box;
var boxWidth = boxAttrs.width;
var boxLineWidth = (boxAttrs.line || {}).width;
var bdPosScaled;
var bPosPxOffset;
if (hasBothSides) {
bdPosScaled = bdPos * boxWidth;
bPosPxOffset = 0;
} else if (hasPositiveSide) {
bdPosScaled = [0, bdPos * boxWidth / 2];
bPosPxOffset = boxLineWidth * {
x: 1,
y: -1
}[t.posLetter];
} else {
bdPosScaled = [bdPos * boxWidth / 2, 0];
bPosPxOffset = boxLineWidth * {
x: -1,
y: 1
}[t.posLetter];
}
// inner box
boxPlot.plotBoxAndWhiskers(plotGroup, {
pos: posAxis,
val: valAxis
}, trace, {
bPos: bPos,
bdPos: bdPosScaled,
bPosPxOffset: bPosPxOffset
});
// meanline insider box
boxPlot.plotBoxMean(plotGroup, {
pos: posAxis,
val: valAxis
}, trace, {
bPos: bPos,
bdPos: bdPosScaled,
bPosPxOffset: bPosPxOffset
});
var fn;
if (!trace.box.visible && trace.meanline.visible) {
fn = Lib.identity;
}
// N.B. use different class name than boxPlot.plotBoxMean,
// to avoid selectAll conflict
var meanPaths = plotGroup.selectAll('path.meanline').data(fn || []);
meanPaths.enter().append('path').attr('class', 'meanline').style('fill', 'none').style('vector-effect', isStatic ? 'none' : 'non-scaling-stroke');
meanPaths.exit().remove();
meanPaths.each(function (d) {
var v = valAxis.c2p(d.mean, true);
var p = helpers.getPositionOnKdePath(d, trace, v);
d3.select(this).attr('d', trace.orientation === 'h' ? 'M' + v + ',' + p[0] + 'V' + p[1] : 'M' + p[0] + ',' + v + 'H' + p[1]);
});
boxPlot.plotPoints(plotGroup, {
x: xa,
y: ya
}, trace, t);
});
};
/***/ }),
/***/ 55160:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Color = __webpack_require__(9240);
var stylePoints = (__webpack_require__(53651).stylePoints);
module.exports = function style(gd) {
var s = d3.select(gd).selectAll('g.trace.violins');
s.style('opacity', function (d) {
return d[0].trace.opacity;
});
s.each(function (d) {
var trace = d[0].trace;
var sel = d3.select(this);
var box = trace.box || {};
var boxLine = box.line || {};
var meanline = trace.meanline || {};
var meanLineWidth = meanline.width;
sel.selectAll('path.violin').style('stroke-width', trace.line.width + 'px').call(Color.stroke, trace.line.color).call(Color.fill, trace.fillcolor);
sel.selectAll('path.box').style('stroke-width', boxLine.width + 'px').call(Color.stroke, boxLine.color).call(Color.fill, box.fillcolor);
var meanLineStyle = {
'stroke-width': meanLineWidth + 'px',
'stroke-dasharray': 2 * meanLineWidth + 'px,' + meanLineWidth + 'px'
};
sel.selectAll('path.mean').style(meanLineStyle).call(Color.stroke, meanline.color);
sel.selectAll('path.meanline').style(meanLineStyle).call(Color.stroke, meanline.color);
stylePoints(sel, trace, gd);
});
};
/***/ }),
/***/ 74636:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var colorScaleAttrs = __webpack_require__(99732);
var isosurfaceAttrs = __webpack_require__(32560);
var surfaceAttrs = __webpack_require__(32004);
var baseAttrs = __webpack_require__(6040);
var extendFlat = (__webpack_require__(55016).extendFlat);
var overrideAll = (__webpack_require__(31176).overrideAll);
var attrs = module.exports = overrideAll(extendFlat({
x: isosurfaceAttrs.x,
y: isosurfaceAttrs.y,
z: isosurfaceAttrs.z,
value: isosurfaceAttrs.value,
isomin: isosurfaceAttrs.isomin,
isomax: isosurfaceAttrs.isomax,
surface: isosurfaceAttrs.surface,
spaceframe: {
show: {
valType: 'boolean',
dflt: false,
description: ['Displays/hides tetrahedron shapes between minimum and', 'maximum iso-values. Often useful when either caps or', 'surfaces are disabled or filled with values less than 1.'].join(' ')
},
fill: {
valType: 'number',
min: 0,
max: 1,
dflt: 1,
description: ['Sets the fill ratio of the `spaceframe` elements. The default fill value', 'is 1 meaning that they are entirely shaded. Applying a `fill` ratio less', 'than one would allow the creation of openings parallel to the edges.'].join(' ')
}
},
slices: isosurfaceAttrs.slices,
caps: isosurfaceAttrs.caps,
text: isosurfaceAttrs.text,
hovertext: isosurfaceAttrs.hovertext,
xhoverformat: isosurfaceAttrs.xhoverformat,
yhoverformat: isosurfaceAttrs.yhoverformat,
zhoverformat: isosurfaceAttrs.zhoverformat,
valuehoverformat: isosurfaceAttrs.valuehoverformat,
hovertemplate: isosurfaceAttrs.hovertemplate
}, colorScaleAttrs('', {
colorAttr: '`value`',
showScaleDflt: true,
editTypeOverride: 'calc'
}), {
colorbar: isosurfaceAttrs.colorbar,
opacity: isosurfaceAttrs.opacity,
opacityscale: surfaceAttrs.opacityscale,
lightposition: isosurfaceAttrs.lightposition,
lighting: isosurfaceAttrs.lighting,
flatshading: isosurfaceAttrs.flatshading,
contour: isosurfaceAttrs.contour,
hoverinfo: extendFlat({}, baseAttrs.hoverinfo),
showlegend: extendFlat({}, baseAttrs.showlegend, {
dflt: false
})
}), 'calc', 'nested');
attrs.x.editType = attrs.y.editType = attrs.z.editType = attrs.value.editType = 'calc+clearAxisTypes';
attrs.transforms = undefined;
/***/ }),
/***/ 77536:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var createMesh = (__webpack_require__(14656).gl_mesh3d);
var parseColorScale = (__webpack_require__(13396).parseColorScale);
var isArrayOrTypedArray = (__webpack_require__(10923).isArrayOrTypedArray);
var str2RgbaArray = __webpack_require__(29864);
var extractOpts = (__webpack_require__(26733).extractOpts);
var zip3 = __webpack_require__(90644);
var findNearestOnAxis = (__webpack_require__(80296).findNearestOnAxis);
var generateIsoMeshes = (__webpack_require__(80296).generateIsoMeshes);
function VolumeTrace(scene, mesh, uid) {
this.scene = scene;
this.uid = uid;
this.mesh = mesh;
this.name = '';
this.data = null;
this.showContour = false;
}
var proto = VolumeTrace.prototype;
proto.handlePick = function (selection) {
if (selection.object === this.mesh) {
var rawId = selection.data.index;
var x = this.data._meshX[rawId];
var y = this.data._meshY[rawId];
var z = this.data._meshZ[rawId];
var height = this.data._Ys.length;
var depth = this.data._Zs.length;
var i = findNearestOnAxis(x, this.data._Xs).id;
var j = findNearestOnAxis(y, this.data._Ys).id;
var k = findNearestOnAxis(z, this.data._Zs).id;
var selectIndex = selection.index = k + depth * j + depth * height * i;
selection.traceCoordinate = [this.data._meshX[selectIndex], this.data._meshY[selectIndex], this.data._meshZ[selectIndex], this.data._value[selectIndex]];
var text = this.data.hovertext || this.data.text;
if (isArrayOrTypedArray(text) && text[selectIndex] !== undefined) {
selection.textLabel = text[selectIndex];
} else if (text) {
selection.textLabel = text;
}
return true;
}
};
proto.update = function (data) {
var scene = this.scene;
var layout = scene.fullSceneLayout;
this.data = generateIsoMeshes(data);
// Unpack position data
function toDataCoords(axis, coord, scale, calendar) {
return coord.map(function (x) {
return axis.d2l(x, 0, calendar) * scale;
});
}
var positions = zip3(toDataCoords(layout.xaxis, data._meshX, scene.dataScale[0], data.xcalendar), toDataCoords(layout.yaxis, data._meshY, scene.dataScale[1], data.ycalendar), toDataCoords(layout.zaxis, data._meshZ, scene.dataScale[2], data.zcalendar));
var cells = zip3(data._meshI, data._meshJ, data._meshK);
var config = {
positions: positions,
cells: cells,
lightPosition: [data.lightposition.x, data.lightposition.y, data.lightposition.z],
ambient: data.lighting.ambient,
diffuse: data.lighting.diffuse,
specular: data.lighting.specular,
roughness: data.lighting.roughness,
fresnel: data.lighting.fresnel,
vertexNormalsEpsilon: data.lighting.vertexnormalsepsilon,
faceNormalsEpsilon: data.lighting.facenormalsepsilon,
opacity: data.opacity,
opacityscale: data.opacityscale,
contourEnable: data.contour.show,
contourColor: str2RgbaArray(data.contour.color).slice(0, 3),
contourWidth: data.contour.width,
useFacetNormals: data.flatshading
};
var cOpts = extractOpts(data);
config.vertexIntensity = data._meshIntensity;
config.vertexIntensityBounds = [cOpts.min, cOpts.max];
config.colormap = parseColorScale(data);
// Update mesh
this.mesh.update(config);
};
proto.dispose = function () {
this.scene.glplot.remove(this.mesh);
this.mesh.dispose();
};
function createVolumeTrace(scene, data) {
var gl = scene.glplot.gl;
var mesh = createMesh({
gl: gl
});
var result = new VolumeTrace(scene, mesh, data.uid);
mesh._trace = result;
result.update(data);
scene.glplot.add(mesh);
return result;
}
module.exports = createVolumeTrace;
/***/ }),
/***/ 3068:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var attributes = __webpack_require__(74636);
var supplyIsoDefaults = (__webpack_require__(30592).supplyIsoDefaults);
var opacityscaleDefaults = (__webpack_require__(19127).opacityscaleDefaults);
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
supplyIsoDefaults(traceIn, traceOut, defaultColor, layout, coerce);
opacityscaleDefaults(traceIn, traceOut, layout, coerce);
};
/***/ }),
/***/ 99076:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(74636),
supplyDefaults: __webpack_require__(3068),
calc: __webpack_require__(70260),
colorbar: {
min: 'cmin',
max: 'cmax'
},
plot: __webpack_require__(77536),
moduleType: 'trace',
name: 'volume',
basePlotModule: __webpack_require__(26544),
categories: ['gl3d', 'showLegend'],
meta: {
description: ['Draws volume trace between iso-min and iso-max values with coordinates given by', 'four 1-dimensional arrays containing the `value`, `x`, `y` and `z` of every vertex', 'of a uniform or non-uniform 3-D grid. Horizontal or vertical slices, caps as well as', 'spaceframe between iso-min and iso-max values could also be drawn using this trace.'].join(' ')
}
};
/***/ }),
/***/ 98376:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var barAttrs = __webpack_require__(39788);
var lineAttrs = (__webpack_require__(49992).line);
var baseAttrs = __webpack_require__(6040);
var axisHoverFormat = (__webpack_require__(67724).axisHoverFormat);
var hovertemplateAttrs = (__webpack_require__(61052)/* .hovertemplateAttrs */ .Ks);
var texttemplateAttrs = (__webpack_require__(61052)/* .texttemplateAttrs */ .Gw);
var constants = __webpack_require__(92632);
var extendFlat = (__webpack_require__(55016).extendFlat);
var Color = __webpack_require__(9240);
function directionAttrs(dirTxt) {
return {
marker: {
color: extendFlat({}, barAttrs.marker.color, {
arrayOk: false,
editType: 'style',
description: 'Sets the marker color of all ' + dirTxt + ' values.'
}),
line: {
color: extendFlat({}, barAttrs.marker.line.color, {
arrayOk: false,
editType: 'style',
description: 'Sets the line color of all ' + dirTxt + ' values.'
}),
width: extendFlat({}, barAttrs.marker.line.width, {
arrayOk: false,
editType: 'style',
description: 'Sets the line width of all ' + dirTxt + ' values.'
}),
editType: 'style'
},
editType: 'style'
},
editType: 'style'
};
}
module.exports = {
measure: {
valType: 'data_array',
dflt: [],
editType: 'calc',
description: ['An array containing types of values.', 'By default the values are considered as \'relative\'.', 'However; it is possible to use \'total\' to compute the sums.', 'Also \'absolute\' could be applied to reset the computed total', 'or to declare an initial value where needed.'].join(' ')
},
base: {
valType: 'number',
dflt: null,
arrayOk: false,
editType: 'calc',
description: ['Sets where the bar base is drawn (in position axis units).'].join(' ')
},
x: barAttrs.x,
x0: barAttrs.x0,
dx: barAttrs.dx,
y: barAttrs.y,
y0: barAttrs.y0,
dy: barAttrs.dy,
xperiod: barAttrs.xperiod,
yperiod: barAttrs.yperiod,
xperiod0: barAttrs.xperiod0,
yperiod0: barAttrs.yperiod0,
xperiodalignment: barAttrs.xperiodalignment,
yperiodalignment: barAttrs.yperiodalignment,
xhoverformat: axisHoverFormat('x'),
yhoverformat: axisHoverFormat('y'),
hovertext: barAttrs.hovertext,
hovertemplate: hovertemplateAttrs({}, {
keys: constants.eventDataKeys
}),
hoverinfo: extendFlat({}, baseAttrs.hoverinfo, {
flags: ['name', 'x', 'y', 'text', 'initial', 'delta', 'final']
}),
textinfo: {
valType: 'flaglist',
flags: ['label', 'text', 'initial', 'delta', 'final'],
extras: ['none'],
editType: 'plot',
arrayOk: false,
description: ['Determines which trace information appear on the graph.', 'In the case of having multiple waterfalls, totals', 'are computed separately (per trace).'].join(' ')
},
// TODO: incorporate `label` and `value` in the eventData
texttemplate: texttemplateAttrs({
editType: 'plot'
}, {
keys: constants.eventDataKeys.concat(['label'])
}),
text: barAttrs.text,
textposition: barAttrs.textposition,
insidetextanchor: barAttrs.insidetextanchor,
textangle: barAttrs.textangle,
textfont: barAttrs.textfont,
insidetextfont: barAttrs.insidetextfont,
outsidetextfont: barAttrs.outsidetextfont,
constraintext: barAttrs.constraintext,
cliponaxis: barAttrs.cliponaxis,
orientation: barAttrs.orientation,
offset: barAttrs.offset,
width: barAttrs.width,
increasing: directionAttrs('increasing'),
decreasing: directionAttrs('decreasing'),
totals: directionAttrs('intermediate sums and total'),
connector: {
line: {
color: extendFlat({}, lineAttrs.color, {
dflt: Color.defaultLine
}),
width: extendFlat({}, lineAttrs.width, {
editType: 'plot' // i.e. to adjust bars is mode: 'between'. See https://github.com/plotly/plotly.js/issues/3787
}),
dash: lineAttrs.dash,
editType: 'plot'
},
mode: {
valType: 'enumerated',
values: ['spanning', 'between'],
dflt: 'between',
editType: 'plot',
description: ['Sets the shape of connector lines.'].join(' ')
},
visible: {
valType: 'boolean',
dflt: true,
editType: 'plot',
description: ['Determines if connector lines are drawn. '].join(' ')
},
editType: 'plot'
},
offsetgroup: barAttrs.offsetgroup,
alignmentgroup: barAttrs.alignmentgroup,
zorder: barAttrs.zorder
};
/***/ }),
/***/ 14736:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var alignPeriod = __webpack_require__(82260);
var mergeArray = (__webpack_require__(10923).mergeArray);
var calcSelection = __webpack_require__(62496);
var BADNUM = (__webpack_require__(41752).BADNUM);
function isAbsolute(a) {
return a === 'a' || a === 'absolute';
}
function isTotal(a) {
return a === 't' || a === 'total';
}
module.exports = function calc(gd, trace) {
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var size, pos, origPos, pObj, hasPeriod, pLetter;
if (trace.orientation === 'h') {
size = xa.makeCalcdata(trace, 'x');
origPos = ya.makeCalcdata(trace, 'y');
pObj = alignPeriod(trace, ya, 'y', origPos);
hasPeriod = !!trace.yperiodalignment;
pLetter = 'y';
} else {
size = ya.makeCalcdata(trace, 'y');
origPos = xa.makeCalcdata(trace, 'x');
pObj = alignPeriod(trace, xa, 'x', origPos);
hasPeriod = !!trace.xperiodalignment;
pLetter = 'x';
}
pos = pObj.vals;
// create the "calculated data" to plot
var serieslen = Math.min(pos.length, size.length);
var cd = new Array(serieslen);
// set position and size (as well as for waterfall total size)
var previousSum = 0;
var newSize;
// trace-wide flags
var hasTotals = false;
for (var i = 0; i < serieslen; i++) {
var amount = size[i] || 0;
var connectToNext = false;
if (size[i] !== BADNUM || isTotal(trace.measure[i]) || isAbsolute(trace.measure[i])) {
if (i + 1 < serieslen && (size[i + 1] !== BADNUM || isTotal(trace.measure[i + 1]) || isAbsolute(trace.measure[i + 1]))) {
connectToNext = true;
}
}
var cdi = cd[i] = {
i: i,
p: pos[i],
s: amount,
rawS: amount,
cNext: connectToNext
};
if (isAbsolute(trace.measure[i])) {
previousSum = cdi.s;
cdi.isSum = true;
cdi.dir = 'totals';
cdi.s = previousSum;
} else if (isTotal(trace.measure[i])) {
cdi.isSum = true;
cdi.dir = 'totals';
cdi.s = previousSum;
} else {
// default: relative
cdi.isSum = false;
cdi.dir = cdi.rawS < 0 ? 'decreasing' : 'increasing';
newSize = cdi.s;
cdi.s = previousSum + newSize;
previousSum += newSize;
}
if (cdi.dir === 'totals') {
hasTotals = true;
}
if (hasPeriod) {
cd[i].orig_p = origPos[i]; // used by hover
cd[i][pLetter + 'End'] = pObj.ends[i];
cd[i][pLetter + 'Start'] = pObj.starts[i];
}
if (trace.ids) {
cdi.id = String(trace.ids[i]);
}
cdi.v = (trace.base || 0) + previousSum;
}
if (cd.length) cd[0].hasTotals = hasTotals;
mergeArray(trace.text, cd, 'tx');
mergeArray(trace.hovertext, cd, 'htx');
calcSelection(cd, trace);
return cd;
};
/***/ }),
/***/ 92632:
/***/ (function(module) {
"use strict";
module.exports = {
eventDataKeys: ['initial', 'delta', 'final']
};
/***/ }),
/***/ 71880:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var setGroupPositions = (__webpack_require__(2616).setGroupPositions);
module.exports = function crossTraceCalc(gd, plotinfo) {
var fullLayout = gd._fullLayout;
var fullData = gd._fullData;
var calcdata = gd.calcdata;
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
var waterfalls = [];
var waterfallsVert = [];
var waterfallsHorz = [];
var cd, i;
for (i = 0; i < fullData.length; i++) {
var fullTrace = fullData[i];
if (fullTrace.visible === true && fullTrace.xaxis === xa._id && fullTrace.yaxis === ya._id && fullTrace.type === 'waterfall') {
cd = calcdata[i];
if (fullTrace.orientation === 'h') {
waterfallsHorz.push(cd);
} else {
waterfallsVert.push(cd);
}
waterfalls.push(cd);
}
}
var opts = {
mode: fullLayout.waterfallmode,
norm: fullLayout.waterfallnorm,
gap: fullLayout.waterfallgap,
groupgap: fullLayout.waterfallgroupgap
};
setGroupPositions(gd, xa, ya, waterfallsVert, opts);
setGroupPositions(gd, ya, xa, waterfallsHorz, opts);
for (i = 0; i < waterfalls.length; i++) {
cd = waterfalls[i];
for (var j = 0; j < cd.length; j++) {
var di = cd[j];
if (di.isSum === false) {
di.s0 += j === 0 ? 0 : cd[j - 1].s;
}
if (j + 1 < cd.length) {
cd[j].nextP0 = cd[j + 1].p0;
cd[j].nextS0 = cd[j + 1].s0;
}
}
}
};
/***/ }),
/***/ 3856:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var handleGroupingDefaults = __webpack_require__(8584);
var handleText = (__webpack_require__(49520).handleText);
var handleXYDefaults = __webpack_require__(88376);
var handlePeriodDefaults = __webpack_require__(98632);
var attributes = __webpack_require__(98376);
var Color = __webpack_require__(9240);
var delta = __webpack_require__(91136);
var INCREASING_COLOR = delta.INCREASING.COLOR;
var DECREASING_COLOR = delta.DECREASING.COLOR;
var TOTALS_COLOR = '#4499FF';
function handleDirection(coerce, direction, defaultColor) {
coerce(direction + '.marker.color', defaultColor);
coerce(direction + '.marker.line.color', Color.defaultLine);
coerce(direction + '.marker.line.width');
}
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}
var len = handleXYDefaults(traceIn, traceOut, layout, coerce);
if (!len) {
traceOut.visible = false;
return;
}
handlePeriodDefaults(traceIn, traceOut, layout, coerce);
coerce('xhoverformat');
coerce('yhoverformat');
coerce('measure');
coerce('orientation', traceOut.x && !traceOut.y ? 'h' : 'v');
coerce('base');
coerce('offset');
coerce('width');
coerce('text');
coerce('hovertext');
coerce('hovertemplate');
var textposition = coerce('textposition');
handleText(traceIn, traceOut, layout, coerce, textposition, {
moduleHasSelected: false,
moduleHasUnselected: false,
moduleHasConstrain: true,
moduleHasCliponaxis: true,
moduleHasTextangle: true,
moduleHasInsideanchor: true
});
if (traceOut.textposition !== 'none') {
coerce('texttemplate');
if (!traceOut.texttemplate) coerce('textinfo');
}
handleDirection(coerce, 'increasing', INCREASING_COLOR);
handleDirection(coerce, 'decreasing', DECREASING_COLOR);
handleDirection(coerce, 'totals', TOTALS_COLOR);
var connectorVisible = coerce('connector.visible');
if (connectorVisible) {
coerce('connector.mode');
var connectorLineWidth = coerce('connector.line.width');
if (connectorLineWidth) {
coerce('connector.line.color');
coerce('connector.line.dash');
}
}
coerce('zorder');
}
function crossTraceDefaults(fullData, fullLayout) {
var traceIn, traceOut;
function coerce(attr) {
return Lib.coerce(traceOut._input, traceOut, attributes, attr);
}
if (fullLayout.waterfallmode === 'group') {
for (var i = 0; i < fullData.length; i++) {
traceOut = fullData[i];
traceIn = traceOut._input;
handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce);
}
}
}
module.exports = {
supplyDefaults: supplyDefaults,
crossTraceDefaults: crossTraceDefaults
};
/***/ }),
/***/ 52229:
/***/ (function(module) {
"use strict";
module.exports = function eventData(out, pt /* , trace, cd, pointNumber */) {
// standard cartesian event data
out.x = 'xVal' in pt ? pt.xVal : pt.x;
out.y = 'yVal' in pt ? pt.yVal : pt.y;
// for funnel
if ('initial' in pt) out.initial = pt.initial;
if ('delta' in pt) out.delta = pt.delta;
if ('final' in pt) out.final = pt.final;
if (pt.xa) out.xaxis = pt.xa;
if (pt.ya) out.yaxis = pt.ya;
return out;
};
/***/ }),
/***/ 79480:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var hoverLabelText = (__webpack_require__(81536).hoverLabelText);
var opacity = (__webpack_require__(9240).opacity);
var hoverOnBars = (__webpack_require__(30284).hoverOnBars);
var delta = __webpack_require__(91136);
var DIRSYMBOL = {
increasing: delta.INCREASING.SYMBOL,
decreasing: delta.DECREASING.SYMBOL
};
module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) {
var point = hoverOnBars(pointData, xval, yval, hovermode, opts);
if (!point) return;
var cd = point.cd;
var trace = cd[0].trace;
var isHorizontal = trace.orientation === 'h';
var vLetter = isHorizontal ? 'x' : 'y';
var vAxis = isHorizontal ? pointData.xa : pointData.ya;
function formatNumber(a) {
return hoverLabelText(vAxis, a, trace[vLetter + 'hoverformat']);
}
// the closest data point
var index = point.index;
var di = cd[index];
var size = di.isSum ? di.b + di.s : di.rawS;
point.initial = di.b + di.s - size;
point.delta = size;
point.final = point.initial + point.delta;
var v = formatNumber(Math.abs(point.delta));
point.deltaLabel = size < 0 ? '(' + v + ')' : v;
point.finalLabel = formatNumber(point.final);
point.initialLabel = formatNumber(point.initial);
var hoverinfo = di.hi || trace.hoverinfo;
var text = [];
if (hoverinfo && hoverinfo !== 'none' && hoverinfo !== 'skip') {
var isAll = hoverinfo === 'all';
var parts = hoverinfo.split('+');
var hasFlag = function (flag) {
return isAll || parts.indexOf(flag) !== -1;
};
if (!di.isSum) {
if (hasFlag('final') && (isHorizontal ? !hasFlag('x') : !hasFlag('y')) // don't display redundant info.
) {
text.push(point.finalLabel);
}
if (hasFlag('delta')) {
if (size < 0) {
text.push(point.deltaLabel + ' ' + DIRSYMBOL.decreasing);
} else {
text.push(point.deltaLabel + ' ' + DIRSYMBOL.increasing);
}
}
if (hasFlag('initial')) {
text.push('Initial: ' + point.initialLabel);
}
}
}
if (text.length) point.extraText = text.join('
');
point.color = getTraceColor(trace, di);
return [point];
};
function getTraceColor(trace, di) {
var cont = trace[di.dir].marker;
var mc = cont.color;
var mlc = cont.line.color;
var mlw = cont.line.width;
if (opacity(mc)) return mc;else if (opacity(mlc) && mlw) return mlc;
}
/***/ }),
/***/ 15519:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
module.exports = {
attributes: __webpack_require__(98376),
layoutAttributes: __webpack_require__(72840),
supplyDefaults: (__webpack_require__(3856).supplyDefaults),
crossTraceDefaults: (__webpack_require__(3856).crossTraceDefaults),
supplyLayoutDefaults: __webpack_require__(28768),
calc: __webpack_require__(14736),
crossTraceCalc: __webpack_require__(71880),
plot: __webpack_require__(47388),
style: (__webpack_require__(11019).style),
hoverPoints: __webpack_require__(79480),
eventData: __webpack_require__(52229),
selectPoints: __webpack_require__(10512),
moduleType: 'trace',
name: 'waterfall',
basePlotModule: __webpack_require__(34316),
categories: ['bar-like', 'cartesian', 'svg', 'oriented', 'showLegend', 'zoomScale'],
meta: {
description: ['Draws waterfall trace which is useful graph to displays the', 'contribution of various elements (either positive or negative)', 'in a bar chart. The data visualized by the span of the bars is', 'set in `y` if `orientation` is set to *v* (the default) and the', 'labels are set in `x`.', 'By setting `orientation` to *h*, the roles are interchanged.'].join(' ')
}
};
/***/ }),
/***/ 72840:
/***/ (function(module) {
"use strict";
module.exports = {
waterfallmode: {
valType: 'enumerated',
values: ['group', 'overlay'],
dflt: 'group',
editType: 'calc',
description: ['Determines how bars at the same location coordinate', 'are displayed on the graph.', 'With *group*, the bars are plotted next to one another', 'centered around the shared location.', 'With *overlay*, the bars are plotted over one another,', 'you might need to reduce *opacity* to see multiple bars.'].join(' ')
},
waterfallgap: {
valType: 'number',
min: 0,
max: 1,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between bars of', 'adjacent location coordinates.'].join(' ')
},
waterfallgroupgap: {
valType: 'number',
min: 0,
max: 1,
dflt: 0,
editType: 'calc',
description: ['Sets the gap (in plot fraction) between bars of', 'the same location coordinate.'].join(' ')
}
};
/***/ }),
/***/ 28768:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var layoutAttributes = __webpack_require__(72840);
module.exports = function (layoutIn, layoutOut, fullData) {
var hasTraceType = false;
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
for (var i = 0; i < fullData.length; i++) {
var trace = fullData[i];
if (trace.visible && trace.type === 'waterfall') {
hasTraceType = true;
break;
}
}
if (hasTraceType) {
coerce('waterfallmode');
coerce('waterfallgap', 0.2);
coerce('waterfallgroupgap');
}
};
/***/ }),
/***/ 47388:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Lib = __webpack_require__(10923);
var Drawing = __webpack_require__(49348);
var BADNUM = (__webpack_require__(41752).BADNUM);
var barPlot = __webpack_require__(39176);
var clearMinTextSize = (__webpack_require__(4096).clearMinTextSize);
module.exports = function plot(gd, plotinfo, cdModule, traceLayer) {
var fullLayout = gd._fullLayout;
clearMinTextSize('waterfall', fullLayout);
barPlot.plot(gd, plotinfo, cdModule, traceLayer, {
mode: fullLayout.waterfallmode,
norm: fullLayout.waterfallmode,
gap: fullLayout.waterfallgap,
groupgap: fullLayout.waterfallgroupgap
});
plotConnectors(gd, plotinfo, cdModule, traceLayer);
};
function plotConnectors(gd, plotinfo, cdModule, traceLayer) {
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
Lib.makeTraceGroups(traceLayer, cdModule, 'trace bars').each(function (cd) {
var plotGroup = d3.select(this);
var trace = cd[0].trace;
var group = Lib.ensureSingle(plotGroup, 'g', 'lines');
if (!trace.connector || !trace.connector.visible) {
group.remove();
return;
}
var isHorizontal = trace.orientation === 'h';
var mode = trace.connector.mode;
var connectors = group.selectAll('g.line').data(Lib.identity);
connectors.enter().append('g').classed('line', true);
connectors.exit().remove();
var len = connectors.size();
connectors.each(function (di, i) {
// don't draw lines between nulls
if (i !== len - 1 && !di.cNext) return;
var xy = getXY(di, xa, ya, isHorizontal);
var x = xy[0];
var y = xy[1];
var shape = '';
if (x[0] !== BADNUM && y[0] !== BADNUM && x[1] !== BADNUM && y[1] !== BADNUM) {
if (mode === 'spanning') {
if (!di.isSum && i > 0) {
if (isHorizontal) {
shape += 'M' + x[0] + ',' + y[1] + 'V' + y[0];
} else {
shape += 'M' + x[1] + ',' + y[0] + 'H' + x[0];
}
}
}
if (mode !== 'between') {
if (di.isSum || i < len - 1) {
if (isHorizontal) {
shape += 'M' + x[1] + ',' + y[0] + 'V' + y[1];
} else {
shape += 'M' + x[0] + ',' + y[1] + 'H' + x[1];
}
}
}
if (x[2] !== BADNUM && y[2] !== BADNUM) {
if (isHorizontal) {
shape += 'M' + x[1] + ',' + y[1] + 'V' + y[2];
} else {
shape += 'M' + x[1] + ',' + y[1] + 'H' + x[2];
}
}
}
if (shape === '') shape = 'M0,0Z';
Lib.ensureSingle(d3.select(this), 'path').attr('d', shape).call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
});
});
}
function getXY(di, xa, ya, isHorizontal) {
var s = [];
var p = [];
var sAxis = isHorizontal ? xa : ya;
var pAxis = isHorizontal ? ya : xa;
s[0] = sAxis.c2p(di.s0, true);
p[0] = pAxis.c2p(di.p0, true);
s[1] = sAxis.c2p(di.s1, true);
p[1] = pAxis.c2p(di.p1, true);
s[2] = sAxis.c2p(di.nextS0, true);
p[2] = pAxis.c2p(di.nextP0, true);
return isHorizontal ? [s, p] : [p, s];
}
/***/ }),
/***/ 11019:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
"use strict";
var d3 = __webpack_require__(6592);
var Drawing = __webpack_require__(49348);
var Color = __webpack_require__(9240);
var DESELECTDIM = (__webpack_require__(1172).DESELECTDIM);
var barStyle = __webpack_require__(21212);
var resizeText = (__webpack_require__(4096).resizeText);
var styleTextPoints = barStyle.styleTextPoints;
function style(gd, cd, sel) {
var s = sel ? sel : d3.select(gd).selectAll('g[class^="waterfalllayer"]').selectAll('g.trace');
resizeText(gd, s, 'waterfall');
s.style('opacity', function (d) {
return d[0].trace.opacity;
});
s.each(function (d) {
var gTrace = d3.select(this);
var trace = d[0].trace;
gTrace.selectAll('.point > path').each(function (di) {
if (!di.isBlank) {
var cont = trace[di.dir].marker;
d3.select(this).call(Color.fill, cont.color).call(Color.stroke, cont.line.color).call(Drawing.dashLine, cont.line.dash, cont.line.width).style('opacity', trace.selectedpoints && !di.selected ? DESELECTDIM : 1);
}
});
styleTextPoints(gTrace, trace, gd);
gTrace.selectAll('.lines').each(function () {
var cont = trace.connector.line;
Drawing.lineGroupStyle(d3.select(this).selectAll('path'), cont.width, cont.color, cont.dash);
});
});
}
module.exports = {
style: style
};
/***/ }),
/***/ 89124:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var Axes = __webpack_require__(81536);
var Lib = __webpack_require__(10923);
var PlotSchema = __webpack_require__(78380);
var pointsAccessorFunction = (__webpack_require__(29328)/* .pointsAccessorFunction */ .W);
var BADNUM = (__webpack_require__(41752).BADNUM);
exports.moduleType = 'transform';
exports.name = 'aggregate';
var attrs = exports.attributes = {
enabled: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether this aggregate transform is enabled or disabled.'].join(' ')
},
groups: {
// TODO: groupby should support string or array grouping this way too
// currently groupby only allows a grouping array
valType: 'string',
strict: true,
noBlank: true,
arrayOk: true,
dflt: 'x',
editType: 'calc',
description: ['Sets the grouping target to which the aggregation is applied.', 'Data points with matching group values will be coalesced into', 'one point, using the supplied aggregation functions to reduce data', 'in other data arrays.', 'If a string, `groups` is assumed to be a reference to a data array', 'in the parent trace object.', 'To aggregate by nested variables, use *.* to access them.', 'For example, set `groups` to *marker.color* to aggregate', 'about the marker color array.', 'If an array, `groups` is itself the data array by which we aggregate.'].join(' ')
},
aggregations: {
_isLinkedToArray: 'aggregation',
target: {
valType: 'string',
editType: 'calc',
description: ['A reference to the data array in the parent trace to aggregate.', 'To aggregate by nested variables, use *.* to access them.', 'For example, set `groups` to *marker.color* to aggregate', 'over the marker color array.', 'The referenced array must already exist, unless `func` is *count*,', 'and each array may only be referenced once.'].join(' ')
},
func: {
valType: 'enumerated',
values: ['count', 'sum', 'avg', 'median', 'mode', 'rms', 'stddev', 'min', 'max', 'first', 'last', 'change', 'range'],
dflt: 'first',
editType: 'calc',
description: ['Sets the aggregation function.', 'All values from the linked `target`, corresponding to the same value', 'in the `groups` array, are collected and reduced by this function.', '*count* is simply the number of values in the `groups` array, so does', 'not even require the linked array to exist. *first* (*last*) is just', 'the first (last) linked value.', 'Invalid values are ignored, so for example in *avg* they do not', 'contribute to either the numerator or the denominator.', 'Any data type (numeric, date, category) may be aggregated with any', 'function, even though in certain cases it is unlikely to make sense,', 'for example a sum of dates or average of categories.', '*median* will return the average of the two central values if there is', 'an even count. *mode* will return the first value to reach the maximum', 'count, in case of a tie.', '*change* will return the difference between the first and last linked values.', '*range* will return the difference between the min and max linked values.'].join(' ')
},
funcmode: {
valType: 'enumerated',
values: ['sample', 'population'],
dflt: 'sample',
editType: 'calc',
description: ['*stddev* supports two formula variants: *sample* (normalize by N-1)', 'and *population* (normalize by N).'].join(' ')
},
enabled: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether this aggregation function is enabled or disabled.'].join(' ')
},
editType: 'calc'
},
editType: 'calc'
};
var aggAttrs = attrs.aggregations;
/**
* Supply transform attributes defaults
*
* @param {object} transformIn
* object linked to trace.transforms[i] with 'func' set to exports.name
* @param {object} traceOut
* the _fullData trace this transform applies to
* @param {object} layout
* the plot's (not-so-full) layout
* @param {object} traceIn
* the input data trace this transform applies to
*
* @return {object} transformOut
* copy of transformIn that contains attribute defaults
*/
exports.supplyDefaults = function (transformIn, traceOut) {
var transformOut = {};
var i;
function coerce(attr, dflt) {
return Lib.coerce(transformIn, transformOut, attrs, attr, dflt);
}
var enabled = coerce('enabled');
if (!enabled) return transformOut;
/*
* Normally _arrayAttrs is calculated during doCalc, but that comes later.
* Anyway this can change due to *count* aggregations (see below) so it's not
* necessarily the same set.
*
* For performance we turn it into an object of truthy values
* we'll use 1 for arrays we haven't aggregated yet, 0 for finished arrays,
* as distinct from undefined which means this array isn't present in the input
* missing arrays can still be aggregate outputs for *count* aggregations.
*/
var arrayAttrArray = PlotSchema.findArrayAttributes(traceOut);
var arrayAttrs = {};
for (i = 0; i < arrayAttrArray.length; i++) arrayAttrs[arrayAttrArray[i]] = 1;
var groups = coerce('groups');
if (!Array.isArray(groups)) {
if (!arrayAttrs[groups]) {
transformOut.enabled = false;
return transformOut;
}
arrayAttrs[groups] = 0;
}
var aggregationsIn = transformIn.aggregations || [];
var aggregationsOut = transformOut.aggregations = new Array(aggregationsIn.length);
var aggregationOut;
function coercei(attr, dflt) {
return Lib.coerce(aggregationsIn[i], aggregationOut, aggAttrs, attr, dflt);
}
for (i = 0; i < aggregationsIn.length; i++) {
aggregationOut = {
_index: i
};
var target = coercei('target');
var func = coercei('func');
var enabledi = coercei('enabled');
// add this aggregation to the output only if it's the first instance
// of a valid target attribute - or an unused target attribute with "count"
if (enabledi && target && (arrayAttrs[target] || func === 'count' && arrayAttrs[target] === undefined)) {
if (func === 'stddev') coercei('funcmode');
arrayAttrs[target] = 0;
aggregationsOut[i] = aggregationOut;
} else aggregationsOut[i] = {
enabled: false,
_index: i
};
}
// any array attributes we haven't yet covered, fill them with the default aggregation
for (i = 0; i < arrayAttrArray.length; i++) {
if (arrayAttrs[arrayAttrArray[i]]) {
aggregationsOut.push({
target: arrayAttrArray[i],
func: aggAttrs.func.dflt,
enabled: true,
_index: -1
});
}
}
return transformOut;
};
exports.calcTransform = function (gd, trace, opts) {
if (!opts.enabled) return;
var groups = opts.groups;
var groupArray = Lib.getTargetArray(trace, {
target: groups
});
if (!groupArray) return;
var i, vi, groupIndex, newGrouping;
var groupIndices = {};
var indexToPoints = {};
var groupings = [];
var originalPointsAccessor = pointsAccessorFunction(trace.transforms, opts);
var len = groupArray.length;
if (trace._length) len = Math.min(len, trace._length);
for (i = 0; i < len; i++) {
vi = groupArray[i];
groupIndex = groupIndices[vi];
if (groupIndex === undefined) {
groupIndices[vi] = groupings.length;
newGrouping = [i];
groupings.push(newGrouping);
indexToPoints[groupIndices[vi]] = originalPointsAccessor(i);
} else {
groupings[groupIndex].push(i);
indexToPoints[groupIndices[vi]] = (indexToPoints[groupIndices[vi]] || []).concat(originalPointsAccessor(i));
}
}
opts._indexToPoints = indexToPoints;
var aggregations = opts.aggregations;
for (i = 0; i < aggregations.length; i++) {
aggregateOneArray(gd, trace, groupings, aggregations[i]);
}
if (typeof groups === 'string') {
aggregateOneArray(gd, trace, groupings, {
target: groups,
func: 'first',
enabled: true
});
}
trace._length = groupings.length;
};
function aggregateOneArray(gd, trace, groupings, aggregation) {
if (!aggregation.enabled) return;
var attr = aggregation.target;
var targetNP = Lib.nestedProperty(trace, attr);
var arrayIn = targetNP.get();
var conversions = Axes.getDataConversions(gd, trace, attr, arrayIn);
var func = getAggregateFunction(aggregation, conversions);
var arrayOut = new Array(groupings.length);
for (var i = 0; i < groupings.length; i++) {
arrayOut[i] = func(arrayIn, groupings[i]);
}
targetNP.set(arrayOut);
if (aggregation.func === 'count') {
// count does not depend on an input array, so it's likely not part of _arrayAttrs yet
// but after this transform it most definitely *is* an array attribute.
Lib.pushUnique(trace._arrayAttrs, attr);
}
}
function getAggregateFunction(opts, conversions) {
var func = opts.func;
var d2c = conversions.d2c;
var c2d = conversions.c2d;
switch (func) {
// count, first, and last don't depend on anything about the data
// point back to pure functions for performance
case 'count':
return count;
case 'first':
return first;
case 'last':
return last;
case 'sum':
// This will produce output in all cases even though it's nonsensical
// for date or category data.
return function (array, indices) {
var total = 0;
for (var i = 0; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) total += vi;
}
return c2d(total);
};
case 'avg':
// Generally meaningless for category data but it still does something.
return function (array, indices) {
var total = 0;
var cnt = 0;
for (var i = 0; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) {
total += vi;
cnt++;
}
}
return cnt ? c2d(total / cnt) : BADNUM;
};
case 'min':
return function (array, indices) {
var out = Infinity;
for (var i = 0; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) out = Math.min(out, vi);
}
return out === Infinity ? BADNUM : c2d(out);
};
case 'max':
return function (array, indices) {
var out = -Infinity;
for (var i = 0; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) out = Math.max(out, vi);
}
return out === -Infinity ? BADNUM : c2d(out);
};
case 'range':
return function (array, indices) {
var min = Infinity;
var max = -Infinity;
for (var i = 0; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) {
min = Math.min(min, vi);
max = Math.max(max, vi);
}
}
return max === -Infinity || min === Infinity ? BADNUM : c2d(max - min);
};
case 'change':
return function (array, indices) {
var first = d2c(array[indices[0]]);
var last = d2c(array[indices[indices.length - 1]]);
return first === BADNUM || last === BADNUM ? BADNUM : c2d(last - first);
};
case 'median':
return function (array, indices) {
var sortCalc = [];
for (var i = 0; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) sortCalc.push(vi);
}
if (!sortCalc.length) return BADNUM;
sortCalc.sort(Lib.sorterAsc);
var mid = (sortCalc.length - 1) / 2;
return c2d((sortCalc[Math.floor(mid)] + sortCalc[Math.ceil(mid)]) / 2);
};
case 'mode':
return function (array, indices) {
var counts = {};
var maxCnt = 0;
var out = BADNUM;
for (var i = 0; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) {
var counti = counts[vi] = (counts[vi] || 0) + 1;
if (counti > maxCnt) {
maxCnt = counti;
out = vi;
}
}
}
return maxCnt ? c2d(out) : BADNUM;
};
case 'rms':
return function (array, indices) {
var total = 0;
var cnt = 0;
for (var i = 0; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) {
total += vi * vi;
cnt++;
}
}
return cnt ? c2d(Math.sqrt(total / cnt)) : BADNUM;
};
case 'stddev':
return function (array, indices) {
// balance numerical stability with performance:
// so that we call d2c once per element but don't need to
// store them, reference all to the first element
var total = 0;
var total2 = 0;
var cnt = 1;
var v0 = BADNUM;
var i;
for (i = 0; i < indices.length && v0 === BADNUM; i++) {
v0 = d2c(array[indices[i]]);
}
if (v0 === BADNUM) return BADNUM;
for (; i < indices.length; i++) {
var vi = d2c(array[indices[i]]);
if (vi !== BADNUM) {
var dv = vi - v0;
total += dv;
total2 += dv * dv;
cnt++;
}
}
// This is population std dev, if we want sample std dev
// we would need (...) / (cnt - 1)
// Also note there's no c2d here - that means for dates the result
// is a number of milliseconds, and for categories it's a number
// of category differences, which is not generically meaningful but
// as in other cases we don't forbid it.
var norm = opts.funcmode === 'sample' ? cnt - 1 : cnt;
// this is debatable: should a count of 1 return sample stddev of
// 0 or undefined?
if (!norm) return 0;
return Math.sqrt((total2 - total * total / cnt) / norm);
};
}
}
function count(array, indices) {
return indices.length;
}
function first(array, indices) {
return array[indices[0]];
}
function last(array, indices) {
return array[indices[indices.length - 1]];
}
/***/ }),
/***/ 23484:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Registry = __webpack_require__(30364);
var Axes = __webpack_require__(81536);
var pointsAccessorFunction = (__webpack_require__(29328)/* .pointsAccessorFunction */ .W);
var filterOps = __webpack_require__(60180);
var COMPARISON_OPS = filterOps.COMPARISON_OPS;
var INTERVAL_OPS = filterOps.INTERVAL_OPS;
var SET_OPS = filterOps.SET_OPS;
exports.moduleType = 'transform';
exports.name = 'filter';
exports.attributes = {
enabled: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether this filter transform is enabled or disabled.'].join(' ')
},
target: {
valType: 'string',
strict: true,
noBlank: true,
arrayOk: true,
dflt: 'x',
editType: 'calc',
description: ['Sets the filter target by which the filter is applied.', 'If a string, `target` is assumed to be a reference to a data array', 'in the parent trace object.', 'To filter about nested variables, use *.* to access them.', 'For example, set `target` to *marker.color* to filter', 'about the marker color array.', 'If an array, `target` is then the data array by which the filter is applied.'].join(' ')
},
operation: {
valType: 'enumerated',
values: [].concat(COMPARISON_OPS).concat(INTERVAL_OPS).concat(SET_OPS),
dflt: '=',
editType: 'calc',
description: ['Sets the filter operation.', '*=* keeps items equal to `value`', '*!=* keeps items not equal to `value`', '*<* keeps items less than `value`', '*<=* keeps items less than or equal to `value`', '*>* keeps items greater than `value`', '*>=* keeps items greater than or equal to `value`', '*[]* keeps items inside `value[0]` to `value[1]` including both bounds', '*()* keeps items inside `value[0]` to `value[1]` excluding both bounds', '*[)* keeps items inside `value[0]` to `value[1]` including `value[0]` but excluding `value[1]', '*(]* keeps items inside `value[0]` to `value[1]` excluding `value[0]` but including `value[1]', '*][* keeps items outside `value[0]` to `value[1]` and equal to both bounds', '*)(* keeps items outside `value[0]` to `value[1]`', '*](* keeps items outside `value[0]` to `value[1]` and equal to `value[0]`', '*)[* keeps items outside `value[0]` to `value[1]` and equal to `value[1]`', '*{}* keeps items present in a set of values', '*}{* keeps items not present in a set of values'].join(' ')
},
value: {
valType: 'any',
dflt: 0,
editType: 'calc',
description: ['Sets the value or values by which to filter.', 'Values are expected to be in the same type as the data linked', 'to `target`.', 'When `operation` is set to one of', 'the comparison values (' + COMPARISON_OPS + ')', '`value` is expected to be a number or a string.', 'When `operation` is set to one of the interval values', '(' + INTERVAL_OPS + ')', '`value` is expected to be 2-item array where the first item', 'is the lower bound and the second item is the upper bound.', 'When `operation`, is set to one of the set values', '(' + SET_OPS + ')', '`value` is expected to be an array with as many items as', 'the desired set elements.'].join(' ')
},
preservegaps: {
valType: 'boolean',
dflt: false,
editType: 'calc',
description: ['Determines whether or not gaps in data arrays produced by the filter operation', 'are preserved.', 'Setting this to *true* might be useful when plotting a line chart', 'with `connectgaps` set to *false*.'].join(' ')
},
editType: 'calc'
};
exports.supplyDefaults = function (transformIn) {
var transformOut = {};
function coerce(attr, dflt) {
return Lib.coerce(transformIn, transformOut, exports.attributes, attr, dflt);
}
var enabled = coerce('enabled');
if (enabled) {
var target = coerce('target');
if (Lib.isArrayOrTypedArray(target) && target.length === 0) {
transformOut.enabled = false;
return transformOut;
}
coerce('preservegaps');
coerce('operation');
coerce('value');
var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleDefaults');
handleCalendarDefaults(transformIn, transformOut, 'valuecalendar', null);
handleCalendarDefaults(transformIn, transformOut, 'targetcalendar', null);
}
return transformOut;
};
exports.calcTransform = function (gd, trace, opts) {
if (!opts.enabled) return;
var targetArray = Lib.getTargetArray(trace, opts);
if (!targetArray) return;
var target = opts.target;
var len = targetArray.length;
if (trace._length) len = Math.min(len, trace._length);
var targetCalendar = opts.targetcalendar;
var arrayAttrs = trace._arrayAttrs;
var preservegaps = opts.preservegaps;
// even if you provide targetcalendar, if target is a string and there
// is a calendar attribute matching target it will get used instead.
if (typeof target === 'string') {
var attrTargetCalendar = Lib.nestedProperty(trace, target + 'calendar').get();
if (attrTargetCalendar) targetCalendar = attrTargetCalendar;
}
var d2c = Axes.getDataToCoordFunc(gd, trace, target, targetArray);
var filterFunc = getFilterFunc(opts, d2c, targetCalendar);
var originalArrays = {};
var indexToPoints = {};
var index = 0;
function forAllAttrs(fn, index) {
for (var j = 0; j < arrayAttrs.length; j++) {
var np = Lib.nestedProperty(trace, arrayAttrs[j]);
fn(np, index);
}
}
var initFn;
var fillFn;
if (preservegaps) {
initFn = function (np) {
originalArrays[np.astr] = Lib.extendDeep([], np.get());
np.set(new Array(len));
};
fillFn = function (np, index) {
var val = originalArrays[np.astr][index];
np.get()[index] = val;
};
} else {
initFn = function (np) {
originalArrays[np.astr] = Lib.extendDeep([], np.get());
np.set([]);
};
fillFn = function (np, index) {
var val = originalArrays[np.astr][index];
np.get().push(val);
};
}
// copy all original array attribute values, and clear arrays in trace
forAllAttrs(initFn);
var originalPointsAccessor = pointsAccessorFunction(trace.transforms, opts);
// loop through filter array, fill trace arrays if passed
for (var i = 0; i < len; i++) {
var passed = filterFunc(targetArray[i]);
if (passed) {
forAllAttrs(fillFn, i);
indexToPoints[index++] = originalPointsAccessor(i);
} else if (preservegaps) index++;
}
opts._indexToPoints = indexToPoints;
trace._length = index;
};
function getFilterFunc(opts, d2c, targetCalendar) {
var operation = opts.operation;
var value = opts.value;
var hasArrayValue = Lib.isArrayOrTypedArray(value);
function isOperationIn(array) {
return array.indexOf(operation) !== -1;
}
var d2cValue = function (v) {
return d2c(v, 0, opts.valuecalendar);
};
var d2cTarget = function (v) {
return d2c(v, 0, targetCalendar);
};
var coercedValue;
if (isOperationIn(COMPARISON_OPS)) {
coercedValue = hasArrayValue ? d2cValue(value[0]) : d2cValue(value);
} else if (isOperationIn(INTERVAL_OPS)) {
coercedValue = hasArrayValue ? [d2cValue(value[0]), d2cValue(value[1])] : [d2cValue(value), d2cValue(value)];
} else if (isOperationIn(SET_OPS)) {
coercedValue = hasArrayValue ? value.map(d2cValue) : [d2cValue(value)];
}
switch (operation) {
case '=':
return function (v) {
return d2cTarget(v) === coercedValue;
};
case '!=':
return function (v) {
return d2cTarget(v) !== coercedValue;
};
case '<':
return function (v) {
return d2cTarget(v) < coercedValue;
};
case '<=':
return function (v) {
return d2cTarget(v) <= coercedValue;
};
case '>':
return function (v) {
return d2cTarget(v) > coercedValue;
};
case '>=':
return function (v) {
return d2cTarget(v) >= coercedValue;
};
case '[]':
return function (v) {
var cv = d2cTarget(v);
return cv >= coercedValue[0] && cv <= coercedValue[1];
};
case '()':
return function (v) {
var cv = d2cTarget(v);
return cv > coercedValue[0] && cv < coercedValue[1];
};
case '[)':
return function (v) {
var cv = d2cTarget(v);
return cv >= coercedValue[0] && cv < coercedValue[1];
};
case '(]':
return function (v) {
var cv = d2cTarget(v);
return cv > coercedValue[0] && cv <= coercedValue[1];
};
case '][':
return function (v) {
var cv = d2cTarget(v);
return cv <= coercedValue[0] || cv >= coercedValue[1];
};
case ')(':
return function (v) {
var cv = d2cTarget(v);
return cv < coercedValue[0] || cv > coercedValue[1];
};
case '](':
return function (v) {
var cv = d2cTarget(v);
return cv <= coercedValue[0] || cv > coercedValue[1];
};
case ')[':
return function (v) {
var cv = d2cTarget(v);
return cv < coercedValue[0] || cv >= coercedValue[1];
};
case '{}':
return function (v) {
return coercedValue.indexOf(d2cTarget(v)) !== -1;
};
case '}{':
return function (v) {
return coercedValue.indexOf(d2cTarget(v)) === -1;
};
}
}
/***/ }),
/***/ 53244:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var PlotSchema = __webpack_require__(78380);
var Plots = __webpack_require__(19896);
var pointsAccessorFunction = (__webpack_require__(29328)/* .pointsAccessorFunction */ .W);
exports.moduleType = 'transform';
exports.name = 'groupby';
exports.attributes = {
enabled: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether this group-by transform is enabled or disabled.'].join(' ')
},
groups: {
valType: 'data_array',
dflt: [],
editType: 'calc',
description: ['Sets the groups in which the trace data will be split.', 'For example, with `x` set to *[1, 2, 3, 4]* and', '`groups` set to *[\'a\', \'b\', \'a\', \'b\']*,', 'the groupby transform with split in one trace', 'with `x` [1, 3] and one trace with `x` [2, 4].'].join(' ')
},
nameformat: {
valType: 'string',
editType: 'calc',
description: ['Pattern by which grouped traces are named. If only one trace is present,', 'defaults to the group name (`"%{group}"`), otherwise defaults to the group name', 'with trace name (`"%{group} (%{trace})"`). Available escape sequences are `%{group}`, which', 'inserts the group name, and `%{trace}`, which inserts the trace name. If grouping', 'GDP data by country when more than one trace is present, for example, the', 'default "%{group} (%{trace})" would return "Monaco (GDP per capita)".'].join(' ')
},
styles: {
_isLinkedToArray: 'style',
target: {
valType: 'string',
editType: 'calc',
description: ['The group value which receives these styles.'].join(' ')
},
value: {
valType: 'any',
dflt: {},
editType: 'calc',
description: ['Sets each group styles.', 'For example, with `groups` set to *[\'a\', \'b\', \'a\', \'b\']*', 'and `styles` set to *[{target: \'a\', value: { marker: { color: \'red\' } }}]', 'marker points in group *\'a\'* will be drawn in red.'].join(' '),
_compareAsJSON: true
},
editType: 'calc'
},
editType: 'calc'
};
/**
* Supply transform attributes defaults
*
* @param {object} transformIn
* object linked to trace.transforms[i] with 'type' set to exports.name
* @param {object} traceOut
* the _fullData trace this transform applies to
* @param {object} layout
* the plot's (not-so-full) layout
* @param {object} traceIn
* the input data trace this transform applies to
*
* @return {object} transformOut
* copy of transformIn that contains attribute defaults
*/
exports.supplyDefaults = function (transformIn, traceOut, layout) {
var i;
var transformOut = {};
function coerce(attr, dflt) {
return Lib.coerce(transformIn, transformOut, exports.attributes, attr, dflt);
}
var enabled = coerce('enabled');
if (!enabled) return transformOut;
coerce('groups');
coerce('nameformat', layout._dataLength > 1 ? '%{group} (%{trace})' : '%{group}');
var styleIn = transformIn.styles;
var styleOut = transformOut.styles = [];
if (styleIn) {
for (i = 0; i < styleIn.length; i++) {
var thisStyle = styleOut[i] = {};
Lib.coerce(styleIn[i], styleOut[i], exports.attributes.styles, 'target');
var value = Lib.coerce(styleIn[i], styleOut[i], exports.attributes.styles, 'value');
// so that you can edit value in place and have Plotly.react notice it, or
// rebuild it every time and have Plotly.react NOT think it changed:
// use _compareAsJSON to say we should diff the _JSON_value
if (Lib.isPlainObject(value)) thisStyle.value = Lib.extendDeep({}, value);else if (value) delete thisStyle.value;
}
}
return transformOut;
};
/**
* Apply transform !!!
*
* @param {array} data
* array of transformed traces (is [fullTrace] upon first transform)
*
* @param {object} state
* state object which includes:
* - transform {object} full transform attributes
* - fullTrace {object} full trace object which is being transformed
* - fullData {array} full pre-transform(s) data array
* - layout {object} the plot's (not-so-full) layout
*
* @return {object} newData
* array of transformed traces
*/
exports.transform = function (data, state) {
var newTraces, i, j;
var newData = [];
for (i = 0; i < data.length; i++) {
newTraces = transformOne(data[i], state);
for (j = 0; j < newTraces.length; j++) {
newData.push(newTraces[j]);
}
}
return newData;
};
function transformOne(trace, state) {
var i, j, k, attr, srcArray, groupName, newTrace, transforms, arrayLookup;
var groupNameObj;
var opts = state.transform;
var transformIndex = state.transformIndex;
var groups = trace.transforms[transformIndex].groups;
var originalPointsAccessor = pointsAccessorFunction(trace.transforms, opts);
if (!Lib.isArrayOrTypedArray(groups) || groups.length === 0) {
return [trace];
}
var groupNames = Lib.filterUnique(groups);
var newData = new Array(groupNames.length);
var len = groups.length;
var arrayAttrs = PlotSchema.findArrayAttributes(trace);
var styles = opts.styles || [];
var styleLookup = {};
for (i = 0; i < styles.length; i++) {
styleLookup[styles[i].target] = styles[i].value;
}
if (opts.styles) {
groupNameObj = Lib.keyedContainer(opts, 'styles', 'target', 'value.name');
}
// An index to map group name --> expanded trace index
var indexLookup = {};
var indexCnts = {};
for (i = 0; i < groupNames.length; i++) {
groupName = groupNames[i];
indexLookup[groupName] = i;
indexCnts[groupName] = 0;
// Start with a deep extend that just copies array references.
newTrace = newData[i] = Lib.extendDeepNoArrays({}, trace);
newTrace._group = groupName;
newTrace.transforms[transformIndex]._indexToPoints = {};
var suppliedName = null;
if (groupNameObj) {
suppliedName = groupNameObj.get(groupName);
}
if (suppliedName || suppliedName === '') {
newTrace.name = suppliedName;
} else {
newTrace.name = Lib.templateString(opts.nameformat, {
trace: trace.name,
group: groupName
});
}
// In order for groups to apply correctly to other transform data (e.g.
// a filter transform), we have to break the connection and clone the
// transforms so that each group writes grouped values into a different
// destination. This function does not break the array reference
// connection between the split transforms it creates. That's handled in
// initialize, which creates a new empty array for each arrayAttr.
transforms = newTrace.transforms;
newTrace.transforms = [];
for (j = 0; j < transforms.length; j++) {
newTrace.transforms[j] = Lib.extendDeepNoArrays({}, transforms[j]);
}
// Initialize empty arrays for the arrayAttrs, to be split in the next step
for (j = 0; j < arrayAttrs.length; j++) {
Lib.nestedProperty(newTrace, arrayAttrs[j]).set([]);
}
}
// For each array attribute including those nested inside this and other
// transforms (small note that we technically only need to do this for
// transforms that have not yet been applied):
for (k = 0; k < arrayAttrs.length; k++) {
attr = arrayAttrs[k];
// Cache all the arrays to which we'll push:
for (j = 0, arrayLookup = []; j < groupNames.length; j++) {
arrayLookup[j] = Lib.nestedProperty(newData[j], attr).get();
}
// Get the input data:
srcArray = Lib.nestedProperty(trace, attr).get();
// Send each data point to the appropriate expanded trace:
for (j = 0; j < len; j++) {
// Map group data --> trace index --> array and push data onto it
arrayLookup[indexLookup[groups[j]]].push(srcArray[j]);
}
}
for (j = 0; j < len; j++) {
newTrace = newData[indexLookup[groups[j]]];
var indexToPoints = newTrace.transforms[transformIndex]._indexToPoints;
indexToPoints[indexCnts[groups[j]]] = originalPointsAccessor(j);
indexCnts[groups[j]]++;
}
for (i = 0; i < groupNames.length; i++) {
groupName = groupNames[i];
newTrace = newData[i];
Plots.clearExpandedTraceDefaultColors(newTrace);
// there's no need to coerce styleLookup[groupName] here
// as another round of supplyDefaults is done on the transformed traces
newTrace = Lib.extendDeepNoArrays(newTrace, styleLookup[groupName] || {});
}
return newData;
}
/***/ }),
/***/ 29328:
/***/ (function(__unused_webpack_module, exports) {
"use strict";
exports.W = function (transforms, opts) {
var tr;
var prevIndexToPoints;
for (var i = 0; i < transforms.length; i++) {
tr = transforms[i];
if (tr === opts) break;
if (!tr._indexToPoints || tr.enabled === false) continue;
prevIndexToPoints = tr._indexToPoints;
}
var originalPointsAccessor = prevIndexToPoints ? function (i) {
return prevIndexToPoints[i];
} : function (i) {
return [i];
};
return originalPointsAccessor;
};
/***/ }),
/***/ 89424:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
"use strict";
var Lib = __webpack_require__(10923);
var Axes = __webpack_require__(81536);
var pointsAccessorFunction = (__webpack_require__(29328)/* .pointsAccessorFunction */ .W);
var BADNUM = (__webpack_require__(41752).BADNUM);
exports.moduleType = 'transform';
exports.name = 'sort';
exports.attributes = {
enabled: {
valType: 'boolean',
dflt: true,
editType: 'calc',
description: ['Determines whether this sort transform is enabled or disabled.'].join(' ')
},
target: {
valType: 'string',
strict: true,
noBlank: true,
arrayOk: true,
dflt: 'x',
editType: 'calc',
description: ['Sets the target by which the sort transform is applied.', 'If a string, *target* is assumed to be a reference to a data array', 'in the parent trace object.', 'To sort about nested variables, use *.* to access them.', 'For example, set `target` to *marker.size* to sort', 'about the marker size array.', 'If an array, *target* is then the data array by which', 'the sort transform is applied.'].join(' ')
},
order: {
valType: 'enumerated',
values: ['ascending', 'descending'],
dflt: 'ascending',
editType: 'calc',
description: ['Sets the sort transform order.'].join(' ')
},
editType: 'calc'
};
exports.supplyDefaults = function (transformIn) {
var transformOut = {};
function coerce(attr, dflt) {
return Lib.coerce(transformIn, transformOut, exports.attributes, attr, dflt);
}
var enabled = coerce('enabled');
if (enabled) {
coerce('target');
coerce('order');
}
return transformOut;
};
exports.calcTransform = function (gd, trace, opts) {
if (!opts.enabled) return;
var targetArray = Lib.getTargetArray(trace, opts);
if (!targetArray) return;
var target = opts.target;
var len = targetArray.length;
if (trace._length) len = Math.min(len, trace._length);
var arrayAttrs = trace._arrayAttrs;
var d2c = Axes.getDataToCoordFunc(gd, trace, target, targetArray);
var indices = getIndices(opts, targetArray, d2c, len);
var originalPointsAccessor = pointsAccessorFunction(trace.transforms, opts);
var indexToPoints = {};
var i, j;
for (i = 0; i < arrayAttrs.length; i++) {
var np = Lib.nestedProperty(trace, arrayAttrs[i]);
var arrayOld = np.get();
var arrayNew = new Array(len);
for (j = 0; j < len; j++) {
arrayNew[j] = arrayOld[indices[j]];
}
np.set(arrayNew);
}
for (j = 0; j < len; j++) {
indexToPoints[j] = originalPointsAccessor(indices[j]);
}
opts._indexToPoints = indexToPoints;
trace._length = len;
};
function getIndices(opts, targetArray, d2c, len) {
var sortedArray = new Array(len);
var indices = new Array(len);
var i;
for (i = 0; i < len; i++) {
sortedArray[i] = {
v: targetArray[i],
i: i
};
}
sortedArray.sort(getSortFunc(opts, d2c));
for (i = 0; i < len; i++) {
indices[i] = sortedArray[i].i;
}
return indices;
}
function getSortFunc(opts, d2c) {
switch (opts.order) {
case 'ascending':
return function (a, b) {
var ac = d2c(a.v);
var bc = d2c(b.v);
if (ac === BADNUM) {
return 1;
}
if (bc === BADNUM) {
return -1;
}
return ac - bc;
};
case 'descending':
return function (a, b) {
var ac = d2c(a.v);
var bc = d2c(b.v);
if (ac === BADNUM) {
return 1;
}
if (bc === BADNUM) {
return -1;
}
return bc - ac;
};
}
}
/***/ }),
/***/ 43720:
/***/ (function(__unused_webpack_module, exports) {
"use strict";
// package version injected by `npm run preprocess`
exports.version = '2.31.0';
/***/ }),
/***/ 14656:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
/* provided dependency */ var process = __webpack_require__(83712);
/******/(function(){// webpackBootstrap
/******/var __webpack_modules__={/***/1964:/***/function(module,__unused_webpack_exports,__nested_webpack_require_129__){module.exports={alpha_shape:__nested_webpack_require_129__(3502),convex_hull:__nested_webpack_require_129__(7352),delaunay_triangulate:__nested_webpack_require_129__(7642),gl_cone3d:__nested_webpack_require_129__(6405),gl_error3d:__nested_webpack_require_129__(9165),gl_heatmap2d:__nested_webpack_require_129__(2510),gl_line3d:__nested_webpack_require_129__(5714),gl_mesh3d:__nested_webpack_require_129__(7201),gl_plot2d:__nested_webpack_require_129__(1850),gl_plot3d:__nested_webpack_require_129__(4100),gl_pointcloud2d:__nested_webpack_require_129__(4696),gl_scatter3d:__nested_webpack_require_129__(8418),gl_select_box:__nested_webpack_require_129__(3161),gl_spikes2d:__nested_webpack_require_129__(4098),gl_streamtube3d:__nested_webpack_require_129__(7815),gl_surface3d:__nested_webpack_require_129__(9499),ndarray:__nested_webpack_require_129__(9618),ndarray_linear_interpolate:__nested_webpack_require_129__(4317)};/***/},/***/4793:/***/function(__unused_webpack_module,exports,__nested_webpack_require_936__){"use strict";var __webpack_unused_export__;/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh
* @license MIT
*/ /* eslint-disable no-proto */function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _defineProperties(target,props){for(var i=0;iK_MAX_LENGTH){throw new RangeError('The value "'+length+'" is invalid for option "size"');}// Return an augmented `Uint8Array` instance
var buf=new Uint8Array(length);Object.setPrototypeOf(buf,Buffer.prototype);return buf;}/**
* The Buffer constructor returns instances of `Uint8Array` that have their
* prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
* `Uint8Array`, so the returned instances will have all the node `Buffer` methods
* and the `Uint8Array` methods. Square bracket notation works as expected -- it
* returns a single octet.
*
* The `Uint8Array` prototype remains unmodified.
*/function Buffer(arg,encodingOrOffset,length){// Common case.
if(typeof arg==='number'){if(typeof encodingOrOffset==='string'){throw new TypeError('The "string" argument must be of type string. Received type number');}return allocUnsafe(arg);}return from(arg,encodingOrOffset,length);}Buffer.poolSize=8192;// not used by this implementation
function from(value,encodingOrOffset,length){if(typeof value==='string'){return fromString(value,encodingOrOffset);}if(ArrayBuffer.isView(value)){return fromArrayView(value);}if(value==null){throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, '+'or Array-like Object. Received type '+_typeof(value));}if(isInstance(value,ArrayBuffer)||value&&isInstance(value.buffer,ArrayBuffer)){return fromArrayBuffer(value,encodingOrOffset,length);}if(typeof SharedArrayBuffer!=='undefined'&&(isInstance(value,SharedArrayBuffer)||value&&isInstance(value.buffer,SharedArrayBuffer))){return fromArrayBuffer(value,encodingOrOffset,length);}if(typeof value==='number'){throw new TypeError('The "value" argument must not be of type number. Received type number');}var valueOf=value.valueOf&&value.valueOf();if(valueOf!=null&&valueOf!==value){return Buffer.from(valueOf,encodingOrOffset,length);}var b=fromObject(value);if(b)return b;if(typeof Symbol!=='undefined'&&Symbol.toPrimitive!=null&&typeof value[Symbol.toPrimitive]==='function'){return Buffer.from(value[Symbol.toPrimitive]('string'),encodingOrOffset,length);}throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, '+'or Array-like Object. Received type '+_typeof(value));}/**
* Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
* if value is a number.
* Buffer.from(str[, encoding])
* Buffer.from(array)
* Buffer.from(buffer)
* Buffer.from(arrayBuffer[, byteOffset[, length]])
**/Buffer.from=function(value,encodingOrOffset,length){return from(value,encodingOrOffset,length);};// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
// https://github.com/feross/buffer/pull/148
Object.setPrototypeOf(Buffer.prototype,Uint8Array.prototype);Object.setPrototypeOf(Buffer,Uint8Array);function assertSize(size){if(typeof size!=='number'){throw new TypeError('"size" argument must be of type number');}else if(size<0){throw new RangeError('The value "'+size+'" is invalid for option "size"');}}function alloc(size,fill,encoding){assertSize(size);if(size<=0){return createBuffer(size);}if(fill!==undefined){// Only pay attention to encoding if it's a string. This
// prevents accidentally sending in a number that would
// be interpreted as a start offset.
return typeof encoding==='string'?createBuffer(size).fill(fill,encoding):createBuffer(size).fill(fill);}return createBuffer(size);}/**
* Creates a new filled Buffer instance.
* alloc(size[, fill[, encoding]])
**/Buffer.alloc=function(size,fill,encoding){return alloc(size,fill,encoding);};function allocUnsafe(size){assertSize(size);return createBuffer(size<0?0:checked(size)|0);}/**
* Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
* */Buffer.allocUnsafe=function(size){return allocUnsafe(size);};/**
* Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
*/Buffer.allocUnsafeSlow=function(size){return allocUnsafe(size);};function fromString(string,encoding){if(typeof encoding!=='string'||encoding===''){encoding='utf8';}if(!Buffer.isEncoding(encoding)){throw new TypeError('Unknown encoding: '+encoding);}var length=byteLength(string,encoding)|0;var buf=createBuffer(length);var actual=buf.write(string,encoding);if(actual!==length){// Writing a hex string, for example, that contains invalid characters will
// cause everything after the first invalid character to be ignored. (e.g.
// 'abxxcd' will be treated as 'ab')
buf=buf.slice(0,actual);}return buf;}function fromArrayLike(array){var length=array.length<0?0:checked(array.length)|0;var buf=createBuffer(length);for(var i=0;i=K_MAX_LENGTH){throw new RangeError('Attempt to allocate Buffer larger than maximum '+'size: 0x'+K_MAX_LENGTH.toString(16)+' bytes');}return length|0;}function SlowBuffer(length){if(+length!=length){// eslint-disable-line eqeqeq
length=0;}return Buffer.alloc(+length);}Buffer.isBuffer=function isBuffer(b){return b!=null&&b._isBuffer===true&&b!==Buffer.prototype;// so Buffer.isBuffer(Buffer.prototype) will be false
};Buffer.compare=function compare(a,b){if(isInstance(a,Uint8Array))a=Buffer.from(a,a.offset,a.byteLength);if(isInstance(b,Uint8Array))b=Buffer.from(b,b.offset,b.byteLength);if(!Buffer.isBuffer(a)||!Buffer.isBuffer(b)){throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');}if(a===b)return 0;var x=a.length;var y=b.length;for(var i=0,len=Math.min(x,y);ibuffer.length){if(!Buffer.isBuffer(buf))buf=Buffer.from(buf);buf.copy(buffer,pos);}else{Uint8Array.prototype.set.call(buffer,buf,pos);}}else if(!Buffer.isBuffer(buf)){throw new TypeError('"list" argument must be an Array of Buffers');}else{buf.copy(buffer,pos);}pos+=buf.length;}return buffer;};function byteLength(string,encoding){if(Buffer.isBuffer(string)){return string.length;}if(ArrayBuffer.isView(string)||isInstance(string,ArrayBuffer)){return string.byteLength;}if(typeof string!=='string'){throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. '+'Received type '+_typeof(string));}var len=string.length;var mustMatch=arguments.length>2&&arguments[2]===true;if(!mustMatch&&len===0)return 0;// Use a for loop to avoid recursion
var loweredCase=false;for(;;){switch(encoding){case'ascii':case'latin1':case'binary':return len;case'utf8':case'utf-8':return utf8ToBytes(string).length;case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return len*2;case'hex':return len>>>1;case'base64':return base64ToBytes(string).length;default:if(loweredCase){return mustMatch?-1:utf8ToBytes(string).length;// assume utf8
}encoding=(''+encoding).toLowerCase();loweredCase=true;}}}Buffer.byteLength=byteLength;function slowToString(encoding,start,end){var loweredCase=false;// No need to verify that "this.length <= MAX_UINT32" since it's a read-only
// property of a typed array.
// This behaves neither like String nor Uint8Array in that we set start/end
// to their upper/lower bounds if the value passed is out of range.
// undefined is handled specially as per ECMA-262 6th Edition,
// Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
if(start===undefined||start<0){start=0;}// Return early if start > this.length. Done here to prevent potential uint32
// coercion fail below.
if(start>this.length){return'';}if(end===undefined||end>this.length){end=this.length;}if(end<=0){return'';}// Force coercion to uint32. This will also coerce falsey/NaN values to 0.
end>>>=0;start>>>=0;if(end<=start){return'';}if(!encoding)encoding='utf8';while(true){switch(encoding){case'hex':return hexSlice(this,start,end);case'utf8':case'utf-8':return utf8Slice(this,start,end);case'ascii':return asciiSlice(this,start,end);case'latin1':case'binary':return latin1Slice(this,start,end);case'base64':return base64Slice(this,start,end);case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return utf16leSlice(this,start,end);default:if(loweredCase)throw new TypeError('Unknown encoding: '+encoding);encoding=(encoding+'').toLowerCase();loweredCase=true;}}}// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
// to detect a Buffer instance. It's not possible to use `instanceof Buffer`
// reliably in a browserify context because there could be multiple different
// copies of the 'buffer' package in use. This method works even for Buffer
// instances that were created from another copy of the `buffer` package.
// See: https://github.com/feross/buffer/issues/154
Buffer.prototype._isBuffer=true;function swap(b,n,m){var i=b[n];b[n]=b[m];b[m]=i;}Buffer.prototype.swap16=function swap16(){var len=this.length;if(len%2!==0){throw new RangeError('Buffer size must be a multiple of 16-bits');}for(var i=0;imax)str+=' ... ';return'';};if(customInspectSymbol){Buffer.prototype[customInspectSymbol]=Buffer.prototype.inspect;}Buffer.prototype.compare=function compare(target,start,end,thisStart,thisEnd){if(isInstance(target,Uint8Array)){target=Buffer.from(target,target.offset,target.byteLength);}if(!Buffer.isBuffer(target)){throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. '+'Received type '+_typeof(target));}if(start===undefined){start=0;}if(end===undefined){end=target?target.length:0;}if(thisStart===undefined){thisStart=0;}if(thisEnd===undefined){thisEnd=this.length;}if(start<0||end>target.length||thisStart<0||thisEnd>this.length){throw new RangeError('out of range index');}if(thisStart>=thisEnd&&start>=end){return 0;}if(thisStart>=thisEnd){return-1;}if(start>=end){return 1;}start>>>=0;end>>>=0;thisStart>>>=0;thisEnd>>>=0;if(this===target)return 0;var x=thisEnd-thisStart;var y=end-start;var len=Math.min(x,y);var thisCopy=this.slice(thisStart,thisEnd);var targetCopy=target.slice(start,end);for(var i=0;i= `byteOffset`,
// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
//
// Arguments:
// - buffer - a Buffer to search
// - val - a string, Buffer, or number
// - byteOffset - an index into `buffer`; will be clamped to an int32
// - encoding - an optional encoding, relevant is val is a string
// - dir - true for indexOf, false for lastIndexOf
function bidirectionalIndexOf(buffer,val,byteOffset,encoding,dir){// Empty buffer means no match
if(buffer.length===0)return-1;// Normalize byteOffset
if(typeof byteOffset==='string'){encoding=byteOffset;byteOffset=0;}else if(byteOffset>0x7fffffff){byteOffset=0x7fffffff;}else if(byteOffset<-0x80000000){byteOffset=-0x80000000;}byteOffset=+byteOffset;// Coerce to Number.
if(numberIsNaN(byteOffset)){// byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
byteOffset=dir?0:buffer.length-1;}// Normalize byteOffset: negative offsets start from the end of the buffer
if(byteOffset<0)byteOffset=buffer.length+byteOffset;if(byteOffset>=buffer.length){if(dir)return-1;else byteOffset=buffer.length-1;}else if(byteOffset<0){if(dir)byteOffset=0;else return-1;}// Normalize val
if(typeof val==='string'){val=Buffer.from(val,encoding);}// Finally, search either indexOf (if dir is true) or lastIndexOf
if(Buffer.isBuffer(val)){// Special case: looking for empty string/buffer always fails
if(val.length===0){return-1;}return arrayIndexOf(buffer,val,byteOffset,encoding,dir);}else if(typeof val==='number'){val=val&0xFF;// Search for a byte value [0-255]
if(typeof Uint8Array.prototype.indexOf==='function'){if(dir){return Uint8Array.prototype.indexOf.call(buffer,val,byteOffset);}else{return Uint8Array.prototype.lastIndexOf.call(buffer,val,byteOffset);}}return arrayIndexOf(buffer,[val],byteOffset,encoding,dir);}throw new TypeError('val must be string, number or Buffer');}function arrayIndexOf(arr,val,byteOffset,encoding,dir){var indexSize=1;var arrLength=arr.length;var valLength=val.length;if(encoding!==undefined){encoding=String(encoding).toLowerCase();if(encoding==='ucs2'||encoding==='ucs-2'||encoding==='utf16le'||encoding==='utf-16le'){if(arr.length<2||val.length<2){return-1;}indexSize=2;arrLength/=2;valLength/=2;byteOffset/=2;}}function read(buf,i){if(indexSize===1){return buf[i];}else{return buf.readUInt16BE(i*indexSize);}}var i;if(dir){var foundIndex=-1;for(i=byteOffset;iarrLength)byteOffset=arrLength-valLength;for(i=byteOffset;i>=0;i--){var found=true;for(var j=0;jremaining){length=remaining;}}var strLen=string.length;if(length>strLen/2){length=strLen/2;}var i;for(i=0;i>>0;if(isFinite(length)){length=length>>>0;if(encoding===undefined)encoding='utf8';}else{encoding=length;length=undefined;}}else{throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported');}var remaining=this.length-offset;if(length===undefined||length>remaining)length=remaining;if(string.length>0&&(length<0||offset<0)||offset>this.length){throw new RangeError('Attempt to write outside buffer bounds');}if(!encoding)encoding='utf8';var loweredCase=false;for(;;){switch(encoding){case'hex':return hexWrite(this,string,offset,length);case'utf8':case'utf-8':return utf8Write(this,string,offset,length);case'ascii':case'latin1':case'binary':return asciiWrite(this,string,offset,length);case'base64':// Warning: maxLength not taken into account in base64Write
return base64Write(this,string,offset,length);case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return ucs2Write(this,string,offset,length);default:if(loweredCase)throw new TypeError('Unknown encoding: '+encoding);encoding=(''+encoding).toLowerCase();loweredCase=true;}}};Buffer.prototype.toJSON=function toJSON(){return{type:'Buffer',data:Array.prototype.slice.call(this._arr||this,0)};};function base64Slice(buf,start,end){if(start===0&&end===buf.length){return base64.fromByteArray(buf);}else{return base64.fromByteArray(buf.slice(start,end));}}function utf8Slice(buf,start,end){end=Math.min(buf.length,end);var res=[];var i=start;while(i0xEF?4:firstByte>0xDF?3:firstByte>0xBF?2:1;if(i+bytesPerSequence<=end){var secondByte=void 0,thirdByte=void 0,fourthByte=void 0,tempCodePoint=void 0;switch(bytesPerSequence){case 1:if(firstByte<0x80){codePoint=firstByte;}break;case 2:secondByte=buf[i+1];if((secondByte&0xC0)===0x80){tempCodePoint=(firstByte&0x1F)<<0x6|secondByte&0x3F;if(tempCodePoint>0x7F){codePoint=tempCodePoint;}}break;case 3:secondByte=buf[i+1];thirdByte=buf[i+2];if((secondByte&0xC0)===0x80&&(thirdByte&0xC0)===0x80){tempCodePoint=(firstByte&0xF)<<0xC|(secondByte&0x3F)<<0x6|thirdByte&0x3F;if(tempCodePoint>0x7FF&&(tempCodePoint<0xD800||tempCodePoint>0xDFFF)){codePoint=tempCodePoint;}}break;case 4:secondByte=buf[i+1];thirdByte=buf[i+2];fourthByte=buf[i+3];if((secondByte&0xC0)===0x80&&(thirdByte&0xC0)===0x80&&(fourthByte&0xC0)===0x80){tempCodePoint=(firstByte&0xF)<<0x12|(secondByte&0x3F)<<0xC|(thirdByte&0x3F)<<0x6|fourthByte&0x3F;if(tempCodePoint>0xFFFF&&tempCodePoint<0x110000){codePoint=tempCodePoint;}}}}if(codePoint===null){// we did not generate a valid codePoint so insert a
// replacement char (U+FFFD) and advance only 1 byte
codePoint=0xFFFD;bytesPerSequence=1;}else if(codePoint>0xFFFF){// encode to utf16 (surrogate pair dance)
codePoint-=0x10000;res.push(codePoint>>>10&0x3FF|0xD800);codePoint=0xDC00|codePoint&0x3FF;}res.push(codePoint);i+=bytesPerSequence;}return decodeCodePointsArray(res);}// Based on http://stackoverflow.com/a/22747272/680742, the browser with
// the lowest limit is Chrome, with 0x10000 args.
// We go 1 magnitude less, for safety
var MAX_ARGUMENTS_LENGTH=0x1000;function decodeCodePointsArray(codePoints){var len=codePoints.length;if(len<=MAX_ARGUMENTS_LENGTH){return String.fromCharCode.apply(String,codePoints);// avoid extra slice()
}// Decode in chunks to avoid "call stack size exceeded".
var res='';var i=0;while(ilen)end=len;var out='';for(var i=start;ilen){start=len;}if(end<0){end+=len;if(end<0)end=0;}else if(end>len){end=len;}if(endlength)throw new RangeError('Trying to access beyond buffer length');}Buffer.prototype.readUintLE=Buffer.prototype.readUIntLE=function readUIntLE(offset,byteLength,noAssert){offset=offset>>>0;byteLength=byteLength>>>0;if(!noAssert)checkOffset(offset,byteLength,this.length);var val=this[offset];var mul=1;var i=0;while(++i>>0;byteLength=byteLength>>>0;if(!noAssert){checkOffset(offset,byteLength,this.length);}var val=this[offset+--byteLength];var mul=1;while(byteLength>0&&(mul*=0x100)){val+=this[offset+--byteLength]*mul;}return val;};Buffer.prototype.readUint8=Buffer.prototype.readUInt8=function readUInt8(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,1,this.length);return this[offset];};Buffer.prototype.readUint16LE=Buffer.prototype.readUInt16LE=function readUInt16LE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,2,this.length);return this[offset]|this[offset+1]<<8;};Buffer.prototype.readUint16BE=Buffer.prototype.readUInt16BE=function readUInt16BE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,2,this.length);return this[offset]<<8|this[offset+1];};Buffer.prototype.readUint32LE=Buffer.prototype.readUInt32LE=function readUInt32LE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,4,this.length);return(this[offset]|this[offset+1]<<8|this[offset+2]<<16)+this[offset+3]*0x1000000;};Buffer.prototype.readUint32BE=Buffer.prototype.readUInt32BE=function readUInt32BE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,4,this.length);return this[offset]*0x1000000+(this[offset+1]<<16|this[offset+2]<<8|this[offset+3]);};Buffer.prototype.readBigUInt64LE=defineBigIntMethod(function readBigUInt64LE(offset){offset=offset>>>0;validateNumber(offset,'offset');var first=this[offset];var last=this[offset+7];if(first===undefined||last===undefined){boundsError(offset,this.length-8);}var lo=first+this[++offset]*Math.pow(2,8)+this[++offset]*Math.pow(2,16)+this[++offset]*Math.pow(2,24);var hi=this[++offset]+this[++offset]*Math.pow(2,8)+this[++offset]*Math.pow(2,16)+last*Math.pow(2,24);return BigInt(lo)+(BigInt(hi)<>>0;validateNumber(offset,'offset');var first=this[offset];var last=this[offset+7];if(first===undefined||last===undefined){boundsError(offset,this.length-8);}var hi=first*Math.pow(2,24)+this[++offset]*Math.pow(2,16)+this[++offset]*Math.pow(2,8)+this[++offset];var lo=this[++offset]*Math.pow(2,24)+this[++offset]*Math.pow(2,16)+this[++offset]*Math.pow(2,8)+last;return(BigInt(hi)<>>0;byteLength=byteLength>>>0;if(!noAssert)checkOffset(offset,byteLength,this.length);var val=this[offset];var mul=1;var i=0;while(++i=mul)val-=Math.pow(2,8*byteLength);return val;};Buffer.prototype.readIntBE=function readIntBE(offset,byteLength,noAssert){offset=offset>>>0;byteLength=byteLength>>>0;if(!noAssert)checkOffset(offset,byteLength,this.length);var i=byteLength;var mul=1;var val=this[offset+--i];while(i>0&&(mul*=0x100)){val+=this[offset+--i]*mul;}mul*=0x80;if(val>=mul)val-=Math.pow(2,8*byteLength);return val;};Buffer.prototype.readInt8=function readInt8(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,1,this.length);if(!(this[offset]&0x80))return this[offset];return(0xff-this[offset]+1)*-1;};Buffer.prototype.readInt16LE=function readInt16LE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,2,this.length);var val=this[offset]|this[offset+1]<<8;return val&0x8000?val|0xFFFF0000:val;};Buffer.prototype.readInt16BE=function readInt16BE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,2,this.length);var val=this[offset+1]|this[offset]<<8;return val&0x8000?val|0xFFFF0000:val;};Buffer.prototype.readInt32LE=function readInt32LE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,4,this.length);return this[offset]|this[offset+1]<<8|this[offset+2]<<16|this[offset+3]<<24;};Buffer.prototype.readInt32BE=function readInt32BE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,4,this.length);return this[offset]<<24|this[offset+1]<<16|this[offset+2]<<8|this[offset+3];};Buffer.prototype.readBigInt64LE=defineBigIntMethod(function readBigInt64LE(offset){offset=offset>>>0;validateNumber(offset,'offset');var first=this[offset];var last=this[offset+7];if(first===undefined||last===undefined){boundsError(offset,this.length-8);}var val=this[offset+4]+this[offset+5]*Math.pow(2,8)+this[offset+6]*Math.pow(2,16)+(last<<24);// Overflow
return(BigInt(val)<>>0;validateNumber(offset,'offset');var first=this[offset];var last=this[offset+7];if(first===undefined||last===undefined){boundsError(offset,this.length-8);}var val=(first<<24)+// Overflow
this[++offset]*Math.pow(2,16)+this[++offset]*Math.pow(2,8)+this[++offset];return(BigInt(val)<>>0;if(!noAssert)checkOffset(offset,4,this.length);return ieee754.read(this,offset,true,23,4);};Buffer.prototype.readFloatBE=function readFloatBE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,4,this.length);return ieee754.read(this,offset,false,23,4);};Buffer.prototype.readDoubleLE=function readDoubleLE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,8,this.length);return ieee754.read(this,offset,true,52,8);};Buffer.prototype.readDoubleBE=function readDoubleBE(offset,noAssert){offset=offset>>>0;if(!noAssert)checkOffset(offset,8,this.length);return ieee754.read(this,offset,false,52,8);};function checkInt(buf,value,offset,ext,max,min){if(!Buffer.isBuffer(buf))throw new TypeError('"buffer" argument must be a Buffer instance');if(value>max||valuebuf.length)throw new RangeError('Index out of range');}Buffer.prototype.writeUintLE=Buffer.prototype.writeUIntLE=function writeUIntLE(value,offset,byteLength,noAssert){value=+value;offset=offset>>>0;byteLength=byteLength>>>0;if(!noAssert){var maxBytes=Math.pow(2,8*byteLength)-1;checkInt(this,value,offset,byteLength,maxBytes,0);}var mul=1;var i=0;this[offset]=value&0xFF;while(++i>>0;byteLength=byteLength>>>0;if(!noAssert){var maxBytes=Math.pow(2,8*byteLength)-1;checkInt(this,value,offset,byteLength,maxBytes,0);}var i=byteLength-1;var mul=1;this[offset+i]=value&0xFF;while(--i>=0&&(mul*=0x100)){this[offset+i]=value/mul&0xFF;}return offset+byteLength;};Buffer.prototype.writeUint8=Buffer.prototype.writeUInt8=function writeUInt8(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,1,0xff,0);this[offset]=value&0xff;return offset+1;};Buffer.prototype.writeUint16LE=Buffer.prototype.writeUInt16LE=function writeUInt16LE(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,2,0xffff,0);this[offset]=value&0xff;this[offset+1]=value>>>8;return offset+2;};Buffer.prototype.writeUint16BE=Buffer.prototype.writeUInt16BE=function writeUInt16BE(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,2,0xffff,0);this[offset]=value>>>8;this[offset+1]=value&0xff;return offset+2;};Buffer.prototype.writeUint32LE=Buffer.prototype.writeUInt32LE=function writeUInt32LE(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,4,0xffffffff,0);this[offset+3]=value>>>24;this[offset+2]=value>>>16;this[offset+1]=value>>>8;this[offset]=value&0xff;return offset+4;};Buffer.prototype.writeUint32BE=Buffer.prototype.writeUInt32BE=function writeUInt32BE(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,4,0xffffffff,0);this[offset]=value>>>24;this[offset+1]=value>>>16;this[offset+2]=value>>>8;this[offset+3]=value&0xff;return offset+4;};function wrtBigUInt64LE(buf,value,offset,min,max){checkIntBI(value,min,max,buf,offset,7);var lo=Number(value&BigInt(0xffffffff));buf[offset++]=lo;lo=lo>>8;buf[offset++]=lo;lo=lo>>8;buf[offset++]=lo;lo=lo>>8;buf[offset++]=lo;var hi=Number(value>>BigInt(32)&BigInt(0xffffffff));buf[offset++]=hi;hi=hi>>8;buf[offset++]=hi;hi=hi>>8;buf[offset++]=hi;hi=hi>>8;buf[offset++]=hi;return offset;}function wrtBigUInt64BE(buf,value,offset,min,max){checkIntBI(value,min,max,buf,offset,7);var lo=Number(value&BigInt(0xffffffff));buf[offset+7]=lo;lo=lo>>8;buf[offset+6]=lo;lo=lo>>8;buf[offset+5]=lo;lo=lo>>8;buf[offset+4]=lo;var hi=Number(value>>BigInt(32)&BigInt(0xffffffff));buf[offset+3]=hi;hi=hi>>8;buf[offset+2]=hi;hi=hi>>8;buf[offset+1]=hi;hi=hi>>8;buf[offset]=hi;return offset+8;}Buffer.prototype.writeBigUInt64LE=defineBigIntMethod(function writeBigUInt64LE(value){var offset=arguments.length>1&&arguments[1]!==undefined?arguments[1]:0;return wrtBigUInt64LE(this,value,offset,BigInt(0),BigInt('0xffffffffffffffff'));});Buffer.prototype.writeBigUInt64BE=defineBigIntMethod(function writeBigUInt64BE(value){var offset=arguments.length>1&&arguments[1]!==undefined?arguments[1]:0;return wrtBigUInt64BE(this,value,offset,BigInt(0),BigInt('0xffffffffffffffff'));});Buffer.prototype.writeIntLE=function writeIntLE(value,offset,byteLength,noAssert){value=+value;offset=offset>>>0;if(!noAssert){var limit=Math.pow(2,8*byteLength-1);checkInt(this,value,offset,byteLength,limit-1,-limit);}var i=0;var mul=1;var sub=0;this[offset]=value&0xFF;while(++i>0)-sub&0xFF;}return offset+byteLength;};Buffer.prototype.writeIntBE=function writeIntBE(value,offset,byteLength,noAssert){value=+value;offset=offset>>>0;if(!noAssert){var limit=Math.pow(2,8*byteLength-1);checkInt(this,value,offset,byteLength,limit-1,-limit);}var i=byteLength-1;var mul=1;var sub=0;this[offset+i]=value&0xFF;while(--i>=0&&(mul*=0x100)){if(value<0&&sub===0&&this[offset+i+1]!==0){sub=1;}this[offset+i]=(value/mul>>0)-sub&0xFF;}return offset+byteLength;};Buffer.prototype.writeInt8=function writeInt8(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,1,0x7f,-0x80);if(value<0)value=0xff+value+1;this[offset]=value&0xff;return offset+1;};Buffer.prototype.writeInt16LE=function writeInt16LE(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,2,0x7fff,-0x8000);this[offset]=value&0xff;this[offset+1]=value>>>8;return offset+2;};Buffer.prototype.writeInt16BE=function writeInt16BE(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,2,0x7fff,-0x8000);this[offset]=value>>>8;this[offset+1]=value&0xff;return offset+2;};Buffer.prototype.writeInt32LE=function writeInt32LE(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,4,0x7fffffff,-0x80000000);this[offset]=value&0xff;this[offset+1]=value>>>8;this[offset+2]=value>>>16;this[offset+3]=value>>>24;return offset+4;};Buffer.prototype.writeInt32BE=function writeInt32BE(value,offset,noAssert){value=+value;offset=offset>>>0;if(!noAssert)checkInt(this,value,offset,4,0x7fffffff,-0x80000000);if(value<0)value=0xffffffff+value+1;this[offset]=value>>>24;this[offset+1]=value>>>16;this[offset+2]=value>>>8;this[offset+3]=value&0xff;return offset+4;};Buffer.prototype.writeBigInt64LE=defineBigIntMethod(function writeBigInt64LE(value){var offset=arguments.length>1&&arguments[1]!==undefined?arguments[1]:0;return wrtBigUInt64LE(this,value,offset,-BigInt('0x8000000000000000'),BigInt('0x7fffffffffffffff'));});Buffer.prototype.writeBigInt64BE=defineBigIntMethod(function writeBigInt64BE(value){var offset=arguments.length>1&&arguments[1]!==undefined?arguments[1]:0;return wrtBigUInt64BE(this,value,offset,-BigInt('0x8000000000000000'),BigInt('0x7fffffffffffffff'));});function checkIEEE754(buf,value,offset,ext,max,min){if(offset+ext>buf.length)throw new RangeError('Index out of range');if(offset<0)throw new RangeError('Index out of range');}function writeFloat(buf,value,offset,littleEndian,noAssert){value=+value;offset=offset>>>0;if(!noAssert){checkIEEE754(buf,value,offset,4,3.4028234663852886e+38,-3.4028234663852886e+38);}ieee754.write(buf,value,offset,littleEndian,23,4);return offset+4;}Buffer.prototype.writeFloatLE=function writeFloatLE(value,offset,noAssert){return writeFloat(this,value,offset,true,noAssert);};Buffer.prototype.writeFloatBE=function writeFloatBE(value,offset,noAssert){return writeFloat(this,value,offset,false,noAssert);};function writeDouble(buf,value,offset,littleEndian,noAssert){value=+value;offset=offset>>>0;if(!noAssert){checkIEEE754(buf,value,offset,8,1.7976931348623157E+308,-1.7976931348623157E+308);}ieee754.write(buf,value,offset,littleEndian,52,8);return offset+8;}Buffer.prototype.writeDoubleLE=function writeDoubleLE(value,offset,noAssert){return writeDouble(this,value,offset,true,noAssert);};Buffer.prototype.writeDoubleBE=function writeDoubleBE(value,offset,noAssert){return writeDouble(this,value,offset,false,noAssert);};// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
Buffer.prototype.copy=function copy(target,targetStart,start,end){if(!Buffer.isBuffer(target))throw new TypeError('argument should be a Buffer');if(!start)start=0;if(!end&&end!==0)end=this.length;if(targetStart>=target.length)targetStart=target.length;if(!targetStart)targetStart=0;if(end>0&&end=this.length)throw new RangeError('Index out of range');if(end<0)throw new RangeError('sourceEnd out of bounds');// Are we oob?
if(end>this.length)end=this.length;if(target.length-targetStart>>0;end=end===undefined?this.length:end>>>0;if(!val)val=0;var i;if(typeof val==='number'){for(i=start;iMath.pow(2,32)){received=addNumericalSeparator(String(input));}else if(typeof input==='bigint'){received=String(input);if(input>Math.pow(BigInt(2),BigInt(32))||input<-Math.pow(BigInt(2),BigInt(32))){received=addNumericalSeparator(received);}received+='n';}msg+=" It must be ".concat(range,". Received ").concat(received);return msg;},RangeError);function addNumericalSeparator(val){var res='';var i=val.length;var start=val[0]==='-'?1:0;for(;i>=start+4;i-=3){res="_".concat(val.slice(i-3,i)).concat(res);}return"".concat(val.slice(0,i)).concat(res);}// CHECK FUNCTIONS
// ===============
function checkBounds(buf,offset,byteLength){validateNumber(offset,'offset');if(buf[offset]===undefined||buf[offset+byteLength]===undefined){boundsError(offset,buf.length-(byteLength+1));}}function checkIntBI(value,min,max,buf,offset,byteLength){if(value>max||value3){if(min===0||min===BigInt(0)){range=">= 0".concat(n," and < 2").concat(n," ** ").concat((byteLength+1)*8).concat(n);}else{range=">= -(2".concat(n," ** ").concat((byteLength+1)*8-1).concat(n,") and < 2 ** ")+"".concat((byteLength+1)*8-1).concat(n);}}else{range=">= ".concat(min).concat(n," and <= ").concat(max).concat(n);}throw new errors.ERR_OUT_OF_RANGE('value',range,value);}checkBounds(buf,offset,byteLength);}function validateNumber(value,name){if(typeof value!=='number'){throw new errors.ERR_INVALID_ARG_TYPE(name,'number',value);}}function boundsError(value,length,type){if(Math.floor(value)!==value){validateNumber(value,type);throw new errors.ERR_OUT_OF_RANGE(type||'offset','an integer',value);}if(length<0){throw new errors.ERR_BUFFER_OUT_OF_BOUNDS();}throw new errors.ERR_OUT_OF_RANGE(type||'offset',">= ".concat(type?1:0," and <= ").concat(length),value);}// HELPER FUNCTIONS
// ================
var INVALID_BASE64_RE=/[^+/0-9A-Za-z-_]/g;function base64clean(str){// Node takes equal signs as end of the Base64 encoding
str=str.split('=')[0];// Node strips out invalid characters like \n and \t from the string, base64-js does not
str=str.trim().replace(INVALID_BASE64_RE,'');// Node converts strings with length < 2 to ''
if(str.length<2)return'';// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
while(str.length%4!==0){str=str+'=';}return str;}function utf8ToBytes(string,units){units=units||Infinity;var codePoint;var length=string.length;var leadSurrogate=null;var bytes=[];for(var i=0;i0xD7FF&&codePoint<0xE000){// last char was a lead
if(!leadSurrogate){// no lead yet
if(codePoint>0xDBFF){// unexpected trail
if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);continue;}else if(i+1===length){// unpaired lead
if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);continue;}// valid lead
leadSurrogate=codePoint;continue;}// 2 leads in a row
if(codePoint<0xDC00){if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);leadSurrogate=codePoint;continue;}// valid surrogate pair
codePoint=(leadSurrogate-0xD800<<10|codePoint-0xDC00)+0x10000;}else if(leadSurrogate){// valid bmp char, but last char was a lead
if((units-=3)>-1)bytes.push(0xEF,0xBF,0xBD);}leadSurrogate=null;// encode utf8
if(codePoint<0x80){if((units-=1)<0)break;bytes.push(codePoint);}else if(codePoint<0x800){if((units-=2)<0)break;bytes.push(codePoint>>0x6|0xC0,codePoint&0x3F|0x80);}else if(codePoint<0x10000){if((units-=3)<0)break;bytes.push(codePoint>>0xC|0xE0,codePoint>>0x6&0x3F|0x80,codePoint&0x3F|0x80);}else if(codePoint<0x110000){if((units-=4)<0)break;bytes.push(codePoint>>0x12|0xF0,codePoint>>0xC&0x3F|0x80,codePoint>>0x6&0x3F|0x80,codePoint&0x3F|0x80);}else{throw new Error('Invalid code point');}}return bytes;}function asciiToBytes(str){var byteArray=[];for(var i=0;i>8;lo=c%256;byteArray.push(lo);byteArray.push(hi);}return byteArray;}function base64ToBytes(str){return base64.toByteArray(base64clean(str));}function blitBuffer(src,dst,offset,length){var i;for(i=0;i=dst.length||i>=src.length)break;dst[i+offset]=src[i];}return i;}// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
// the `instanceof` check but they should be treated as of that type.
// See: https://github.com/feross/buffer/issues/166
function isInstance(obj,type){return obj instanceof type||obj!=null&&obj.constructor!=null&&obj.constructor.name!=null&&obj.constructor.name===type.name;}function numberIsNaN(obj){// For IE11 support
return obj!==obj;// eslint-disable-line no-self-compare
}// Create lookup table for `toString('hex')`
// See: https://github.com/feross/buffer/issues/219
var hexSliceLookupTable=function(){var alphabet='0123456789abcdef';var table=new Array(256);for(var i=0;i<16;++i){var i16=i*16;for(var j=0;j<16;++j){table[i16+j]=alphabet[i]+alphabet[j];}}return table;}();// Return not function with Error if BigInt not supported
function defineBigIntMethod(fn){return typeof BigInt==='undefined'?BufferBigIntNotDefined:fn;}function BufferBigIntNotDefined(){throw new Error('BigInt not supported');}/***/},/***/9216:/***/function(module){"use strict";module.exports=isMobile;module.exports.isMobile=isMobile;module.exports["default"]=isMobile;var mobileRE=/(android|bb\d+|meego).+mobile|armv7l|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series[46]0|samsungbrowser.*mobile|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i;var notMobileRE=/CrOS/;var tabletRE=/android|ipad|playbook|silk/i;function isMobile(opts){if(!opts)opts={};var ua=opts.ua;if(!ua&&typeof navigator!=='undefined')ua=navigator.userAgent;if(ua&&ua.headers&&typeof ua.headers['user-agent']==='string'){ua=ua.headers['user-agent'];}if(typeof ua!=='string')return false;var result=mobileRE.test(ua)&&!notMobileRE.test(ua)||!!opts.tablet&&tabletRE.test(ua);if(!result&&opts.tablet&&opts.featureDetect&&navigator&&navigator.maxTouchPoints>1&&ua.indexOf('Macintosh')!==-1&&ua.indexOf('Safari')!==-1){result=true;}return result;}/***/},/***/6296:/***/function(module,__unused_webpack_exports,__nested_webpack_require_53135__){"use strict";module.exports=createViewController;var createTurntable=__nested_webpack_require_53135__(7261);var createOrbit=__nested_webpack_require_53135__(9977);var createMatrix=__nested_webpack_require_53135__(4192);function ViewController(controllers,mode){this._controllerNames=Object.keys(controllers);this._controllerList=this._controllerNames.map(function(n){return controllers[n];});this._mode=mode;this._active=controllers[mode];if(!this._active){this._mode='turntable';this._active=controllers.turntable;}this.modes=this._controllerNames;this.computedMatrix=this._active.computedMatrix;this.computedEye=this._active.computedEye;this.computedUp=this._active.computedUp;this.computedCenter=this._active.computedCenter;this.computedRadius=this._active.computedRadius;}var proto=ViewController.prototype;proto.flush=function(a0){var cc=this._controllerList;for(var i=0;i0){throw new Error('Invalid string. Length must be a multiple of 4');}// Trim off extra bytes after placeholder bytes are found
// See: https://github.com/beatgammit/base64-js/issues/42
var validLen=b64.indexOf('=');if(validLen===-1)validLen=len;var placeHoldersLen=validLen===len?0:4-validLen%4;return[validLen,placeHoldersLen];}// base64 is 4/3 + up to two characters of the original data
function byteLength(b64){var lens=getLens(b64);var validLen=lens[0];var placeHoldersLen=lens[1];return(validLen+placeHoldersLen)*3/4-placeHoldersLen;}function _byteLength(b64,validLen,placeHoldersLen){return(validLen+placeHoldersLen)*3/4-placeHoldersLen;}function toByteArray(b64){var tmp;var lens=getLens(b64);var validLen=lens[0];var placeHoldersLen=lens[1];var arr=new Arr(_byteLength(b64,validLen,placeHoldersLen));var curByte=0;// if there are placeholders, only get up to the last complete 4 chars
var len=placeHoldersLen>0?validLen-4:validLen;var i;for(i=0;i>16&0xFF;arr[curByte++]=tmp>>8&0xFF;arr[curByte++]=tmp&0xFF;}if(placeHoldersLen===2){tmp=revLookup[b64.charCodeAt(i)]<<2|revLookup[b64.charCodeAt(i+1)]>>4;arr[curByte++]=tmp&0xFF;}if(placeHoldersLen===1){tmp=revLookup[b64.charCodeAt(i)]<<10|revLookup[b64.charCodeAt(i+1)]<<4|revLookup[b64.charCodeAt(i+2)]>>2;arr[curByte++]=tmp>>8&0xFF;arr[curByte++]=tmp&0xFF;}return arr;}function tripletToBase64(num){return lookup[num>>18&0x3F]+lookup[num>>12&0x3F]+lookup[num>>6&0x3F]+lookup[num&0x3F];}function encodeChunk(uint8,start,end){var tmp;var output=[];for(var i=start;ilen2?len2:i+maxChunkLength));}// pad the end with zeros, but make sure to not forget the extra bytes
if(extraBytes===1){tmp=uint8[len-1];parts.push(lookup[tmp>>2]+lookup[tmp<<4&0x3F]+'==');}else if(extraBytes===2){tmp=(uint8[len-2]<<8)+uint8[len-1];parts.push(lookup[tmp>>10]+lookup[tmp>>4&0x3F]+lookup[tmp<<2&0x3F]+'=');}return parts.join('');}/***/},/***/3865:/***/function(module,__unused_webpack_exports,__nested_webpack_require_63262__){"use strict";var rationalize=__nested_webpack_require_63262__(869);module.exports=add;function add(a,b){return rationalize(a[0].mul(b[1]).add(b[0].mul(a[1])),a[1].mul(b[1]));}/***/},/***/1318:/***/function(module){"use strict";module.exports=cmp;function cmp(a,b){return a[0].mul(b[1]).cmp(b[0].mul(a[1]));}/***/},/***/8697:/***/function(module,__unused_webpack_exports,__nested_webpack_require_63640__){"use strict";var rationalize=__nested_webpack_require_63640__(869);module.exports=div;function div(a,b){return rationalize(a[0].mul(b[1]),a[1].mul(b[0]));}/***/},/***/7842:/***/function(module,__unused_webpack_exports,__nested_webpack_require_63866__){"use strict";var isRat=__nested_webpack_require_63866__(6330);var isBN=__nested_webpack_require_63866__(1533);var num2bn=__nested_webpack_require_63866__(2651);var str2bn=__nested_webpack_require_63866__(4387);var rationalize=__nested_webpack_require_63866__(869);var div=__nested_webpack_require_63866__(8697);module.exports=makeRational;function makeRational(numer,denom){if(isRat(numer)){if(denom){return div(numer,makeRational(denom));}return[numer[0].clone(),numer[1].clone()];}var shift=0;var a,b;if(isBN(numer)){a=numer.clone();}else if(typeof numer==='string'){a=str2bn(numer);}else if(numer===0){return[num2bn(0),num2bn(1)];}else if(numer===Math.floor(numer)){a=num2bn(numer);}else{while(numer!==Math.floor(numer)){numer=numer*Math.pow(2,256);shift-=256;}a=num2bn(numer);}if(isRat(denom)){a.mul(denom[1]);b=denom[0].clone();}else if(isBN(denom)){b=denom.clone();}else if(typeof denom==='string'){b=str2bn(denom);}else if(!denom){b=num2bn(1);}else if(denom===Math.floor(denom)){b=num2bn(denom);}else{while(denom!==Math.floor(denom)){denom=denom*Math.pow(2,256);shift+=256;}b=num2bn(denom);}if(shift>0){a=a.ushln(shift);}else if(shift<0){b=b.ushln(-shift);}return rationalize(a,b);}/***/},/***/6330:/***/function(module,__unused_webpack_exports,__nested_webpack_require_65061__){"use strict";var isBN=__nested_webpack_require_65061__(1533);module.exports=isRat;function isRat(x){return Array.isArray(x)&&x.length===2&&isBN(x[0])&&isBN(x[1]);}/***/},/***/5716:/***/function(module,__unused_webpack_exports,__nested_webpack_require_65295__){"use strict";var BN=__nested_webpack_require_65295__(6859);module.exports=sign;function sign(x){return x.cmp(new BN(0));}/***/},/***/1369:/***/function(module,__unused_webpack_exports,__nested_webpack_require_65487__){"use strict";var sign=__nested_webpack_require_65487__(5716);module.exports=bn2num;//TODO: Make this better
function bn2num(b){var l=b.length;var words=b.words;var out=0;if(l===1){out=words[0];}else if(l===2){out=words[0]+words[1]*0x4000000;}else{for(var i=0;i20){return 52;}return h+32;}/***/},/***/1533:/***/function(module,__unused_webpack_exports,__nested_webpack_require_66252__){"use strict";var BN=__nested_webpack_require_66252__(6859);module.exports=isBN;//Test if x is a bignumber
//FIXME: obviously this is the wrong way to do it
function isBN(x){return x&&typeof x==='object'&&Boolean(x.words);}/***/},/***/2651:/***/function(module,__unused_webpack_exports,__nested_webpack_require_66545__){"use strict";var BN=__nested_webpack_require_66545__(6859);var db=__nested_webpack_require_66545__(2361);module.exports=num2bn;function num2bn(x){var e=db.exponent(x);if(e<52){return new BN(x);}else{return new BN(x*Math.pow(2,52-e)).ushln(e-52);}}/***/},/***/869:/***/function(module,__unused_webpack_exports,__nested_webpack_require_66849__){"use strict";var num2bn=__nested_webpack_require_66849__(2651);var sign=__nested_webpack_require_66849__(5716);module.exports=rationalize;function rationalize(numer,denom){var snumer=sign(numer);var sdenom=sign(denom);if(snumer===0){return[num2bn(0),num2bn(1)];}if(sdenom===0){return[num2bn(0),num2bn(0)];}if(sdenom<0){numer=numer.neg();denom=denom.neg();}var d=numer.gcd(denom);if(d.cmpn(1)){return[numer.div(d),denom.div(d)];}return[numer,denom];}/***/},/***/4387:/***/function(module,__unused_webpack_exports,__nested_webpack_require_67356__){"use strict";var BN=__nested_webpack_require_67356__(6859);module.exports=str2BN;function str2BN(x){return new BN(x);}/***/},/***/6504:/***/function(module,__unused_webpack_exports,__nested_webpack_require_67545__){"use strict";var rationalize=__nested_webpack_require_67545__(869);module.exports=mul;function mul(a,b){return rationalize(a[0].mul(b[0]),a[1].mul(b[1]));}/***/},/***/7721:/***/function(module,__unused_webpack_exports,__nested_webpack_require_67771__){"use strict";var bnsign=__nested_webpack_require_67771__(5716);module.exports=sign;function sign(x){return bnsign(x[0])*bnsign(x[1]);}/***/},/***/5572:/***/function(module,__unused_webpack_exports,__nested_webpack_require_67976__){"use strict";var rationalize=__nested_webpack_require_67976__(869);module.exports=sub;function sub(a,b){return rationalize(a[0].mul(b[1]).sub(a[1].mul(b[0])),a[1].mul(b[1]));}/***/},/***/946:/***/function(module,__unused_webpack_exports,__nested_webpack_require_68221__){"use strict";var bn2num=__nested_webpack_require_68221__(1369);var ctz=__nested_webpack_require_68221__(4025);module.exports=roundRat;// Round a rational to the closest float
function roundRat(f){var a=f[0];var b=f[1];if(a.cmpn(0)===0){return 0;}var h=a.abs().divmod(b.abs());var iv=h.div;var x=bn2num(iv);var ir=h.mod;var sgn=a.negative!==b.negative?-1:1;if(ir.cmpn(0)===0){return sgn*x;}if(x){var s=ctz(x)+4;var y=bn2num(ir.ushln(s).divRound(b));return sgn*(x+y*Math.pow(2,-s));}else{var ybits=b.bitLength()-ir.bitLength()+53;var y=bn2num(ir.ushln(ybits).divRound(b));if(ybits<1023){return sgn*y*Math.pow(2,-ybits);}y*=Math.pow(2,-1023);return sgn*y*Math.pow(2,1023-ybits);}}/***/},/***/2478:/***/function(module){"use strict";// (a, y, c, l, h) = (array, y[, cmp, lo, hi])
function ge(a,y,c,l,h){var i=h+1;while(l<=h){var m=l+h>>>1,x=a[m];var p=c!==undefined?c(x,y):x-y;if(p>=0){i=m;h=m-1;}else{l=m+1;}}return i;};function gt(a,y,c,l,h){var i=h+1;while(l<=h){var m=l+h>>>1,x=a[m];var p=c!==undefined?c(x,y):x-y;if(p>0){i=m;h=m-1;}else{l=m+1;}}return i;};function lt(a,y,c,l,h){var i=l-1;while(l<=h){var m=l+h>>>1,x=a[m];var p=c!==undefined?c(x,y):x-y;if(p<0){i=m;l=m+1;}else{h=m-1;}}return i;};function le(a,y,c,l,h){var i=l-1;while(l<=h){var m=l+h>>>1,x=a[m];var p=c!==undefined?c(x,y):x-y;if(p<=0){i=m;l=m+1;}else{h=m-1;}}return i;};function eq(a,y,c,l,h){while(l<=h){var m=l+h>>>1,x=a[m];var p=c!==undefined?c(x,y):x-y;if(p===0){return m;}if(p<=0){l=m+1;}else{h=m-1;}}return-1;};function norm(a,y,c,l,h,f){if(typeof c==='function'){return f(a,y,c,l===undefined?0:l|0,h===undefined?a.length-1:h|0);}return f(a,y,undefined,c===undefined?0:c|0,l===undefined?a.length-1:l|0);}module.exports={ge:function(a,y,c,l,h){return norm(a,y,c,l,h,ge);},gt:function(a,y,c,l,h){return norm(a,y,c,l,h,gt);},lt:function(a,y,c,l,h){return norm(a,y,c,l,h,lt);},le:function(a,y,c,l,h){return norm(a,y,c,l,h,le);},eq:function(a,y,c,l,h){return norm(a,y,c,l,h,eq);}};/***/},/***/8828:/***/function(__unused_webpack_module,exports){"use strict";/**
* Bit twiddling hacks for JavaScript.
*
* Author: Mikola Lysenko
*
* Ported from Stanford bit twiddling hack library:
* http://graphics.stanford.edu/~seander/bithacks.html
*/"use restrict";//Number of bits in an integer
var INT_BITS=32;//Constants
exports.INT_BITS=INT_BITS;exports.INT_MAX=0x7fffffff;exports.INT_MIN=-1<0)-(v<0);};//Computes absolute value of integer
exports.abs=function(v){var mask=v>>INT_BITS-1;return(v^mask)-mask;};//Computes minimum of integers x and y
exports.min=function(x,y){return y^(x^y)&-(x0xFFFF)<<4;v>>>=r;shift=(v>0xFF)<<3;v>>>=shift;r|=shift;shift=(v>0xF)<<2;v>>>=shift;r|=shift;shift=(v>0x3)<<1;v>>>=shift;r|=shift;return r|v>>1;};//Computes log base 10 of v
exports.log10=function(v){return v>=1000000000?9:v>=100000000?8:v>=10000000?7:v>=1000000?6:v>=100000?5:v>=10000?4:v>=1000?3:v>=100?2:v>=10?1:0;};//Counts number of bits
exports.popCount=function(v){v=v-(v>>>1&0x55555555);v=(v&0x33333333)+(v>>>2&0x33333333);return(v+(v>>>4)&0xF0F0F0F)*0x1010101>>>24;};//Counts number of trailing zeros
function countTrailingZeros(v){var c=32;v&=-v;if(v)c--;if(v&0x0000FFFF)c-=16;if(v&0x00FF00FF)c-=8;if(v&0x0F0F0F0F)c-=4;if(v&0x33333333)c-=2;if(v&0x55555555)c-=1;return c;}exports.countTrailingZeros=countTrailingZeros;//Rounds to next power of 2
exports.nextPow2=function(v){v+=v===0;--v;v|=v>>>1;v|=v>>>2;v|=v>>>4;v|=v>>>8;v|=v>>>16;return v+1;};//Rounds down to previous power of 2
exports.prevPow2=function(v){v|=v>>>1;v|=v>>>2;v|=v>>>4;v|=v>>>8;v|=v>>>16;return v-(v>>>1);};//Computes parity of word
exports.parity=function(v){v^=v>>>16;v^=v>>>8;v^=v>>>4;v&=0xf;return 0x6996>>>v&1;};var REVERSE_TABLE=new Array(256);(function(tab){for(var i=0;i<256;++i){var v=i,r=i,s=7;for(v>>>=1;v;v>>>=1){r<<=1;r|=v&1;--s;}tab[i]=r<>>8&0xff]<<16|REVERSE_TABLE[v>>>16&0xff]<<8|REVERSE_TABLE[v>>>24&0xff];};//Interleave bits of 2 coordinates with 16 bits. Useful for fast quadtree codes
exports.interleave2=function(x,y){x&=0xFFFF;x=(x|x<<8)&0x00FF00FF;x=(x|x<<4)&0x0F0F0F0F;x=(x|x<<2)&0x33333333;x=(x|x<<1)&0x55555555;y&=0xFFFF;y=(y|y<<8)&0x00FF00FF;y=(y|y<<4)&0x0F0F0F0F;y=(y|y<<2)&0x33333333;y=(y|y<<1)&0x55555555;return x|y<<1;};//Extracts the nth interleaved component
exports.deinterleave2=function(v,n){v=v>>>n&0x55555555;v=(v|v>>>1)&0x33333333;v=(v|v>>>2)&0x0F0F0F0F;v=(v|v>>>4)&0x00FF00FF;v=(v|v>>>16)&0x000FFFF;return v<<16>>16;};//Interleave bits of 3 coordinates, each with 10 bits. Useful for fast octree codes
exports.interleave3=function(x,y,z){x&=0x3FF;x=(x|x<<16)&4278190335;x=(x|x<<8)&251719695;x=(x|x<<4)&3272356035;x=(x|x<<2)&1227133513;y&=0x3FF;y=(y|y<<16)&4278190335;y=(y|y<<8)&251719695;y=(y|y<<4)&3272356035;y=(y|y<<2)&1227133513;x|=y<<1;z&=0x3FF;z=(z|z<<16)&4278190335;z=(z|z<<8)&251719695;z=(z|z<<4)&3272356035;z=(z|z<<2)&1227133513;return x|z<<2;};//Extracts nth interleaved component of a 3-tuple
exports.deinterleave3=function(v,n){v=v>>>n&1227133513;v=(v|v>>>2)&3272356035;v=(v|v>>>4)&251719695;v=(v|v>>>8)&4278190335;v=(v|v>>>16)&0x3FF;return v<<22>>22;};//Computes next combination in colexicographic order (this is mistakenly called nextPermutation on the bit twiddling hacks page)
exports.nextCombination=function(v){var t=v|v-1;return t+1|(~t&-~t)-1>>>countTrailingZeros(v)+1;};/***/},/***/6859:/***/function(module,__unused_webpack_exports,__nested_webpack_require_74030__){/* module decorator */module=__nested_webpack_require_74030__.nmd(module);(function(module,exports){'use strict';// Utils
function assert(val,msg){if(!val)throw new Error(msg||'Assertion failed');}// Could use `inherits` module, but don't want to move from single file
// architecture yet.
function inherits(ctor,superCtor){ctor.super_=superCtor;var TempCtor=function(){};TempCtor.prototype=superCtor.prototype;ctor.prototype=new TempCtor();ctor.prototype.constructor=ctor;}// BN
function BN(number,base,endian){if(BN.isBN(number)){return number;}this.negative=0;this.words=null;this.length=0;// Reduction context
this.red=null;if(number!==null){if(base==='le'||base==='be'){endian=base;base=10;}this._init(number||0,base||10,endian||'be');}}if(typeof module==='object'){module.exports=BN;}else{exports.BN=BN;}BN.BN=BN;BN.wordSize=26;var Buffer;try{if(typeof window!=='undefined'&&typeof window.Buffer!=='undefined'){Buffer=window.Buffer;}else{Buffer=__nested_webpack_require_74030__(7790).Buffer;}}catch(e){}BN.isBN=function isBN(num){if(num instanceof BN){return true;}return num!==null&&typeof num==='object'&&num.constructor.wordSize===BN.wordSize&&Array.isArray(num.words);};BN.max=function max(left,right){if(left.cmp(right)>0)return left;return right;};BN.min=function min(left,right){if(left.cmp(right)<0)return left;return right;};BN.prototype._init=function init(number,base,endian){if(typeof number==='number'){return this._initNumber(number,base,endian);}if(typeof number==='object'){return this._initArray(number,base,endian);}if(base==='hex'){base=16;}assert(base===(base|0)&&base>=2&&base<=36);number=number.toString().replace(/\s+/g,'');var start=0;if(number[0]==='-'){start++;this.negative=1;}if(start=0;i-=3){w=number[i]|number[i-1]<<8|number[i-2]<<16;this.words[j]|=w<>>26-off&0x3ffffff;off+=24;if(off>=26){off-=26;j++;}}}else if(endian==='le'){for(i=0,j=0;i>>26-off&0x3ffffff;off+=24;if(off>=26){off-=26;j++;}}}return this.strip();};function parseHex4Bits(string,index){var c=string.charCodeAt(index);// 'A' - 'F'
if(c>=65&&c<=70){return c-55;// 'a' - 'f'
}else if(c>=97&&c<=102){return c-87;// '0' - '9'
}else{return c-48&0xf;}}function parseHexByte(string,lowerBound,index){var r=parseHex4Bits(string,index);if(index-1>=lowerBound){r|=parseHex4Bits(string,index-1)<<4;}return r;}BN.prototype._parseHex=function _parseHex(number,start,endian){// Create possibly bigger array to ensure that it fits the number
this.length=Math.ceil((number.length-start)/6);this.words=new Array(this.length);for(var i=0;i=start;i-=2){w=parseHexByte(number,start,i)<=18){off-=18;j+=1;this.words[j]|=w>>>26;}else{off+=8;}}}else{var parseLength=number.length-start;for(i=parseLength%2===0?start+1:start;i=18){off-=18;j+=1;this.words[j]|=w>>>26;}else{off+=8;}}}this.strip();};function parseBase(str,start,end,mul){var r=0;var len=Math.min(str.length,end);for(var i=start;i=49){r+=c-49+0xa;// 'A'
}else if(c>=17){r+=c-17+0xa;// '0' - '9'
}else{r+=c;}}return r;}BN.prototype._parseBase=function _parseBase(number,base,start){// Initialize as zero
this.words=[0];this.length=1;// Find length of limb in base
for(var limbLen=0,limbPow=1;limbPow<=0x3ffffff;limbPow*=base){limbLen++;}limbLen--;limbPow=limbPow/base|0;var total=number.length-start;var mod=total%limbLen;var end=Math.min(total,total-mod)+start;var word=0;for(var i=start;i1&&this.words[this.length-1]===0){this.length--;}return this._normSign();};BN.prototype._normSign=function _normSign(){// -0 = 0
if(this.length===1&&this.words[0]===0){this.negative=0;}return this;};BN.prototype.inspect=function inspect(){return(this.red?'';};/*
var zeros = [];
var groupSizes = [];
var groupBases = [];
var s = '';
var i = -1;
while (++i < BN.wordSize) {
zeros[i] = s;
s += '0';
}
groupSizes[0] = 0;
groupSizes[1] = 0;
groupBases[0] = 0;
groupBases[1] = 0;
var base = 2 - 1;
while (++base < 36 + 1) {
var groupSize = 0;
var groupBase = 1;
while (groupBase < (1 << BN.wordSize) / base) {
groupBase *= base;
groupSize += 1;
}
groupSizes[base] = groupSize;
groupBases[base] = groupBase;
}
*/var zeros=['','0','00','000','0000','00000','000000','0000000','00000000','000000000','0000000000','00000000000','000000000000','0000000000000','00000000000000','000000000000000','0000000000000000','00000000000000000','000000000000000000','0000000000000000000','00000000000000000000','000000000000000000000','0000000000000000000000','00000000000000000000000','000000000000000000000000','0000000000000000000000000'];var groupSizes=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5];var groupBases=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,10000000,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64000000,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,24300000,28629151,33554432,39135393,45435424,52521875,60466176];BN.prototype.toString=function toString(base,padding){base=base||10;padding=padding|0||1;var out;if(base===16||base==='hex'){out='';var off=0;var carry=0;for(var i=0;i>>24-off&0xffffff;if(carry!==0||i!==this.length-1){out=zeros[6-word.length]+word+out;}else{out=word+out;}off+=2;if(off>=26){off-=26;i--;}}if(carry!==0){out=carry.toString(16)+out;}while(out.length%padding!==0){out='0'+out;}if(this.negative!==0){out='-'+out;}return out;}if(base===(base|0)&&base>=2&&base<=36){// var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));
var groupSize=groupSizes[base];// var groupBase = Math.pow(base, groupSize);
var groupBase=groupBases[base];out='';var c=this.clone();c.negative=0;while(!c.isZero()){var r=c.modn(groupBase).toString(base);c=c.idivn(groupBase);if(!c.isZero()){out=zeros[groupSize-r.length]+r+out;}else{out=r+out;}}if(this.isZero()){out='0'+out;}while(out.length%padding!==0){out='0'+out;}if(this.negative!==0){out='-'+out;}return out;}assert(false,'Base should be between 2 and 36');};BN.prototype.toNumber=function toNumber(){var ret=this.words[0];if(this.length===2){ret+=this.words[1]*0x4000000;}else if(this.length===3&&this.words[2]===0x01){// NOTE: at this stage it is known that the top bit is set
ret+=0x10000000000000+this.words[1]*0x4000000;}else if(this.length>2){assert(false,'Number can only safely store up to 53 bits');}return this.negative!==0?-ret:ret;};BN.prototype.toJSON=function toJSON(){return this.toString(16);};BN.prototype.toBuffer=function toBuffer(endian,length){assert(typeof Buffer!=='undefined');return this.toArrayLike(Buffer,endian,length);};BN.prototype.toArray=function toArray(endian,length){return this.toArrayLike(Array,endian,length);};BN.prototype.toArrayLike=function toArrayLike(ArrayType,endian,length){var byteLength=this.byteLength();var reqLength=length||Math.max(1,byteLength);assert(byteLength<=reqLength,'byte array longer than desired length');assert(reqLength>0,'Requested array length <= 0');this.strip();var littleEndian=endian==='le';var res=new ArrayType(reqLength);var b,i;var q=this.clone();if(!littleEndian){// Assume big-endian
for(i=0;i=0x1000){r+=13;t>>>=13;}if(t>=0x40){r+=7;t>>>=7;}if(t>=0x8){r+=4;t>>>=4;}if(t>=0x02){r+=2;t>>>=2;}return r+t;};}BN.prototype._zeroBits=function _zeroBits(w){// Short-cut
if(w===0)return 26;var t=w;var r=0;if((t&0x1fff)===0){r+=13;t>>>=13;}if((t&0x7f)===0){r+=7;t>>>=7;}if((t&0xf)===0){r+=4;t>>>=4;}if((t&0x3)===0){r+=2;t>>>=2;}if((t&0x1)===0){r++;}return r;};// Return number of used bits in a BN
BN.prototype.bitLength=function bitLength(){var w=this.words[this.length-1];var hi=this._countBits(w);return(this.length-1)*26+hi;};function toBitArray(num){var w=new Array(num.bitLength());for(var bit=0;bit>>wbit;}return w;}// Number of trailing zero bits
BN.prototype.zeroBits=function zeroBits(){if(this.isZero())return 0;var r=0;for(var i=0;inum.length)return this.clone().ior(num);return num.clone().ior(this);};BN.prototype.uor=function uor(num){if(this.length>num.length)return this.clone().iuor(num);return num.clone().iuor(this);};// And `num` with `this` in-place
BN.prototype.iuand=function iuand(num){// b = min-length(num, this)
var b;if(this.length>num.length){b=num;}else{b=this;}for(var i=0;inum.length)return this.clone().iand(num);return num.clone().iand(this);};BN.prototype.uand=function uand(num){if(this.length>num.length)return this.clone().iuand(num);return num.clone().iuand(this);};// Xor `num` with `this` in-place
BN.prototype.iuxor=function iuxor(num){// a.length > b.length
var a;var b;if(this.length>num.length){a=this;b=num;}else{a=num;b=this;}for(var i=0;inum.length)return this.clone().ixor(num);return num.clone().ixor(this);};BN.prototype.uxor=function uxor(num){if(this.length>num.length)return this.clone().iuxor(num);return num.clone().iuxor(this);};// Not ``this`` with ``width`` bitwidth
BN.prototype.inotn=function inotn(width){assert(typeof width==='number'&&width>=0);var bytesNeeded=Math.ceil(width/26)|0;var bitsLeft=width%26;// Extend the buffer with leading zeroes
this._expand(bytesNeeded);if(bitsLeft>0){bytesNeeded--;}// Handle complete words
for(var i=0;i0){this.words[i]=~this.words[i]&0x3ffffff>>26-bitsLeft;}// And remove leading zeroes
return this.strip();};BN.prototype.notn=function notn(width){return this.clone().inotn(width);};// Set `bit` of `this`
BN.prototype.setn=function setn(bit,val){assert(typeof bit==='number'&&bit>=0);var off=bit/26|0;var wbit=bit%26;this._expand(off+1);if(val){this.words[off]=this.words[off]|1< b.length
var a,b;if(this.length>num.length){a=this;b=num;}else{a=num;b=this;}var carry=0;for(var i=0;i>>26;}for(;carry!==0&&i>>26;}this.length=a.length;if(carry!==0){this.words[this.length]=carry;this.length++;// Copy the rest of the words
}else if(a!==this){for(;inum.length)return this.clone().iadd(num);return num.clone().iadd(this);};// Subtract `num` from `this` in-place
BN.prototype.isub=function isub(num){// this - (-num) = this + num
if(num.negative!==0){num.negative=0;var r=this.iadd(num);num.negative=1;return r._normSign();// -this - num = -(this + num)
}else if(this.negative!==0){this.negative=0;this.iadd(num);this.negative=1;return this._normSign();}// At this point both numbers are positive
var cmp=this.cmp(num);// Optimization - zeroify
if(cmp===0){this.negative=0;this.length=1;this.words[0]=0;return this;}// a > b
var a,b;if(cmp>0){a=this;b=num;}else{a=num;b=this;}var carry=0;for(var i=0;i>26;this.words[i]=r&0x3ffffff;}for(;carry!==0&&i>26;this.words[i]=r&0x3ffffff;}// Copy rest of the words
if(carry===0&&i= 0x3ffffff
var ncarry=carry>>>26;var rword=carry&0x3ffffff;var maxJ=Math.min(k,num.length-1);for(var j=Math.max(0,k-self.length+1);j<=maxJ;j++){var i=k-j|0;a=self.words[i]|0;b=num.words[j]|0;r=a*b+rword;ncarry+=r/0x4000000|0;rword=r&0x3ffffff;}out.words[k]=rword|0;carry=ncarry|0;}if(carry!==0){out.words[k]=carry|0;}else{out.length--;}return out.strip();}// TODO(indutny): it may be reasonable to omit it for users who don't need
// to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit
// multiplication (like elliptic secp256k1).
var comb10MulTo=function comb10MulTo(self,num,out){var a=self.words;var b=num.words;var o=out.words;var c=0;var lo;var mid;var hi;var a0=a[0]|0;var al0=a0&0x1fff;var ah0=a0>>>13;var a1=a[1]|0;var al1=a1&0x1fff;var ah1=a1>>>13;var a2=a[2]|0;var al2=a2&0x1fff;var ah2=a2>>>13;var a3=a[3]|0;var al3=a3&0x1fff;var ah3=a3>>>13;var a4=a[4]|0;var al4=a4&0x1fff;var ah4=a4>>>13;var a5=a[5]|0;var al5=a5&0x1fff;var ah5=a5>>>13;var a6=a[6]|0;var al6=a6&0x1fff;var ah6=a6>>>13;var a7=a[7]|0;var al7=a7&0x1fff;var ah7=a7>>>13;var a8=a[8]|0;var al8=a8&0x1fff;var ah8=a8>>>13;var a9=a[9]|0;var al9=a9&0x1fff;var ah9=a9>>>13;var b0=b[0]|0;var bl0=b0&0x1fff;var bh0=b0>>>13;var b1=b[1]|0;var bl1=b1&0x1fff;var bh1=b1>>>13;var b2=b[2]|0;var bl2=b2&0x1fff;var bh2=b2>>>13;var b3=b[3]|0;var bl3=b3&0x1fff;var bh3=b3>>>13;var b4=b[4]|0;var bl4=b4&0x1fff;var bh4=b4>>>13;var b5=b[5]|0;var bl5=b5&0x1fff;var bh5=b5>>>13;var b6=b[6]|0;var bl6=b6&0x1fff;var bh6=b6>>>13;var b7=b[7]|0;var bl7=b7&0x1fff;var bh7=b7>>>13;var b8=b[8]|0;var bl8=b8&0x1fff;var bh8=b8>>>13;var b9=b[9]|0;var bl9=b9&0x1fff;var bh9=b9>>>13;out.negative=self.negative^num.negative;out.length=19;/* k = 0 */lo=Math.imul(al0,bl0);mid=Math.imul(al0,bh0);mid=mid+Math.imul(ah0,bl0)|0;hi=Math.imul(ah0,bh0);var w0=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w0>>>26)|0;w0&=0x3ffffff;/* k = 1 */lo=Math.imul(al1,bl0);mid=Math.imul(al1,bh0);mid=mid+Math.imul(ah1,bl0)|0;hi=Math.imul(ah1,bh0);lo=lo+Math.imul(al0,bl1)|0;mid=mid+Math.imul(al0,bh1)|0;mid=mid+Math.imul(ah0,bl1)|0;hi=hi+Math.imul(ah0,bh1)|0;var w1=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w1>>>26)|0;w1&=0x3ffffff;/* k = 2 */lo=Math.imul(al2,bl0);mid=Math.imul(al2,bh0);mid=mid+Math.imul(ah2,bl0)|0;hi=Math.imul(ah2,bh0);lo=lo+Math.imul(al1,bl1)|0;mid=mid+Math.imul(al1,bh1)|0;mid=mid+Math.imul(ah1,bl1)|0;hi=hi+Math.imul(ah1,bh1)|0;lo=lo+Math.imul(al0,bl2)|0;mid=mid+Math.imul(al0,bh2)|0;mid=mid+Math.imul(ah0,bl2)|0;hi=hi+Math.imul(ah0,bh2)|0;var w2=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w2>>>26)|0;w2&=0x3ffffff;/* k = 3 */lo=Math.imul(al3,bl0);mid=Math.imul(al3,bh0);mid=mid+Math.imul(ah3,bl0)|0;hi=Math.imul(ah3,bh0);lo=lo+Math.imul(al2,bl1)|0;mid=mid+Math.imul(al2,bh1)|0;mid=mid+Math.imul(ah2,bl1)|0;hi=hi+Math.imul(ah2,bh1)|0;lo=lo+Math.imul(al1,bl2)|0;mid=mid+Math.imul(al1,bh2)|0;mid=mid+Math.imul(ah1,bl2)|0;hi=hi+Math.imul(ah1,bh2)|0;lo=lo+Math.imul(al0,bl3)|0;mid=mid+Math.imul(al0,bh3)|0;mid=mid+Math.imul(ah0,bl3)|0;hi=hi+Math.imul(ah0,bh3)|0;var w3=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w3>>>26)|0;w3&=0x3ffffff;/* k = 4 */lo=Math.imul(al4,bl0);mid=Math.imul(al4,bh0);mid=mid+Math.imul(ah4,bl0)|0;hi=Math.imul(ah4,bh0);lo=lo+Math.imul(al3,bl1)|0;mid=mid+Math.imul(al3,bh1)|0;mid=mid+Math.imul(ah3,bl1)|0;hi=hi+Math.imul(ah3,bh1)|0;lo=lo+Math.imul(al2,bl2)|0;mid=mid+Math.imul(al2,bh2)|0;mid=mid+Math.imul(ah2,bl2)|0;hi=hi+Math.imul(ah2,bh2)|0;lo=lo+Math.imul(al1,bl3)|0;mid=mid+Math.imul(al1,bh3)|0;mid=mid+Math.imul(ah1,bl3)|0;hi=hi+Math.imul(ah1,bh3)|0;lo=lo+Math.imul(al0,bl4)|0;mid=mid+Math.imul(al0,bh4)|0;mid=mid+Math.imul(ah0,bl4)|0;hi=hi+Math.imul(ah0,bh4)|0;var w4=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w4>>>26)|0;w4&=0x3ffffff;/* k = 5 */lo=Math.imul(al5,bl0);mid=Math.imul(al5,bh0);mid=mid+Math.imul(ah5,bl0)|0;hi=Math.imul(ah5,bh0);lo=lo+Math.imul(al4,bl1)|0;mid=mid+Math.imul(al4,bh1)|0;mid=mid+Math.imul(ah4,bl1)|0;hi=hi+Math.imul(ah4,bh1)|0;lo=lo+Math.imul(al3,bl2)|0;mid=mid+Math.imul(al3,bh2)|0;mid=mid+Math.imul(ah3,bl2)|0;hi=hi+Math.imul(ah3,bh2)|0;lo=lo+Math.imul(al2,bl3)|0;mid=mid+Math.imul(al2,bh3)|0;mid=mid+Math.imul(ah2,bl3)|0;hi=hi+Math.imul(ah2,bh3)|0;lo=lo+Math.imul(al1,bl4)|0;mid=mid+Math.imul(al1,bh4)|0;mid=mid+Math.imul(ah1,bl4)|0;hi=hi+Math.imul(ah1,bh4)|0;lo=lo+Math.imul(al0,bl5)|0;mid=mid+Math.imul(al0,bh5)|0;mid=mid+Math.imul(ah0,bl5)|0;hi=hi+Math.imul(ah0,bh5)|0;var w5=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w5>>>26)|0;w5&=0x3ffffff;/* k = 6 */lo=Math.imul(al6,bl0);mid=Math.imul(al6,bh0);mid=mid+Math.imul(ah6,bl0)|0;hi=Math.imul(ah6,bh0);lo=lo+Math.imul(al5,bl1)|0;mid=mid+Math.imul(al5,bh1)|0;mid=mid+Math.imul(ah5,bl1)|0;hi=hi+Math.imul(ah5,bh1)|0;lo=lo+Math.imul(al4,bl2)|0;mid=mid+Math.imul(al4,bh2)|0;mid=mid+Math.imul(ah4,bl2)|0;hi=hi+Math.imul(ah4,bh2)|0;lo=lo+Math.imul(al3,bl3)|0;mid=mid+Math.imul(al3,bh3)|0;mid=mid+Math.imul(ah3,bl3)|0;hi=hi+Math.imul(ah3,bh3)|0;lo=lo+Math.imul(al2,bl4)|0;mid=mid+Math.imul(al2,bh4)|0;mid=mid+Math.imul(ah2,bl4)|0;hi=hi+Math.imul(ah2,bh4)|0;lo=lo+Math.imul(al1,bl5)|0;mid=mid+Math.imul(al1,bh5)|0;mid=mid+Math.imul(ah1,bl5)|0;hi=hi+Math.imul(ah1,bh5)|0;lo=lo+Math.imul(al0,bl6)|0;mid=mid+Math.imul(al0,bh6)|0;mid=mid+Math.imul(ah0,bl6)|0;hi=hi+Math.imul(ah0,bh6)|0;var w6=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w6>>>26)|0;w6&=0x3ffffff;/* k = 7 */lo=Math.imul(al7,bl0);mid=Math.imul(al7,bh0);mid=mid+Math.imul(ah7,bl0)|0;hi=Math.imul(ah7,bh0);lo=lo+Math.imul(al6,bl1)|0;mid=mid+Math.imul(al6,bh1)|0;mid=mid+Math.imul(ah6,bl1)|0;hi=hi+Math.imul(ah6,bh1)|0;lo=lo+Math.imul(al5,bl2)|0;mid=mid+Math.imul(al5,bh2)|0;mid=mid+Math.imul(ah5,bl2)|0;hi=hi+Math.imul(ah5,bh2)|0;lo=lo+Math.imul(al4,bl3)|0;mid=mid+Math.imul(al4,bh3)|0;mid=mid+Math.imul(ah4,bl3)|0;hi=hi+Math.imul(ah4,bh3)|0;lo=lo+Math.imul(al3,bl4)|0;mid=mid+Math.imul(al3,bh4)|0;mid=mid+Math.imul(ah3,bl4)|0;hi=hi+Math.imul(ah3,bh4)|0;lo=lo+Math.imul(al2,bl5)|0;mid=mid+Math.imul(al2,bh5)|0;mid=mid+Math.imul(ah2,bl5)|0;hi=hi+Math.imul(ah2,bh5)|0;lo=lo+Math.imul(al1,bl6)|0;mid=mid+Math.imul(al1,bh6)|0;mid=mid+Math.imul(ah1,bl6)|0;hi=hi+Math.imul(ah1,bh6)|0;lo=lo+Math.imul(al0,bl7)|0;mid=mid+Math.imul(al0,bh7)|0;mid=mid+Math.imul(ah0,bl7)|0;hi=hi+Math.imul(ah0,bh7)|0;var w7=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w7>>>26)|0;w7&=0x3ffffff;/* k = 8 */lo=Math.imul(al8,bl0);mid=Math.imul(al8,bh0);mid=mid+Math.imul(ah8,bl0)|0;hi=Math.imul(ah8,bh0);lo=lo+Math.imul(al7,bl1)|0;mid=mid+Math.imul(al7,bh1)|0;mid=mid+Math.imul(ah7,bl1)|0;hi=hi+Math.imul(ah7,bh1)|0;lo=lo+Math.imul(al6,bl2)|0;mid=mid+Math.imul(al6,bh2)|0;mid=mid+Math.imul(ah6,bl2)|0;hi=hi+Math.imul(ah6,bh2)|0;lo=lo+Math.imul(al5,bl3)|0;mid=mid+Math.imul(al5,bh3)|0;mid=mid+Math.imul(ah5,bl3)|0;hi=hi+Math.imul(ah5,bh3)|0;lo=lo+Math.imul(al4,bl4)|0;mid=mid+Math.imul(al4,bh4)|0;mid=mid+Math.imul(ah4,bl4)|0;hi=hi+Math.imul(ah4,bh4)|0;lo=lo+Math.imul(al3,bl5)|0;mid=mid+Math.imul(al3,bh5)|0;mid=mid+Math.imul(ah3,bl5)|0;hi=hi+Math.imul(ah3,bh5)|0;lo=lo+Math.imul(al2,bl6)|0;mid=mid+Math.imul(al2,bh6)|0;mid=mid+Math.imul(ah2,bl6)|0;hi=hi+Math.imul(ah2,bh6)|0;lo=lo+Math.imul(al1,bl7)|0;mid=mid+Math.imul(al1,bh7)|0;mid=mid+Math.imul(ah1,bl7)|0;hi=hi+Math.imul(ah1,bh7)|0;lo=lo+Math.imul(al0,bl8)|0;mid=mid+Math.imul(al0,bh8)|0;mid=mid+Math.imul(ah0,bl8)|0;hi=hi+Math.imul(ah0,bh8)|0;var w8=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w8>>>26)|0;w8&=0x3ffffff;/* k = 9 */lo=Math.imul(al9,bl0);mid=Math.imul(al9,bh0);mid=mid+Math.imul(ah9,bl0)|0;hi=Math.imul(ah9,bh0);lo=lo+Math.imul(al8,bl1)|0;mid=mid+Math.imul(al8,bh1)|0;mid=mid+Math.imul(ah8,bl1)|0;hi=hi+Math.imul(ah8,bh1)|0;lo=lo+Math.imul(al7,bl2)|0;mid=mid+Math.imul(al7,bh2)|0;mid=mid+Math.imul(ah7,bl2)|0;hi=hi+Math.imul(ah7,bh2)|0;lo=lo+Math.imul(al6,bl3)|0;mid=mid+Math.imul(al6,bh3)|0;mid=mid+Math.imul(ah6,bl3)|0;hi=hi+Math.imul(ah6,bh3)|0;lo=lo+Math.imul(al5,bl4)|0;mid=mid+Math.imul(al5,bh4)|0;mid=mid+Math.imul(ah5,bl4)|0;hi=hi+Math.imul(ah5,bh4)|0;lo=lo+Math.imul(al4,bl5)|0;mid=mid+Math.imul(al4,bh5)|0;mid=mid+Math.imul(ah4,bl5)|0;hi=hi+Math.imul(ah4,bh5)|0;lo=lo+Math.imul(al3,bl6)|0;mid=mid+Math.imul(al3,bh6)|0;mid=mid+Math.imul(ah3,bl6)|0;hi=hi+Math.imul(ah3,bh6)|0;lo=lo+Math.imul(al2,bl7)|0;mid=mid+Math.imul(al2,bh7)|0;mid=mid+Math.imul(ah2,bl7)|0;hi=hi+Math.imul(ah2,bh7)|0;lo=lo+Math.imul(al1,bl8)|0;mid=mid+Math.imul(al1,bh8)|0;mid=mid+Math.imul(ah1,bl8)|0;hi=hi+Math.imul(ah1,bh8)|0;lo=lo+Math.imul(al0,bl9)|0;mid=mid+Math.imul(al0,bh9)|0;mid=mid+Math.imul(ah0,bl9)|0;hi=hi+Math.imul(ah0,bh9)|0;var w9=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w9>>>26)|0;w9&=0x3ffffff;/* k = 10 */lo=Math.imul(al9,bl1);mid=Math.imul(al9,bh1);mid=mid+Math.imul(ah9,bl1)|0;hi=Math.imul(ah9,bh1);lo=lo+Math.imul(al8,bl2)|0;mid=mid+Math.imul(al8,bh2)|0;mid=mid+Math.imul(ah8,bl2)|0;hi=hi+Math.imul(ah8,bh2)|0;lo=lo+Math.imul(al7,bl3)|0;mid=mid+Math.imul(al7,bh3)|0;mid=mid+Math.imul(ah7,bl3)|0;hi=hi+Math.imul(ah7,bh3)|0;lo=lo+Math.imul(al6,bl4)|0;mid=mid+Math.imul(al6,bh4)|0;mid=mid+Math.imul(ah6,bl4)|0;hi=hi+Math.imul(ah6,bh4)|0;lo=lo+Math.imul(al5,bl5)|0;mid=mid+Math.imul(al5,bh5)|0;mid=mid+Math.imul(ah5,bl5)|0;hi=hi+Math.imul(ah5,bh5)|0;lo=lo+Math.imul(al4,bl6)|0;mid=mid+Math.imul(al4,bh6)|0;mid=mid+Math.imul(ah4,bl6)|0;hi=hi+Math.imul(ah4,bh6)|0;lo=lo+Math.imul(al3,bl7)|0;mid=mid+Math.imul(al3,bh7)|0;mid=mid+Math.imul(ah3,bl7)|0;hi=hi+Math.imul(ah3,bh7)|0;lo=lo+Math.imul(al2,bl8)|0;mid=mid+Math.imul(al2,bh8)|0;mid=mid+Math.imul(ah2,bl8)|0;hi=hi+Math.imul(ah2,bh8)|0;lo=lo+Math.imul(al1,bl9)|0;mid=mid+Math.imul(al1,bh9)|0;mid=mid+Math.imul(ah1,bl9)|0;hi=hi+Math.imul(ah1,bh9)|0;var w10=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w10>>>26)|0;w10&=0x3ffffff;/* k = 11 */lo=Math.imul(al9,bl2);mid=Math.imul(al9,bh2);mid=mid+Math.imul(ah9,bl2)|0;hi=Math.imul(ah9,bh2);lo=lo+Math.imul(al8,bl3)|0;mid=mid+Math.imul(al8,bh3)|0;mid=mid+Math.imul(ah8,bl3)|0;hi=hi+Math.imul(ah8,bh3)|0;lo=lo+Math.imul(al7,bl4)|0;mid=mid+Math.imul(al7,bh4)|0;mid=mid+Math.imul(ah7,bl4)|0;hi=hi+Math.imul(ah7,bh4)|0;lo=lo+Math.imul(al6,bl5)|0;mid=mid+Math.imul(al6,bh5)|0;mid=mid+Math.imul(ah6,bl5)|0;hi=hi+Math.imul(ah6,bh5)|0;lo=lo+Math.imul(al5,bl6)|0;mid=mid+Math.imul(al5,bh6)|0;mid=mid+Math.imul(ah5,bl6)|0;hi=hi+Math.imul(ah5,bh6)|0;lo=lo+Math.imul(al4,bl7)|0;mid=mid+Math.imul(al4,bh7)|0;mid=mid+Math.imul(ah4,bl7)|0;hi=hi+Math.imul(ah4,bh7)|0;lo=lo+Math.imul(al3,bl8)|0;mid=mid+Math.imul(al3,bh8)|0;mid=mid+Math.imul(ah3,bl8)|0;hi=hi+Math.imul(ah3,bh8)|0;lo=lo+Math.imul(al2,bl9)|0;mid=mid+Math.imul(al2,bh9)|0;mid=mid+Math.imul(ah2,bl9)|0;hi=hi+Math.imul(ah2,bh9)|0;var w11=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w11>>>26)|0;w11&=0x3ffffff;/* k = 12 */lo=Math.imul(al9,bl3);mid=Math.imul(al9,bh3);mid=mid+Math.imul(ah9,bl3)|0;hi=Math.imul(ah9,bh3);lo=lo+Math.imul(al8,bl4)|0;mid=mid+Math.imul(al8,bh4)|0;mid=mid+Math.imul(ah8,bl4)|0;hi=hi+Math.imul(ah8,bh4)|0;lo=lo+Math.imul(al7,bl5)|0;mid=mid+Math.imul(al7,bh5)|0;mid=mid+Math.imul(ah7,bl5)|0;hi=hi+Math.imul(ah7,bh5)|0;lo=lo+Math.imul(al6,bl6)|0;mid=mid+Math.imul(al6,bh6)|0;mid=mid+Math.imul(ah6,bl6)|0;hi=hi+Math.imul(ah6,bh6)|0;lo=lo+Math.imul(al5,bl7)|0;mid=mid+Math.imul(al5,bh7)|0;mid=mid+Math.imul(ah5,bl7)|0;hi=hi+Math.imul(ah5,bh7)|0;lo=lo+Math.imul(al4,bl8)|0;mid=mid+Math.imul(al4,bh8)|0;mid=mid+Math.imul(ah4,bl8)|0;hi=hi+Math.imul(ah4,bh8)|0;lo=lo+Math.imul(al3,bl9)|0;mid=mid+Math.imul(al3,bh9)|0;mid=mid+Math.imul(ah3,bl9)|0;hi=hi+Math.imul(ah3,bh9)|0;var w12=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w12>>>26)|0;w12&=0x3ffffff;/* k = 13 */lo=Math.imul(al9,bl4);mid=Math.imul(al9,bh4);mid=mid+Math.imul(ah9,bl4)|0;hi=Math.imul(ah9,bh4);lo=lo+Math.imul(al8,bl5)|0;mid=mid+Math.imul(al8,bh5)|0;mid=mid+Math.imul(ah8,bl5)|0;hi=hi+Math.imul(ah8,bh5)|0;lo=lo+Math.imul(al7,bl6)|0;mid=mid+Math.imul(al7,bh6)|0;mid=mid+Math.imul(ah7,bl6)|0;hi=hi+Math.imul(ah7,bh6)|0;lo=lo+Math.imul(al6,bl7)|0;mid=mid+Math.imul(al6,bh7)|0;mid=mid+Math.imul(ah6,bl7)|0;hi=hi+Math.imul(ah6,bh7)|0;lo=lo+Math.imul(al5,bl8)|0;mid=mid+Math.imul(al5,bh8)|0;mid=mid+Math.imul(ah5,bl8)|0;hi=hi+Math.imul(ah5,bh8)|0;lo=lo+Math.imul(al4,bl9)|0;mid=mid+Math.imul(al4,bh9)|0;mid=mid+Math.imul(ah4,bl9)|0;hi=hi+Math.imul(ah4,bh9)|0;var w13=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w13>>>26)|0;w13&=0x3ffffff;/* k = 14 */lo=Math.imul(al9,bl5);mid=Math.imul(al9,bh5);mid=mid+Math.imul(ah9,bl5)|0;hi=Math.imul(ah9,bh5);lo=lo+Math.imul(al8,bl6)|0;mid=mid+Math.imul(al8,bh6)|0;mid=mid+Math.imul(ah8,bl6)|0;hi=hi+Math.imul(ah8,bh6)|0;lo=lo+Math.imul(al7,bl7)|0;mid=mid+Math.imul(al7,bh7)|0;mid=mid+Math.imul(ah7,bl7)|0;hi=hi+Math.imul(ah7,bh7)|0;lo=lo+Math.imul(al6,bl8)|0;mid=mid+Math.imul(al6,bh8)|0;mid=mid+Math.imul(ah6,bl8)|0;hi=hi+Math.imul(ah6,bh8)|0;lo=lo+Math.imul(al5,bl9)|0;mid=mid+Math.imul(al5,bh9)|0;mid=mid+Math.imul(ah5,bl9)|0;hi=hi+Math.imul(ah5,bh9)|0;var w14=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w14>>>26)|0;w14&=0x3ffffff;/* k = 15 */lo=Math.imul(al9,bl6);mid=Math.imul(al9,bh6);mid=mid+Math.imul(ah9,bl6)|0;hi=Math.imul(ah9,bh6);lo=lo+Math.imul(al8,bl7)|0;mid=mid+Math.imul(al8,bh7)|0;mid=mid+Math.imul(ah8,bl7)|0;hi=hi+Math.imul(ah8,bh7)|0;lo=lo+Math.imul(al7,bl8)|0;mid=mid+Math.imul(al7,bh8)|0;mid=mid+Math.imul(ah7,bl8)|0;hi=hi+Math.imul(ah7,bh8)|0;lo=lo+Math.imul(al6,bl9)|0;mid=mid+Math.imul(al6,bh9)|0;mid=mid+Math.imul(ah6,bl9)|0;hi=hi+Math.imul(ah6,bh9)|0;var w15=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w15>>>26)|0;w15&=0x3ffffff;/* k = 16 */lo=Math.imul(al9,bl7);mid=Math.imul(al9,bh7);mid=mid+Math.imul(ah9,bl7)|0;hi=Math.imul(ah9,bh7);lo=lo+Math.imul(al8,bl8)|0;mid=mid+Math.imul(al8,bh8)|0;mid=mid+Math.imul(ah8,bl8)|0;hi=hi+Math.imul(ah8,bh8)|0;lo=lo+Math.imul(al7,bl9)|0;mid=mid+Math.imul(al7,bh9)|0;mid=mid+Math.imul(ah7,bl9)|0;hi=hi+Math.imul(ah7,bh9)|0;var w16=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w16>>>26)|0;w16&=0x3ffffff;/* k = 17 */lo=Math.imul(al9,bl8);mid=Math.imul(al9,bh8);mid=mid+Math.imul(ah9,bl8)|0;hi=Math.imul(ah9,bh8);lo=lo+Math.imul(al8,bl9)|0;mid=mid+Math.imul(al8,bh9)|0;mid=mid+Math.imul(ah8,bl9)|0;hi=hi+Math.imul(ah8,bh9)|0;var w17=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w17>>>26)|0;w17&=0x3ffffff;/* k = 18 */lo=Math.imul(al9,bl9);mid=Math.imul(al9,bh9);mid=mid+Math.imul(ah9,bl9)|0;hi=Math.imul(ah9,bh9);var w18=(c+lo|0)+((mid&0x1fff)<<13)|0;c=(hi+(mid>>>13)|0)+(w18>>>26)|0;w18&=0x3ffffff;o[0]=w0;o[1]=w1;o[2]=w2;o[3]=w3;o[4]=w4;o[5]=w5;o[6]=w6;o[7]=w7;o[8]=w8;o[9]=w9;o[10]=w10;o[11]=w11;o[12]=w12;o[13]=w13;o[14]=w14;o[15]=w15;o[16]=w16;o[17]=w17;o[18]=w18;if(c!==0){o[19]=c;out.length++;}return out;};// Polyfill comb
if(!Math.imul){comb10MulTo=smallMulTo;}function bigMulTo(self,num,out){out.negative=num.negative^self.negative;out.length=self.length+num.length;var carry=0;var hncarry=0;for(var k=0;k= 0x3ffffff
var ncarry=hncarry;hncarry=0;var rword=carry&0x3ffffff;var maxJ=Math.min(k,num.length-1);for(var j=Math.max(0,k-self.length+1);j<=maxJ;j++){var i=k-j;var a=self.words[i]|0;var b=num.words[j]|0;var r=a*b;var lo=r&0x3ffffff;ncarry=ncarry+(r/0x4000000|0)|0;lo=lo+rword|0;rword=lo&0x3ffffff;ncarry=ncarry+(lo>>>26)|0;hncarry+=ncarry>>>26;ncarry&=0x3ffffff;}out.words[k]=rword;carry=ncarry;ncarry=hncarry;}if(carry!==0){out.words[k]=carry;}else{out.length--;}return out.strip();}function jumboMulTo(self,num,out){var fftm=new FFTM();return fftm.mulp(self,num,out);}BN.prototype.mulTo=function mulTo(num,out){var res;var len=this.length+num.length;if(this.length===10&&num.length===10){res=comb10MulTo(this,num,out);}else if(len<63){res=smallMulTo(this,num,out);}else if(len<1024){res=bigMulTo(this,num,out);}else{res=jumboMulTo(this,num,out);}return res;};// Cooley-Tukey algorithm for FFT
// slightly revisited to rely on looping instead of recursion
function FFTM(x,y){this.x=x;this.y=y;}FFTM.prototype.makeRBT=function makeRBT(N){var t=new Array(N);var l=BN.prototype._countBits(N)-1;for(var i=0;i>=1;}return rb;};// Performs "tweedling" phase, therefore 'emulating'
// behaviour of the recursive algorithm
FFTM.prototype.permute=function permute(rbt,rws,iws,rtws,itws,N){for(var i=0;i>>1){i++;}return 1<>>13;rws[2*i+1]=carry&0x1fff;carry=carry>>>13;}// Pad with zeroes
for(i=2*len;i>=26;carry+=w/0x4000000|0;// NOTE: lo is 27bit maximum
carry+=lo>>>26;this.words[i]=lo&0x3ffffff;}if(carry!==0){this.words[i]=carry;this.length++;}return this;};BN.prototype.muln=function muln(num){return this.clone().imuln(num);};// `this` * `this`
BN.prototype.sqr=function sqr(){return this.mul(this);};// `this` * `this` in-place
BN.prototype.isqr=function isqr(){return this.imul(this.clone());};// Math.pow(`this`, `num`)
BN.prototype.pow=function pow(num){var w=toBitArray(num);if(w.length===0)return new BN(1);// Skip leading zeroes
var res=this;for(var i=0;i=0);var r=bits%26;var s=(bits-r)/26;var carryMask=0x3ffffff>>>26-r<<26-r;var i;if(r!==0){var carry=0;for(i=0;i>>26-r;}if(carry){this.words[i]=carry;this.length++;}}if(s!==0){for(i=this.length-1;i>=0;i--){this.words[i+s]=this.words[i];}for(i=0;i=0);var h;if(hint){h=(hint-hint%26)/26;}else{h=0;}var r=bits%26;var s=Math.min((bits-r)/26,this.length);var mask=0x3ffffff^0x3ffffff>>>r<s){this.length-=s;for(i=0;i=0&&(carry!==0||i>=h);i--){var word=this.words[i]|0;this.words[i]=carry<<26-r|word>>>r;carry=word&mask;}// Push carried bits as a mask
if(maskedWords&&carry!==0){maskedWords.words[maskedWords.length++]=carry;}if(this.length===0){this.words[0]=0;this.length=1;}return this.strip();};BN.prototype.ishrn=function ishrn(bits,hint,extended){// TODO(indutny): implement me
assert(this.negative===0);return this.iushrn(bits,hint,extended);};// Shift-left
BN.prototype.shln=function shln(bits){return this.clone().ishln(bits);};BN.prototype.ushln=function ushln(bits){return this.clone().iushln(bits);};// Shift-right
BN.prototype.shrn=function shrn(bits){return this.clone().ishrn(bits);};BN.prototype.ushrn=function ushrn(bits){return this.clone().iushrn(bits);};// Test if n bit is set
BN.prototype.testn=function testn(bit){assert(typeof bit==='number'&&bit>=0);var r=bit%26;var s=(bit-r)/26;var q=1<=0);var r=bits%26;var s=(bits-r)/26;assert(this.negative===0,'imaskn works only with positive numbers');if(this.length<=s){return this;}if(r!==0){s++;}this.length=Math.min(s,this.length);if(r!==0){var mask=0x3ffffff^0x3ffffff>>>r<=0x4000000;i++){this.words[i]-=0x4000000;if(i===this.length-1){this.words[i+1]=1;}else{this.words[i+1]++;}}this.length=Math.max(this.length,i+1);return this;};// Subtract plain number `num` from `this`
BN.prototype.isubn=function isubn(num){assert(typeof num==='number');assert(num<0x4000000);if(num<0)return this.iaddn(-num);if(this.negative!==0){this.negative=0;this.iaddn(num);this.negative=1;return this;}this.words[0]-=num;if(this.length===1&&this.words[0]<0){this.words[0]=-this.words[0];this.negative=1;}else{// Carry
for(var i=0;i>26)-(right/0x4000000|0);this.words[i+shift]=w&0x3ffffff;}for(;i>26;this.words[i+shift]=w&0x3ffffff;}if(carry===0)return this.strip();// Subtraction overflow
assert(carry===-1);carry=0;for(i=0;i>26;this.words[i]=w&0x3ffffff;}this.negative=1;return this.strip();};BN.prototype._wordDiv=function _wordDiv(num,mode){var shift=this.length-num.length;var a=this.clone();var b=num;// Normalize
var bhi=b.words[b.length-1]|0;var bhiBits=this._countBits(bhi);shift=26-bhiBits;if(shift!==0){b=b.ushln(shift);a.iushln(shift);bhi=b.words[b.length-1]|0;}// Initialize quotient
var m=a.length-b.length;var q;if(mode!=='mod'){q=new BN(null);q.length=m+1;q.words=new Array(q.length);for(var i=0;i=0;j--){var qj=(a.words[b.length+j]|0)*0x4000000+(a.words[b.length+j-1]|0);// NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max
// (0x7ffffff)
qj=Math.min(qj/bhi|0,0x3ffffff);a._ishlnsubmul(b,qj,j);while(a.negative!==0){qj--;a.negative=0;a._ishlnsubmul(b,1,j);if(!a.isZero()){a.negative^=1;}}if(q){q.words[j]=qj;}}if(q){q.strip();}a.strip();// Denormalize
if(mode!=='div'&&shift!==0){a.iushrn(shift);}return{div:q||null,mod:a};};// NOTE: 1) `mode` can be set to `mod` to request mod only,
// to `div` to request div only, or be absent to
// request both div & mod
// 2) `positive` is true if unsigned mod is requested
BN.prototype.divmod=function divmod(num,mode,positive){assert(!num.isZero());if(this.isZero()){return{div:new BN(0),mod:new BN(0)};}var div,mod,res;if(this.negative!==0&&num.negative===0){res=this.neg().divmod(num,mode);if(mode!=='mod'){div=res.div.neg();}if(mode!=='div'){mod=res.mod.neg();if(positive&&mod.negative!==0){mod.iadd(num);}}return{div:div,mod:mod};}if(this.negative===0&&num.negative!==0){res=this.divmod(num.neg(),mode);if(mode!=='mod'){div=res.div.neg();}return{div:div,mod:res.mod};}if((this.negative&num.negative)!==0){res=this.neg().divmod(num.neg(),mode);if(mode!=='div'){mod=res.mod.neg();if(positive&&mod.negative!==0){mod.isub(num);}}return{div:res.div,mod:mod};}// Both numbers are positive at this point
// Strip both numbers to approximate shift value
if(num.length>this.length||this.cmp(num)<0){return{div:new BN(0),mod:this};}// Very short reduction
if(num.length===1){if(mode==='div'){return{div:this.divn(num.words[0]),mod:null};}if(mode==='mod'){return{div:null,mod:new BN(this.modn(num.words[0]))};}return{div:this.divn(num.words[0]),mod:new BN(this.modn(num.words[0]))};}return this._wordDiv(num,mode);};// Find `this` / `num`
BN.prototype.div=function div(num){return this.divmod(num,'div',false).div;};// Find `this` % `num`
BN.prototype.mod=function mod(num){return this.divmod(num,'mod',false).mod;};BN.prototype.umod=function umod(num){return this.divmod(num,'mod',true).mod;};// Find Round(`this` / `num`)
BN.prototype.divRound=function divRound(num){var dm=this.divmod(num);// Fast case - exact division
if(dm.mod.isZero())return dm.div;var mod=dm.div.negative!==0?dm.mod.isub(num):dm.mod;var half=num.ushrn(1);var r2=num.andln(1);var cmp=mod.cmp(half);// Round down
if(cmp<0||r2===1&&cmp===0)return dm.div;// Round up
return dm.div.negative!==0?dm.div.isubn(1):dm.div.iaddn(1);};BN.prototype.modn=function modn(num){assert(num<=0x3ffffff);var p=(1<<26)%num;var acc=0;for(var i=this.length-1;i>=0;i--){acc=(p*acc+(this.words[i]|0))%num;}return acc;};// In-place division by number
BN.prototype.idivn=function idivn(num){assert(num<=0x3ffffff);var carry=0;for(var i=this.length-1;i>=0;i--){var w=(this.words[i]|0)+carry*0x4000000;this.words[i]=w/num|0;carry=w%num;}return this.strip();};BN.prototype.divn=function divn(num){return this.clone().idivn(num);};BN.prototype.egcd=function egcd(p){assert(p.negative===0);assert(!p.isZero());var x=this;var y=p.clone();if(x.negative!==0){x=x.umod(p);}else{x=x.clone();}// A * x + B * y = x
var A=new BN(1);var B=new BN(0);// C * x + D * y = y
var C=new BN(0);var D=new BN(1);var g=0;while(x.isEven()&&y.isEven()){x.iushrn(1);y.iushrn(1);++g;}var yp=y.clone();var xp=x.clone();while(!x.isZero()){for(var i=0,im=1;(x.words[0]&im)===0&&i<26;++i,im<<=1);if(i>0){x.iushrn(i);while(i-->0){if(A.isOdd()||B.isOdd()){A.iadd(yp);B.isub(xp);}A.iushrn(1);B.iushrn(1);}}for(var j=0,jm=1;(y.words[0]&jm)===0&&j<26;++j,jm<<=1);if(j>0){y.iushrn(j);while(j-->0){if(C.isOdd()||D.isOdd()){C.iadd(yp);D.isub(xp);}C.iushrn(1);D.iushrn(1);}}if(x.cmp(y)>=0){x.isub(y);A.isub(C);B.isub(D);}else{y.isub(x);C.isub(A);D.isub(B);}}return{a:C,b:D,gcd:y.iushln(g)};};// This is reduced incarnation of the binary EEA
// above, designated to invert members of the
// _prime_ fields F(p) at a maximal speed
BN.prototype._invmp=function _invmp(p){assert(p.negative===0);assert(!p.isZero());var a=this;var b=p.clone();if(a.negative!==0){a=a.umod(p);}else{a=a.clone();}var x1=new BN(1);var x2=new BN(0);var delta=b.clone();while(a.cmpn(1)>0&&b.cmpn(1)>0){for(var i=0,im=1;(a.words[0]&im)===0&&i<26;++i,im<<=1);if(i>0){a.iushrn(i);while(i-->0){if(x1.isOdd()){x1.iadd(delta);}x1.iushrn(1);}}for(var j=0,jm=1;(b.words[0]&jm)===0&&j<26;++j,jm<<=1);if(j>0){b.iushrn(j);while(j-->0){if(x2.isOdd()){x2.iadd(delta);}x2.iushrn(1);}}if(a.cmp(b)>=0){a.isub(b);x1.isub(x2);}else{b.isub(a);x2.isub(x1);}}var res;if(a.cmpn(1)===0){res=x1;}else{res=x2;}if(res.cmpn(0)<0){res.iadd(p);}return res;};BN.prototype.gcd=function gcd(num){if(this.isZero())return num.abs();if(num.isZero())return this.abs();var a=this.clone();var b=num.clone();a.negative=0;b.negative=0;// Remove common factor of two
for(var shift=0;a.isEven()&&b.isEven();shift++){a.iushrn(1);b.iushrn(1);}do{while(a.isEven()){a.iushrn(1);}while(b.isEven()){b.iushrn(1);}var r=a.cmp(b);if(r<0){// Swap `a` and `b` to make `a` always bigger than `b`
var t=a;a=b;b=t;}else if(r===0||b.cmpn(1)===0){break;}a.isub(b);}while(true);return b.iushln(shift);};// Invert number in the field F(num)
BN.prototype.invm=function invm(num){return this.egcd(num).a.umod(num);};BN.prototype.isEven=function isEven(){return(this.words[0]&1)===0;};BN.prototype.isOdd=function isOdd(){return(this.words[0]&1)===1;};// And first word and num
BN.prototype.andln=function andln(num){return this.words[0]#};// Increment at the bit position in-line
BN.prototype.bincn=function bincn(bit){assert(typeof bit==='number');var r=bit%26;var s=(bit-r)/26;var q=1<>>26;w&=0x3ffffff;this.words[i]=w;}if(carry!==0){this.words[i]=carry;this.length++;}return this;};BN.prototype.isZero=function isZero(){return this.length===1&&this.words[0]===0;};BN.prototype.cmpn=function cmpn(num){var negative=num<0;if(this.negative!==0&&!negative)return-1;if(this.negative===0&&negative)return 1;this.strip();var res;if(this.length>1){res=1;}else{if(negative){num=-num;}assert(num<=0x3ffffff,'Number is too big');var w=this.words[0]|0;res=w===num?0:w `num`
// 0 - if `this` == `num`
// -1 - if `this` < `num`
BN.prototype.cmp=function cmp(num){if(this.negative!==0&&num.negative===0)return-1;if(this.negative===0&&num.negative!==0)return 1;var res=this.ucmp(num);if(this.negative!==0)return-res|0;return res;};// Unsigned comparison
BN.prototype.ucmp=function ucmp(num){// At this point both numbers have the same sign
if(this.length>num.length)return 1;if(this.length=0;i--){var a=this.words[i]|0;var b=num.words[i]|0;if(a===b)continue;if(ab){res=1;}break;}return res;};BN.prototype.gtn=function gtn(num){return this.cmpn(num)===1;};BN.prototype.gt=function gt(num){return this.cmp(num)===1;};BN.prototype.gten=function gten(num){return this.cmpn(num)>=0;};BN.prototype.gte=function gte(num){return this.cmp(num)>=0;};BN.prototype.ltn=function ltn(num){return this.cmpn(num)===-1;};BN.prototype.lt=function lt(num){return this.cmp(num)===-1;};BN.prototype.lten=function lten(num){return this.cmpn(num)<=0;};BN.prototype.lte=function lte(num){return this.cmp(num)<=0;};BN.prototype.eqn=function eqn(num){return this.cmpn(num)===0;};BN.prototype.eq=function eq(num){return this.cmp(num)===0;};//
// A reduce context, could be using montgomery or something better, depending
// on the `m` itself.
//
BN.red=function red(num){return new Red(num);};BN.prototype.toRed=function toRed(ctx){assert(!this.red,'Already a number in reduction context');assert(this.negative===0,'red works only with positives');return ctx.convertTo(this)._forceRed(ctx);};BN.prototype.fromRed=function fromRed(){assert(this.red,'fromRed works only with numbers in reduction context');return this.red.convertFrom(this);};BN.prototype._forceRed=function _forceRed(ctx){this.red=ctx;return this;};BN.prototype.forceRed=function forceRed(ctx){assert(!this.red,'Already a number in reduction context');return this._forceRed(ctx);};BN.prototype.redAdd=function redAdd(num){assert(this.red,'redAdd works only with red numbers');return this.red.add(this,num);};BN.prototype.redIAdd=function redIAdd(num){assert(this.red,'redIAdd works only with red numbers');return this.red.iadd(this,num);};BN.prototype.redSub=function redSub(num){assert(this.red,'redSub works only with red numbers');return this.red.sub(this,num);};BN.prototype.redISub=function redISub(num){assert(this.red,'redISub works only with red numbers');return this.red.isub(this,num);};BN.prototype.redShl=function redShl(num){assert(this.red,'redShl works only with red numbers');return this.red.shl(this,num);};BN.prototype.redMul=function redMul(num){assert(this.red,'redMul works only with red numbers');this.red._verify2(this,num);return this.red.mul(this,num);};BN.prototype.redIMul=function redIMul(num){assert(this.red,'redMul works only with red numbers');this.red._verify2(this,num);return this.red.imul(this,num);};BN.prototype.redSqr=function redSqr(){assert(this.red,'redSqr works only with red numbers');this.red._verify1(this);return this.red.sqr(this);};BN.prototype.redISqr=function redISqr(){assert(this.red,'redISqr works only with red numbers');this.red._verify1(this);return this.red.isqr(this);};// Square root over p
BN.prototype.redSqrt=function redSqrt(){assert(this.red,'redSqrt works only with red numbers');this.red._verify1(this);return this.red.sqrt(this);};BN.prototype.redInvm=function redInvm(){assert(this.red,'redInvm works only with red numbers');this.red._verify1(this);return this.red.invm(this);};// Return negative clone of `this` % `red modulo`
BN.prototype.redNeg=function redNeg(){assert(this.red,'redNeg works only with red numbers');this.red._verify1(this);return this.red.neg(this);};BN.prototype.redPow=function redPow(num){assert(this.red&&!num.red,'redPow(normalNum)');this.red._verify1(this);return this.red.pow(this,num);};// Prime numbers with efficient reduction
var primes={k256:null,p224:null,p192:null,p25519:null};// Pseudo-Mersenne prime
function MPrime(name,p){// P = 2 ^ N - K
this.name=name;this.p=new BN(p,16);this.n=this.p.bitLength();this.k=new BN(1).iushln(this.n).isub(this.p);this.tmp=this._tmp();}MPrime.prototype._tmp=function _tmp(){var tmp=new BN(null);tmp.words=new Array(Math.ceil(this.n/13));return tmp;};MPrime.prototype.ireduce=function ireduce(num){// Assumes that `num` is less than `P^2`
// num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)
var r=num;var rlen;do{this.split(r,this.tmp);r=this.imulK(r);r=r.iadd(this.tmp);rlen=r.bitLength();}while(rlen>this.n);var cmp=rlen0){r.isub(this.p);}else{if(r.strip!==undefined){// r is BN v4 instance
r.strip();}else{// r is BN v5 instance
r._strip();}}return r;};MPrime.prototype.split=function split(input,out){input.iushrn(this.n,0,out);};MPrime.prototype.imulK=function imulK(num){return num.imul(this.k);};function K256(){MPrime.call(this,'k256','ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');}inherits(K256,MPrime);K256.prototype.split=function split(input,output){// 256 = 9 * 26 + 22
var mask=0x3fffff;var outLen=Math.min(input.length,9);for(var i=0;i>>22;prev=next;}prev>>>=22;input.words[i-10]=prev;if(prev===0&&input.length>10){input.length-=10;}else{input.length-=9;}};K256.prototype.imulK=function imulK(num){// K = 0x1000003d1 = [ 0x40, 0x3d1 ]
num.words[num.length]=0;num.words[num.length+1]=0;num.length+=2;// bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390
var lo=0;for(var i=0;i>>=26;num.words[i]=lo;carry=hi;}if(carry!==0){num.words[num.length++]=carry;}return num;};// Exported mostly for testing purposes, use plain name instead
BN._prime=function prime(name){// Cached version of prime
if(primes[name])return primes[name];var prime;if(name==='k256'){prime=new K256();}else if(name==='p224'){prime=new P224();}else if(name==='p192'){prime=new P192();}else if(name==='p25519'){prime=new P25519();}else{throw new Error('Unknown prime '+name);}primes[name]=prime;return prime;};//
// Base reduction engine
//
function Red(m){if(typeof m==='string'){var prime=BN._prime(m);this.m=prime.p;this.prime=prime;}else{assert(m.gtn(1),'modulus must be greater than 1');this.m=m;this.prime=null;}}Red.prototype._verify1=function _verify1(a){assert(a.negative===0,'red works only with positives');assert(a.red,'red works only with red numbers');};Red.prototype._verify2=function _verify2(a,b){assert((a.negative|b.negative)===0,'red works only with positives');assert(a.red&&a.red===b.red,'red works only with red numbers');};Red.prototype.imod=function imod(a){if(this.prime)return this.prime.ireduce(a)._forceRed(this);return a.umod(this.m)._forceRed(this);};Red.prototype.neg=function neg(a){if(a.isZero()){return a.clone();}return this.m.sub(a)._forceRed(this);};Red.prototype.add=function add(a,b){this._verify2(a,b);var res=a.add(b);if(res.cmp(this.m)>=0){res.isub(this.m);}return res._forceRed(this);};Red.prototype.iadd=function iadd(a,b){this._verify2(a,b);var res=a.iadd(b);if(res.cmp(this.m)>=0){res.isub(this.m);}return res;};Red.prototype.sub=function sub(a,b){this._verify2(a,b);var res=a.sub(b);if(res.cmpn(0)<0){res.iadd(this.m);}return res._forceRed(this);};Red.prototype.isub=function isub(a,b){this._verify2(a,b);var res=a.isub(b);if(res.cmpn(0)<0){res.iadd(this.m);}return res;};Red.prototype.shl=function shl(a,num){this._verify1(a);return this.imod(a.ushln(num));};Red.prototype.imul=function imul(a,b){this._verify2(a,b);return this.imod(a.imul(b));};Red.prototype.mul=function mul(a,b){this._verify2(a,b);return this.imod(a.mul(b));};Red.prototype.isqr=function isqr(a){return this.imul(a,a.clone());};Red.prototype.sqr=function sqr(a){return this.mul(a,a);};Red.prototype.sqrt=function sqrt(a){if(a.isZero())return a.clone();var mod3=this.m.andln(3);assert(mod3%2===1);// Fast case
if(mod3===3){var pow=this.m.add(new BN(1)).iushrn(2);return this.pow(a,pow);}// Tonelli-Shanks algorithm (Totally unoptimized and slow)
//
// Find Q and S, that Q * 2 ^ S = (P - 1)
var q=this.m.subn(1);var s=0;while(!q.isZero()&&q.andln(1)===0){s++;q.iushrn(1);}assert(!q.isZero());var one=new BN(1).toRed(this);var nOne=one.redNeg();// Find quadratic non-residue
// NOTE: Max is such because of generalized Riemann hypothesis.
var lpow=this.m.subn(1).iushrn(1);var z=this.m.bitLength();z=new BN(2*z*z).toRed(this);while(this.pow(z,lpow).cmp(nOne)!==0){z.redIAdd(nOne);}var c=this.pow(z,q);var r=this.pow(a,q.addn(1).iushrn(1));var t=this.pow(a,q);var m=s;while(t.cmp(one)!==0){var tmp=t;for(var i=0;tmp.cmp(one)!==0;i++){tmp=tmp.redSqr();}assert(i=0;i--){var word=num.words[i];for(var j=start-1;j>=0;j--){var bit=word>>j&1;if(res!==wnd[0]){res=this.sqr(res);}if(bit===0&¤t===0){currentLen=0;continue;}current<<=1;current|=bit;currentLen++;if(currentLen!==windowSize&&(i!==0||j!==0))continue;res=this.mul(res,wnd[current]);currentLen=0;current=0;}start=26;}return res;};Red.prototype.convertTo=function convertTo(num){var r=num.umod(this.m);return r===num?r.clone():r;};Red.prototype.convertFrom=function convertFrom(num){var res=num.clone();res.red=null;return res;};//
// Montgomery method engine
//
BN.mont=function mont(num){return new Mont(num);};function Mont(m){Red.call(this,m);this.shift=this.m.bitLength();if(this.shift%26!==0){this.shift+=26-this.shift%26;}this.r=new BN(1).iushln(this.shift);this.r2=this.imod(this.r.sqr());this.rinv=this.r._invmp(this.m);this.minv=this.rinv.mul(this.r).isubn(1).div(this.m);this.minv=this.minv.umod(this.r);this.minv=this.r.sub(this.minv);}inherits(Mont,Red);Mont.prototype.convertTo=function convertTo(num){return this.imod(num.ushln(this.shift));};Mont.prototype.convertFrom=function convertFrom(num){var r=this.imod(num.mul(this.rinv));r.red=null;return r;};Mont.prototype.imul=function imul(a,b){if(a.isZero()||b.isZero()){a.words[0]=0;a.length=1;return a;}var t=a.imul(b);var c=t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);var u=t.isub(c).iushrn(this.shift);var res=u;if(u.cmp(this.m)>=0){res=u.isub(this.m);}else if(u.cmpn(0)<0){res=u.iadd(this.m);}return res._forceRed(this);};Mont.prototype.mul=function mul(a,b){if(a.isZero()||b.isZero())return new BN(0)._forceRed(this);var t=a.mul(b);var c=t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);var u=t.isub(c).iushrn(this.shift);var res=u;if(u.cmp(this.m)>=0){res=u.isub(this.m);}else if(u.cmpn(0)<0){res=u.iadd(this.m);}return res._forceRed(this);};Mont.prototype.invm=function invm(a){// (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R
var res=this.imod(a._invmp(this.m).mul(this.r2));return res._forceRed(this);};})( false||module,this);/***/},/***/6204:/***/function(module){"use strict";module.exports=boundary;function boundary(cells){var i,j,k;var n=cells.length;var sz=0;for(i=0;i>>1;if(d<=0){return;}var retval;//Convert red boxes
var redList=pool.mallocDouble(2*d*n);var redIds=pool.mallocInt32(n);n=convertBoxes(red,d,redList,redIds);if(n>0){if(d===1&&full){//Special case: 1d complete
sweep.init(n);retval=sweep.sweepComplete(d,visit,0,n,redList,redIds,0,n,redList,redIds);}else{//Convert blue boxes
var blueList=pool.mallocDouble(2*d*m);var blueIds=pool.mallocInt32(m);m=convertBoxes(blue,d,blueList,blueIds);if(m>0){sweep.init(n+m);if(d===1){//Special case: 1d bipartite
retval=sweep.sweepBipartite(d,visit,0,n,redList,redIds,0,m,blueList,blueIds);}else{//General case: d>1
retval=boxIntersectIter(d,visit,full,n,redList,redIds,m,blueList,blueIds);}pool.free(blueList);pool.free(blueIds);}}pool.free(redList);pool.free(redIds);}return retval;}var RESULT;function appendItem(i,j){RESULT.push([i,j]);}function intersectFullArray(x){RESULT=[];boxIntersect(x,x,appendItem,true);return RESULT;}function intersectBipartiteArray(x,y){RESULT=[];boxIntersect(x,y,appendItem,false);return RESULT;}//User-friendly wrapper, handle full input and no-visitor cases
function boxIntersectWrapper(arg0,arg1,arg2){switch(arguments.length){case 1:return intersectFullArray(arg0);case 2:if(typeof arg1==='function'){return boxIntersect(arg0,arg0,arg1,true);}else{return intersectBipartiteArray(arg0,arg1);}case 3:return boxIntersect(arg0,arg1,arg2,false);default:throw new Error('box-intersect: Invalid arguments');}}/***/},/***/2455:/***/function(__unused_webpack_module,exports){"use strict";function full(){function bruteForceRedFull(d,ax,vv,rs,re,rb,ri,bs,be,bb,bi){var es=2*d;for(var i=rs,rp=es*rs;ibe-bs){return bruteForceRedFull(d,ax,vv,rs,re,rb,ri,bs,be,bb,bi);}else{return bruteForceBlueFull(d,ax,vv,rs,re,rb,ri,bs,be,bb,bi);}}return bruteForceFull;}function partial(){function bruteForceRedFlip(d,ax,vv,rs,re,rb,ri,bs,be,bb,bi){var es=2*d;for(var i=rs,rp=es*rs;ibe-bs){if(fp){return bruteForceRedFlip(d,ax,vv,rs,re,rb,ri,bs,be,bb,bi);}else{return bruteForceRed(d,ax,vv,rs,re,rb,ri,bs,be,bb,bi);}}else{if(fp){return bruteForceBlueFlip(d,ax,vv,rs,re,rb,ri,bs,be,bb,bi);}else{return bruteForceBlue(d,ax,vv,rs,re,rb,ri,bs,be,bb,bi);}}}return bruteForcePartial;}function bruteForcePlanner(isFull){return isFull?full():partial();}exports.partial=bruteForcePlanner(false);exports.full=bruteForcePlanner(true);/***/},/***/7150:/***/function(module,__unused_webpack_exports,__nested_webpack_require_141648__){"use strict";module.exports=boxIntersectIter;var pool=__nested_webpack_require_141648__(1888);var bits=__nested_webpack_require_141648__(8828);var bruteForce=__nested_webpack_require_141648__(2455);var bruteForcePartial=bruteForce.partial;var bruteForceFull=bruteForce.full;var sweep=__nested_webpack_require_141648__(855);var findMedian=__nested_webpack_require_141648__(3545);var genPartition=__nested_webpack_require_141648__(8105);//Twiddle parameters
var BRUTE_FORCE_CUTOFF=128;//Cut off for brute force search
var SCAN_CUTOFF=1<<22;//Cut off for two way scan
var SCAN_COMPLETE_CUTOFF=1<<22;//Partition functions
var partitionInteriorContainsInterval=genPartition('!(lo>=p0)&&!(p1>=hi)');var partitionStartEqual=genPartition('lo===p0');var partitionStartLessThan=genPartition('lo0){top-=1;var iptr=top*IFRAME_SIZE;var axis=BOX_ISTACK[iptr];var redStart=BOX_ISTACK[iptr+1];var redEnd=BOX_ISTACK[iptr+2];var blueStart=BOX_ISTACK[iptr+3];var blueEnd=BOX_ISTACK[iptr+4];var state=BOX_ISTACK[iptr+5];var dptr=top*DFRAME_SIZE;var lo=BOX_DSTACK[dptr];var hi=BOX_DSTACK[dptr+1];//Unpack state info
var flip=state&1;var full=!!(state&16);//Unpack indices
var red=xBoxes;var redIndex=xIndex;var blue=yBoxes;var blueIndex=yIndex;if(flip){red=yBoxes;redIndex=yIndex;blue=xBoxes;blueIndex=xIndex;}if(state&2){redEnd=partitionStartLessThan(d,axis,redStart,redEnd,red,redIndex,hi);if(redStart>=redEnd){continue;}}if(state&4){redStart=partitionEndLessThanEqual(d,axis,redStart,redEnd,red,redIndex,lo);if(redStart>=redEnd){continue;}}var redCount=redEnd-redStart;var blueCount=blueEnd-blueStart;if(full){if(d*redCount*(redCount+blueCount) mid point
//
var blue0=findMedian(d,axis,blueStart,blueEnd,blue,blueIndex);var mid=blue[elemSize*blue0+axis];var blue1=partitionStartEqual(d,axis,blue0,blueEnd,blue,blueIndex,mid);//Right case
if(blue1start&&boxes[ptr+axis]>x;--j,ptr-=elemSize){//Swap
var aPtr=ptr;var bPtr=ptr+elemSize;for(var k=0;k>>1;var elemSize=2*d;var pivot=mid;var value=boxes[elemSize*mid+axis];while(lo=value1){pivot=pivot1;value=value1;}else if(value0>=value2){pivot=pivot0;value=value0;}else{pivot=pivot2;value=value2;}}else{if(value1>=value2){pivot=pivot1;value=value1;}else if(value2>=value0){pivot=pivot0;value=value0;}else{pivot=pivot2;value=value2;}}//Swap pivot to end of array
var aPtr=elemSize*(hi-1);var bPtr=elemSize*pivot;for(var i=0;i=p0)&&!(p1>=hi)':lo_lessThan_p0_and_p1_lessThan_hi};function genPartition(predicate){return P2F[predicate];}// lo===p0
function lo_equal_p0(a,b,c,d,e,f,p0){for(var j=2*a,k=j*c,l=k,m=c,n=b,o=a+b,p=c;d>p;++p,k+=j){var lo=e[k+n];if(lo===p0)if(m===p)m+=1,l+=j;else{for(var s=0;j>s;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t;}var u=f[p];f[p]=f[m],f[m++]=u;}}return m;}// lop;++p,k+=j){var lo=e[k+n];if(los;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t;}var u=f[p];f[p]=f[m],f[m++]=u;}}return m;}// lo<=p0
function lo_lessOrEqual_p0(a,b,c,d,e,f,p0){for(var j=2*a,k=j*c,l=k,m=c,n=b,o=a+b,p=c;d>p;++p,k+=j){var hi=e[k+o];if(hi<=p0)if(m===p)m+=1,l+=j;else{for(var s=0;j>s;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t;}var u=f[p];f[p]=f[m],f[m++]=u;}}return m;}// hi<=p0
function hi_lessOrEqual_p0(a,b,c,d,e,f,p0){for(var j=2*a,k=j*c,l=k,m=c,n=b,o=a+b,p=c;d>p;++p,k+=j){var hi=e[k+o];if(hi<=p0)if(m===p)m+=1,l+=j;else{for(var s=0;j>s;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t;}var u=f[p];f[p]=f[m],f[m++]=u;}}return m;}// lo<=p0&&p0<=hi
function lo_lassOrEqual_p0_and_p0_lessOrEqual_hi(a,b,c,d,e,f,p0){for(var j=2*a,k=j*c,l=k,m=c,n=b,o=a+b,p=c;d>p;++p,k+=j){var lo=e[k+n],hi=e[k+o];if(lo<=p0&&p0<=hi)if(m===p)m+=1,l+=j;else{for(var s=0;j>s;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t;}var u=f[p];f[p]=f[m],f[m++]=u;}}return m;}// lop;++p,k+=j){var lo=e[k+n],hi=e[k+o];if(los;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t;}var u=f[p];f[p]=f[m],f[m++]=u;}}return m;}// !(lo>=p0)&&!(p1>=hi)
function lo_lessThan_p0_and_p1_lessThan_hi(a,b,c,d,e,f,p0,p1){for(var j=2*a,k=j*c,l=k,m=c,n=b,o=a+b,p=c;d>p;++p,k+=j){var lo=e[k+n],hi=e[k+o];if(!(lo>=p0)&&!(p1>=hi))if(m===p)m+=1,l+=j;else{for(var s=0;j>s;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t;}var u=f[p];f[p]=f[m],f[m++]=u;}}return m;}/***/},/***/1811:/***/function(module){"use strict";//This code is extracted from ndarray-sort
//It is inlined here as a temporary workaround
module.exports=wrapper;var INSERT_SORT_CUTOFF=32;function wrapper(data,n0){if(n0<=4*INSERT_SORT_CUTOFF){insertionSort(0,n0-1,data);}else{quickSort(0,n0-1,data);}}function insertionSort(left,right,data){var ptr=2*(left+1);for(var i=left+1;i<=right;++i){var a=data[ptr++];var b=data[ptr++];var j=i;var jptr=ptr-2;while(j-->left){var x=data[jptr-2];var y=data[jptr-1];if(xdata[j+1];}return true;}function comparePivot(i,y,b,data){i*=2;var x=data[i];if(x>1,index2=index3-sixth,index4=index3+sixth,el1=index1,el2=index2,el3=index3,el4=index4,el5=index5,less=left+1,great=right-1,tmp=0;if(compare(el1,el2,data)){tmp=el1;el1=el2;el2=tmp;}if(compare(el4,el5,data)){tmp=el4;el4=el5;el5=tmp;}if(compare(el1,el3,data)){tmp=el1;el1=el3;el3=tmp;}if(compare(el2,el3,data)){tmp=el2;el2=el3;el3=tmp;}if(compare(el1,el4,data)){tmp=el1;el1=el4;el4=tmp;}if(compare(el3,el4,data)){tmp=el3;el3=el4;el4=tmp;}if(compare(el2,el5,data)){tmp=el2;el2=el5;el5=tmp;}if(compare(el2,el3,data)){tmp=el2;el2=el3;el3=tmp;}if(compare(el4,el5,data)){tmp=el4;el4=el5;el5=tmp;}var pivot1X=data[2*el2];var pivot1Y=data[2*el2+1];var pivot2X=data[2*el4];var pivot2Y=data[2*el4+1];var ptr0=2*el1;var ptr2=2*el3;var ptr4=2*el5;var ptr5=2*index1;var ptr6=2*index3;var ptr7=2*index5;for(var i1=0;i1<2;++i1){var x=data[ptr0+i1];var y=data[ptr2+i1];var z=data[ptr4+i1];data[ptr5+i1]=x;data[ptr6+i1]=y;data[ptr7+i1]=z;}move(index2,left,data);move(index4,right,data);for(var k=less;k<=great;++k){if(comparePivot(k,pivot1X,pivot1Y,data)){if(k!==less){swap(k,less,data);}++less;}else{if(!comparePivot(k,pivot2X,pivot2Y,data)){while(true){if(!comparePivot(great,pivot2X,pivot2Y,data)){if(--greatright
var n=ptr>>>1;isort(SWEEP_EVENTS,n);var redActive=0;var blueActive=0;for(var i=0;i=BLUE_FLAG){//blue destroy event
e=e-BLUE_FLAG|0;sqPop(BLUE_SWEEP_QUEUE,BLUE_SWEEP_INDEX,blueActive--,e);}else if(e>=0){//red destroy event
sqPop(RED_SWEEP_QUEUE,RED_SWEEP_INDEX,redActive--,e);}else if(e<=-BLUE_FLAG){//blue create event
e=-e-BLUE_FLAG|0;for(var j=0;jright
var n=ptr>>>1;isort(SWEEP_EVENTS,n);var redActive=0;var blueActive=0;var commonActive=0;for(var i=0;i>1===SWEEP_EVENTS[2*i+3]>>1){color=2;i+=1;}if(e<0){//Create event
var id=-(e>>1)-1;//Intersect with common
for(var j=0;j>1)-1;if(color===0){//Red
sqPop(RED_SWEEP_QUEUE,RED_SWEEP_INDEX,redActive--,id);}else if(color===1){//Blue
sqPop(BLUE_SWEEP_QUEUE,BLUE_SWEEP_INDEX,blueActive--,id);}else if(color===2){//Both
sqPop(COMMON_SWEEP_QUEUE,COMMON_SWEEP_INDEX,commonActive--,id);}}}}//Sweep and prune/scanline algorithm:
// Scan along axis, detect intersections
// Brute force all boxes along axis
function scanBipartite(d,axis,visit,flip,redStart,redEnd,red,redIndex,blueStart,blueEnd,blue,blueIndex){var ptr=0;var elemSize=2*d;var istart=axis;var iend=axis+d;var redShift=1;var blueShift=1;if(flip){blueShift=BLUE_FLAG;}else{redShift=BLUE_FLAG;}for(var i=redStart;iright
var n=ptr>>>1;isort(SWEEP_EVENTS,n);var redActive=0;for(var i=0;i=BLUE_FLAG){isRed=!flip;idx-=BLUE_FLAG;}else{isRed=!!flip;idx-=1;}if(isRed){sqPush(RED_SWEEP_QUEUE,RED_SWEEP_INDEX,redActive++,idx);}else{var blueId=blueIndex[idx];var bluePtr=elemSize*idx;var b0=blue[bluePtr+axis+1];var b1=blue[bluePtr+axis+1+d];red_loop:for(var j=0;jright
var n=ptr>>>1;isort(SWEEP_EVENTS,n);var redActive=0;for(var i=0;i=BLUE_FLAG){RED_SWEEP_QUEUE[redActive++]=idx-BLUE_FLAG;}else{idx-=1;var blueId=blueIndex[idx];var bluePtr=elemSize*idx;var b0=blue[bluePtr+axis+1];var b1=blue[bluePtr+axis+1+d];red_loop:for(var j=0;j=0;--j){if(RED_SWEEP_QUEUE[j]===idx){for(var k=j+1;k0){var b=stack.pop();var a=stack.pop();//Find opposite pairs
var x=-1,y=-1;var star=stars[a];for(var i=1;i=0){continue;}//Flip the edge
triangulation.flip(a,b);//Test flipping neighboring edges
testFlip(points,triangulation,stack,x,a,y);testFlip(points,triangulation,stack,a,y,x);testFlip(points,triangulation,stack,y,b,x);testFlip(points,triangulation,stack,b,x,y);}}/***/},/***/5023:/***/function(module,__unused_webpack_exports,__nested_webpack_require_170291__){"use strict";var bsearch=__nested_webpack_require_170291__(2478);module.exports=classifyFaces;function FaceIndex(cells,neighbor,constraint,flags,active,next,boundary){this.cells=cells;this.neighbor=neighbor;this.flags=flags;this.constraint=constraint;this.active=active;this.next=next;this.boundary=boundary;}var proto=FaceIndex.prototype;function compareCell(a,b){return a[0]-b[0]||a[1]-b[1]||a[2]-b[2];}proto.locate=function(){var key=[0,0,0];return function(a,b,c){var x=a,y=b,z=c;if(b0||next.length>0){while(active.length>0){var t=active.pop();if(flags[t]===-side){continue;}flags[t]=side;var c=cells[t];for(var j=0;j<3;++j){var f=neighbor[3*t+j];if(f>=0&&flags[f]===0){if(constraint[3*t+j]){next.push(f);}else{active.push(f);flags[f]=side;}}}}//Swap arrays and loop
var tmp=next;next=active;active=tmp;next.length=0;side=-side;}var result=filterCells(cells,flags,target);if(infinity){return result.concat(index.boundary);}return result;}/***/},/***/8902:/***/function(module,__unused_webpack_exports,__nested_webpack_require_172942__){"use strict";var bsearch=__nested_webpack_require_172942__(2478);var orient=__nested_webpack_require_172942__(3250)[3];var EVENT_POINT=0;var EVENT_END=1;var EVENT_START=2;module.exports=monotoneTriangulate;//A partial convex hull fragment, made of two unimonotone polygons
function PartialHull(a,b,idx,lowerIds,upperIds){this.a=a;this.b=b;this.idx=idx;this.lowerIds=lowerIds;this.upperIds=upperIds;}//An event in the sweep line procedure
function Event(a,b,type,idx){this.a=a;this.b=b;this.type=type;this.idx=idx;}//This is used to compare events for the sweep line procedure
// Points are:
// 1. sorted lexicographically
// 2. sorted by type (point < end < start)
// 3. segments sorted by winding order
// 4. sorted by index
function compareEvent(a,b){var d=a.a[0]-b.a[0]||a.a[1]-b.a[1]||a.type-b.type;if(d){return d;}if(a.type!==EVENT_POINT){d=orient(a.a,a.b,b.b);if(d){return d;}}return a.idx-b.idx;}function testPoint(hull,p){return orient(hull.a,hull.b,p);}function addPoint(cells,hulls,points,p,idx){var lo=bsearch.lt(hulls,p,testPoint);var hi=bsearch.gt(hulls,p,testPoint);for(var i=lo;i1&&orient(points[lowerIds[m-2]],points[lowerIds[m-1]],p)>0){cells.push([lowerIds[m-1],lowerIds[m-2],idx]);m-=1;}lowerIds.length=m;lowerIds.push(idx);//Insert p into upper hull
var upperIds=hull.upperIds;var m=upperIds.length;while(m>1&&orient(points[upperIds[m-2]],points[upperIds[m-1]],p)<0){cells.push([upperIds[m-2],upperIds[m-1],idx]);m-=1;}upperIds.length=m;upperIds.push(idx);}}function findSplit(hull,edge){var d;if(hull.a[0]b[0]){events.push(new Event(b,a,EVENT_START,i),new Event(a,b,EVENT_END,i));}}//Sort events
events.sort(compareEvent);//Initialize hull
var minX=events[0].a[0]-(1+Math.abs(events[0].a[0]))*Math.pow(2,-52);var hull=[new PartialHull([minX,1],[minX,0],-1,[],[],[],[])];//Process events in order
var cells=[];for(var i=0,numEvents=events.length;i=0;};}();proto.removeTriangle=function(i,j,k){var stars=this.stars;removePair(stars[i],j,k);removePair(stars[j],k,i);removePair(stars[k],i,j);};proto.addTriangle=function(i,j,k){var stars=this.stars;stars[i].push(j,k);stars[j].push(k,i);stars[k].push(i,j);};proto.opposite=function(j,i){var list=this.stars[i];for(var k=1,n=list.length;k=0;--i){var junction=junctions[i];e=junction[0];var edge=edges[e];var s=edge[0];var t=edge[1];// Check if edge is not lexicographically sorted
var a=floatPoints[s];var b=floatPoints[t];if((a[0]-b[0]||a[1]-b[1])<0){var tmp=s;s=t;t=tmp;}// Split leading edge
edge[0]=s;var last=edge[1]=junction[1];// If we are grouping edges by color, remember to track data
var color;if(useColor){color=edge[2];}// Split other edges
while(i>0&&junctions[i-1][0]===e){var junction=junctions[--i];var next=junction[1];if(useColor){edges.push([last,next,color]);}else{edges.push([last,next]);}last=next;}// Add final edge
if(useColor){edges.push([last,t,color]);}else{edges.push([last,t]);}}// Return constructed rational points
return ratPoints;}// Merge overlapping points
function dedupPoints(floatPoints,ratPoints,floatBounds){var numPoints=ratPoints.length;var uf=new UnionFind(numPoints);// Compute rational bounds
var bounds=[];for(var i=0;ib[2]){return 1;}return 0;}// Remove duplicate edge labels
function dedupEdges(edges,labels,useColor){if(edges.length===0){return;}if(labels){for(var i=0;i0||tjunctions.length>0;}// More iterations necessary
return true;}// Main loop, runs PSLG clean up until completion
function cleanPSLG(points,edges,colors){// If using colors, augment edges with color data
var prevEdges;if(colors){prevEdges=edges;var augEdges=new Array(edges.length);for(var i=0;inshades+1){throw new Error(colormap+' map requires nshades to be at least size '+cmap.length);}if(!Array.isArray(spec.alpha)){if(typeof spec.alpha==='number'){alpha=[spec.alpha,spec.alpha];}else{alpha=[1,1];}}else if(spec.alpha.length!==2){alpha=[1,1];}else{alpha=spec.alpha.slice();}// map index points from 0..1 to 0..n-1
indicies=cmap.map(function(c){return Math.round(c.index*nshades);});// Add alpha channel to the map
alpha[0]=Math.min(Math.max(alpha[0],0),1);alpha[1]=Math.min(Math.max(alpha[1],0),1);var steps=cmap.map(function(c,i){var index=cmap[i].index;var rgba=cmap[i].rgb.slice();// if user supplies their own map use it
if(rgba.length===4&&rgba[3]>=0&&rgba[3]<=1){return rgba;}rgba[3]=alpha[0]+(alpha[1]-alpha[0])*index;return rgba;});/*
* map increasing linear values between indicies to
* linear steps in colorvalues
*/var colors=[];for(i=0;i=0;}function compareAngle(a,b,c,d){var bcd=orient(b,c,d);if(bcd===0){//Handle degenerate cases
var sabc=sgn(orient(a,b,c));var sabd=sgn(orient(a,b,d));if(sabc===sabd){if(sabc===0){var ic=testInterior(a,b,c);var id=testInterior(a,b,d);if(ic===id){return 0;}else if(ic){return 1;}else{return-1;}}return 0;}else if(sabd===0){if(sabc>0){return-1;}else if(testInterior(a,b,d)){return-1;}else{return 1;}}else if(sabc===0){if(sabd>0){return 1;}else if(testInterior(a,b,c)){return 1;}else{return-1;}}return sgn(sabd-sabc);}var abc=orient(a,b,c);if(abc>0){if(bcd>0&&orient(a,b,d)>0){return 1;}return-1;}else if(abc<0){if(bcd>0||orient(a,b,d)>0){return 1;}return-1;}else{var abd=orient(a,b,d);if(abd>0){return 1;}else{if(testInterior(a,b,c)){return 1;}else{return-1;}}}}/***/},/***/8572:/***/function(module){"use strict";module.exports=function signum(x){if(x<0){return-1;}if(x>0){return 1;}return 0.0;};/***/},/***/8507:/***/function(module){module.exports=compareCells;var min=Math.min;function compareInt(a,b){return a-b;}function compareCells(a,b){var n=a.length,t=a.length-b.length;if(t){return t;}switch(n){case 0:return 0;case 1:return a[0]-b[0];case 2:return a[0]+a[1]-b[0]-b[1]||min(a[0],a[1])-min(b[0],b[1]);case 3:var l1=a[0]+a[1],m1=b[0]+b[1];t=l1+a[2]-(m1+b[2]);if(t){return t;}var l0=min(a[0],a[1]),m0=min(b[0],b[1]);return min(l0,a[2])-min(m0,b[2])||min(l0+a[2],l1)-min(m0+b[2],m1);case 4:var aw=a[0],ax=a[1],ay=a[2],az=a[3],bw=b[0],bx=b[1],by=b[2],bz=b[3];return aw+ax+ay+az-(bw+bx+by+bz)||min(aw,ax,ay,az)-min(bw,bx,by,bz,bw)||min(aw+ax,aw+ay,aw+az,ax+ay,ax+az,ay+az)-min(bw+bx,bw+by,bw+bz,bx+by,bx+bz,by+bz)||min(aw+ax+ay,aw+ax+az,aw+ay+az,ax+ay+az)-min(bw+bx+by,bw+bx+bz,bw+by+bz,bx+by+bz);default:var as=a.slice().sort(compareInt);var bs=b.slice().sort(compareInt);for(var i=0;ipoints[hi][0]){hi=i;}}if(lohi){return[[hi],[lo]];}else{return[[lo]];}}/***/},/***/4750:/***/function(module,__unused_webpack_exports,__nested_webpack_require_205357__){"use strict";module.exports=convexHull2D;var monotoneHull=__nested_webpack_require_205357__(3090);function convexHull2D(points){var hull=monotoneHull(points);var h=hull.length;if(h<=2){return[];}var edges=new Array(h);var a=hull[h-1];for(var i=0;i=front[k]){x+=1;}}c[j]=x;}}}return cells;}function convexHullnD(points,d){try{return ich(points,true);}catch(e){//If point set is degenerate, try to find a basis and rerun it
var ah=aff(points);if(ah.length<=d){//No basis, no try
return[];}var npoints=permute(points,ah);var nhull=ich(npoints,true);return invPermute(nhull,ah);}}/***/},/***/4769:/***/function(module){"use strict";function dcubicHermite(p0,v0,p1,v1,t,f){var dh00=6*t*t-6*t,dh10=3*t*t-4*t+1,dh01=-6*t*t+6*t,dh11=3*t*t-2*t;if(p0.length){if(!f){f=new Array(p0.length);}for(var i=p0.length-1;i>=0;--i){f[i]=dh00*p0[i]+dh10*v0[i]+dh01*p1[i]+dh11*v1[i];}return f;}return dh00*p0+dh10*v0+dh01*p1[i]+dh11*v1;}function cubicHermite(p0,v0,p1,v1,t,f){var ti=t-1,t2=t*t,ti2=ti*ti,h00=(1+2*t)*ti2,h10=t*ti2,h01=t2*(3-2*t),h11=t2*ti;if(p0.length){if(!f){f=new Array(p0.length);}for(var i=p0.length-1;i>=0;--i){f[i]=h00*p0[i]+h10*v0[i]+h01*p1[i]+h11*v1[i];}return f;}return h00*p0+h10*v0+h01*p1+h11*v1;}module.exports=cubicHermite;module.exports.derivative=dcubicHermite;/***/},/***/7642:/***/function(module,__unused_webpack_exports,__nested_webpack_require_207403__){"use strict";var ch=__nested_webpack_require_207403__(8954);var uniq=__nested_webpack_require_207403__(1682);module.exports=triangulate;function LiftedPoint(p,i){this.point=p;this.index=i;}function compareLifted(a,b){var ap=a.point;var bp=b.point;var d=ap.length;for(var i=0;i=2){return false;}}cell[j]=v;}return true;});}else{hull=hull.filter(function(cell){for(var i=0;i<=d;++i){var v=dindex[cell[i]];if(v<0){return false;}cell[i]=v;}return true;});}if(d&1){for(var i=0;i>>31;};module.exports.exponent=function(n){var b=module.exports.hi(n);return(b<<1>>>21)-1023;};module.exports.fraction=function(n){var lo=module.exports.lo(n);var hi=module.exports.hi(n);var b=hi&(1<<20)-1;if(hi&0x7ff00000){b+=1<<20;}return[lo,b];};module.exports.denormalized=function(n){var hi=module.exports.hi(n);return!(hi&0x7ff00000);};/***/},/***/1338:/***/function(module){"use strict";function dupe_array(count,value,i){var c=count[i]|0;if(c<=0){return[];}var result=new Array(c),j;if(i===count.length-1){for(j=0;j0){return dupe_number(count|0,value);}break;case"object":if(typeof count.length==="number"){return dupe_array(count,value,0);}break;}return[];}module.exports=dupe;/***/},/***/3134:/***/function(module,__unused_webpack_exports,__nested_webpack_require_212399__){"use strict";module.exports=edgeToAdjacency;var uniq=__nested_webpack_require_212399__(1682);function edgeToAdjacency(edges,numVertices){var numEdges=edges.length;if(typeof numVertices!=="number"){numVertices=0;for(var i=0;i=n-1){var ptr=state.length-1;var tf=t-time[n-1];for(var i=0;i=n-1){var ptr=state.length-1;var tf=t-time[n-1];for(var i=0;i=0;--i){if(velocity[--ptr]){return false;}}return true;};proto.jump=function(t){var t0=this.lastT();var d=this.dimension;if(t0;--i){state.push(clamp(lo[i-1],hi[i-1],arguments[i]));velocity.push(0);}};proto.push=function(t){var t0=this.lastT();var d=this.dimension;if(t1e-6?1/dt:0;this._time.push(t);for(var i=d;i>0;--i){var xc=clamp(lo[i-1],hi[i-1],arguments[i]);state.push(xc);velocity.push((xc-state[ptr++])*sf);}};proto.set=function(t){var d=this.dimension;if(t0;--i){state.push(clamp(lo[i-1],hi[i-1],arguments[i]));velocity.push(0);}};proto.move=function(t){var t0=this.lastT();var d=this.dimension;if(t<=t0||arguments.length!==d+1){return;}var state=this._state;var velocity=this._velocity;var statePtr=state.length-this.dimension;var bounds=this.bounds;var lo=bounds[0];var hi=bounds[1];var dt=t-t0;var sf=dt>1e-6?1/dt:0.0;this._time.push(t);for(var i=d;i>0;--i){var dx=arguments[i];state.push(clamp(lo[i-1],hi[i-1],state[statePtr++]+dx));velocity.push(dx*sf);}};proto.idle=function(t){var t0=this.lastT();if(t=0;--i){state.push(clamp(lo[i],hi[i],state[statePtr]+dt*velocity[statePtr]));velocity.push(0);statePtr+=1;}};function getZero(d){var result=new Array(d);for(var i=0;i=0;--s){var n=n_stack[s];if(d_stack[s]<=0){n_stack[s]=new RBNode(n._color,n.key,n.value,n_stack[s+1],n.right,n._count+1);}else{n_stack[s]=new RBNode(n._color,n.key,n.value,n.left,n_stack[s+1],n._count+1);}}//Rebalance tree using rotations
//console.log("start insert", key, d_stack)
for(var s=n_stack.length-1;s>1;--s){var p=n_stack[s-1];var n=n_stack[s];if(p._color===BLACK||n._color===BLACK){break;}var pp=n_stack[s-2];if(pp.left===p){if(p.left===n){var y=pp.right;if(y&&y._color===RED){//console.log("LLr")
p._color=BLACK;pp.right=repaint(BLACK,y);pp._color=RED;s-=1;}else{//console.log("LLb")
pp._color=RED;pp.left=p.right;p._color=BLACK;p.right=pp;n_stack[s-2]=p;n_stack[s-1]=n;recount(pp);recount(p);if(s>=3){var ppp=n_stack[s-3];if(ppp.left===pp){ppp.left=p;}else{ppp.right=p;}}break;}}else{var y=pp.right;if(y&&y._color===RED){//console.log("LRr")
p._color=BLACK;pp.right=repaint(BLACK,y);pp._color=RED;s-=1;}else{//console.log("LRb")
p.right=n.left;pp._color=RED;pp.left=n.right;n._color=BLACK;n.left=p;n.right=pp;n_stack[s-2]=n;n_stack[s-1]=p;recount(pp);recount(p);recount(n);if(s>=3){var ppp=n_stack[s-3];if(ppp.left===pp){ppp.left=n;}else{ppp.right=n;}}break;}}}else{if(p.right===n){var y=pp.left;if(y&&y._color===RED){//console.log("RRr", y.key)
p._color=BLACK;pp.left=repaint(BLACK,y);pp._color=RED;s-=1;}else{//console.log("RRb")
pp._color=RED;pp.right=p.left;p._color=BLACK;p.left=pp;n_stack[s-2]=p;n_stack[s-1]=n;recount(pp);recount(p);if(s>=3){var ppp=n_stack[s-3];if(ppp.right===pp){ppp.right=p;}else{ppp.left=p;}}break;}}else{var y=pp.left;if(y&&y._color===RED){//console.log("RLr")
p._color=BLACK;pp.left=repaint(BLACK,y);pp._color=RED;s-=1;}else{//console.log("RLb")
p.left=n.right;pp._color=RED;pp.right=n.left;n._color=BLACK;n.right=p;n.left=pp;n_stack[s-2]=n;n_stack[s-1]=p;recount(pp);recount(p);recount(n);if(s>=3){var ppp=n_stack[s-3];if(ppp.right===pp){ppp.right=n;}else{ppp.left=n;}}break;}}}}//Return new tree
n_stack[0]._color=BLACK;return new RedBlackTree(cmp,n_stack[0]);};//Visit all nodes inorder
function doVisitFull(visit,node){if(node.left){var v=doVisitFull(visit,node.left);if(v){return v;}}var v=visit(node.key,node.value);if(v){return v;}if(node.right){return doVisitFull(visit,node.right);}}//Visit half nodes in order
function doVisitHalf(lo,compare,visit,node){var l=compare(lo,node.key);if(l<=0){if(node.left){var v=doVisitHalf(lo,compare,visit,node.left);if(v){return v;}}var v=visit(node.key,node.value);if(v){return v;}}if(node.right){return doVisitHalf(lo,compare,visit,node.right);}}//Visit all nodes within a range
function doVisit(lo,hi,compare,visit,node){var l=compare(lo,node.key);var h=compare(hi,node.key);var v;if(l<=0){if(node.left){v=doVisit(lo,hi,compare,visit,node.left);if(v){return v;}}if(h>0){v=visit(node.key,node.value);if(v){return v;}}}if(h>0&&node.right){return doVisit(lo,hi,compare,visit,node.right);}}proto.forEach=function rbTreeForEach(visit,lo,hi){if(!this.root){return;}switch(arguments.length){case 1:return doVisitFull(visit,this.root);break;case 2:return doVisitHalf(lo,this._compare,visit,this.root);break;case 3:if(this._compare(lo,hi)>=0){return;}return doVisit(lo,hi,this._compare,visit,this.root);break;}};//First item in list
Object.defineProperty(proto,"begin",{get:function(){var stack=[];var n=this.root;while(n){stack.push(n);n=n.left;}return new RedBlackTreeIterator(this,stack);}});//Last item in list
Object.defineProperty(proto,"end",{get:function(){var stack=[];var n=this.root;while(n){stack.push(n);n=n.right;}return new RedBlackTreeIterator(this,stack);}});//Find the ith item in the tree
proto.at=function(idx){if(idx<0){return new RedBlackTreeIterator(this,[]);}var n=this.root;var stack=[];while(true){stack.push(n);if(n.left){if(idx=n.right._count){break;}n=n.right;}else{break;}}return new RedBlackTreeIterator(this,[]);};proto.ge=function(key){var cmp=this._compare;var n=this.root;var stack=[];var last_ptr=0;while(n){var d=cmp(key,n.key);stack.push(n);if(d<=0){last_ptr=stack.length;}if(d<=0){n=n.left;}else{n=n.right;}}stack.length=last_ptr;return new RedBlackTreeIterator(this,stack);};proto.gt=function(key){var cmp=this._compare;var n=this.root;var stack=[];var last_ptr=0;while(n){var d=cmp(key,n.key);stack.push(n);if(d<0){last_ptr=stack.length;}if(d<0){n=n.left;}else{n=n.right;}}stack.length=last_ptr;return new RedBlackTreeIterator(this,stack);};proto.lt=function(key){var cmp=this._compare;var n=this.root;var stack=[];var last_ptr=0;while(n){var d=cmp(key,n.key);stack.push(n);if(d>0){last_ptr=stack.length;}if(d<=0){n=n.left;}else{n=n.right;}}stack.length=last_ptr;return new RedBlackTreeIterator(this,stack);};proto.le=function(key){var cmp=this._compare;var n=this.root;var stack=[];var last_ptr=0;while(n){var d=cmp(key,n.key);stack.push(n);if(d>=0){last_ptr=stack.length;}if(d<0){n=n.left;}else{n=n.right;}}stack.length=last_ptr;return new RedBlackTreeIterator(this,stack);};//Finds the item with key if it exists
proto.find=function(key){var cmp=this._compare;var n=this.root;var stack=[];while(n){var d=cmp(key,n.key);stack.push(n);if(d===0){return new RedBlackTreeIterator(this,stack);}if(d<=0){n=n.left;}else{n=n.right;}}return new RedBlackTreeIterator(this,[]);};//Removes item with key from tree
proto.remove=function(key){var iter=this.find(key);if(iter){return iter.remove();}return this;};//Returns the item at `key`
proto.get=function(key){var cmp=this._compare;var n=this.root;while(n){var d=cmp(key,n.key);if(d===0){return n.value;}if(d<=0){n=n.left;}else{n=n.right;}}return;};//Iterator for red black tree
function RedBlackTreeIterator(tree,stack){this.tree=tree;this._stack=stack;}var iproto=RedBlackTreeIterator.prototype;//Test if iterator is valid
Object.defineProperty(iproto,"valid",{get:function(){return this._stack.length>0;}});//Node of the iterator
Object.defineProperty(iproto,"node",{get:function(){if(this._stack.length>0){return this._stack[this._stack.length-1];}return null;},enumerable:true});//Makes a copy of an iterator
iproto.clone=function(){return new RedBlackTreeIterator(this.tree,this._stack.slice());};//Swaps two nodes
function swapNode(n,v){n.key=v.key;n.value=v.value;n.left=v.left;n.right=v.right;n._color=v._color;n._count=v._count;}//Fix up a double black node in a tree
function fixDoubleBlack(stack){var n,p,s,z;for(var i=stack.length-1;i>=0;--i){n=stack[i];if(i===0){n._color=BLACK;return;}//console.log("visit node:", n.key, i, stack[i].key, stack[i-1].key)
p=stack[i-1];if(p.left===n){//console.log("left child")
s=p.right;if(s.right&&s.right._color===RED){//console.log("case 1: right sibling child red")
s=p.right=cloneNode(s);z=s.right=cloneNode(s.right);p.right=s.left;s.left=p;s.right=z;s._color=p._color;n._color=BLACK;p._color=BLACK;z._color=BLACK;recount(p);recount(s);if(i>1){var pp=stack[i-2];if(pp.left===p){pp.left=s;}else{pp.right=s;}}stack[i-1]=s;return;}else if(s.left&&s.left._color===RED){//console.log("case 1: left sibling child red")
s=p.right=cloneNode(s);z=s.left=cloneNode(s.left);p.right=z.left;s.left=z.right;z.left=p;z.right=s;z._color=p._color;p._color=BLACK;s._color=BLACK;n._color=BLACK;recount(p);recount(s);recount(z);if(i>1){var pp=stack[i-2];if(pp.left===p){pp.left=z;}else{pp.right=z;}}stack[i-1]=z;return;}if(s._color===BLACK){if(p._color===RED){//console.log("case 2: black sibling, red parent", p.right.value)
p._color=BLACK;p.right=repaint(RED,s);return;}else{//console.log("case 2: black sibling, black parent", p.right.value)
p.right=repaint(RED,s);continue;}}else{//console.log("case 3: red sibling")
s=cloneNode(s);p.right=s.left;s.left=p;s._color=p._color;p._color=RED;recount(p);recount(s);if(i>1){var pp=stack[i-2];if(pp.left===p){pp.left=s;}else{pp.right=s;}}stack[i-1]=s;stack[i]=p;if(i+11){var pp=stack[i-2];if(pp.right===p){pp.right=s;}else{pp.left=s;}}stack[i-1]=s;return;}else if(s.right&&s.right._color===RED){//console.log("case 1: right sibling child red")
s=p.left=cloneNode(s);z=s.right=cloneNode(s.right);p.left=z.right;s.right=z.left;z.right=p;z.left=s;z._color=p._color;p._color=BLACK;s._color=BLACK;n._color=BLACK;recount(p);recount(s);recount(z);if(i>1){var pp=stack[i-2];if(pp.right===p){pp.right=z;}else{pp.left=z;}}stack[i-1]=z;return;}if(s._color===BLACK){if(p._color===RED){//console.log("case 2: black sibling, red parent")
p._color=BLACK;p.left=repaint(RED,s);return;}else{//console.log("case 2: black sibling, black parent")
p.left=repaint(RED,s);continue;}}else{//console.log("case 3: red sibling")
s=cloneNode(s);p.left=s.right;s.right=p;s._color=p._color;p._color=RED;recount(p);recount(s);if(i>1){var pp=stack[i-2];if(pp.right===p){pp.right=s;}else{pp.left=s;}}stack[i-1]=s;stack[i]=p;if(i+1=0;--i){var n=stack[i];if(n.left===stack[i+1]){cstack[i]=new RBNode(n._color,n.key,n.value,cstack[i+1],n.right,n._count);}else{cstack[i]=new RBNode(n._color,n.key,n.value,n.left,cstack[i+1],n._count);}}//Get node
n=cstack[cstack.length-1];//console.log("start remove: ", n.value)
//If not leaf, then swap with previous node
if(n.left&&n.right){//console.log("moving to leaf")
//First walk to previous leaf
var split=cstack.length;n=n.left;while(n.right){cstack.push(n);n=n.right;}//Copy path to leaf
var v=cstack[split-1];cstack.push(new RBNode(n._color,v.key,v.value,n.left,n.right,n._count));cstack[split-1].key=n.key;cstack[split-1].value=n.value;//Fix up stack
for(var i=cstack.length-2;i>=split;--i){n=cstack[i];cstack[i]=new RBNode(n._color,n.key,n.value,n.left,cstack[i+1],n._count);}cstack[split-1].left=cstack[split];}//console.log("stack=", cstack.map(function(v) { return v.value }))
//Remove leaf node
n=cstack[cstack.length-1];if(n._color===RED){//Easy case: removing red leaf
//console.log("RED leaf")
var p=cstack[cstack.length-2];if(p.left===n){p.left=null;}else if(p.right===n){p.right=null;}cstack.pop();for(var i=0;i0){return this._stack[this._stack.length-1].key;}return;},enumerable:true});//Returns value
Object.defineProperty(iproto,"value",{get:function(){if(this._stack.length>0){return this._stack[this._stack.length-1].value;}return;},enumerable:true});//Returns the position of this iterator in the sorted list
Object.defineProperty(iproto,"index",{get:function(){var idx=0;var stack=this._stack;if(stack.length===0){var r=this.tree.root;if(r){return r._count;}return 0;}else if(stack[stack.length-1].left){idx=stack[stack.length-1].left._count;}for(var s=stack.length-2;s>=0;--s){if(stack[s+1]===stack[s].right){++idx;if(stack[s].left){idx+=stack[s].left._count;}}}return idx;},enumerable:true});//Advances iterator to next element in list
iproto.next=function(){var stack=this._stack;if(stack.length===0){return;}var n=stack[stack.length-1];if(n.right){n=n.right;while(n){stack.push(n);n=n.left;}}else{stack.pop();while(stack.length>0&&stack[stack.length-1].right===n){n=stack[stack.length-1];stack.pop();}}};//Checks if iterator is at end of tree
Object.defineProperty(iproto,"hasNext",{get:function(){var stack=this._stack;if(stack.length===0){return false;}if(stack[stack.length-1].right){return true;}for(var s=stack.length-1;s>0;--s){if(stack[s-1].left===stack[s]){return true;}}return false;}});//Update value
iproto.update=function(value){var stack=this._stack;if(stack.length===0){throw new Error("Can't update empty node!");}var cstack=new Array(stack.length);var n=stack[stack.length-1];cstack[cstack.length-1]=new RBNode(n._color,n.key,value,n.left,n.right,n._count);for(var i=stack.length-2;i>=0;--i){n=stack[i];if(n.left===stack[i+1]){cstack[i]=new RBNode(n._color,n.key,n.value,cstack[i+1],n.right,n._count);}else{cstack[i]=new RBNode(n._color,n.key,n.value,n.left,cstack[i+1],n._count);}}return new RedBlackTree(this.tree._compare,cstack[0]);};//Moves iterator backward one element
iproto.prev=function(){var stack=this._stack;if(stack.length===0){return;}var n=stack[stack.length-1];if(n.left){n=n.left;while(n){stack.push(n);n=n.right;}}else{stack.pop();while(stack.length>0&&stack[stack.length-1].left===n){n=stack[stack.length-1];stack.pop();}}};//Checks if iterator is at start of tree
Object.defineProperty(iproto,"hasPrev",{get:function(){var stack=this._stack;if(stack.length===0){return false;}if(stack[stack.length-1].left){return true;}for(var s=stack.length-1;s>0;--s){if(stack[s-1].right===stack[s]){return true;}}return false;}});//Default comparison function
function defaultCompare(a,b){if(ab){return 1;}return 0;}//Build a tree
function createRBTree(compare){return new RedBlackTree(compare||defaultCompare,null);}/***/},/***/3837:/***/function(module,__unused_webpack_exports,__nested_webpack_require_234991__){"use strict";module.exports=createAxes;var createText=__nested_webpack_require_234991__(4935);var createLines=__nested_webpack_require_234991__(501);var createBackground=__nested_webpack_require_234991__(5304);var getCubeProperties=__nested_webpack_require_234991__(6429);var Ticks=__nested_webpack_require_234991__(6444);var identity=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);function copyVec3(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];return a;}function Axes(gl){this.gl=gl;this.pixelRatio=1;this.bounds=[[-10,-10,-10],[10,10,10]];this.ticks=[[],[],[]];this.autoTicks=true;this.tickSpacing=[1,1,1];this.tickEnable=[true,true,true];this.tickFont=['sans-serif','sans-serif','sans-serif'];this.tickSize=[12,12,12];this.tickAngle=[0,0,0];this.tickAlign=['auto','auto','auto'];this.tickColor=[[0,0,0,1],[0,0,0,1],[0,0,0,1]];this.tickPad=[10,10,10];this.lastCubeProps={cubeEdges:[0,0,0],axis:[0,0,0]};this.labels=['x','y','z'];this.labelEnable=[true,true,true];this.labelFont='sans-serif';this.labelSize=[20,20,20];this.labelAngle=[0,0,0];this.labelAlign=['auto','auto','auto'];this.labelColor=[[0,0,0,1],[0,0,0,1],[0,0,0,1]];this.labelPad=[10,10,10];this.lineEnable=[true,true,true];this.lineMirror=[false,false,false];this.lineWidth=[1,1,1];this.lineColor=[[0,0,0,1],[0,0,0,1],[0,0,0,1]];this.lineTickEnable=[true,true,true];this.lineTickMirror=[false,false,false];this.lineTickLength=[0,0,0];this.lineTickWidth=[1,1,1];this.lineTickColor=[[0,0,0,1],[0,0,0,1],[0,0,0,1]];this.gridEnable=[true,true,true];this.gridWidth=[1,1,1];this.gridColor=[[0,0,0,1],[0,0,0,1],[0,0,0,1]];this.zeroEnable=[true,true,true];this.zeroLineColor=[[0,0,0,1],[0,0,0,1],[0,0,0,1]];this.zeroLineWidth=[2,2,2];this.backgroundEnable=[false,false,false];this.backgroundColor=[[0.8,0.8,0.8,0.5],[0.8,0.8,0.8,0.5],[0.8,0.8,0.8,0.5]];this._firstInit=true;this._text=null;this._lines=null;this._background=createBackground(gl);}var proto=Axes.prototype;proto.update=function(options){options=options||{};//Option parsing helper functions
function parseOption(nest,cons,name){if(name in options){var opt=options[name];var prev=this[name];var next;if(nest?Array.isArray(opt)&&Array.isArray(opt[0]):Array.isArray(opt)){this[name]=next=[cons(opt[0]),cons(opt[1]),cons(opt[2])];}else{this[name]=next=[cons(opt),cons(opt),cons(opt)];}for(var i=0;i<3;++i){if(next[i]!==prev[i]){return true;}}}return false;}var NUMBER=parseOption.bind(this,false,Number);var BOOLEAN=parseOption.bind(this,false,Boolean);var STRING=parseOption.bind(this,false,String);var COLOR=parseOption.bind(this,true,function(v){if(Array.isArray(v)){if(v.length===3){return[+v[0],+v[1],+v[2],1.0];}else if(v.length===4){return[+v[0],+v[1],+v[2],+v[3]];}}return[0,0,0,1];});//Tick marks and bounds
var nextTicks;var ticksUpdate=false;var boundsChanged=false;if('bounds'in options){var bounds=options.bounds;i_loop:for(var i=0;i<2;++i){for(var j=0;j<3;++j){if(bounds[i][j]!==this.bounds[i][j]){boundsChanged=true;}this.bounds[i][j]=bounds[i][j];}}}if('ticks'in options){nextTicks=options.ticks;ticksUpdate=true;this.autoTicks=false;for(var i=0;i<3;++i){this.tickSpacing[i]=0.0;}}else if(NUMBER('tickSpacing')){this.autoTicks=true;boundsChanged=true;}if(this._firstInit){if(!('ticks'in options||'tickSpacing'in options)){this.autoTicks=true;}//Force tick recomputation on first update
boundsChanged=true;ticksUpdate=true;this._firstInit=false;}if(boundsChanged&&this.autoTicks){nextTicks=Ticks.create(this.bounds,this.tickSpacing);ticksUpdate=true;}//Compare next ticks to previous ticks, only update if needed
if(ticksUpdate){for(var i=0;i<3;++i){nextTicks[i].sort(function(a,b){return a.x-b.x;});}if(Ticks.equal(nextTicks,this.ticks)){ticksUpdate=false;}else{this.ticks=nextTicks;}}//Parse tick properties
BOOLEAN('tickEnable');if(STRING('tickFont')){ticksUpdate=true;//If font changes, must rebuild vbo
}NUMBER('tickSize');NUMBER('tickAngle');NUMBER('tickPad');COLOR('tickColor');//Axis labels
var labelUpdate=STRING('labels');if(STRING('labelFont')){labelUpdate=true;}BOOLEAN('labelEnable');NUMBER('labelSize');NUMBER('labelPad');COLOR('labelColor');//Axis lines
BOOLEAN('lineEnable');BOOLEAN('lineMirror');NUMBER('lineWidth');COLOR('lineColor');//Axis line ticks
BOOLEAN('lineTickEnable');BOOLEAN('lineTickMirror');NUMBER('lineTickLength');NUMBER('lineTickWidth');COLOR('lineTickColor');//Grid lines
BOOLEAN('gridEnable');NUMBER('gridWidth');COLOR('gridColor');//Zero line
BOOLEAN('zeroEnable');COLOR('zeroLineColor');NUMBER('zeroLineWidth');//Background
BOOLEAN('backgroundEnable');COLOR('backgroundColor');//Update text if necessary
if(!this._text){this._text=createText(this.gl,this.bounds,this.labels,this.labelFont,this.ticks,this.tickFont);}else if(this._text&&(labelUpdate||ticksUpdate)){this._text.update(this.bounds,this.labels,this.labelFont,this.ticks,this.tickFont);}//Update lines if necessary
if(this._lines&&ticksUpdate){this._lines.dispose();this._lines=null;}if(!this._lines){this._lines=createLines(this.gl,this.bounds,this.ticks);}};function OffsetInfo(){this.primalOffset=[0,0,0];this.primalMinor=[0,0,0];this.mirrorOffset=[0,0,0];this.mirrorMinor=[0,0,0];}var LINE_OFFSET=[new OffsetInfo(),new OffsetInfo(),new OffsetInfo()];function computeLineOffset(result,i,bounds,cubeEdges,cubeAxis){var primalOffset=result.primalOffset;var primalMinor=result.primalMinor;var dualOffset=result.mirrorOffset;var dualMinor=result.mirrorMinor;var e=cubeEdges[i];//Calculate offsets
for(var j=0;j<3;++j){if(i===j){continue;}var a=primalOffset,b=dualOffset,c=primalMinor,d=dualMinor;if(e&1<0){c[j]=-1;d[j]=0;}else{c[j]=0;d[j]=+1;}}}var CUBE_ENABLE=[0,0,0];var DEFAULT_PARAMS={model:identity,view:identity,projection:identity,_ortho:false};proto.isOpaque=function(){return true;};proto.isTransparent=function(){return false;};proto.drawTransparent=function(params){};var ALIGN_OPTION_AUTO=0;// i.e. as defined in the shader the text would rotate to stay upwards range: [-90,90]
var PRIMAL_MINOR=[0,0,0];var MIRROR_MINOR=[0,0,0];var PRIMAL_OFFSET=[0,0,0];proto.draw=function(params){params=params||DEFAULT_PARAMS;var gl=this.gl;//Geometry for camera and axes
var model=params.model||identity;var view=params.view||identity;var projection=params.projection||identity;var bounds=this.bounds;var isOrtho=params._ortho||false;//Unpack axis info
var cubeParams=getCubeProperties(model,view,projection,bounds,isOrtho);var cubeEdges=cubeParams.cubeEdges;var cubeAxis=cubeParams.axis;var cx=view[12];var cy=view[13];var cz=view[14];var cw=view[15];var orthoFix=isOrtho?2:1;// double up padding for orthographic ticks & labels
var pixelScaleF=orthoFix*this.pixelRatio*(projection[3]*cx+projection[7]*cy+projection[11]*cz+projection[15]*cw)/gl.drawingBufferHeight;for(var i=0;i<3;++i){this.lastCubeProps.cubeEdges[i]=cubeEdges[i];this.lastCubeProps.axis[i]=cubeAxis[i];}//Compute axis info
var lineOffset=LINE_OFFSET;for(var i=0;i<3;++i){computeLineOffset(LINE_OFFSET[i],i,this.bounds,cubeEdges,cubeAxis);}//Set up state parameters
var gl=this.gl;//Draw background first
var cubeEnable=CUBE_ENABLE;for(var i=0;i<3;++i){if(this.backgroundEnable[i]){cubeEnable[i]=cubeAxis[i];}else{cubeEnable[i]=0;}}this._background.draw(model,view,projection,bounds,cubeEnable,this.backgroundColor);//Draw lines
this._lines.bind(model,view,projection,this);//First draw grid lines and zero lines
for(var i=0;i<3;++i){var x=[0,0,0];if(cubeAxis[i]>0){x[i]=bounds[1][i];}else{x[i]=bounds[0][i];}//Draw grid lines
for(var j=0;j<2;++j){var u=(i+1+j)%3;var v=(i+1+(j^1))%3;if(this.gridEnable[u]){this._lines.drawGrid(u,v,this.bounds,x,this.gridColor[u],this.gridWidth[u]*this.pixelRatio);}}//Draw zero lines (need to do this AFTER all grid lines are drawn)
for(var j=0;j<2;++j){var u=(i+1+j)%3;var v=(i+1+(j^1))%3;if(this.zeroEnable[v]){//Check if zero line in bounds
if(Math.min(bounds[0][v],bounds[1][v])<=0&&Math.max(bounds[0][v],bounds[1][v])>=0){this._lines.drawZero(u,v,this.bounds,x,this.zeroLineColor[v],this.zeroLineWidth[v]*this.pixelRatio);}}}}//Then draw axis lines and tick marks
for(var i=0;i<3;++i){//Draw axis lines
if(this.lineEnable[i]){this._lines.drawAxisLine(i,this.bounds,lineOffset[i].primalOffset,this.lineColor[i],this.lineWidth[i]*this.pixelRatio);}if(this.lineMirror[i]){this._lines.drawAxisLine(i,this.bounds,lineOffset[i].mirrorOffset,this.lineColor[i],this.lineWidth[i]*this.pixelRatio);}//Compute minor axes
var primalMinor=copyVec3(PRIMAL_MINOR,lineOffset[i].primalMinor);var mirrorMinor=copyVec3(MIRROR_MINOR,lineOffset[i].mirrorMinor);var tickLength=this.lineTickLength;for(var j=0;j<3;++j){var scaleFactor=pixelScaleF/model[5*j];primalMinor[j]*=tickLength[j]*scaleFactor;mirrorMinor[j]*=tickLength[j]*scaleFactor;}//Draw axis line ticks
if(this.lineTickEnable[i]){this._lines.drawAxisTicks(i,lineOffset[i].primalOffset,primalMinor,this.lineTickColor[i],this.lineTickWidth[i]*this.pixelRatio);}if(this.lineTickMirror[i]){this._lines.drawAxisTicks(i,lineOffset[i].mirrorOffset,mirrorMinor,this.lineTickColor[i],this.lineTickWidth[i]*this.pixelRatio);}}this._lines.unbind();//Draw text sprites
this._text.bind(model,view,projection,this.pixelRatio);var alignOpt;// options in shader are from this list {-1, 0, 1, 2, 3, ..., n}
// -1: backward compatible
// 0: raw data
// 1: auto align, free angles
// 2: auto align, horizontal or vertical
//3-n: auto align, round to n directions e.g. 12 -> round to angles with 30-degree steps
var hv_ratio=0.5;// can have an effect on the ratio between horizontals and verticals when using option 2
var enableAlign;var alignDir;function alignTo(i){alignDir=[0,0,0];alignDir[i]=1;}function solveTickAlignments(i,minor,major){var i1=(i+1)%3;var i2=(i+2)%3;var A=minor[i1];var B=minor[i2];var C=major[i1];var D=major[i2];if(A>0&&D>0){alignTo(i1);return;}else if(A>0&&D<0){alignTo(i1);return;}else if(A<0&&D>0){alignTo(i1);return;}else if(A<0&&D<0){alignTo(i1);return;}else if(B>0&&C>0){alignTo(i2);return;}else if(B>0&&C<0){alignTo(i2);return;}else if(B<0&&C>0){alignTo(i2);return;}else if(B<0&&C<0){alignTo(i2);return;}}for(var i=0;i<3;++i){var minor=lineOffset[i].primalMinor;var major=lineOffset[i].mirrorMinor;var offset=copyVec3(PRIMAL_OFFSET,lineOffset[i].primalOffset);for(var j=0;j<3;++j){if(this.lineTickEnable[i]){offset[j]+=pixelScaleF*minor[j]*Math.max(this.lineTickLength[j],0)/model[5*j];}}var axis=[0,0,0];axis[i]=1;//Draw tick text
if(this.tickEnable[i]){if(this.tickAngle[i]===-3600){this.tickAngle[i]=0;this.tickAlign[i]='auto';}else{this.tickAlign[i]=-1;}enableAlign=1;alignOpt=[this.tickAlign[i],hv_ratio,enableAlign];if(alignOpt[0]==='auto')alignOpt[0]=ALIGN_OPTION_AUTO;else alignOpt[0]=parseInt(''+alignOpt[0]);alignDir=[0,0,0];solveTickAlignments(i,minor,major);//Add tick padding
for(var j=0;j<3;++j){offset[j]+=pixelScaleF*minor[j]*this.tickPad[j]/model[5*j];}//Draw axis
this._text.drawTicks(i,this.tickSize[i],this.tickAngle[i],offset,this.tickColor[i],axis,alignDir,alignOpt);}//Draw labels
if(this.labelEnable[i]){enableAlign=0;alignDir=[0,0,0];if(this.labels[i].length>4){// for large label axis enable alignDir to axis
alignTo(i);enableAlign=1;}alignOpt=[this.labelAlign[i],hv_ratio,enableAlign];if(alignOpt[0]==='auto')alignOpt[0]=ALIGN_OPTION_AUTO;else alignOpt[0]=parseInt(''+alignOpt[0]);//Add label padding
for(var j=0;j<3;++j){offset[j]+=pixelScaleF*minor[j]*this.labelPad[j]/model[5*j];}offset[i]+=0.5*(bounds[0][i]+bounds[1][i]);//Draw axis
this._text.drawLabel(i,this.labelSize[i],this.labelAngle[i],offset,this.labelColor[i],[0,0,0],alignDir,alignOpt);}}this._text.unbind();};proto.dispose=function(){this._text.dispose();this._lines.dispose();this._background.dispose();this._lines=null;this._text=null;this._background=null;this.gl=null;};function createAxes(gl,options){var axes=new Axes(gl);axes.update(options);return axes;}/***/},/***/5304:/***/function(module,__unused_webpack_exports,__nested_webpack_require_246858__){"use strict";module.exports=createBackgroundCube;var createBuffer=__nested_webpack_require_246858__(2762);var createVAO=__nested_webpack_require_246858__(8116);var createShader=__nested_webpack_require_246858__(1879).bg;function BackgroundCube(gl,buffer,vao,shader){this.gl=gl;this.buffer=buffer;this.vao=vao;this.shader=shader;}var proto=BackgroundCube.prototype;proto.draw=function(model,view,projection,bounds,enable,colors){var needsBG=false;for(var i=0;i<3;++i){needsBG=needsBG||enable[i];}if(!needsBG){return;}var gl=this.gl;gl.enable(gl.POLYGON_OFFSET_FILL);gl.polygonOffset(1,2);this.shader.bind();this.shader.uniforms={model:model,view:view,projection:projection,bounds:bounds,enable:enable,colors:colors};this.vao.bind();this.vao.draw(this.gl.TRIANGLES,36);this.vao.unbind();gl.disable(gl.POLYGON_OFFSET_FILL);};proto.dispose=function(){this.vao.dispose();this.buffer.dispose();this.shader.dispose();};function createBackgroundCube(gl){//Create cube vertices
var vertices=[];var indices=[];var ptr=0;for(var d=0;d<3;++d){var u=(d+1)%3;var v=(d+2)%3;var x=[0,0,0];var c=[0,0,0];for(var s=-1;s<=1;s+=2){indices.push(ptr,ptr+2,ptr+1,ptr+1,ptr+2,ptr+3);x[d]=s;c[d]=s;for(var i=-1;i<=1;i+=2){x[u]=i;for(var j=-1;j<=1;j+=2){x[v]=j;vertices.push(x[0],x[1],x[2],c[0],c[1],c[2]);ptr+=1;}}//Swap u and v
var tt=u;u=v;v=tt;}}//Allocate buffer and vertex array
var buffer=createBuffer(gl,new Float32Array(vertices));var elements=createBuffer(gl,new Uint16Array(indices),gl.ELEMENT_ARRAY_BUFFER);var vao=createVAO(gl,[{buffer:buffer,type:gl.FLOAT,size:3,offset:0,stride:24},{buffer:buffer,type:gl.FLOAT,size:3,offset:12,stride:24}],elements);//Create shader object
var shader=createShader(gl);shader.attributes.position.location=0;shader.attributes.normal.location=1;return new BackgroundCube(gl,buffer,vao,shader);}/***/},/***/6429:/***/function(module,__unused_webpack_exports,__nested_webpack_require_248713__){"use strict";module.exports=getCubeEdges;var bits=__nested_webpack_require_248713__(8828);var multiply=__nested_webpack_require_248713__(6760);var splitPoly=__nested_webpack_require_248713__(5202);var orient=__nested_webpack_require_248713__(3250);var mvp=new Array(16);var pCubeVerts=new Array(8);var cubeVerts=new Array(8);var x=new Array(3);var zero3=[0,0,0];(function(){for(var i=0;i<8;++i){pCubeVerts[i]=[1,1,1,1];cubeVerts[i]=[1,1,1];}})();function transformHg(result,x,mat){for(var i=0;i<4;++i){result[i]=mat[12+i];for(var j=0;j<3;++j){result[i]+=x[j]*mat[4*j+i];}}}var FRUSTUM_PLANES=[[0,0,1,0,0],[0,0,-1,1,0],[0,-1,0,1,0],[0,1,0,1,0],[-1,0,0,1,0],[1,0,0,1,0]];function polygonArea(p){for(var i=0;io0){closest|=1<o0){closest|=1<cubeVerts[i][1]){bottom=i;}}//Find left/right neighbors of bottom vertex
var left=-1;for(var i=0;i<3;++i){var idx=bottom^1<cubeVerts[right][0]){right=idx;}}//Determine edge axis coordinates
var cubeEdges=CUBE_EDGES;cubeEdges[0]=cubeEdges[1]=cubeEdges[2]=0;cubeEdges[bits.log2(left^bottom)]=bottom&left;cubeEdges[bits.log2(bottom^right)]=bottom&right;var top=right^7;if(top===closest||top===farthest){top=left^7;cubeEdges[bits.log2(right^top)]=top&right;}else{cubeEdges[bits.log2(left^top)]=top&left;}//Determine visible faces
var axis=CUBE_AXIS;var cutCorner=closest;for(var d=0;d<3;++d){if(cutCorner&1< HALF_PI) && (b <= ONE_AND_HALF_PI)) ?\n b - PI :\n b;\n}\n\nfloat look_horizontal_or_vertical(float a, float ratio) {\n // ratio controls the ratio between being horizontal to (vertical + horizontal)\n // if ratio is set to 0.5 then it is 50%, 50%.\n // when using a higher ratio e.g. 0.75 the result would\n // likely be more horizontal than vertical.\n\n float b = positive_angle(a);\n\n return\n (b < ( ratio) * HALF_PI) ? 0.0 :\n (b < (2.0 - ratio) * HALF_PI) ? -HALF_PI :\n (b < (2.0 + ratio) * HALF_PI) ? 0.0 :\n (b < (4.0 - ratio) * HALF_PI) ? HALF_PI :\n 0.0;\n}\n\nfloat roundTo(float a, float b) {\n return float(b * floor((a + 0.5 * b) / b));\n}\n\nfloat look_round_n_directions(float a, int n) {\n float b = positive_angle(a);\n float div = TWO_PI / float(n);\n float c = roundTo(b, div);\n return look_upwards(c);\n}\n\nfloat applyAlignOption(float rawAngle, float delta) {\n return\n (option > 2) ? look_round_n_directions(rawAngle + delta, option) : // option 3-n: round to n directions\n (option == 2) ? look_horizontal_or_vertical(rawAngle + delta, hv_ratio) : // horizontal or vertical\n (option == 1) ? rawAngle + delta : // use free angle, and flip to align with one direction of the axis\n (option == 0) ? look_upwards(rawAngle) : // use free angle, and stay upwards\n (option ==-1) ? 0.0 : // useful for backward compatibility, all texts remains horizontal\n rawAngle; // otherwise return back raw input angle\n}\n\nbool isAxisTitle = (axis.x == 0.0) &&\n (axis.y == 0.0) &&\n (axis.z == 0.0);\n\nvoid main() {\n //Compute world offset\n float axisDistance = position.z;\n vec3 dataPosition = axisDistance * axis + offset;\n\n float beta = angle; // i.e. user defined attributes for each tick\n\n float axisAngle;\n float clipAngle;\n float flip;\n\n if (enableAlign) {\n axisAngle = (isAxisTitle) ? HALF_PI :\n computeViewAngle(dataPosition, dataPosition + axis);\n clipAngle = computeViewAngle(dataPosition, dataPosition + alignDir);\n\n axisAngle += (sin(axisAngle) < 0.0) ? PI : 0.0;\n clipAngle += (sin(clipAngle) < 0.0) ? PI : 0.0;\n\n flip = (dot(vec2(cos(axisAngle), sin(axisAngle)),\n vec2(sin(clipAngle),-cos(clipAngle))) > 0.0) ? 1.0 : 0.0;\n\n beta += applyAlignOption(clipAngle, flip * PI);\n }\n\n //Compute plane offset\n vec2 planeCoord = position.xy * pixelScale;\n\n mat2 planeXform = scale * mat2(\n cos(beta), sin(beta),\n -sin(beta), cos(beta)\n );\n\n vec2 viewOffset = 2.0 * planeXform * planeCoord / resolution;\n\n //Compute clip position\n vec3 clipPosition = project(dataPosition);\n\n //Apply text offset in clip coordinates\n clipPosition += vec3(viewOffset, 0.0);\n\n //Done\n gl_Position = vec4(clipPosition, 1.0);\n}"]);var textFrag=glslify(["precision highp float;\n#define GLSLIFY 1\n\nuniform vec4 color;\nvoid main() {\n gl_FragColor = color;\n}"]);exports.Q=function(gl){return createShader(gl,textVert,textFrag,null,[{name:'position',type:'vec3'}]);};var bgVert=glslify(["precision highp float;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute vec3 normal;\n\nuniform mat4 model, view, projection;\nuniform vec3 enable;\nuniform vec3 bounds[2];\n\nvarying vec3 colorChannel;\n\nvoid main() {\n\n vec3 signAxis = sign(bounds[1] - bounds[0]);\n\n vec3 realNormal = signAxis * normal;\n\n if(dot(realNormal, enable) > 0.0) {\n vec3 minRange = min(bounds[0], bounds[1]);\n vec3 maxRange = max(bounds[0], bounds[1]);\n vec3 nPosition = mix(minRange, maxRange, 0.5 * (position + 1.0));\n gl_Position = projection * view * model * vec4(nPosition, 1.0);\n } else {\n gl_Position = vec4(0,0,0,0);\n }\n\n colorChannel = abs(realNormal);\n}"]);var bgFrag=glslify(["precision highp float;\n#define GLSLIFY 1\n\nuniform vec4 colors[3];\n\nvarying vec3 colorChannel;\n\nvoid main() {\n gl_FragColor = colorChannel.x * colors[0] +\n colorChannel.y * colors[1] +\n colorChannel.z * colors[2];\n}"]);exports.bg=function(gl){return createShader(gl,bgVert,bgFrag,null,[{name:'position',type:'vec3'},{name:'normal',type:'vec3'}]);};/***/},/***/4935:/***/function(module,__unused_webpack_exports,__nested_webpack_require_263397__){"use strict";module.exports=createTextSprites;var createBuffer=__nested_webpack_require_263397__(2762);var createVAO=__nested_webpack_require_263397__(8116);var vectorizeText=__nested_webpack_require_263397__(4359);var createShader=__nested_webpack_require_263397__(1879)/* .text */.Q;var globals=window||process.global||{};var __TEXT_CACHE=globals.__TEXT_CACHE||{};globals.__TEXT_CACHE={};//Vertex buffer format for text is:
//
/// [x,y,z] = Spatial coordinate
//
var VERTEX_SIZE=3;function TextSprites(gl,shader,buffer,vao){this.gl=gl;this.shader=shader;this.buffer=buffer;this.vao=vao;this.tickOffset=this.tickCount=this.labelOffset=this.labelCount=null;}var proto=TextSprites.prototype;//Bind textures for rendering
var SHAPE=[0,0];proto.bind=function(model,view,projection,pixelScale){this.vao.bind();this.shader.bind();var uniforms=this.shader.uniforms;uniforms.model=model;uniforms.view=view;uniforms.projection=projection;uniforms.pixelScale=pixelScale;SHAPE[0]=this.gl.drawingBufferWidth;SHAPE[1]=this.gl.drawingBufferHeight;this.shader.uniforms.resolution=SHAPE;};proto.unbind=function(){this.vao.unbind();};proto.update=function(bounds,labels,labelFont,ticks,tickFont){var data=[];function addItem(t,text,font,size,lineSpacing,styletags){var fontcache=__TEXT_CACHE[font];if(!fontcache){fontcache=__TEXT_CACHE[font]={};}var mesh=fontcache[text];if(!mesh){mesh=fontcache[text]=tryVectorizeText(text,{triangles:true,font:font,textAlign:'center',textBaseline:'middle',lineSpacing:lineSpacing,styletags:styletags});}var scale=(size||12)/12;var positions=mesh.positions;var cells=mesh.cells;for(var i=0,nc=cells.length;i=0;--j){var p=positions[c[j]];data.push(scale*p[0],-scale*p[1],t);}}}//Generate sprites for all 3 axes, store data in texture atlases
var tickOffset=[0,0,0];var tickCount=[0,0,0];var labelOffset=[0,0,0];var labelCount=[0,0,0];var lineSpacing=1.25;var styletags={breaklines:true,bolds:true,italics:true,subscripts:true,superscripts:true};for(var d=0;d<3;++d){//Generate label
labelOffset[d]=data.length/VERTEX_SIZE|0;addItem(0.5*(bounds[0][d]+bounds[1][d]),labels[d],labelFont[d],12,// labelFontSize
lineSpacing,styletags);labelCount[d]=(data.length/VERTEX_SIZE|0)-labelOffset[d];//Generate sprites for tick marks
tickOffset[d]=data.length/VERTEX_SIZE|0;for(var i=0;i=0){sigFigs=stepStr.length-u-1;}var shift=Math.pow(10,sigFigs);var x=Math.round(spacing*i*shift);var xstr=x+"";if(xstr.indexOf("e")>=0){return xstr;}var xi=x/shift,xf=x%shift;if(x<0){xi=-Math.ceil(xi)|0;xf=-xf|0;}else{xi=Math.floor(xi)|0;xf=xf|0;}var xis=""+xi;if(x<0){xis="-"+xis;}if(sigFigs){var xs=""+xf;while(xs.length=bounds[0][d];--t){ticks.push({x:t*tickSpacing[d],text:prettyPrint(tickSpacing[d],t)});}array.push(ticks);}return array;}function ticksEqual(ticksA,ticksB){for(var i=0;i<3;++i){if(ticksA[i].length!==ticksB[i].length){return false;}for(var j=0;jlen){throw new Error("gl-buffer: If resizing buffer, must not specify offset");}gl.bufferSubData(type,offset,data);return len;}function makeScratchTypeArray(array,dtype){var res=pool.malloc(array.length,dtype);var n=array.length;for(var i=0;i=0;--i){if(stride[i]!==n){return false;}n*=shape[i];}return true;}proto.update=function(array,offset){if(typeof offset!=="number"){offset=-1;}this.bind();if(typeof array==="object"&&typeof array.shape!=="undefined"){//ndarray
var dtype=array.dtype;if(SUPPORTED_TYPES.indexOf(dtype)<0){dtype="float32";}if(this.type===this.gl.ELEMENT_ARRAY_BUFFER){var ext=gl.getExtension('OES_element_index_uint');if(ext&&dtype!=="uint16"){dtype="uint32";}else{dtype="uint16";}}if(dtype===array.dtype&&isPacked(array.shape,array.stride)){if(array.offset===0&&array.data.length===array.shape[0]){this.length=updateTypeArray(this.gl,this.type,this.length,this.usage,array.data,offset);}else{this.length=updateTypeArray(this.gl,this.type,this.length,this.usage,array.data.subarray(array.offset,array.shape[0]),offset);}}else{var tmp=pool.malloc(array.size,dtype);var ndt=ndarray(tmp,array.shape);ops.assign(ndt,array);if(offset<0){this.length=updateTypeArray(this.gl,this.type,this.length,this.usage,tmp,offset);}else{this.length=updateTypeArray(this.gl,this.type,this.length,this.usage,tmp.subarray(0,array.size),offset);}pool.free(tmp);}}else if(Array.isArray(array)){//Vanilla array
var t;if(this.type===this.gl.ELEMENT_ARRAY_BUFFER){t=makeScratchTypeArray(array,"uint16");}else{t=makeScratchTypeArray(array,"float32");}if(offset<0){this.length=updateTypeArray(this.gl,this.type,this.length,this.usage,t,offset);}else{this.length=updateTypeArray(this.gl,this.type,this.length,this.usage,t.subarray(0,array.length),offset);}pool.free(t);}else if(typeof array==="object"&&typeof array.length==="number"){//Typed array
this.length=updateTypeArray(this.gl,this.type,this.length,this.usage,array,offset);}else if(typeof array==="number"||array===undefined){//Number/default
if(offset>=0){throw new Error("gl-buffer: Cannot specify offset when resizing buffer");}array=array|0;if(array<=0){array=1;}this.gl.bufferData(this.type,array|0,this.usage);this.length=array;}else{//Error, case should not happen
throw new Error("gl-buffer: Invalid data type");}};function createBuffer(gl,data,type,usage){type=type||gl.ARRAY_BUFFER;usage=usage||gl.DYNAMIC_DRAW;if(type!==gl.ARRAY_BUFFER&&type!==gl.ELEMENT_ARRAY_BUFFER){throw new Error("gl-buffer: Invalid type for webgl buffer, must be either gl.ARRAY_BUFFER or gl.ELEMENT_ARRAY_BUFFER");}if(usage!==gl.DYNAMIC_DRAW&&usage!==gl.STATIC_DRAW&&usage!==gl.STREAM_DRAW){throw new Error("gl-buffer: Invalid usage for buffer, must be either gl.DYNAMIC_DRAW, gl.STATIC_DRAW or gl.STREAM_DRAW");}var handle=gl.createBuffer();var result=new GLBuffer(gl,type,handle,0,usage);result.update(data);return result;}module.exports=createBuffer;/***/},/***/6405:/***/function(module,__unused_webpack_exports,__nested_webpack_require_275746__){"use strict";var vec3=__nested_webpack_require_275746__(2931);module.exports=function(vectorfield,bounds){var positions=vectorfield.positions;var vectors=vectorfield.vectors;var geo={positions:[],vertexIntensity:[],vertexIntensityBounds:vectorfield.vertexIntensityBounds,vectors:[],cells:[],coneOffset:vectorfield.coneOffset,colormap:vectorfield.colormap};if(vectorfield.positions.length===0){if(bounds){bounds[0]=[0,0,0];bounds[1]=[0,0,0];}return geo;}// Compute bounding box for the dataset.
// Compute maximum velocity for the dataset to use for scaling the cones.
var maxNorm=0;var minX=Infinity,maxX=-Infinity;var minY=Infinity,maxY=-Infinity;var minZ=Infinity,maxZ=-Infinity;var p2=null;var u2=null;var positionVectors=[];var vectorScale=Infinity;var skipIt=false;var rawSizemodemode=vectorfield.coneSizemode==='raw';for(var i=0;imaxNorm){maxNorm=vec3.length(u);}if(i&&!rawSizemodemode){// Find vector scale [w/ units of time] using "successive" positions
// (not "adjacent" with would be O(n^2)),
//
// The vector scale corresponds to the minimum "time" to travel across two
// two adjacent positions at the average velocity of those two adjacent positions
var q=2*vec3.distance(p2,p)/(vec3.length(u2)+vec3.length(u));if(q){vectorScale=Math.min(vectorScale,q);skipIt=false;}else{skipIt=true;}}if(!skipIt){p2=p;u2=u;}positionVectors.push(u);}var minV=[minX,minY,minZ];var maxV=[maxX,maxY,maxZ];if(bounds){bounds[0]=minV;bounds[1]=maxV;}if(maxNorm===0){maxNorm=1;}// Inverted max norm would map vector with norm maxNorm to 1 coord space units in length
var invertedMaxNorm=1/maxNorm;if(!isFinite(vectorScale)){vectorScale=1.0;}geo.vectorScale=vectorScale;var coneScale=vectorfield.coneSize||(rawSizemodemode?1:0.5);if(vectorfield.absoluteConeSize){coneScale=vectorfield.absoluteConeSize*invertedMaxNorm;}geo.coneScale=coneScale;// Build the cone model.
for(var i=0,j=0;i=1;};proto.isTransparent=function(){return this.opacity<1;};proto.pickSlots=1;proto.setPickBase=function(id){this.pickId=id;};function genColormap(param){var colors=colormap({colormap:param,nshades:256,format:'rgba'});var result=new Uint8Array(256*4);for(var i=0;i<256;++i){var c=colors[i];for(var j=0;j<3;++j){result[4*i+j]=c[j];}result[4*i+3]=c[3]*255;}return ndarray(result,[256,256,4],[4,0,1]);}function takeZComponent(array){var n=array.length;var result=new Array(n);for(var i=0;i0){var shader=this.triShader;shader.bind();shader.uniforms=uniforms;this.triangleVAO.bind();gl.drawArrays(gl.TRIANGLES,0,this.triangleCount*3);this.triangleVAO.unbind();}};proto.drawPick=function(params){params=params||{};var gl=this.gl;var model=params.model||IDENTITY;var view=params.view||IDENTITY;var projection=params.projection||IDENTITY;var clipBounds=[[-1e6,-1e6,-1e6],[1e6,1e6,1e6]];for(var i=0;i<3;++i){clipBounds[0][i]=Math.max(clipBounds[0][i],this.clipBounds[0][i]);clipBounds[1][i]=Math.min(clipBounds[1][i],this.clipBounds[1][i]);}//Save camera parameters
this._model=[].slice.call(model);this._view=[].slice.call(view);this._projection=[].slice.call(projection);this._resolution=[gl.drawingBufferWidth,gl.drawingBufferHeight];var uniforms={model:model,view:view,projection:projection,clipBounds:clipBounds,tubeScale:this.tubeScale,vectorScale:this.vectorScale,coneScale:this.coneScale,coneOffset:this.coneOffset,pickId:this.pickId/255.0};var shader=this.pickShader;shader.bind();shader.uniforms=uniforms;if(this.triangleCount>0){this.triangleVAO.bind();gl.drawArrays(gl.TRIANGLES,0,this.triangleCount*3);this.triangleVAO.unbind();}};proto.pick=function(pickData){if(!pickData){return null;}if(pickData.id!==this.pickId){return null;}var cellId=pickData.value[0]+256*pickData.value[1]+65536*pickData.value[2];var cell=this.cells[cellId];var pos=this.positions[cell[1]].slice(0,3);var result={position:pos,dataCoordinate:pos,index:Math.floor(cell[1]/48)};if(this.traceType==='cone'){result.index=Math.floor(cell[1]/48);}else if(this.traceType==='streamtube'){result.intensity=this.intensity[cell[1]];result.velocity=this.vectors[cell[1]].slice(0,3);result.divergence=this.vectors[cell[1]][3];result.index=cellId;}return result;};proto.dispose=function(){this.texture.dispose();this.triShader.dispose();this.pickShader.dispose();this.triangleVAO.dispose();this.trianglePositions.dispose();this.triangleVectors.dispose();this.triangleColors.dispose();this.triangleUVs.dispose();this.triangleIds.dispose();};function createMeshShader(gl,shaders){var shader=createShader(gl,shaders.meshShader.vertex,shaders.meshShader.fragment,null,shaders.meshShader.attributes);shader.attributes.position.location=0;shader.attributes.color.location=2;shader.attributes.uv.location=3;shader.attributes.vector.location=4;return shader;}function createPickShader(gl,shaders){var shader=createShader(gl,shaders.pickShader.vertex,shaders.pickShader.fragment,null,shaders.pickShader.attributes);shader.attributes.position.location=0;shader.attributes.id.location=1;shader.attributes.vector.location=4;return shader;}function createVectorMesh(gl,params,opts){var shaders=opts.shaders;if(arguments.length===1){params=gl;gl=params.gl;}var triShader=createMeshShader(gl,shaders);var pickShader=createPickShader(gl,shaders);var meshTexture=createTexture(gl,ndarray(new Uint8Array([255,255,255,255]),[1,1,4]));meshTexture.generateMipmap();meshTexture.minFilter=gl.LINEAR_MIPMAP_LINEAR;meshTexture.magFilter=gl.LINEAR;var trianglePositions=createBuffer(gl);var triangleVectors=createBuffer(gl);var triangleColors=createBuffer(gl);var triangleUVs=createBuffer(gl);var triangleIds=createBuffer(gl);var triangleVAO=createVAO(gl,[{buffer:trianglePositions,type:gl.FLOAT,size:4},{buffer:triangleIds,type:gl.UNSIGNED_BYTE,size:4,normalized:true},{buffer:triangleColors,type:gl.FLOAT,size:4},{buffer:triangleUVs,type:gl.FLOAT,size:2},{buffer:triangleVectors,type:gl.FLOAT,size:4}]);var mesh=new VectorMesh(gl,meshTexture,triShader,pickShader,trianglePositions,triangleVectors,triangleIds,triangleColors,triangleUVs,triangleVAO,opts.traceType||'cone');mesh.update(params);return mesh;}module.exports=createVectorMesh;/***/},/***/614:/***/function(__unused_webpack_module,exports,__nested_webpack_require_289417__){var glslify=__nested_webpack_require_289417__(3236);var triVertSrc=glslify(["precision highp float;\n\nprecision highp float;\n#define GLSLIFY 1\n\nvec3 getOrthogonalVector(vec3 v) {\n // Return up-vector for only-z vector.\n // Return ax + by + cz = 0, a point that lies on the plane that has v as a normal and that isn't (0,0,0).\n // From the above if-statement we have ||a|| > 0 U ||b|| > 0.\n // Assign z = 0, x = -b, y = a:\n // a*-b + b*a + c*0 = -ba + ba + 0 = 0\n if (v.x*v.x > v.z*v.z || v.y*v.y > v.z*v.z) {\n return normalize(vec3(-v.y, v.x, 0.0));\n } else {\n return normalize(vec3(0.0, v.z, -v.y));\n }\n}\n\n// Calculate the cone vertex and normal at the given index.\n//\n// The returned vertex is for a cone with its top at origin and height of 1.0,\n// pointing in the direction of the vector attribute.\n//\n// Each cone is made up of a top vertex, a center base vertex and base perimeter vertices.\n// These vertices are used to make up the triangles of the cone by the following:\n// segment + 0 top vertex\n// segment + 1 perimeter vertex a+1\n// segment + 2 perimeter vertex a\n// segment + 3 center base vertex\n// segment + 4 perimeter vertex a\n// segment + 5 perimeter vertex a+1\n// Where segment is the number of the radial segment * 6 and a is the angle at that radial segment.\n// To go from index to segment, floor(index / 6)\n// To go from segment to angle, 2*pi * (segment/segmentCount)\n// To go from index to segment index, index - (segment*6)\n//\nvec3 getConePosition(vec3 d, float rawIndex, float coneOffset, out vec3 normal) {\n\n const float segmentCount = 8.0;\n\n float index = rawIndex - floor(rawIndex /\n (segmentCount * 6.0)) *\n (segmentCount * 6.0);\n\n float segment = floor(0.001 + index/6.0);\n float segmentIndex = index - (segment*6.0);\n\n normal = -normalize(d);\n\n if (segmentIndex > 2.99 && segmentIndex < 3.01) {\n return mix(vec3(0.0), -d, coneOffset);\n }\n\n float nextAngle = (\n (segmentIndex > 0.99 && segmentIndex < 1.01) ||\n (segmentIndex > 4.99 && segmentIndex < 5.01)\n ) ? 1.0 : 0.0;\n float angle = 2.0 * 3.14159 * ((segment + nextAngle) / segmentCount);\n\n vec3 v1 = mix(d, vec3(0.0), coneOffset);\n vec3 v2 = v1 - d;\n\n vec3 u = getOrthogonalVector(d);\n vec3 v = normalize(cross(u, d));\n\n vec3 x = u * cos(angle) * length(d)*0.25;\n vec3 y = v * sin(angle) * length(d)*0.25;\n vec3 v3 = v2 + x + y;\n if (segmentIndex < 3.0) {\n vec3 tx = u * sin(angle);\n vec3 ty = v * -cos(angle);\n vec3 tangent = tx + ty;\n normal = normalize(cross(v3 - v1, tangent));\n }\n\n if (segmentIndex == 0.0) {\n return mix(d, vec3(0.0), coneOffset);\n }\n return v3;\n}\n\nattribute vec3 vector;\nattribute vec4 color, position;\nattribute vec2 uv;\n\nuniform float vectorScale, coneScale, coneOffset;\nuniform mat4 model, view, projection, inverseModel;\nuniform vec3 eyePosition, lightPosition;\n\nvarying vec3 f_normal, f_lightDirection, f_eyeDirection, f_data, f_position;\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n // Scale the vector magnitude to stay constant with\n // model & view changes.\n vec3 normal;\n vec3 XYZ = getConePosition(mat3(model) * ((vectorScale * coneScale) * vector), position.w, coneOffset, normal);\n vec4 conePosition = model * vec4(position.xyz, 1.0) + vec4(XYZ, 0.0);\n\n //Lighting geometry parameters\n vec4 cameraCoordinate = view * conePosition;\n cameraCoordinate.xyz /= cameraCoordinate.w;\n f_lightDirection = lightPosition - cameraCoordinate.xyz;\n f_eyeDirection = eyePosition - cameraCoordinate.xyz;\n f_normal = normalize((vec4(normal, 0.0) * inverseModel).xyz);\n\n // vec4 m_position = model * vec4(conePosition, 1.0);\n vec4 t_position = view * conePosition;\n gl_Position = projection * t_position;\n\n f_color = color;\n f_data = conePosition.xyz;\n f_position = position.xyz;\n f_uv = uv;\n}\n"]);var triFragSrc=glslify(["#extension GL_OES_standard_derivatives : enable\n\nprecision highp float;\n#define GLSLIFY 1\n\nfloat beckmannDistribution(float x, float roughness) {\n float NdotH = max(x, 0.0001);\n float cos2Alpha = NdotH * NdotH;\n float tan2Alpha = (cos2Alpha - 1.0) / cos2Alpha;\n float roughness2 = roughness * roughness;\n float denom = 3.141592653589793 * roughness2 * cos2Alpha * cos2Alpha;\n return exp(tan2Alpha / roughness2) / denom;\n}\n\nfloat cookTorranceSpecular(\n vec3 lightDirection,\n vec3 viewDirection,\n vec3 surfaceNormal,\n float roughness,\n float fresnel) {\n\n float VdotN = max(dot(viewDirection, surfaceNormal), 0.0);\n float LdotN = max(dot(lightDirection, surfaceNormal), 0.0);\n\n //Half angle vector\n vec3 H = normalize(lightDirection + viewDirection);\n\n //Geometric term\n float NdotH = max(dot(surfaceNormal, H), 0.0);\n float VdotH = max(dot(viewDirection, H), 0.000001);\n float LdotH = max(dot(lightDirection, H), 0.000001);\n float G1 = (2.0 * NdotH * VdotN) / VdotH;\n float G2 = (2.0 * NdotH * LdotN) / LdotH;\n float G = min(1.0, min(G1, G2));\n \n //Distribution term\n float D = beckmannDistribution(NdotH, roughness);\n\n //Fresnel term\n float F = pow(1.0 - VdotN, fresnel);\n\n //Multiply terms and done\n return G * F * D / max(3.14159265 * VdotN, 0.000001);\n}\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nuniform vec3 clipBounds[2];\nuniform float roughness, fresnel, kambient, kdiffuse, kspecular, opacity;\nuniform sampler2D texture;\n\nvarying vec3 f_normal, f_lightDirection, f_eyeDirection, f_data, f_position;\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n if (outOfRange(clipBounds[0], clipBounds[1], f_position)) discard;\n vec3 N = normalize(f_normal);\n vec3 L = normalize(f_lightDirection);\n vec3 V = normalize(f_eyeDirection);\n\n if(gl_FrontFacing) {\n N = -N;\n }\n\n float specular = min(1.0, max(0.0, cookTorranceSpecular(L, V, N, roughness, fresnel)));\n float diffuse = min(kambient + kdiffuse * max(dot(N, L), 0.0), 1.0);\n\n vec4 surfaceColor = f_color * texture2D(texture, f_uv);\n vec4 litColor = surfaceColor.a * vec4(diffuse * surfaceColor.rgb + kspecular * vec3(1,1,1) * specular, 1.0);\n\n gl_FragColor = litColor * opacity;\n}\n"]);var pickVertSrc=glslify(["precision highp float;\n\nprecision highp float;\n#define GLSLIFY 1\n\nvec3 getOrthogonalVector(vec3 v) {\n // Return up-vector for only-z vector.\n // Return ax + by + cz = 0, a point that lies on the plane that has v as a normal and that isn't (0,0,0).\n // From the above if-statement we have ||a|| > 0 U ||b|| > 0.\n // Assign z = 0, x = -b, y = a:\n // a*-b + b*a + c*0 = -ba + ba + 0 = 0\n if (v.x*v.x > v.z*v.z || v.y*v.y > v.z*v.z) {\n return normalize(vec3(-v.y, v.x, 0.0));\n } else {\n return normalize(vec3(0.0, v.z, -v.y));\n }\n}\n\n// Calculate the cone vertex and normal at the given index.\n//\n// The returned vertex is for a cone with its top at origin and height of 1.0,\n// pointing in the direction of the vector attribute.\n//\n// Each cone is made up of a top vertex, a center base vertex and base perimeter vertices.\n// These vertices are used to make up the triangles of the cone by the following:\n// segment + 0 top vertex\n// segment + 1 perimeter vertex a+1\n// segment + 2 perimeter vertex a\n// segment + 3 center base vertex\n// segment + 4 perimeter vertex a\n// segment + 5 perimeter vertex a+1\n// Where segment is the number of the radial segment * 6 and a is the angle at that radial segment.\n// To go from index to segment, floor(index / 6)\n// To go from segment to angle, 2*pi * (segment/segmentCount)\n// To go from index to segment index, index - (segment*6)\n//\nvec3 getConePosition(vec3 d, float rawIndex, float coneOffset, out vec3 normal) {\n\n const float segmentCount = 8.0;\n\n float index = rawIndex - floor(rawIndex /\n (segmentCount * 6.0)) *\n (segmentCount * 6.0);\n\n float segment = floor(0.001 + index/6.0);\n float segmentIndex = index - (segment*6.0);\n\n normal = -normalize(d);\n\n if (segmentIndex > 2.99 && segmentIndex < 3.01) {\n return mix(vec3(0.0), -d, coneOffset);\n }\n\n float nextAngle = (\n (segmentIndex > 0.99 && segmentIndex < 1.01) ||\n (segmentIndex > 4.99 && segmentIndex < 5.01)\n ) ? 1.0 : 0.0;\n float angle = 2.0 * 3.14159 * ((segment + nextAngle) / segmentCount);\n\n vec3 v1 = mix(d, vec3(0.0), coneOffset);\n vec3 v2 = v1 - d;\n\n vec3 u = getOrthogonalVector(d);\n vec3 v = normalize(cross(u, d));\n\n vec3 x = u * cos(angle) * length(d)*0.25;\n vec3 y = v * sin(angle) * length(d)*0.25;\n vec3 v3 = v2 + x + y;\n if (segmentIndex < 3.0) {\n vec3 tx = u * sin(angle);\n vec3 ty = v * -cos(angle);\n vec3 tangent = tx + ty;\n normal = normalize(cross(v3 - v1, tangent));\n }\n\n if (segmentIndex == 0.0) {\n return mix(d, vec3(0.0), coneOffset);\n }\n return v3;\n}\n\nattribute vec4 vector;\nattribute vec4 position;\nattribute vec4 id;\n\nuniform mat4 model, view, projection;\nuniform float vectorScale, coneScale, coneOffset;\n\nvarying vec3 f_position;\nvarying vec4 f_id;\n\nvoid main() {\n vec3 normal;\n vec3 XYZ = getConePosition(mat3(model) * ((vectorScale * coneScale) * vector.xyz), position.w, coneOffset, normal);\n vec4 conePosition = model * vec4(position.xyz, 1.0) + vec4(XYZ, 0.0);\n gl_Position = projection * view * conePosition;\n f_id = id;\n f_position = position.xyz;\n}\n"]);var pickFragSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nuniform vec3 clipBounds[2];\nuniform float pickId;\n\nvarying vec3 f_position;\nvarying vec4 f_id;\n\nvoid main() {\n if (outOfRange(clipBounds[0], clipBounds[1], f_position)) discard;\n\n gl_FragColor = vec4(pickId, f_id.xyz);\n}"]);exports.meshShader={vertex:triVertSrc,fragment:triFragSrc,attributes:[{name:'position',type:'vec4'},{name:'color',type:'vec4'},{name:'uv',type:'vec2'},{name:'vector',type:'vec3'}]};exports.pickShader={vertex:pickVertSrc,fragment:pickFragSrc,attributes:[{name:'position',type:'vec4'},{name:'id',type:'vec4'},{name:'vector',type:'vec3'}]};/***/},/***/737:/***/function(module){module.exports={0:'NONE',1:'ONE',2:'LINE_LOOP',3:'LINE_STRIP',4:'TRIANGLES',5:'TRIANGLE_STRIP',6:'TRIANGLE_FAN',256:'DEPTH_BUFFER_BIT',512:'NEVER',513:'LESS',514:'EQUAL',515:'LEQUAL',516:'GREATER',517:'NOTEQUAL',518:'GEQUAL',519:'ALWAYS',768:'SRC_COLOR',769:'ONE_MINUS_SRC_COLOR',770:'SRC_ALPHA',771:'ONE_MINUS_SRC_ALPHA',772:'DST_ALPHA',773:'ONE_MINUS_DST_ALPHA',774:'DST_COLOR',775:'ONE_MINUS_DST_COLOR',776:'SRC_ALPHA_SATURATE',1024:'STENCIL_BUFFER_BIT',1028:'FRONT',1029:'BACK',1032:'FRONT_AND_BACK',1280:'INVALID_ENUM',1281:'INVALID_VALUE',1282:'INVALID_OPERATION',1285:'OUT_OF_MEMORY',1286:'INVALID_FRAMEBUFFER_OPERATION',2304:'CW',2305:'CCW',2849:'LINE_WIDTH',2884:'CULL_FACE',2885:'CULL_FACE_MODE',2886:'FRONT_FACE',2928:'DEPTH_RANGE',2929:'DEPTH_TEST',2930:'DEPTH_WRITEMASK',2931:'DEPTH_CLEAR_VALUE',2932:'DEPTH_FUNC',2960:'STENCIL_TEST',2961:'STENCIL_CLEAR_VALUE',2962:'STENCIL_FUNC',2963:'STENCIL_VALUE_MASK',2964:'STENCIL_FAIL',2965:'STENCIL_PASS_DEPTH_FAIL',2966:'STENCIL_PASS_DEPTH_PASS',2967:'STENCIL_REF',2968:'STENCIL_WRITEMASK',2978:'VIEWPORT',3024:'DITHER',3042:'BLEND',3088:'SCISSOR_BOX',3089:'SCISSOR_TEST',3106:'COLOR_CLEAR_VALUE',3107:'COLOR_WRITEMASK',3317:'UNPACK_ALIGNMENT',3333:'PACK_ALIGNMENT',3379:'MAX_TEXTURE_SIZE',3386:'MAX_VIEWPORT_DIMS',3408:'SUBPIXEL_BITS',3410:'RED_BITS',3411:'GREEN_BITS',3412:'BLUE_BITS',3413:'ALPHA_BITS',3414:'DEPTH_BITS',3415:'STENCIL_BITS',3553:'TEXTURE_2D',4352:'DONT_CARE',4353:'FASTEST',4354:'NICEST',5120:'BYTE',5121:'UNSIGNED_BYTE',5122:'SHORT',5123:'UNSIGNED_SHORT',5124:'INT',5125:'UNSIGNED_INT',5126:'FLOAT',5386:'INVERT',5890:'TEXTURE',6401:'STENCIL_INDEX',6402:'DEPTH_COMPONENT',6406:'ALPHA',6407:'RGB',6408:'RGBA',6409:'LUMINANCE',6410:'LUMINANCE_ALPHA',7680:'KEEP',7681:'REPLACE',7682:'INCR',7683:'DECR',7936:'VENDOR',7937:'RENDERER',7938:'VERSION',9728:'NEAREST',9729:'LINEAR',9984:'NEAREST_MIPMAP_NEAREST',9985:'LINEAR_MIPMAP_NEAREST',9986:'NEAREST_MIPMAP_LINEAR',9987:'LINEAR_MIPMAP_LINEAR',10240:'TEXTURE_MAG_FILTER',10241:'TEXTURE_MIN_FILTER',10242:'TEXTURE_WRAP_S',10243:'TEXTURE_WRAP_T',10497:'REPEAT',10752:'POLYGON_OFFSET_UNITS',16384:'COLOR_BUFFER_BIT',32769:'CONSTANT_COLOR',32770:'ONE_MINUS_CONSTANT_COLOR',32771:'CONSTANT_ALPHA',32772:'ONE_MINUS_CONSTANT_ALPHA',32773:'BLEND_COLOR',32774:'FUNC_ADD',32777:'BLEND_EQUATION_RGB',32778:'FUNC_SUBTRACT',32779:'FUNC_REVERSE_SUBTRACT',32819:'UNSIGNED_SHORT_4_4_4_4',32820:'UNSIGNED_SHORT_5_5_5_1',32823:'POLYGON_OFFSET_FILL',32824:'POLYGON_OFFSET_FACTOR',32854:'RGBA4',32855:'RGB5_A1',32873:'TEXTURE_BINDING_2D',32926:'SAMPLE_ALPHA_TO_COVERAGE',32928:'SAMPLE_COVERAGE',32936:'SAMPLE_BUFFERS',32937:'SAMPLES',32938:'SAMPLE_COVERAGE_VALUE',32939:'SAMPLE_COVERAGE_INVERT',32968:'BLEND_DST_RGB',32969:'BLEND_SRC_RGB',32970:'BLEND_DST_ALPHA',32971:'BLEND_SRC_ALPHA',33071:'CLAMP_TO_EDGE',33170:'GENERATE_MIPMAP_HINT',33189:'DEPTH_COMPONENT16',33306:'DEPTH_STENCIL_ATTACHMENT',33635:'UNSIGNED_SHORT_5_6_5',33648:'MIRRORED_REPEAT',33901:'ALIASED_POINT_SIZE_RANGE',33902:'ALIASED_LINE_WIDTH_RANGE',33984:'TEXTURE0',33985:'TEXTURE1',33986:'TEXTURE2',33987:'TEXTURE3',33988:'TEXTURE4',33989:'TEXTURE5',33990:'TEXTURE6',33991:'TEXTURE7',33992:'TEXTURE8',33993:'TEXTURE9',33994:'TEXTURE10',33995:'TEXTURE11',33996:'TEXTURE12',33997:'TEXTURE13',33998:'TEXTURE14',33999:'TEXTURE15',34000:'TEXTURE16',34001:'TEXTURE17',34002:'TEXTURE18',34003:'TEXTURE19',34004:'TEXTURE20',34005:'TEXTURE21',34006:'TEXTURE22',34007:'TEXTURE23',34008:'TEXTURE24',34009:'TEXTURE25',34010:'TEXTURE26',34011:'TEXTURE27',34012:'TEXTURE28',34013:'TEXTURE29',34014:'TEXTURE30',34015:'TEXTURE31',34016:'ACTIVE_TEXTURE',34024:'MAX_RENDERBUFFER_SIZE',34041:'DEPTH_STENCIL',34055:'INCR_WRAP',34056:'DECR_WRAP',34067:'TEXTURE_CUBE_MAP',34068:'TEXTURE_BINDING_CUBE_MAP',34069:'TEXTURE_CUBE_MAP_POSITIVE_X',34070:'TEXTURE_CUBE_MAP_NEGATIVE_X',34071:'TEXTURE_CUBE_MAP_POSITIVE_Y',34072:'TEXTURE_CUBE_MAP_NEGATIVE_Y',34073:'TEXTURE_CUBE_MAP_POSITIVE_Z',34074:'TEXTURE_CUBE_MAP_NEGATIVE_Z',34076:'MAX_CUBE_MAP_TEXTURE_SIZE',34338:'VERTEX_ATTRIB_ARRAY_ENABLED',34339:'VERTEX_ATTRIB_ARRAY_SIZE',34340:'VERTEX_ATTRIB_ARRAY_STRIDE',34341:'VERTEX_ATTRIB_ARRAY_TYPE',34342:'CURRENT_VERTEX_ATTRIB',34373:'VERTEX_ATTRIB_ARRAY_POINTER',34466:'NUM_COMPRESSED_TEXTURE_FORMATS',34467:'COMPRESSED_TEXTURE_FORMATS',34660:'BUFFER_SIZE',34661:'BUFFER_USAGE',34816:'STENCIL_BACK_FUNC',34817:'STENCIL_BACK_FAIL',34818:'STENCIL_BACK_PASS_DEPTH_FAIL',34819:'STENCIL_BACK_PASS_DEPTH_PASS',34877:'BLEND_EQUATION_ALPHA',34921:'MAX_VERTEX_ATTRIBS',34922:'VERTEX_ATTRIB_ARRAY_NORMALIZED',34930:'MAX_TEXTURE_IMAGE_UNITS',34962:'ARRAY_BUFFER',34963:'ELEMENT_ARRAY_BUFFER',34964:'ARRAY_BUFFER_BINDING',34965:'ELEMENT_ARRAY_BUFFER_BINDING',34975:'VERTEX_ATTRIB_ARRAY_BUFFER_BINDING',35040:'STREAM_DRAW',35044:'STATIC_DRAW',35048:'DYNAMIC_DRAW',35632:'FRAGMENT_SHADER',35633:'VERTEX_SHADER',35660:'MAX_VERTEX_TEXTURE_IMAGE_UNITS',35661:'MAX_COMBINED_TEXTURE_IMAGE_UNITS',35663:'SHADER_TYPE',35664:'FLOAT_VEC2',35665:'FLOAT_VEC3',35666:'FLOAT_VEC4',35667:'INT_VEC2',35668:'INT_VEC3',35669:'INT_VEC4',35670:'BOOL',35671:'BOOL_VEC2',35672:'BOOL_VEC3',35673:'BOOL_VEC4',35674:'FLOAT_MAT2',35675:'FLOAT_MAT3',35676:'FLOAT_MAT4',35678:'SAMPLER_2D',35680:'SAMPLER_CUBE',35712:'DELETE_STATUS',35713:'COMPILE_STATUS',35714:'LINK_STATUS',35715:'VALIDATE_STATUS',35716:'INFO_LOG_LENGTH',35717:'ATTACHED_SHADERS',35718:'ACTIVE_UNIFORMS',35719:'ACTIVE_UNIFORM_MAX_LENGTH',35720:'SHADER_SOURCE_LENGTH',35721:'ACTIVE_ATTRIBUTES',35722:'ACTIVE_ATTRIBUTE_MAX_LENGTH',35724:'SHADING_LANGUAGE_VERSION',35725:'CURRENT_PROGRAM',36003:'STENCIL_BACK_REF',36004:'STENCIL_BACK_VALUE_MASK',36005:'STENCIL_BACK_WRITEMASK',36006:'FRAMEBUFFER_BINDING',36007:'RENDERBUFFER_BINDING',36048:'FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE',36049:'FRAMEBUFFER_ATTACHMENT_OBJECT_NAME',36050:'FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL',36051:'FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE',36053:'FRAMEBUFFER_COMPLETE',36054:'FRAMEBUFFER_INCOMPLETE_ATTACHMENT',36055:'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT',36057:'FRAMEBUFFER_INCOMPLETE_DIMENSIONS',36061:'FRAMEBUFFER_UNSUPPORTED',36064:'COLOR_ATTACHMENT0',36096:'DEPTH_ATTACHMENT',36128:'STENCIL_ATTACHMENT',36160:'FRAMEBUFFER',36161:'RENDERBUFFER',36162:'RENDERBUFFER_WIDTH',36163:'RENDERBUFFER_HEIGHT',36164:'RENDERBUFFER_INTERNAL_FORMAT',36168:'STENCIL_INDEX8',36176:'RENDERBUFFER_RED_SIZE',36177:'RENDERBUFFER_GREEN_SIZE',36178:'RENDERBUFFER_BLUE_SIZE',36179:'RENDERBUFFER_ALPHA_SIZE',36180:'RENDERBUFFER_DEPTH_SIZE',36181:'RENDERBUFFER_STENCIL_SIZE',36194:'RGB565',36336:'LOW_FLOAT',36337:'MEDIUM_FLOAT',36338:'HIGH_FLOAT',36339:'LOW_INT',36340:'MEDIUM_INT',36341:'HIGH_INT',36346:'SHADER_COMPILER',36347:'MAX_VERTEX_UNIFORM_VECTORS',36348:'MAX_VARYING_VECTORS',36349:'MAX_FRAGMENT_UNIFORM_VECTORS',37440:'UNPACK_FLIP_Y_WEBGL',37441:'UNPACK_PREMULTIPLY_ALPHA_WEBGL',37442:'CONTEXT_LOST_WEBGL',37443:'UNPACK_COLORSPACE_CONVERSION_WEBGL',37444:'BROWSER_DEFAULT_WEBGL'};/***/},/***/5171:/***/function(module,__unused_webpack_exports,__nested_webpack_require_307512__){var gl10=__nested_webpack_require_307512__(737);module.exports=function lookupConstant(number){return gl10[number];};/***/},/***/9165:/***/function(module,__unused_webpack_exports,__nested_webpack_require_307699__){"use strict";module.exports=createErrorBars;var createBuffer=__nested_webpack_require_307699__(2762);var createVAO=__nested_webpack_require_307699__(8116);var createShader=__nested_webpack_require_307699__(3436);var IDENTITY=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];function ErrorBars(gl,buffer,vao,shader){this.gl=gl;this.shader=shader;this.buffer=buffer;this.vao=vao;this.pixelRatio=1;this.bounds=[[Infinity,Infinity,Infinity],[-Infinity,-Infinity,-Infinity]];this.clipBounds=[[-Infinity,-Infinity,-Infinity],[Infinity,Infinity,Infinity]];this.lineWidth=[1,1,1];this.capSize=[10,10,10];this.lineCount=[0,0,0];this.lineOffset=[0,0,0];this.opacity=1;this.hasAlpha=false;}var proto=ErrorBars.prototype;proto.isOpaque=function(){return!this.hasAlpha;};proto.isTransparent=function(){return this.hasAlpha;};proto.drawTransparent=proto.draw=function(cameraParams){var gl=this.gl;var uniforms=this.shader.uniforms;this.shader.bind();var view=uniforms.view=cameraParams.view||IDENTITY;var projection=uniforms.projection=cameraParams.projection||IDENTITY;uniforms.model=cameraParams.model||IDENTITY;uniforms.clipBounds=this.clipBounds;uniforms.opacity=this.opacity;var cx=view[12];var cy=view[13];var cz=view[14];var cw=view[15];var isOrtho=cameraParams._ortho||false;var orthoFix=isOrtho?2:1;// double up padding for orthographic ticks & labels
var pixelScaleF=orthoFix*this.pixelRatio*(projection[3]*cx+projection[7]*cy+projection[11]*cz+projection[15]*cw)/gl.drawingBufferHeight;this.vao.bind();for(var i=0;i<3;++i){gl.lineWidth(this.lineWidth[i]*this.pixelRatio);uniforms.capSize=this.capSize[i]*pixelScaleF;if(this.lineCount[i]){gl.drawArrays(gl.LINES,this.lineOffset[i],this.lineCount[i]);}}this.vao.unbind();};function updateBounds(bounds,point){for(var i=0;i<3;++i){bounds[0][i]=Math.min(bounds[0][i],point[i]);bounds[1][i]=Math.max(bounds[1][i],point[i]);}}var FACE_TABLE=function(){var table=new Array(3);for(var d=0;d<3;++d){var row=[];for(var j=1;j<=2;++j){for(var s=-1;s<=1;s+=2){var u=(j+d)%3;var y=[0,0,0];y[u]=s;row.push(y);}}table[d]=row;}return table;}();function emitFace(verts,x,c,d){var offsets=FACE_TABLE[d];for(var i=0;i0){var x=p.slice();x[j]+=e[1][j];verts.push(p[0],p[1],p[2],c[0],c[1],c[2],c[3],0,0,0,x[0],x[1],x[2],c[0],c[1],c[2],c[3],0,0,0);updateBounds(this.bounds,x);vertexCount+=2+emitFace(verts,x,c,j);}}this.lineCount[j]=vertexCount-this.lineOffset[j];}this.buffer.update(verts);}};proto.dispose=function(){this.shader.dispose();this.buffer.dispose();this.vao.dispose();};function createErrorBars(options){var gl=options.gl;var buffer=createBuffer(gl);var vao=createVAO(gl,[{buffer:buffer,type:gl.FLOAT,size:3,offset:0,stride:40},{buffer:buffer,type:gl.FLOAT,size:4,offset:12,stride:40},{buffer:buffer,type:gl.FLOAT,size:3,offset:28,stride:40}]);var shader=createShader(gl);shader.attributes.position.location=0;shader.attributes.color.location=1;shader.attributes.offset.location=2;var result=new ErrorBars(gl,buffer,vao,shader);result.update(options);return result;}/***/},/***/3436:/***/function(module,__unused_webpack_exports,__nested_webpack_require_312338__){"use strict";var glslify=__nested_webpack_require_312338__(3236);var createShader=__nested_webpack_require_312338__(9405);var vertSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nattribute vec3 position, offset;\nattribute vec4 color;\nuniform mat4 model, view, projection;\nuniform float capSize;\nvarying vec4 fragColor;\nvarying vec3 fragPosition;\n\nvoid main() {\n vec4 worldPosition = model * vec4(position, 1.0);\n worldPosition = (worldPosition / worldPosition.w) + vec4(capSize * offset, 0.0);\n gl_Position = projection * view * worldPosition;\n fragColor = color;\n fragPosition = position;\n}"]);var fragSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nuniform vec3 clipBounds[2];\nuniform float opacity;\nvarying vec3 fragPosition;\nvarying vec4 fragColor;\n\nvoid main() {\n if (\n outOfRange(clipBounds[0], clipBounds[1], fragPosition) ||\n fragColor.a * opacity == 0.\n ) discard;\n\n gl_FragColor = opacity * fragColor;\n}"]);module.exports=function(gl){return createShader(gl,vertSrc,fragSrc,null,[{name:'position',type:'vec3'},{name:'color',type:'vec4'},{name:'offset',type:'vec3'}]);};/***/},/***/2260:/***/function(module,__unused_webpack_exports,__nested_webpack_require_314061__){"use strict";var createTexture=__nested_webpack_require_314061__(7766);module.exports=createFBO;var colorAttachmentArrays=null;var FRAMEBUFFER_UNSUPPORTED;var FRAMEBUFFER_INCOMPLETE_ATTACHMENT;var FRAMEBUFFER_INCOMPLETE_DIMENSIONS;var FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;function saveFBOState(gl){var fbo=gl.getParameter(gl.FRAMEBUFFER_BINDING);var rbo=gl.getParameter(gl.RENDERBUFFER_BINDING);var tex=gl.getParameter(gl.TEXTURE_BINDING_2D);return[fbo,rbo,tex];}function restoreFBOState(gl,data){gl.bindFramebuffer(gl.FRAMEBUFFER,data[0]);gl.bindRenderbuffer(gl.RENDERBUFFER,data[1]);gl.bindTexture(gl.TEXTURE_2D,data[2]);}function lazyInitColorAttachments(gl,ext){var maxColorAttachments=gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL);colorAttachmentArrays=new Array(maxColorAttachments+1);for(var i=0;i<=maxColorAttachments;++i){var x=new Array(maxColorAttachments);for(var j=0;j1){ext.drawBuffersWEBGL(colorAttachmentArrays[numColors]);}//Allocate depth/stencil buffers
var WEBGL_depth_texture=gl.getExtension('WEBGL_depth_texture');if(WEBGL_depth_texture){if(useStencil){fbo.depth=initTexture(gl,width,height,WEBGL_depth_texture.UNSIGNED_INT_24_8_WEBGL,gl.DEPTH_STENCIL,gl.DEPTH_STENCIL_ATTACHMENT);}else if(useDepth){fbo.depth=initTexture(gl,width,height,gl.UNSIGNED_SHORT,gl.DEPTH_COMPONENT,gl.DEPTH_ATTACHMENT);}}else{if(useDepth&&useStencil){fbo._depth_rb=initRenderBuffer(gl,width,height,gl.DEPTH_STENCIL,gl.DEPTH_STENCIL_ATTACHMENT);}else if(useDepth){fbo._depth_rb=initRenderBuffer(gl,width,height,gl.DEPTH_COMPONENT16,gl.DEPTH_ATTACHMENT);}else if(useStencil){fbo._depth_rb=initRenderBuffer(gl,width,height,gl.STENCIL_INDEX,gl.STENCIL_ATTACHMENT);}}//Check frame buffer state
var status=gl.checkFramebufferStatus(gl.FRAMEBUFFER);if(status!==gl.FRAMEBUFFER_COMPLETE){//Release all partially allocated resources
fbo._destroyed=true;//Release all resources
gl.bindFramebuffer(gl.FRAMEBUFFER,null);gl.deleteFramebuffer(fbo.handle);fbo.handle=null;if(fbo.depth){fbo.depth.dispose();fbo.depth=null;}if(fbo._depth_rb){gl.deleteRenderbuffer(fbo._depth_rb);fbo._depth_rb=null;}for(var i=0;imaxFBOSize||h<0||h>maxFBOSize){throw new Error('gl-fbo: Can\'t resize FBO, invalid dimensions');}//Update shape
fbo._shape[0]=w;fbo._shape[1]=h;//Save framebuffer state
var state=saveFBOState(gl);//Resize framebuffer attachments
for(var i=0;imaxFBOSize||height<0||height>maxFBOSize){throw new Error('gl-fbo: Parameters are too large for FBO');}//Handle each option type
options=options||{};//Figure out number of color buffers to use
var numColors=1;if('color'in options){numColors=Math.max(options.color|0,0);if(numColors<0){throw new Error('gl-fbo: Must specify a nonnegative number of colors');}if(numColors>1){//Check if multiple render targets supported
if(!WEBGL_draw_buffers){throw new Error('gl-fbo: Multiple draw buffer extension not supported');}else if(numColors>gl.getParameter(WEBGL_draw_buffers.MAX_COLOR_ATTACHMENTS_WEBGL)){throw new Error('gl-fbo: Context does not support '+numColors+' draw buffers');}}}//Determine whether to use floating point textures
var colorType=gl.UNSIGNED_BYTE;var OES_texture_float=gl.getExtension('OES_texture_float');if(options.float&&numColors>0){if(!OES_texture_float){throw new Error('gl-fbo: Context does not support floating point textures');}colorType=gl.FLOAT;}else if(options.preferFloat&&numColors>0){if(OES_texture_float){colorType=gl.FLOAT;}}//Check if we should use depth buffer
var useDepth=true;if('depth'in options){useDepth=!!options.depth;}//Check if we should use a stencil buffer
var useStencil=false;if('stencil'in options){useStencil=!!options.stencil;}return new Framebuffer(gl,width,height,colorType,numColors,useDepth,useStencil,WEBGL_draw_buffers);}/***/},/***/2992:/***/function(module,__unused_webpack_exports,__nested_webpack_require_324521__){var sprintf=__nested_webpack_require_324521__(3387).sprintf;var glConstants=__nested_webpack_require_324521__(5171);var shaderName=__nested_webpack_require_324521__(1848);var addLineNumbers=__nested_webpack_require_324521__(1085);module.exports=formatCompilerError;function formatCompilerError(errLog,src,type){"use strict";var name=shaderName(src)||'of unknown name (see npm glsl-shader-name)';var typeName='unknown type';if(type!==undefined){typeName=type===glConstants.FRAGMENT_SHADER?'fragment':'vertex';}var longForm=sprintf('Error compiling %s shader %s:\n',typeName,name);var shortForm=sprintf("%s%s",longForm,errLog);var errorStrings=errLog.split('\n');var errors={};for(var i=0;i>i*8&0xff;}this.pickOffset=pickOffset;shader.bind();var uniforms=shader.uniforms;uniforms.viewTransform=MATRIX;uniforms.pickOffset=PICK_VECTOR;uniforms.shape=this.shape;var attributes=shader.attributes;this.positionBuffer.bind();attributes.position.pointer();this.weightBuffer.bind();attributes.weight.pointer(gl.UNSIGNED_BYTE,false);this.idBuffer.bind();attributes.pickId.pointer(gl.UNSIGNED_BYTE,false);gl.drawArrays(gl.TRIANGLES,0,numVertices);return pickOffset+this.shape[0]*this.shape[1];};}();proto.pick=function(x,y,value){var pickOffset=this.pickOffset;var pointCount=this.shape[0]*this.shape[1];if(value=pickOffset+pointCount){return null;}var pointId=value-pickOffset;var xData=this.xData;var yData=this.yData;return{object:this,pointId:pointId,dataCoord:[xData[pointId%this.shape[0]],yData[pointId/this.shape[0]|0]]};};proto.update=function(options){options=options||{};var shape=options.shape||[0,0];var x=options.x||iota(shape[0]);var y=options.y||iota(shape[1]);var z=options.z||new Float32Array(shape[0]*shape[1]);var isSmooth=options.zsmooth!==false;this.xData=x;this.yData=y;var colorLevels=options.colorLevels||[0];var colorValues=options.colorValues||[0,0,0,1];var colorCount=colorLevels.length;var bounds=this.bounds;var lox,loy,hix,hiy;if(isSmooth){lox=bounds[0]=x[0];loy=bounds[1]=y[0];hix=bounds[2]=x[x.length-1];hiy=bounds[3]=y[y.length-1];}else{// To get squares to centre on data values
lox=bounds[0]=x[0]+(x[1]-x[0])/2;// starting x value
loy=bounds[1]=y[0]+(y[1]-y[0])/2;// starting y value
// Bounds needs to add half a square on each end
hix=bounds[2]=x[x.length-1]+(x[x.length-1]-x[x.length-2])/2;hiy=bounds[3]=y[y.length-1]+(y[y.length-1]-y[y.length-2])/2;// N.B. Resolution = 1 / range
}var xs=1.0/(hix-lox);var ys=1.0/(hiy-loy);var numX=shape[0];var numY=shape[1];this.shape=[numX,numY];var numVerts=(isSmooth?(numX-1)*(numY-1):numX*numY)*(WEIGHTS.length>>>1);this.numVertices=numVerts;var colors=pool.mallocUint8(numVerts*4);var positions=pool.mallocFloat32(numVerts*2);var weights=pool.mallocUint8(numVerts*2);var ids=pool.mallocUint32(numVerts);var ptr=0;var ni=isSmooth?numX-1:numX;var nj=isSmooth?numY-1:numY;for(var j=0;j max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nuniform vec3 clipBounds[2];\nuniform sampler2D dashTexture;\nuniform float dashScale;\nuniform float opacity;\n\nvarying vec3 worldPosition;\nvarying float pixelArcLength;\nvarying vec4 fragColor;\n\nvoid main() {\n if (\n outOfRange(clipBounds[0], clipBounds[1], worldPosition) ||\n fragColor.a * opacity == 0.\n ) discard;\n\n float dashWeight = texture2D(dashTexture, vec2(dashScale * pixelArcLength, 0)).r;\n if(dashWeight < 0.5) {\n discard;\n }\n gl_FragColor = fragColor * opacity;\n}\n"]);var pickFrag=glslify(["precision highp float;\n#define GLSLIFY 1\n\n#define FLOAT_MAX 1.70141184e38\n#define FLOAT_MIN 1.17549435e-38\n\n// https://github.com/mikolalysenko/glsl-read-float/blob/master/index.glsl\nvec4 packFloat(float v) {\n float av = abs(v);\n\n //Handle special cases\n if(av < FLOAT_MIN) {\n return vec4(0.0, 0.0, 0.0, 0.0);\n } else if(v > FLOAT_MAX) {\n return vec4(127.0, 128.0, 0.0, 0.0) / 255.0;\n } else if(v < -FLOAT_MAX) {\n return vec4(255.0, 128.0, 0.0, 0.0) / 255.0;\n }\n\n vec4 c = vec4(0,0,0,0);\n\n //Compute exponent and mantissa\n float e = floor(log2(av));\n float m = av * pow(2.0, -e) - 1.0;\n\n //Unpack mantissa\n c[1] = floor(128.0 * m);\n m -= c[1] / 128.0;\n c[2] = floor(32768.0 * m);\n m -= c[2] / 32768.0;\n c[3] = floor(8388608.0 * m);\n\n //Unpack exponent\n float ebias = e + 127.0;\n c[0] = floor(ebias / 2.0);\n ebias -= c[0] * 2.0;\n c[1] += floor(ebias) * 128.0;\n\n //Unpack sign bit\n c[0] += 128.0 * step(0.0, -v);\n\n //Scale back to range\n return c / 255.0;\n}\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nuniform float pickId;\nuniform vec3 clipBounds[2];\n\nvarying vec3 worldPosition;\nvarying float pixelArcLength;\nvarying vec4 fragColor;\n\nvoid main() {\n if (outOfRange(clipBounds[0], clipBounds[1], worldPosition)) discard;\n\n gl_FragColor = vec4(pickId/255.0, packFloat(pixelArcLength).xyz);\n}"]);var ATTRIBUTES=[{name:'position',type:'vec3'},{name:'nextPosition',type:'vec3'},{name:'arcLength',type:'float'},{name:'lineWidth',type:'float'},{name:'color',type:'vec4'}];exports.createShader=function(gl){return createShader(gl,vertSrc,forwardFrag,null,ATTRIBUTES);};exports.createPickShader=function(gl){return createShader(gl,vertSrc,pickFrag,null,ATTRIBUTES);};/***/},/***/5714:/***/function(module,__unused_webpack_exports,__nested_webpack_require_338868__){"use strict";module.exports=createLinePlot;var createBuffer=__nested_webpack_require_338868__(2762);var createVAO=__nested_webpack_require_338868__(8116);var createTexture=__nested_webpack_require_338868__(7766);var UINT8_VIEW=new Uint8Array(4);var FLOAT_VIEW=new Float32Array(UINT8_VIEW.buffer);// https://github.com/mikolalysenko/glsl-read-float/blob/master/index.js
function unpackFloat(x,y,z,w){UINT8_VIEW[0]=w;UINT8_VIEW[1]=z;UINT8_VIEW[2]=y;UINT8_VIEW[3]=x;return FLOAT_VIEW[0];}var bsearch=__nested_webpack_require_338868__(2478);var ndarray=__nested_webpack_require_338868__(9618);var shaders=__nested_webpack_require_338868__(7319);var createShader=shaders.createShader;var createPickShader=shaders.createPickShader;var identity=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];function distance(a,b){var s=0.0;for(var i=0;i<3;++i){var d=a[i]-b[i];s+=d*d;}return Math.sqrt(s);}function filterClipBounds(bounds){var result=[[-1e6,-1e6,-1e6],[1e6,1e6,1e6]];for(var i=0;i<3;++i){result[0][i]=Math.max(bounds[0][i],result[0][i]);result[1][i]=Math.min(bounds[1][i],result[1][i]);}return result;}function PickResult(tau,position,index,dataCoordinate){this.arcLength=tau;this.position=position;this.index=index;this.dataCoordinate=dataCoordinate;}function LinePlot(gl,shader,pickShader,buffer,vao,texture){this.gl=gl;this.shader=shader;this.pickShader=pickShader;this.buffer=buffer;this.vao=vao;this.clipBounds=[[-Infinity,-Infinity,-Infinity],[Infinity,Infinity,Infinity]];this.points=[];this.arcLength=[];this.vertexCount=0;this.bounds=[[0,0,0],[0,0,0]];this.pickId=0;this.lineWidth=1;this.texture=texture;this.dashScale=1;this.opacity=1;this.hasAlpha=false;this.dirty=true;this.pixelRatio=1;}var proto=LinePlot.prototype;proto.isTransparent=function(){return this.hasAlpha;};proto.isOpaque=function(){return!this.hasAlpha;};proto.pickSlots=1;proto.setPickBase=function(id){this.pickId=id;};proto.drawTransparent=proto.draw=function(camera){if(!this.vertexCount)return;var gl=this.gl;var shader=this.shader;var vao=this.vao;shader.bind();shader.uniforms={model:camera.model||identity,view:camera.view||identity,projection:camera.projection||identity,clipBounds:filterClipBounds(this.clipBounds),dashTexture:this.texture.bind(),dashScale:this.dashScale/this.arcLength[this.arcLength.length-1],opacity:this.opacity,screenShape:[gl.drawingBufferWidth,gl.drawingBufferHeight],pixelRatio:this.pixelRatio};vao.bind();vao.draw(gl.TRIANGLE_STRIP,this.vertexCount);vao.unbind();};proto.drawPick=function(camera){if(!this.vertexCount)return;var gl=this.gl;var shader=this.pickShader;var vao=this.vao;shader.bind();shader.uniforms={model:camera.model||identity,view:camera.view||identity,projection:camera.projection||identity,pickId:this.pickId,clipBounds:filterClipBounds(this.clipBounds),screenShape:[gl.drawingBufferWidth,gl.drawingBufferHeight],pixelRatio:this.pixelRatio};vao.bind();vao.draw(gl.TRIANGLE_STRIP,this.vertexCount);vao.unbind();};proto.update=function(options){var i,j;this.dirty=true;var connectGaps=!!options.connectGaps;if('dashScale'in options){this.dashScale=options.dashScale;}this.hasAlpha=false;// default to no transparent draw
if('opacity'in options){this.opacity=+options.opacity;if(this.opacity<1){this.hasAlpha=true;}}// Recalculate buffer data
var buffer=[];var arcLengthArray=[];var pointArray=[];var arcLength=0.0;var vertexCount=0;var bounds=[[Infinity,Infinity,Infinity],[-Infinity,-Infinity,-Infinity]];var positions=options.position||options.positions;if(positions){// Default color
var colors=options.color||options.colors||[0,0,0,1];var lineWidth=options.lineWidth||1;var hadGap=false;fill_loop:for(i=1;i0){for(var k=0;k<24;++k){buffer.push(buffer[buffer.length-12]);}vertexCount+=2;hadGap=true;}continue fill_loop;}bounds[0][j]=Math.min(bounds[0][j],a[j],b[j]);bounds[1][j]=Math.max(bounds[1][j],a[j],b[j]);}var acolor,bcolor;if(Array.isArray(colors[0])){acolor=colors.length>i-1?colors[i-1]:// using index value
colors.length>0?colors[colors.length-1]:// using last item
[0,0,0,1];// using black
bcolor=colors.length>i?colors[i]:// using index value
colors.length>0?colors[colors.length-1]:// using last item
[0,0,0,1];// using black
}else{acolor=bcolor=colors;}if(acolor.length===3){acolor=[acolor[0],acolor[1],acolor[2],1];}if(bcolor.length===3){bcolor=[bcolor[0],bcolor[1],bcolor[2],1];}if(!this.hasAlpha&&acolor[3]<1)this.hasAlpha=true;var w0;if(Array.isArray(lineWidth)){w0=lineWidth.length>i-1?lineWidth[i-1]:// using index value
lineWidth.length>0?lineWidth[lineWidth.length-1]:// using last item
[0,0,0,1];// using black
}else{w0=lineWidth;}var t0=arcLength;arcLength+=distance(a,b);if(hadGap){for(j=0;j<2;++j){buffer.push(a[0],a[1],a[2],b[0],b[1],b[2],t0,w0,acolor[0],acolor[1],acolor[2],acolor[3]);}vertexCount+=2;hadGap=false;}buffer.push(a[0],a[1],a[2],b[0],b[1],b[2],t0,w0,acolor[0],acolor[1],acolor[2],acolor[3],a[0],a[1],a[2],b[0],b[1],b[2],t0,-w0,acolor[0],acolor[1],acolor[2],acolor[3],b[0],b[1],b[2],a[0],a[1],a[2],arcLength,-w0,bcolor[0],bcolor[1],bcolor[2],bcolor[3],b[0],b[1],b[2],a[0],a[1],a[2],arcLength,w0,bcolor[0],bcolor[1],bcolor[2],bcolor[3]);vertexCount+=4;}}this.buffer.update(buffer);arcLengthArray.push(arcLength);pointArray.push(positions[positions.length-1].slice());this.bounds=bounds;this.vertexCount=vertexCount;this.points=pointArray;this.arcLength=arcLengthArray;if('dashes'in options){var dashArray=options.dashes;// Calculate prefix sum
var prefixSum=dashArray.slice();prefixSum.unshift(0);for(i=1;i1.0001){return null;}s+=weights[i];}if(Math.abs(s-1.0)>0.001){return null;}return[closestIndex,interpolate(simplex,weights),weights];}/***/},/***/840:/***/function(__unused_webpack_module,exports,__nested_webpack_require_364052__){var glslify=__nested_webpack_require_364052__(3236);var triVertSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nattribute vec3 position, normal;\nattribute vec4 color;\nattribute vec2 uv;\n\nuniform mat4 model\n , view\n , projection\n , inverseModel;\nuniform vec3 eyePosition\n , lightPosition;\n\nvarying vec3 f_normal\n , f_lightDirection\n , f_eyeDirection\n , f_data;\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvec4 project(vec3 p) {\n return projection * view * model * vec4(p, 1.0);\n}\n\nvoid main() {\n gl_Position = project(position);\n\n //Lighting geometry parameters\n vec4 cameraCoordinate = view * vec4(position , 1.0);\n cameraCoordinate.xyz /= cameraCoordinate.w;\n f_lightDirection = lightPosition - cameraCoordinate.xyz;\n f_eyeDirection = eyePosition - cameraCoordinate.xyz;\n f_normal = normalize((vec4(normal, 0.0) * inverseModel).xyz);\n\n f_color = color;\n f_data = position;\n f_uv = uv;\n}\n"]);var triFragSrc=glslify(["#extension GL_OES_standard_derivatives : enable\n\nprecision highp float;\n#define GLSLIFY 1\n\nfloat beckmannDistribution(float x, float roughness) {\n float NdotH = max(x, 0.0001);\n float cos2Alpha = NdotH * NdotH;\n float tan2Alpha = (cos2Alpha - 1.0) / cos2Alpha;\n float roughness2 = roughness * roughness;\n float denom = 3.141592653589793 * roughness2 * cos2Alpha * cos2Alpha;\n return exp(tan2Alpha / roughness2) / denom;\n}\n\nfloat cookTorranceSpecular(\n vec3 lightDirection,\n vec3 viewDirection,\n vec3 surfaceNormal,\n float roughness,\n float fresnel) {\n\n float VdotN = max(dot(viewDirection, surfaceNormal), 0.0);\n float LdotN = max(dot(lightDirection, surfaceNormal), 0.0);\n\n //Half angle vector\n vec3 H = normalize(lightDirection + viewDirection);\n\n //Geometric term\n float NdotH = max(dot(surfaceNormal, H), 0.0);\n float VdotH = max(dot(viewDirection, H), 0.000001);\n float LdotH = max(dot(lightDirection, H), 0.000001);\n float G1 = (2.0 * NdotH * VdotN) / VdotH;\n float G2 = (2.0 * NdotH * LdotN) / LdotH;\n float G = min(1.0, min(G1, G2));\n \n //Distribution term\n float D = beckmannDistribution(NdotH, roughness);\n\n //Fresnel term\n float F = pow(1.0 - VdotN, fresnel);\n\n //Multiply terms and done\n return G * F * D / max(3.14159265 * VdotN, 0.000001);\n}\n\n//#pragma glslify: beckmann = require(glsl-specular-beckmann) // used in gl-surface3d\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nuniform vec3 clipBounds[2];\nuniform float roughness\n , fresnel\n , kambient\n , kdiffuse\n , kspecular;\nuniform sampler2D texture;\n\nvarying vec3 f_normal\n , f_lightDirection\n , f_eyeDirection\n , f_data;\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n if (f_color.a == 0.0 ||\n outOfRange(clipBounds[0], clipBounds[1], f_data)\n ) discard;\n\n vec3 N = normalize(f_normal);\n vec3 L = normalize(f_lightDirection);\n vec3 V = normalize(f_eyeDirection);\n\n if(gl_FrontFacing) {\n N = -N;\n }\n\n float specular = min(1.0, max(0.0, cookTorranceSpecular(L, V, N, roughness, fresnel)));\n //float specular = max(0.0, beckmann(L, V, N, roughness)); // used in gl-surface3d\n\n float diffuse = min(kambient + kdiffuse * max(dot(N, L), 0.0), 1.0);\n\n vec4 surfaceColor = vec4(f_color.rgb, 1.0) * texture2D(texture, f_uv);\n vec4 litColor = surfaceColor.a * vec4(diffuse * surfaceColor.rgb + kspecular * vec3(1,1,1) * specular, 1.0);\n\n gl_FragColor = litColor * f_color.a;\n}\n"]);var edgeVertSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute vec4 color;\nattribute vec2 uv;\n\nuniform mat4 model, view, projection;\n\nvarying vec4 f_color;\nvarying vec3 f_data;\nvarying vec2 f_uv;\n\nvoid main() {\n gl_Position = projection * view * model * vec4(position, 1.0);\n f_color = color;\n f_data = position;\n f_uv = uv;\n}"]);var edgeFragSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nuniform vec3 clipBounds[2];\nuniform sampler2D texture;\nuniform float opacity;\n\nvarying vec4 f_color;\nvarying vec3 f_data;\nvarying vec2 f_uv;\n\nvoid main() {\n if (outOfRange(clipBounds[0], clipBounds[1], f_data)) discard;\n\n gl_FragColor = f_color * texture2D(texture, f_uv) * opacity;\n}"]);var pointVertSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nattribute vec3 position;\nattribute vec4 color;\nattribute vec2 uv;\nattribute float pointSize;\n\nuniform mat4 model, view, projection;\nuniform vec3 clipBounds[2];\n\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n if (outOfRange(clipBounds[0], clipBounds[1], position)) {\n\n gl_Position = vec4(0.0, 0.0 ,0.0 ,0.0);\n } else {\n gl_Position = projection * view * model * vec4(position, 1.0);\n }\n gl_PointSize = pointSize;\n f_color = color;\n f_uv = uv;\n}"]);var pointFragSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nuniform sampler2D texture;\nuniform float opacity;\n\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n vec2 pointR = gl_PointCoord.xy - vec2(0.5, 0.5);\n if(dot(pointR, pointR) > 0.25) {\n discard;\n }\n gl_FragColor = f_color * texture2D(texture, f_uv) * opacity;\n}"]);var pickVertSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute vec4 id;\n\nuniform mat4 model, view, projection;\n\nvarying vec3 f_position;\nvarying vec4 f_id;\n\nvoid main() {\n gl_Position = projection * view * model * vec4(position, 1.0);\n f_id = id;\n f_position = position;\n}"]);var pickFragSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nuniform vec3 clipBounds[2];\nuniform float pickId;\n\nvarying vec3 f_position;\nvarying vec4 f_id;\n\nvoid main() {\n if (outOfRange(clipBounds[0], clipBounds[1], f_position)) discard;\n\n gl_FragColor = vec4(pickId, f_id.xyz);\n}"]);var pickPointVertSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nbool outOfRange(float a, float b, float p) {\n return ((p > max(a, b)) || \n (p < min(a, b)));\n}\n\nbool outOfRange(vec2 a, vec2 b, vec2 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y));\n}\n\nbool outOfRange(vec3 a, vec3 b, vec3 p) {\n return (outOfRange(a.x, b.x, p.x) ||\n outOfRange(a.y, b.y, p.y) ||\n outOfRange(a.z, b.z, p.z));\n}\n\nbool outOfRange(vec4 a, vec4 b, vec4 p) {\n return outOfRange(a.xyz, b.xyz, p.xyz);\n}\n\nattribute vec3 position;\nattribute float pointSize;\nattribute vec4 id;\n\nuniform mat4 model, view, projection;\nuniform vec3 clipBounds[2];\n\nvarying vec3 f_position;\nvarying vec4 f_id;\n\nvoid main() {\n if (outOfRange(clipBounds[0], clipBounds[1], position)) {\n\n gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n } else {\n gl_Position = projection * view * model * vec4(position, 1.0);\n gl_PointSize = pointSize;\n }\n f_id = id;\n f_position = position;\n}"]);var contourVertSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nattribute vec3 position;\n\nuniform mat4 model, view, projection;\n\nvoid main() {\n gl_Position = projection * view * model * vec4(position, 1.0);\n}"]);var contourFragSrc=glslify(["precision highp float;\n#define GLSLIFY 1\n\nuniform vec3 contourColor;\n\nvoid main() {\n gl_FragColor = vec4(contourColor, 1.0);\n}\n"]);exports.meshShader={vertex:triVertSrc,fragment:triFragSrc,attributes:[{name:'position',type:'vec3'},{name:'normal',type:'vec3'},{name:'color',type:'vec4'},{name:'uv',type:'vec2'}]};exports.wireShader={vertex:edgeVertSrc,fragment:edgeFragSrc,attributes:[{name:'position',type:'vec3'},{name:'color',type:'vec4'},{name:'uv',type:'vec2'}]};exports.pointShader={vertex:pointVertSrc,fragment:pointFragSrc,attributes:[{name:'position',type:'vec3'},{name:'color',type:'vec4'},{name:'uv',type:'vec2'},{name:'pointSize',type:'float'}]};exports.pickShader={vertex:pickVertSrc,fragment:pickFragSrc,attributes:[{name:'position',type:'vec3'},{name:'id',type:'vec4'}]};exports.pointPickShader={vertex:pickPointVertSrc,fragment:pickFragSrc,attributes:[{name:'position',type:'vec3'},{name:'pointSize',type:'float'},{name:'id',type:'vec4'}]};exports.contourShader={vertex:contourVertSrc,fragment:contourFragSrc,attributes:[{name:'position',type:'vec3'}]};/***/},/***/7201:/***/function(module,__unused_webpack_exports,__nested_webpack_require_374441__){"use strict";var DEFAULT_VERTEX_NORMALS_EPSILON=1e-6;// may be too large if triangles are very small
var DEFAULT_FACE_NORMALS_EPSILON=1e-6;var createShader=__nested_webpack_require_374441__(9405);var createBuffer=__nested_webpack_require_374441__(2762);var createVAO=__nested_webpack_require_374441__(8116);var createTexture=__nested_webpack_require_374441__(7766);var normals=__nested_webpack_require_374441__(8406);var multiply=__nested_webpack_require_374441__(6760);var invert=__nested_webpack_require_374441__(7608);var ndarray=__nested_webpack_require_374441__(9618);var colormap=__nested_webpack_require_374441__(6729);var getContour=__nested_webpack_require_374441__(7765);var pool=__nested_webpack_require_374441__(1888);var shaders=__nested_webpack_require_374441__(840);var closestPoint=__nested_webpack_require_374441__(7626);var meshShader=shaders.meshShader;var wireShader=shaders.wireShader;var pointShader=shaders.pointShader;var pickShader=shaders.pickShader;var pointPickShader=shaders.pointPickShader;var contourShader=shaders.contourShader;var IDENTITY=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];function SimplicialMesh(gl,texture,triShader,lineShader,pointShader,pickShader,pointPickShader,contourShader,trianglePositions,triangleIds,triangleColors,triangleUVs,triangleNormals,triangleVAO,edgePositions,edgeIds,edgeColors,edgeUVs,edgeVAO,pointPositions,pointIds,pointColors,pointUVs,pointSizes,pointVAO,contourPositions,contourVAO){this.gl=gl;this.pixelRatio=1;this.cells=[];this.positions=[];this.intensity=[];this.texture=texture;this.dirty=true;this.triShader=triShader;this.lineShader=lineShader;this.pointShader=pointShader;this.pickShader=pickShader;this.pointPickShader=pointPickShader;this.contourShader=contourShader;this.trianglePositions=trianglePositions;this.triangleColors=triangleColors;this.triangleNormals=triangleNormals;this.triangleUVs=triangleUVs;this.triangleIds=triangleIds;this.triangleVAO=triangleVAO;this.triangleCount=0;this.lineWidth=1;this.edgePositions=edgePositions;this.edgeColors=edgeColors;this.edgeUVs=edgeUVs;this.edgeIds=edgeIds;this.edgeVAO=edgeVAO;this.edgeCount=0;this.pointPositions=pointPositions;this.pointColors=pointColors;this.pointUVs=pointUVs;this.pointSizes=pointSizes;this.pointIds=pointIds;this.pointVAO=pointVAO;this.pointCount=0;this.contourLineWidth=1;this.contourPositions=contourPositions;this.contourVAO=contourVAO;this.contourCount=0;this.contourColor=[0,0,0];this.contourEnable=true;this.pickVertex=true;this.pickId=1;this.bounds=[[Infinity,Infinity,Infinity],[-Infinity,-Infinity,-Infinity]];this.clipBounds=[[-Infinity,-Infinity,-Infinity],[Infinity,Infinity,Infinity]];this.lightPosition=[1e5,1e5,0];this.ambientLight=0.8;this.diffuseLight=0.8;this.specularLight=2.0;this.roughness=0.5;this.fresnel=1.5;this.opacity=1.0;this.hasAlpha=false;this.opacityscale=false;this._model=IDENTITY;this._view=IDENTITY;this._projection=IDENTITY;this._resolution=[1,1];}var proto=SimplicialMesh.prototype;proto.isOpaque=function(){return!this.hasAlpha;};proto.isTransparent=function(){return this.hasAlpha;};proto.pickSlots=1;proto.setPickBase=function(id){this.pickId=id;};function getOpacityFromScale(ratio,opacityscale){if(!opacityscale)return 1;if(!opacityscale.length)return 1;for(var i=0;iratio&&i>0){var d=(opacityscale[i][0]-ratio)/(opacityscale[i][0]-opacityscale[i-1][0]);return opacityscale[i][1]*(1-d)+d*opacityscale[i-1][1];}}return 1;}function genColormap(param,opacityscale){var colors=colormap({colormap:param,nshades:256,format:'rgba'});var result=new Uint8Array(256*4);for(var i=0;i<256;++i){var c=colors[i];for(var j=0;j<3;++j){result[4*i+j]=c[j];}if(!opacityscale){result[4*i+3]=255*c[3];}else{result[4*i+3]=255*getOpacityFromScale(i/255.0,opacityscale);}}return ndarray(result,[256,256,4],[4,0,1]);}function takeZComponent(array){var n=array.length;var result=new Array(n);for(var i=0;i0){var shader=this.triShader;shader.bind();shader.uniforms=uniforms;this.triangleVAO.bind();gl.drawArrays(gl.TRIANGLES,0,this.triangleCount*3);this.triangleVAO.unbind();}if(this.edgeCount>0&&this.lineWidth>0){var shader=this.lineShader;shader.bind();shader.uniforms=uniforms;this.edgeVAO.bind();gl.lineWidth(this.lineWidth*this.pixelRatio);gl.drawArrays(gl.LINES,0,this.edgeCount*2);this.edgeVAO.unbind();}if(this.pointCount>0){var shader=this.pointShader;shader.bind();shader.uniforms=uniforms;this.pointVAO.bind();gl.drawArrays(gl.POINTS,0,this.pointCount);this.pointVAO.unbind();}if(this.contourEnable&&this.contourCount>0&&this.contourLineWidth>0){var shader=this.contourShader;shader.bind();shader.uniforms=uniforms;this.contourVAO.bind();gl.drawArrays(gl.LINES,0,this.contourCount);this.contourVAO.unbind();}};proto.drawPick=function(params){params=params||{};var gl=this.gl;var model=params.model||IDENTITY;var view=params.view||IDENTITY;var projection=params.projection||IDENTITY;var clipBounds=[[-1e6,-1e6,-1e6],[1e6,1e6,1e6]];for(var i=0;i<3;++i){clipBounds[0][i]=Math.max(clipBounds[0][i],this.clipBounds[0][i]);clipBounds[1][i]=Math.min(clipBounds[1][i],this.clipBounds[1][i]);}//Save camera parameters
this._model=[].slice.call(model);this._view=[].slice.call(view);this._projection=[].slice.call(projection);this._resolution=[gl.drawingBufferWidth,gl.drawingBufferHeight];var uniforms={model:model,view:view,projection:projection,clipBounds:clipBounds,pickId:this.pickId/255.0};var shader=this.pickShader;shader.bind();shader.uniforms=uniforms;if(this.triangleCount>0){this.triangleVAO.bind();gl.drawArrays(gl.TRIANGLES,0,this.triangleCount*3);this.triangleVAO.unbind();}if(this.edgeCount>0){this.edgeVAO.bind();gl.lineWidth(this.lineWidth*this.pixelRatio);gl.drawArrays(gl.LINES,0,this.edgeCount*2);this.edgeVAO.unbind();}if(this.pointCount>0){var shader=this.pointPickShader;shader.bind();shader.uniforms=uniforms;this.pointVAO.bind();gl.drawArrays(gl.POINTS,0,this.pointCount);this.pointVAO.unbind();}};proto.pick=function(pickData){if(!pickData){return null;}if(pickData.id!==this.pickId){return null;}var cellId=pickData.value[0]+256*pickData.value[1]+65536*pickData.value[2];var cell=this.cells[cellId];var positions=this.positions;var simplex=new Array(cell.length);for(var i=0;itickOffset[start]){shader.uniforms.dataAxis=DATA_AXIS;shader.uniforms.screenOffset=SCREEN_OFFSET;shader.uniforms.color=textColor[axis];shader.uniforms.angle=textAngle[axis];gl.drawArrays(gl.TRIANGLES,tickOffset[start],tickOffset[end]-tickOffset[start]);}}if(labelEnable[axis]&&labelCount){SCREEN_OFFSET[axis^1]-=screenScale*pixelRatio*labelPad[axis];shader.uniforms.dataAxis=ZERO_2;shader.uniforms.screenOffset=SCREEN_OFFSET;shader.uniforms.color=labelColor[axis];shader.uniforms.angle=labelAngle[axis];gl.drawArrays(gl.TRIANGLES,labelOffset,labelCount);}SCREEN_OFFSET[axis^1]=screenScale*viewBox[2+(axis^1)]-1.0;if(tickEnable[axis+2]){SCREEN_OFFSET[axis^1]+=screenScale*pixelRatio*tickPad[axis+2];if(starttickOffset[start]){shader.uniforms.dataAxis=DATA_AXIS;shader.uniforms.screenOffset=SCREEN_OFFSET;shader.uniforms.color=textColor[axis+2];shader.uniforms.angle=textAngle[axis+2];gl.drawArrays(gl.TRIANGLES,tickOffset[start],tickOffset[end]-tickOffset[start]);}}if(labelEnable[axis+2]&&labelCount){SCREEN_OFFSET[axis^1]+=screenScale*pixelRatio*labelPad[axis+2];shader.uniforms.dataAxis=ZERO_2;shader.uniforms.screenOffset=SCREEN_OFFSET;shader.uniforms.color=labelColor[axis+2];shader.uniforms.angle=labelAngle[axis+2];gl.drawArrays(gl.TRIANGLES,labelOffset,labelCount);}};}();proto.drawTitle=function(){var DATA_AXIS=[0,0];var SCREEN_OFFSET=[0,0];return function(){var plot=this.plot;var shader=this.shader;var gl=plot.gl;var screenBox=plot.screenBox;var titleCenter=plot.titleCenter;var titleAngle=plot.titleAngle;var titleColor=plot.titleColor;var pixelRatio=plot.pixelRatio;if(!this.titleCount){return;}for(var i=0;i<2;++i){SCREEN_OFFSET[i]=2.0*(titleCenter[i]*pixelRatio-screenBox[i])/(screenBox[2+i]-screenBox[i])-1;}shader.bind();shader.uniforms.dataAxis=DATA_AXIS;shader.uniforms.screenOffset=SCREEN_OFFSET;shader.uniforms.angle=titleAngle;shader.uniforms.color=titleColor;gl.drawArrays(gl.TRIANGLES,this.titleOffset,this.titleCount);};}();proto.bind=function(){var DATA_SHIFT=[0,0];var DATA_SCALE=[0,0];var TEXT_SCALE=[0,0];return function(){var plot=this.plot;var shader=this.shader;var bounds=plot._tickBounds;var dataBox=plot.dataBox;var screenBox=plot.screenBox;var viewBox=plot.viewBox;shader.bind();//Set up coordinate scaling uniforms
for(var i=0;i<2;++i){var lo=bounds[i];var hi=bounds[i+2];var boundScale=hi-lo;var dataCenter=0.5*(dataBox[i+2]+dataBox[i]);var dataWidth=dataBox[i+2]-dataBox[i];var viewLo=viewBox[i];var viewHi=viewBox[i+2];var viewScale=viewHi-viewLo;var screenLo=screenBox[i];var screenHi=screenBox[i+2];var screenScale=screenHi-screenLo;DATA_SCALE[i]=2.0*boundScale/dataWidth*viewScale/screenScale;DATA_SHIFT[i]=2.0*(lo-dataCenter)/dataWidth*viewScale/screenScale;}TEXT_SCALE[1]=2.0*plot.pixelRatio/(screenBox[3]-screenBox[1]);TEXT_SCALE[0]=TEXT_SCALE[1]*(screenBox[3]-screenBox[1])/(screenBox[2]-screenBox[0]);shader.uniforms.dataScale=DATA_SCALE;shader.uniforms.dataShift=DATA_SHIFT;shader.uniforms.textScale=TEXT_SCALE;//Set attributes
this.vbo.bind();shader.attributes.textCoordinate.pointer();};}();proto.update=function(options){var vertices=[];var axesTicks=options.ticks;var bounds=options.bounds;var i,j,k,data,scale,dimension;for(dimension=0;dimension<2;++dimension){var offsets=[Math.floor(vertices.length/3)],tickX=[-Infinity];//Copy vertices over to buffer
var ticks=axesTicks[dimension];for(i=0;i=0)){continue;}var zeroIntercept=screenBox[i]-dataBox[i]*(screenBox[i+2]-screenBox[i])/(dataBox[i+2]-dataBox[i]);if(i===0){line.drawLine(zeroIntercept,screenBox[1],zeroIntercept,screenBox[3],zeroLineWidth[i],zeroLineColor[i]);}else{line.drawLine(screenBox[0],zeroIntercept,screenBox[2],zeroIntercept,zeroLineWidth[i],zeroLineColor[i]);}}}//Draw traces
for(var i=0;i=0;--i){this.objects[i].dispose();}this.objects.length=0;for(var i=this.overlays.length-1;i>=0;--i){this.overlays[i].dispose();}this.overlays.length=0;this.gl=null;};proto.addObject=function(object){if(this.objects.indexOf(object)<0){this.objects.push(object);this.setDirty();}};proto.removeObject=function(object){var objects=this.objects;for(var i=0;iMath.abs(dy)){view.rotate(t,0,0,-dx*flipX*Math.PI*camera.rotateSpeed/window.innerWidth);}else{if(!camera._ortho){var kzoom=-camera.zoomSpeed*flipY*dy/window.innerHeight*(t-view.lastT())/20.0;view.pan(t,0,0,distance*(Math.exp(kzoom)-1));}}},true);};camera.enableMouseListeners();return camera;}/***/},/***/799:/***/function(module,__unused_webpack_exports,__nested_webpack_require_431926__){var glslify=__nested_webpack_require_431926__(3236);var createShader=__nested_webpack_require_431926__(9405);var vertSrc=glslify(["precision mediump float;\n#define GLSLIFY 1\nattribute vec2 position;\nvarying vec2 uv;\nvoid main() {\n uv = position;\n gl_Position = vec4(position, 0, 1);\n}"]);var fragSrc=glslify(["precision mediump float;\n#define GLSLIFY 1\n\nuniform sampler2D accumBuffer;\nvarying vec2 uv;\n\nvoid main() {\n vec4 accum = texture2D(accumBuffer, 0.5 * (uv + 1.0));\n gl_FragColor = min(vec4(1,1,1,1), accum);\n}"]);module.exports=function(gl){return createShader(gl,vertSrc,fragSrc,null,[{name:'position',type:'vec2'}]);};/***/},/***/4100:/***/function(module,__unused_webpack_exports,__nested_webpack_require_432630__){"use strict";var createCamera=__nested_webpack_require_432630__(4437);var createAxes=__nested_webpack_require_432630__(3837);var axesRanges=__nested_webpack_require_432630__(5445);var createSpikes=__nested_webpack_require_432630__(4449);var createSelect=__nested_webpack_require_432630__(3589);var createFBO=__nested_webpack_require_432630__(2260);var drawTriangle=__nested_webpack_require_432630__(7169);var mouseChange=__nested_webpack_require_432630__(351);var perspective=__nested_webpack_require_432630__(4772);var ortho=__nested_webpack_require_432630__(4040);var createShader=__nested_webpack_require_432630__(799);var isMobile=__nested_webpack_require_432630__(9216)({tablet:true,featureDetect:true});module.exports={createScene:createScene,createCamera:createCamera};function MouseSelect(){this.mouse=[-1,-1];this.screen=null;this.distance=Infinity;this.index=null;this.dataCoordinate=null;this.dataPosition=null;this.object=null;this.data=null;}function getContext(canvas,options){var gl=null;try{gl=canvas.getContext('webgl',options);if(!gl){gl=canvas.getContext('experimental-webgl',options);}}catch(e){return null;}return gl;}function roundUpPow10(x){var y=Math.round(Math.log(Math.abs(x))/Math.log(10));if(y<0){var base=Math.round(Math.pow(10,-y));return Math.ceil(x*base)/base;}else if(y>0){var base=Math.round(Math.pow(10,y));return Math.ceil(x/base)*base;}return Math.ceil(x);}function defaultBool(x){if(typeof x==='boolean'){return x;}return true;}function createScene(options){options=options||{};options.camera=options.camera||{};var canvas=options.canvas;if(!canvas){canvas=document.createElement('canvas');if(options.container){var container=options.container;container.appendChild(canvas);}else{document.body.appendChild(canvas);}}var gl=options.gl;if(!gl){if(options.glOptions){isMobile=!!options.glOptions.preserveDrawingBuffer;}gl=getContext(canvas,options.glOptions||{premultipliedAlpha:true,antialias:true,preserveDrawingBuffer:isMobile});}if(!gl){throw new Error('webgl not supported');}//Initial bounds
var bounds=options.bounds||[[-10,-10,-10],[10,10,10]];//Create selection
var selection=new MouseSelect();//Accumulation buffer
var accumBuffer=createFBO(gl,gl.drawingBufferWidth,gl.drawingBufferHeight,{preferFloat:!isMobile});var accumShader=createShader(gl);var isOrtho=options.cameraObject&&options.cameraObject._ortho===true||options.camera.projection&&options.camera.projection.type==='orthographic'||false;//Create a camera
var cameraOptions={eye:options.camera.eye||[2,0,0],center:options.camera.center||[0,0,0],up:options.camera.up||[0,1,0],zoomMin:options.camera.zoomMax||0.1,zoomMax:options.camera.zoomMin||100,mode:options.camera.mode||'turntable',_ortho:isOrtho};//Create axes
var axesOptions=options.axes||{};var axes=createAxes(gl,axesOptions);axes.enable=!axesOptions.disable;//Create spikes
var spikeOptions=options.spikes||{};var spikes=createSpikes(gl,spikeOptions);//Object list is empty initially
var objects=[];var pickBufferIds=[];var pickBufferCount=[];var pickBuffers=[];//Dirty flag, skip redraw if scene static
var dirty=true;var pickDirty=true;var projection=new Array(16);var model=new Array(16);var cameraParams={view:null,projection:projection,model:model,_ortho:false};var pickDirty=true;var viewShape=[gl.drawingBufferWidth,gl.drawingBufferHeight];var camera=options.cameraObject||createCamera(canvas,cameraOptions);//Create scene object
var scene={gl:gl,contextLost:false,pixelRatio:options.pixelRatio||1,canvas:canvas,selection:selection,camera:camera,axes:axes,axesPixels:null,spikes:spikes,bounds:bounds,objects:objects,shape:viewShape,aspect:options.aspectRatio||[1,1,1],pickRadius:options.pickRadius||10,zNear:options.zNear||0.01,zFar:options.zFar||1000,fovy:options.fovy||Math.PI/4,clearColor:options.clearColor||[0,0,0,0],autoResize:defaultBool(options.autoResize),autoBounds:defaultBool(options.autoBounds),autoScale:!!options.autoScale,autoCenter:defaultBool(options.autoCenter),clipToBounds:defaultBool(options.clipToBounds),snapToData:!!options.snapToData,onselect:options.onselect||null,onrender:options.onrender||null,onclick:options.onclick||null,cameraParams:cameraParams,oncontextloss:null,mouseListener:null,_stopped:false,getAspectratio:function(){return{x:this.aspect[0],y:this.aspect[1],z:this.aspect[2]};},setAspectratio:function(aspectratio){this.aspect[0]=aspectratio.x;this.aspect[1]=aspectratio.y;this.aspect[2]=aspectratio.z;pickDirty=true;},setBounds:function(axisIndex,range){this.bounds[0][axisIndex]=range.min;this.bounds[1][axisIndex]=range.max;},setClearColor:function(clearColor){this.clearColor=clearColor;},clearRGBA:function(){this.gl.clearColor(this.clearColor[0],this.clearColor[1],this.clearColor[2],this.clearColor[3]);this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT);}};var pickShape=[gl.drawingBufferWidth/scene.pixelRatio|0,gl.drawingBufferHeight/scene.pixelRatio|0];function resizeListener(){if(scene._stopped){return;}if(!scene.autoResize){return;}var parent=canvas.parentNode;var width=1;var height=1;if(parent&&parent!==document.body){width=parent.clientWidth;height=parent.clientHeight;}else{width=window.innerWidth;height=window.innerHeight;}var nextWidth=Math.ceil(width*scene.pixelRatio)|0;var nextHeight=Math.ceil(height*scene.pixelRatio)|0;if(nextWidth!==canvas.width||nextHeight!==canvas.height){canvas.width=nextWidth;canvas.height=nextHeight;var style=canvas.style;style.position=style.position||'absolute';style.left='0px';style.top='0px';style.width=width+'px';style.height=height+'px';dirty=true;}}if(scene.autoResize){resizeListener();}window.addEventListener('resize',resizeListener);function reallocPickIds(){var numObjs=objects.length;var numPick=pickBuffers.length;for(var i=0;i0&&pickBufferCount[numPick-1]===0){pickBufferCount.pop();pickBuffers.pop().dispose();}}scene.update=function(options){if(scene._stopped){return;}options=options||{};dirty=true;pickDirty=true;};scene.add=function(obj){if(scene._stopped){return;}obj.axes=axes;objects.push(obj);pickBufferIds.push(-1);dirty=true;pickDirty=true;reallocPickIds();};scene.remove=function(obj){if(scene._stopped){return;}var idx=objects.indexOf(obj);if(idx<0){return;}objects.splice(idx,1);pickBufferIds.pop();dirty=true;pickDirty=true;reallocPickIds();};scene.dispose=function(){if(scene._stopped){return;}scene._stopped=true;window.removeEventListener('resize',resizeListener);canvas.removeEventListener('webglcontextlost',checkContextLoss);scene.mouseListener.enabled=false;if(scene.contextLost){return;}//Destroy objects
axes.dispose();spikes.dispose();for(var i=0;i