apexcharts
Version:
A JavaScript Chart Library
373 lines (297 loc) • 10.6 kB
JavaScript
import Graphics from '../Graphics'
import Series from '../Series'
/**
* ApexCharts Tooltip.Position Class to move the tooltip based on x and y position.
*
* @module Tooltip.Position
**/
export default class Position {
constructor (tooltipContext) {
this.ttCtx = tooltipContext
this.ctx = tooltipContext.ctx
this.w = tooltipContext.w
}
/**
* This will move the crosshair (the vertical/horz line that moves along with mouse)
* Along with this, this function also calls the xaxisMove function
* @memberof Position
* @param {int} - cx = point's x position, wherever point's x is, you need to move crosshair
*/
moveXCrosshairs (cx, j = null) {
const ttCtx = this.ttCtx
let w = this.w
const xcrosshairs = ttCtx.getElXCrosshairs()
let x = cx - ttCtx.xcrosshairsWidth / 2
let tickAmount = w.globals.labels.slice().length
if (j !== null) {
x = (w.globals.gridWidth / tickAmount) * j
}
if (w.config.xaxis.crosshairs.width === 'tickWidth' || w.config.xaxis.crosshairs.width === 'barWidth') {
if (x + ttCtx.xcrosshairsWidth > w.globals.gridWidth) {
x = w.globals.gridWidth - ttCtx.xcrosshairsWidth
}
} else {
if (j !== null) {
x = x + (w.globals.gridWidth / tickAmount) / 2
}
}
if (x < 0) {
x = 0
}
if (x > w.globals.gridWidth) {
x = w.globals.gridWidth
}
if (xcrosshairs !== null) {
xcrosshairs.setAttribute('x', x)
xcrosshairs.classList.add('active')
}
if (ttCtx.blxaxisTooltip) {
let tx = x
if (w.config.xaxis.crosshairs.width === 'tickWidth' || w.config.xaxis.crosshairs.width === 'barWidth') {
tx = x + ttCtx.xcrosshairsWidth / 2
}
this.moveXAxisTooltip(tx)
}
}
/**
* This will move the crosshair (the vertical/horz line that moves along with mouse)
* Along with this, this function also calls the xaxisMove function
* @memberof Position
* @param {int} - cx = point's x position, wherever point's x is, you need to move crosshair
*/
moveYCrosshairs (cy) {
const ttCtx = this.ttCtx
if (ttCtx.ycrosshairs !== null) {
Graphics.setAttrs(ttCtx.ycrosshairs, {
y1: cy,
y2: cy
})
Graphics.setAttrs(ttCtx.ycrosshairsHidden, {
y1: cy,
y2: cy
})
}
}
/**
** AxisTooltip is the small rectangle which appears on x axis with x value, when user moves
* @memberof Position
* @param {int} - cx = point's x position, wherever point's x is, you need to move
*/
moveXAxisTooltip (cx) {
let w = this.w
const ttCtx = this.ttCtx
if (ttCtx.xaxisTooltip !== null) {
ttCtx.xaxisTooltip.classList.add('active')
let cy = ttCtx.xaxisOffY + w.config.xaxis.tooltip.offsetY + w.globals.translateY + 1 + w.config.xaxis.offsetY
let xaxisTTText = ttCtx.xaxisTooltip.getBoundingClientRect()
let xaxisTTTextWidth = xaxisTTText.width
cx = cx - (xaxisTTTextWidth / 2)
if (!isNaN(cx)) {
cx = cx + w.globals.translateX
let textRect = 0
const graphics = new Graphics(this.ctx)
textRect = graphics.getTextRects(ttCtx.xaxisTooltipText.innerHTML)
ttCtx.xaxisTooltipText.style.minWidth = textRect.width + 'px'
ttCtx.xaxisTooltip.style.left = cx + 'px'
ttCtx.xaxisTooltip.style.top = cy + 'px'
}
}
}
moveYAxisTooltip (index) {
const w = this.w
const ttCtx = this.ttCtx
if (ttCtx.yaxisTTEls === null) {
ttCtx.yaxisTTEls = w.globals.dom.baseEl.querySelectorAll('.apexcharts-yaxistooltip')
}
const ycrosshairsHiddenRectY1 = parseInt(ttCtx.ycrosshairsHidden.getAttribute('y1'))
let cy = w.globals.translateY + ycrosshairsHiddenRectY1
const yAxisTTRect = ttCtx.yaxisTTEls[index].getBoundingClientRect()
const yAxisTTHeight = yAxisTTRect.height
let cx = w.globals.translateYAxisX[index] - 2
if (w.config.yaxis[index].opposite) {
cx = cx - 26
}
cy = cy - yAxisTTHeight / 2
if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1) {
ttCtx.yaxisTTEls[index].classList.add('active')
ttCtx.yaxisTTEls[index].style.top = cy + 'px'
ttCtx.yaxisTTEls[index].style.left = cx + w.config.yaxis[index].tooltip.offsetX + 'px'
} else {
ttCtx.yaxisTTEls[index].classList.remove('active')
}
}
/**
** moves the whole tooltip by changing x, y attrs
* @memberof Position
* @param {int} - cx = point's x position, wherever point's x is, you need to move tooltip
* @param {int} - cy = point's y position, wherever point's y is, you need to move tooltip
* @param {int} - r = point's radius
*/
moveTooltip (cx, cy, r = null) {
let w = this.w
let ttCtx = this.ttCtx
const tooltipEl = ttCtx.getElTooltip()
let tooltipRect = ttCtx.tooltipRect
let pointR = r !== null ? parseInt(r) : 1
let x = parseInt(cx) + pointR + 5
let y = parseInt(cy) + pointR / 2 // - tooltipRect.ttHeight / 2
if (x > w.globals.gridWidth / 2) {
x = x - tooltipRect.ttWidth - pointR - 15
}
if (x > w.globals.gridWidth - tooltipRect.ttWidth - 10) {
x = w.globals.gridWidth - tooltipRect.ttWidth
}
if (x < -20) {
x = -20
}
if (w.config.tooltip.followCursor) {
const elGrid = ttCtx.getElGrid()
const seriesBound = elGrid.getBoundingClientRect()
y = ttCtx.e.clientY - seriesBound.top - tooltipRect.ttHeight / 2
}
const newPositions = this.positionChecks(tooltipRect, x, y)
x = newPositions.x
y = newPositions.y
if (!isNaN(x)) {
x = x + w.globals.translateX
tooltipEl.style.left = x + 'px'
tooltipEl.style.top = y + 'px'
}
}
positionChecks (tooltipRect, x, y) {
const w = this.w
if (tooltipRect.ttHeight + y > w.globals.gridHeight) {
y = w.globals.gridHeight - tooltipRect.ttHeight + w.globals.translateY
}
if (y < 0) {
y = 0
}
return {
x, y
}
}
moveMarkers (i, j) {
let w = this.w
let ttCtx = this.ttCtx
if (w.globals.markers.size[i] > 0) {
let allPoints = w.globals.dom.baseEl.querySelectorAll(` .apexcharts-series[data\\:realIndex='${i}'] .apexcharts-marker`)
for (let p = 0; p < allPoints.length; p++) {
if (parseInt(allPoints[p].getAttribute('rel')) === j) {
ttCtx.marker.resetPointsSize()
ttCtx.marker.enlargeCurrentPoint(j, allPoints[p])
}
}
} else {
ttCtx.marker.resetPointsSize()
this.moveDynamicPointOnHover(
j,
i
)
}
}
// This function is used when you need to show markers/points only on hover -
// DIFFERENT X VALUES in multiple series
moveDynamicPointOnHover (j, capturedSeries) {
let w = this.w
let ttCtx = this.ttCtx
let cx = 0
let cy = 0
let pointsArr = w.globals.pointsArray
let hoverSize = w.config.markers.hover.size
if (hoverSize === undefined) {
hoverSize = w.globals.markers.size[capturedSeries] + w.config.markers.hover.sizeOffset
}
cx = pointsArr[capturedSeries][j][0]
cy = pointsArr[capturedSeries][j][1] ? pointsArr[capturedSeries][j][1] : 0
let point = w.globals.dom.baseEl.querySelector(
`.apexcharts-series[data\\:realIndex='${capturedSeries}'] .apexcharts-series-markers circle`
)
point.setAttribute('r', hoverSize)
point.setAttribute('cx', cx)
point.setAttribute('cy', cy)
// point.style.opacity = w.config.markers.hover.opacity
this.moveXCrosshairs(cx)
if (!ttCtx.fixedTooltip) {
this.moveTooltip(cx, cy, hoverSize)
}
}
// This function is used when you need to show markers/points only on hover -
// SAME X VALUES in multiple series
moveDynamicPointsOnHover (j) {
const ttCtx = this.ttCtx
let w = ttCtx.w
let cx = 0
let cy = 0
let activeSeries = 0
let pointsArr = w.globals.pointsArray
let series = new Series(this.ctx)
activeSeries = series.getActiveSeriesIndex()
let hoverSize = w.config.markers.hover.size
if (hoverSize === undefined) {
hoverSize = w.globals.markers.size[activeSeries] + w.config.markers.hover.sizeOffset
}
if (pointsArr[activeSeries]) {
cx = pointsArr[activeSeries][j][0]
cy = pointsArr[activeSeries][j][1]
}
let points = null
const allPoints = ttCtx.getAllMarkers()
if (allPoints !== null) {
points = allPoints
} else {
points = w.globals.dom.baseEl.querySelectorAll(
'.apexcharts-series-markers circle'
)
}
if (points !== null) {
for (let p = 0; p < points.length; p++) {
let pointArr = pointsArr[p]
if (pointArr && pointArr.length) {
let pcy = pointsArr[p][j][1]
points[p].setAttribute('cx', cx)
let realIndex = parseInt(
points[p].parentNode.parentNode.parentNode.getAttribute(
'data:realIndex'
)
)
if (pcy !== null) {
points[realIndex] && points[realIndex].setAttribute('r', hoverSize)
points[realIndex] && points[realIndex].setAttribute('cy', pcy)
} else {
points[realIndex] && points[realIndex].setAttribute('r', 0)
}
}
}
}
this.moveXCrosshairs(cx)
if (!ttCtx.fixedTooltip) {
let tcy = cy || w.globals.gridHeight
this.moveTooltip(cx, tcy, hoverSize)
}
}
moveStickyTooltipOverBars (j) {
const w = this.w
const ttCtx = this.ttCtx
let jBar = w.globals.dom.baseEl.querySelector(`.apexcharts-bar-series .apexcharts-series[rel='1'] path[j='${j}'], .apexcharts-candlestick-series .apexcharts-series[rel='1'] path[j='${j}']`)
let bcx = jBar ? parseFloat(jBar.getAttribute('cx')) : 0
let bcy = 0
let bw = jBar ? parseFloat(jBar.getAttribute('barWidth')) : 0
if (w.globals.isXNumeric) {
bcx = bcx - bw / 2
} else {
bcx = ttCtx.xAxisTicksPositions[j - 1] + (ttCtx.dataPointsDividedWidth / 2)
if (isNaN(bcx)) {
bcx = ttCtx.xAxisTicksPositions[j] - (ttCtx.dataPointsDividedWidth / 2)
}
}
// tooltip will move vertically along with mouse as it is a shared tooltip
const elGrid = ttCtx.getElGrid()
let seriesBound = elGrid.getBoundingClientRect()
bcy = ttCtx.e.clientY - seriesBound.top - ttCtx.tooltipRect.ttHeight / 2
this.moveXCrosshairs(bcx)
if (!ttCtx.fixedTooltip) {
let tcy = bcy || w.globals.gridHeight
this.moveTooltip(bcx, tcy)
}
}
}