mirror of
https://github.com/ethan-zf/cesium-plot-js.git
synced 2025-06-24 03:27:29 +00:00
add attack arrow
This commit is contained in:
parent
252dbf4bcc
commit
599f047e0a
@ -1,16 +1,16 @@
|
||||
import CesiumPlot from "../src";
|
||||
import CesiumPlot from '../src';
|
||||
// import CesiumPlot from "../dist/CesiumPlot";
|
||||
import * as Cesium from "./cesium/index";
|
||||
import * as Cesium from './cesium/index';
|
||||
|
||||
// let raster = new Cesium.ArcGisMapServerImageryProvider({
|
||||
// url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
|
||||
// });
|
||||
|
||||
let keda = new Cesium.UrlTemplateImageryProvider({
|
||||
url: "https://10.68.8.41:9043/kmap-server/gridMap/tile/{z}/{y}/{x}",
|
||||
url: 'https://10.68.8.41:9043/kmap-server/gridMap/tile/{z}/{y}/{x}',
|
||||
// url: 'http://10.68.8.58:8080/3d/dom2/{z}/{x}/{y}.png'
|
||||
});
|
||||
const viewer = new Cesium.Viewer("cesiumContainer", {
|
||||
const viewer = new Cesium.Viewer('cesiumContainer', {
|
||||
animation: false,
|
||||
shouldAnimate: true,
|
||||
geocoder: false,
|
||||
@ -34,6 +34,12 @@ viewer.scene.camera.setView({
|
||||
destination: Cesium.Cartesian3.fromDegrees(107.857, 35.594498, 8000000),
|
||||
});
|
||||
|
||||
document.getElementById("drawStraightArrow").onclick = () => {
|
||||
const fineArrow = document.getElementById('drawFineArrow') as HTMLElement;
|
||||
fineArrow.onclick = () => {
|
||||
new CesiumPlot.FineArrow(Cesium, viewer, {});
|
||||
};
|
||||
|
||||
const attackArrow = document.getElementById('drawAttackArrow') as HTMLElement;
|
||||
attackArrow.onclick = () => {
|
||||
new CesiumPlot.AttackArrow(Cesium, viewer, {});
|
||||
};
|
28
index.html
28
index.html
@ -15,19 +15,41 @@
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
#drawStraightArrow {
|
||||
/* #btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
} */
|
||||
|
||||
.button-container {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
display: flex; /* 使用 Flex 布局 */
|
||||
justify-content: center; /* 水平居中对齐 */
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: 0 10px; /* 按钮之间的间距 */
|
||||
padding: 6px 10px; /* 按钮内边距 */
|
||||
background-color: #3498db; /* 按钮背景颜色 */
|
||||
color: #ffffff; /* 按钮文字颜色 */
|
||||
border: none; /* 去除边框 */
|
||||
border-radius: 5px; /* 圆角边框 */
|
||||
cursor: pointer; /* 鼠标指针样式 */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div id="cesiumContainer"></div>
|
||||
<button id="drawStraightArrow" class="btn btn-success">直箭头</button>
|
||||
<div class="button-container">
|
||||
<button id="drawFineArrow" class="button">直箭头</button>
|
||||
<button id="drawAttackArrow" class="button">进攻方向箭头</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.CESIUM_BASE_URL = "./examples/cesium";
|
||||
window.CESIUM_BASE_URL = './examples/cesium';
|
||||
</script>
|
||||
<script type="module" src="./examples/index.ts"></script>
|
||||
</body>
|
||||
|
139
src/arrow/attack-arrow.ts
Normal file
139
src/arrow/attack-arrow.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import Draw from '../draw';
|
||||
import * as Utils from '../utils';
|
||||
import { Cartesian3 } from '@examples/cesium';
|
||||
|
||||
export default class AttackArrow extends Draw {
|
||||
points: Cartesian3[] = [];
|
||||
headHeightFactor: number;
|
||||
headWidthFactor: number;
|
||||
neckHeightFactor: number;
|
||||
neckWidthFactor: number;
|
||||
headTailFactor: number;
|
||||
|
||||
constructor(cesium: any, viewer: any, style: any) {
|
||||
super(cesium, viewer);
|
||||
this.cesium = cesium;
|
||||
this.headHeightFactor = 0.18;
|
||||
this.headWidthFactor = 0.3;
|
||||
this.neckHeightFactor = 0.85;
|
||||
this.neckWidthFactor = 0.15;
|
||||
this.headTailFactor = 0.8;
|
||||
this.setState('drawing');
|
||||
this.onDoubleClick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add points only on click events
|
||||
*/
|
||||
addPoint(cartesian: Cartesian3) {
|
||||
this.points.push(cartesian);
|
||||
if (this.points.length < 2) {
|
||||
this.onMouseMove();
|
||||
} else if (this.points.length === 2) {
|
||||
this.setGeometryPoints(this.points);
|
||||
this.addToMap();
|
||||
this.lineEntity && this.viewer.entities.remove(this.lineEntity);
|
||||
} else {
|
||||
console.error('click...');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a shape based on mouse movement points during the initial drawing.
|
||||
*/
|
||||
updateMovingPoint(cartesian: Cartesian3) {
|
||||
const tempPoints = [...this.points, cartesian];
|
||||
//
|
||||
this.setGeometryPoints(tempPoints);
|
||||
if (tempPoints.length === 2) {
|
||||
this.drawLine();
|
||||
} else {
|
||||
const geometryPoints = this.createPolygon(tempPoints);
|
||||
this.setGeometryPoints(geometryPoints);
|
||||
this.addToMap();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate geometric shapes based on key points.
|
||||
*/
|
||||
createPolygon(positions: Cartesian3[]): Cartesian3[] {
|
||||
const lnglatPoints = positions.map((pnt) => {
|
||||
return this.cartesianToLnglat(pnt);
|
||||
});
|
||||
|
||||
let [tailLeft, tailRight] = [lnglatPoints[0], lnglatPoints[1]];
|
||||
if (Utils.isClockWise(lnglatPoints[0], lnglatPoints[1], lnglatPoints[2])) {
|
||||
tailLeft = lnglatPoints[1];
|
||||
tailRight = lnglatPoints[0];
|
||||
}
|
||||
|
||||
const midTail = Utils.Mid(tailLeft, tailRight);
|
||||
const bonePnts = [midTail].concat(lnglatPoints.slice(2));
|
||||
const headPnts = this.getArrowHeadPoints(bonePnts, tailLeft, tailRight);
|
||||
const [neckLeft, neckRight] = [headPnts[0], headPnts[4]];
|
||||
const tailWidthFactor = Utils.MathDistance(tailLeft, tailRight) / Utils.getBaseLength(bonePnts);
|
||||
const bodyPnts = this.getArrowBodyPoints(bonePnts, neckLeft, neckRight, tailWidthFactor);
|
||||
const count = bodyPnts.length;
|
||||
let leftPnts = [tailLeft].concat(bodyPnts.slice(0, count / 2));
|
||||
leftPnts.push(neckLeft);
|
||||
let rightPnts = [tailRight].concat(bodyPnts.slice(count / 2, count));
|
||||
rightPnts.push(neckRight);
|
||||
leftPnts = Utils.getQBSplinePoints(leftPnts);
|
||||
rightPnts = Utils.getQBSplinePoints(rightPnts);
|
||||
const points = leftPnts.concat(headPnts, rightPnts.reverse());
|
||||
const temp = [].concat(...points);
|
||||
const cartesianPoints = this.cesium.Cartesian3.fromDegreesArray(temp);
|
||||
return cartesianPoints;
|
||||
}
|
||||
|
||||
getPoints() {
|
||||
return this.points;
|
||||
}
|
||||
|
||||
getArrowHeadPoints(points, tailLeft, tailRight) {
|
||||
try {
|
||||
let len = Utils.getBaseLength(points);
|
||||
let headHeight = len * this.headHeightFactor;
|
||||
const headPnt = points[points.length - 1];
|
||||
len = Utils.MathDistance(headPnt, points[points.length - 2]);
|
||||
const tailWidth = Utils.MathDistance(tailLeft, tailRight);
|
||||
if (headHeight > tailWidth * this.headTailFactor) {
|
||||
headHeight = tailWidth * this.headTailFactor;
|
||||
}
|
||||
const headWidth = headHeight * this.headWidthFactor;
|
||||
const neckWidth = headHeight * this.neckWidthFactor;
|
||||
headHeight = headHeight > len ? len : headHeight;
|
||||
const neckHeight = headHeight * this.neckHeightFactor;
|
||||
const headEndPnt = Utils.getThirdPoint(points[points.length - 2], headPnt, 0, headHeight, true);
|
||||
const neckEndPnt = Utils.getThirdPoint(points[points.length - 2], headPnt, 0, neckHeight, true);
|
||||
const headLeft = Utils.getThirdPoint(headPnt, headEndPnt, Math.PI / 2, headWidth, false);
|
||||
const headRight = Utils.getThirdPoint(headPnt, headEndPnt, Math.PI / 2, headWidth, true);
|
||||
const neckLeft = Utils.getThirdPoint(headPnt, neckEndPnt, Math.PI / 2, neckWidth, false);
|
||||
const neckRight = Utils.getThirdPoint(headPnt, neckEndPnt, Math.PI / 2, neckWidth, true);
|
||||
return [neckLeft, headLeft, headPnt, headRight, neckRight];
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
getArrowBodyPoints(points, neckLeft, neckRight, tailWidthFactor) {
|
||||
const allLen = Utils.wholeDistance(points);
|
||||
const len = Utils.getBaseLength(points);
|
||||
const tailWidth = len * tailWidthFactor;
|
||||
const neckWidth = Utils.MathDistance(neckLeft, neckRight);
|
||||
const widthDif = (tailWidth - neckWidth) / 2;
|
||||
// eslint-disable-next-line
|
||||
let [tempLen, leftBodyPnts, rightBodyPnts] = [0, [], []];
|
||||
for (let i = 1; i < points.length - 1; i++) {
|
||||
const angle = Utils.getAngleOfThreePoints(points[i - 1], points[i], points[i + 1]) / 2;
|
||||
tempLen += Utils.MathDistance(points[i - 1], points[i]);
|
||||
const w = (tailWidth / 2 - (tempLen / allLen) * widthDif) / Math.sin(angle);
|
||||
const left = Utils.getThirdPoint(points[i - 1], points[i], Math.PI - angle, w, true);
|
||||
const right = Utils.getThirdPoint(points[i - 1], points[i], angle, w, false);
|
||||
leftBodyPnts.push(left);
|
||||
rightBodyPnts.push(right);
|
||||
}
|
||||
return leftBodyPnts.concat(rightBodyPnts);
|
||||
}
|
||||
}
|
@ -4,10 +4,22 @@ import { Cartesian3 } from '@examples/cesium';
|
||||
|
||||
export default class FineArrow extends Draw {
|
||||
points: Cartesian3[] = [];
|
||||
arrowLengthScale: number = 5;
|
||||
maxArrowLength: number = 2;
|
||||
tailWidthFactor: number;
|
||||
neckWidthFactor: number;
|
||||
headWidthFactor: number;
|
||||
headAngle: number;
|
||||
neckAngle: number;
|
||||
|
||||
constructor(cesium: any, viewer: any, style: any) {
|
||||
super(cesium, viewer);
|
||||
this.cesium = cesium;
|
||||
this.tailWidthFactor = 0.1;
|
||||
this.neckWidthFactor = 0.2;
|
||||
this.headWidthFactor = 0.25;
|
||||
this.headAngle = Math.PI / 8.5;
|
||||
this.neckAngle = Math.PI / 13;
|
||||
this.setState('drawing');
|
||||
}
|
||||
|
||||
@ -15,24 +27,32 @@ export default class FineArrow extends Draw {
|
||||
* Add points only on click events
|
||||
*/
|
||||
addPoint(cartesian: Cartesian3) {
|
||||
this.points.push();
|
||||
if (this.points.length === 0) {
|
||||
this.points[0] = cartesian;
|
||||
if (this.points.length < 2) {
|
||||
this.points.push(cartesian);
|
||||
this.onMouseMove();
|
||||
}
|
||||
if (this.points.length === 2) {
|
||||
const geometryPoints = this.createPolygon(this.points);
|
||||
this.setGeometryPoints(geometryPoints);
|
||||
this.addToMap();
|
||||
this.removeMoveListener();
|
||||
this.setState('static');
|
||||
this.finishDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the last point as the mouse moves.
|
||||
* Draw a shape based on mouse movement points during the initial drawing.
|
||||
*/
|
||||
updateMovingPoint(cartesian: Cartesian3, index: number) {
|
||||
updateMovingPoint(cartesian: Cartesian3) {
|
||||
const tempPoints = [...this.points, cartesian];
|
||||
const geometryPoints = this.createPolygon(tempPoints);
|
||||
this.setGeometryPoints(geometryPoints);
|
||||
this.addToMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* In edit mode, drag key points to update corresponding key point data.
|
||||
*/
|
||||
updateDraggingPoint(cartesian: Cartesian3, index: number) {
|
||||
this.points[index] = cartesian;
|
||||
const geometryPoints = this.createPolygon(this.points);
|
||||
this.setGeometryPoints(geometryPoints);
|
||||
|
93
src/draw.ts
93
src/draw.ts
@ -5,28 +5,18 @@ import { State } from './interface';
|
||||
export default class Draw {
|
||||
cesium: typeof CesiumTypeOnly;
|
||||
viewer: CesiumTypeOnly.Viewer;
|
||||
arrowLengthScale: number = 5;
|
||||
maxArrowLength: number = 2;
|
||||
tailWidthFactor: number;
|
||||
neckWidthFactor: number;
|
||||
headWidthFactor: number;
|
||||
headAngle: number;
|
||||
neckAngle: number;
|
||||
eventHandler: CesiumTypeOnly.ScreenSpaceEventHandler;
|
||||
entity: CesiumTypeOnly.Entity;
|
||||
polygonEntity: CesiumTypeOnly.Entity;
|
||||
geometryPoints: CesiumTypeOnly.Cartesian3[] = [];
|
||||
state: State = 'drawing';
|
||||
controlPoints: CesiumTypeOnly.EntityCollection;
|
||||
controlPointsEventHandler: CesiumTypeOnly.ScreenSpaceEventHandler;
|
||||
lineEntity: CesiumTypeOnly.Entity;
|
||||
|
||||
constructor(cesium: typeof CesiumTypeOnly, viewer: CesiumTypeOnly.Viewer) {
|
||||
this.cesium = cesium;
|
||||
this.viewer = viewer;
|
||||
this.tailWidthFactor = 0.1;
|
||||
this.neckWidthFactor = 0.2;
|
||||
this.headWidthFactor = 0.25;
|
||||
this.headAngle = Math.PI / 8.5;
|
||||
this.neckAngle = Math.PI / 13;
|
||||
|
||||
this.cartesianToLnglat = this.cartesianToLnglat.bind(this);
|
||||
this.pixelToCartesian = this.pixelToCartesian.bind(this);
|
||||
this.onClick();
|
||||
@ -52,12 +42,18 @@ export default class Draw {
|
||||
*/
|
||||
onClick() {
|
||||
this.eventHandler = new this.cesium.ScreenSpaceEventHandler(this.viewer.canvas);
|
||||
this.eventHandler.setInputAction((evt) => {
|
||||
this.eventHandler.setInputAction((evt: any) => {
|
||||
const pickedObject = this.viewer.scene.pick(evt.position);
|
||||
const hitEntities = this.cesium.defined(pickedObject) && pickedObject.id instanceof CesiumTypeOnly.Entity;
|
||||
if (this.state === 'drawing') {
|
||||
// In the drawing state, the points clicked are key nodes of the shape, and they are saved in this.points.
|
||||
const cartesian = this.pixelToCartesian(evt.position);
|
||||
const points = this.getPoints();
|
||||
// If clicked outside the sphere or if the distance between the current click position and
|
||||
// the previous click position is less than 10 meters, it is considered an invalid point.
|
||||
if (!cartesian || (points.length > 0 && !this.checkDistance(cartesian, points[points.length - 1]))) {
|
||||
return;
|
||||
}
|
||||
this.addPoint(cartesian);
|
||||
} else if (this.state === 'edit') {
|
||||
//In edit mode, exiting the edit state and deleting control points when clicking in the blank area.
|
||||
@ -79,22 +75,38 @@ export default class Draw {
|
||||
}
|
||||
|
||||
onMouseMove() {
|
||||
this.eventHandler.setInputAction((evt) => {
|
||||
this.drawingWhileMoving(evt.endPosition, 1);
|
||||
this.eventHandler.setInputAction((evt: any) => {
|
||||
const points = this.getPoints();
|
||||
const cartesian = this.pixelToCartesian(evt.endPosition);
|
||||
if (!cartesian) {
|
||||
return;
|
||||
}
|
||||
if (this.checkDistance(cartesian, points[points.length - 1])) {
|
||||
// Synchronize data to subclasses.If the distance is less than 10 meters, do not proceed
|
||||
this.updateMovingPoint(cartesian, points.length);
|
||||
}
|
||||
}, this.cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||
}
|
||||
|
||||
drawingWhileMoving(position: CesiumTypeOnly.Cartesian2, index: number) {
|
||||
const cartesian = this.pixelToCartesian(position);
|
||||
const lnglat = this.cartesianToLnglat(cartesian);
|
||||
const points = this.getPoints();
|
||||
const lastPoint = this.cartesianToLnglat(points[points.length - 1]);
|
||||
const distance = Utils.MathDistance(lnglat, lastPoint);
|
||||
if (distance < 0.0001) {
|
||||
return false;
|
||||
onDoubleClick() {
|
||||
// this.eventHandler = new this.cesium.ScreenSpaceEventHandler(this.viewer.canvas);
|
||||
this.eventHandler.setInputAction((evt: any) => {
|
||||
console.error('db click...');
|
||||
this.finishDrawing();
|
||||
}, this.cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
|
||||
}
|
||||
// Synchronize data to subclasses.
|
||||
this.updateMovingPoint(cartesian, index);
|
||||
|
||||
/**
|
||||
* Check if the distance between two points is greater than 10 meters.
|
||||
*/
|
||||
checkDistance(cartesian1: CesiumTypeOnly.Cartesian3, cartesian2: CesiumTypeOnly.Cartesian3) {
|
||||
const distance = this.cesium.Cartesian3.distance(cartesian1, cartesian2);
|
||||
return distance > 10;
|
||||
}
|
||||
|
||||
finishDrawing() {
|
||||
this.removeMoveListener();
|
||||
this.setState('static');
|
||||
}
|
||||
|
||||
removeClickListener() {
|
||||
@ -117,8 +129,8 @@ export default class Draw {
|
||||
const callback = () => {
|
||||
return new this.cesium.PolygonHierarchy(this.geometryPoints);
|
||||
};
|
||||
if (!this.entity) {
|
||||
this.entity = this.viewer.entities.add({
|
||||
if (!this.polygonEntity) {
|
||||
this.polygonEntity = this.viewer.entities.add({
|
||||
polygon: new this.cesium.PolygonGraphics({
|
||||
hierarchy: new this.cesium.CallbackProperty(callback, false),
|
||||
show: true,
|
||||
@ -129,6 +141,19 @@ export default class Draw {
|
||||
}
|
||||
}
|
||||
|
||||
drawLine() {
|
||||
if (!this.lineEntity) {
|
||||
this.lineEntity = this.viewer.entities.add({
|
||||
polyline: {
|
||||
positions: new this.cesium.CallbackProperty(() => this.geometryPoints, false),
|
||||
width: 5,
|
||||
// material: this.cesium.Color.RED,
|
||||
clampToGround: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cartesianToLnglat(cartesian: CesiumTypeOnly.Cartesian3): number[] {
|
||||
const lnglat = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
|
||||
const lat = this.cesium.Math.toDegrees(lnglat.latitude);
|
||||
@ -161,7 +186,7 @@ export default class Draw {
|
||||
|
||||
this.controlPointsEventHandler = new this.cesium.ScreenSpaceEventHandler(this.viewer.canvas);
|
||||
// Listen for left mouse button press events
|
||||
this.controlPointsEventHandler.setInputAction((clickEvent) => {
|
||||
this.controlPointsEventHandler.setInputAction((clickEvent: any) => {
|
||||
const pickedObject = this.viewer.scene.pick(clickEvent.position);
|
||||
|
||||
if (this.cesium.defined(pickedObject)) {
|
||||
@ -179,12 +204,12 @@ export default class Draw {
|
||||
}, this.cesium.ScreenSpaceEventType.LEFT_DOWN);
|
||||
|
||||
// Listen for mouse movement events
|
||||
this.controlPointsEventHandler.setInputAction((moveEvent) => {
|
||||
this.controlPointsEventHandler.setInputAction((moveEvent: any) => {
|
||||
if (isDragging && draggedIcon) {
|
||||
const cartesian = this.viewer.camera.pickEllipsoid(moveEvent.endPosition, this.viewer.scene.globe.ellipsoid);
|
||||
if (cartesian) {
|
||||
draggedIcon.position.setValue(cartesian);
|
||||
this.drawingWhileMoving(moveEvent.endPosition, draggedIcon.index);
|
||||
this.updateDraggingPoint(cartesian, draggedIcon.index);
|
||||
}
|
||||
}
|
||||
}, this.cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||
@ -215,7 +240,11 @@ export default class Draw {
|
||||
return this.cesium.Cartesian3();
|
||||
}
|
||||
|
||||
updateMovingPoint(cartesian: CesiumTypeOnly.Cartesian3, index: number) {
|
||||
updateMovingPoint(cartesian: CesiumTypeOnly.Cartesian3, index?: number) {
|
||||
//Abstract method that must be implemented by subclasses.
|
||||
}
|
||||
|
||||
updateDraggingPoint(cartesian: CesiumTypeOnly.Cartesian3, index: number) {
|
||||
//Abstract method that must be implemented by subclasses.
|
||||
}
|
||||
}
|
||||
|
10
src/index.ts
10
src/index.ts
@ -1,7 +1,9 @@
|
||||
import FineArrow from './arrow/fine-arrow'
|
||||
import FineArrow from './arrow/fine-arrow';
|
||||
import AttackArrow from './arrow/attack-arrow';
|
||||
|
||||
const CesiumPlot = {
|
||||
FineArrow
|
||||
}
|
||||
const CesiumPlot = {
|
||||
FineArrow,
|
||||
AttackArrow,
|
||||
};
|
||||
|
||||
export default CesiumPlot;
|
||||
|
Loading…
Reference in New Issue
Block a user