Skip to content

Commit

Permalink
chore: refactor legend as FC (#3488)
Browse files Browse the repository at this point in the history
  • Loading branch information
hwbllmnn authored Sep 2, 2023
1 parent 44551ea commit 937674b
Showing 1 changed file with 98 additions and 170 deletions.
268 changes: 98 additions & 170 deletions src/Legend/Legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,30 @@ import Logger from '@terrestris/base-util/dist/Logger';
import MapUtil from '@terrestris/ol-util/dist/MapUtil/MapUtil';

import { CSS_PREFIX } from '../constants';
import { useEffect, useState } from 'react';

/**
* Get the corresponding legendGraphic of a layer. If layer is configured with
* "legendUrl" this will be used. Otherwise a getLegendGraphic requestString
* will be created by the MapUtil.
*
* @param legendLayer The layer to get the legend graphic request for.
* @param params The extra params.
*/
const getLegendUrl = (
legendLayer: OlLayerTile<OlSourceTileWMS> | OlLayerImage<OlSourceImageWMS>,
params: any
) => {
let url;

if (legendLayer.get('legendUrl')) {
url = legendLayer.get('legendUrl');
} else {
url = MapUtil.getLegendGraphicUrl(legendLayer, params);
}

return url;
};

export interface BaseProps {
/**
Expand Down Expand Up @@ -46,25 +70,6 @@ export interface BaseProps {
headers?: HeadersInit;
}

interface LegendState {
/**
* The current loading state of the legend image.
*/
loading: boolean;
/**
* The base64 encoded image for the legend.
*/
imgSrc: string;
/**
* The legend url.
*/
legendUrl: string;
/**
* Flag indicating if loading of the image source lead to an error
*/
legendError: boolean;
}

export type LegendProps = BaseProps & React.HTMLAttributes<HTMLDivElement>;

/**
Expand All @@ -73,178 +78,101 @@ export type LegendProps = BaseProps & React.HTMLAttributes<HTMLDivElement>;
* @class Legend
* @extends React.Component
*/
export class Legend extends React.Component<LegendProps, LegendState> {

/**
* The className added to this component.
* @private
*/
className = `${CSS_PREFIX}legend`;

/**
* Create the Legend.
*
* @constructs Legend
*/
constructor(props: LegendProps) {
super(props);
const {
layer,
extraParams
} = props;

this.state = {
// A transparent 1 x 1 px image
// eslint-disable-next-line max-len
imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',
legendUrl: this.getLegendUrl(layer, extraParams),
legendError: false,
loading: false
};
}

componentDidMount() {
this.setLegendSrc();
}

/**
* Invoked immediately after updating occurs. This method is not called for
* the initial render.
*
* @param prevProps The previous props.
*/
componentDidUpdate(prevProps: LegendProps) {
const {
extraParams,
layer
} = this.props;

if (extraParams && !(_isEqual(extraParams, prevProps.extraParams))) {
this.setState({
legendUrl: this.getLegendUrl(layer, extraParams)
}, this.setLegendSrc);
}
}

async setLegendSrc() {
const {
headers
} = this.props;

export const Legend: React.FC<LegendProps> = ({
className,
layer,
extraParams,
onError,
errorMsg,
headers,
...passThroughProps
}) => {

// eslint-disable-next-line
const [imgSrc, setImgSrc] = useState('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=');
const [legendUrl, setLegendUrl] = useState(getLegendUrl(layer, extraParams));
const [legendError, setLegendError] = useState(false);
const [loading, setLoading] = useState(false);

useEffect(() => {
setLegendSrc();
}, []);

useEffect(() => {
setLegendUrl(getLegendUrl(layer, extraParams));
setLegendSrc();
}, []);

const setLegendSrc = async () => {
try {
this.setState({
loading: true
});
setLoading(true);

const response = await fetch(this.state.legendUrl, {
const response = await fetch(legendUrl, {
headers
});

if (!response.ok) {
throw new Error('No successful response returned while getting the legend graphic');
}

if (this.state.imgSrc) {
URL.revokeObjectURL(this.state.imgSrc);
if (imgSrc) {
URL.revokeObjectURL(imgSrc);
}

this.setState({
imgSrc: URL.createObjectURL(await response.blob())
});
setImgSrc(URL.createObjectURL(await response.blob()));
} catch (error) {
Logger.error('Error while setting the img src: ', error);

this.onError(error);
handleError(error);
} finally {
this.setState({
loading: false
});
}
}

/**
* Get the corresponding legendGraphic of a layer. If layer is configured with
* "legendUrl" this will be used. Otherwise a getLegendGraphic requestString
* will be created by the MapUtil.
*
* @param layer The layer to get the legend graphic request for.
* @param extraParams The extra params.
*/
getLegendUrl(layer: OlLayerTile<OlSourceTileWMS> | OlLayerImage<OlSourceImageWMS>, extraParams: any) {
let legendUrl;

if (layer.get('legendUrl')) {
legendUrl = layer.get('legendUrl');
} else {
legendUrl = MapUtil.getLegendGraphicUrl(layer, extraParams);
setLoading(false);
}

return legendUrl;
}
};

/**
* onError handler for the rendered img.
*/
onError(e: any) {
Logger.warn(`Image error for legend of "${this.props.layer.get('name')}".`);
this.setState({
legendError: true
});
if (this.props.onError) {
this.props.onError(e);
const handleError = (e: any) => {
Logger.warn(`Image error for legend of "${layer.get('name')}".`);
setLegendError(true);
if (onError) {
onError(e);
}
}

/**
* The render function.
*/
render() {
const {
className,
layer,
extraParams,
errorMsg,
...passThroughProps
} = this.props;

const finalClassName = className
? `${className} ${this.className}`
: this.className;

const alt = layer.get('name')
? layer.get('name') + ' legend'
: 'layer legend';

return (
<div
className={finalClassName}
{...passThroughProps}
};

const alt = layer.get('name')
? layer.get('name') + ' legend'
: 'layer legend';

return (
<div
className={`${CSS_PREFIX}legend ${className ? className : ''}`}
{...passThroughProps}
>
<Spin
spinning={loading}
indicator={(
<FontAwesomeIcon
icon={faCircleNotch}
/>
)}
>
<Spin
spinning={this.state.loading}
indicator={(
<FontAwesomeIcon
icon={faCircleNotch}
/>
)}
>
{this.state.legendError ?
<div
className='legend-load-error'
>
{errorMsg}
</div>
:
<img
src={this.state.imgSrc}
alt={alt}
onError={this.onError.bind(this)}
/>
}
</Spin>
</div>
);
}
}
{legendError ?
<div
className='legend-load-error'
>
{errorMsg}
</div>
:
<img
src={imgSrc}
alt={alt}
onError={handleError.bind(this)}
/>
}
</Spin>
</div>
);
};

export default Legend;

0 comments on commit 937674b

Please sign in to comment.