Skip to content

Commit f2bf791

Browse files
HarelMclaude
andauthored
feat!: camera composition instead of inheritance (#7800)
* Use classes for all the events. * Update changelog * Fix comments. * Update bundle size * More event changes * Update changelog * Make evented generic to allow spcifying the event types. * Improve imports, make evented abstract. * Remove string from event registration. * Remvoe dead event code. * Fix render test typecheck. * Fix docs generation * Refactor: Map composes Camera instead of extending it Major architectural change moving from inheritance to composition: - Map now extends Evented<MapEventType> instead of Camera - Map has a _camera property containing a Camera instance - Camera is now a concrete class (was abstract) - All camera-related state moved to Camera class - Handlers initialized on Camera instance - TransformProvider now receives Camera directly - Dependency injection for handlers in handler constructors This reduces coupling between Map and Camera while maintaining the same public API. Camera is now a more self-contained component. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Fix: pass allowGestures parameter in Camera.stop() The public stop() method was accepting the allowGestures parameter but not passing it to _stop(), causing handlers to be reset when they shouldn't be. This caused dragend and other end events to fire prematurely. Fixes: 41 test failures in drag_pan, drag_rotate, and other handlers. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Restore CHANGELOG.md with complete version history The composition refactoring commit accidentally wiped most of the CHANGELOG content. Restored all versions from 6.0.0-7 onwards and updated the main section with notes about the composition refactoring and Camera.stop() fix. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Update CHANGELOG with camera composition refactoring details Added Camera composition feature note and Camera.stop() bugfix to main section. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Update chagelog * Remove unwanted getters and setters. * More changes to file to reduce decopling. * Remove reference to camera in draw method. * Update bundle size. * Improve test. * Improve public API and reduce breaking changes. * Fix lint * Fix changelog * Update comments to avoid showing transform in the docs. * Fix out-of-date comment * Remove transform getter. * Move getMatrixForModel into the example code. * Remove the `getTerrain` callback. * TransformProvider only needs the camera now. * Fix lint, update changelog --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 7f6b95c commit f2bf791

44 files changed

Lines changed: 1357 additions & 1329 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## main
22
### ✨ Features and improvements
3+
- ⚠️ `Map` now composes a `Camera` instead of extending it (`Map` extends `Evented` directly and forwards the camera API). The internal `map.transform` was removed — use map's public API instead or open a PR if you need something that's not exposed. Removed the internal `transform.getMatrixForModel` helper ([#7800](https://github.com/maplibre/maplibre-gl-js/pull/7800)) (by [@HarelM](https://github.com/HarelM))
34
- _...Add new stuff here..._
45

56
### 🐞 Bug fixes

src/geo/projection/globe_transform.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,6 @@ export class GlobeTransform implements ITransform {
448448
return this._verticalPerspectiveTransform.getRayDirectionFromPixel(p);
449449
}
450450

451-
getMatrixForModel(location: LngLatLike, altitude?: number): mat4 {
452-
return this.currentTransform.getMatrixForModel(location, altitude);
453-
}
454-
455451
getProjectionDataForCustomLayer(applyGlobeMatrix: boolean = true): CustomLayerProjectionData {
456452
const mercatorData = this._mercatorTransform.getProjectionDataForCustomLayer(applyGlobeMatrix);
457453

src/geo/projection/mercator_transform.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {LngLat, type LngLatLike} from '../lng_lat.ts';
22
import {MercatorCoordinate, mercatorXfromLng, mercatorYfromLat, mercatorZfromAltitude} from '../mercator_coordinate.ts';
33
import Point from '@mapbox/point-geometry';
4-
import {wrap, clamp, createIdentityMat4f64, createMat4f64, degreesToRadians, createIdentityMat4f32, zoomScale, scaleZoom, type Mat4f32, type Mat4f64} from '../../util/util.ts';
4+
import {wrap, clamp, createMat4f64, degreesToRadians, createIdentityMat4f32, zoomScale, scaleZoom, type Mat4f32, type Mat4f64} from '../../util/util.ts';
55
import {type mat2, mat4, vec3, vec4} from 'gl-matrix';
66
import {UnwrappedTileID, OverscaledTileID, type CanonicalTileID, calculateTileKey} from '../../tile/tile_id.ts';
77
import {interpolates} from '@maplibre/maplibre-gl-style-spec';
@@ -801,21 +801,6 @@ export class MercatorTransform implements ITransform {
801801
}
802802
}
803803

804-
getMatrixForModel(location: LngLatLike, altitude?: number): mat4 {
805-
const modelAsMercatorCoordinate = MercatorCoordinate.fromLngLat(
806-
location,
807-
altitude
808-
);
809-
const scale = modelAsMercatorCoordinate.meterInMercatorCoordinateUnits();
810-
811-
const m = createIdentityMat4f64();
812-
mat4.translate(m, m, [modelAsMercatorCoordinate.x, modelAsMercatorCoordinate.y, modelAsMercatorCoordinate.z]);
813-
mat4.rotateZ(m, m, Math.PI);
814-
mat4.rotateX(m, m, Math.PI / 2);
815-
mat4.scale(m, m, [-scale, scale, scale]);
816-
return m;
817-
}
818-
819804
getProjectionDataForCustomLayer(applyGlobeMatrix: boolean = true): CustomLayerProjectionData {
820805
const tileID = new OverscaledTileID(0, 0, 0, 0, 0);
821806
const rendererProjectionData = this.getProjectionData({overscaledTileID: tileID, applyGlobeMatrix});

src/geo/projection/vertical_perspective_transform.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -978,19 +978,6 @@ export class VerticalPerspectiveTransform implements ITransform {
978978
return sphereSurfacePointToCoordinates(closestOnHorizon);
979979
}
980980

981-
getMatrixForModel(location: LngLatLike, altitude?: number): mat4 {
982-
const lnglat = LngLat.convert(location);
983-
const scale = 1.0 / earthRadius;
984-
985-
const m = createIdentityMat4f64();
986-
mat4.rotateY(m, m, lnglat.lng / 180.0 * Math.PI);
987-
mat4.rotateX(m, m, -lnglat.lat / 180.0 * Math.PI);
988-
mat4.translate(m, m, [0, 0, 1 + altitude / earthRadius]);
989-
mat4.rotateX(m, m, Math.PI * 0.5);
990-
mat4.scale(m, m, [scale, scale, scale]);
991-
return m;
992-
}
993-
994981
getProjectionDataForCustomLayer(applyGlobeMatrix: boolean = true): CustomLayerProjectionData {
995982
const globeData = this.getProjectionData({overscaledTileID: new OverscaledTileID(0, 0, 0, 0, 0), applyGlobeMatrix});
996983
globeData.tileMercatorCoords = [0, 0, 1, 1];

src/geo/transform_interface.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -493,15 +493,6 @@ export interface IReadonlyTransform extends ITransformGetters {
493493
*/
494494
projectTileCoordinates(x: number, y: number, unwrappedTileID: UnwrappedTileID, getElevation: (x: number, y: number) => number): PointProjection;
495495

496-
/**
497-
* Returns a matrix that will place, rotate and scale a model to display at the given location and altitude
498-
* while also being projected by the custom layer matrix.
499-
* This function is intended to be called from custom layers.
500-
* @param location - Location of the model.
501-
* @param altitude - Altitude of the model. May be undefined.
502-
*/
503-
getMatrixForModel(location: LngLatLike, altitude?: number): mat4;
504-
505496
/**
506497
* Return projection data such that coordinates in mercator projection in range 0..1 will get projected to the map correctly.
507498
*/

src/style/style.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1764,7 +1764,7 @@ export class Style extends Evented<MapEventType> {
17641764
}
17651765

17661766
_setProjectionInternal(name: ProjectionSpecification['type']): void {
1767-
const projectionObjects = createProjectionFromName(name, this.map.transformConstrain);
1767+
const projectionObjects = createProjectionFromName(name, this.map._camera?.transform.constrainOverride);
17681768
this.projection = projectionObjects.projection;
17691769
this.map.migrateProjection(projectionObjects.transform, projectionObjects.cameraHelper);
17701770
for (const key in this.tileManagers) {

src/style/style_layer/custom_style_layer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export type CustomRenderMethodInput = {
130130
* For more details of this object's internals, see its doc comments in `src/geo/projection/projection_data.ts`.
131131
*
132132
* These uniforms are set so that `projectTile` in shader accepts a vec2 in range 0..1 in web mercator coordinates.
133-
* Use `map.transform.getProjectionData({overscaledTileID: tileID})` to get uniforms for a given tile and pass vec2 in tile-local range 0..EXTENT instead.
133+
* Use `getProjectionData({overscaledTileID: tileID})` to get uniforms for a given tile and pass vec2 in tile-local range 0..EXTENT instead.
134134
*
135135
* For projection 3D features, use `projectTileFor3D` in the shader.
136136
*

0 commit comments

Comments
 (0)