@unovis/ts 1.6.0-bigip.1 → 1.6.0-bigip.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/area/index.js +2 -1
- package/components/area/index.js.map +1 -1
- package/components/crosshair/config.d.ts +13 -13
- package/components/crosshair/config.js +1 -1
- package/components/crosshair/config.js.map +1 -1
- package/components/crosshair/index.d.ts +4 -12
- package/components/crosshair/index.js +120 -229
- package/components/crosshair/index.js.map +1 -1
- package/containers/single-container/index.js +3 -1
- package/containers/single-container/index.js.map +1 -1
- package/containers/xy-container/index.js +3 -1
- package/containers/xy-container/index.js.map +1 -1
- package/core/component/index.d.ts +4 -0
- package/core/component/index.js +6 -0
- package/core/component/index.js.map +1 -1
- package/core/xy-component/index.d.ts +1 -0
- package/core/xy-component/index.js +3 -1
- package/core/xy-component/index.js.map +1 -1
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/types/data.d.ts +5 -0
- package/types/data.js +7 -0
- package/types/data.js.map +1 -1
- package/types.js +1 -1
- package/utils/data.d.ts +3 -3
- package/utils/data.js +38 -8
- package/utils/data.js.map +1 -1
package/components/area/index.js
CHANGED
|
@@ -101,7 +101,8 @@ class Area extends XYComponentCore {
|
|
|
101
101
|
getYDataExtent(scaleByVisibleData) {
|
|
102
102
|
const { config, datamodel } = this;
|
|
103
103
|
const yAccessors = (isArray(config.y) ? config.y : [config.y]);
|
|
104
|
-
const
|
|
104
|
+
const xDomain = this.xScale.domain();
|
|
105
|
+
const data = scaleByVisibleData ? filterDataByRange(datamodel.data, xDomain, config.x, true) : datamodel.data;
|
|
105
106
|
return getStackedExtent(data, config.baseline, ...yAccessors);
|
|
106
107
|
}
|
|
107
108
|
_emptyPath() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/components/area/index.ts"],"sourcesContent":["import { select } from 'd3-selection'\nimport { Transition } from 'd3-transition'\nimport { area, Area as AreaInterface } from 'd3-shape'\nimport { interpolatePath } from 'd3-interpolate-path'\n\n// Core\nimport { XYComponentCore } from 'core/xy-component'\n\n// Utils\nimport { getNumber, getString, isArray, isNumber, getStackedExtent, getStackedData, filterDataByRange } from 'utils/data'\nimport { smartTransition } from 'utils/d3'\nimport { getColor } from 'utils/color'\n\n// Types\nimport { Curve, CurveType } from 'types/curve'\nimport { NumericAccessor } from 'types/accessor'\n\n// Local Types\nimport { AreaDatum } from './types'\n\n// Config\nimport { AreaDefaultConfig, AreaConfigInterface } from './config'\n\n// Styles\nimport * as s from './style'\n\nexport class Area<Datum> extends XYComponentCore<Datum, AreaConfigInterface<Datum>> {\n static selectors = s\n protected _defaultConfig = AreaDefaultConfig as AreaConfigInterface<Datum>\n public config: AreaConfigInterface<Datum> = this._defaultConfig\n public stacked = true\n private _areaGen: AreaInterface<AreaDatum>\n private _prevNegative: boolean[] | undefined // To help guessing the stack direction when an accessor was set to null or 0\n\n events = {\n [Area.selectors.area]: {},\n }\n\n constructor (config?: AreaConfigInterface<Datum>) {\n super()\n if (config) this.setConfig(config)\n\n // Determine if the provided chart should be stacked\n this.stacked = Array.isArray(this.config.y)\n }\n\n _render (customDuration?: number): void {\n super._render(customDuration)\n const { config, datamodel: { data } } = this\n const duration = isNumber(customDuration) ? customDuration : config.duration\n\n const curveGen = Curve[config.curveType as CurveType]\n this._areaGen = area<AreaDatum>()\n .x(d => d.x)\n .y0(d => d.y0)\n .y1(d => d.y1)\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n .curve(curveGen)\n\n const yAccessors = (isArray(config.y) ? config.y : [config.y]) as NumericAccessor<Datum>[]\n const areaDataX = data.map((d, i) => this.xScale(getNumber(d, config.x, i)))\n\n const stacked = getStackedData(data, config.baseline, yAccessors, this._prevNegative)\n this._prevNegative = stacked.map(s => !!s.isMostlyNegative)\n const minHeightCumulativeArray: number[] = []\n const stackedData: AreaDatum[][] = stacked.map(\n arr => arr.map(\n (d, j) => {\n const x = areaDataX[j]\n const y0 = this.yScale(d[0])\n const y1 = this.yScale(d[1])\n const isNegativeArea = y1 > y0\n\n // Get cumulative adjustment and apply in the correct direction\n const cumulative = minHeightCumulativeArray[j] || 0\n const adjustedY0 = isNegativeArea ? y0 + cumulative : y0 - cumulative\n const adjustedY1 = isNegativeArea ? y1 + cumulative : y1 - cumulative\n\n // Calculate height adjustment if needed\n let heightAdjustment = 0\n if ((config.minHeight || config.minHeight1Px) &&\n Math.abs(adjustedY1 - adjustedY0) < (config.minHeight ?? 1)) {\n heightAdjustment = (config.minHeight ?? 1) - Math.abs(adjustedY1 - adjustedY0)\n minHeightCumulativeArray[j] = cumulative + heightAdjustment\n }\n\n return {\n x,\n y0: adjustedY0,\n y1: isNegativeArea ? adjustedY1 + heightAdjustment : adjustedY1 - heightAdjustment,\n }\n }\n )\n )\n\n // We reverse the data in order to have the first areas to be displayed on top\n // for better visibility when they're close to zero\n const areaMaxIdx = stackedData.length - 1\n const stackedDataReversed = stackedData.reverse()\n const areas = this.g\n .selectAll<SVGPathElement, AreaDatum>(`.${s.area}`)\n .data(stackedDataReversed)\n\n const areasEnter = areas.enter().append('path')\n .attr('class', s.area)\n .attr('d', d => this._areaGen(d) || this._emptyPath())\n .style('opacity', 0)\n .style('fill', (d, i) => getColor(data, config.color, areaMaxIdx - i))\n\n const areasMerged = smartTransition(areasEnter.merge(areas), duration)\n .style('opacity', (d, i) => {\n const isDefined = d.some(p => (p.y0 - p.y1) !== 0)\n return isDefined ? getNumber(data, config.opacity, areaMaxIdx - i) : 0\n })\n .style('fill', (d, i) => getColor(data, config.color, areaMaxIdx - i))\n .style('cursor', (d, i) => getString(data, config.cursor, areaMaxIdx - i))\n\n if (duration) {\n const transition = areasMerged as Transition<SVGPathElement, AreaDatum[], SVGGElement, AreaDatum[]>\n transition.attrTween('d', (d, i, el) => {\n const previous = select(el[i]).attr('d')\n const next = this._areaGen(d) || this._emptyPath()\n return interpolatePath(previous, next)\n })\n } else {\n areasMerged.attr('d', d => this._areaGen(d) || this._emptyPath())\n }\n\n smartTransition(areas.exit(), duration)\n .style('opacity', 0)\n .remove()\n }\n\n getYDataExtent (scaleByVisibleData: boolean): number[] {\n const { config, datamodel } = this\n const yAccessors = (isArray(config.y) ? config.y : [config.y]) as NumericAccessor<Datum>[]\n\n const data = scaleByVisibleData ? filterDataByRange(datamodel.data, this.xScale.domain() as [number, number], config.x) : datamodel.data\n return getStackedExtent(data, config.baseline, ...yAccessors)\n }\n\n _emptyPath (): string {\n const xRange = this.xScale.range()\n const yDomain = this.yScale.domain() as number[]\n\n const y0 = this.yScale((yDomain[0] + yDomain[1]) / 2)\n const y1 = y0\n\n return this._areaGen([\n { y0, y1, x: xRange[0] },\n { y0, y1, x: xRange[1] },\n ])\n }\n}\n"],"names":["s.area","s"],"mappings":";;;;;;;;;;;;AA0BM,MAAO,IAAY,SAAQ,eAAkD,CAAA;AAYjF,IAAA,WAAA,CAAa,MAAmC,EAAA;AAC9C,QAAA,KAAK,EAAE,CAAA;QAXC,IAAc,CAAA,cAAA,GAAG,iBAA+C,CAAA;AACnE,QAAA,IAAA,CAAA,MAAM,GAA+B,IAAI,CAAC,cAAc,CAAA;QACxD,IAAO,CAAA,OAAA,GAAG,IAAI,CAAA;AAIrB,QAAA,IAAA,CAAA,MAAM,GAAG;AACP,YAAA,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,EAAE;SAC1B,CAAA;AAIC,QAAA,IAAI,MAAM;AAAE,YAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;;AAGlC,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;KAC5C;AAED,IAAA,OAAO,CAAE,cAAuB,EAAA;AAC9B,QAAA,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;QAC7B,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,CAAA;AAC5C,QAAA,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,GAAG,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAA;QAE5E,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,SAAsB,CAAC,CAAA;AACrD,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,EAAa;aAC9B,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aACX,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;aACb,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;;;aAGb,KAAK,CAAC,QAAQ,CAAC,CAAA;QAElB,MAAM,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAA6B,CAAA;AAC1F,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAA;AACrF,QAAA,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAA;QAC3D,MAAM,wBAAwB,GAAa,EAAE,CAAA;AAC7C,QAAA,MAAM,WAAW,GAAkB,OAAO,CAAC,GAAG,CAC5C,GAAG,IAAI,GAAG,CAAC,GAAG,CACZ,CAAC,CAAC,EAAE,CAAC,KAAI;;AACP,YAAA,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;YACtB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC5B,YAAA,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,CAAA;;YAG9B,MAAM,UAAU,GAAG,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AACnD,YAAA,MAAM,UAAU,GAAG,cAAc,GAAG,EAAE,GAAG,UAAU,GAAG,EAAE,GAAG,UAAU,CAAA;AACrE,YAAA,MAAM,UAAU,GAAG,cAAc,GAAG,EAAE,GAAG,UAAU,GAAG,EAAE,GAAG,UAAU,CAAA;;YAGrE,IAAI,gBAAgB,GAAG,CAAC,CAAA;YACxB,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,YAAY;AACxC,gBAAA,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,UAAU,CAAC,IAAI,CAAA,EAAA,GAAA,MAAM,CAAC,SAAS,MAAI,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAA,CAAC,CAAC,EAAE;AAC/D,gBAAA,gBAAgB,GAAG,CAAC,CAAA,EAAA,GAAA,MAAM,CAAC,SAAS,mCAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,UAAU,CAAC,CAAA;AAC9E,gBAAA,wBAAwB,CAAC,CAAC,CAAC,GAAG,UAAU,GAAG,gBAAgB,CAAA;AAC5D,aAAA;YAED,OAAO;gBACL,CAAC;AACD,gBAAA,EAAE,EAAE,UAAU;AACd,gBAAA,EAAE,EAAE,cAAc,GAAG,UAAU,GAAG,gBAAgB,GAAG,UAAU,GAAG,gBAAgB;aACnF,CAAA;SACF,CACF,CACF,CAAA;;;AAID,QAAA,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAA;AACzC,QAAA,MAAM,mBAAmB,GAAG,WAAW,CAAC,OAAO,EAAE,CAAA;AACjD,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC;AACjB,aAAA,SAAS,CAA4B,CAAI,CAAA,EAAAA,MAAM,EAAE,CAAC;aAClD,IAAI,CAAC,mBAAmB,CAAC,CAAA;QAE5B,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;AAC5C,aAAA,IAAI,CAAC,OAAO,EAAEA,MAAM,CAAC;AACrB,aAAA,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;AACrD,aAAA,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;aACnB,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAA;AAExE,QAAA,MAAM,WAAW,GAAG,eAAe,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;aACnE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,KAAI;YACzB,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;YAClD,OAAO,SAAS,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;AACxE,SAAC,CAAC;aACD,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;aACrE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAA;AAE5E,QAAA,IAAI,QAAQ,EAAE;YACZ,MAAM,UAAU,GAAG,WAAgF,CAAA;AACnG,YAAA,UAAU,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,KAAI;AACrC,gBAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACxC,gBAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAA;AAClD,gBAAA,OAAO,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;AACxC,aAAC,CAAC,CAAA;AACH,SAAA;AAAM,aAAA;YACL,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;AAClE,SAAA;AAED,QAAA,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC;AACpC,aAAA,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;AACnB,aAAA,MAAM,EAAE,CAAA;KACZ;AAED,IAAA,cAAc,CAAE,kBAA2B,EAAA;AACzC,QAAA,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;QAClC,MAAM,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAA6B,CAAA;AAE1F,QAAA,MAAM,IAAI,GAAG,kBAAkB,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAsB,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,IAAI,CAAA;QACxI,OAAO,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,CAAA;KAC9D;IAED,UAAU,GAAA;QACR,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAc,CAAA;QAEhD,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QACrD,MAAM,EAAE,GAAG,EAAE,CAAA;QAEb,OAAO,IAAI,CAAC,QAAQ,CAAC;YACnB,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE;YACxB,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE;AACzB,SAAA,CAAC,CAAA;KACH;;AA9HM,IAAS,CAAA,SAAA,GAAGC,KAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/components/area/index.ts"],"sourcesContent":["import { select } from 'd3-selection'\nimport { Transition } from 'd3-transition'\nimport { area, Area as AreaInterface } from 'd3-shape'\nimport { interpolatePath } from 'd3-interpolate-path'\n\n// Core\nimport { XYComponentCore } from 'core/xy-component'\n\n// Utils\nimport { getNumber, getString, isArray, isNumber, getStackedExtent, getStackedData, filterDataByRange } from 'utils/data'\nimport { smartTransition } from 'utils/d3'\nimport { getColor } from 'utils/color'\n\n// Types\nimport { Curve, CurveType } from 'types/curve'\nimport { NumericAccessor } from 'types/accessor'\n\n// Local Types\nimport { AreaDatum } from './types'\n\n// Config\nimport { AreaDefaultConfig, AreaConfigInterface } from './config'\n\n// Styles\nimport * as s from './style'\n\nexport class Area<Datum> extends XYComponentCore<Datum, AreaConfigInterface<Datum>> {\n static selectors = s\n protected _defaultConfig = AreaDefaultConfig as AreaConfigInterface<Datum>\n public config: AreaConfigInterface<Datum> = this._defaultConfig\n public stacked = true\n private _areaGen: AreaInterface<AreaDatum>\n private _prevNegative: boolean[] | undefined // To help guessing the stack direction when an accessor was set to null or 0\n\n events = {\n [Area.selectors.area]: {},\n }\n\n constructor (config?: AreaConfigInterface<Datum>) {\n super()\n if (config) this.setConfig(config)\n\n // Determine if the provided chart should be stacked\n this.stacked = Array.isArray(this.config.y)\n }\n\n _render (customDuration?: number): void {\n super._render(customDuration)\n const { config, datamodel: { data } } = this\n const duration = isNumber(customDuration) ? customDuration : config.duration\n\n const curveGen = Curve[config.curveType as CurveType]\n this._areaGen = area<AreaDatum>()\n .x(d => d.x)\n .y0(d => d.y0)\n .y1(d => d.y1)\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n .curve(curveGen)\n\n const yAccessors = (isArray(config.y) ? config.y : [config.y]) as NumericAccessor<Datum>[]\n const areaDataX = data.map((d, i) => this.xScale(getNumber(d, config.x, i)))\n\n const stacked = getStackedData(data, config.baseline, yAccessors, this._prevNegative)\n this._prevNegative = stacked.map(s => !!s.isMostlyNegative)\n const minHeightCumulativeArray: number[] = []\n const stackedData: AreaDatum[][] = stacked.map(\n arr => arr.map(\n (d, j) => {\n const x = areaDataX[j]\n const y0 = this.yScale(d[0])\n const y1 = this.yScale(d[1])\n const isNegativeArea = y1 > y0\n\n // Get cumulative adjustment and apply in the correct direction\n const cumulative = minHeightCumulativeArray[j] || 0\n const adjustedY0 = isNegativeArea ? y0 + cumulative : y0 - cumulative\n const adjustedY1 = isNegativeArea ? y1 + cumulative : y1 - cumulative\n\n // Calculate height adjustment if needed\n let heightAdjustment = 0\n if ((config.minHeight || config.minHeight1Px) &&\n Math.abs(adjustedY1 - adjustedY0) < (config.minHeight ?? 1)) {\n heightAdjustment = (config.minHeight ?? 1) - Math.abs(adjustedY1 - adjustedY0)\n minHeightCumulativeArray[j] = cumulative + heightAdjustment\n }\n\n return {\n x,\n y0: adjustedY0,\n y1: isNegativeArea ? adjustedY1 + heightAdjustment : adjustedY1 - heightAdjustment,\n }\n }\n )\n )\n\n // We reverse the data in order to have the first areas to be displayed on top\n // for better visibility when they're close to zero\n const areaMaxIdx = stackedData.length - 1\n const stackedDataReversed = stackedData.reverse()\n const areas = this.g\n .selectAll<SVGPathElement, AreaDatum>(`.${s.area}`)\n .data(stackedDataReversed)\n\n const areasEnter = areas.enter().append('path')\n .attr('class', s.area)\n .attr('d', d => this._areaGen(d) || this._emptyPath())\n .style('opacity', 0)\n .style('fill', (d, i) => getColor(data, config.color, areaMaxIdx - i))\n\n const areasMerged = smartTransition(areasEnter.merge(areas), duration)\n .style('opacity', (d, i) => {\n const isDefined = d.some(p => (p.y0 - p.y1) !== 0)\n return isDefined ? getNumber(data, config.opacity, areaMaxIdx - i) : 0\n })\n .style('fill', (d, i) => getColor(data, config.color, areaMaxIdx - i))\n .style('cursor', (d, i) => getString(data, config.cursor, areaMaxIdx - i))\n\n if (duration) {\n const transition = areasMerged as Transition<SVGPathElement, AreaDatum[], SVGGElement, AreaDatum[]>\n transition.attrTween('d', (d, i, el) => {\n const previous = select(el[i]).attr('d')\n const next = this._areaGen(d) || this._emptyPath()\n return interpolatePath(previous, next)\n })\n } else {\n areasMerged.attr('d', d => this._areaGen(d) || this._emptyPath())\n }\n\n smartTransition(areas.exit(), duration)\n .style('opacity', 0)\n .remove()\n }\n\n getYDataExtent (scaleByVisibleData: boolean): number[] {\n const { config, datamodel } = this\n const yAccessors = (isArray(config.y) ? config.y : [config.y]) as NumericAccessor<Datum>[]\n\n const xDomain = this.xScale.domain() as [number, number]\n const data = scaleByVisibleData ? filterDataByRange(datamodel.data, xDomain, config.x, true) : datamodel.data\n return getStackedExtent(data, config.baseline, ...yAccessors)\n }\n\n _emptyPath (): string {\n const xRange = this.xScale.range()\n const yDomain = this.yScale.domain() as number[]\n\n const y0 = this.yScale((yDomain[0] + yDomain[1]) / 2)\n const y1 = y0\n\n return this._areaGen([\n { y0, y1, x: xRange[0] },\n { y0, y1, x: xRange[1] },\n ])\n }\n}\n"],"names":["s.area","s"],"mappings":"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"}
|
|
@@ -21,9 +21,11 @@ export interface CrosshairConfigInterface<Datum> extends WithOptional<XYComponen
|
|
|
21
21
|
baseline?: NumericAccessor<Datum>;
|
|
22
22
|
/** An instance of the Tooltip component to be used with Crosshair. Default: `undefined` */
|
|
23
23
|
tooltip?: Tooltip | undefined;
|
|
24
|
-
/** Tooltip template accessor. The function is supposed to return either a valid HTML string or an HTMLElement.
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
/** Tooltip template accessor. The function is supposed to return either a valid HTML string or an HTMLElement.
|
|
25
|
+
* When `snapToData` is `false`, `datum` will be `undefined` but `data` and `leftNearestDatumIndex` will be provided.
|
|
26
|
+
* Default: `d => ''` */
|
|
27
|
+
template?: (datum: Datum, x: number | Date, data: Datum[], leftNearestDatumIndex: number) => string | HTMLElement;
|
|
28
|
+
/** Hide Crosshair when the corresponding datum element is far from mouse pointer. Default: `true` */
|
|
27
29
|
hideWhenFarFromPointer?: boolean;
|
|
28
30
|
/** Distance in pixels to check in the hideWhenFarFromPointer condition. Default: `100` */
|
|
29
31
|
hideWhenFarFromPointerDistance?: number;
|
|
@@ -34,17 +36,15 @@ export interface CrosshairConfigInterface<Datum> extends WithOptional<XYComponen
|
|
|
34
36
|
*/
|
|
35
37
|
snapToData?: boolean;
|
|
36
38
|
/** Custom function for setting up the crosshair circles, usually needed when `snapToData` is set to `false`.
|
|
37
|
-
* The function receives the horizontal position of the crosshair (in the data space, not in pixels), the data array
|
|
38
|
-
*
|
|
39
|
-
* It has to return an array of the CrosshairCircle objects: `{ y: number; color: string; opacity?: number }[]`.
|
|
39
|
+
* The function receives the horizontal position of the crosshair (in the data space, not in pixels), the data array,
|
|
40
|
+
* the `yScale` instance to help you calculate the correct vertical position of the circles, and the nearest datum index.
|
|
41
|
+
* It has to return an array of the `CrosshairCircle` objects: `{ y: number; color: string; opacity?: number }[]`.
|
|
40
42
|
* Default: `undefined`
|
|
41
43
|
*/
|
|
42
|
-
getCircles?: (x: number | Date
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
/** Force
|
|
46
|
-
|
|
47
|
-
/** Callback function called when crosshair position changes. Receives x position in data space. Default: `undefined` */
|
|
48
|
-
onCrosshairMove?: (x: number | Date | undefined) => void;
|
|
44
|
+
getCircles?: (x: number | Date, data: Datum[], yScale: ContinuousScale, leftNearestDatumIndex: number) => CrosshairCircle[];
|
|
45
|
+
/** Callback function that is called when the crosshair is moved. Default: `undefined` */
|
|
46
|
+
onCrosshairMove?: (x: number | Date, datum: Datum | undefined, datumIndex: number | undefined) => void;
|
|
47
|
+
/** Force the crosshair to show at a specific position. Default: `undefined` */
|
|
48
|
+
forceShowAt?: number | Date;
|
|
49
49
|
}
|
|
50
50
|
export declare const CrosshairDefaultConfig: CrosshairConfigInterface<unknown>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { XYComponentDefaultConfig } from '../../core/xy-component/config.js';
|
|
2
2
|
|
|
3
|
-
const CrosshairDefaultConfig = Object.assign(Object.assign({}, XYComponentDefaultConfig), { yStacked: undefined, baseline: null, duration: 100, tooltip: undefined, template: (d, x) => '', hideWhenFarFromPointer: true, hideWhenFarFromPointerDistance: 100, snapToData: true, getCircles: undefined, color: undefined, strokeColor: undefined, strokeWidth: undefined,
|
|
3
|
+
const CrosshairDefaultConfig = Object.assign(Object.assign({}, XYComponentDefaultConfig), { yStacked: undefined, baseline: null, duration: 100, tooltip: undefined, template: (d, x, data, leftNearestDatumIndex) => '', hideWhenFarFromPointer: true, hideWhenFarFromPointerDistance: 100, snapToData: true, getCircles: undefined, color: undefined, strokeColor: undefined, strokeWidth: undefined, onCrosshairMove: undefined, forceShowAt: undefined });
|
|
4
4
|
|
|
5
5
|
export { CrosshairDefaultConfig };
|
|
6
6
|
//# sourceMappingURL=config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sources":["../../../src/components/crosshair/config.ts"],"sourcesContent":["import { XYComponentConfigInterface, XYComponentDefaultConfig } from 'core/xy-component/config'\nimport { Tooltip } from 'components/tooltip'\n\n// Types\nimport { NumericAccessor, ColorAccessor } from 'types/accessor'\nimport { ContinuousScale } from 'types/scale'\nimport { WithOptional } from 'types/misc'\nimport { CrosshairCircle } from './types'\n\n// We extend partial XY config interface because x and y properties are optional for Crosshair\nexport interface CrosshairConfigInterface<Datum> extends WithOptional<XYComponentConfigInterface<Datum>, 'x' | 'y'> {\n /** Optional accessor function for getting the values along the X axis. Default: `undefined` */\n x?: NumericAccessor<Datum>;\n /** Optional single of multiple accessor functions for getting the values along the Y axis. Default: `undefined` */\n y?: NumericAccessor<Datum> | NumericAccessor<Datum>[];\n /** Optional color array or color accessor function for crosshair circles. Default: `d => d.color` */\n color?: ColorAccessor<Datum>;\n /** Optional stroke color accessor function for crosshair circles. Default: `undefined` */\n strokeColor?: ColorAccessor<Datum>;\n /** Optional stroke width for crosshair circles. Default: `undefined` */\n strokeWidth?: NumericAccessor<Datum>;\n /** Separate array of accessors for stacked components (eg StackedBar, Area). Default: `undefined` */\n yStacked?: NumericAccessor<Datum>[];\n /** Baseline accessor function for stacked values, useful with stacked areas. Default: `null` */\n baseline?: NumericAccessor<Datum>;\n /** An instance of the Tooltip component to be used with Crosshair. Default: `undefined` */\n tooltip?: Tooltip | undefined;\n /** Tooltip template accessor. The function is supposed to return either a valid HTML string or an HTMLElement
|
|
1
|
+
{"version":3,"file":"config.js","sources":["../../../src/components/crosshair/config.ts"],"sourcesContent":["import { XYComponentConfigInterface, XYComponentDefaultConfig } from 'core/xy-component/config'\nimport { Tooltip } from 'components/tooltip'\n\n// Types\nimport { NumericAccessor, ColorAccessor } from 'types/accessor'\nimport { ContinuousScale } from 'types/scale'\nimport { WithOptional } from 'types/misc'\nimport { CrosshairCircle } from './types'\n\n// We extend partial XY config interface because x and y properties are optional for Crosshair\nexport interface CrosshairConfigInterface<Datum> extends WithOptional<XYComponentConfigInterface<Datum>, 'x' | 'y'> {\n /** Optional accessor function for getting the values along the X axis. Default: `undefined` */\n x?: NumericAccessor<Datum>;\n /** Optional single of multiple accessor functions for getting the values along the Y axis. Default: `undefined` */\n y?: NumericAccessor<Datum> | NumericAccessor<Datum>[];\n /** Optional color array or color accessor function for crosshair circles. Default: `d => d.color` */\n color?: ColorAccessor<Datum>;\n /** Optional stroke color accessor function for crosshair circles. Default: `undefined` */\n strokeColor?: ColorAccessor<Datum>;\n /** Optional stroke width for crosshair circles. Default: `undefined` */\n strokeWidth?: NumericAccessor<Datum>;\n /** Separate array of accessors for stacked components (eg StackedBar, Area). Default: `undefined` */\n yStacked?: NumericAccessor<Datum>[];\n /** Baseline accessor function for stacked values, useful with stacked areas. Default: `null` */\n baseline?: NumericAccessor<Datum>;\n /** An instance of the Tooltip component to be used with Crosshair. Default: `undefined` */\n tooltip?: Tooltip | undefined;\n // TODO: Change `datum` type to `Datum | undefined`. This may break the build for many people, so we might want to do it in version 2.0\n /** Tooltip template accessor. The function is supposed to return either a valid HTML string or an HTMLElement.\n * When `snapToData` is `false`, `datum` will be `undefined` but `data` and `leftNearestDatumIndex` will be provided.\n * Default: `d => ''` */\n template?: (datum: Datum, x: number | Date, data: Datum[], leftNearestDatumIndex: number) => string | HTMLElement;\n /** Hide Crosshair when the corresponding datum element is far from mouse pointer. Default: `true` */\n hideWhenFarFromPointer?: boolean;\n /** Distance in pixels to check in the hideWhenFarFromPointer condition. Default: `100` */\n hideWhenFarFromPointerDistance?: number;\n /** Snap to the nearest data point.\n * If disabled, the tooltip template will receive only the horizontal position of the crosshair and you'll be responsible\n * for getting the underlying data records and crosshair circles (see the `getCircles` configuration option).\n * Default: `true`\n */\n snapToData?: boolean;\n /** Custom function for setting up the crosshair circles, usually needed when `snapToData` is set to `false`.\n * The function receives the horizontal position of the crosshair (in the data space, not in pixels), the data array,\n * the `yScale` instance to help you calculate the correct vertical position of the circles, and the nearest datum index.\n * It has to return an array of the `CrosshairCircle` objects: `{ y: number; color: string; opacity?: number }[]`.\n * Default: `undefined`\n */\n getCircles?: (x: number | Date, data: Datum[], yScale: ContinuousScale, leftNearestDatumIndex: number) => CrosshairCircle[];\n /** Callback function that is called when the crosshair is moved. Default: `undefined` */\n onCrosshairMove?: (x: number | Date, datum: Datum | undefined, datumIndex: number | undefined) => void;\n /** Force the crosshair to show at a specific position. Default: `undefined` */\n forceShowAt?: number | Date;\n}\n\nexport const CrosshairDefaultConfig: CrosshairConfigInterface<unknown> = {\n ...XYComponentDefaultConfig,\n yStacked: undefined,\n baseline: null,\n duration: 100,\n tooltip: undefined,\n template: <Datum>(d: Datum, x: number | Date, data: Datum[], leftNearestDatumIndex: number): string => '',\n hideWhenFarFromPointer: true,\n hideWhenFarFromPointerDistance: 100,\n snapToData: true,\n getCircles: undefined,\n color: undefined,\n strokeColor: undefined,\n strokeWidth: undefined,\n onCrosshairMove: undefined,\n forceShowAt: undefined,\n}\n\n"],"names":[],"mappings":";;AAuDO,MAAM,sBAAsB,GAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,EAAA,EAC9B,wBAAwB,CAC3B,EAAA,EAAA,QAAQ,EAAE,SAAS,EACnB,QAAQ,EAAE,IAAI,EACd,QAAQ,EAAE,GAAG,EACb,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,CAAQ,CAAQ,EAAE,CAAgB,EAAE,IAAa,EAAE,qBAA6B,KAAa,EAAE,EACzG,sBAAsB,EAAE,IAAI,EAC5B,8BAA8B,EAAE,GAAG,EACnC,UAAU,EAAE,IAAI,EAChB,UAAU,EAAE,SAAS,EACrB,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,SAAS,EACtB,WAAW,EAAE,SAAS,EACtB,eAAe,EAAE,SAAS,EAC1B,WAAW,EAAE,SAAS;;;;"}
|
|
@@ -11,13 +11,10 @@ export declare class Crosshair<Datum> extends XYComponentCore<Datum, CrosshairCo
|
|
|
11
11
|
config: CrosshairConfigInterface<Datum>;
|
|
12
12
|
container: Selection<SVGSVGElement, any, SVGSVGElement, any>;
|
|
13
13
|
line: Selection<SVGLineElement, any, SVGElement, any>;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
show: boolean;
|
|
14
|
+
private _xPx;
|
|
15
|
+
private _yPx;
|
|
16
|
+
private _mouseEvent;
|
|
18
17
|
private _animFrameId;
|
|
19
|
-
private _dataX;
|
|
20
|
-
private _isMouseOver;
|
|
21
18
|
/** Tooltip component to be used by Crosshair if not provided by the config.
|
|
22
19
|
* This property is supposed to be set externally by a container component like XYContainer. */
|
|
23
20
|
tooltip: Tooltip;
|
|
@@ -27,17 +24,12 @@ export declare class Crosshair<Datum> extends XYComponentCore<Datum, CrosshairCo
|
|
|
27
24
|
get accessors(): CrosshairAccessors<Datum>;
|
|
28
25
|
constructor(config?: CrosshairConfigInterface<Datum>);
|
|
29
26
|
setContainer(containerSvg: Selection<SVGSVGElement, unknown, SVGSVGElement, unknown>): void;
|
|
30
|
-
setConfig(config: CrosshairConfigInterface<Datum>): void;
|
|
31
27
|
_render(customDuration?: number): void;
|
|
32
28
|
hide(): void;
|
|
33
|
-
destroy(): void;
|
|
34
29
|
_onMouseMove(event: MouseEvent): void;
|
|
35
|
-
private _processMouseMove;
|
|
36
30
|
_onMouseOut(): void;
|
|
37
|
-
_showTooltip(
|
|
31
|
+
_showTooltip(datum: Datum, xValue: number, pos: [number, number], nearestDatumIndex: number | undefined): void;
|
|
38
32
|
_hideTooltip(): void;
|
|
39
33
|
getYDataExtent(): number[];
|
|
40
34
|
private getCircleData;
|
|
41
|
-
_updateFromSync(xData: number | Date | undefined): void;
|
|
42
|
-
private _getSyncState;
|
|
43
35
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { pointer } from 'd3-selection';
|
|
2
2
|
import { easeLinear } from 'd3-ease';
|
|
3
3
|
import { XYComponentCore } from '../../core/xy-component/index.js';
|
|
4
|
-
import { isArray, isNumber, getNearest,
|
|
4
|
+
import { isArray, isNumber, getNearest, clamp, getNumber, isFunction, getStackedValues } from '../../utils/data.js';
|
|
5
5
|
import { smartTransition } from '../../utils/d3.js';
|
|
6
6
|
import { getColor } from '../../utils/color.js';
|
|
7
7
|
import { Position } from '../../types/position.js';
|
|
8
|
+
import { FindNearestDirection } from '../../types/data.js';
|
|
8
9
|
import { CrosshairDefaultConfig } from './config.js';
|
|
9
10
|
import * as style from './style.js';
|
|
10
11
|
import { line, circle } from './style.js';
|
|
@@ -15,11 +16,10 @@ class Crosshair extends XYComponentCore {
|
|
|
15
16
|
this.clippable = true; // Don't apply clipping path to this component. See XYContainer
|
|
16
17
|
this._defaultConfig = CrosshairDefaultConfig;
|
|
17
18
|
this.config = this._defaultConfig;
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
19
|
+
this._xPx = undefined;
|
|
20
|
+
this._yPx = undefined;
|
|
21
|
+
this._mouseEvent = undefined;
|
|
20
22
|
this._animFrameId = null;
|
|
21
|
-
this._dataX = undefined;
|
|
22
|
-
this._isMouseOver = false;
|
|
23
23
|
/** Accessors passed externally (e.g. from XYContainer) */
|
|
24
24
|
this._accessors = {
|
|
25
25
|
x: undefined,
|
|
@@ -28,8 +28,8 @@ class Crosshair extends XYComponentCore {
|
|
|
28
28
|
baseline: undefined,
|
|
29
29
|
};
|
|
30
30
|
if (config)
|
|
31
|
-
this.
|
|
32
|
-
this.g.style('opacity',
|
|
31
|
+
this.setConfig(config);
|
|
32
|
+
this.g.style('opacity', 0);
|
|
33
33
|
this.line = this.g.append('line')
|
|
34
34
|
.attr('class', line);
|
|
35
35
|
}
|
|
@@ -37,44 +37,96 @@ class Crosshair extends XYComponentCore {
|
|
|
37
37
|
get accessors() {
|
|
38
38
|
var _a;
|
|
39
39
|
const { config } = this;
|
|
40
|
-
|
|
41
|
-
const x = config.x
|
|
42
|
-
const yAcc = config.y
|
|
40
|
+
const hasConfig = !!(config.x || config.y || config.yStacked);
|
|
41
|
+
const x = hasConfig ? config.x : this._accessors.x;
|
|
42
|
+
const yAcc = hasConfig ? config.y : this._accessors.y;
|
|
43
43
|
const y = yAcc ? (isArray(yAcc) ? yAcc : [yAcc]) : undefined;
|
|
44
|
-
const yStacked = config.yStacked
|
|
44
|
+
const yStacked = hasConfig ? config.yStacked : this._accessors.yStacked;
|
|
45
45
|
const baseline = (_a = config.baseline) !== null && _a !== void 0 ? _a : this._accessors.baseline;
|
|
46
46
|
return { x, y, yStacked, baseline };
|
|
47
47
|
}
|
|
48
48
|
setContainer(containerSvg) {
|
|
49
|
+
// Set up mousemove event for Crosshair
|
|
49
50
|
this.container = containerSvg;
|
|
50
51
|
this.container.on('mousemove.crosshair', this._onMouseMove.bind(this));
|
|
51
52
|
this.container.on('mouseout.crosshair', this._onMouseOut.bind(this));
|
|
52
|
-
this._render();
|
|
53
|
-
}
|
|
54
|
-
setConfig(config) {
|
|
55
|
-
super.setConfig(config);
|
|
56
|
-
// For synchronized charts, update from sync when config changes
|
|
57
|
-
const { isActive, enableSync } = this._getSyncState();
|
|
58
|
-
if (enableSync && !isActive && (isNumber(config.xPosition) || config.xPosition instanceof Date)) {
|
|
59
|
-
this._updateFromSync(config.xPosition);
|
|
60
|
-
}
|
|
61
53
|
}
|
|
62
54
|
_render(customDuration) {
|
|
63
|
-
|
|
55
|
+
var _a, _b, _c, _d;
|
|
56
|
+
const { config, datamodel } = this;
|
|
64
57
|
const duration = isNumber(customDuration) ? customDuration : config.duration;
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
const isForceShowAtDefined = config.forceShowAt !== undefined;
|
|
59
|
+
const xPx = isForceShowAtDefined ? this.xScale(config.forceShowAt) : this._xPx;
|
|
60
|
+
const xValue = this.xScale.invert(xPx);
|
|
61
|
+
const leftNearestDatumIndex = (((_a = datamodel.data) === null || _a === void 0 ? void 0 : _a.length) && this.accessors.x)
|
|
62
|
+
? datamodel.data.indexOf(getNearest(datamodel.data, xValue, this.accessors.x, FindNearestDirection.Left)) : undefined;
|
|
63
|
+
let nearestDatum;
|
|
64
|
+
let nearestDatumIndex;
|
|
65
|
+
if (config.snapToData) {
|
|
66
|
+
if (!this.accessors.y && !this.accessors.yStacked && ((_b = datamodel.data) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
67
|
+
console.warn('Unovis | Crosshair: Y accessors have not been configured. Please check if they\'re present in the configuration object');
|
|
68
|
+
}
|
|
69
|
+
nearestDatum = getNearest(datamodel.data, xValue, this.accessors.x);
|
|
70
|
+
nearestDatumIndex = datamodel.data.indexOf(nearestDatum);
|
|
71
|
+
if (!nearestDatum)
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const xRange = this.xScale.range();
|
|
75
|
+
const yRange = this.yScale.range();
|
|
76
|
+
const xClamped = config.snapToData
|
|
77
|
+
? clamp(Math.round(this.xScale(getNumber(nearestDatum, this.accessors.x, nearestDatumIndex))), 0, this._width)
|
|
78
|
+
: clamp(xPx, xRange[0], xRange[1]);
|
|
79
|
+
const isCrosshairWithinXRange = (xPx >= xRange[0]) && (xPx <= xRange[1]);
|
|
80
|
+
const isCrosshairWithinYRange = (this._yPx >= yRange[1]) && (this._yPx <= yRange[0]);
|
|
81
|
+
let shouldShow = this._xPx ? isCrosshairWithinXRange && isCrosshairWithinYRange : isCrosshairWithinXRange;
|
|
82
|
+
// If the crosshair is far from the mouse pointer (usually when `snapToData` is `true` and data resolution is low), hide it
|
|
83
|
+
if (config.hideWhenFarFromPointer && ((Math.abs(xClamped - (+xPx)) >= config.hideWhenFarFromPointerDistance))) {
|
|
84
|
+
shouldShow = false;
|
|
85
|
+
}
|
|
86
|
+
const tooltip = (_c = config.tooltip) !== null && _c !== void 0 ? _c : this.tooltip;
|
|
87
|
+
if (shouldShow && tooltip) {
|
|
88
|
+
const container = tooltip.getContainer() || this.container.node();
|
|
89
|
+
const isContainerBody = tooltip.isContainerBody();
|
|
90
|
+
if (isForceShowAtDefined) {
|
|
91
|
+
// Convert SVG coordinates to screen coordinates
|
|
92
|
+
const containerRect = this.container.node().getBoundingClientRect();
|
|
93
|
+
// Use the actual left margin from the container
|
|
94
|
+
const screenX = (isContainerBody ? xPx + containerRect.left : xPx) + this._containerMargin.left;
|
|
95
|
+
const screenY = this._height / 2 + (isContainerBody ? containerRect.top : 0);
|
|
96
|
+
const pos = [screenX, screenY];
|
|
97
|
+
this._showTooltip(nearestDatum, xValue, pos, leftNearestDatumIndex);
|
|
98
|
+
}
|
|
99
|
+
else if (this._mouseEvent) {
|
|
100
|
+
const pos = (isContainerBody ? [this._mouseEvent.clientX, this._mouseEvent.clientY] : pointer(this._mouseEvent, container));
|
|
101
|
+
this._showTooltip(nearestDatum, xValue, pos, leftNearestDatumIndex);
|
|
102
|
+
}
|
|
69
103
|
}
|
|
70
|
-
|
|
104
|
+
else
|
|
105
|
+
this._hideTooltip();
|
|
106
|
+
// Trigger `onCrosshairMove` if the render was triggered by a mouse move event
|
|
107
|
+
if (this._mouseEvent) {
|
|
108
|
+
(_d = config.onCrosshairMove) === null || _d === void 0 ? void 0 : _d.call(config, shouldShow ? this.xScale.invert(this._xPx) : undefined, nearestDatum, nearestDatumIndex);
|
|
109
|
+
this._mouseEvent = undefined;
|
|
110
|
+
}
|
|
111
|
+
// When `config.forceShowAt` becomes undefined, the component will "jump" to `this._xPx` which is set to the last mouse position.
|
|
112
|
+
// This looks off, so we set `this._xPx` to `xPx` to make it look like the crosshair is rendered at the forced position
|
|
113
|
+
if (isForceShowAtDefined) {
|
|
114
|
+
this._xPx = undefined;
|
|
115
|
+
}
|
|
116
|
+
smartTransition(this.g, duration)
|
|
117
|
+
.style('opacity', shouldShow ? 1 : 0);
|
|
71
118
|
this.line
|
|
72
119
|
.attr('y1', 0)
|
|
73
|
-
.attr('
|
|
120
|
+
.attr('y1', this._height);
|
|
121
|
+
// Don't render the crosshair if the xPx is not finite
|
|
122
|
+
if (!isFinite(xClamped))
|
|
123
|
+
return;
|
|
74
124
|
smartTransition(this.line, duration, easeLinear)
|
|
75
|
-
.attr('x1',
|
|
76
|
-
.attr('x2',
|
|
77
|
-
const circleData =
|
|
125
|
+
.attr('x1', xClamped)
|
|
126
|
+
.attr('x2', xClamped);
|
|
127
|
+
const circleData = isFunction(config.getCircles)
|
|
128
|
+
? config.getCircles(xValue, datamodel.data, this.yScale, leftNearestDatumIndex)
|
|
129
|
+
: this.getCircleData(nearestDatum, nearestDatumIndex);
|
|
78
130
|
const circles = this.g
|
|
79
131
|
.selectAll('circle')
|
|
80
132
|
.data(circleData, (d, i) => { var _a; return (_a = d.id) !== null && _a !== void 0 ? _a : i; });
|
|
@@ -82,13 +134,13 @@ class Crosshair extends XYComponentCore {
|
|
|
82
134
|
.append('circle')
|
|
83
135
|
.attr('class', circle)
|
|
84
136
|
.attr('r', 0)
|
|
85
|
-
.attr('cx',
|
|
137
|
+
.attr('cx', xClamped)
|
|
86
138
|
.attr('cy', d => d.y)
|
|
87
139
|
.style('fill', d => d.color)
|
|
88
140
|
.style('stroke', d => d.strokeColor)
|
|
89
141
|
.style('stroke-width', d => d.strokeWidth);
|
|
90
142
|
smartTransition(circlesEnter.merge(circles), duration, easeLinear)
|
|
91
|
-
.attr('cx',
|
|
143
|
+
.attr('cx', xClamped)
|
|
92
144
|
.attr('cy', d => d.y)
|
|
93
145
|
.attr('r', 4)
|
|
94
146
|
.style('opacity', d => d.opacity)
|
|
@@ -100,108 +152,36 @@ class Crosshair extends XYComponentCore {
|
|
|
100
152
|
hide() {
|
|
101
153
|
this._onMouseOut();
|
|
102
154
|
}
|
|
103
|
-
destroy() {
|
|
104
|
-
if (this._animFrameId) {
|
|
105
|
-
window.cancelAnimationFrame(this._animFrameId);
|
|
106
|
-
this._animFrameId = null;
|
|
107
|
-
}
|
|
108
|
-
this._hideTooltip();
|
|
109
|
-
}
|
|
110
155
|
_onMouseMove(event) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return;
|
|
114
|
-
this._animFrameId = window.requestAnimationFrame(() => {
|
|
115
|
-
this._processMouseMove(event);
|
|
116
|
-
this._animFrameId = null;
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
_processMouseMove(event) {
|
|
120
|
-
var _a, _b;
|
|
121
|
-
this._isMouseOver = true;
|
|
122
|
-
const { config, datamodel, element } = this;
|
|
123
|
-
const { isActive, enableSync } = this._getSyncState();
|
|
124
|
-
// Early return for synchronized non-active charts, but allow tooltip display
|
|
125
|
-
if (enableSync && !isActive) {
|
|
126
|
-
if (this.show && this.datum) {
|
|
127
|
-
this._showTooltip(event);
|
|
128
|
-
}
|
|
129
|
-
else if (this.show && this._dataX !== undefined && isNumber(this._dataX)) {
|
|
130
|
-
// For synchronized charts, find the datum if it doesn't exist
|
|
131
|
-
this.datum = getNearest(this.datamodel.data, this._dataX, this.accessors.x);
|
|
132
|
-
if (this.datum) {
|
|
133
|
-
this._showTooltip(event);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
// Check if we have the necessary accessors
|
|
156
|
+
var _a;
|
|
157
|
+
const { datamodel, element } = this;
|
|
139
158
|
if (!this.accessors.x && ((_a = datamodel.data) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
140
159
|
console.warn('Unovis | Crosshair: X accessor function has not been configured. Please check if it\'s present in the configuration object');
|
|
141
|
-
return;
|
|
142
160
|
}
|
|
143
|
-
const [x] = pointer(event, element);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const valueX = scaleX.invert(x);
|
|
152
|
-
this.datum = getNearest(datamodel.data, valueX, this.accessors.x);
|
|
153
|
-
this.datumIndex = datamodel.data.indexOf(this.datum);
|
|
154
|
-
if (!this.datum)
|
|
155
|
-
return;
|
|
156
|
-
const dataX = getNumber(this.datum, this.accessors.x, this.datumIndex);
|
|
157
|
-
this.x = clamp(Math.round(scaleX(dataX)), 0, this._width);
|
|
158
|
-
this._dataX = dataX;
|
|
159
|
-
// Show the crosshair only if it's in the chart range and not far from mouse pointer (if configured)
|
|
160
|
-
this.show = (this.x >= 0) && (this.x <= this._width) && (!config.hideWhenFarFromPointer || (Math.abs(this.x - x) < config.hideWhenFarFromPointerDistance));
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
const tolerance = 2; // Show the crosshair when it is at least 2 pixels close to the chart area
|
|
164
|
-
this.x = clamp(x, xRange[0], xRange[1]);
|
|
165
|
-
this._dataX = this.xScale.invert(this.x);
|
|
166
|
-
this.show = (x >= (xRange[0] - tolerance)) && (x <= (xRange[1] + tolerance));
|
|
167
|
-
}
|
|
168
|
-
// Call onCrosshairMove callback if provided
|
|
169
|
-
if (this.show && config.onCrosshairMove && this._dataX !== undefined) {
|
|
170
|
-
config.onCrosshairMove(this._dataX);
|
|
171
|
-
}
|
|
172
|
-
// Render immediately since we're already in a throttled context
|
|
173
|
-
this._render();
|
|
174
|
-
if (this.show)
|
|
175
|
-
this._showTooltip(event);
|
|
176
|
-
else
|
|
177
|
-
this._hideTooltip();
|
|
161
|
+
const [x, y] = pointer(event, element);
|
|
162
|
+
this._xPx = x;
|
|
163
|
+
this._yPx = y;
|
|
164
|
+
this._mouseEvent = event;
|
|
165
|
+
window.cancelAnimationFrame(this._animFrameId);
|
|
166
|
+
this._animFrameId = window.requestAnimationFrame(() => {
|
|
167
|
+
this._render();
|
|
168
|
+
});
|
|
178
169
|
}
|
|
179
170
|
_onMouseOut() {
|
|
180
|
-
this.
|
|
181
|
-
const { config } = this;
|
|
182
|
-
// Always hide on mouse out
|
|
183
|
-
this.show = false;
|
|
184
|
-
this._hideTooltip();
|
|
185
|
-
// Throttle rendering using requestAnimationFrame
|
|
186
|
-
if (this._animFrameId)
|
|
187
|
-
return;
|
|
171
|
+
window.cancelAnimationFrame(this._animFrameId);
|
|
188
172
|
this._animFrameId = window.requestAnimationFrame(() => {
|
|
189
173
|
this._render();
|
|
190
|
-
this._animFrameId = null;
|
|
191
174
|
});
|
|
192
|
-
// If this is the active chart, notify parent to clear sync state
|
|
193
|
-
if (config.onCrosshairMove) {
|
|
194
|
-
config.onCrosshairMove(undefined);
|
|
195
|
-
}
|
|
196
175
|
}
|
|
197
|
-
_showTooltip(
|
|
176
|
+
_showTooltip(datum, xValue, pos, nearestDatumIndex) {
|
|
198
177
|
var _a;
|
|
199
|
-
const
|
|
200
|
-
|
|
178
|
+
const { config, datamodel } = this;
|
|
179
|
+
const tooltip = (_a = config.tooltip) !== null && _a !== void 0 ? _a : this.tooltip;
|
|
180
|
+
if (!tooltip || !pos)
|
|
201
181
|
return;
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
|
|
182
|
+
const [x, y] = pos;
|
|
183
|
+
const content = config.template(datum, xValue, datamodel.data, nearestDatumIndex);
|
|
184
|
+
// Force set `followCursor` to `true` because we don't want Crosshair's tooltip to be hoverable
|
|
205
185
|
tooltip.config.followCursor = true;
|
|
206
186
|
// Set tooltip placement based on Crosshair's position (left / right)
|
|
207
187
|
if (!tooltip.config.horizontalPlacement || tooltip.config.horizontalPlacement === Position.Auto) {
|
|
@@ -213,133 +193,44 @@ class Crosshair extends XYComponentCore {
|
|
|
213
193
|
}
|
|
214
194
|
_hideTooltip() {
|
|
215
195
|
var _a;
|
|
216
|
-
const
|
|
196
|
+
const { config } = this;
|
|
197
|
+
const tooltip = (_a = config.tooltip) !== null && _a !== void 0 ? _a : this.tooltip;
|
|
217
198
|
tooltip === null || tooltip === void 0 ? void 0 : tooltip.hide();
|
|
218
199
|
}
|
|
219
|
-
// We don't want Crosshair to be taken
|
|
200
|
+
// We don't want Crosshair to be be taken in to account in domain calculations
|
|
220
201
|
getYDataExtent() {
|
|
221
202
|
return [undefined, undefined];
|
|
222
203
|
}
|
|
223
|
-
getCircleData() {
|
|
204
|
+
getCircleData(datum, datumIndex) {
|
|
224
205
|
var _a, _b;
|
|
225
|
-
const {
|
|
226
|
-
|
|
227
|
-
if (isFunction(this.config.getCircles)) {
|
|
228
|
-
return this.config.getCircles(this._dataX || this.xScale.invert(this.x), data, this.yScale);
|
|
229
|
-
}
|
|
230
|
-
// Get the datum - either from active mode or from synchronized mode
|
|
231
|
-
let datum = this.datum;
|
|
232
|
-
let datumIndex = this.datumIndex;
|
|
233
|
-
if (!datum && enableSync && !isActive && this._dataX !== undefined) {
|
|
234
|
-
if (isNumber(this._dataX)) {
|
|
235
|
-
datum = getNearest(this.datamodel.data, this._dataX, this.accessors.x);
|
|
236
|
-
datumIndex = this.datamodel.data.indexOf(datum);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
if (this.config.snapToData && datum) {
|
|
206
|
+
const { config } = this;
|
|
207
|
+
if (config.snapToData && datum) {
|
|
240
208
|
const yAccessors = (_a = this.accessors.y) !== null && _a !== void 0 ? _a : [];
|
|
241
209
|
const yStackedAccessors = (_b = this.accessors.yStacked) !== null && _b !== void 0 ? _b : [];
|
|
242
210
|
const baselineValue = getNumber(datum, this.accessors.baseline, datumIndex) || 0;
|
|
243
211
|
const stackedValues = getStackedValues(datum, datumIndex, ...yStackedAccessors)
|
|
244
|
-
.map((value, index) => {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
strokeColor: this.config.strokeColor ? getColor(datum, this.config.strokeColor, index) : undefined,
|
|
252
|
-
strokeWidth: this.config.strokeWidth ? getNumber(datum, this.config.strokeWidth, index) : undefined,
|
|
253
|
-
};
|
|
254
|
-
});
|
|
212
|
+
.map((value, index) => ({
|
|
213
|
+
y: this.yScale(value + baselineValue),
|
|
214
|
+
opacity: isNumber(getNumber(datum, yStackedAccessors[index], index)) ? 1 : 0,
|
|
215
|
+
color: getColor(datum, config.color, index),
|
|
216
|
+
strokeColor: config.strokeColor ? getColor(datum, config.strokeColor, index) : undefined,
|
|
217
|
+
strokeWidth: config.strokeWidth ? getNumber(datum, config.strokeWidth, index) : undefined,
|
|
218
|
+
}));
|
|
255
219
|
const regularValues = yAccessors
|
|
256
220
|
.map((a, index) => {
|
|
257
|
-
const value = getNumber(datum, a);
|
|
258
|
-
const yPixel = isNumber(value) ? this.yScale(value) : 0;
|
|
221
|
+
const value = getNumber(datum, a, datumIndex);
|
|
259
222
|
return {
|
|
260
|
-
y:
|
|
223
|
+
y: this.yScale(value),
|
|
261
224
|
opacity: isNumber(value) ? 1 : 0,
|
|
262
|
-
color: getColor(datum,
|
|
263
|
-
strokeColor:
|
|
264
|
-
strokeWidth:
|
|
225
|
+
color: getColor(datum, config.color, stackedValues.length + index),
|
|
226
|
+
strokeColor: config.strokeColor ? getColor(datum, config.strokeColor, index) : undefined,
|
|
227
|
+
strokeWidth: config.strokeWidth ? getNumber(datum, config.strokeWidth, index) : undefined,
|
|
265
228
|
};
|
|
266
229
|
});
|
|
267
230
|
return stackedValues.concat(regularValues);
|
|
268
231
|
}
|
|
269
|
-
// Return empty array if no data or no datum - crosshair line will still show
|
|
270
232
|
return [];
|
|
271
233
|
}
|
|
272
|
-
_updateFromSync(xData) {
|
|
273
|
-
var _a;
|
|
274
|
-
const { isActive, enableSync } = this._getSyncState();
|
|
275
|
-
if (!enableSync || isActive)
|
|
276
|
-
return;
|
|
277
|
-
// Handle mouse out signal
|
|
278
|
-
if (xData === undefined) {
|
|
279
|
-
this.show = false;
|
|
280
|
-
this._hideTooltip();
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
if (!this.accessors.x || !((_a = this.datamodel.data) === null || _a === void 0 ? void 0 : _a.length))
|
|
284
|
-
return;
|
|
285
|
-
// Check if xPosition is within the chart's x domain
|
|
286
|
-
const xDomain = this.xScale.domain();
|
|
287
|
-
let xValue;
|
|
288
|
-
if (typeof xData === 'number') {
|
|
289
|
-
xValue = xData;
|
|
290
|
-
}
|
|
291
|
-
else if (xData instanceof Date) {
|
|
292
|
-
xValue = xData.getTime();
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
this.show = false;
|
|
296
|
-
this._hideTooltip();
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
// If xPosition is outside the chart's domain, hide the crosshair
|
|
300
|
-
const domainMin = typeof xDomain[0] === 'number' ? xDomain[0] : (xDomain[0] instanceof Date ? xDomain[0].getTime() : 0);
|
|
301
|
-
const domainMax = typeof xDomain[1] === 'number' ? xDomain[1] : (xDomain[1] instanceof Date ? xDomain[1].getTime() : 0);
|
|
302
|
-
if (xValue < domainMin || xValue > domainMax) {
|
|
303
|
-
this.show = false;
|
|
304
|
-
this._hideTooltip();
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
// Find the datum at this x position
|
|
308
|
-
if (typeof xData === 'number') {
|
|
309
|
-
this.datum = getNearest(this.datamodel.data, xData, this.accessors.x);
|
|
310
|
-
}
|
|
311
|
-
else if (xData instanceof Date) {
|
|
312
|
-
this.datum = getNearest(this.datamodel.data, xData.getTime(), this.accessors.x);
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
this.datum = undefined;
|
|
316
|
-
}
|
|
317
|
-
this.datumIndex = this.datamodel.data.indexOf(this.datum);
|
|
318
|
-
// If no datum found, hide the crosshair
|
|
319
|
-
if (!this.datum) {
|
|
320
|
-
this.show = false;
|
|
321
|
-
this._hideTooltip();
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
const dataX = getNumber(this.datum, this.accessors.x, this.datumIndex);
|
|
325
|
-
this.x = clamp(Math.round(this.xScale(dataX)), 0, this._width);
|
|
326
|
-
this._dataX = dataX;
|
|
327
|
-
// Show the crosshair
|
|
328
|
-
this.show = true;
|
|
329
|
-
// Show tooltip for synchronized chart using the same logic as active charts
|
|
330
|
-
const syntheticEvent = {
|
|
331
|
-
clientX: this.container.node().getBoundingClientRect().left + this.x,
|
|
332
|
-
clientY: this.container.node().getBoundingClientRect().top + this._height / 2,
|
|
333
|
-
};
|
|
334
|
-
this._showTooltip(syntheticEvent);
|
|
335
|
-
}
|
|
336
|
-
_getSyncState() {
|
|
337
|
-
// A chart is active if it's being hovered and doesn't have external sync props
|
|
338
|
-
const isActive = this._isMouseOver && !isNumber(this.config.xPosition) && !this.config.forceShow;
|
|
339
|
-
// A chart is in sync mode if it has external sync props (regardless of mouse state)
|
|
340
|
-
const enableSync = isNumber(this.config.xPosition) || !!this.config.forceShow;
|
|
341
|
-
return { isActive, enableSync };
|
|
342
|
-
}
|
|
343
234
|
}
|
|
344
235
|
Crosshair.selectors = style;
|
|
345
236
|
|