import CLASS from './class' import { ChartInternal } from './core' import { isValue, isFunction, isArray, isString, sanitise } from './util' ChartInternal.prototype.initTooltip = function() { var $$ = this, config = $$.config, i $$.tooltip = $$.selectChart .style('position', 'relative') .append('div') .attr('class', CLASS.tooltipContainer) .style('position', 'absolute') .style('pointer-events', 'none') .style('display', 'none') // Show tooltip if needed if (config.tooltip_init_show) { if ($$.isTimeSeries() && isString(config.tooltip_init_x)) { config.tooltip_init_x = $$.parseDate(config.tooltip_init_x) for (i = 0; i < $$.data.targets[0].values.length; i++) { if ($$.data.targets[0].values[i].x - config.tooltip_init_x === 0) { break } } config.tooltip_init_x = i } $$.tooltip.html( config.tooltip_contents.call( $$, $$.data.targets.map(function(d) { return $$.addName(d.values[config.tooltip_init_x]) }), $$.axis.getXAxisTickFormat(), $$.getYFormat($$.hasArcType()), $$.color ) ) $$.tooltip .style('top', config.tooltip_init_position.top) .style('left', config.tooltip_init_position.left) .style('display', 'block') } } ChartInternal.prototype.getTooltipSortFunction = function() { var $$ = this, config = $$.config if (config.data_groups.length === 0 || config.tooltip_order !== undefined) { // if data are not grouped or if an order is specified // for the tooltip values we sort them by their values var order = config.tooltip_order if (order === undefined) { order = config.data_order } var valueOf = function(obj) { return obj ? obj.value : null } // if data are not grouped, we sort them by their value if (isString(order) && order.toLowerCase() === 'asc') { return function(a, b) { return valueOf(a) - valueOf(b) } } else if (isString(order) && order.toLowerCase() === 'desc') { return function(a, b) { return valueOf(b) - valueOf(a) } } else if (isFunction(order)) { // if the function is from data_order we need // to wrap the returned function in order to format // the sorted value to the expected format var sortFunction = order if (config.tooltip_order === undefined) { sortFunction = function(a, b) { return order( a ? { id: a.id, values: [a] } : null, b ? { id: b.id, values: [b] } : null ) } } return sortFunction } else if (isArray(order)) { return function(a, b) { return order.indexOf(a.id) - order.indexOf(b.id) } } } else { // if data are grouped, we follow the order of grouped targets var ids = $$.orderTargets($$.data.targets).map(function(i) { return i.id }) // if it was either asc or desc we need to invert the order // returned by orderTargets if ($$.isOrderAsc() || $$.isOrderDesc()) { ids = ids.reverse() } return function(a, b) { return ids.indexOf(a.id) - ids.indexOf(b.id) } } } ChartInternal.prototype.getTooltipContent = function( d, defaultTitleFormat, defaultValueFormat, color ) { var $$ = this, config = $$.config, titleFormat = config.tooltip_format_title || defaultTitleFormat, nameFormat = config.tooltip_format_name || function(name) { return name }, text, i, title, value, name, bgcolor var valueFormat = config.tooltip_format_value if (!valueFormat) { valueFormat = $$.isTargetNormalized(d.id) ? (v, ratio) => `${(ratio * 100).toFixed(2)}%` : defaultValueFormat } var tooltipSortFunction = this.getTooltipSortFunction() if (tooltipSortFunction) { d.sort(tooltipSortFunction) } for (i = 0; i < d.length; i++) { if (!(d[i] && (d[i].value || d[i].value === 0))) { continue } if ($$.isStanfordGraphType()) { // Custom tooltip for stanford plots if (!text) { title = $$.getStanfordTooltipTitle(d[i]) text = "" + title } bgcolor = $$.getStanfordPointColor(d[i]) name = sanitise(config.data_epochs) // Epochs key name value = d[i].epochs } else { // Regular tooltip if (!text) { title = sanitise(titleFormat ? titleFormat(d[i].x, d[i].index) : d[i].x) text = "
" + (title || title === 0 ? "' : '') } value = sanitise( valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index, d) ) if (value !== undefined) { // Skip elements when their name is set to null if (d[i].name === null) { continue } name = sanitise(nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index)) bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id) } } if (value !== undefined) { text += "" text += "' text += "' text += '' } } return text + '
" + title + '
" + name + '" + value + '
' } ChartInternal.prototype.tooltipPosition = function( dataToShow, tWidth, tHeight, element ) { var $$ = this, config = $$.config, d3 = $$.d3 var svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight var forArc = $$.hasArcType(), mouse = d3.mouse(element) // Determin tooltip position if (forArc) { tooltipLeft = ($$.width - ($$.isLegendRight ? $$.getLegendWidth() : 0)) / 2 + mouse[0] tooltipTop = ($$.hasType('gauge') ? $$.height : $$.height / 2) + mouse[1] + 20 } else { svgLeft = $$.getSvgLeft(true) if (config.axis_rotated) { tooltipLeft = svgLeft + mouse[0] + 100 tooltipRight = tooltipLeft + tWidth chartRight = $$.currentWidth - $$.getCurrentPaddingRight() tooltipTop = $$.x(dataToShow[0].x) + 20 } else { tooltipLeft = svgLeft + $$.getCurrentPaddingLeft(true) + $$.x(dataToShow[0].x) + 20 tooltipRight = tooltipLeft + tWidth chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight() tooltipTop = mouse[1] + 15 } if (tooltipRight > chartRight) { // 20 is needed for Firefox to keep tooltip width tooltipLeft -= tooltipRight - chartRight + 20 } if (tooltipTop + tHeight > $$.currentHeight) { tooltipTop -= tHeight + 30 } } if (tooltipTop < 0) { tooltipTop = 0 } return { top: tooltipTop, left: tooltipLeft } } ChartInternal.prototype.showTooltip = function(selectedData, element) { var $$ = this, config = $$.config var tWidth, tHeight, position var forArc = $$.hasArcType(), dataToShow = selectedData.filter(function(d) { return d && isValue(d.value) }), positionFunction = config.tooltip_position || ChartInternal.prototype.tooltipPosition if (dataToShow.length === 0 || !config.tooltip_show) { $$.hideTooltip() return } $$.tooltip .html( config.tooltip_contents.call( $$, selectedData, $$.axis.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color ) ) .style('display', 'block') // Get tooltip dimensions tWidth = $$.tooltip.property('offsetWidth') tHeight = $$.tooltip.property('offsetHeight') position = positionFunction.call(this, dataToShow, tWidth, tHeight, element) // Set tooltip $$.tooltip .style('top', position.top + 'px') .style('left', position.left + 'px') } ChartInternal.prototype.hideTooltip = function() { this.tooltip.style('display', 'none') }