等值线/面生成一站式封装

等值线/面生成一站式封装

选择要生成的点

  • 前台页面
<a-modal
      title="设置"
      :width="900"
      :visible="AnalysisVisible"
      @ok="AnalysishandleSubmit"
      @cancel="AnalysishandleCancel"
    >
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">年份:</span>
        <el-select v-model="Analysis.year" placeholder="请选择">
          <el-option v-for="item in AnalysisYear" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">月份:</span>
        <el-select v-model="Analysis.month" placeholder="请选择">
          <el-option v-for="item in AnalysisMonth" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">等值面颜色设定:</span
        ><color-select :color-list="colorList" v-model="settings.color"></color-select>
      </div>
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">间隔设定:</span>
        <el-select v-model="settings.interval" placeholder="请选择">
          <el-option v-for="item in intervaloptions" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">生成类型:</span>
        <el-button-group>
          <el-button :type="type1" @click="typeSele('isobands')">等值面</el-button>
          <el-button :type="type2" @click="typeSele('isolines')">等值线 </el-button>
        </el-button-group>
      </div>
    </a-modal>
  • 给后台一个数组,返回的数据格式options如下
{
    color: "rgba(218,165,32,1)",
    extent: (4)[115.63528641258763, 38.69892119142736, 116.3275678594995, 39.17138063219472],
    interval: 1,
    type: "isobands",
    x: (17)[116.13, 116.09, 116.17],
    y: (17)[39.14, 39.09, 39.02],
    z: (17)[24.6, 24.5, 24.3],
        }

传递给mapgis插件(自封装),通过openlayers代码生成等值线

  • 封装类


/**
    功能:   等值线 等值面 
    参数: 
    作者:Moke
    邮箱:zjmoke1026@163.com
    时间:2021年07月23日 14:22:01
    版本:v1.0
    修改记录:
    修改内容:
    修改时间:2021年07月23日 14:22:01
   */
var self;
import geojsonObject from '../../../../public/loading/xa2000.json'
export default class EquivaTool {
    constructor(map) {
        self = this
        this.map = map
        this.WFSVectorSource = null
        this.WFSVectorLayer = null
        this.vectorLayer = null
        this.vectorSource = null
        this.select = new ol.interaction.Select()
        this.dragBox = new ol.interaction.DragBox({
            condition: ol.events.condition.platformModifierKeyOnly,
        })
    }
        /******* 
     * @description: 
     * @param {*} options  前台给的配置项
     * @return {*}
     */
    //    等值线isolines  or  等值面isobands
    CreateIsolines(options, cb) {
        // 传递过来的z 的最大最小值
        var min = Math.floor(Math.min.apply(null, options.z) - 2)
        var max = Math.ceil(Math.max.apply(null, options.z) + 5)
        // 根据z值范围调整  
        var breaks = []
        // 对值进行处理
        for (let i = 0, j = min; j < max; i++) {
            breaks.push(j)
            j += options.interval
        }
        //  isolines --线 isobands--面
        let params = {
            mapCenter: [116.14, 39.11],
            maxValue: 100,
            krigingModel: 'spherical', //model还可选'gaussian','spherical',exponential
            krigingSigma2: 0,
            krigingAlpha: 100,
            canvasAlpha: 0.75, //canvas图层透明度
            colors: [],
        }
        // 传递过来的颜色的处理
        var blue = []
        var green = []
        var red = []
        var golden = []
        var yellowish = []
        let str = ""
        switch (options.color) {
            // 金色
            case 'rgba(218,165,32,1)':
                for (let i = 0, j = 50; j < 100; i++) {

                    j += 50 / breaks.length
                    str = `rgba(218,165,32,${(j / 100).toFixed(2)})`
                    golden.push(str)
                }
                params.colors = golden
                break;
            // 蓝色
            case 'rgba(0,0,255,1)':
                for (let i = 0, j = 50; j < 100; i++) {
                    j += 50 / breaks.length
                    str = `rgba(0,0,255,${(j / 100).toFixed(2)})`
                    blue.push(str)
                }
                params.colors = blue
                break;
            //    绿色
            case 'rgba(0,128,0,1)':
                for (let i = 0, j = 50; j < 100; i++) {
                    j += 50 / breaks.length
                    str = `rgba(0,128,0,${(j / 100).toFixed(2)})`
                    green.push(str)
                }
                params.colors = green
                break;
            //    红色
            case 'rgba(255,0,0,1)':
                for (let i = 0, j = 50; j < 100; i++) {
                    j += 50 / breaks.length
                    str = `rgba(255,0,0,${(j / 100).toFixed(2)})`
                    red.push(str)
                }
                params.colors = red
                break;
            //    淡黄色
            case 'rgba(240,230,140,1)':
                for (let i = 0, j = 50; j < 100; i++) {
                    j += 50 / breaks.length
                    str = `rgba(240,230,140,${(j / 100).toFixed(2)})`
                   yellowish.push(str)
                }

                params.colors = yellowish
                break;
            default:
                break;
        }
        // 返回给前端页面的
        var result = {
            legend: [
            ]
        }
        self.WFSVectorSource = new ol.source.Vector()
        self.WFSVectorLayer = new ol.layer.Vector({
            source: self.WFSVectorSource,
        })
        self.map.addLayer(self.WFSVectorLayer)
        //添加选择和框选控件,按住Ctr键,使用鼠标框选采样点
        self.map.addInteraction(self.select)
        self.map.addInteraction(self.dragBox)
        //设置框选事件
        let selectedFeatures = self.select.getFeatures()
        self.dragBox.on('boxend', () => {
            let extent = self.dragBox.getGeometry().getExtent()
            self.WFSVectorSource.forEachFeatureIntersectingExtent(extent, (feature) => {
                selectedFeatures.push(feature)
            })
            drawKriging(extent)
        })
        self.dragBox.on('boxstart', () => {
            selectedFeatures.clear()
        })

        //利用网格计算点集
        const gridFeatureCollection = function (grid, xlim, ylim) {
            var range = grid.zlim[1] - grid.zlim[0]
            var i, j, x, y, z
            var n = grid.length //列数
            var m = grid[0].length //行数
            var pointArray = []
            for (i = 0; i < n; i++)
                for (j = 0; j < m; j++) {
                    x = i * grid.width + grid.xlim[0]
                    y = j * grid.width + grid.ylim[0]
                    z = grid[i][j]
                    // z = (grid[i][j] - grid.zlim[0]) / range
                    // if (z < 0.0) z = 0.0
                    // if (z > 1.0) z = 1.0
                    pointArray.push(
                        turf.point([x, y], {
                            value: z,
                        })
                    )
                }
            return pointArray
        }
        //绘制kriging插值图
        const drawKriging = (extent) => {
            let values = options.z,
                lngs = options.x,
                lats = options.y
            if (values.length > 3) {
                let variogram = kriging.train(
                    values,
                    lngs,
                    lats,
                    params.krigingModel,
                    params.krigingSigma2,
                    params.krigingAlpha
                )
                let polygons = []
                polygons.push([
                    [extent[0], extent[1]],
                    [extent[0], extent[3]],
                    [extent[2], extent[3]],
                    [extent[2], extent[1]],
                ])
                let grid = kriging.grid(polygons, variogram, (extent[2] - extent[0]) / 500)
                let dragboxExtent = extent
                if (self.vectorLayer !== null) {
                    self.map.removeLayer(self.vectorLayer)
                }
                self.vectorSource = new ol.source.Vector()
                self.vectorLayer = new ol.layer.Vector({
                    source: self.vectorSource,
                    opacity: 0.9,
                    style: function (feature) {
                        var style = new ol.style.Style({
                            text: new ol.style.Text({
                                text: feature.get('value') + '',
                                scale: 1.5,
                            }),
                        })
                        // 判断是等值线  还是  等值面
                        if (options.type == 'isobands') {
                            let ind = breaks.indexOf(parseFloat(feature.get('value').split('-')))
                            style.fill_ = new ol.style.Fill({
                                color: params.colors[ind],
                            })
                            result.type = "等值面"
                            result.legend.push(
                                {
                                    label: feature.get('value'),
                                    value: params.colors[ind]
                                }
                            )
                        } else {
                            //等值线
                            style.stroke_ = new ol.style.Stroke({
                                color: '#000',
                            })
                            result.type = "等值线"
                        }
                        return style
                    },
                })
                //使用turf渲染等值面/线
                let fc = gridFeatureCollection(grid, [extent[0], extent[2]], [extent[1], extent[3]])
                var collection = turf.featureCollection(fc)

                // 要生成的等值效果
                var isobands
                if (options.type == 'isobands') {
                    //等值线

                    isobands = turf.isobands(collection, breaks, {
                        zProperty: 'value',
                    })
                } else {
                    //等值面
                    isobands = turf.isolines(collection, breaks, {
                        zProperty: 'value',
                    })
                }
                function sortArea(a, b) {
                    return turf.area(b) - turf.area(a)
                }
                // -------裁剪工具类start---------
                let features = [];
                isobands.features.forEach(function (layer1) {
                    geojsonObject.features.forEach(function (layer2) {
                        let intersection = null;
                        try {
                            intersection = turf.intersect(layer1, layer2);
                        } catch (e) {
                            layer1 = turf.buffer(layer1, 0);
                            intersection = turf.intersect(layer1, layer2);
                        }
                        if (intersection != null) {
                            intersection.properties = layer1.properties;
                            intersection.id = Math.random() * 100000;
                            features.push(intersection);
                        }
                    });
                });
                let intersections = turf.featureCollection(features);
                //-------------裁剪工具类end======
                //按照面积对图层进行排序,规避turf的一个bug
                intersections.features.sort(sortArea)
                var polyFeatures = new ol.format.GeoJSON().readFeatures(intersections, {
                    featureProjection: 'EPSG:4326',
                })
                self.vectorSource.addFeatures(polyFeatures)
                self.map.addLayer(self.vectorLayer)
            } else {
                alert('有效样点个数不足,无法插值')
            }
        }
        // 边界的范围
        let extent = options.extent
        self.WFSVectorSource.forEachFeatureIntersectingExtent(extent, (feature) => {
            selectedFeatures.push(feature)
        })
        drawKriging(extent)
        cb(result)//返回结果 
        // 返回格式
        /**
         * {
            legend: [
                {
                    label: "24-25",
                    value: "rgba(218,165,32,0.77)"
                },
                {
                    label: "23-24",
                    value: "rgba(218,165,32,0.67)"
                },
            ],
            type: "等值面"
        }
         */
    }
    clearIsolines() {
        self.map.removeInteraction(self.WFSVectorSource);
        self.map.removeInteraction(self.vectorSource);
        self.map.removeInteraction(self.dragBox);
        self.map.removeInteraction(self.select);
        self.map.removeLayer(self.vectorLayer)
        self.map.removeLayer(self.WFSVectorLayer)
    }
}

生成等值线、面的图例返回到页面上生成图例

  • html
        <div class="sample">
          <a-button type="primary" style="padding: 3px 20px; margin-right: 10px" @click="MapImExport">导出</a-button>
          <a-table
            :row-selection="rowSelection"
            :columns="columns"
            :data-source="datas"
            :rowKey="(record) => record.GCEABC"
            :pagination="false"
          >
          </a-table>
        </div>


<a-modal
      title="设置"
      :width="900"
      :visible="AnalysisVisible"
      @ok="AnalysishandleSubmit"
      @cancel="AnalysishandleCancel"
    >
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">年份:</span>
        <el-select v-model="Analysis.year" placeholder="请选择">
          <el-option v-for="item in AnalysisYear" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">月份:</span>
        <el-select v-model="Analysis.month" placeholder="请选择">
          <el-option v-for="item in AnalysisMonth" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">等值面颜色设定:</span
        ><color-select :color-list="colorList" v-model="settings.color"></color-select>
      </div>
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">间隔设定:</span>
        <el-select v-model="settings.interval" placeholder="请选择">
          <el-option v-for="item in intervaloptions" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div>
      <div style="margin-top: 20px">
        <span style="width: 120px; display: inline-block; text-align: right; margin-right: 10px">生成类型:</span>
        <el-button-group>
          <el-button :type="type1" @click="typeSele('isobands')">等值面</el-button>
          <el-button :type="type2" @click="typeSele('isolines')">等值线 </el-button>
        </el-button-group>
      </div>
    </a-modal>
  • js
  // 分析
    AnalysishandleSubmit() {
      this.Analysis.uniCodeList = this.selectedRowKeys
      if (this.Analysis.uniCodeList.length < 3) {
        this.$message.success('选择的井不足三个无法生成等值线')
        return
      } else {
        postAnslysisContour(this.Analysis).then((res) => {
          let obj = Object.assign(this.settings, res.data.contourData)
          this.$refs.map.CreateEquivalence(obj)
        })
      }

      this.AnalysisVisible = false
    },
    // 取消
    AnalysishandleCancel() {
      this.AnalysisVisible = false
    },
    //导出调用Mapgis.vue    
    MapImExport() {
      this.$refs.map.MapImExport()
    },
  • css
.sample {
  height: 268px;
  overflow: auto;
}

MapGis.vue页面通过html2canvas生成图片,然后通过blob流下载等值线图

下载npm包: npm i html2canvas@1.2.2

  • html
 <a-modal v-model="visible" title="等值线预览" @ok="handleOk">
      <div id="image" class="Export" style="100%">
        <div class="ExportImg">
          <div class="ExTit">
            <h3>2021年6月</h3>
            <p>地下水位等值线图(单位:米)</p>
          </div>
          <img id="MapImage" :src="MapImg" alt="" style="width: 100%" />
        </div>

        <div class="IsolineLegend">
          <p style="font: bold 16px/26px '微软雅黑'">图例</p>
          <div style="display: flex">
            <div style="margin-right: 50px">
              <h4 style="margin: 10px 0">监测井图例</h4>
              <p style="font: 12px/20px '微软雅黑'">
                <span class="iconfont icon-zuankong" style="color: rgb(0, 255, 0); margin-right: 10px"></span>人工监测
              </p>
              <p style="font: 12px/20px '微软雅黑'">
                <span class="iconfont icon-zuankong" style="color: rgb(255, 0, 0); margin-right: 10px"></span>自动监测
              </p>
              <p style="font: 12px/20px '微软雅黑'">
                <span class="iconfont icon-zuankong" style="color: rgb(152 150 150); margin-right: 10px"></span>设备离线
              </p>
            </div>
            <div>
              <h4 style="margin: 10px 0">{{ IsolineLegend.type }}图例</h4>

              <ul style="width: 320px; display: flex; flex-wrap: wrap" v-if="IsolineLegend.type == '等值面'">
                <li
                  v-for="(item, ind) in IsolineLegend.legend"
                  :key="ind"
                  style="font: 14px/20px '微软雅黑'; margin-right: 20px"
                >
                  <span
                    :style="{
                      background: item.value,
                      'margin-right': '15px',
                      width: '30px',
                      height: '20px',
                      display: 'inline-block',
                    }"
                  ></span
                  >{{ item.label }}
                </li>
              </ul>
              <p v-else>
                <span style="margin-right: 10px; display: inline-block; width: 30px; height: 3px;color:#000">——</span>等值线
              </p>
            </div>
          </div>
        </div>
      </div>
    </a-modal>
  • js
  data() {
    return {
      mapgis: {}, //地图实例
      MapImg: '', //生成图片的地址
      visible: false, //预览开关
      wholeExtent: [], //范围
      IsolineLegend: {}, //等值线需要的图例结果
    }
  },    

// 生成等值线
    CreateEquivalence(data) {
      data.extent = this.wholeExtent
      this.Mapgiss.QueryToolClear()

      this.Mapgiss.CreateEquivalence(data, (res) => {
      
        this.IsolineLegend = res
      })
    },
          methods: {
    //等值线导出
    MapImExport() {
      this.visible = true
      var that = this
      // 地图截图
      this.mapgis.once('postcompose', function (event) {
        //获取map中的canvas,并转换为图片
        var canvas = event.context.canvas

        if (navigator.msSaveBlob) {
          navigator.msSaveBlob(canvas.msToBlob(), 'map.png')
        } else {
          console.log(that)
          that.MapImg = canvas.toDataURL('image/png')
          // canvas.toBlob(function (blob) {
          //   // saveAs(blob, 'map.png')
          // })
        }
      })
      this.mapgis.renderSync()
    },
    //保存到本地
    handleOk(e) {
    //通过html2canvas插件把整个Div生成为片  点击确定实现下载   需要后台传来导出名字
      html2canvas(document.getElementById('image')).then(function (canvas) {
        var imgUri = canvas.toDataURL('image/jpeg') // 获取生成的图片的url

        let el = document.createElement('a')
        el.href = imgUri
        // 指定下载的文件名
        el.download = '等值导出结果.png'
        el.hidden = true
        document.body.appendChild(el)
        el.click()
        document.body.removeChild(el)
      })
      this.visible = false
    },
          }
  • css
.Export {
  width: 100%;
  position: relative;
}
.Export .ExportImg {
  border: 2px solid #999;
}
.Export .ExTit {
  border: 1px solid #999;
  width: 60%;
  position: absolute;
  background: #fff;
  top: 1px;
  left: 1px;
}
.Export .ExTit > h3 {
  text-align: center;
  padding: 5px 0;
}
.Export .ExTit > p {
  text-align: center;
  padding: 0 0 0 10px;
}
.Export .IsolineLegend {
  background: #fff;
  padding: 10px;
}

以上是本人基于openlayers封装的生成等值线或者面生成的可下载为图片的部分代码,基本逻辑已描述。
逻辑步骤:
① 选择要生成的点(点里有xyz三个值)根据里面的z来判断等值间隔
② 通过设置页设置色带,间隔值,等值线/面
③ 生成的等值面通过openlayers内置的截图工具截图出来
④ 生成的地图,图例拼接起来然后通过html2canvas插件把该div导出成图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值