You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GeoTools 25-SNAPSHOT(Java11):无刷新在栅格地图添加标记

解决GeoTools添加标记不刷新地图的问题

我明白你的问题了——每次点击添加标记都调用addLayer()导致整个地图重载,这确实影响体验。核心问题是你每次都新建了一个FeatureLayer并加入地图,这会触发MapContent的图层变更事件,进而导致全图重绘。咱们换个思路,复用同一个标记图层,只更新它里面的点数据就可以了,这样地图就不会重载啦!

解决思路

  1. 提前创建一个全局的DefaultFeatureCollection(用来存储所有标记点)和对应的FeatureLayer,并把这个图层添加到MapContent中,只做一次。
  2. 鼠标点击时,不再新建图层,而是直接往已有的DefaultFeatureCollection里添加新的点Feature。
  3. 调用featureCollection.fireFeaturesChanged()触发数据更新事件,让地图只刷新标记图层的内容,而不重载整个栅格底图。
  4. 如果需要用图片作为标记,只需要把SLD的点样式替换为图片符号器即可。

修改后的完整代码

import java.awt.Color;
import java.io.File;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JToolBar;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.coverage.grid.io.GridFormatFinder;
import org.geotools.data.DataUtilities;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.map.FeatureLayer;
import org.geotools.map.GridCoverageLayer;
import org.geotools.map.MapContent;
import org.geotools.styling.SLD;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.geotools.swing.JMapFrame;
import org.geotools.swing.event.MapMouseEvent;
import org.geotools.swing.tool.CursorTool;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

public class Test {
    // 全局的标记点集合和对应的图层,复用这两个对象
    private static DefaultFeatureCollection markerCollection;
    private static SimpleFeatureType MARKER_TYPE;

    public static void main(String[] args) throws Exception {
        try {
            JMapFrame mapFrame;
            File file = new File("mapfile.tif");
            GridFormatFinder.scanForPlugins();
            AbstractGridFormat format = GridFormatFinder.findFormat(file);
            GridCoverage2DReader reader = format.getReader(file);
            GridCoverage2D coverage = (GridCoverage2D) reader.read(null);

            // 创建地图内容并添加栅格底图
            MapContent map = new MapContent();
            map.setTitle("Marker test");
            StyleBuilder sb = new StyleBuilder();
            Style baseStyle = sb.createStyle(sb.createRasterSymbolizer());
            map.addLayer(new GridCoverageLayer(coverage, baseStyle));

            // ---------------------- 关键改动:提前创建标记图层 ----------------------
            // 定义标记点的FeatureType
            MARKER_TYPE = DataUtilities.createType("MarkerLayer", "the_geom:Point");
            // 创建全局的FeatureCollection存储所有标记点
            markerCollection = new DefaultFeatureCollection();
            // 创建标记图层的样式(这里用红圈,后面可以改成图片)
            Style markerStyle = SLD.createPointStyle("Circle", Color.BLACK, Color.RED, 1f, 15f);
            // 创建标记图层并添加到地图,只做一次
            FeatureLayer markerLayer = new FeatureLayer(markerCollection, markerStyle);
            map.addLayer(markerLayer);
            // ---------------------------------------------------------------------

            mapFrame = new JMapFrame(map);
            mapFrame.enableToolBar(true);
            mapFrame.enableStatusBar(true);

            // 工具栏按钮
            JToolBar toolBar = mapFrame.getToolBar();
            Icon icon = new ImageIcon("icon.png");
            JButton btn = new JButton(icon);
            btn.setToolTipText("Add mining manually");
            toolBar.addSeparator();
            toolBar.add(btn);

            // 鼠标点击添加标记的逻辑,现在只更新已有集合
            btn.addActionListener(e -> mapFrame.getMapPane().setCursorTool(new CursorTool() {
                @Override
                public void onMouseClicked(MapMouseEvent ev) {
                    try {
                        DirectPosition2D p = ev.getWorldPos();
                        System.out.println(p.getX() + " -- " + p.getY());
                        // 调用方法往全局集合里添加新标记点
                        addMarkerToCollection(new Coordinate(p.getX(), p.getY()));
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }));

            mapFrame.setTitle("Aeron GIS Utility");
            mapFrame.setSize(2030,830);
            mapFrame.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 往全局的标记集合里添加新的点,并触发更新事件
     */
    static void addMarkerToCollection(Coordinate coords) throws SchemaException {
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
        Point point = geometryFactory.createPoint(coords);
        
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(MARKER_TYPE);
        featureBuilder.add(point);
        // 生成唯一的Feature ID,避免重复
        SimpleFeature feature = featureBuilder.buildFeature("marker_" + System.currentTimeMillis());
        
        // 添加到全局集合
        markerCollection.add(feature);
        // 触发集合变更事件,让地图刷新标记层
        markerCollection.fireFeaturesChanged();
    }

    // 如果需要用图片作为标记,替换上面的markerStyle为下面的方法创建的样式
    static Style createImageMarkerStyle(String imagePath) {
        StyleBuilder sb = new StyleBuilder();
        // 创建图片符号器,设置图片路径和大小
        return sb.createStyle(
            sb.createPointSymbolizer(
                sb.createExternalGraphic(imagePath, "image/png"),
                20 // 图片大小
            )
        );
    }
}

关键改动说明

  • 把原来每次点击创建新图层的逻辑,改成提前创建全局的FeatureCollection和FeatureLayer,只添加一次到地图。
  • 点击时只往这个集合里加新点,然后调用fireFeaturesChanged()通知地图更新这个图层,这样只会刷新标记层,不会重载整个栅格底图。
  • 新增了createImageMarkerStyle方法,如果你需要用图片作为标记,只需要把创建markerStyle的代码替换成调用这个方法即可。

这样修改后,你点击添加标记时,地图就不会重载了,只会在指定位置显示新的标记点~

内容的提问来源于stack exchange,提问作者code_poetry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:04:16