UNPKG

@gooddata/react-components

Version:

GoodData.UI - A powerful JavaScript library for building analytical applications

121 lines (114 loc) 4.71 kB
// (C) 2007-2019 GoodData Corporation import cloneDeep = require("lodash/cloneDeep"); import last = require("lodash/last"); import Highcharts from "./highchartsEntryPoint"; import { IHighchartsAxisExtend, IHighchartsSeriesExtend, IHighchartsSeriesOptionsType, } from "../../../../interfaces/HighchartsExtend"; function between(x: number, lowerLimit: number, higherLimit: number): number { return Math.min(Math.max(lowerLimit, x), higherLimit); } // Fix Highchart issue https://github.com/highcharts/highcharts/issues/11229 export function resetPointPaddingForTooSmallHeatmapCells(series: IHighchartsSeriesExtend) { const xAxis: IHighchartsAxisExtend = series.xAxis; const yAxis: IHighchartsAxisExtend = series.yAxis; const options: IHighchartsSeriesOptionsType = series.options; const seriesPointPadding: number = options.pointPadding || 0; const pointPlacement: number = series.pointPlacementToXValue(); series.points.forEach((point: Highcharts.Point) => { // Recalculate (x1, x2, y1, y2) <=> (left, right, top, bottom) of heatmap cells in pixels // Transform the calculation of x1, x2, y1, y2 from javascripts to typescripts // From source: https://github.com/highcharts/highcharts/blob/v7.1.1/js/parts-map/HeatmapSeries.js#L222 const xPad: number = (options.colsize || 1) / 2; const yPad: number = (options.rowsize || 1) / 2; const x1 = between( Math.round(xAxis.len - xAxis.translate(point.x - xPad, 0, 1, 0, 1, -pointPlacement)), -xAxis.len, 2 * xAxis.len, ); const x2 = between( Math.round(xAxis.len - xAxis.translate(point.x + xPad, 0, 1, 0, 1, -pointPlacement)), -xAxis.len, 2 * xAxis.len, ); const y1 = between( Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)), -yAxis.len, 2 * yAxis.len, ); const y2 = between( Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1)), -yAxis.len, 2 * yAxis.len, ); const pointPadding: number = point.pointPadding || seriesPointPadding; // width: Math.abs(x2 - x1) - pointPadding * 2 // height: Math.abs(y2 - y1) - pointPadding * 2 // Note for highchart upgrading later: // 1. The modification reset only pointPadding property by below `if`. // 2. Another parts just transform javascript to typescripts. if (Math.abs(x2 - x1) < pointPadding * 2 || Math.abs(y2 - y1) < pointPadding * 2) { // reset pointPadding if new width/Height is negative number point.pointPadding = 0; } }); } const HEATMAP_TEMPLATE = { chart: { type: "heatmap", marginTop: 8, marginRight: 0, spacingRight: 0, }, plotOptions: { heatmap: { dataLabels: { enabled: true, allowOverlap: false, crop: true, overflow: "justify", }, point: { events: { // from Highcharts 5.0.0 cursor can be set by using 'className' for individual data items mouseOver() { if (this.drilldown) { this.graphic.element.style.cursor = "pointer"; } }, }, }, events: { afterGeneratePoints() { resetPointPaddingForTooSmallHeatmapCells(this); }, }, }, }, yAxis: [ { labels: { formatter() { const { axis, isLast } = this; const { tickPositions, categories } = axis; // tickPositions is array of index of categories const lastIndex = parseInt(last(tickPositions).toString(), 10); const lastCategory = categories ? categories[lastIndex] : null; let labelValue = axis.defaultLabelFormatter.call(this); // When generate linear tick positions base on categories length. // Last tick position can be out of index of categories. // In this case, set label value to null to ignore last label. if (isLast && categories && !lastCategory) { labelValue = null; } return labelValue; }, }, }, ], }; export function getHeatmapConfiguration() { return cloneDeep(HEATMAP_TEMPLATE); }