@gooddata/react-components
Version:
GoodData.UI - A powerful JavaScript library for building analytical applications
156 lines (135 loc) • 4.84 kB
text/typescript
// (C) 2020 GoodData Corporation
import get = require("lodash/get");
import isEmpty = require("lodash/isEmpty");
import isFinite = require("lodash/isFinite");
import escape = require("lodash/escape");
import mapboxgl from "mapbox-gl";
import { ISeparators } from "@gooddata/numberjs";
import {
TOOLTIP_MAX_WIDTH,
isTooltipShownInFullScreen,
formatValueForTooltip,
getTooltipContentWidth,
} from "../../visualizations/chart/tooltip";
import { DEFAULT_PUSHPIN_COLOR_VALUE, NULL_TOOLTIP_VALUE } from "../../../constants/geoChart";
import { IGeoConfig, IGeoTooltipItem } from "../../../interfaces/GeoChart";
import { parseGeoProperties } from "../../../helpers/geoChart/data";
function isTooltipItemValid(item: IGeoTooltipItem): boolean {
if (!item) {
return false;
}
const { title } = item;
return Boolean(title);
}
function escapeAttributeValue(value: number | string): number | string {
return isFinite(value) ? value : escape(String(value));
}
function formatMeasure(item: IGeoTooltipItem, separators?: ISeparators): IGeoTooltipItem {
const { title, value, format } = item;
return {
title,
value: isFinite(value) ? formatValueForTooltip(value, format, separators) : NULL_TOOLTIP_VALUE,
};
}
function formatAttribute(item: IGeoTooltipItem): IGeoTooltipItem {
const { value } = item;
return {
...item,
value: Boolean(value) ? escapeAttributeValue(value) : NULL_TOOLTIP_VALUE,
};
}
export function shouldShowTooltip(geoProperties: GeoJSON.GeoJsonProperties): boolean {
if (isEmpty(geoProperties)) {
return false;
}
const { locationName, color, size, segment } = geoProperties;
return (
isTooltipItemValid(locationName) ||
isTooltipItemValid(size) ||
isTooltipItemValid(color) ||
isTooltipItemValid(segment)
);
}
export function getTooltipHtml(
geoProperties: GeoJSON.GeoJsonProperties,
tooltipStroke: string,
maxWidth: number,
separators?: ISeparators,
): string {
const { locationName = {}, size = {}, color = {}, segment = {} } = geoProperties;
const tooltipItems: string = [
formatAttribute(locationName),
formatMeasure(size, separators),
formatMeasure(color, separators),
formatAttribute(segment),
]
.map(getTooltipItemHtml)
.join("");
return `<div class="gd-viz-tooltip" style="max-width:${maxWidth}px">
<span class="stroke gd-viz-tooltip-stroke" style="border-top-color: ${tooltipStroke}"></span>
<div class="content gd-viz-tooltip-content">${tooltipItems}</div>
</div>`;
}
function getTooltipItemHtml(item: IGeoTooltipItem): string {
if (!isTooltipItemValid(item)) {
return "";
}
// value is escaped in formatAttribute or formatMeasure function
const { title, value } = item;
return `<div class="gd-viz-tooltip-item">
<span class="gd-viz-tooltip-title">${escape(title)}</span>
<div class="gd-viz-tooltip-value-wraper">
<span class="gd-viz-tooltip-value">${value}</span>
</div>
</div>`;
}
export const handlePushpinMouseEnter = (
e: mapboxgl.EventData,
chart: mapboxgl.Map,
tooltip: mapboxgl.Popup,
config: IGeoConfig,
) => {
if (isTooltipDisabled(config)) {
return;
}
const { separators } = config;
const [feature] = e.features;
const { properties } = feature;
const parsedProps = parseGeoProperties(properties);
if (!shouldShowTooltip(parsedProps)) {
return;
}
chart.getCanvas().style.cursor = "pointer";
const coordinates = feature.geometry.coordinates.slice();
const tooltipStroke = get(parsedProps, "color.background", DEFAULT_PUSHPIN_COLOR_VALUE);
const isFullScreenTooltip = isTooltipShownInFullScreen();
const chartWidth: number = chart.getCanvas().clientWidth;
const maxTooltipContentWidth: number = getTooltipContentWidth(
isFullScreenTooltip,
chartWidth,
TOOLTIP_MAX_WIDTH,
);
const tooltipHtml = getTooltipHtml(parsedProps, tooltipStroke, maxTooltipContentWidth, separators);
tooltip
.setLngLat(coordinates)
.setHTML(tooltipHtml)
.setMaxWidth(`${maxTooltipContentWidth}px`)
.addTo(chart);
};
export const handlePushpinMouseLeave = (
_e: mapboxgl.EventData,
chart: mapboxgl.Map,
tooltip: mapboxgl.Popup,
config: IGeoConfig,
) => {
if (isTooltipDisabled(config)) {
return;
}
chart.getCanvas().style.cursor = "";
tooltip.remove();
};
// Tooltips are now switched off in edit/export mode
function isTooltipDisabled(config: IGeoConfig): boolean {
const { viewport = {} } = config;
return Boolean(viewport.frozen);
}