SVG实现中国地图

这篇具有很好参考价值的文章主要介绍了SVG实现中国地图。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.SVG是什么?

svg 是Scalable Vector Graphics的缩写,指可伸缩矢量图形,可以用于绘制复杂不规则的控件。

svg绘制原理,就是利用了Path绘制图形。
1)svg利用xml定义图形。在xml中就包晗了绘制Path所需的数据。
2)加载xml中的PathData,转换成Path对象。
3)利用Canvas,把Path绘制在屏幕上了。
4)处理点击事件。

path支持的指令有:
M = moveto(M X,Y) :将画笔移动到指定的坐标位置
L = lineto(L X,Y) :画直线到指定的坐标位置
H = horizontal lineto(H X):画水平线到指定的X坐标位置
V = vertical lineto(V Y):画垂直线到指定的Y坐标位置
C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三次贝赛曲线
S = smooth curveto(S X2,Y2,ENDX,ENDY)
Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二次贝赛曲线
T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线
Z = closepath():关闭路径

2.利用SVG绘制中国地图

1)利用Dom解析xml数据,把省份信息解析成java对象。
下面就是svg的数据格式。其中pathData保存的就是绘制省份地图所需要的path信息。

<path
    id="340000"
    title="安徽"
    class="land"
    pathData="M541.02,336.29L541.71,336.09L543.77,338.27L543.53,338.58..."

利用Dom解析Xml。将xml中定义的标签转换成JavaBean

关键代码将xml中定义的PathData转换成Java中Path对象。

  Path path = PathParser.createPathFromPathData(pathData);

InputStream in = getResources().openRawResource(R.raw.china);
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder documentBuilder = null;
    try {
        documentBuilder = factory.newDocumentBuilder();
        Document document = documentBuilder.parse(in);
        NodeList nodeList = document.getElementsByTagName("path");
        list = new ArrayList<>();
        float left = -1;
        float top = -1;
        float right = -1;
        float bottom = -1;

        for (int i = 0; i < nodeList.getLength(); i++) {
            Element node = (Element) nodeList.item(i);
            //拿到定义在xml中的pathData数据
            String pathData = node.getAttribute("pathData");
            //利用PathParser转换成Path对象。
            Path path = PathParser.createPathFromPathData(pathData);
            String name = node.getAttribute("title");
            ProviceItem item = new ProviceItem();
            item.path = path;
            item.name = name;
            item.drawColor = colorArray[i % colorArray.length];
            list.add(item);

            RectF rectF = new RectF();
            path.computeBounds(rectF, true);

            //下面是为了拿到整个地图的最左、最上、最右、最下的坐标值。
            left = left == -1 ? rectF.left : Math.min(left, rectF.left);
            top = top == -1 ? rectF.top : Math.min(top, rectF.top);
            right = right == -1 ? rectF.right : Math.max(right, rectF.right);
            bottom = bottom == -1 ? rectF.bottom : Math.max(bottom, rectF.bottom);

        }
        //通过坐标值,构建一个矩形,就是地图要绘制的矩形区域。
        mapRectF = new RectF(left, top, right, bottom);

    } catch (Exception e) {
        e.printStackTrace();
    }

将得到的list集合设置给自定义的MapView。 

public void setData(List<ProviceItem> list, RectF rectF) {
    this.list = list;
    this.mapRectF = rectF;
    if (mapRectF != null) {
        //拿到地图的原始大小
        double mapWidth = mapRectF.width();
        //拿到缩放比,使绘制的地图宽度铺满。
        scale = (float) (mWidth / mapWidth);
    }
    //调用View的onDraw方法
    postInvalidate();
}
在onMeasure时,拿到MapView的宽度。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mWidth = MeasureSpec.getSize(widthMeasureSpec);
}

2)自定义View绘制地图。执行完MapView的onDraw方法,地图就显示到了屏幕上。

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (list != null && list.size() > 0) {
        canvas.save();
        //按获得的缩放比,对画布进行缩放
        canvas.scale(scale, scale);
        for (ProviceItem proviceItem : list) {
            //selectItem 是被选中的item。
            //调用ProviceItem的方法,绘制自己省份的地图。
            proviceItem.drawItem(canvas, paint, selectItem == proviceItem);
        }
    }
}

        将JavaBean中封装的Path对象,通过canvas.drawPath(path,paint),绘制到屏幕上。

 public void drawItem(Canvas canvas, Paint paint, boolean isSelect) {
        //选中状态
        if (isSelect) {
            //清除绘制的阴影
            paint.clearShadowLayer();
            paint.setStrokeWidth(2);
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(drawColor);
            paint.setShadowLayer(1, 2, 2, 0xffffff);
            canvas.drawPath(path, paint);
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.BLACK);
            //将拿到的path绘制到画布上
            canvas.drawPath(path, paint);
        } else {
            //未选择状态
            paint.setStrokeWidth(1);
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(drawColor);
            canvas.drawPath(path, paint);
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.BLACK);
            //将拿到的path绘制到画布上
            canvas.drawPath(path, paint);
        }

    }

3)给每一个省份添加点击事件。首先要判断点击的是哪个省份地图。

在ViewGroup做事件分发处理时,判断触摸点落在哪个View上,View是一个矩形,比较容易判断,省份是一个不规则的图形,怎么判断呢?

先看下ViewGroup中是如何处理点击事件的落点的。

   public boolean pointInView(float localX, float localY, float slop) {
          return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
                  localY < ((mBottom - mTop) + slop);
  }

 但是要判断触摸点,落在哪个地图上,和上面的类似,但也有不同。
 通常View可以接收事件的区域是一个规则的矩形,但地图确实不规则的,
 这里用到了Region,来对不规则的View做事件的相应。具体做法,看代码实现。

复写onTouchEvent方法。

在按下时进行判断,也可以在手指滑动过程中进行判断。

手指抬起后,恢复原来状态。

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //按下时响应
            handleOnTouch((int) event.getX(), (int) event.getY());
            break;
        case MotionEvent.ACTION_MOVE:
            //移动过程中响应
            handleOnTouch((int) event.getX(), (int) event.getY());
            break;
        case MotionEvent.ACTION_UP:
            //手指抬起来后,恢复原来状态
            selectItem = null;
            postInvalidate();
            break;
    }
    return true;
}

 拿到手指落点的x,y坐标和省份的Region进行对比。Region封装了一个path。

调用region.contains((int)x, (int)y)方法,就可以和落点进行比对。

ProviceItem selectItem = null;
private void handleOnTouch(int x, int y) {
    if (list == null || list.size() <= 0) {
        return;
    }
    ProviceItem select = null;
    for (int i = 0; i < list.size(); i++) {
        ProviceItem item = list.get(i);
        //isTouch返回true,说明一件匹配到了相应的省份地图来响应事件。
        if (item.isTouch(x / scale, y / scale)) {
            select = item;
            if (select != selectItem) {//判断按下的是同一个,则不重复触发绘制。
                //调用onDraw方法。
                postInvalidate();
            }
            selectItem = select;
            return;
        }
    }
}

public boolean isTouch(float x, float y) {
    RectF rectF = new RectF();
    //计算出path路径的边距,并把得到的值存在RectF中
    path.computeBounds(rectF, true);
    //创建一个和RectF矩形大小的区域
    Region region = new Region();
    //将path的路径,设置到region中,
    region.setPath(path, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));
    //通过这个api就能够判断触摸点,是否落在了path绘制的区域内
    return region.contains((int)x, (int)y);
}


到这,中国地图绘制、事件的相应核心代码已经完毕。
举一反三,上面的代码也可以用于绘制其他SVG等不规则的图形。
核心点就三个,解析xml,绘制path,事件响应。

Demo链接:

android开发之SVG实现中国地图-Android文档类资源-CSDN下载文章来源地址https://www.toymoban.com/news/detail-444822.html

到了这里,关于SVG实现中国地图的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • html Antv L7 + mapbox 实现3D地图 3D中国地图 不限于中国地图

    echarts的3D地图实在太丑了,还一堆bug 使用阿里的Antv可视化库L7,实现3D地图,底图是mapbox 参考示例:https://l7.antv.antgroup.com/zh/examples/polygon/3d#floatMap 如果不需要底图样式,可把Scene的style设置为blank 直接上代码了,vue的就不说了,项目是html的 mapbox依赖 L7依赖 body元素 实现

    2024年02月14日
    浏览(51)
  • echarts实现中国地图记录篇之2D,3D地图

    工具: 实现2D平面地图需要用到的包为:echarts 实现3D地图需要用到的包为:echarts,echarts-gl 版本 —— echarts5.0+和5.0以下版本的差异: echarts 5.0以下的版本,做中国地图,推荐使用\\\"echarts\\\": \\\"^4.9.0\\\"版本,安装、引入和使用方式,如下: Echarts官方在5+版本中移除了echarts/map/js/china.

    2023年04月08日
    浏览(37)
  • 基于Vue3 + ts + echarts(版本5.X)实现中国地图下钻、地图打点、地图热力图功能

    写在前面: 实现效果图   1.比较重要的部分用 红字 标出  2.安装echats:         3.由于echarts5版本的已经没有自带地图数据了,所以地图数据需要到专门的GEO数据网站中下载。这里提供一个阿里的下载地址:DataV.GeoAtlas地理小工具系列 对于这个工具网站,有一个重点需要说一

    2024年02月09日
    浏览(50)
  • 用Three.js实现3D中国地图的可视化大屏

    在前端开发中,使用Three.js库可以轻松创建各种令人印象深刻的3D效果。本文将介绍如何使用Three.js库创建一个令人惊叹的3D中国地图可视化大屏。我们将使用JavaScript和Three.js来呈现中国地图,并添加一些交互功能。 首先,我们需要在HTML页面中引入Three.js库。你可以从官方网站

    2024年02月03日
    浏览(106)
  • vue项目中使用echarts和china.js实现中国地图

    在echarts最新的5.4.0版本中,已不能直接引用china.js来绘制中国地图,需要我们自己下载china.js包 在网上查找资料,大部分是在index.html文件中直接引入echarts和china.js文件,但我使用这种方法在vue项目中引入失败,目前尝试可行的方法是把包下载到node_modules的echarts包里面,文件和

    2024年02月13日
    浏览(39)
  • Echarts中国地图与世界地图实战

    Echarts中中国地图与世界地图实战,完整代码。 其中 china.js 与 world.js 两个文件已通过CDN的方法给出,而 echarts.js 大家可以自行去官网下载。 echarts.js是百度团队推出的一款用于图表可视化的插件,用于以图表的形式展现数据,功能强大,上手简单。 版本区别: 1.完全版:ec

    2024年02月03日
    浏览(90)
  • Python 地图篇 - 使用pyecharts绘制世界地图、中国地图、省级地图、市级地图实例详解

    [ 系列文章篇 ] 2022 见证中国崛起从 Python 绘制中国地图开始:使用 pyecharts 最新版本绘制中国地图实例详解,个性化地图定制及常用参数解析 [ 专栏推荐 ] Python 短视频自动化发布,包含抖音、快手、 bilibili 、小红书、微视、好看视频、西瓜视频、视频号等 10 余种平台 先给大

    2024年02月03日
    浏览(47)
  • Python绘制中国地图

     1. 导入库 2. 导入数据 3. 南海九段线部分数据预处理 开始绘图之前需进行数据选择,即中国区域的数据,特别是绘制南海小地图的更需要,可避免一些问题(小地图上方出现完整地图) 4. 定义掩膜方法,从全球的nc数据中,裁出中国地图部分的数据(根据shp文件裁剪nc数据)

    2024年02月06日
    浏览(42)
  • 大屏echarts示例------中国地图

    最近做了几个大屏,有很多echarts图表,挑重要的记录一下: 1. 中国地图 首先要找一个json文件,包含中国地区内所有地方的经纬度和名称等,初始化地图的时候需要 这里的city就是我的json文件。在上方引入即可 这里我把它放在和大屏index同目录下了,注意引入时的路径 然后

    2024年02月03日
    浏览(52)
  • ECharts 图表简单示例,中国地图

    2024年01月25日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包