import {
deepMerge,
getLevelMiddleHeight,
wgs84ToGcj02Format,
convertPosition,
} from "../util";
import Mars3dEntity from "../base/mars3d_entity";
import GaodeEntity from "../base/gaode_entity";
import SijiEntity from "../base/siji_entity";
import CesiumEntity from "../base/cesium_entity";
const HorizontalOrigin: any = {
center: 0,
left: 1,
right: -1,
};
const VerticalOrigin: any = {
center: 0,
top: -1,
bottom: 1,
};
export default (hnMap: any) => {
const defaultOption = {
id: "",
position: [],
image: "",
height: 30,
width: 30,
rotation: 0,
horizontalOrigin: "center",
verticalOrigin: "center",
text: "",
fontSize: 12,
color: "#000000",
offset: [0, 0],
scaleByDistance: true,
distanceDisplayCondition: false,
distanceDisplayCondition_far: 1,
distanceDisplayCondition_near: 18,
data: null,
};
class mars3d_class extends Mars3dEntity {
id: any = null;
option: any = JSON.parse(JSON.stringify(defaultOption));
config: any = null;
graphic: any = null;
constructor(option: any) {
super(hnMap);
this.id = option.id;
deepMerge(this.option, option);
this.config = this.formatConfig(this.option);
this.graphic = new mars3d.graphic.BillboardEntity(this.config);
}
formatConfig(option: any) {
const distanceDisplayCondition_far = getLevelMiddleHeight(
option.distanceDisplayCondition_far
);
const distanceDisplayCondition_near = getLevelMiddleHeight(
option.distanceDisplayCondition_near
);
return {
id: option.id,
position: option.position,
style: {
width: option.width,
height: option.height,
image: option.image,
label: {
text: option.text,
font_size: option.fontSize,
color: option.color,
pixelOffset: option.offset,
scaleByDistance: option.scaleByDistance,
distanceDisplayCondition: option.distanceDisplayCondition,
distanceDisplayCondition_far: distanceDisplayCondition_far,
distanceDisplayCondition_near: distanceDisplayCondition_near,
visibleDepth: false,
},
scaleByDistance: option.scaleByDistance,
distanceDisplayCondition: option.distanceDisplayCondition,
distanceDisplayCondition_far: option.distanceDisplayCondition_far,
distanceDisplayCondition_near: option.distanceDisplayCondition_near,
clampToGround: !option.position[2],
rotationDegree: option.rotation,
horizontalOrigin: HorizontalOrigin[option.horizontalOrigin],
verticalOrigin: VerticalOrigin[option.verticalOrigin],
visibleDepth: true,
},
attr: option.data,
};
}
set(option: any) {
deepMerge(this.option, option);
this.config = this.formatConfig(this.option);
this.graphic.setOptions(this.config);
}
// flyTo(option = {}) {
// let config = {}
// if(option.height){
// config.radius = option.height
// }
//
// this.graphic.flyTo(config);
// }
openPopup() {
this.graphic.openPopup();
}
}
class gaode_class extends GaodeEntity {
type: any = "imagePoint";
id: any = null;
option: any = JSON.parse(JSON.stringify(defaultOption));
config: any = null;
graphic: any = null;
constructor(option: any) {
super(hnMap);
this.id = option.id;
deepMerge(this.option, option);
this.config = this.formatConfig(this.option);
this.graphic = new AMap.Marker(this.config);
}
formatConfig(option: any) {
let amapPosition = wgs84ToGcj02Format(option.position);
const content = `
${option.text}
`;
return {
extData: {
id: option.id,
data: option.data,
},
position: new AMap.LngLat(amapPosition[0], amapPosition[1]),
icon: new AMap.Icon({
image: option.image,
imageSize: new AMap.Size(option.height, option.width),
size: new AMap.Size(option.height, option.width),
}),
angle: 360 - option.rotation,
anchor: "center",
label: {
direction: "center",
offset: new AMap.Pixel(option.offset[0], option.offset[1]), //设置文本标注偏移量
content: content,
},
};
}
}
class siji_class extends SijiEntity {
type: any = "imagePoint";
id: any = null;
option: any = JSON.parse(JSON.stringify(defaultOption));
config: any = null;
graphic: any = null;
constructor(option: any) {
super(hnMap);
this.id = option.id;
deepMerge(this.option, option);
this.config = this.formatConfig(this.option);
}
formatConfig(option: any) {
let config: any = {};
config = {
id: option.id,
type: "symbol",
source: {
type: "geojson",
data: {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: convertPosition(option.position),
},
properties: {
name: option.text,
},
},
],
},
},
layout: {
"icon-image": option.id + "_image",
// "icon-size": 1,
"icon-ignore-placement": true,
// "icon-offset": convertPosition(option.offset),
"text-ignore-placement": true, //
"text-field": "{name}", // 文本
"text-size": Number(option.fontSize),
"text-anchor": option.verticalOrigin,
"icon-anchor": option.verticalOrigin,
"text-offset": convertPosition(option.offset),
},
paint: {
"text-color": option.color,
}, // 填充样式
};
return config;
}
set(option: any) {
deepMerge(this.option, option);
this.config = this.formatConfig(this.option);
let mySource = hnMap.map.map.getSource(this.config.id);
mySource.setData({
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: convertPosition(this.option.position),
},
properties: {
name: this.option.text,
},
},
],
});
for (let key in this.config) {
if (this.config.hasOwnProperty(key)) {
if (key == "layout") {
for (let key2 in this.config[key]) {
if (this.config[key].hasOwnProperty(key2)) {
// 遍历 layout 属性
hnMap.map.map.setLayoutProperty(
this.config.id,
key2,
key2 == "text-size"
? Number(this.config[key][key2])
: this.config[key][key2]
);
}
}
}
}
}
for (let key in this.config) {
if (this.config.hasOwnProperty(key)) {
if (key == "paint") {
for (let key2 in this.config[key]) {
if (this.config[key].hasOwnProperty(key2)) {
// 遍历 paint 属性
hnMap.map.map.setPaintProperty(
this.config.id,
key2,
this.config[key][key2]
);
}
}
}
}
}
}
}
class cesium_class extends CesiumEntity {
type: any = "imagePoint";
id: any = null;
option: any = JSON.parse(JSON.stringify(defaultOption));
config: any = null;
graphic: any = null;
constructor(option: any) {
super(hnMap);
this.id = option.id;
deepMerge(this.option, option);
this.config = this.formatConfig(this.option);
// 创建cesium实体
this.graphic = new Cesium.Entity(this.config);
// 添加自定义属性
this.graphic.userData = {
type: "billboard",
originalData: this.option.data || {},
};
}
formatConfig(option: any) {
// 转换位置坐标为 Cesium 格式
const position = Cesium.Cartesian3.fromDegrees(
Number(option.position[0]),
Number(option.position[1]),
Number(option.position[2]) || 0
);
// 映射水平和垂直原点
const horizontalOriginMap: any = {
left: Cesium.HorizontalOrigin.LEFT,
center: Cesium.HorizontalOrigin.CENTER,
right: Cesium.HorizontalOrigin.RIGHT,
};
const verticalOriginMap: any = {
top: Cesium.VerticalOrigin.TOP,
center: Cesium.VerticalOrigin.CENTER,
bottom: Cesium.VerticalOrigin.BOTTOM,
};
const config: any = {
id: option.id,
position: position,
billboard: {
image: option.image,
width: Number(option.width),
height: Number(option.height),
horizontalOrigin: horizontalOriginMap[option.horizontalOrigin],
verticalOrigin: verticalOriginMap[option.verticalOrigin],
pixelOffset: new Cesium.Cartesian2(
Number(option.offset[0]) || 0,
Number(option.offset[1]) || 0
),
rotation: Cesium.Math.toRadians(option.rotation || 0),
clampToGround: !option.position[2],
scaleByDistance: option.scaleByDistance
? new Cesium.NearFarScalar(1.0e2, 1.0, 1.0e7, 0.1)
: undefined,
show: true,
visibleDepth: true,
},
label: {
text: option.text,
font: `${option.fontSize || 16}px sans-serif`,
fillColor: Cesium.Color.fromCssColorString(option.color || "#000000"),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
// horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
// verticalOrigin: Cesium.VerticalOrigin.CENTER,
pixelOffset: new Cesium.Cartesian2(
Number(option.offset[0]) || 0,
-Number(option.offset[1]) || 0
),
scaleByDistance: option.scaleByDistance
? new Cesium.NearFarScalar(1.0e2, 1.0, 1.0e7, 0.1)
: undefined,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
heightReference: Cesium.HeightReference.NONE, // 高度参考
show: true,
visibleDepth: true,
},
properties: option.data || {}, // 添加自定义数据
};
// 添加距离显示条件
if (option.distanceDisplayCondition) {
const near = getLevelMiddleHeight(option.distanceDisplayCondition_near);
const far = getLevelMiddleHeight(option.distanceDisplayCondition_far);
config.label.distanceDisplayCondition =
new Cesium.DistanceDisplayCondition(near, far);
config.billboard.distanceDisplayCondition =
new Cesium.DistanceDisplayCondition(near, far);
}
return config;
}
// 添加 set 方法用于动态更新
set(option: any) {
deepMerge(this.option, option);
this.config = this.formatConfig(this.option);
if (this.graphic) {
// 更新位置
if (option.position !== undefined) {
this.graphic.position = Cesium.Cartesian3.fromDegrees(
Number(option.position[0]),
Number(option.position[1]),
Number(option.position[2]) || 0
);
}
// 更新 billboard 属性
if (this.graphic.billboard) {
const billboard = this.graphic.billboard;
if (option.image !== undefined) {
billboard.image = option.image;
}
if (option.width !== undefined) {
billboard.width = Number(option.width);
}
if (option.height !== undefined) {
billboard.height = Number(option.height);
}
if (option.rotation !== undefined) {
billboard.rotation = Cesium.Math.toRadians(option.rotation);
}
// if (option.offset !== undefined) {
// billboard.pixelOffset = new Cesium.Cartesian2(
// Number(option.offset[0]) || 0,
// Number(option.offset[1]) || 0
// );
// }
// 更新原点
if (option.horizontalOrigin !== undefined) {
const horizontalOriginMap: any = {
left: Cesium.HorizontalOrigin.LEFT,
center: Cesium.HorizontalOrigin.CENTER,
right: Cesium.HorizontalOrigin.RIGHT,
};
billboard.horizontalOrigin =
horizontalOriginMap[option.horizontalOrigin] ||
Cesium.HorizontalOrigin.CENTER;
}
if (option.verticalOrigin !== undefined) {
const verticalOriginMap: any = {
top: Cesium.VerticalOrigin.TOP,
center: Cesium.VerticalOrigin.CENTER,
bottom: Cesium.VerticalOrigin.BOTTOM,
};
billboard.verticalOrigin =
verticalOriginMap[option.verticalOrigin] ||
Cesium.VerticalOrigin.CENTER;
}
if (option.scaleByDistance) {
billboard.scaleByDistance = new Cesium.NearFarScalar(
1.0e2,
1.0,
1.0e7,
0.1
);
} else {
billboard.scaleByDistance = undefined;
}
}
// 更新 label 属性
if (this.graphic.label) {
const label = this.graphic.label;
label.horizontalOrigin = Cesium.HorizontalOrigin.CENTER;
label.verticalOrigin = Cesium.VerticalOrigin.CENTER;
label.disableDepthTestDistance = Number.POSITIVE_INFINITY;
label.heightReference = Cesium.HeightReference.NONE;
if (option.text !== undefined) {
label.text = String(option.text);
}
if (option.fontSize !== undefined || option.color !== undefined) {
label.font = `${option.fontSize || 12}px sans-serif`;
label.fillColor = Cesium.Color.fromCssColorString(
option.color || "#000000"
);
}
if (option.offset !== undefined) {
label.pixelOffset = new Cesium.Cartesian2(
Number(option.offset[0]) || 0,
-Number(option.offset[1]) || 0
);
}
if (option.scaleByDistance) {
label.scaleByDistance = new Cesium.NearFarScalar(
1.0e2,
1.0,
1.0e7,
0.1
);
} else {
label.scaleByDistance = undefined;
}
}
// 更新距离显示条件
if(option.distanceDisplayCondition!==undefined){
if (option.distanceDisplayCondition) {
const near = getLevelMiddleHeight(
option.distanceDisplayCondition_near
);
const far = getLevelMiddleHeight(option.distanceDisplayCondition_far);
if (this.graphic.billboard) {
this.graphic.billboard.distanceDisplayCondition =
new Cesium.DistanceDisplayCondition(near, far);
}
if (this.graphic.label) {
this.graphic.label.distanceDisplayCondition =
new Cesium.DistanceDisplayCondition(near, far);
}
} else {
if (this.graphic.billboard) {
this.graphic.billboard.distanceDisplayCondition = false;
}
if (this.graphic.label) {
this.graphic.label.distanceDisplayCondition = false;
}
}
}
}
}
// 销毁方法
destroy() {
if (this.graphic && hnMap.map.map && hnMap.map.map.entities) {
hnMap.map.map.entities.remove(this.graphic);
}
}
}
const fn: any = {
mars3d: mars3d_class,
gaode: gaode_class,
siji: siji_class,
cesium: cesium_class,
};
return fn[hnMap.mapType];
};