基于openlayers6的基本地图操作--4. 添加弹出框popup

实现map点击,添加弹出框popup,其实质是Overlay

引入需要的组件

import Overlay from 'ol/Overlay';

创建popup

  • 创建div
    <div id="popup"></div>
  • 创建popup实例
var element = document.getElementById('popup');
var popup = new Overlay({
  element: element,
  positioning: 'bottom-center',
  stopEvent: false,
  offset: [0, -50]
});
map.addOverlay(popup);
  • map点击处,添加popup
// display popup on click
map.on('click', function(evt) {
  var feature = map.forEachFeatureAtPixel(evt.pixel,
    function(feature) {
      return feature;
    });
  if (feature) {
    var coordinates = feature.getGeometry().getCoordinates();
    popup.setPosition(coordinates);
    $(element).popover({
      placement: 'top',
      html: true,
      content: feature.get('name')
    });
    $(element).popover('show');
  } else {
    $(element).popover('destroy');
  }
});

封装成vue组件

popup的实现过程封装成组件,方便重复利用

  • popup.js: 实现添加的业务方法集合
import Overlay from 'ol/Overlay.js';
import './popup.css'
export class Popup {
  constructor(map, props) {
    this.map = map;
    this.container = props.container || null;
    this.content = props.content || '';
    this.addLayer()
  }

  addLayer() {
    if (this.container !== null) {
      this.popupLayer = new Overlay({
        element: this.container,
        autoPan: true,
        positioning: 'bottom-center',
        stopEvent: false,
        offset: [0, -20],
        autoPanAnimation: {
          duration: 250
        }
      });
      //this.map.addOverlay(this.popupLayer);
    }
  }

  addPopup(coordinate) {
    this.popupLayer.setPosition(coordinate);
    this.map.addOverlay(this.popupLayer);
  }

  removePopup() {
    this.popupLayer.setPosition(undefined);
    this.map.removeOverlay(this.popupLayer);
    return false;
  }

  setContent(content) {
    this.content.innerHTML = content;
  }

  clear() {
    if (this.popupLayer) {
      this.map.removeOverlay(this.popupLayer);
    }
  }
}
  • popup.css: 设置样式
.ol-popup {
  background-color: rgba(0, 23, 55, 0.6);
  border-radius: 5px;
  color: white;
  box-shadow: 0 4px 14px rgba(7, 154, 238, 0.35);
  border-radius: 4px;
  width: 310px;
}

.popup-title {
  border-bottom: 1px solid #eee;
  padding: 10px;
}

.ol-popup-content{
  padding: 10px;
  font-size: 0.8em;
  line-height: 25px;
}

.ol-popup-closer {
  position: absolute;
  top: 12px;
  right: 6px;
}

  • popupView.vue: 封装的vue组件
<template>
    <div id="popup" class="ol-popup">
      <div class="popup-title">{{title}}</div>
      <div class="ol-popup-closer" @click="handleClose"><i class="el-icon-close"></i></div>
      <!-- <a href="#" id="popup-closer" class="ol-popup-closer" @click="handleClose"></a> -->
      <div id="popup-content" class="ol-popup-content">
        <a :href="pointImageURL" title="点击查看详情" target='_blank' v-show="type==='野外核查'">
          <img class="hecha-img" :src="pointImageURL" alt="" @error="handleImgError">
        </a>
        <div v-for="(val, key) in popupContent" :key="key">
          <el-row>
            <el-col :span="8" style="text-align: right;">{{key}}:</el-col>
            <el-col :span="16">{{val}}</el-col>
          </el-row>
        </div>
      </div>
    </div>
</template>
<script>
import { PopupTool } from "./popup";

export default {
  name: "OlPopup",
  data() {
    return {
      popup: null,
      defaultImg: "img/lake/no_photo.png"
    };
  },
  props: ["map", "title", "popupContent", "type", "pointURL"],
  components: {},
  computed: {
    pointImageURL() {
      return this.pointURL;
    }
  },
  watch: {
    map(val) {
      if (val) {
        this.init();
      }
    }
  },
  methods: {
    init() {
      let container = document.getElementById("popup");
      let content = document.getElementById("popup-content");
      // let closer = document.getElementById('popup-closer')
      this.popup = new PopupTool(this.map, {
        container: container,
        content: content
      });
    },
    handleClose() {
      if (this.popup) {
        this.popup.removePopup();
      }
    },
    addPopup(point) {
      this.popup.addPopup(point);
    },
    setPopupContent() {
      this.popup.setContent(this.popupContent);
    },
    handleImgError() {
      this.$emit("update:pointURL", "img/lake/no_photo.png");
      //this.$emit("update:type", "");
    }
  }
};
</script>
<style scoped>
.hecha-img {
    width: 291px;
    height: 150px;
}
</style>

控制显隐的实现方法

  • 主要实现方法
/**
 * 弹出框
 */
import Overlay from 'ol/Overlay';
export default {
  overlay: null,
  map: null,
  popupId: "",
  init(map, popupId) {
    /* if (this.popupId !== popupId) {
      
    } */
    this.add(map, popupId);
  },
  add(map, popupId) {
    this.container = document.getElementById(popupId);
    this.popupId = popupId;
    this.overlay = new Overlay({
      element: this.container,
      positioning: 'bottom-left',
      stopEvent: false,
      offset: [-50, -10],
      autoPan: true,
      autoPanAnimation: {
        duration: 250
      }
    });
    map.addOverlay(this.overlay);
  },
  open(coordinate) {
    this.overlay.setPosition(coordinate);
  },
  close() {
    this.overlay.setPosition(undefined);
  }
}
  • 组件中应用
<template>
  <div class="containerRainPopup" style="display: none;">
    <div id="popupRain" class="ol-popup" v-show="activePanelName === 'rain'">
      <div class="ol-popup-closer" @click="handleClose"></div>
      <div id="rain-popup-content">
        <el-row>
          <el-col :span="1">
            <div class="rain-title"></div>
          </el-col>
          <el-col :span="10" style="line-height: 28px;">{{queryInfo['测站名称']}}</el-col>
        </el-row>
        <el-row>
          <el-form ref="form" :model="form" label-width="60px" :inline="true">
            <el-form-item label="时间:">
              <el-col :span="12">
                <el-date-picker type="datetime" placeholder="选择开始日期" v-model="form.startTime"></el-date-picker>
              </el-col>
              <el-col :span="2" style="color: white;">至</el-col>
              <el-col :span="10">
                <el-date-picker type="datetime" placeholder="选择结束日期" v-model="form.endTime"></el-date-picker>
              </el-col>
            </el-form-item>
            <el-form-item label="类型:">
              <el-select
                v-model="form.type"
                placeholder="类型"
                style="width: 120px;"
                @change="handleSearch"
              >
                <el-option label="时段降雨量" value="1"></el-option>
                <el-option label="整点降雨量" value="2"></el-option>
                <el-option label="日降雨量" value="3"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item style="margin: 0;">
              <el-button
                type="primary"
                class="search"
                size="small"
                style="margin: 0;"
                @click="handleSearch"
              >查询</el-button>
            </el-form-item>
          </el-form>
        </el-row>
        <el-row>
          <div class="basic-info" @click="handleBasicClick"></div>
          <div class="process-line" @click="handleProcessClick"></div>
          <div class="info-table" @click="handleTableClick"></div>
          <div class="line"></div>
          <div :class="currentClass"></div>
          <BasicInfoPanel :queryInfo="queryInfo" v-show="currentClass === 'rain-info'"></BasicInfoPanel>
          <HistoGram :rainData="rainData" v-show="currentClass === 'rain-echarts'"></HistoGram>
          <RainTablePanel :rainData="rainData" v-show="currentClass === 'rain-table'"></RainTablePanel>
          <div class="rain-time">时间段:{{form.startTime}}-{{form.endTime}} 累计雨量:{{totalRain}}mm</div>
        </el-row>
      </div>
    </div>
  </div>
</template>

<script>
import PopupTool from "../Popup";
import { mapGetters } from "vuex";
import BasicInfoPanel from "./BasicInfoPanel";
import HistoGram from "./HistoGram";
import RainTablePanel from "./RainTablePanel";
import { queryByPeriodAndTypeStcd } from "@/api/queryInfo";

export default {
  name: "RainPopup",
  data() {
    return {
      popup: null,
      queryInfo: {},
      form: {
        startTime: "2020-04-07 08:00:00",
        endTime: "2020-04-07 12:00:00",
        type: "2"
      },
      stcd: "80813", // 测站编码
      currentClass: "rain-info",
      rainData: [],
      totalRain: 0
    };
  },
  props: ["map", "rainQueryInfo"],
  computed: {
    ...mapGetters(["activePanelName"])
  },
  components: {
    BasicInfoPanel,
    HistoGram,
    RainTablePanel
  },
  watch: {
    rainQueryInfo(newData) {
      if (newData) {
        if (this.activePanelName === "rain") {
          this.queryInfo = newData.info;
          this.stcd = this.queryInfo["测站编码"];
          this.addPopup(newData.point);
        }
      }
    },
    activePanelName(val) {
      if (val === "rain") {
        this.$nextTick(() => {
          this.init();
        });
      }
    },
    rainData(val) {
      let pArray = [];
      val.forEach(item => {
        pArray.push(item.drpData);
      });
      this.totalRain = eval(pArray.join("+"));
    }
  },
  methods: {
    init() {
      PopupTool.init(this.map, "popupRain");
    },
    handleClose() {
      PopupTool.close();
      this.currentClass = "rain-info";
    },
    addPopup(point) {
      PopupTool.open(point);
    },
    handleBasicClick() {
      this.currentClass = "rain-info";
    },
    handleProcessClick() {
      this.currentClass = "rain-echarts";
      this.handleSearch();
    },
    handleTableClick() {
      this.currentClass = "rain-table";
    },
    handleSearch() {
      queryByPeriodAndTypeStcd(
        this.form.endTime,
        this.form.startTime,
        this.stcd,
        this.form.type
      ).then(res => {
        this.rainData = res.data.data;
      });
    }
  }
};
</script>

<style scoped lang="scss">
#popupRain {
  width: 730px;
}
/* #popupRain:after {
  border-top-color: rgba(2, 30, 80, 0.8);
  border-width: 10px;
  left: 380px;
  margin-left: -10px;
} */
@mixin rain-popup {
  background: url(~img/queryInfo/rain-popup.png) no-repeat;
}
@mixin 标题前icon {
  height: 30px;
  width: 32px;
  background-position: 0 0;
}
@mixin 直方图 {
  height: 75px;
  width: 295px;
  background-position: -32px 0;
}
@mixin 雨量报表 {
  height: 75px;
  width: 295px;
  background-position: -327px 0;
}
@mixin 基本信息 {
  height: 75px;
  width: 295px;
  background-position: -622px 0;
}
@mixin info() {
  height: 45px;
  position: absolute;
  width: 76px;
  margin-left: 20px;
  cursor: pointer;
}

.rain-title {
  @include rain-popup;
  @include 标题前icon;
}
.rain-info {
  @include rain-popup;
  @include 基本信息;
}
.rain-echarts {
  @include rain-popup;
  @include 直方图;
}
.rain-table {
  @include rain-popup;
  @include 雨量报表;
}
.basic-info {
  @include info;
}
.process-line {
  @include info;
  margin-left: 116px;
}
.info-table {
  @include info;
  margin-left: 207px;
}
.line {
  height: 40px;
  position: absolute;
  width: 427px;
  margin-left: 295px;
  border-bottom: 1px solid #047edb;
}
.rain-time {
  color: #fbc515;
  margin: 20px 0px 0 20px;
}
</style>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容

  • 基于Vue的一些资料 内容 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 element★...
    尝了又尝阅读 1,151评论 0 1
  • UI组件 element- 饿了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的组件库 m...
    小姜先森o0O阅读 9,486评论 0 72
  • UI组件 element- 饿了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的组件库 m...
    35eeabfa0772阅读 3,270评论 7 12
  • UI组件 element- 饿了么出品的Vue2的web UI工具套件 Vux- 基于Vue和WeUI的组件库 m...
    王喂马_阅读 6,454评论 1 77
  • 我自幼喜欢看武侠,喜欢抱打不平,喜欢恩怨分明,多少年,我都遵循只要开心就好,隐忍是我不愿意做的事,只是有了孩子后,...
    悠然_3c09阅读 265评论 1 3