需求
需要实现如下图所示模块
水滴型:![[Pasted image 20241016093333.png]]
圆形:![[Pasted image 20241015163602.png]]
![[Pasted image 20241017144745.png]]
水滴里面radius是指AE,a是指BE,b是指BD
实现1:纯Canvas实现
圆形实际上可以通过Cesium自带的# CircleOutlineGeometry来实现,但是我这里想统一,因为水滴型是只能通过canvas绘制成img再加载进行,所以暂时统一通过canvas绘制的方法来实现
缺点
太粗暴直接加载而已,无法通过中心点和半径来改变这个园;仅仅只是为了加载出来
代码
圆形Canvas绘制代码(Rectangle就直接贴图实现)
javascript
const viewer = new Cesium.Viewer('cesiumContainer');
// 定义经纬度范围
const lonMin = 100.0;
const latMin = 20.0;
const lonMax = 110.0;
const latMax = 30.0;
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 500;
const ctx = canvas.getContext('2d');
// 定义参数
const width = 500;
const radius = width / 2;
const lineWidth = 5; // 边框线的宽度
const strokeColor = '#3FCF8F'; // 轮廓线的颜色
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 开始绘制圆形轮廓
ctx.save();
ctx.beginPath();
ctx.arc(radius, radius, radius - lineWidth / 2, 0, 2 * Math.PI); // 圆形轮廓
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeColor; // 设置边框颜色
ctx.stroke(); // 绘制边框
ctx.restore();
// 使用Cesium的贴地primitive加载Canvas
viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: new Cesium.GeometryInstance({
// 和二维类似,本质上还是一个矩形
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(
// 提供矩形的四至经纬度
lonMin,
latMin,
lonMax,
latMax
),
}),
}),
appearance: new Cesium.Appearance({
// 创建一个完全自定义的material
material: new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
// textureCanvas是我们创建的自定义Canvas
image: canvas,
},
},
}),
flat: true,
}),
})
);
// 视角飞向贴地圆形区域
viewer.camera.flyTo({
destination: Cesium.Rectangle.fromDegrees(lonMin, latMin, lonMax, latMax),
duration: 3, // 飞行的时间(秒)
});
水滴形cavas绘制代码(Rectangle就直接贴图实现)
javascript
const viewer = new Cesium.Viewer('cesiumContainer');
// 定义经纬度范围
const lonMin = 100.0;
const latMin = 20.0;
const lonMax = 110.0;
const latMax = 30.0;
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 500;
const ctx = canvas.getContext('2d');
// 定义参数
const width = 500;
const radius = width / 2;
const a = 100; // 椭圆的短轴半径
const b = 150; // 椭圆的长轴半径
const rotate = 0; // 旋转角度
const lineWidth = 5; // 轮廓线宽度
const strokeColor = '#3FCF8F'; // 轮廓线颜色
const fillColor = 'transparent'; // 填充颜色(透明)
const alpha = 1; // 透明度
const AB = radius - a; // 用于控制曲线的参数
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 缩小比例
ctx.scale(0.5, 1.0); // 将绘制的图形缩小一半
// 开始绘制水滴形轮廓
ctx.save();
ctx.beginPath();
ctx.globalAlpha = alpha;
ctx.fillStyle = fillColor || 'transparent'; // 设置填充颜色为透明
ctx.strokeStyle = strokeColor; // 设置边框颜色
ctx.lineWidth = lineWidth;
// 移动到水滴的起点
ctx.moveTo(radius, radius);
ctx.rotate((rotate * Math.PI) / 180);
// 绘制二次贝塞尔曲线(左边的弯曲部分)
ctx.quadraticCurveTo(radius + b, radius - AB / 2, radius + b, radius - AB);
// 绘制半椭圆(顶部圆滑部分)
ctx.ellipse(radius, radius - AB, b, a, 0, 0, Math.PI, true);
// 绘制二次贝塞尔曲线(右边的弯曲部分)
ctx.quadraticCurveTo(radius - b, radius - AB / 2, radius, radius);
// 绘制路径并应用样式
ctx.fill(); // 不会显示颜色,填充为空
ctx.stroke(); // 仅绘制边框
ctx.restore();
// 使用Cesium的贴地primitive加载Canvas
viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: new Cesium.GeometryInstance({
// 和二维类似,本质上还是一个矩形
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(
// 提供矩形的四至经纬度
lonMin,
latMin,
lonMax,
latMax
),
}),
}),
appearance: new Cesium.Appearance({
// 创建一个完全自定义的material
material: new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
// textureCanvas是我们创建的自定义Canvas
image: canvas,
},
},
}),
flat: true,
}),
})
);
// 视角飞向贴地圆形区域
viewer.camera.flyTo({
destination: Cesium.Rectangle.fromDegrees(lonMin, latMin, lonMax, latMax),
duration: 3, // 飞行的时间(秒)
});
实现2:Canvas + CircleGeometry实现
圆形轮廓线贴地(传中心点+半径)
javascript
const viewer = new Cesium.Viewer('cesiumContainer');
// 定义中心点
const centerPoint = {
longitude: 112.0285,
latitude: 37.43843,
};
const radiusInMeters = 50; // 半径设置为50米
// 创建 canvas 并绘制圆形图案
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 500;
const ctx = canvas.getContext('2d');
// 定义圆形参数
const width = 500;
const radius = width / 2;
const lineWidth = 5; // 边框线宽
const strokeColor = '#3FCF8F'; // 边框颜色
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制圆形
ctx.save();
ctx.beginPath();
ctx.arc(radius, radius, radius - lineWidth / 2, 0, 2 * Math.PI); // 圆形轮廓
ctx.lineWidth = lineWidth;
ctx.strokeStyle = strokeColor; // 设置边框颜色
ctx.stroke(); // 绘制边框
ctx.restore();
// 使用 CircleGeometry 来绘制贴地的圆形
viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
radius: radiusInMeters, // 半径设置为50米
}),
}),
appearance: new Cesium.Appearance({
material: new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
image: canvas, // 自定义的canvas图形作为材质
},
},
}),
flat: true,
}),
})
);
// 添加中心点标记
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
point: {
pixelSize: 10, // 点的大小
color: Cesium.Color.RED, // 点的颜色
outlineColor: Cesium.Color.WHITE, // 外轮廓的颜色
outlineWidth: 2, // 外轮廓的宽度
},
});
// 飞向圆形区域
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude, 500), // 设置飞行高度
});
为什么不直接用CircleOutlineGeometry来绘制
因为CircleOutlineGeometry不支持贴地,如果要做的话,要用turfJS来把圆半径外的每一个点算出来,再用线贴地的方式来实现(现阶段太麻烦,直接用这种先),先加个todo吧
实现3 完美贴合需求实现
借助AI的力量来实现了,给够描述参数即可实现
水滴型
![[Pasted image 20241016104214.png]]
javascript
// 假设 Cesium 和 CanvasGraphic 已经导入
const viewer = new Cesium.Viewer('cesiumContainer', {
terrain: Cesium.Terrain.fromWorldTerrain(),
});
class CanvasGraphic {
constructor(options = {}) {
const { color = '#3FCF8F', width = 500, lineWidth = 1, shadowColor, shadowBlur = 24 } = options;
this.color = color;
this.width = width;
this.height = width;
this.lineWidth = lineWidth;
this.shadowColor = shadowColor || color;
this.shadowBlur = shadowBlur;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
this.canvas = canvas;
this.ctx = ctx;
ctx.canvas.height = width;
ctx.canvas.width = width;
// 将坐标移到画布中心,不管画什么图,都需要移到中间,使用图层叠加时不会偏移
ctx.translate(width / 2, width / 2);
ctx.moveTo(0, 0);
}
/**
* 绘制圆形
* @param {object} options 绘制圆形传入参数
* @param {string} options.fillColor 填充颜色
* @param {number} options.radius 半径,默认是画板的一半宽
* @param {number} options.alpha 颜色的透明度
*/
drawCircle(options = {}) {
const { ctx, width, shadowColor, color } = this;
const { radius = width / 2, alpha = 1, lineWidth = 2, fillColor = color } = options;
ctx.globalAlpha = alpha;
ctx.save();
ctx.beginPath();
// 只保留内部阴影部分)
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.clip();
// 边框+阴影
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.shadowColor = shadowColor || '#3FCF8F';
ctx.shadowBlur = 0;
ctx.arc(0, 0, radius + lineWidth / 2 + 1, 0, 2 * Math.PI);
ctx.fillStyle = fillColor; // 设置填充颜色
ctx.fill(); // 开始填充
ctx.stroke();
ctx.shadowBlur = 0;
ctx.restore();
}
/**
* 绘制水滴型图形
* @param {object} options 绘制水滴型传入参数
* @param {string} options.fillColor 填充颜色
* @param {number} options.radius 半径,默认是画板的一半宽
* @param {number} options.alpha 颜色的透明度
* @param {number} options.a 椭圆的长轴,radius包含长轴
* @param {number} options.b 椭圆的短轴 radius=>AE; a=>BE; b=>BD
* @param {number} options.rotate 旋转角度,0是向上,逆时针旋转
* @param {*} options
*/
drawWaterDrop(options) {
const { ctx, width, shadowColor, color } = this;
const { fillColor, radius = width / 2, alpha = 1, a, b, rotate = 0, lineWidth = 2 } = options;
ctx.fillStyle = fillColor || shadowColor || color;
const AB = radius - a;
ctx.save();
// 开始新路径
ctx.beginPath();
ctx.globalAlpha = alpha;
// 指定起点,建立子路径
ctx.moveTo(0, 0);
// 指定起点,建立子路径
ctx.rotate((rotate * Math.PI) / 180);
// 绘制二次贝塞尔曲线
ctx.quadraticCurveTo(b, -AB / 2, b, -AB);
// 绘制半椭圆
ctx.ellipse(0, -AB, b, a, 0, 0, Math.PI, true);
// 绘制二次贝塞尔曲线
ctx.quadraticCurveTo(-b, -AB / 2, 0, 0);
ctx.fill();
ctx.strokeStyle = fillColor;
ctx.lineWidth = lineWidth;
ctx.stroke();
ctx.restore();
}
// 得到图片的路径,返回的图片的base64编码
getImage() {
return this.canvas.toDataURL('image/png');
}
}
// 定义中心点
const centerPoint = {
longitude: 112.0285,
latitude: 37.43843,
};
// 定义水滴图案的参数
const option = {
id: '61974198357e00002d0039f5',
longitude: 112.0285,
latitude: 37.43843,
isShow: true,
rotate: 360,
rounds: [
{
color: 'green',
alpha: 0.4,
radius: 30,
a: 9,
b: 7.5,
},
{
color: 'yellow',
radius: 20,
alpha: 0.4,
a: 6,
b: 5,
},
{
color: 'red',
radius: 14,
alpha: 0.4,
a: 4,
b: 3,
},
],
};
// 生成水滴图像的函数
function _getWaterDropImage(options) {
const { rounds = [], maxRadius = 30, rotate = 0 } = options;
const canvasGraphic = new CanvasGraphic({ width: 500, lineWidth: 2 });
const unitRadiusWidth = canvasGraphic.width / (2 * maxRadius); // 单位半径对应的宽度
if (rounds.length) {
rounds.forEach((round) => {
const { radius, color, alpha, a, b } = round;
canvasGraphic.drawWaterDrop({
radius: radius * unitRadiusWidth,
fillColor: color,
alpha,
a: a * unitRadiusWidth,
b: b * unitRadiusWidth,
rotate,
});
});
}
return canvasGraphic.getImage(); // 返回 base64 图片
}
// 将水滴图形添加到 Cesium
function addWaterDropToCesium(viewer, imageBase64, centerPoint) {
viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
radius: 50, // 半径可根据需要调整
}),
}),
appearance: new Cesium.Appearance({
material: new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
image: imageBase64, // 使用生成的水滴图像
},
},
}),
flat: true,
}),
})
);
}
// 获取水滴图像
const waterDropImage = _getWaterDropImage(option);
// 将水滴图像添加到 Cesium 场景
addWaterDropToCesium(viewer, waterDropImage, centerPoint);
// 添加中心点标记
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
point: {
pixelSize: 10, // 点的大小
color: Cesium.Color.RED, // 点的颜色
outlineColor: Cesium.Color.WHITE, // 外轮廓的颜色
outlineWidth: 2, // 外轮廓的宽度
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
// 飞到中心点
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude, 500),
});
圆型
![[Pasted image 20241016104312.png]]
javascript
// 假设 Cesium 和 CanvasGraphic 已经导入
const viewer = new Cesium.Viewer('cesiumContainer', {
terrain: Cesium.Terrain.fromWorldTerrain(),
});
class CanvasGraphic {
constructor(options = {}) {
const { color = '#3FCF8F', width = 500, lineWidth = 1, shadowColor, shadowBlur = 24 } = options;
this.color = color;
this.width = width;
this.height = width;
this.lineWidth = lineWidth;
this.shadowColor = shadowColor || color;
this.shadowBlur = shadowBlur;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
this.canvas = canvas;
this.ctx = ctx;
ctx.canvas.height = width;
ctx.canvas.width = width;
// 将坐标移到画布中心,不管画什么图,都需要移到中间,使用图层叠加时不会偏移
ctx.translate(width / 2, width / 2);
ctx.moveTo(0, 0);
}
/**
* 绘制圆形
* @param {object} options 绘制圆形传入参数
* @param {string} options.fillColor 填充颜色
* @param {number} options.radius 半径,默认是画板的一半宽
* @param {number} options.alpha 颜色的透明度
*/
drawCircle(options = {}) {
const { ctx, width, shadowColor, color } = this;
const { radius = width / 2, alpha = 1, lineWidth = 2, fillColor = color } = options;
ctx.globalAlpha = alpha;
ctx.save();
ctx.beginPath();
// 只保留内部阴影部分)
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.clip();
// 边框+阴影
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.shadowColor = shadowColor || '#3FCF8F';
ctx.shadowBlur = 0;
ctx.arc(0, 0, radius + lineWidth / 2 + 1, 0, 2 * Math.PI);
ctx.fillStyle = fillColor; // 设置填充颜色
ctx.fill(); // 开始填充
ctx.stroke();
ctx.shadowBlur = 0;
ctx.restore();
}
/**
* 绘制水滴型图形
* @param {object} options 绘制水滴型传入参数
* @param {string} options.fillColor 填充颜色
* @param {number} options.radius 半径,默认是画板的一半宽
* @param {number} options.alpha 颜色的透明度
* @param {number} options.a 椭圆的长轴,radius包含长轴
* @param {number} options.b 椭圆的短轴 radius=>AE; a=>BE; b=>BD
* @param {number} options.rotate 旋转角度,0是向上,逆时针旋转
* @param {*} options
*/
drawWaterDrop(options) {
const { ctx, width, shadowColor, color } = this;
const { fillColor, radius = width / 2, alpha = 1, a, b, rotate = 0, lineWidth = 2 } = options;
ctx.fillStyle = fillColor || shadowColor || color;
const AB = radius - a;
ctx.save();
// 开始新路径
ctx.beginPath();
ctx.globalAlpha = alpha;
// 指定起点,建立子路径
ctx.moveTo(0, 0);
// 指定起点,建立子路径
ctx.rotate((rotate * Math.PI) / 180);
// 绘制二次贝塞尔曲线
ctx.quadraticCurveTo(b, -AB / 2, b, -AB);
// 绘制半椭圆
ctx.ellipse(0, -AB, b, a, 0, 0, Math.PI, true);
// 绘制二次贝塞尔曲线
ctx.quadraticCurveTo(-b, -AB / 2, 0, 0);
ctx.fill();
ctx.strokeStyle = fillColor;
ctx.lineWidth = lineWidth;
ctx.stroke();
ctx.restore();
}
// 得到图片的路径,返回的图片的base64编码
getImage() {
return this.canvas.toDataURL('image/png');
}
}
// 定义中心点
const centerPoint = {
longitude: 112.0285,
latitude: 37.43843,
};
// 圆形图案参数
const circleOption = {
id: '61974198357e00002d0039f5',
longitude: 112.0285,
latitude: 37.43843,
rounds: [
{
color: 'green',
alpha: 0.4,
radius: 30, // 圆的半径
},
{
color: 'yellow',
radius: 20,
alpha: 0.4,
},
{
color: 'red',
radius: 14,
alpha: 0.4,
},
],
};
// 生成圆形图像的函数
function _getCircleImage(options) {
const { rounds = [], maxRadius = 30 } = options;
const canvasGraphic = new CanvasGraphic({ width: 500, lineWidth: 2 }); // 创建 CanvasGraphic 实例
// 单位半径对应的宽度
const unitRadiusWidth = canvasGraphic.width / (2 * maxRadius);
if (rounds.length) {
rounds.forEach((round) => {
const { radius, color, alpha } = round;
// 绘制圆形
canvasGraphic.drawCircle({
radius: radius * unitRadiusWidth,
fillColor: color,
alpha,
});
});
}
return canvasGraphic.getImage(); // 返回 base64 图片
}
// 在 Cesium 场景中显示圆形图案
function addCircleToCesium(viewer, imageBase64, centerPoint) {
viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
radius: 30, // 设置半径为 50 米
}),
}),
appearance: new Cesium.Appearance({
material: new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
image: imageBase64, // 使用生成的圆形图案
},
},
}),
flat: true,
}),
})
);
}
// 获取圆形图像
const circleImage = _getCircleImage(circleOption);
// 将圆形图像添加到 Cesium 场景中
addCircleToCesium(viewer, circleImage, centerPoint);
// 添加中心点标记
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
point: {
pixelSize: 10, // 点的大小
color: Cesium.Color.RED, // 点的颜色
outlineColor: Cesium.Color.WHITE, // 外轮廓的颜色
outlineWidth: 2, // 外轮廓的宽度
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
// 飞到中心点
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude, 500),
});
水滴加标签
![[Pasted image 20241016114817.png]]
javascript
// 假设 Cesium 和 CanvasGraphic 已经导入
const viewer = new Cesium.Viewer('cesiumContainer', {
terrain: Cesium.Terrain.fromWorldTerrain(),
});
class CanvasGraphic {
constructor(options = {}) {
const { color = '#3FCF8F', width = 500, lineWidth = 1, shadowColor, shadowBlur = 24 } = options;
this.color = color;
this.width = width;
this.height = width;
this.lineWidth = lineWidth;
this.shadowColor = shadowColor || color;
this.shadowBlur = shadowBlur;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
this.canvas = canvas;
this.ctx = ctx;
ctx.canvas.height = width;
ctx.canvas.width = width;
// 将坐标移到画布中心,不管画什么图,都需要移到中间,使用图层叠加时不会偏移
ctx.translate(width / 2, width / 2);
ctx.moveTo(0, 0);
}
/**
* 绘制圆形
* @param {object} options 绘制圆形传入参数
* @param {string} options.fillColor 填充颜色
* @param {number} options.radius 半径,默认是画板的一半宽
* @param {number} options.alpha 颜色的透明度
*/
drawCircle(options = {}) {
const { ctx, width, shadowColor, color } = this;
const { radius = width / 2, alpha = 1, lineWidth = 2, fillColor = color, label = '' } = options;
ctx.globalAlpha = alpha;
ctx.save();
ctx.beginPath();
// 只保留内部阴影部分)
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.clip();
// 边框+阴影
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.shadowColor = shadowColor || '#3FCF8F';
ctx.shadowBlur = 0;
ctx.arc(0, 0, radius + lineWidth / 2 + 1, 0, 2 * Math.PI);
ctx.fillStyle = fillColor; // 设置填充颜色
ctx.fill(); // 开始填充
ctx.stroke();
ctx.shadowBlur = 0;
ctx.restore();
// 绘制标签
if (label) {
this.drawLabel(label, radius);
}
}
/**
* 绘制水滴型图形
* @param {object} options 绘制水滴型传入参数
* @param {string} options.fillColor 填充颜色
* @param {number} options.radius 半径,默认是画板的一半宽
* @param {number} options.alpha 颜色的透明度
* @param {number} options.a 椭圆的长轴,radius包含长轴
* @param {number} options.b 椭圆的短轴 radius=>AE; a=>BE; b=>BD
* @param {number} options.rotate 旋转角度,0是向上,逆时针旋转
* @param {*} options
*/
drawWaterDrop(options) {
const { ctx, width, shadowColor, color } = this;
const { fillColor, radius = width / 2, alpha = 1, a, b, rotate = 0, lineWidth = 2, label = '' } = options;
ctx.fillStyle = fillColor || shadowColor || color;
const AB = radius - a;
ctx.save();
// 开始新路径
ctx.beginPath();
ctx.globalAlpha = alpha;
// 指定起点,建立子路径
ctx.moveTo(0, 0);
// 指定起点,建立子路径
ctx.rotate((rotate * Math.PI) / 180);
// 绘制二次贝塞尔曲线
ctx.quadraticCurveTo(b, -AB / 2, b, -AB);
// 绘制半椭圆
ctx.ellipse(0, -AB, b, a, 0, 0, Math.PI, true);
// 绘制二次贝塞尔曲线
ctx.quadraticCurveTo(-b, -AB / 2, 0, 0);
ctx.fill();
ctx.strokeStyle = fillColor;
ctx.lineWidth = lineWidth;
ctx.stroke();
ctx.restore();
// 绘制标签
if (label) {
this.drawLabel(label, radius);
}
}
// 绘制标签方法
drawLabel(label, radius) {
const { ctx } = this;
ctx.save();
ctx.fillStyle = '#000'; // 标签颜色
ctx.font = '16px Arial'; // 标签字体
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const x = 0; // 标签的X坐标
const y = -(radius - 20); // 标签的Y坐标
ctx.fillText(label, x, y); // 在指定位置绘制标签
ctx.restore();
}
// 得到图片的路径,返回的图片的base64编码
getImage() {
return this.canvas.toDataURL('image/png');
}
}
// 定义中心点
const centerPoint = {
longitude: 112.0285,
latitude: 37.43843,
};
// 定义水滴图案的参数
const option = {
id: '61974198357e00002d0039f5',
longitude: 112.0285,
latitude: 37.43843,
isShow: true,
rotate: 360,
rounds: [
{
color: 'green',
alpha: 0.4,
radius: 30,
a: 9,
b: 7.5,
label: 'Green Circle', // 圆的标签
},
{
color: 'yellow',
radius: 20,
alpha: 0.4,
a: 6,
b: 5,
label: 'Yellow Circle',
},
{
color: 'red',
radius: 14,
alpha: 0.4,
a: 4,
b: 3,
label: 'Red Circle',
},
],
};
// 生成水滴图像的函数
function _getWaterDropImage(options) {
const { rounds = [], maxRadius = 30, rotate = 0 } = options;
const canvasGraphic = new CanvasGraphic({ width: 500, lineWidth: 2 });
const unitRadiusWidth = canvasGraphic.width / (2 * maxRadius); // 单位半径对应的宽度
if (rounds.length) {
rounds.forEach((round, index) => {
const { radius, color, alpha, a, b, label } = round;
canvasGraphic.drawWaterDrop({
radius: radius * unitRadiusWidth,
fillColor: color,
alpha,
a: a * unitRadiusWidth,
b: b * unitRadiusWidth,
rotate,
label: label || `Label ${index + 1}`, // 默认标签
});
});
}
return canvasGraphic.getImage(); // 返回 base64 图片
}
// 将水滴图形添加到 Cesium
function addWaterDropToCesium(viewer, imageBase64, centerPoint) {
viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
radius: 50, // 半径可根据需要调整
}),
}),
appearance: new Cesium.Appearance({
material: new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
image: imageBase64, // 使用生成的水滴图像
},
},
}),
flat: true,
}),
})
);
}
// 获取水滴图像
const waterDropImage = _getWaterDropImage(option);
// 将水滴图像添加到 Cesium 场景
addWaterDropToCesium(viewer, waterDropImage, centerPoint);
// 添加中心点标记
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
point: {
pixelSize: 10, // 点的大小
color: Cesium.Color.RED, // 点的颜色
outlineColor: Cesium.Color.WHITE, // 外轮廓的颜色
outlineWidth: 2, // 外轮廓的宽度
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
// 飞到中心点
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude, 500),
});
圆形加标签
![[Pasted image 20241016115005.png]]
javascript
// 假设 Cesium 和 CanvasGraphic 已经导入
const viewer = new Cesium.Viewer('cesiumContainer', {
terrain: Cesium.Terrain.fromWorldTerrain(),
});
class CanvasGraphic {
constructor(options = {}) {
const { color = '#3FCF8F', width = 500, lineWidth = 1, shadowColor, shadowBlur = 24 } = options;
this.color = color;
this.width = width;
this.height = width;
this.lineWidth = lineWidth;
this.shadowColor = shadowColor || color;
this.shadowBlur = shadowBlur;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
this.canvas = canvas;
this.ctx = ctx;
ctx.canvas.height = width;
ctx.canvas.width = width;
ctx.translate(width / 2, width / 2); // 将坐标移到画布中心
}
// 绘制圆形
drawCircle(options = {}) {
const { ctx, width, shadowColor, color } = this;
const { radius = width / 2, alpha = 1, lineWidth = 2, fillColor = color, label = '' } = options;
ctx.globalAlpha = alpha;
ctx.save();
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.clip();
ctx.beginPath();
ctx.lineWidth = lineWidth;
ctx.shadowColor = shadowColor || '#3FCF8F';
ctx.shadowBlur = 0;
ctx.arc(0, 0, radius + lineWidth / 2 + 1, 0, 2 * Math.PI);
ctx.fillStyle = fillColor;
ctx.fill();
ctx.stroke();
ctx.restore();
// 绘制标签
if (label) {
this.drawLabel(label, radius);
}
}
// 绘制标签方法
drawLabel(label, radius) {
const { ctx } = this;
ctx.save();
ctx.fillStyle = '#000'; // 标签颜色
ctx.font = '16px Arial'; // 标签字体
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const x = 0; // 标签的X坐标
const y = -(radius - 20); // 标签的Y坐标,放在圆的上方
ctx.fillText(label, x, y); // 在指定位置绘制标签
ctx.restore();
}
getImage() {
return this.canvas.toDataURL('image/png');
}
}
// 定义中心点
const centerPoint = {
longitude: 112.0285,
latitude: 37.43843,
};
// 圆形图案参数
const circleOption = {
id: '61974198357e00002d0039f5',
longitude: 112.0285,
latitude: 37.43843,
rounds: [
{
color: 'green',
alpha: 0.4,
radius: 30, // 圆的半径
label: 'Green Circle', // 圆的标签
},
{
color: 'yellow',
radius: 20,
alpha: 0.4,
label: 'Yellow Circle',
},
{
color: 'red',
radius: 14,
alpha: 0.4,
label: 'Red Circle',
},
],
};
// 使用修改后的代码,绘制带有标签的圆形图像
function _getCircleImageWithLabels(options) {
const { rounds = [], maxRadius = 30 } = options;
const canvasGraphic = new CanvasGraphic({ width: 500, lineWidth: 2 });
const unitRadiusWidth = canvasGraphic.width / (2 * maxRadius);
if (rounds.length) {
rounds.forEach((round, index) => {
const { radius, color, alpha, label } = round;
canvasGraphic.drawCircle({
radius: radius * unitRadiusWidth,
fillColor: color,
alpha,
label: label || `Label ${index + 1}`, // 默认标签
});
});
}
return canvasGraphic.getImage();
}
// 在 Cesium 场景中显示圆形图案
function addCircleToCesium(viewer, imageBase64, centerPoint) {
viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
radius: 30, // 设置半径为 50 米
}),
}),
appearance: new Cesium.Appearance({
material: new Cesium.Material({
fabric: {
type: 'Image',
uniforms: {
image: imageBase64, // 使用生成的圆形图案
},
},
}),
flat: true,
}),
})
);
}
// 获取带标签的圆形图像
const circleImageWithLabels = _getCircleImageWithLabels(circleOption);
// 在 Cesium 场景中显示带有标签的圆形图像
addCircleToCesium(viewer, circleImageWithLabels, centerPoint);
// 添加中心点标记
viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude),
point: {
pixelSize: 10, // 点的大小
color: Cesium.Color.RED, // 点的颜色
outlineColor: Cesium.Color.WHITE, // 外轮廓的颜色
outlineWidth: 2, // 外轮廓的宽度
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
// 飞到中心点
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(centerPoint.longitude, centerPoint.latitude, 500),
});