Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements for RLayerTileWMSProps #214

Open
eacpaula opened this issue Feb 21, 2024 · 1 comment
Open

Improvements for RLayerTileWMSProps #214

eacpaula opened this issue Feb 21, 2024 · 1 comment

Comments

@eacpaula
Copy link

Just giving the context about my issue:

I'm using RLayers to load some layers from GeoServer, and I was implementing a print button to make it possible to print only the portion that is visible on the map viewport.

This is an example of the print function:

if (olMap) {
      console.error('Map not found')
      return
    }

    const canvas = olMap.getViewport().querySelector('canvas')
    if (!canvas) {
      console.error('Map canvas not found')
      return
    }

    const imgData = canvas.toDataURL('image/png')
    const pdf = new jsPDF({
      orientation: canvas.width > canvas.height ? 'landscape' : 'portrait',
      unit: 'px',
      format: [canvas.width, canvas.height],
    })

    pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height)
    pdf.save('mapa.pdf')

So, when I try to use functions like "toDataURL" I have errors like this

Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
    at handleClick (http://localhost:3002/static/js/bundle.js:4406:28)
    at HTMLUnknownElement.callCallback (http://localhost:3002/static/js/bundle.js:382147:18)
    at Object.invokeGuardedCallbackDev (http://localhost:3002/static/js/bundle.js:382191:20)
    at invokeGuardedCallback (http://localhost:3002/static/js/bundle.js:382248:35)
    at invokeGuardedCallbackAndCatchFirstError (http://localhost:3002/static/js/bundle.js:382262:29)
    at executeDispatch (http://localhost:3002/static/js/bundle.js:386406:7)
    at processDispatchQueueItemsInOrder (http://localhost:3002/static/js/bundle.js:386432:11)
    at processDispatchQueue (http://localhost:3002/static/js/bundle.js:386443:9)
    at dispatchEventsForPlugins (http://localhost:3002/static/js/bundle.js:386452:7)
    at http://localhost:3002/static/js/bundle.js:386612:16

doing some research on this, I got:

The error "Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported." occurs when you attempt to access or modify the pixels of a canvas that has loaded images from different origins than the page's origin without the correct permissions. This is known as the Same-Origin Policy, a security measure to prevent malicious scripts from reading sensitive data from other sites.

From this point, I already configured GeoServer CORS, and I was trying to pass CORS configuration on the components that I'm using, the RLayers component that not was possible to pass the crossOrigin parameter is the RLayerTileWMS and that's why I'm open the issue to improve the RLayerTileWMSProps.

I also was thinking to fork this repository, implement by myself and use it as a private package, but I'm pretty sure that's not the best way here.

I also have the piece of code that would resolve my issue below:

import TileLayer from 'ol/layer/Tile';
import TileWMS from 'ol/source/TileWMS';

import React from 'react';
import {RContextType} from '../context';
import {default as RLayerRaster, RLayerRasterProps} from './RLayerRaster';

// TileWMS options from https://openlayers.org/en/latest/apidoc/module-ol_source_TileWMS-TileWMS.html
/**
 * @propsfor RLayerTileWMS
 */
export interface RLayerTileWMSProps extends RLayerRasterProps {
    params?: Record<string, unknown>;
    url: string;
    crossOrigin?: string //CHANGE HERE
}

/**
 * Tiled layer using WMS
 */
export default class RLayerTileWMS extends RLayerRaster<RLayerTileWMSProps> {
    ol: TileLayer<TileWMS>;
    source: TileWMS;

    constructor(props: Readonly<RLayerTileWMSProps>, context?: React.Context<RContextType>) {
        super(props, context);
        this.createSource();
        this.ol = new TileLayer({source: this.source});
        this.eventSources = [this.ol, this.source];
    }

    protected createSource(): void {
        const {params, url, crossOrigin, projection} = this.props; //CHANGE HERE
        const options = {params, url, crossOrigin, projection}; //CHANGE HERE

        this.source = new TileWMS(options);
        this.eventSources = [this.ol, this.source];
    }

    protected refresh(prevProps?: RLayerTileWMSProps): void {
        super.refresh(prevProps);
        this.createSource();
        this.ol.setSource(this.source);
        this.attachOldEventHandlers(this.source);
    }
}

I hope that my request makes sense and I need to say thank you, this is the best "React.JS" package that I found to work openlayers!

@mmomtchev
Copy link
Owner

Yes, CORS should be supported, this is indeed an omission. Can you submit a PR, I will merge it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants