前端实现一个简单的svg定制地图

前端实现一个简单的svg定制地图

实现的效果

在这里插入图片描述

身为一个三线小城市的开发者,开发管理类的前端项目,必须有一个首页大屏页面,因为领导们都喜欢看这个,于是参考别人的项目也做了一个。
中间的地图模块有点意思,载入的是一张网络上的图片,使用svg技术画了建筑的边框,然后就可以像操作dom一样触发交互了。
中间地图可以换成任何图片,比如大楼的设计图,厂区的平面图等等,实现定制化地图的开发。
绘制svg用的软件是cdr,画布使用像素做单位,将图片载入cdr中,然后绘制轮廓图,导出svg格式的文件就可以在项目中使用了,说起来挺简单,但是学习cdr还是要花点时间的。

地图代码

一想到用代码去画图就很蛋疼,偶然发现cdr可以导出svg格式的文件,本人业余时间喜欢搞点设计绘画什么的,正好派上用场,研究了一下午svg技术,上手做了个这个小东西,给有需求的同学们做个参考。
地图模块没有做窗口自适应。
此项目的框架使用vue。
这是index.vue

<template >
  <div class="chartMain">
    <!-- 闪烁的小方格 -->
    <svg class="commu" width="300px" height="35px" style="transform: scale(0.666667, 0.571429);"><rect fill="#7acaec" x="8.038461538461538" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="19.576923076923077" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.3509551554555508s" begin="0.9979486091755545" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="31.115384615384613" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.7637955340176938s" begin="1.6805424644533238" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="42.65384615384615" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="54.19230769230769" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.3747094662786s" begin="0.19808113937130178" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="65.73076923076923" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.3582927763248147s" begin="0.3826910406214452" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="77.26923076923077" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.2356613685960556s" begin="0.906340497984393" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="88.8076923076923" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.190398572665799s" begin="0.31425562628166226" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="100.34615384615384" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="111.88461538461539" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.7610740681880848s" begin="0.9188888980921393" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="123.42307692307692" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.8660856952000844s" begin="1.1529554149565775" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="134.96153846153845" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="146.5" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.5298307185524032s" begin="0.47617417673840334" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="158.03846153846155" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.095277295656217s" begin="0.5458242166039429" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="169.57692307692307" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="181.1153846153846" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.0882628254060283s" begin="0.12544313244181682" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="192.65384615384616" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="204.19230769230768" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="215.73076923076923" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="227.26923076923077" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.314860655388488s" begin="0.2314555034915884" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="238.8076923076923" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.2923221508749196s" begin="0.1395582878569468" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="250.34615384615384" y="8.166666666666666" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.3398513682820994s" begin="0.5501367445873719" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="261.88461538461536" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="273.4230769230769" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="284.96153846153845" y="8.166666666666666" width="7" height="7"></rect><rect fill="#7acaec" x="8.038461538461538" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="19.576923076923077" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="31.115384615384613" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="42.65384615384615" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.8434621648340461s" begin="1.4854327963498637" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="54.19230769230769" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="65.73076923076923" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="77.26923076923077" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="88.8076923076923" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="100.34615384615384" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="111.88461538461539" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.6792044936409287s" begin="1.852986216666268" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="123.42307692307692" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.540012954273926s" begin="1.7752272962493065" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="134.96153846153845" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="146.5" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="158.03846153846155" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.9457622153010579s" begin="0.8602651128463727" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="169.57692307692307" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.8909055204160286s" begin="1.5640207633154337" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="181.1153846153846" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="192.65384615384616" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.6251410471874284s" begin="1.155740498287225" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="204.19230769230768" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="215.73076923076923" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="227.26923076923077" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.5884886285146997s" begin="0.31865144631108633" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="238.8076923076923" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.7821157194319543s" begin="0.3587508606161629" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="250.34615384615384" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="261.88461538461536" y="19.833333333333332" width="7" height="7"></rect><rect fill="#7acaec" x="273.4230769230769" y="19.833333333333332" width="7" height="7"><animate attributeName="fill" values="#7acaec;transparent" dur="1.05086576292224s" begin="1.6073987662135174" repeatCount="indefinite"></animate></rect><rect fill="#7acaec" x="284.96153846153845" y="19.833333333333332" width="7" height="7"></rect></svg>
    <header>
      <h1>智慧养殖图像项目展示平台</h1>
    </header>

    <showTime></showTime>
    <floatInfo v-show="floatShow" :mapClick11="mapClick" @closeFloatInfo="closeFloatInfo"></floatInfo>

    <section class="mainbox">
      <!-- 左侧 -->
      <div class="column" style="width: 29%;">
        <div class="panel">
          <h2>平均运动量</h2>
          <lineChart style="height: 90%"></lineChart>
          <div class="panel-footer"></div>
        </div>

        <div class="panel">
          <h2>栏位信息</h2>
          <scrollList></scrollList>
          <div class="panel-footer"></div>
        </div>
      </div>
      <!-- 中间 -->
      <div class="column" style="width: 42%;">
        <mainHeader class="mainHeader"></mainHeader>
        <!-- 视频 -->
        <div class="videoCenter">

          <!-- video -->
          <!-- <video style="outline: none;" controls>
            <source src="/movie.mp4"  type="video/mp4">
          </video> -->

          <mapSvg @mapChange="onMapChange"></mapSvg>
        </div>
      </div>

      <!-- 右边 -->
      <div class="column" style="width: 29%;">
        <div class="panel line1">
          <h2>身体指标</h2>
          <progressBar></progressBar>
          <div class="panel-footer"></div>
        </div>

        <div class="panel bar1">
          <h2>整体估重</h2>
          <barChart style="height: 90%"></barChart>
          <div class="panel-footer"></div>
        </div>
      </div>
    </section>
  </div>
</template>

<script>

import lineChart from './cmp/lineChart'
import barChart from './cmp/barChart'
import progressBar from './cmp/progressBar'
import scrollList from './cmp/scrollList'
import mainHeader from './cmp/mainHeader'
import showTime from './cmp/showTime'
import mapSvg from './cmp/mapSvg'
import floatInfo from './cmp/floatInfo'

export default {
  name: "Screen",
  data() {
    return {
      mapClick: 0,
      floatShow: false
    }
  },
  components: {
    lineChart,
    barChart,
    progressBar,
    scrollList,
    mainHeader,
    showTime,
    mapSvg,
    floatInfo
  },
  mounted() {
    
  },
  methods: {
    onMapChange(n) {
      // console.log(n)
      this.mapClick = n
      this.floatShow = true
    },
    closeFloatInfo() {
      this.floatShow = false
    }
  }

};
</script>

<style scoped>

.chartMain {
  background-color: #09163b;
  /* 上面的导航栏是固定的84 */
  /* 必须这么写,height 100%没用 */
  height: calc(100vh - 84px);
  overflow-y: scroll;
}
.chartMain .commu {
  position: absolute;
  top: 15px;
}
header {
  position: relative;
  background: url(/img/head_bg.png) no-repeat top center;
  background-size: 100% 100%;
}
header h1 {
  color: rgb(255, 255, 255);
  margin: 0;
  padding: 20px 0;
  text-align: center;
}

.mainbox {
  /* height: 90vh; */
  padding: 0 1.5rem;
  display: flex;
  margin: 0 auto;
}

/* 每个小块图表 */
.panel {
  position: relative;
  /* 如果设置为百分比,图表在渲染时获取的高度值是不准确的,不能用!!! */
  /* height: 43%; */
  height: 350px;
  border: 1px solid rgba(25, 186, 139, 0.17);
  background: rgba(255, 255, 255, 0.04) url(/img/line.png);
  padding: 7px;
  margin-bottom: 15px;
}
/*四个角的边框 */
.panel::before {
  position: absolute;
  top: 0;
  left: 0;
  content: "";
  width: 10px;
  height: 10px;
  border-top: 2px solid #02a6b5;
  border-left: 2px solid #02a6b5;
  border-radius: 20%;
}
.panel::after {
  position: absolute;
  top: 0;
  right: 0;
  content: "";
  width: 10px;
  height: 10px;
  border-top: 2px solid #02a6b5;
  border-right: 2px solid #02a6b5;
  border-radius: 20%;
}
.panel .panel-footer {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
}
.panel .panel-footer::before {
  position: absolute;
  bottom: 0;
  left: 0;
  content: "";
  width: 10px;
  height: 10px;
  border-bottom: 2px solid #02a6b5;
  border-left: 2px solid #02a6b5;
  border-radius: 20%;
}
.panel .panel-footer::after {
  position: absolute;
  bottom: 0;
  right: 0;
  content: "";
  width: 10px;
  height: 10px;
  border-bottom: 2px solid #02a6b5;
  border-right: 2px solid #02a6b5;
  border-radius: 20%;
}
.panel h2 {
  text-align: center;
  color: #fff;
  font-size: 15px;
  /* 400就是标准值 */
  /* font-weight: 400; */
}

.mainHeader {
  margin: 0 15px;
}

.videoCenter {
  /* background-color: rgb(201, 201, 201); */
  position: relative;
  height: 485px;
  margin: 15px;
  /* color: #fff;
  font-size: 20px;
  text-align: center;
  line-height: 485px;  */
}
/* .videoCenter video {
  width: 100%;
} */

/* 媒体查询 */
/* @media screen and (max-width: 1024px) {
  html {
    font-size: 42px !important;
  }
}
@media screen and (min-width: 1920px) {
  html {
    font-size: 80px !important;
  }
}  */

</style>

这是svg地图的模块

<template>
  <div>

    <svg class="svgAll" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="590px" height="485px" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
      viewBox="0 0 590 485"
      xmlns:xlink="http://www.w3.org/1999/xlink">
      <defs>
        <clipPath id="id0">
          <rect x="2" y="3" width="586" height="479"/>
        </clipPath>
      </defs>
      <g style="clip-path:url(#id0)">
        <image x="2" y="3" width="586" height="479" xlink:href="map.png"/>
      </g>
      <g id="building">
        <path @click="onSvg(1)" class="fil0" d="M89 33c-1,3 -1,10 -2,14 -1,5 -3,7 -5,9 -2,2 -5,2 -7,4 -2,2 -4,5 -5,8 -2,3 -3,6 -3,9 -1,3 -1,7 -1,15 0,8 -1,19 -1,25 0,6 0,6 -1,6 -1,0 -2,0 -3,4 -1,4 -1,11 -1,16 0,5 0,7 1,8 1,1 3,2 9,2 5,0 14,1 24,1 10,0 22,-1 28,-1 6,0 6,0 6,-5 0,-5 0,-15 0,-20 0,-5 -1,-6 -1,-14 0,-8 0,-23 0,-31 0,-8 -1,-9 -3,-10 -2,-1 -6,-2 -9,-1 -3,1 -6,3 -8,4 -2,1 -2,1 -2,-1 0,-2 -1,-6 -2,-10 -1,-4 -3,-7 -5,-11 -2,-4 -4,-8 -5,-13 -1,-4 -2,-9 -2,-11 0,-3 0,-3 -1,-3 -1,0 -2,1 -2,4z"/>
        <path @click="onSvg(2)" class="fil0" d="M355 230c-2,-2 -3,-5 -5,-10 -2,-5 -4,-11 -6,-17 -2,-5 -5,-10 -6,-17 -1,-7 0,-16 1,-21 1,-5 3,-4 6,-3 2,1 5,4 7,5 2,1 4,1 5,0 1,-2 0,-5 1,-7 1,-2 5,-2 7,-2 2,-1 4,-3 5,-3 2,0 4,2 5,4 1,2 1,6 1,9 0,3 1,6 2,6 1,0 2,-1 3,-3 1,-2 0,-5 1,-9 1,-5 3,-11 7,-15 3,-4 7,-6 11,-6 4,0 8,1 12,5 4,4 8,11 12,20 4,9 7,20 8,26 2,6 2,7 2,8 1,1 3,3 4,5 1,2 1,4 -1,6 -2,2 -5,3 -8,3 -3,0 -5,0 -8,0 -3,0 -7,2 -14,4 -8,2 -19,5 -26,6 -7,1 -10,1 -11,1 -2,0 -2,-1 -3,0 -1,1 -2,4 -5,5 -2,2 -5,2 -7,0z"/>
      </g>
    </svg>

  </div>
</template>

<script>
export default {
  name: "MapSvg",
  data() {
    return {};
  },
  mounted() {

  },
  methods: {
    onSvg(n) {
      // console.log(n)
      this.$emit('mapChange', n)
    },
  },
};
</script>

<style scoped>
.svgAll {
  position: absolute;
  top: 0;
  left: 0;
}
#building path:hover {
  cursor: pointer;
  stroke:#d70000;
  stroke-width: 4px;
}
.fil0 {fill:#FEFEFE;fill-opacity:0.200000}
</style>

其他模块的代码就不贴了,canvas和svg的对比网上有很多文章,基本上的结论就是图形量比较少的话svg性能更好,需要大量重绘的项目适合用canvas。
但是svg可以使用其他工具软件画,并且可以当作dom使用,css也可以控制其样式,这些优势canvas是无法比拟的。
代码没啥难点,关键是你得会cdr等矢量图绘制软件。
有此需求的同学可以学习一下绘图软件。

  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值