terriajs
Version:
Geospatial data visualization platform.
220 lines • 12 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { observer } from "mobx-react";
import { Component, Fragment } from "react";
import defined from "terriajs-cesium/Source/Core/defined";
import Resource from "terriajs-cesium/Source/Core/Resource";
import URI from "urijs";
import isDefined from "../../../Core/isDefined";
import { getMakiIcon } from "../../../Map/Icons/Maki/MakiIcons";
import MinMaxLevelMixin from "../../../ModelMixins/MinMaxLevelMixin";
import TableMixin from "../../../ModelMixins/TableMixin";
import proxyCatalogItemUrl from "../../../Models/Catalog/proxyCatalogItemUrl";
import hasTraits from "../../../Models/Definition/hasTraits";
import Button from "../../../Styled/Button";
import Icon, { StyledIcon } from "../../../Styled/Icon";
import LegendOwnerTraits from "../../../Traits/TraitsClasses/LegendOwnerTraits";
import Styles from "./legend.scss";
/* A lookup map for displayable mime types */
const DISPLAYABLE_MIME_TYPES = [
"image/jpeg",
"image/gif",
"image/png",
"image/svg+xml",
"image/bmp",
"image/x-bmp"
].reduce((acc, mimeType) => {
acc[mimeType] = true;
return acc;
}, {});
const IMAGE_URL_REGEX = /[./](png|jpg|jpeg|gif|svg)/i;
function checkMimeType(legend) {
return ((legend.urlMimeType && !!DISPLAYABLE_MIME_TYPES[legend.urlMimeType]) ||
!!legend.url?.match(IMAGE_URL_REGEX));
}
let Legend = class Legend extends Component {
static defaultProps = {
forPrint: false
};
onImageLoad(evt, legend) {
const image = evt.target;
image.style.display = "none";
image.style.maxWidth = "none";
if (evt.type === "error") {
return;
}
image.style.display = "initial";
// If legend need scaling, this is the only way to do it :/
// See https://stackoverflow.com/questions/7699621/display-image-at-50-of-its-native-size
// or https://stackoverflow.com/questions/35711807/display-high-dpi-image-at-50-scaling-using-just-css
image.style.width = `${(legend.imageScaling ?? 1) * image.offsetWidth}px`;
// Must set maxWidth *after* setting width, as it may change offsetWidth
image.style.maxWidth = "100%";
}
renderLegend(legend, i) {
if (defined(legend.url)) {
return this.renderImageLegend(legend, i);
}
else if (defined(legend.items)) {
return this.renderGeneratedLegend(legend, i);
}
return null;
}
renderImageLegend(legend, _i) {
const isImage = checkMimeType(legend);
// const insertDirectly = !!legend.safeSvgContent; // we only insert content we generated ourselves, not arbitrary SVG from init files.
// const svg = legend.safeSvgContent;
// // Safari xlink NS issue fix
// const processedSvg = svg ? svg.replace(/NS\d+:href/gi, "xlink:href") : null;
// const safeSvgContent = { __html: processedSvg };
/* We proxy the legend so it's cached, and so that the Print/Export feature works with non-CORS servers.
* We make it absolute because the print view is opened on a different domain (about:blank) so relative
* URLs will not work.
*/
const proxiedUrl = isDefined(legend.url)
? makeAbsolute(proxyCatalogItemUrl(this.props.item, legend.url))
: undefined;
// padding-top: 8px;
// padding-bottom: 8px;
// if (isImage && insertDirectly) {
// return (<li
// key={i}
// className={Styles.legendSvg}
// dangerouslySetInnerHTML={safeSvgContent}
// />)
// }
if (!isDefined(proxiedUrl))
return null;
if (isImage) {
return (_jsx("li", { children: _jsx("a", { href: proxiedUrl, className: Styles.imageAnchor, target: "_blank", rel: "noreferrer noopener", css: { backgroundColor: legend.backgroundColor }, children: _jsx("img", { src: proxiedUrl,
// Set maxWidth to 100% if no scaling required (otherwise - see onImageLoad)
style: {
maxWidth: !isDefined(legend.imageScaling) || legend.imageScaling === 1
? "100%"
: undefined
}, onError: (evt) => this.onImageLoad.bind(this, evt, legend)(), onLoad: (evt) => this.onImageLoad.bind(this, evt, legend)() }) }) }, proxiedUrl));
}
return (_jsx("li", { children: _jsx("a", { href: proxiedUrl, target: "_blank", rel: "noreferrer noopener", className: Styles.legendOpenExternally, children: "Open legend in a separate tab" }) }, proxiedUrl));
}
renderGeneratedLegend(legend, i) {
if (isDefined(legend.items) && legend.items.length > 0) {
return (_jsx("li", { className: Styles.generatedLegend, children: _jsx("table", { css: { backgroundColor: legend.backgroundColor }, children: _jsx("tbody", { children: legend.items.map(this.renderLegendItem.bind(this)) }) }) }, i));
}
return null;
}
renderLegendItem(legendItem, i) {
let imageUrl = legendItem.imageUrl;
if (legendItem.marker) {
imageUrl =
getMakiIcon(legendItem.marker, legendItem.color ?? "#fff", // We have to have a fallback color here for `getMakiIcon`
legendItem.outlineWidth, legendItem.outlineColor, legendItem.imageHeight, legendItem.imageWidth) ??
// If getMakiIcons returns nothing, we assume legendItem.marker is a URL
legendItem.marker;
}
// Set boxStyle border to solid black if we aren't showing an image AND this legend item has space above it
let boxStyle = {
border: !imageUrl && legendItem.addSpacingAbove ? "1px solid black" : undefined
};
// Override the boxStyle border if we have outlineColor and outlineWidth defined for this legend item
if (!imageUrl && legendItem.outlineColor && legendItem.outlineWidth) {
boxStyle.border = `${legendItem.outlineWidth}px ${legendItem.outlineStyle ?? "solid"} ${legendItem.outlineColor}`;
}
let boxContents;
// Browsers don't print background colors by default, so we render things a little differently.
// Chrome and Firefox let you override this, but not IE and Edge. So...
if (this.props.forPrint) {
if (imageUrl) {
boxContents = (_jsx("img", { width: "20px", height: "16px", src: imageUrl, style: { transform: `rotate(${legendItem.rotation ?? 0}deg)` } }));
}
else {
boxContents = _jsx(_Fragment, { children: "\u25A0" });
boxStyle = {
color: legendItem.color,
fontSize: "48px",
lineHeight: "16px",
...boxStyle
};
}
}
else {
if (imageUrl || legendItem.marker) {
boxStyle = {
transform: `rotate(${legendItem.rotation}deg)`,
backgroundImage: `url(${imageUrl})`,
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
backgroundSize: "24px",
width: `${legendItem.imageWidth}px`,
...boxStyle
};
}
else {
boxStyle = {
backgroundColor: legendItem.color,
minWidth: "20px",
...boxStyle
};
}
}
const rowStyle = {
height: `${legendItem.imageHeight + 2}px`
};
return (_jsxs(Fragment, { children: [legendItem.addSpacingAbove && (_jsx("tr", { className: Styles.legendSpacer, children: _jsx("td", {}) })), _jsxs("tr", { style: rowStyle, children: [_jsx("td", { style: boxStyle, children: boxContents }), _jsxs("td", { className: Styles.legendTitles, children: [legendItem.titleAbove && (_jsx("div", { className: Styles.legendTitleAbove, children: legendItem.titleAbove })), _jsx("div", { title: isDefined(legendItem.multipleTitles)
? legendItem.multipleTitles.join(", ")
: legendItem.title, children: isDefined(legendItem.multipleTitles)
? `${legendItem.multipleTitles
.slice(0, legendItem.maxMultipleTitlesShowed)
.join(", ")}${legendItem.multipleTitles.length >
legendItem.maxMultipleTitlesShowed
? "..."
: ""}`
: legendItem.title }), legendItem.titleBelow && (_jsx("div", { className: Styles.legendTitleBelow, children: legendItem.titleBelow }))] })] })] }, i));
}
render() {
if ((!hasTraits(this.props.item, LegendOwnerTraits, "legends") ||
!hasTraits(this.props.item, LegendOwnerTraits, "hideLegendInWorkbench")) &&
!TableMixin.isMixedInto(this.props.item)) {
return null;
}
if ((hasTraits(this.props.item, LegendOwnerTraits, "hideLegendInWorkbench") &&
this.props.item.hideLegendInWorkbench) ||
(MinMaxLevelMixin.isMixedInto(this.props.item) &&
this.props.item.scaleWorkbenchInfo))
return null;
if (isDefined(this.props.item.legends) &&
this.props.item.legends.length > 0) {
const backgroundColor = hasTraits(this.props.item, LegendOwnerTraits, "legendBackgroundColor")
? this.props.item.legendBackgroundColor
: undefined;
return (_jsx("ul", { className: Styles.legend, children: _jsxs("div", { className: Styles.legendInner, css: { position: "relative", " li": { backgroundColor } }, children: [
// Show temporary "legend button" - if custom styling has been applied
TableMixin.isMixedInto(this.props.item) &&
this.props.item.legendButton ? (_jsx(Button, { primary: true, shortMinHeight: true, css: { position: "absolute", top: 10, right: 0 }, renderIcon: () => (_jsx(StyledIcon, { light: true, glyph: Icon.GLYPHS.menuDotted, styledWidth: "12px" })), rightIcon: true, iconProps: { css: { marginRight: 0, marginLeft: 4 } }, onClick: this.props.item.legendButton.onClick.bind(this.props.item), children: this.props.item.legendButton.title })) : null, this.props.item.legends.map((legend, i) => (_jsxs(Fragment, { children: [isDefined(legend.title) ? (_jsx("h3", { className: Styles.legendTitle, children: legend.title })) : null, this.renderLegend.bind(this)(legend, i)] }, i)))] }) }));
}
return null;
}
};
Legend = __decorate([
observer
], Legend);
export default Legend;
function makeAbsolute(url) {
if (url instanceof Resource) {
url = url.url;
}
const uri = new URI(url);
if (uri.protocol() &&
uri.protocol() !== "http" &&
uri.protocol() !== "https") {
return url;
}
else {
return uri.absoluteTo(window.location.href).toString();
}
}
//# sourceMappingURL=Legend.js.map