Skip to content

Commit

Permalink
fix Geometry rotate pivot error when coordinates change (#2396)
Browse files Browse the repository at this point in the history
* fix Geometry rotate pivot error when coordinates change

* spec

* updates

* fix typo

* tweak

* update rollup.config.js
  • Loading branch information
deyihu authored Aug 12, 2024
1 parent 1c60ee3 commit 7f71f60
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 100 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
"dependencies": {
"@maptalks/feature-filter": "^1.3.0",
"@maptalks/function-type": "^1.3.1",
"dts-bundle-generator": "^9.5.1",
"frustum-intersects": "^0.1.0",
"lineclip": "^1.1.5",
"maptalks": "file:",
Expand All @@ -67,6 +66,7 @@
"@rollup/plugin-typescript": "^11.1.6",
"@types/node": "^20.11.30",
"@types/offscreencanvas": "^2019.7.3",
"dts-bundle-generator": "^9.5.1",
"eslint": "^8.57.0",
"eslint-plugin-mocha": "^10.4.1",
"expect-maptalks": "^0.4.1",
Expand Down
4 changes: 3 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ const rollupPlugins = [
main: true
}),
commonjs(),
typescript()
typescript({
sourceMap: true
})
];

// const compilePlugins = [
Expand Down
197 changes: 100 additions & 97 deletions src/geometry/CenterMixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,109 +12,112 @@ import type { Map } from '../map';
* @mixin CenterMixin
*/
export default function <T extends MixinConstructor>(Base: T) {
return class extends Base {
//@internal
_coordinates: Coordinate
//@internal
_pcenter: Coordinate
//@internal
_dirtyCoords: boolean
getMap?(): Map
//@internal
_getProjection?(): CommonProjectionType
onPositionChanged?(): void
//@internal
_verifyProjection?(): void
//@internal
_clearCache?(): void
/**
* 获取几何图形的中心点
* @english
* Get geometry's center
* @return {Coordinate} - center of the geometry
* @function CenterMixin.getCoordinates
*/
getCoordinates(): Coordinate {
return this._coordinates;
}
return class extends Base {
//@internal
_coordinates: Coordinate
//@internal
_pcenter: Coordinate
//@internal
_dirtyCoords: boolean
getMap?(): Map
//@internal
_getProjection?(): CommonProjectionType
onPositionChanged?(): void
//@internal
_verifyProjection?(): void
//@internal
_clearCache?(): void
//@internal
_translateRotatePivot?(coordinate: Coordinate): this;
/**
* 获取几何图形的中心点
* @english
* Get geometry's center
* @return {Coordinate} - center of the geometry
* @function CenterMixin.getCoordinates
*/
getCoordinates(): Coordinate {
return this._coordinates;
}

/**
* 设置几何图形的中心点
* @english
* Set a new center to the geometry
* @param {Coordinate|Number[]} coordinates - new center
* @return {Geometry} this
* @fires Geometry#positionchange
* @function CenterMixin.setCoordinates
*/
setCoordinates(coordinates: Coordinate | Array<number>) {
const center = (coordinates instanceof Coordinate) ? coordinates : new Coordinate(coordinates as [number, number, number]);
this._coordinates = center;
if (!this.getMap()) {
//When not on a layer or when creating a new one, temporarily save the coordinates,
this._dirtyCoords = true;
this.onPositionChanged();
return this;
}
const projection = this._getProjection();
this._setPrjCoordinates(projection.project(this._coordinates));
return this;
}
/**
* 设置几何图形的中心点
* @english
* Set a new center to the geometry
* @param {Coordinate|Number[]} coordinates - new center
* @return {Geometry} this
* @fires Geometry#positionchange
* @function CenterMixin.setCoordinates
*/
setCoordinates(coordinates: Coordinate | Array<number>) {
const center = (coordinates instanceof Coordinate) ? coordinates : new Coordinate(coordinates as [number, number, number]);
this._translateRotatePivot(center);
this._coordinates = center;
if (!this.getMap()) {
//When not on a layer or when creating a new one, temporarily save the coordinates,
this._dirtyCoords = true;
this.onPositionChanged();
return this;
}
const projection = this._getProjection();
this._setPrjCoordinates(projection.project(this._coordinates));
return this;
}

//Gets view point of the geometry's center
//@internal
_getCenter2DPoint(res?: number): Point {
const map = this.getMap();
if (!map) {
return null;
}
const pcenter = this._getPrjCoordinates();
if (!pcenter) { return null; }
if (!res) {
res = map._getResolution();
}
return map._prjToPointAtRes(pcenter, res);
}
//Gets view point of the geometry's center
//@internal
_getCenter2DPoint(res?: number): Point {
const map = this.getMap();
if (!map) {
return null;
}
const pcenter = this._getPrjCoordinates();
if (!pcenter) { return null; }
if (!res) {
res = map._getResolution();
}
return map._prjToPointAtRes(pcenter, res);
}

//@internal
_getPrjCoordinates(): Coordinate {
const projection = this._getProjection();
this._verifyProjection();
if (!this._pcenter && projection) {
if (this._coordinates) {
this._pcenter = projection.project(this._coordinates);
//@internal
_getPrjCoordinates(): Coordinate {
const projection = this._getProjection();
this._verifyProjection();
if (!this._pcenter && projection) {
if (this._coordinates) {
this._pcenter = projection.project(this._coordinates);
}
}
return this._pcenter;
}
}
return this._pcenter;
}

//Set center by projected coordinates
//@internal
_setPrjCoordinates(pcenter: Coordinate): void {
this._pcenter = pcenter;
this.onPositionChanged();
}
//Set center by projected coordinates
//@internal
_setPrjCoordinates(pcenter: Coordinate): void {
this._pcenter = pcenter;
this.onPositionChanged();
}

//update cached const iables if geometry is updated.
//@internal
_updateCache(): void {
this._clearCache();
const projection = this._getProjection();
if (this._pcenter && projection) {
this._coordinates = projection.unproject(this._pcenter);
}
}
//update cached const iables if geometry is updated.
//@internal
_updateCache(): void {
this._clearCache();
const projection = this._getProjection();
if (this._pcenter && projection) {
this._coordinates = projection.unproject(this._pcenter);
}
}

//@internal
_clearProjection(): void {
this._pcenter = null;
// @ts-expect-error todo
super._clearProjection();
}
//@internal
_clearProjection(): void {
this._pcenter = null;
// @ts-expect-error todo
super._clearProjection();
}

//@internal
_computeCenter(): Coordinate | null {
return this._coordinates ? this._coordinates.copy() : null;
}
};
//@internal
_computeCenter(): Coordinate | null {
return this._coordinates ? this._coordinates.copy() : null;
}
};
}
24 changes: 24 additions & 0 deletions src/geometry/Geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,30 @@ export class Geometry extends JSONAble(Eventable(Handlerable(Class))) {
return this;
}

//translate rotate Pivot when coordinates change
//@interlal
_translateRotatePivot(newCoordinate: Coordinate) {
if (!this._pivot || !newCoordinate) {
return this;
}
if (this.options.rotatePivot) {
const oldCoordinate = this.getCoordinates();
if (!oldCoordinate) {
return this;
}
if (!(newCoordinate instanceof Coordinate)) {
newCoordinate = new Coordinate(newCoordinate);
}
const offset = newCoordinate.sub(oldCoordinate as Coordinate);
if (offset.x === 0 && offset.y === 0) {
return this;
}
this._pivot._add(offset);
this.options.rotatePivot = this._pivot.toArray();
}
return this;
}

/**
* 闪烁几何图形,按一定的内部显示和隐藏计数次数。
* @english
Expand Down
4 changes: 3 additions & 1 deletion src/geometry/Rectangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ export class Rectangle extends Polygon {
*/
// @ts-expect-error 确实需要重写父类的属性
setCoordinates(nw: Coordinate | Array<number>) {
this._coordinates = (nw instanceof Coordinate) ? nw : new Coordinate(nw as any);
const newCoordinate = (nw instanceof Coordinate) ? nw : new Coordinate(nw as any);
this._translateRotatePivot(newCoordinate);
this._coordinates = newCoordinate;
if (!this._coordinates || !this.getMap()) {
this.onPositionChanged();
return this;
Expand Down
3 changes: 3 additions & 0 deletions src/geometry/ext/Geometry.Drag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ class GeometryDragHandler extends Handler {
if (!needShadow) {
return;
}
if (!target.options.dragShadow) {
return;
}
this._prepareDragStageLayer();
if (this._shadow) {
this._shadow.remove();
Expand Down
49 changes: 49 additions & 0 deletions test/geometry/GeometrySpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,55 @@ describe('Geometry.main', function () {
test();
});

it('#2381 rotate pivot should change when coordinates change', function (done) {
//rect ellipse etc
const center = map.getCenter();
const rect = new maptalks.Rectangle(center, 100, 70);
const ellipse = new maptalks.Ellipse(center, 100, 70);
const sector = new maptalks.Sector(center, 50, 0, 45);
const geos = [rect, ellipse, sector];
let idx = 0;
const test = () => {
layer.clear();
if (idx === geos.length) {
done();
return;
} else {
const geo = geos[idx];
geo.addTo(layer);


const angle = Math.random() * 180;
const offset = Math.random() / 100;
geo.rotate(angle);

setTimeout(() => {
expect(geo).to.have.property('_pivot');
expect(geo).to.have.property('_angle');
expect(geo._angle).to.eql(angle);

expect(geo.options).to.have.property('rotateAngle');
expect(geo.options.rotateAngle).to.eql(angle);

expect(geo.options).to.have.property('rotatePivot');
expect(geo.options.rotatePivot).to.be.an('array');

const rotatePivot = geo.options.rotatePivot;
geo.translate(new maptalks.Coordinate(offset, offset));

setTimeout(() => {
rotatePivot[0] += offset;
rotatePivot[1] += offset;
expect(geo.options.rotatePivot).to.eql(rotatePivot);
idx++;
test();
}, 100);
}, 100);
}
}
test();
});

});
//测试Geometry的公共方法
function registerGeometryCommonTest(geometry, _context) {
Expand Down

0 comments on commit 7f71f60

Please sign in to comment.