效果图
DfPopUp.vue
<template>
<div class="wrap" ref="wrapDom">
<svg class="lineWrap">
<line :id="'line_' + props.domId" stroke="#9fe511" stroke-width="2" stroke-dasharray="10,10"></line>
</svg>
<div class="itemwrap">
<div class="item item1" :id="'item1_' + props.domId"></div>
</div>
<div class="item item2" :id="'item2_' + props.domId" :style="{ top: item2Data.top + 'px', left: item2Data.left + 'px' }">{{ props.textData }}</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, getCurrentInstance, onMounted, nextTick, defineProps } from 'vue';
const { proxy }: any = getCurrentInstance();
const wrapDom = ref<any>(null);
const props = defineProps({
left: {
type: Number
},
top: {
type: Number
},
textData: {
type: String
},
position: {
type: Object
},
domId: {
type: String
}
});
const item1Data = reactive({
top: props.top,
left: props.left
});
const item2Data = reactive({
top: -140,
left: -120
});
// data
//onMounted
onMounted(async () => {
nextTick(async () => {
$(function () {
function move() {
var pos1 = getElCoordinate($('#item1_' + props.domId)[0]);
var pos2 = getElCoordinate($('#item2_' + props.domId)[0]);
var start = getPos(pos1, pos2).start;
var end = getPos(pos1, pos2).end;
$('#line_' + props.domId).attr({ x1: start.x, y1: start.y, x2: end.x, y2: end.y });
$('#path').attr({ d: 'M20,20 L100,100' });
}
move();
drag($('#item2_' + props.domId), move);
function getPos(pos1, pos2) {
//分四种情况
var x1, y1, x2, y2;
if (pos2.top < pos1.top) {
//结束点位于左上角
x1 = pos1.left + pos1.width / 2;
y1 = pos1.top;
y2 = pos2.top + pos2.height;
if (pos2.left < pos1.left) {
x2 = pos2.left + pos2.width / 2;
} else {
//右上角
x2 = pos2.left + pos2.width / 2;
}
} else {
x1 = pos1.left + pos1.width / 2;
y1 = pos1.top + pos1.height;
x2 = pos2.left + pos2.width / 2;
y2 = pos2.top;
}
return {
start: { x: x1, y: y1 },
end: { x: x2, y: y2 }
};
}
function drag(obj, callback) {
var dragEles = obj;
dragEles.each(function (index, dragEleDom) {
var _move = false;
var _x, _y;
var dragEle = $(dragEleDom);
dragEle
.click(function () {
//alert("click");//点击(松开后触发)
})
.mousedown(function (e) {
_move = true;
_x = e.pageX - parseInt(dragEle.css('left'));
_y = e.pageY - parseInt(dragEle.css('top'));
});
$(document)
.mousemove(function (e) {
if (_move) {
var x = e.pageX - _x; //移动时根据鼠标位置计算控件左上角的绝对位置
var y = e.pageY - _y;
dragEle.css({ top: y, left: x });
if (callback) {
callback();
}
}
})
.mouseup(function () {
_move = false;
dragEle.fadeTo('fast', 1);
});
});
}
//获取元素左上角相对于某一元素的的位置
function getElCoordinate(dom) {
var t = dom.offsetTop;
var l = dom.offsetLeft;
var w = dom.offsetWidth;
var h = dom.offsetHeight;
dom = dom.offsetParent;
while (!$(dom).hasClass('wrap')) {
t += dom.offsetTop;
l += dom.offsetLeft;
dom = dom.offsetParent;
}
return {
top: t,
left: l,
width: w,
height: h
};
}
});
window.Viewer.scene.postRender.addEventListener(() => {
if (window.Cesium.defined(props.position)) {
let changedC = Cesium.SceneTransforms.wgs84ToWindowCoordinates(window.Viewer.scene, props.position);
let curPos = new Cesium.Cartesian2(changedC.x, changedC.y);
let left = curPos.x;
let top = curPos.y;
wrapDom.value.style.left = left + 'px';
wrapDom.value.style.top = top + 'px';
}
});
});
});
</script>
<style lang="scss" scoped>
.wrap {
position: relative;
height: 0px;
user-select: none;
}
.itemwrap {
position: absolute;
top: 0;
left: 0;
width: 50%;
height: 50%;
}
.item {
position: absolute;
border: 1px solid #9fe511;
height: 50px;
line-height: 50px;
width: 50px;
text-align: center;
// top: -50px;
// left: -50px;
}
.item1 {
position: absolute;
border: 1px solid #9fe511;
background: red;
border-radius: 50%;
height: 15px;
line-height: 50px;
width: 15px;
text-align: center;
// top: -50px;
// left: -50px;
}
.item2 {
padding: 0px 15px !important;
min-width: 130px;
height: 50px;
font-size: 15px;
font-weight: bold;
color: #ffffff;
}
.lineWrap {
position: absolute;
left: 0;
top: 0;
width: 1px;
height: 1px;
overflow: visible;
}
</style>
addDfPopUp.ts
import { createApp } from 'vue';
import DfPopUp from '../components/DfPopUp.vue';
class AddDfPopUp {
constructor(lon: any, lat: any, text) {
this.lon = lon;
this.lat = lat;
this.text = text;
this.id = null;
}
add() {
var parent: any = document.getElementById('DfPopUpAll');
var child: any = document.createElement('div');
let id = new Date().getTime() + Math.floor(Math.random() * Math.floor(100));
this.id = id;
child.id = 'DfPopUp_' + id;
child.style.position = 'absolute';
parent.appendChild(child);
let postion = window.Cesium.Cartesian3.fromDegrees(this.lon, this.lat);
const app = createApp(DfPopUp, {
left: window.Cesium.SceneTransforms.wgs84ToWindowCoordinates(window.viewer.scene, postion).x,
top: window.Cesium.SceneTransforms.wgs84ToWindowCoordinates(window.viewer.scene, postion).y,
position: postion,
textData: this.text, //显示文字
domId: id // id,防止重复
});
app.mount('#DfPopUp_' + id);
}
remove() {
var parent: any = document.getElementById('DfPopUpAll');
var child: any = document.getElementById('DfPopUp_' + this.id);
if (parent && child) {
parent.removeChild(child);
}
}
}
export default AddDfPopUp;
使用
let P1 = new AddDfPopUp(110.061719, 35.054499, '测试文字');
P1.add();//添加
P1.remove();//删除
在 index.html下添加
<div id="app"></div>
<div id="DfPopUpAll"></div> //当前这行
<script type="module" src="/src/main.ts"></script>
css
#app{
position: absolute;
left: 0;
top: 0;
overflow: hidden;
}
#DfPopUpAll {
width: 100%;
height: 100%;
}