---
title: ThreeJS Layer
source: https://vjmap.com/en/guide/threejs.html
---

# ThreeJS Layer


::: warning Notice!!!
The `vjthree` in the documentation below is deprecated. For ThreeJS 3D layer overlay, please use the latest [Vijmap 3D Library](https://vjmap.com/map3d/) https://vjmap.com/map3d/
:::


The ThreeJS layer is provided as a plugin.

Can be loaded via 
```
npm  intall vjthree

import { } from 'vjthree'
// vjthree and THREE objects will be exposed as window globals
```

Or load via 
```js
vjmap.addScript([{
    src: "js/plugins/vjthree.min.js"
},{
    src: "js/plugins/vjthree.min.css"
}])
```
to load its script.

::: tip Note
vjthree and THREE objects will be exposed as window global variables
:::

### Getting Started

```js
if (typeof vjThree !== "object") {
    // If the environment is not available
    await vjmap.addScript([{
        src: "js/plugins/vjthree.min.js"
    },{
        src: "js/plugins/vjthree.min.css"
    }])
}
const threeContext = map.createThreeJsContext({
    defaultLights: true
});

const lineOptions = {
    geometry: line,
    color: 0xff0000
}

let lineMesh = threeContext.line(lineOptions);
threeContext.add(lineMesh);

map.addLayer(new vjmap.ThreeLayer({context: threeContext}));
```

- - -


#### createThreeJsContext Options

```js
const threeContext = map.createThreeJsContext(options);
```

The `options` parameter is optional and can include the following values:

| Option | Required | Default | Type | Description                                                                                |
|-----------|----------|---------|--------|----------------------------------------------------------------------------------------------|
| `defaultLights`    | no       | false      | boolean | Whether to add default lighting to the scene. Without lighting, most objects will render as black |
| `realSunlight`    | no       | false      | boolean | Sets simulated sunlight based on map center (`map.getCenter`) and local date/time (`new Date()`). Can be updated via `threeContext.setSunlight`. Uses suncalc module internally. |
| `realSunlightHelper`    | no       | false      | boolean | Whether to show the light helper when `realSunlight` is true. |
| `passiveRendering`     | no       | true   | boolean  | Line color. Unlike other objects, this color is rendered exactly as specified on screen, independent of scene lighting |
| `enableSelectingFeatures`     | no       | false   | boolean  | Enable mouse hover and selection for fill-extrusion features. Triggers event [`SelectedFeatureChange`](#SelectedFeatureChange) |
| `enableSelectingObjects`     | no       | false   | boolean  | Enable mouse hover and selection for 3D objects. Triggers event [`SelectedChange`](#SelectedChange). Sets `options.bbox` for created objects.|
| `enableDraggingObjects`     | no       | false   | boolean  | Enable dragging 3D objects. Triggers event [`ObjectDragged`](#ObjectDragged) where `draggedAction = 'translate'` or `draggedAction = 'altitude'` |
| `enableRotatingObjects`     | no       | false   | boolean  | Enable rotating 3D objects. Triggers event [`ObjectDragged`](#ObjectDragged) where `draggedAction = 'rotate'`|
| `enableToltips`     | no       | false   | boolean  | Enable default tooltips for fill-extrusion features and 3D objects|
| `multiLayer`     | no       | false   | boolean  | Enable multi-layer pages with an internal default layer to manage [`threeContext.update`](#update) calls  |
| `orthographic`     | no       | false   | boolean  | Use `THREE.OrthographicCamera` |
| `fov`     | no       | threeContextConstants.FOV_DEGREES | number | FOV for default [`THREE.PerspectiveCamera`](https://threejs.org/docs/index.html#api/en/cameras/PerspectiveCamera). Invalid when `orthographic: true`  |
| `sky`    | no       | false      | boolean | Sets built-in atmosphere layer. Auto-updates when `realSunlight` is true, or can be updated via `threeContext.updateSunSky(threeContext.getSunSky())`. |
| `terrain`    | no       | false    | boolean  | Sets built-in terrain layer. Auto-updates when `realSunlight` is true, or can be updated via `threeContext.updateSunSky(threeContext.getSunSky())`. |

- - -

### Loading 3D Models

3D models can be loaded from external files in different formats (OBJ/MTL, GLTF/GLB, FBX, DAE). After loading and adding to threeContext, objects support methods, interactions, events, and animations.

Objects loaded and added to threeContext can be **selectable**, **draggable**, and **rotatable** (on z-axis) when [`enableSelectingObjects`](#enableSelectingObjects), [`enableDraggingObjects`](#enableDraggingObjects), and [`enableRotatingObjects`](#enableRotatingObjects) are set to `true`.

- To **drag** an object: select it, then hold **SHIFT** and move the mouse to change lnglat position, or hold **CTRL** to change altitude.
- To **rotate** an object: select it, then hold **ALT** and move the mouse. The object rotates around its defined center.

When [`threeContext.enableTooltips`](#enableTooltips) is true, all 3D objects (including fill-extrusion extrusions) show tooltips.

- - -

### Methods


#### add
```js
threeContext.add(obj [, layerId, sourceId])
```
Adds an object to the threeContext scene. It is appended to `threeContext.world.children`.

<br>


#### clear
```js
async threeContext.clear([layerId, dispose])
```
Removes all children from `threeContext.world`. If `layerId` is provided, only that layer is affected. If `true` is passed as the second parameter, it also calls `obj.dispose` to release resources.

<br>

#### createSkyLayer
```js
threeContext.createSkyLayer()
```
Creates a new sky atmosphere layer, used internally by `threeContext.sky`.

<br>

#### createTerrainLayer
```js
threeContext.createTerrainLayer()
```
Creates a new terrain layer, used internally by `threeContext.terrain`.

<br>


#### defaultLights
```js
threeContext.defaultLights()
```
Creates default lighting for the threeContext `scene`. Creates `THREE.AmbientLight` and two `THREE.DirectionalLight` instances. These can be overridden by adding custom lights to the scene.

<br>

#### dispose
```js
threeContext.dispose() : Promise (async)
```
Call `dispose` when the threeContext instance is no longer needed, or before navigating away from a page that uses it, to avoid **memory leaks** from Map and Three.js internals.

This method disposes all Three.js objects, geometries, materials, textures, and Map resources including `WebGLRenderingContext` and the threeContext instance itself.

After calling this method, the threeContext and Map instances are fully released. Use only when navigating away from the page.

<br>

#### findParent3DObject
```js
threeContext.findParent3DObject(mesh) : Object3D
```
Finds the parent Object3D in the threeContext scene from a mesh. Used with `threeContext.queryRenderedFeatures`, which returns [`THREE.Raycaster`](https://threejs.org/docs/#api/en/core/Raycaster) intersection results.

<br>


#### getFeatureCenter
```js
threeContext.getFeatureCenter(feature, model, level): lnglat
```
Computes the center of a feature geometry in meters, including altitude. Supports GeoJson features with or without loaded 3D models. Used for fill-extrusion and point features.

<br>


#### getObjectHeightOnFloor
```js
threeContext.getObjectHeightOnFloor(feature, obj, level) : number
```
Computes the height of a GeoJson feature in meters, with or without a loaded 3D model. Used for fill-extrusion and point features.
<br>

#### getSunPosition
```js
threeContext.getSunPosition(date, coords)
```
Gets sun position (azimuth, elevation) from the suncalc.js module for the given date, time, lng, and lat.

<br>

#### getSunSky
```js
threeContext.getSunSky(date, sunPos)
```
Gets sun sky layer position [azimuth, elevation] from suncalc.js. Uses `date` if provided, otherwise `new Date()`. Uses `sunPos` if provided, otherwise computes via `threeContext.getSunPosition` with `map.getCenter()`.
<br>


#### getSunTimes
```js
threeContext.getSunTimes(date, coords)
```
Gets sun times (sunrise, sunset, etc.) from suncalc.js for the given date, time, lng, lat, and alt. Used to adjust map style by day/night.
Returns an object with date properties for each phase.


#### loadObj
```js
async threeContext.loadObj(options, callback(obj));
```
Loads 3D models from external files in various formats. Caches the first loaded object per URL for reuse via `obj.duplicate`. This method is async and passes the loaded object to the callback.

Uses [THREE.OBJLoader](https://github.com/mrdoob/three.js/blob/dev/examples/jsm/loaders/OBJLoader.js), [THREE.FBXLoader](https://github.com/mrdoob/three.js/blob/dev/examples/jsm/loaders/FBXLoader.js), [THREE.GLTFLoader](https://github.com/mrdoob/three.js/blob/dev/examples/jsm/loaders/GLTFLoader.js), or [THREE.ColladaLoader](https://github.com/mrdoob/three.js/blob/dev/examples/jsm/loaders/ColladaLoader.js). [THREE.FBXLoader](https://github.com/mrdoob/three.js/blob/dev/examples/jsm/loaders/FBXLoader.js) depends on [Zlib](https://github.com/imaya/zlib.js) for compressed FBX files.

| Option | Required | Default | Type | Description                                                                         |
|-----------|----------|---------|--------|----------|
| `type`  | yes       | "mtl"       | string (`"mtl"`, `"gltf"`, `"fbx"`, `"dae"`) | Model format type |
| `obj`  | yes       | NA       | string | URL path to .obj file for OBJ models |
| `mtl`  | no       | NA       | string | URL path to .mtl file for OBJ models |
| `bin`  | no       | NA       | string | URL path to .bin files for GLTF models |
| `units`    | no       | scene      | string (`"scene"` or `"meters"`) | Units for vertex interpretation. Use "meters" for precision. threeContext rescales objects by latitude when using meters. |
| `rotation`     | no       | 0   | number or {x, y, z}  | Rotate object along axes before alignment. Future rotations apply on top. Example: `rotation: {x: 90, y: 0, z: 0}` for 90° on x |
| `scale`     | no       | 1   | number or {x, y, z}  | Scale object along axes. Future scaling applies on top. Example: `scale: {x: 1, y: 1, z: 3}` for 3× height |
| `anchor`     | no       | `bottom-left`   | string  | 3D model anchor point. Values: `top`, `bottom`, `left`, `right`, `center`, `top-left`, `top-right`, `bottom-left`, `bottom-right`. Default `bottom-left`. `auto` uses model-defined anchor. |
| `adjustment`     | no       | 1   | {x, y, z}  | 3D models are often off-center. Provide per-axis units (e.g. `adjustment: {x: 0.5, y: 0.5, z: 0}`) to correct center. |
| `normalize`     | no       | true   | bool  | Normalize highlight values for some 3D models |
| `feature`     | no       | 1   | [*GeoJson*](https://geojson.org/) feature  | GeoJson feature instance: e.g. `height`, `base_height`, `color` |
| `tooltip`     | no       | false   | bool  | Enable or disable tooltip. Defaults to `threeContext.enableTooltips` |
| `bbox`     | no       | false   | bool  | Enable or disable bounding box. Defaults to `threeContext.enableSelectingObjects` |
| `raycasted`     | no       | true   | bool  | Exclude object from raycasting |
| `clone`     | no       | true   | bool  | Clone loaded object by default. `clone: false` uses more memory but may be needed when animation/textures don't clone well. |
| `defaultAnimation`     | no       | 0   | number  | Default animation index. Ignored if animation not present |
| `callback`     | yes       | NA   | function  | Called after load. First argument is the loaded object. Use to configure and add via `threeContext.add()` |



Objects can listen for these events for UI updates. Add them in the `threeContext.loadObj` callback:

```js
	threeContext.loadObj(options, function (model) {

		soldier = model.setCoords(origin);

		soldier.addEventListener('SelectedChange', onSelectedChange, false);
		soldier.addEventListener('Wireframed', onWireframed, false);
		soldier.addEventListener('IsPlayingChanged', onIsPlayingChanged, false);
		soldier.addEventListener('ObjectDragged', onDraggedObject, false);
		soldier.addEventListener('ObjectMouseOver', onObjectMouseOver, false);
		soldier.addEventListener('ObjectMouseOut', onObjectMouseOut, false);

		threeContext.add(soldier);
	})
```

See the `onSelectedChange` example below for using `map.flyTo(options[, eventData])`:

```js
// Method to enable/disable UI buttons.
// This example uses jQuery
// Requires GeoJson feature in threeContext.loadObj(options)
function onSelectedChange(e) {
	let selected = e.detail.selected; // Whether object is selected after event
	$('#deleteButton')[0].disabled = !selected; // Find delete button with jQuery

	// if selected
	if (selected) {
		selectedObject = e.detail; //
		// Fly to selected object
		map.flyTo({
			center: selectedObject.userData.feature.properties.camera,
			zoom: selectedObject.userData.feature.properties.zoom,
			pitch: selectedObject.userData.feature.properties.pitch,
			bearing: selectedObject.userData.feature.properties.bearing
		});
	}
	threeContext.update();
	map.repaint = true;
}
```
<br>

##### 3D Formats and MIME Types
Most 3D formats (.glb, .gltf, .fbx, .dae, ...) are not standard MIME types. Configure your web server to serve these extensions, or downloads may fail with HTTP errors.
<br>
For IIS (ASP.Net), add to web.config under `<system.webServer>`:
```xml
<system.webServer>
	  ...
	  <staticContent>
		  <remove fileExtension=".mtl" />
		  <mimeMap fileExtension=".mtl" mimeType="model/mtl" />
		  <remove fileExtension=".obj" />
		  <mimeMap fileExtension=".obj" mimeType="model/obj" />
		  <remove fileExtension=".glb" />
		  <mimeMap fileExtension=".glb" mimeType="model/gltf-binary" />
		  <remove fileExtension=".gltf" />
		  <mimeMap fileExtension=".gltf" mimeType="model/gltf+json" />
		  <remove fileExtension=".fbx" />
		  <mimeMap fileExtension=".fbx" mimeType="application/octet-stream" />
		  <remove fileExtension=".dae" />
		  <mimeMap fileExtension=".dae" mimeType="application/vnd.oipf.dae.svg+xml" />
	  </staticContent>
</system.webServer>
```
<br/>

For ASP.NET Core, add to `Configure` in `Startup`:
```C#
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    // Set up custom content types - associating file extension to MIME type
    var provider = new FileExtensionContentTypeProvider();
    // Add new mappings
    provider.Mappings[".mtl"] = "model/mtl";
    provider.Mappings[".obj"] = "model/obj";
    provider.Mappings[".glb"] = "model/gltf-binary";
    provider.Mappings[".gltf"] = "model/gltf+json";
    provider.Mappings[".fbx"] = "application/octet-stream";
    provider.Mappings[".dae"] = "application/vnd.oipf.dae.svg+xml";

    app.UseStaticFiles(new StaticFileOptions 
    {
        ContentTypeProvider = provider
    });

    ...
}
```

<br/>

For nginx, add to `http` in nginx.conf:
```
http {
	include /etc/nginx/mime.types;
	types {
		model/mtl mtl;
		model/obj obj;
		model/gltf+json gltf;
		model/gltf-binary glb;
		application/octet-stream fbx;
		application/vnd.oipf.dae.svg+xml dae;
	}
	...
}
```
For Apache, add to mime.types:
```
model/mtl mtl
model/obj obj
model/gltf+json gltf
model/gltf-binary glb
application/octet-stream fbx
application/vnd.oipf.dae.svg+xml dae
```

<br>

#### memory
```js
threeContext.memory() : Object
```
Returns the `memory` member from `THREE.WebGLRenderer.info`.

<br>

#### programs
```js
threeContext.programs() : int
```
Returns the length of the `programs` member from `THREE.WebGLRenderer.info`.

<br>

#### projectToWorld
```js
threeContext.projectToWorld(lnglat) : THREE.Vector3
```
Converts `lnglat` to `THREE.Vector3`. Inverse of `threeContext.unprojectFromWorld`.

<br>

#### queryRenderedFeatures
```js
threeContext.queryRenderedFeatures(point) : Array
```
Uses `THREE.Raycaster` to find objects intersecting the pick ray. Returns an array of threeContext objects sorted by distance. Input is `{x: number, y: number}` in screen coordinates (e.g. `e.point` from Map mouse events).

<br>

#### realSunlight
```js
threeContext.realSunlight([helper = true])
```
Creates simulated sunlight for the scene. Uses suncalc.js and `map.getCenter` + `new Date()`. Calls `threeContext.setSunlight` internally. If `helper` is true, shows a helper.
<br>

#### remove
```js
threeContext.remove(obj)
```
Removes an object from the threeContext scene and `threeContext.world.children`.

<br>

#### removeByName
```js
threeContext.removeByName(name)
```
Removes from the scene and `threeContext.world.children` by searching the object and its children for the first matching name.
<br>

#### removeLayer
```js
threeContext.removeLayer(layerId)
```
Removes a layer from the map, including all 3D objects in the threeContext scene and `threeContext.world.children`.

<br>


#### setLayerHeigthProperty
```js
threeContext.setLayerHeigthProperty(layerId, level) 
```
Sets height for all objects in a layer. Only applies when objects have a GeoJson feature with a "level" property.

<br>

#### setLayerZoomRange
```js
threeContext.setLayerZoomRange(layerId, minZoomLayer, maxZoomLayer)
```
Custom layers use this method instead of minzoom/maxzoom. Sets zoom range and manages 3D object and CSS2D label visibility for the layer.

<br>

#### setLayerZoomVisibility
```js
threeContext.setLayerZoomVisibility(layerId)
```
Sets or resets layer visibility based on current zoom.

<br>

#### setLayoutProperty
```js
threeContext.setLayoutProperty(layerId, name, value)
```
Mirrors `map.setLayoutProperty` for custom layers. Can be used for any layer type.

<br>

#### setObjectsScale
```js
threeContext.setObjectsScale()
```
Scales all `fixedZoom` objects in `threeContext.world.children`.

<br>

#### setStyle
```js
threeContext.setStyle(styleId[, options])
```
Mirrors `map.setStyle` and removes 3D objects from `threeContext.world`. Internally calls `threeContext.clear(true)` to dispose resources.

<br>

#### setSunlight
```js
threeContext.setSunlight(newDate = new Date(), coords)
```
Updates sunlight position from suncalc.js for the given date, time, lng, lat. Uses `map.getCenter` and `new Date()` when not provided.
<br>

#### toggleLayer
```js
threeContext.toggleLayer(layerId, visible) 
```
Toggles layer visibility. Useful for custom layers as a replacement for `map.setLayoutProperty(layerId, 'visibility', visible)`.

<br>


#### update
```js
threeContext.update()
```
One of the most important methods. Calls `THREE.WebGLRenderer.render(scene, camera)`. Required when using `threeContext.loadObj(options, callback(obj))`.

<br>

#### updateLightHelper
```js
threeContext.updateLightHelper()
```
Updates `threeContext.lights.dirLightHelper` position. Call when the light moves to keep the helper correct.

<br>

#### updateSunGround
```js
threeContext.updateSunGround(sunPos)
```
When `threeContext.realSunlight` is true, updates lighting on satellite style (if applied) based on sun elevation.

<br>

#### updateSunSky
```js
threeContext.updateSunSky(sunPos)
```
When `threeContext.sky` is true, updates the sky atmosphere layer with the given sun position.

<br>

#### unprojectFromWorld
```js
threeContext.unprojectFromWorld(Vector3): lnglat
```
Converts `THREE.Vector3` to `lnglat`. Inverse of `threeContext.projectToWorld`.
<br>

#### versions
```js
threeContext.version() : string
```
Returns the threeContext version.
<br>

- - -


### threeContext Properties

In the examples below, the threeContext instance is referred to as "tb".
<br>

#### altitudeStep

```js
threeContext.altitudeStep : Number
```
Step size in meters for vertical dragging. Default 0.1 (10cm).

<br>


#### defaultCursor

```js
threeContext.defaultCursor : string
```
Default cursor for the map canvas container (`this.getCanvasContainer().style.cursor`). Initial value `'default'`.

<br>

#### enableDraggingObjects

```js
threeContext.enableDraggingObjects : Boolean
```
Enables horizontal or vertical dragging of 3D objects. Requires `threeContext.enableSelectingFeatures` to be true. When true and an object is selected: hold [Shift] + mouse to move on x-y; hold [Ctrl] + mouse to move on z. Triggers `ObjectDragged` event:
```js
obj.addEventListener('ObjectDragged', onDraggedObject, false)
```

Does not affect map fill-extrusion layers.

<br>

#### enableRotatingObjects

```js
threeContext.enableRotatingObjects : Boolean
```
Enables rotating 3D objects. Requires `threeContext.enableSelectingFeatures` to be true. When true and an object is selected: hold [Alt] + mouse to rotate around z-axis. Triggers `ObjectDragged` event:
```js
obj.addEventListener('ObjectDragged', onDraggedObject, false)
```

Does not affect map fill-extrusion layers.

<br>

#### enableSelectingFeatures

```js
threeContext.enableSelectingFeatures : Boolean
```
Enables selecting features from fill-extrusion layers. Triggers `SelectedFeatureChange` on select/unselect:
```js
obj.addEventListener('SelectedFeatureChange', onSelectedFeatureChange, false)
```


<br>

#### enableSelectingObjects

```js
threeContext.enableSelectingObjects : Boolean
```
Enables selecting 3D objects created with threeContext. Triggers `SelectedChange` on select/unselect:
```js
obj.addEventListener('SelectedChange', onSelectedChange, false)
```

Does not affect map fill-extrusion layers.

<br>

#### enableTooltips

```js
threeContext.enableTooltips : Boolean
```
Enables tooltips (custom or default) on objects. Requires `threeContext.enableSelectingFeatures` to be true. When true, tooltips show on hover or selection.

<br>

#### fov

```js
threeContext.fov : Number (degrees)
```
Default `threeContextConstants.FOV_DEGREES`. Field of view for the camera. Only applies when `threeContext.orthographic` is false (i.e. when using `THREE.PerspectiveCamera`).



#### gridStep

```js
threeContext.gridStep : Number(integer)
```
Step size for horizontal dragging (decimal precision). Default 6 decimals ≈ 11.1cm. Set to 7 for ≈ 1.1cm. Map FOV minimum is 0.01; 0 is converted to 0.01.

<br>

#### lights
```js
threeContext.lights : Object
```
Set of lights applied to the scene.
- `threeContext.lights.ambientLight` – `THREE.AmbientLight` from `threeContext.defaultLights()`, can be overridden.
- `threeContext.lights.dirLight` – `THREE.DirectionalLight` from `threeContext.defaultLights()` or `threeContext.setSunlight`. Avoid overriding when using `realSunlight`.
- `threeContext.lights.dirLightHelper` – `THREE.DirectionalLightHelper` from `threeContext.setSunlight`.
- `threeContext.lights.hemiLight` – `THREE.HemisphereLight` from `threeContext.setSunlight`.
- `threeContext.lights.pointLight` – Not initialized by default.

<br>

#### multiLayer

```js
threeContext.multiLayer : Boolean
```
Default false. Enables multiple 3D layers with an internal default layer for `threeContext.update` calls. Takes effect on style change via `threeContext.setStyle`. Initialize with `multiLayer: true` if the page may have multiple 3D layers.

<br>

#### orthographic

```js
threeContext.orthographic : Boolean 
```
Default false. Whether to use orthographic camera.

<br>

#### rotationStep

```js
threeContext.rotationStep : Number
```
Step size in degrees for dragging and rotating objects. Default 5.

<br>

#### sky

```js
threeContext.sky: Boolean
```
Default false. Set by init param `sky: true`. Enables built-in atmosphere layer. Auto-updates when `realSunlight` is true, or via `threeContext.updateSunSky(threeContext.getSunSky())`. Setting to false after creation removes the layer.

<br>

#### terrain

```js
threeContext.terrain: Boolean
```
Default false. Set by init param `terrain: true`. Enables built-in terrain layer. Auto-updates when `realSunlight` is true, or via `threeContext.updateSunGround(threeContext.getSunPosition())`. Setting to false after creation removes the layer.

<br>

## Objects

threeContext provides helpers to build various mesh types and 3D models. They use subclasses of `THREE.Object3D`. Objects fall into two categories: **static** (fixed after placement, for background or geographic features, geometry in lnglat) and **dynamic** (positioned by a single lnglat point, geometry in local scene units or from external OBJ files).
<br>

### Static objects

#### Line

```js
threeContext.line(options);
```

Adds a line to the map in 3D space. Color is independent of scene lighting. Uses a custom line shader.

| Option | Required | Default | Type | Description                                                                                |
|-----------|----------|---------|--------|----------------------------------------------------------------------------------------------|
| `geometry`    | yes       | NA      | lineGeometry | Array of lnglat coordinates for the line |
| `color`     | no       | black   | color  | Line color. Rendered exactly as specified, independent of scene lighting |
| `width`     | no       | 1   | number  | Line width in display pixels (not meters or scene units). |
| `opacity`     | no       | 1   | Number  | Line opacity |                                                                       


<br>

### Dynamic objects

#### Extrusion

```js
threeContext.extrusion(options);
```

Adds an extruded shape to the map.

| Option | Required | Default | Type | Description                                                                             |
|-----------|----------|---------|--------|-------|
| `coordinates`    | no       | [[[]]] or Vector2 array  | nested array | GeoJson-style nested array. Geometry as "Polygon" or coordinate array. |
| `geometryOptions`    | no       | {} | Object | Options for `ExtrudeGeometry` |
| `height`    | no       | 100      | Number | Extrusion height. |
| `units`    | no       | `scene`      | string ("scene" or "meters") | Units for vertices. "meters" rescales by latitude. |
| `scale`     | no       | 1   | number or {x, y, z}  | Scale along axes. Future scaling applies on top. Example: `scale: {x: 1, y: 1, z: 3}` |
| `rotation`     | no       | 0   | number or {x, y, z}  | Rotate along axes. Future rotation applies on top. Example: `rotation: {x: 90, y: 0, z: 0}` |
| `materials`     | no       | `THREE.MeshPhongMaterial({ color: 0x660000, side: THREE.DoubleSide })`   | threeMaterial or threeMaterials array  | `THREE.Material` instance or string. |
| `anchor`     | no       | `bottom-left`   | string | Anchor point. Values: top, bottom, left, right, center, top-left, top-right, bottom-left, bottom-right. Default bottom-left. |
| `adjustment`     | no       | 1   | {x, y, z}  | Center offset in normalized units. Example: `adjustment: {x: -0.5, y: -0.5, z: 0}` to shift center. For a cube centered at ground level: `adjustment: {x: -0.5, y: -0.5, z: 0.5}`. |
| `tooltip`     | no       | false   | bool  | Enable tooltip. Defaults to `threeContext.enableTooltips` |
| `bbox`     | no       | false   | bool  | Enable bounding box. Defaults to `threeContext.enableSelectingObjects` |
| `raycasted`     | no       | true   | bool  | Include in raycasting |

<br>


#### Label

```js
threeContext.label(options);
```

Creates an HTML label positioned via `obj.setCoords(coords)` and added with `threeContext.add(obj)`. Uses `THREE.CSS2DRenderer` and `CSS2DObject`.

| Option | Required | Default | Type | Description                                                                              |
|-----------|----------|---------|--------|-------|
| `htmlElement`    | yes       | null      | htmlElement | HTMLElement rendered as `CSS2DObject` |
| `cssClass`    | no       | " label3D"      | string | CSS class for label styling. |
| `alwaysVisible`  | no       | false       | number | Number of width and height segments. Higher = smoother sphere. |
| `topMargin`     | no       | -0.5   | int  | Vertical offset in units (1 = object height). Default -0.5 = vertical center. |
| `feature`     | no       | null   | `GeoJson` feature | GeoJson feature for dynamic positioning. |                                                            

<br>

#### Object3D

```js
threeContext.Object3D(options)
```

Adds any geometry as `THREE.Object3D` or `THREE.Mesh`.

| Option | Required | Default | Type | Description                                                                            |
|-----------|----------|---------|--------|------------|
| `obj`    | yes       | null      | `THREE.Mesh` | Object to enrich with new properties. |
| `units`    | no       | `scene`      | string ("scene" or "meters") | Units for vertices. "meters" rescales by latitude. |
| `anchor`     | no       | `bottom-left`   | string | Anchor point. Values: top, bottom, left, right, center, top-left, top-right, bottom-left, bottom-right. Default bottom-left. |
| `adjustment`     | no       | 1   | {x, y, z}  | Center offset. Example: `adjustment: {x: -0.5, y: -0.5, z: 0}`. For ground-level cube: `adjustment: {x: -0.5, y: -0.5, z: 0.5}`. |
| `tooltip`     | no       | false   | bool  | Enable tooltip. Defaults to `threeContext.enableTooltips` |
| `bbox`     | no       | false   | bool  | Enable bounding box. Defaults to `threeContext.enableSelectingObjects` |
| `raycasted`     | no       | true   | bool  | Include in raycasting |



<br>

#### Sphere

```js
threeContext.sphere(options);
```

Adds a sphere to the map. Uses `THREE.SphereGeometry` and `THREE.Mesh`, wrapped with `Object3D(options)`.

| Option | Required | Default | Type | Description                                                                               |
|-----------|----------|---------|--------|-------|
| `radius`    | no       | 50      | number | Sphere radius. |
| `units`    | no       | `scene`      | string ("scene" or "meters") | Units for vertices. "meters" rescales by latitude. |
| `sides`  | no       | 8       | number | Width and height segments. Higher = smoother. |
| `color`     | no       | black   | color  | Sphere color. |
| `material`     | no       | MeshLambertMaterial   | `THREE.Material` | Material instance or string. |
| `anchor`     | no       | `bottom-left`   | string | Anchor point. Default bottom-left. |
| `adjustment`     | no       | 1   | {x, y, z}  | Center offset. Example: `adjustment: {x: -0.5, y: -0.5, z: 0}`. |
| `tooltip`     | no       | false   | bool  | Enable tooltip. Defaults to `threeContext.enableTooltips` |
| `bbox`     | no       | false   | bool  | Enable bounding box. Defaults to `threeContext.enableSelectingObjects` |
| `raycasted`     | no       | true   | bool  | Include in raycasting |

<br>

#### Tooltip

```js
threeContext.tooltip(options);
```

Creates a browser-like tooltip positioned via `obj.setCoords(coords)` and added with `threeContext.add(obj)`. Uses `THREE.CSS2DRenderer` and `CSS2DObject`.

| Option | Required | Default | Type | Description                                                                             |
|-----------|----------|---------|--------|-------|
| `text`    | yes       | ""      | string | Text rendered as `CSS2DObject` |
| `cssClass`    | no       | "toolTip text-xs"      | string | CSS class for tooltip styling. |
| `mapStyle`     | no       | false   | int  | If true, use same style as Map popup. |                                                                            
| `topMargin`     | no       | 0   | int  | Vertical offset (1 = object height). Default 0 = top. |                                
| `feature`     | no       | null   | `GeoJson` feature | GeoJson feature for dynamic positioning. |                                                                            

<br>

#### Tube

```js
threeContext.tube(options);
```

Extrudes a tube along a line geometry with an equilateral polygon cross-section. Uses custom tube geometry and `Object3D(options)`.

| Option | Required | Default | Type | Description                                                                              |
|-----------|----------|---------|--------|----------|
| `geometry`    | yes       | NA      | lineGeometry | Line coordinates for the tube axis |
| `radius`    | no       | 20      | number | Tube cross-section radius (half of tube width). |
| `sides`  | no       | 8       | number | Faces along the tube. Higher = smoother cylinder. |
| `material`     | no       | MeshLambertMaterial   | threeMaterial  | [THREE.Material](https://github.com/mrdoob/three.js/tree/dev/src/materials). String or instance. |
| `color`     | no       | black   | color  | Tube color. Ignored if material is predefined. |
| `opacity`     | no       | 1   | Number  | Tube opacity |                                                                                                                                                   
| `anchor`     | no       | `bottom-left`   | string | Anchor point. Default bottom-left. |
| `adjustment`     | no       | 1   | {x, y, z}  | Center offset. Example: `adjustment: {x: -0.5, y: -0.5, z: 0}`. |
| `tooltip`     | no       | false   | bool  | Enable tooltip. Defaults to `threeContext.enableTooltips` |
| `bbox`     | no       | false   | bool  | Enable bounding box. Defaults to `threeContext.enableSelectingObjects` |
| `raycasted`     | no       | true   | bool  | Include in raycasting |

<br>

#### mapToWorld

```js
mapToWorld(coords);
```
Convert map geometry coordinates to ThreeJS world coordinates.

#### worldToMap

```js
worldToMap(coords);
```
Convert ThreeJS world coordinates to map geometry coordinates.


#### mapToWorldLength

```js
mapToWorldLength(coords);
```
Convert map geometry length to ThreeJS world coordinate length.

#### worldToMapLength

```js
worldToMapLength(coords);
```
Convert ThreeJS world coordinate length to map geometry length.

#### getWorldSize

```js
getWorldSize();
```
Total length of ThreeJS world coordinates.

#### loadTexture

```js
loadTexture(img, defaultImg);
```
Load texture. Use base64 image. Returns `THREE.Texture` object.



#### coneMesh

Create a quadrangular pyramid

```typescript
/**
 * Create a quadrangular pyramid
 **/
coneMesh(co: GeoPoint, opts?:  {
    size?: number /* Size, default 1024 */
    height?: number /* Height, default 4096 */
    color?: string | number /* Color, default 0xffcc00 */
    animation?: boolean /* Whether to animate, default true */
    animationUpDown?: boolean /* Whether to have up/down animation. Default true if z value exists */
    obj3dOpts?: object /* Object3D options */
}): any
```

Option parameter list:

| Option | Required | Type | Description  |
|-----------|----------|--------|----------|
| `size`    | no    | number | Size, default 1024 |
| `height`    | no    | number | Height, default 4096 |
| `color`    | no    | string, number | Color, default 0xffcc00 |
| `animation`    | no    | boolean | Whether to animate, default true |
| `animationUpDown`    | no    | boolean | Whether to have up/down animation. Default true if z value exists |
| `obj3dOpts`    | no    | object | Object3D options |



#### wall

Create a 3D light wall

```typescript
/**
 * Create a 3D light wall
 **/
wall(pts: GeoPoint[], opts?:  {
    height?: number /* Light wall height, default 10000 */
    flyline?: boolean /* Fly line effect beside light wall, default on */
    repeatX?: number /* Light wall fly line texture X repeat count, default 3 */
    repeatY?: number /* Light wall fly line texture Y repeat count, default 3 */
    offsetX?: number /* Light wall fly line texture X animation offset per frame, default 0.02 */
    offsetY?: number /* Light wall fly line texture Y repeat count, default 0 */
    color1?: string | number /* Light wall fly line color, default 0xffff00 */
    texture1?: string /* Light wall fly line texture image */
    color2?: string | number /* 3D light wall color, default 0x00ffff */
    texture2?: string /* 3D light wall texture image */
    opacity?: number /* 3D light wall opacity, default 0.5 */
    obj3dOpts?: object /* Object3D options */
}): any
```
Option parameter list:

| Option | Required | Type | Description  |
|-----------|----------|--------|----------|
| `height`    | no    | number | Light wall height, default 10000 |
| `flyline`    | no    | boolean | Fly line effect beside light wall, default on |
| `repeatX`    | no    | number | Light wall fly line texture X repeat count, default 3 |
| `repeatY`    | no    | number | Light wall fly line texture Y repeat count, default 3 |
| `offsetX`    | no    | number | Light wall fly line texture X animation offset per frame, default 0.02 |
| `offsetY`    | no    | number | Light wall fly line texture Y repeat count, default 0 |
| `color1`    | no    | string, number | Light wall fly line color, default 0xffff00 |
| `texture1`    | no    | string | Light wall fly line texture image |
| `color2`    | no    | string, number | 3D light wall color, default 0x00ffff |
| `texture2`    | no    | string | 3D light wall texture image |
| `opacity`    | no    | number | 3D light wall opacity, default 0.5 |
| `obj3dOpts`    | no    | object | Object3D options |





#### wave

Create a wave ring

```typescript
 /**
 * Create a wave ring
 **/
wave(co: GeoPoint, opts?:  {
    size?: number /* Size, default 3413 */
    color?: string | number /* Color, default 0x22ffcc */
    texture?: string /* Wave ring texture image */
    speed?: number /* Speed, default 0.4 */
}): any
```
Option parameter list:

| Option | Required | Type | Description  |
|-----------|----------|--------|----------|
| `size`    | no    | number | Size, default 3413 |
| `color`    | no    | string, number | Color, default 0x22ffcc |
| `texture`    | no    | string | Wave ring texture image |
| `speed`    | no    | number | Speed, default 0.4 |






#### radialGradient

Create a radial gradient sphere

```typescript
  /**
 * Create a radial gradient sphere
 **/
radialGradient(co: GeoPoint, opts?:  {
    size?: number /* Size, default 10240 */
    color?: string | number | any/* Color, default new THREE.Vector3(0.0,1.0,1.0) */
    speed?: number /* Speed, default 0.02 */
}): any
```
Option parameter list:

| Option | Required | Type | Description  |
|-----------|----------|--------|----------|
| `size`    | no    | number | Size, default 10240 |
| `color`    | no    | string, number | Color, default new THREE.Vector3(0.0,1.0,1.0) |
| `speed`    | no    | number | Speed, default 0.02 |





#### radar

Create a scan radar

```typescript
/**
 * Create a scan radar
 **/
radar(co: GeoPoint, opts?:  {
    size?: number /* Size, default 20480 */
    color1?: string | number /* Radar scan color, default 0x00ffff */
    texture1: string /* Radar scan texture image */
    color2?: string | number /* Radar scale color, default 0x00cccc */
    texture2: string /* Radar scale texture image */
    speed?: number /* Speed, default 0.02 */
}): any
```
Option parameter list:

| Option | Required | Type | Description  |
|-----------|----------|--------|----------|
| `size`    | no    | number | Size, default 20480 |
| `color1`    | no    | string, number | Radar scan color, default 0x00ffff |
| `texture1`    | yes    | string | Radar scan texture image |
| `color2`    | no    | string, number | Radar scale color, default 0x00cccc |
| `texture2`    | yes    | string | Radar scale texture image |
| `speed`    | no    | number | Speed, default 0.02 |



#### waveWall

Create a wave wall

```typescript
 /**
 * Create a wave wall
 **/
waveWall(co: GeoPoint, opts?:  {
    size?: number /* Size, default 10240 */
    height?: number /* Height, default 2000 */
    color?: string | number /* Color, default 0x00ffff */
    texture?: string /* Texture image */
    speed?: number /* Speed, default 0.1 */
    opacity?: number /* Opacity, default 0.5 */
}): any
```
Option parameter list:

| Option | Required | Type | Description  |
|-----------|----------|--------|----------|
| `size`    | no    | number | Size, default 10240 |
| `height`    | no    | number | Height, default 2000 |
| `color`    | no    | string, number | Color, default 0x00ffff |
| `texture`    | no    | string | Texture image |
| `speed`    | no    | number | Speed, default 0.1 |
| `opacity`    | no    | number | Opacity, default 0.5 |



#### flyline

Create a fly line

```typescript
 /**
 * Create a fly line
 **/
flyline(opts:  {
    source: GeoPoint, /* Start point */
    target: GeoPoint /* End point */
    height?: number /* Height at interpolated midpoint */
    size?: number /* Particle size, default 3 */
    color: string | number /* Color */
    color2?: string | number /* Set for gradient color */
    count?: number /* Total particle count, default 1000 */
    range?: number /* Particle display range, default 500 */
    opacity?: number /* Opacity, default 1.0 */
    speed?: number /* Speed, default 1 */
}): any
```
Option parameter list:

| Option | Required | Type | Description  |
|-----------|----------|--------|----------|
| `source`    | yes    | GeoPoint | Start point |
| `target`    | yes    | GeoPoint | End point |
| `size`    | no    | number | Particle size, default 30 |
| `height`    | no    | number | Height at interpolated midpoint |
| `color`    | yes    | string, number | Color |
| `color2`    | no    | string, number | Set for gradient color |
| `count`    | no    | number | Total particle count, default 1000 |
| `range`    | no    | number | Particle display range, default 500 |
| `speed`    | no    | number | Speed, default 1 |
| `opacity`    | no    | number | Opacity, default 1.0 |
   
        
---


### Object Methods


<br>

#### addCSS2D
```js
obj.addCSS2D(element, objName [, center = obj.anchor, height = 0])
```
Generic method to render a DOM HTMLElement on screen relative to the containing object. `objName` identifies the object and may replace a previous one. `center` is the label position (default `obj.anchor`). `height` is vertical offset: 0 = bottom, 1 = top (default 0).


<br>

#### addHelp
```js
obj.addHelp(helpText [,objName = helpName, mapSyle = false, center = obj.anchor, height = 0])
```
Creates a browser-like help tooltip accessible via `obj.help`. Visible only when dragging for translate, rotate, or altitude. If `mapStyle` is true, uses Map popup style. `center` defaults to `obj.anchor`. `height`: 0 = bottom, 1 = top (default 0).



<br>

#### addLabel
```js
obj.addLabel(HTMLElement [, visible, center = obj.anchor, height = 0.5])
```
Renders a DOM HTMLElement on screen relative to the containing object. If `visible` is true, the label is always visible; otherwise it shows on mouse over. `center` defaults to `obj.anchor`. `height`: 0 = bottom, 1 = top (default 0.5 = middle).

<br>

#### addTooltip
```js
obj.addTooltip(tooltipText [, mapSyle = false, center = obj.anchor, custom = true, height = 1])
```
Creates a browser-like tooltip for the object. If `mapStyle` is true, uses Map popup style. `center` defaults to `obj.anchor`. `custom` is true for user-added tooltips (not auto-generated). `height`: 0 = bottom, 1 = top (default 1).


<br>

#### copyAnchor
```js
obj.copyAnchor(anchor)
```
Copies the anchor property used internally by `obj.duplicate`.

<br>

#### drawBoundingBox
```js
obj.drawBoundingBox
```
Creates two bounding boxes with [`THREE.Box3Helper`](https://threejs.org/docs/#api/en/helpers/BoxHelper). The first is assigned to `obj.boundingBox`, the second to `obj.boundingBoxShadow`.

<br>

#### drawLabelHTML
```js
obj.drawLabelHTML(HTMLElement [, visible = false, center = obj.anchor])
```
Renders a DOM [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) on screen relative to the containing object. If `visible` is true, always visible; otherwise shows on mouse over. `center` is the position/rotation center defined by `options.adjustment`. Position is relative to the object and re-rendered when the label is visible. Uses [`THREE.CSS2DRenderer`](https://threejs.org/docs/#examples/en/renderers/CSS2DRenderer) and `CSS2DObject`, assigned to `obj.label`.

<br/>

#### duplicate
```js
obj.duplicate()
```
Returns a clone of the object. Reuses materials and geometry for ~95% performance improvement when adding many identical objects.

<br>

#### removeCSS2D
```js
obj.removeCSS2D(objName)
```
Removes the CSS2DObject instance by `objName` and disposes its resources.

<br>

#### removeHelp
```js
obj.removeHelp()
```
Removes the `CSS2DObject` stored in `obj.help`. Calls `obj.removeCSS2D` internally.

<br>

#### removeLabel
```js
obj.removeLabel()
```
Removes the `CSS2DObject` stored in `obj.label`. Calls `obj.removeCSS2D` internally.

<br>

#### removeTooltip
```js
obj.removeTooltip()
```
Removes the `CSS2DObject` stored in `obj.tooltip`. Calls `obj.removeCSS2D` internally.

<br>

#### set
```js
obj.set(options)
```
Updates position, rotation, and scale in one call. Calls `obj._setObject(options)` internally. If `options.duration` is set, animates the object. See types section for details.

**options object on animations (`duration > 0`)**

| option | required | default | type   | description                                                                                  |
|-----------|----------|---------|--------|------------|
| `coords`    | no       | NA      | `lnglat` | Target position |
| `rotation`    | no       | NA      | `rotationTransform` | Rotation in degrees |
| `scale`    | no       | NA      | `scaleTransform` | Scale (1 = default) |
| `duration`    | no       | 1000      | number | Animation duration in ms. 0 or undefined = no animation. |

**options object without animations (`duration == 0`)**

| option | required | default | type   | description                                                                                  |
|-----------|----------|---------|--------|------------|
| `position`    | no       | NA      | `lnglat` | Target position |
| `rotation`    | no       | NA      | `rotationTransform` | Rotation in degrees |
| `scale`    | no       | NA      | `scaleTransform` | Scale (1 = default)|
| `worldCoordinates` | no       | NA | `Vector3` | World position |
| `quaternion`    | no       | NA     | [`Vector3`, `radians`] | Rotation by axis and angle in radians |
| `translate`    | no       | NA      | `lnglat` | Incremental position change |
| `worldTranslate`  | no       | NA   | `Vector3` | Incremental world position change |

<br>

#### setAnchor
```js
obj.setAnchor(anchor)
```
Sets position and key anchor from a string. `anchor` values: `top`, `bottom`, `left`, `right`, `center`, `top left`, `top right`, `bottom left`, `bottom right`. Default: bottom-left.

<br>

#### setBoundingBoxShadowFloor
```js
obj.setBoundingBoxShadowFloor()
```
Called from `obj.setCoords` when the object receives new coordinates. Positions `obj.boundingBoxShadow` at floor height so the shadow stays on the ground when height changes, making drag/position/rotate easier to see.

<br>

#### setCoords
```js
obj.setCoords(lnglat)
```
Positions the object at `lnglat`. Resizes appropriately if instantiated with `units: "meters"`. Can be called before adding to the map.

<br>

#### setFixedZoom
```js
obj.setFixedZoom(scale)
```
Sets scale for object transformation based on `fixedZoom`. `scale` should equal `map.transform.scale`. Called from `obj.setScale` and load methods; usually not called directly from UI.

<br>

#### setObjectScale
```js
obj.setObjectScale(scale)
```
Sets scale for object transformation using `obj.unitsPerMeter` and `scene` or `meters` units. `scale` should equal `map.transform.scale`. Calls `obj.setScale(scale)`, `obj.setBoundingBoxShadowFloor()`, `obj.setReceiveShadowFloor()` internally.

<br>

#### setRotation
```js
obj.setRotation(xyz)
```

Rotates the object on all 3 axes around its defined center. Value in degrees, as number (all axes) or `{x, y, z}`. Applied on top of rotation from `loadObj(options)`.

<br>

#### setRotationAxis
```js
obj.setRotationAxis(xyz)
```

Rotates the object around a bottom corner on the z-axis. Value in degrees, as number or `{x, y, z}`. Applied on top of rotation from `loadObj(options)`.

<br>

#### setScale
```js
obj.setScale(scale)
```
Sets scale for object transformation using `obj.unitsPerMeter` and `scene` or `meters` units. `scale` should equal `map.transform.scale`, or `obj.userData.mapScale` if null. Calls `obj.setFixedZoom` internally.

<br>

#### setTranslate
```js
obj.setTranslate(lnglat)
```
Moves the object from its current position by adding `lnglat`. Different from `obj.setCoords`. Must be called after the object is added to the map.

<br>

### Object Properties

In the examples below, the threeContext object instance is referred to as "obj".
<br>

#### boundingBox

```js
obj.boundingBox : THREE.Box3Helper
```
`THREE.Box3Helper` with the object's initial size. Visible on MouseOver (yellow) or Selected (green). Hidden from `THREE.Raycaster` by design.

<br>

#### boundingBoxShadow

```js
obj.boundingBoxShadow : THREE.Box3Helper
```
`THREE.Box3Helper` with initial size but height 0, projected on the map floor. Acts as a shadow. Visible on MouseOver or Selected (black). Hidden from `THREE.Raycaster` by design.

<br>

#### castShadow

```js
obj.castShadow : boolean
```
Whether the object casts shadows. Creates a plane with `THREE.PlaneBufferGeometry` and `THREE.ShadowMaterial()` centered on the object, sized to the longest dimension, scaled to fit the full shadow.

<br>

#### color

```js
obj.color : integer hex 
```
Gets/sets color from hex value. Calls `color.setHex`.
<br>

#### help

```js
obj.help : CSS2DObject
```
`CSS2DObject` created by `obj.addHelp`, showing rotate, translate, or altitude values during drag. Internal; visible only during drag operations.

<br>

#### hidden

```js
obj.hidden : boolean
```
Object hidden state. Overrides `obj.visibility`.

<br>

#### fixedZoom

```js
obj.fixedZoom : Number
```
Zoom level below which the object keeps a fixed scale. Above it, the object rescales normally. Useful for models that must stay visible at low zoom (e.g. aircraft). `fixedZoom` uses `scene` units, not `meters`.
<br>

#### label

```js
obj.label : CSS2DObject
```
`CSS2DObject` created by `obj.addLabel`. Can show on hover or always. Used for object attributes or state; can contain any HTMLElement.

<br>

#### modelHeight

```js
obj.modelHeight : Number
```
Object height in meters.
<br>

#### raycasted

```js
obj.raycasted : boolean
```
If false, hides the object from `THREE.Raycaster`. Default true. Can be set via `threeContext.loadObj` or `threeContext.Object3D`.

<br>


#### receiveShadow

```js
obj.receiveShadow : boolean
```
Whether the object receives shadows.

<br>

#### tooltip

```js
obj.tooltip : CSS2DObject
```
`CSS2DObject` created by `obj.addTooltip`. Default text is object `uuid`. Visible only when `threeContext.enableTooltips` is true.

<br>

#### unitsPerMeter

```js
obj.unitsPerMeter : Number
```
Conversion factor for units per meter at the object's current latitude.
<br>

#### visibility

```js
obj.visibility : boolean
```
Overrides `THREE.Object3D.visible`. Also applied to `obj.label` and `obj.tooltip`. Overridden by `obj.hidden`.

<br>

#### wireframe

```js
obj.wireframe : boolean
```
Switches the object between wireframe and textured mode. When in wireframe, hidden from `THREE.Raycaster` by design.

<br>

---


### Object Events

In the examples below, the threeContext object instance is referred to as "obj".
<br>

#### IsPlayingChanged

```js
obj.addEventListener('IsPlayingChanged', onIsPlayingChanged, false)
```

Fired when the object's animation play state changes (start or stop). Listen after `threeContext.loadObj` callback. Changed object in `eventArgs.detail`.
```js
map.addLayer({
	...
	threeContext.loadObj(options, function (model) {

		soldier = model.setCoords(origin);

		soldier.addEventListener('IsPlayingChanged', onIsPlayingChanged, false);

		threeContext.add(soldier);
	})

	...
});
...
function onIsPlayingChanged(eventArgs) {
	if (e.detail.isPlaying) {
		//do something in the UI such as changing a button state
	}
	else {
		//do something in the UI such as changing a button state
	}
}
```

<br>

#### ObjectChanged

```js
obj.addEventListener('ObjectChanged', onObjectChanged, false)
```

Fired when the object changes (including via animation). Listen after `threeContext.loadObj` callback. Changed object in `eventArgs.detail`. Possible actions: `position` (lnglat + alt), `rotation` (Vector3 radians), `scale` (Vector3).

```js
map.addLayer({
	...
	threeContext.loadObj(options, function (model) {
		model.setCoords(origin);
		model.addEventListener('ObjectChanged', onObjectChanged, false);
		threeContext.add(model);
	})

	...
});
...
function onObjectChanged(e) {
	let object = e.detail.object; // the object that has changed
	let action = e.detail.action; // the action that defines the change
	//do something in the UI such as changing a button state or updating the new position and rotation
}
```

<br>


#### ObjectDragged

```js
obj.addEventListener('ObjectDragged', onDraggedObject, false)
```

Fired once when an object is dragged to a new position, on `map.once('mouseup')` and `map.once('mouseout')`. Listen after `threeContext.loadObj` callback. In `eventArgs.detail`: `draggedAction` may be `"rotate"` (rotated), `"translate"` (moved), or `"altitude"` (height changed).
```js
map.addLayer({
	...
	threeContext.loadObj(options, function (model) {

		soldier = model.setCoords(origin);

		soldier.addEventListener('ObjectDragged', onDraggedObject, false);

		threeContext.add(soldier);
	})

	...
});
...
function onDraggedObject(e) {
	let draggedObject = e.detail.draggedObject; // the object dragged
	let draggedAction = e.detail.draggedAction; // the action during dragging

	//do something in the UI such as changing a button state or updating the new position and rotation
}
```

<br>


#### ObjectMouseOver

```js
obj.addEventListener('ObjectMouseOver', onObjectMouseOver, false)
```

Fired when the mouse pointer hovers over the object. Listen after `threeContext.loadObj` callback. Object in `eventArgs.detail`.

```js
map.addLayer({
	...
	threeContext.loadObj(options, function (model) {

		soldier = model.setCoords(origin);

		soldier.addEventListener('ObjectMouseOver', onObjectMouseOver, false);

		threeContext.add(soldier);
	})

	...
});
...
function onObjectMouseOver(e) {
	//do something in the UI such as adding help or showing this object attributes
}
```

<br>


#### ObjectMouseOut

```js
obj.addEventListener('ObjectMouseOut', onObjectMouseOut, false)
```

Fired when the mouse pointer leaves an object that was hovered. Listen after `threeContext.loadObj` callback. Object in `eventArgs.detail`.

```js
map.addLayer({
	...
	threeContext.loadObj(options, function (model) {

		soldier = model.setCoords(origin);

		soldier.addEventListener('ObjectMouseOut', onObjectMouseOut, false);

		threeContext.add(soldier);
	})

	...
});
...
function onObjectMouseOut(e) {
	//do something in the UI such as removing help
}
```

<br>

#### SelectedChange

```js
obj.addEventListener('SelectedChange', onSelectedChange, false)
```
Fired when the object's selection state changes (selected or unselected). Listen after `threeContext.loadObj` callback. Object in `eventArgs.detail`.

```js
map.addLayer({
	...
	threeContext.loadObj(options, function (model) {

		soldier = model.setCoords(origin);

		soldier.addEventListener('SelectedChange', onSelectedChange, false);

		threeContext.add(soldier);
	})

	...
});
...
function onSelectedChange(e) {
	let selectedObject = e.detail; //we get the object selected/unselected
	let selectedValue = selectedObject.selected; //we get if the object is selected after the event
}
```

<br>

#### SelectedFeature

```js
map.on('SelectedFeature', onSelectedFeature)
```

Fired by threeContext using the same `feature-state` pattern as the map (`select` and `hover`). Object in `eventArgs.detail`.
```js
map.addLayer({
	'id': 'room-extrusion',
	'type': 'fill-extrusion',
	'source': 'floorplan',
	'paint': {
	// See the map Style Specification for details on data expressions.
 
	// Get the fill-extrusion-color from the source 'color' property.
	'fill-extrusion-color':
		[
			'case',
			['boolean', ['feature-state', 'select'], false],
			'#ffff00',
			['boolean', ['feature-state', 'hover'], false],
			'#0000ff',
			['get', 'color']
		],
 
	// Get fill-extrusion-height from the source 'height' property.
	'fill-extrusion-height': ['get', 'height'],
 
	// Get fill-extrusion-base from the source 'base_height' property.
	'fill-extrusion-base': ['get', 'base_height'],
 
	// Make extrusions slightly opaque for see through indoor walls.
	'fill-extrusion-opacity': 0.5
}
});
//selected extrusion feature event
map.on('SelectedFeature', onSelectedFeature);
...
function onSelectedFeature(e) {
	let selectedObject = e.detail; //we get the object selected/unselected
	let selectedValue = selectedObject.selected; //we get if the object is selected after the event
}
```

<br>

#### Wireframed

```js
obj.addEventListener('Wireframed', onWireframed, false)
```

Fired when the object's wireframe state changes. Listen after `threeContext.loadObj` callback. Object in `eventArgs.detail`.

```js
map.addLayer({
	...
	threeContext.loadObj(options, function (model) {

		soldier = model.setCoords(origin);

		soldier.addEventListener('Wireframed', onWireframed, false);

		threeContext.add(soldier);
	})

	...
});
...
function onWireframed(e) {
	if (e.detail.wireframe) {
		//do something in the UI such as changing a button state
	}
	else {
		//do something in the UI such as changing a button state
	}
}
```

<br>

---


### Object Animations

#### playDefault
```js
obj.playDefault(options)
```
Plays the default embedded animation of the loaded 3D model.

**options object**

| Option | Required | Default | Type | Description                                                                        |
|-----------|----------|---------|--------|------------|
| `duration`    | no       | 1000      | number | Animation duration in ms |
| `speed`    | no       | 1      | number | Time scale for animation (1 = default, <1 slower, >1 faster) |

<br>

#### playAnimation
```js
obj.playAnimation(options)
```
Plays one embedded animation of the loaded 3D model. Set animation index in `options.animation`.

**options object**

| option | required | default | type   | description                                                                                  |
|-----------|----------|---------|--------|------------|
| `animation`    | yes       | NA      | number | Animation index in the 3D model. Use `obj.animations` for full array. |
| `duration`    | no       | 1000      | number | Animation duration in ms |
| `speed`    | no       | 1      | number | Time scale (1 = default, <1 slower, >1 faster) |


<br>


#### followPath
```js
obj.followPath(options [, callback] )
```

Translates the object along a path. Optional callback when animation ends.

| Option | Required | Default | Type | Description                                                                              |
|-----------|----------|---------|--------|------------|
| `path`    | yes       | NA      | lineGeometry | Path for the object to follow |
| `duration`    | no       | 1000      | number | Duration in ms |
| `trackHeading`    | no       | true      | boolean | Rotate object to align with movement direction during animation |

<br>


#### stop
```js
obj.stop()
```

Stops all current animations on the object.

<br>


- - -

## threeContext Types

#### pointGeometry
`[longitude, latitude(, meters altitude)]`

Array of 2–3 numbers: longitude, latitude, optional altitude in meters. Altitude 0 if omitted. From GeoJson point: `point.geometry.coordinates`. threeContext accepts altitude for z-axis positioning.

<br>

#### lineGeometry

`[pointGeometry, pointGeometry ... pointGeometry]`

Array of at least two lnglat points forming a line. From GeoJson LineString: `line.geometry.coordinates`.

<br>

#### rotationTransform

`number` or `{x: number, y: number, z: number}`

Rotation in degrees. Object form: x parallel to equator, y parallel to meridian, z perpendicular to ground. Number form: rotation around z-axis, equivalent to `{z: number}`.

<br>

#### scaleTransform

`number` or `{x: number, y: number, z: number}`

Scale factor (1 = default). Same axes as rotationTransform. Number form scales all three axes.

#### threeMaterial

`string` or instance of `THREE.Material()`

Material for the object. Can be customized with `color` and `opacity`. `opacity` can be a string for the material type (e.g. `'MeshPhysicalMaterial'` for `THREE.MeshPhysicalMaterial()`), or a pre-built THREE material.

<br>

- - -


## Performance Considerations

- Use `obj.duplicate()` when adding many identical objects. If the object has collections not in `obj.children`, those must be cloned as well.
  

**For ThreeJS usage details, refer to the [ThreeJS](https://threejs.org/) official documentation**



### Example

<mapFrame src="/examples/index.html?name=threejs"/>

<br/>
<br/>

#### 

```js
(async () => {
    // --ThreeJS 3D line--
    // Map service object
    let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
    // Open map
    let res = await svc.openMap({
        mapid: env.exampleMapId, // Map ID
        mapopenway: vjmap.MapOpenWay.GeomRender, // Open with geometry data rendering
        style: vjmap.openMapDarkStyle() // Use dark background style when div has dark background
    })
    if (res.error) {
        // If open fails
        message.error(res.error)
    }
    // Get map bounds
    let mapExtent = vjmap.GeoBounds.fromString(res.bounds);
    // Create geometric projection coordinate system from map bounds
    let prj = new vjmap.GeoProjection(mapExtent);

    // Map object
    let map = new vjmap.Map({
        container: 'map', // DIV container ID
        style: svc.rasterStyle(), // Style, raster style here
        center: prj.toLngLat(mapExtent.center()),
        zoom: 2,
        pitch: 60,
        antialias:true,
        renderWorldCopies: false // Do not show multi-world map
    });

    // Attach service object and projection
    map.attach(svc, prj);
    // Fit map to full extent
    //map.fitMapBounds();
    await map.onLoad();

    const mapBounds = map.getGeoBounds(0.6);

    if (typeof vjThree !== "object") {
        // If the environment is not available
        await vjmap.addScript([{
            src: "js/plugins/vjthree.min.js"
        },{
            src: "js/plugins/vjthree.min.css"
        }])
    }

    const threeContext = map.createThreeJsContext({
        defaultLights: true
    });
    const arcSegments = 25;
    const lineQuantity = 50;

    for (let i = 0; i < lineQuantity; i++){
        const line = [];
        const destination = [300*(Math.random()-0.5), 140*(Math.random()-0.5)];
        const maxElevation = Math.pow(Math.abs(destination[0]*destination[1]), 0.5) * 80000;

        const increment = destination.map(function(direction){
            return direction/arcSegments;
        })

        for (let l = 0; l<=arcSegments; l++){
            const waypoint = increment.map(function(direction){
                return direction * l
            })

            const waypointElevation = Math.sin(Math.PI*l/arcSegments) * maxElevation;

            waypoint.push(waypointElevation);
            line.push(waypoint);
        }

        const lineOptions = {
            geometry: line,
            color: (line[1][1]/180) * 0xffffff, // color based on latitude of endpoint
            width: Math.random() + 1 // random width between 1 and 2
        }

        let lineMesh = threeContext.line(lineOptions);
        threeContext.add(lineMesh)
    }
    map.addLayer(new vjmap.ThreeLayer({context: threeContext}));
})();
```
