1+ /**
2+ * @module ol/Feature
3+ */
4+ import BaseObject , { getChangeEventType } from './Object.js' ;
5+ import EventType from './events/EventType.js' ;
6+ import { assert } from './asserts.js' ;
7+ import { listen , unlistenByKey } from './events.js' ;
8+
9+ /**
10+ * @typedef {typeof Feature|typeof import("./render/Feature.js").default } FeatureClass
11+ */
12+
13+ /**
14+ * @typedef {Feature|import("./render/Feature.js").default } FeatureLike
15+ */
16+
17+ /**
18+ * @classdesc
19+ * A vector object for geographic features with a geometry and other
20+ * attribute properties, similar to the features in vector file formats like
21+ * GeoJSON.
22+ *
23+ * Features can be styled individually with `setStyle`; otherwise they use the
24+ * style of their vector layer.
25+ *
26+ * Note that attribute properties are set as {@link module:ol/Object} properties on
27+ * the feature object, so they are observable, and have get/set accessors.
28+ *
29+ * Typically, a feature has a single geometry property. You can set the
30+ * geometry using the `setGeometry` method and get it with `getGeometry`.
31+ * It is possible to store more than one geometry on a feature using attribute
32+ * properties. By default, the geometry used for rendering is identified by
33+ * the property name `geometry`. If you want to use another geometry property
34+ * for rendering, use the `setGeometryName` method to change the attribute
35+ * property associated with the geometry for the feature. For example:
36+ *
37+ * ```js
38+ *
39+ * import Feature from 'ol/Feature';
40+ * import Polygon from 'ol/geom/Polygon';
41+ * import Point from 'ol/geom/Point';
42+ *
43+ * var feature = new Feature({
44+ * geometry: new Polygon(polyCoords),
45+ * labelPoint: new Point(labelCoords),
46+ * name: 'My Polygon'
47+ * });
48+ *
49+ * // get the polygon geometry
50+ * var poly = feature.getGeometry();
51+ *
52+ * // Render the feature as a point using the coordinates from labelPoint
53+ * feature.setGeometryName('labelPoint');
54+ *
55+ * // get the point geometry
56+ * var point = feature.getGeometry();
57+ * ```
58+ *
59+ * @api
60+ * @template {import("./geom/Geometry.js").default} Geometry
61+ */
62+ class Feature extends BaseObject {
63+ /**
64+ * @param {Geometry|Object<string, *>= } opt_geometryOrProperties
65+ * You may pass a Geometry object directly, or an object literal containing
66+ * properties. If you pass an object literal, you may include a Geometry
67+ * associated with a `geometry` key.
68+ */
69+ constructor ( opt_geometryOrProperties ) {
70+ super ( ) ;
71+
72+ /**
73+ * @private
74+ * @type {number|string|undefined }
75+ */
76+ this . id_ = undefined ;
77+
78+ /**
79+ * @type {string }
80+ * @private
81+ */
82+ this . geometryName_ = 'geometry' ;
83+
84+ /**
85+ * User provided style.
86+ * @private
87+ * @type {import("./style/Style.js").StyleLike }
88+ */
89+ this . style_ = null ;
90+
91+ /**
92+ * @private
93+ * @type {import("./style/Style.js").StyleFunction|undefined }
94+ */
95+ this . styleFunction_ = undefined ;
96+
97+ /**
98+ * @private
99+ * @type {?import("./events.js").EventsKey }
100+ */
101+ this . geometryChangeKey_ = null ;
102+
103+ this . addEventListener (
104+ getChangeEventType ( this . geometryName_ ) ,
105+ this . handleGeometryChanged_
106+ ) ;
107+
108+ if ( opt_geometryOrProperties ) {
109+ if (
110+ typeof (
111+ /** @type {? } */ ( opt_geometryOrProperties ) . getSimplifiedGeometry
112+ ) === 'function'
113+ ) {
114+ const geometry = /** @type {Geometry } */ ( opt_geometryOrProperties ) ;
115+ this . setGeometry ( geometry ) ;
116+ } else {
117+ /** @type {Object<string, *> } */
118+ const properties = opt_geometryOrProperties ;
119+ this . setProperties ( properties ) ;
120+ }
121+ }
122+ }
123+
124+ /**
125+ * Clone this feature. If the original feature has a geometry it
126+ * is also cloned. The feature id is not set in the clone.
127+ * @return {Feature } The clone.
128+ * @api
129+ */
130+ clone ( ) {
131+ const clone = new Feature (
132+ this . hasProperties ( ) ? this . getProperties ( ) : null
133+ ) ;
134+ clone . setGeometryName ( this . getGeometryName ( ) ) ;
135+ const geometry = this . getGeometry ( ) ;
136+ if ( geometry ) {
137+ clone . setGeometry ( geometry . clone ( ) ) ;
138+ }
139+ const style = this . getStyle ( ) ;
140+ if ( style ) {
141+ clone . setStyle ( style ) ;
142+ }
143+ return clone ;
144+ }
145+
146+ /**
147+ * Get the feature's default geometry. A feature may have any number of named
148+ * geometries. The "default" geometry (the one that is rendered by default) is
149+ * set when calling {@link module:ol/Feature~Feature#setGeometry}.
150+ * @return {Geometry|undefined } The default geometry for the feature.
151+ * @api
152+ * @observable
153+ */
154+ getGeometry ( ) {
155+ return /** @type {Geometry|undefined } */ ( this . get ( this . geometryName_ ) ) ;
156+ }
157+
158+ /**
159+ * Get the feature identifier. This is a stable identifier for the feature and
160+ * is either set when reading data from a remote source or set explicitly by
161+ * calling {@link module:ol/Feature~Feature#setId}.
162+ * @return {number|string|undefined } Id.
163+ * @api
164+ */
165+ getId ( ) {
166+ return this . id_ ;
167+ }
168+
169+ /**
170+ * Get the name of the feature's default geometry. By default, the default
171+ * geometry is named `geometry`.
172+ * @return {string } Get the property name associated with the default geometry
173+ * for this feature.
174+ * @api
175+ */
176+ getGeometryName ( ) {
177+ return this . geometryName_ ;
178+ }
179+
180+ /**
181+ * Get the feature's style. Will return what was provided to the
182+ * {@link module:ol/Feature~Feature#setStyle} method.
183+ * @return {import("./style/Style.js").StyleLike|undefined } The feature style.
184+ * @api
185+ */
186+ getStyle ( ) {
187+ return this . style_ ;
188+ }
189+
190+ /**
191+ * Get the feature's style function.
192+ * @return {import("./style/Style.js").StyleFunction|undefined } Return a function
193+ * representing the current style of this feature.
194+ * @api
195+ */
196+ getStyleFunction ( ) {
197+ return this . styleFunction_ ;
198+ }
199+
200+ /**
201+ * @private
202+ */
203+ handleGeometryChange_ ( ) {
204+ this . changed ( ) ;
205+ }
206+
207+ /**
208+ * @private
209+ */
210+ handleGeometryChanged_ ( ) {
211+ if ( this . geometryChangeKey_ ) {
212+ unlistenByKey ( this . geometryChangeKey_ ) ;
213+ this . geometryChangeKey_ = null ;
214+ }
215+ const geometry = this . getGeometry ( ) ;
216+ if ( geometry ) {
217+ this . geometryChangeKey_ = listen (
218+ geometry ,
219+ EventType . CHANGE ,
220+ this . handleGeometryChange_ ,
221+ this
222+ ) ;
223+ }
224+ this . changed ( ) ;
225+ }
226+
227+ /**
228+ * Set the default geometry for the feature. This will update the property
229+ * with the name returned by {@link module:ol/Feature~Feature#getGeometryName}.
230+ * @param {Geometry|undefined } geometry The new geometry.
231+ * @api
232+ * @observable
233+ */
234+ setGeometry ( geometry ) {
235+ this . set ( this . geometryName_ , geometry ) ;
236+ }
237+
238+ /**
239+ * Set the style for the feature to override the layer style. This can be a
240+ * single style object, an array of styles, or a function that takes a
241+ * resolution and returns an array of styles. To unset the feature style, call
242+ * `setStyle()` without arguments or a falsey value.
243+ * @param {import("./style/Style.js").StyleLike= } opt_style Style for this feature.
244+ * @api
245+ * @fires module:ol/events/Event~BaseEvent#event:change
246+ */
247+ setStyle ( opt_style ) {
248+ this . style_ = opt_style ;
249+ this . styleFunction_ = ! opt_style
250+ ? undefined
251+ : createStyleFunction ( opt_style ) ;
252+ this . changed ( ) ;
253+ }
254+
255+ /**
256+ * Set the feature id. The feature id is considered stable and may be used when
257+ * requesting features or comparing identifiers returned from a remote source.
258+ * The feature id can be used with the
259+ * {@link module:ol/source/Vector~VectorSource#getFeatureById} method.
260+ * @param {number|string|undefined } id The feature id.
261+ * @api
262+ * @fires module:ol/events/Event~BaseEvent#event:change
263+ */
264+ setId ( id ) {
265+ this . id_ = id ;
266+ this . changed ( ) ;
267+ }
268+
269+ /**
270+ * Set the property name to be used when getting the feature's default geometry.
271+ * When calling {@link module:ol/Feature~Feature#getGeometry}, the value of the property with
272+ * this name will be returned.
273+ * @param {string } name The property name of the default geometry.
274+ * @api
275+ */
276+ setGeometryName ( name ) {
277+ this . removeEventListener (
278+ getChangeEventType ( this . geometryName_ ) ,
279+ this . handleGeometryChanged_
280+ ) ;
281+ this . geometryName_ = name ;
282+ this . addEventListener (
283+ getChangeEventType ( this . geometryName_ ) ,
284+ this . handleGeometryChanged_
285+ ) ;
286+ this . handleGeometryChanged_ ( ) ;
287+ }
288+ }
289+
290+ /**
291+ * Convert the provided object into a feature style function. Functions passed
292+ * through unchanged. Arrays of Style or single style objects wrapped
293+ * in a new feature style function.
294+ * @param {!import("./style/Style.js").StyleFunction|!Array<import("./style/Style.js").default>|!import("./style/Style.js").default } obj
295+ * A feature style function, a single style, or an array of styles.
296+ * @return {import("./style/Style.js").StyleFunction } A style function.
297+ */
298+ export function createStyleFunction ( obj ) {
299+ if ( typeof obj === 'function' ) {
300+ return obj ;
301+ } else {
302+ /**
303+ * @type {Array<import("./style/Style.js").default> }
304+ */
305+ let styles ;
306+ if ( Array . isArray ( obj ) ) {
307+ styles = obj ;
308+ } else {
309+ assert ( typeof ( /** @type {? } */ ( obj ) . getZIndex ) === 'function' , 41 ) ; // Expected an `import("./style/Style.js").Style` or an array of `import("./style/Style.js").Style`
310+ const style = /** @type {import("./style/Style.js").default } */ ( obj ) ;
311+ styles = [ style ] ;
312+ }
313+ return function ( ) {
314+ return styles ;
315+ } ;
316+ }
317+ }
318+ export default Feature ;
0 commit comments