My business scenario:
You need to use html2canvas to download the map drawn by Openlayers.
Expectation: Can be downloaded as images or even other formats (svg) files.
Result: The download is a blank image.
Troubleshooting errors: The request data is echoed to the page normally. When intercepted using html2canvas, cross-domain will occur, resulting in the inability to draw.
First deal with tomcat cross-domain issues
The first step is to download two jar packages:
1. cors-filter-2.6.jar
https://mvnrepository.com/artifact/com.thetransactioncompany/cors-filter/2.6
2. java-property-utils-1.9.1.jar
https://mvnrepository.com/artifact/com.thetransactioncompany/java-property-utils/1.9.1
Download and place it in the webapps/geoserver/WEB-INF/lib file, as shown in the figure below:
Step 2: Modify the code under webapps/geoserver/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>GeoServer</display-name> <context-param> <param-name>serviceStrategy</param-name> <!-- Meaning of the different values : PARTIAL-BUFFER2 - Partially buffers the first xKb to disk. Once that has buffered, the the result is streamed to the user. This will allow for most errors to be caught early. BUFFER - stores the entire response in memory first, before sending it off to the user (may run out of memory) SPEED - outputs directly to the response (and cannot recover in the case of an error) FILE - outputs to the local filesystem first, before sending it off to the user --> <param-value>PARTIAL-BUFFER2</param-value> </context-param> <context-param> <!-- see comments on the PARTIAL-BUFFER strategy --> <!-- this sets the size of the buffer. default is "50" = 50kb --> <param-name>PARTIAL_BUFFER_STRATEGY_SIZE</param-name> <param-value>50</param-value> </context-param> <!--Can be true or false (defaults to: false). --> <!--When true the JSONP (text/javascript) output format is enabled --> <!-- <context-param> <param-name>ENABLE_JSONP</param-name> <param-value>true</param-value> </context-param> --> <!-- <context-param> <param-name>PROXY_BASE_URL</param-name> <param-value>http://82.58.146.45/geoserver</param-value> </context-param> --> <!-- <context-param> <param-name>GEOSERVER_DATA_DIR</param-name> <param-value>C:\eclipse\workspace\geoserver_trunk\cite\confCiteWFSPostGIS</param-value> </context-param> --> <!-- pick up all spring application contexts --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/applicationContext.xml classpath*:/applicationSecurityContext.xml</param-value> </context-param> <filter> <filter-name>FlushSafeFilter</filter-name> <filter-class>org.geoserver.filters.FlushSafeFilter</filter-class> </filter> <filter> <filter-name>Set Character Encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter> <filter-name>SessionDebugger</filter-name> <filter-class>org.geoserver.filters.SessionDebugFilter</filter-class> </filter> <filter> <filter-name>filterChainProxy</filter-name> <filter-class> org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter> <filter-name>xFrameOptionsFilter</filter-name> <filter-class>org.geoserver.filters.XFrameOptionsFilter</filter-class> </filter> <filter> <filter-name>GZIP Compression Filter</filter-name> <filter-class>org.geoserver.filters.GZIPFilter</filter-class> <init-param> <!-- The compressed-types parameter is a comma-separated list of regular expressions. If a mime type matches any of the regular expressions then it will be compressed. --> <param-name>compressed-types</param-name> <param-value>text/.*,.*xml.*,application/json,application/x-javascript</param-value> </init-param> </filter> <filter> <filter-name>Advanced Dispatch Filter</filter-name> <filter-class>org.geoserver.platform.AdvancedDispatchFilter</filter-class> <!-- This filter allows for a single mapping to the spring dispatcher. However using /* as a mapping in a servlet mapping causes the servlet path to be "/" of the request. This causes problems with library like wicket and restlet. So this filter fakes the servlet path by assuming the first component of the path is the mapped path. --> </filter> <filter> <filter-name>Spring Delegating Filter</filter-name> <filter-class>org.geoserver.filters.SpringDelegatingFilter</filter-class> <!-- This filter allows for filters to be loaded via spring rather than registered here in web.xml. One thing to note is that for such filters init() is not called. INstead any initialization is performed via spring ioc. --> </filter> <filter> <filter-name>Thread locals cleanup filter</filter-name> <filter-class>org.geoserver.filters.ThreadLocalsCleanupFilter</filter-class> <!-- This filter cleans up thread locals Geotools is setting up for concurrency and performance reasons --> </filter> <!-- Uncomment following filter to enable CORS in Jetty. Do not forget the second config block further down. <filter> <filter-name>cross-origin</filter-name> <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class> <init-param> <param-name>chainPreflight</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>allowedOrigins</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>allowedMethods</param-name> <param-value>GET,POST,PUT,DELETE,HEAD,OPTIONS</param-value> </init-param> <init-param> <param-name>allowedHeaders</param-name> <param-value>*</param-value> </init-param> </filter> --> <!-- Uncomment following filter to enable CORS in Tomcat. Do not forget the second config block further down. <filter> <filter-name>cross-origin</filter-name> <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> <init-param> <param-name>cors.allowed.origins</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.allowed.methods</param-name> <param-value>GET,POST,PUT,DELETE,HEAD,OPTIONS</param-value> </init-param> <init-param> <param-name>cors.allowed.headers</param-name> <param-value>*</param-value> </init-param> </filter> --> <!-- THIS FILTER MAPPING MUST BE THE FIRST ONE, otherwise we end up with ruined chars in the input from the GUI See the "Note" in the Tomcat character encoding guide: http://wiki.apache.org/tomcat/FAQ/CharacterEncoding --> <filter-mapping> <filter-name>Set Character Encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Uncomment following filter to enable CORS <filter-mapping> <filter-name>cross-origin</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> --> <filter-mapping> <filter-name>FlushSafeFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>SessionDebugger</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>GZIP Compression Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>xFrameOptionsFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- If you want to use your security system comment out this one too --> <filter-mapping> <filter-name>filterChainProxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>Advanced Dispatch Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>Spring Delegating Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>Thread locals cleanup filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- general initializer, should be first thing to execute --> <listener> <listener-class>org.geoserver.GeoserverInitStartupListener</listener-class> </listener> <!-- logging initializer, should execute before spring context startup --> <listener> <listener-class>org.geoserver.logging.LoggingStartupContextListener</listener-class> </listener> <!-- spring context loader --> <listener> <listener-class>org.geoserver.platform.GeoServerContextLoaderListener</listener-class> </listener> <!-- http session listener proxy --> <listener> <listener-class>org.geoserver.platform.GeoServerHttpSessionListenerProxy</listener-class> </listener> <!-- request context listener for session-scoped beans --> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> <!-- spring dispatcher servlet, dispatches all incoming requests --> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <!-- single mapping to spring, this only works properly if the advanced dispatch filter is active --> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <mime-mapping> <extension>xsl</extension> <mime-type>text/xml</mime-type> </mime-mapping> <mime-mapping> <extension>sld</extension> <mime-type>text/xml</mime-type> </mime-mapping> <mime-mapping> <extension>json</extension> <mime-type>application/json</mime-type> </mime-mapping> <!-- Provide cross-domain support (the code below is core and other users’ own) --> <filter> <filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param> <param-name>cors.allowOrigin</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, POST, HEAD, PUT, DELETE</param-value> </init-param> <init-param> <param-name>cors.supportedHeaders</param-name> <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value> </init-param> <init-param> <param-name>cors.exposedHeaders</param-name> <param-value>Set-Cookie</param-value> </init-param> <init-param> <param-name>cors.supportsCredentials</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app>
Next is to modify the front-end code:
First download the html2canvas dependencies:
npm install –save html2canvas
//Downloaded code download() { const el = document.getElementById("shuilunColorMap") html2canvas(el, { backgroundColor: '#07253B', useCORS: true, // Allow cross-domain // foreignObjectRendering : true, allowTaint :false }).then((canvas) => { const dataURL = canvas.toDataURL('image/png') const creatDom = document.createElement('a') document.body.appendChild(creatDom) creatDom.href = dataURL creatDom.download = 'picture' createDom.click() }) },//Add crossOrigin: 'anonymous' under all new TileLayer var lineView = new TileLayer({ source: new TileWMS({ crossOrigin: 'anonymous', url: URL_MAP, params: { VERSION: "1.1.1", LAYERS: "wanjiazhai_longkou:shuilunji_dwg_Polyline", STYLES: "wjzLine", }, }), });
After completing the above steps, congratulations on solving another Party A’s specific needs. (Girls are welcome to come for consultation, if you have any questions, you can answer them at any time)