需求
需要实现如下图所示模块
水滴型:![[Pasted image 20241015163544.png]]
圆形:![[Pasted image 20241015163602.png]]
实现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吧
问题
1、如何确保我给的中心点就是圆的中心点 / 水滴的下方中心点
2、 要加标签怎么加?