toggle-corp/react-store

View on GitHub
components/Visualization/Map/MapDownload/index.js

Summary

Maintainability
A
0 mins
Test Coverage
import React from 'react';
import PropTypes from 'prop-types';
import html2canvas from 'html2canvas';

import Button from '../../../Action/Button';
import MapChild from '../MapChild';

const propTypes = {
    // eslint-disable-next-line react/forbid-prop-types
    map: PropTypes.object.isRequired,
    legendContainerClassName: PropTypes.string,
    setDestroyer: PropTypes.func,
    zoomLevel: PropTypes.number,
    mapContainerRef: PropTypes.object, // eslint-disable-line react/forbid-prop-types
    mapStyle: PropTypes.string,
};

const defaultProps = {
    legendContainerClassName: undefined,

    setDestroyer: undefined,
    zoomLevel: undefined,
    mapContainerRef: undefined,
    mapStyle: undefined,
};

class MapDownload extends React.PureComponent {
    static propTypes = propTypes;

    static defaultProps = defaultProps;

    constructor(props) {
        super(props);
        this.state = {
            pending: false,
        };
    }

    export = () => {
        const {
            map,
            legendContainerClassName,
        } = this.props;
        if (!map) {
            console.warn('Cannot export as there is no map');
            return;
        }

        this.setState({ pending: true });
        const mapCanvas = map.getCanvas();

        const canvas = document.createElement('canvas');
        canvas.width = mapCanvas.width;
        canvas.height = mapCanvas.height;

        const context = canvas.getContext('2d');
        context.drawImage(mapCanvas, 0, 0);

        const legend = document.getElementsByClassName(legendContainerClassName);
        if (legend) {
            const promises = Array.from(legend).map((l) => {
                const el = l;
                const prevHeight = el.style.height;
                el.style.height = 'auto';
                const elCanvas = html2canvas(l);
                el.style.height = prevHeight;

                return elCanvas;
            });

            Promise.all(promises).then((canvases) => {
                let y = 6;

                canvases.forEach((c) => {
                    const x = mapCanvas.width - 6 - c.width;
                    context.shadowBlur = 1;
                    context.shadowColor = 'rgba(0, 0, 0, 0.1)';
                    context.drawImage(c, x, y);

                    y += c.height + 6;
                });

                canvas.toBlob((blob) => {
                    const link = document.createElement('a');
                    link.download = 'map-export.png';
                    link.href = URL.createObjectURL(blob);
                    link.click();
                    this.setState({ pending: false });
                }, 'image/png');
            });
        } else {
            canvas.toBlob((blob) => {
                const link = document.createElement('a');
                link.download = 'map-export.png';
                link.href = URL.createObjectURL(blob);
                link.click();
                this.setState({ pending: false });
            }, 'image/png');
        }
    }

    render() {
        const {
            legendContainerClassName, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars, max-len
            setDestroyer, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars
            zoomLevel, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars
            mapContainerRef, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars, max-len
            mapStyle, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars
            ...otherProps
        } = this.props;
        const {
            pending,
        } = this.state;

        return (
            <Button
                pending={pending}
                onClick={this.export}
                {...otherProps}
            />
        );
    }
}

export default MapChild(MapDownload);