npm package: 51timapi
Description: TimApi is a traffic related plugin for WdpApi.
Author: 51TIM
Latest version: 1.2.4

## 介绍

tim-api是一个交通行业的Wdp插件，其运行依赖于wdpapi

#### 安装
```bash
$ npm i @wdp-api/tim-api
```

#### 引入
```javascript
import WdpApi from 'wdpapi'
import TimApi from '@wdp-api/tim-api'
```

#### 初始化
```javascript
const config = {
    "id": "player", //[required] Render scene container(DOM node id)
    "url": "http://10.66.8.158:8889/Renderers/Any/order", //[optional] Cloud rendering service address
    "order": "cba557541abbdccaed3c2043b7e9db35", //[optional] Rendering order, obtained on the cloud rendering client
    "resolution": [ window.screen.width, window.screen.height ], //[optional] Set the cloud rendering output resolution[width, height]
    "debugMode": "normal", //[optional] none: does not print logs, normal: normal logs
    "keyboard": { //[optional] keyboard event
        "normal": false, //[optional] Keyboard event, exclude F1~F12 [default disabled]
        "func": false //[optional] Browser F1 ~ F12 function keys [default disabled]
    }
}
const App = new WdpApi(config) as WdpApi & TimApi
App.Plugin.Install(TimApi).then(r=>{
    App.Renderer.Start().then((res) => {
        if (res.success) {
            App.Renderer.RegisterEvent([
                {
                    name: 'onVideoStreamLoaded', func: function () {
                        // 视频流加载成功
                    }
                }
            ])
        }
    })
});

/** 停止推流 **/
App.Renderer.Stop();
```

#### 加载 Xodr 高精路网
```javascript
const TrafficOdRoad = new App.TrafficODRoad({
    "Online": true, // 是否为离线数据
    "AutoFocus": true, // 加载后自动聚焦至路网
    "Url": "test.xodr", // 路网地址
    "Lon": 116.31,
    "Lat": 31.31,
    "Height": 20000
})
const res = await App.Scene.Add(TrafficODRoad)

/** 更新车流 **/
TrafficODRoad.Update({
    "Url": "ws://10.66.9.186:5681/965" // 符合规范的websocket链接
})

/** 删除车流 **/
TrafficODRoad.Delete()
```

#### 车流
```javascript
/** 创建车流 **/
const TrafficFlow = new App.TrafficFlow({
    trafficDataUrl: "ws://10.66.9.186:5681/965" // 符合规范的websocket链接
})
const res = await App.Scene.Add(TrafficFlow)

/** 更新车流 **/
TrafficFlow.Update({
    trafficDataUrl: "ws://10.66.9.186:5681/965" // 符合规范的websocket链接
})

/** 删除车流 **/
TrafficFlow.Delete()

/** 获取车流信息 **/
TrafficFlow.GetTrafficFlowInfo()

/** 根据id获取车流中的车辆信息 **/
TrafficFlow.GetTrafficVehicleInfo("v-10") // v-10为车辆ID

/** 获取全量车辆信息 **/
TrafficFlow.GetAllTrafficVehicleInfo() // v-10为车辆ID

/** 车流控制 **/
TrafficFlow.RunTrafficFlowAction({
    actionName: "Pause" //车流暂停：Pause；播放：Play；显示：Show；隐藏：Hide；气泡隐藏：HideBubbles；气泡显示：ShowBubbles；开启点击查询：EnableQuery；关闭点击查询：DisableQuery
})

/** 车流气泡控制 **/
TrafficFlow.ToggleBubbles(true) // 打开ture，关闭 false

/** 车流速度包围盒控制 **/
TrafficFlow.ToggleSpeedBox(true) // 打开ture，关闭 false


/** 设置聚焦显示交通体气泡 **/
TrafficFlow.FocusTrafficVehicles(["id1","id2"]) //仅显示当前气泡交通体id的气泡。传空数组表示显示所有气泡

/** 获取聚焦显示交通体id **/
TrafficFlow.GetFocusedTrafficVehicles()


/** 创建历史车流(除下列方法外，其他方法同实时车流) **/
const TrafficHistoryFlow = new App.TrafficHistoryFlow({
    trafficDataUrl: "ws://10.66.9.186:5681/965", // 符合规范的websocket链接
    isCompare: false // ture 表示对比车流
})
const res = await App.Scene.Add(TrafficHistoryFlow)

/** 历史车流播放控制 **/
TrafficHistoryFlow.Play()
TrafficHistoryFlow.Pause()
TrafficHistoryFlow.Stop()
TrafficHistoryFlow.PlaySpeed(3) // 倍速播放
TrafficHistoryFlow.JumpTo(100) // 跳转到指定时间，车流时间在加载回调中获取

/** 历史车流加载回调 **/
App.Scene.Covering.TrafficFlowHistory.OnProcessControlledTrackTime((res)=>{
    console.log("=============OnProcessControlledTrackTime===========", res)
})

/** 交通流统计围栏 **/
const boundary = new App.TrafficFlowBoundary([
    {
        "boundaryId": "TestId", //围界id（自定义）
        "positions": [ //围界顶点
            [ 121, 31, 0 ],
            [ 121, 31, 0 ],
            [ 121, 31, 0 ]
        ]
    },
    {
        "boundaryId": "TestId2",
        "positions": [
            [ 121, 31, 0 ],
            [ 121, 31, 0 ],
            [ 121, 31, 0 ]
        ]
    }
])
const res = await App.Scene.Add(boundary)

/**车流**/
App.Scene.Covering.TrafficFlowBoundary.OnProcessAlertBoundary((res)=>{
    console.log("=============OnProcessAlertBoundary===========", res)
})
```

#### 相机
```javascript
/** 点击鼠标跟车 **/
App.TrafficCamAPI.FollowVehicleByClick({
    clickToFollow: true,
    followMode: "Follower" //None不跟车，Driver驾驶视角，Follower第三人称跟车视角
})

/** 通过车辆ID跟车 **/
App.TrafficCamAPI.FollowVehicleByID({
    vehicleId: "", // 车辆ID
    followMode: "Follower" //None不跟车，Driver驾驶视角，Follower第三人称跟车视角
})

/** 取消跟车模式 **/
App.TrafficCamAPI.CancelFollowVehicle()

/** 加载桩号文件 **/
App.TrafficCamAPI.LoadTrafficCameraTourData({
    "url": "D:/ZS_1.js", //桩号文件路径
    "list_id": "1" // 数据ID
})

/** 场景镜头沿桩号文件漫游 **/
App.TrafficCamAPI.StartTrafficCameraTour({
    "list_id": "1",
    "start_station_name": "ZSK1+181",  //漫游起点桩号 ，可置空，置空时将从距离镜头最近的桩号开始漫游
    "target_station_name": "ZSK2+533",  //漫游终点桩号
    "speed": "50",   //漫游速度
    "time": 1,          //总体运动时间（speed缺省时有效）
    "height": 5,       //镜头高度
    "target_offset": [1, 10, 20],//相对终点桩号的偏移量，单位m，车道方向为x轴正方向，上方为z轴正方向，右手坐标系
    "rotation": {              //镜头角度
        "pitch": -10,     //俯仰角（0，-90）
        "yaw": 0           //偏航角（车道方向为0度，左负右正）
    }
})

/** 漫游开始、暂停 **/
App.TrafficCamAPI.UpdateTrafficCameraTour({
    "Mode": "Pause"   //Pause暂停；play开始；stop停止
})

/** 相机变化回调事件 **/
App.TrafficCamAPI.OnTrafficCamStatusChanged((info) => {
    console.log(info)
});
```


#### 高精路网热力图
```javascript
/** 创建高精路网热力图 **/
const TrafficRoadHeatMap = new App.TrafficRoadHeatMap({
    openDriveUrl: "v1.xodr", //路网文件路径
    densitySettings:
        {
            mode: "MaxSpeed",  //车道最大速度：MaxSpeed;车道内所有车辆平均速度：AvgSpeed;VehCount:车道上的最大车辆数。
            min: 10, //阈值下限。当Mode中的统计类型值小于等于LevelMin值时，热力图显示为绿色。
            max: 100 //阈值上限。当Mode中的统计类型值大于等于LevelMax值时，热力图显示为红色。
        },
    offset:[0,0,1000], //位置偏移 xyz，单位：cm
    isVisible: false //是否可见
})
const res = await App.Scene.Add(TrafficRoadHeatMap)

/** 更新热力图 **/
TrafficRoadHeatMap.Update({
    openDriveUrl: "v1.xodr", //路网文件路径
    densitySettings:
        {
            mode: "MaxSpeed",  //车道最大速度：MaxSpeed;车道内所有车辆平均速度：AvgSpeed;VehCount:车道上的最大车辆数。
            min: 10, //阈值下限。当Mode中的统计类型值小于等于LevelMin值时，热力图显示为绿色。
            max: 100 //阈值上限。当Mode中的统计类型值大于等于LevelMax值时，热力图显示为红色。
        },
    offset:[0,0,1000], //位置偏移 xyz，单位：cm
    isVisible: false //是否可见
})

/** 删除热力图 **/
TrafficRoadHeatMap.Delete()

/** 微观道路热力图 **/
const TrafficRoadHeatMap = new App.TrafficRoadHeatMap({
    openDriveUrl: "v1.xodr", //路网文件路径
    densitySettings:
        {
            mode: "MaxSpeed",  //车道最大速度：MaxSpeed;车道内所有车辆平均速度：AvgSpeed;VehCount:车道上的最大车辆数。
            min: 10, //阈值下限。当Mode中的统计类型值小于等于LevelMin值时，热力图显示为绿色。
            max: 100 //阈值上限。当Mode中的统计类型值大于等于LevelMax值时，热力图显示为红色。
        },
    offset:[0,0,1000], //位置偏移 xyz，单位：cm
    isVisible: false //是否可见
})
const res = await App.Scene.Add(TrafficRoadHeatMap)

/** 车道热力图 **/
const TrafficRoadNetworkHeatMap = new App.TrafficRoadNetworkHeatMap({
    "RoadMeshDataUrl":"E://Projects//URP0823//NanNing_ortho1.xodr", // 路网文件路径
    "HeatMapPointsDataUrl": "ws://10.66.8.162:33021/AnalyzeResult", // 热力图数据地址
    "height": 0.25, // 热力图高度
    "compare": true // 是否开启对比车流
})
const res = await App.Scene.Add(TrafficRoadNetworkHeatMap)
```

#### GeoJson线段热力图
```javascript
/** 创建GeoJson线段热力图 **/
const TrafficAnalysis = new App.TrafficAnalysis({
    "roadDataUrl": "roadDataUrl", // Geojson在线请求地址
    "height": 30,
    "width": 5,
    "field": "fieldKey", // Geojson中需计算的属性
    "symbolMap":  {
        "0": "#00ffff",
        "0.5": "#ffff00",
        "1": "#ff00ff"
    }
});
const res = await App.Scene.Add(TrafficRoadHeatMap)

/** 更新热力图 **/
TrafficAnalysis.Update({
    "height": 30,
    "width": 5,
    "field": "fieldKey", // Geojson中需计算的属性
    "symbolMap":  {
        "0": "#00ffff",
        "0.5": "#ffff00",
        "1": "#ff00ff"
    }
})

/** 删除热力图 **/
TrafficAnalysis.Delete()
```

#### 截面流量统计
```javascript
/** 创建截面流量统计 **/
const TrafficSectionFlow = new App.TrafficSectionFlow({
    startLonLat: [],//截面起点
    endLonLat: [], //截面终点
    opacity: 0, //透明度，取值范围0到1
    
    hexColor: "",//颜色，HEX值
    height: 0 //高度
})
const res = await App.Scene.Add(TrafficSectionFlow)

/** 获取截面流量统计 **/
TrafficSectionFlow.GetSectionFlowStatistics()

/**  删除截面 **/
TrafficSectionFlow.Delete()
```

#### 全局设置
```javascript
/** 启用 / 关闭 编辑模式 此模式在下方模型点击回调 OnModelClicked 中有模型信息 **/
App.TimGlobal.toggleEditMode(true);

/** 启用 / 关闭 Gizmo **/
App.TimGlobal.toggleGizmo(true);

/** 加载场景 **/
App.TimGlobal.loadScene('FS'); // 场景名称
```

#### 模型
```javascript
/** 模型加载 **/
const Asset = new App.TimAsset({
    "model": {
        "sourceType": "Imported", // BuiltIn内置模型, Imported外部导入模型
        "url": "http://10.66.8.158:5173/1.fbx" // fbx文件地址
    },
    "scale": [0,0,0],
    "location": [0,0,0],
    "rotation": [0,0,0]
})

/** 模型更新 **/
Asset.Update({
    "scale": [0,0,0],
})

/** 模型删除 **/
Asset.Delete()

/** 模型设置自定义属性 **/
App?.Scene.Covering.TimAsset.SetCustomProperties({
    "params":
        {
            "customId": "",  //自定义ID
            "customProperties": {  //自定义属性，键值对的key和value可自定义
                "P_A":  1,
                "D_B":  2
            }
        },
    "eid": "-123456789"  //eid
})

/** 通过EID查询自定义ID和属性 **/
App?.Scene.Covering.TimAsset.GetTimModelInfoByEid(eid) 

/** 通过自定义ID和属性查询 **/
App?.Scene.Covering.TimAsset.QueryEidsByCustomProperties({
    "customId": "",
    "customProperties":{}
}) 

/** 通过EID控制资产功能 **/
App?.Scene.Covering.TimAsset.ModelControl({
    type: 'dashboard', // type类型待定
    params: {} // params 格式随type类型变化
})

/** 创建交通事件 **/
const Event = new App.TimAsset({
    "model": {
        "sourceType": "BuiltIn", // BuiltIn内置模型, Imported外部导入模型
        "url": "",
        "assetId": "BP_Event_01" //定义事件选择   0单车事故 1两车事故 2多车事故 3车辆起火 4抛洒物 5设备故障 6道路施工占道 7危险品泄露 8道路结冰 9锥桶 10障碍物当道
    },
    "location": [118.07364477436617, 24.806057678089054, 0],
    "rotation": [0, 0, 90],
    "scale": [1, 1, 1]
})

/** 设置交通事件 **/
App?.Scene.Covering.TimAsset.ModelControl({
    "TrafficEvent": "True",
    "EventNumber": "1"//定义事件选择   0单车事故 1两车事故 2多车事故 3车辆起火 4抛洒物 5设备故障 6道路施工占道 7危险品泄露 8道路结冰 9锥桶 10障碍物当道
})

/** 删除事件 **/
Event.Delete()

/** 模型材质替换 **/
App?.Scene.Covering.TimAsset.UpdateSelectionMaterial(
    {
        "materialInfo": {
        "materialParams":
            {
                "textures": {},
                "colors": {},
                "scalars": {}
            },
            "sourceType": "BuiltIn",
            "assetId": "",
            "url": ""
        }
    }
)

/** 模型加载状态回调 **/
App.Scene.Covering.TimAsset.OnModelProcessState(()=>{
    console.log("=============OnModelProcessState===========")
})

/** 开启编辑状态后的模型点击回调 **/
App.Scene.Covering.TimAsset.OnModelProcessState(()=>{
    console.log("=============OnModelProcessState===========")
})

/** 加载储存场景 **/
App?.Scene.Covering.TimAsset.LoadTimModelScene()
App?.Scene.Covering.TimAsset.SaveTimModelScene()
App?.Scene.Covering.TimAsset.LoadTimModelSceneOnline()
App?.Scene.Covering.TimAsset.SaveTimModelSceneOnline()
```

### 信控、引导线
```javascript
/** 信控 **/
App.TimSignal.CreateTIMSignal({
    "SignalLines": [
        {
            "LaneID": "12",//本项目中无实际意义，可置空
            "NodeID": "1",//本项目中无实际意义，可置空
            "RoadID_c": "1",//本项目中无实际意义，可置空
            //停止线端点坐标
            "coord1": [117.31884370955275,38.989795506281467],
            "coord2": [117.31890374051923,38.989940666684802],
            "customId": "1001",//停止线ID
            "customProperties": {
                "NodeID_c": "A路口",  //可置空
                "PhaseID": "相位1",//可置空
                "LightID": "信号灯1296"//可置空
            }
        },
        {
            "LaneID": "12",
            "NodeID": "1",
            "RoadID_c": "1",
            //停止线端点坐标
            "coord1": [117.31884370955275,38.989795506281467],
            "coord2": [117.31890374051923,38.989940666684802],
            "customId": "1002",//停止线ID
            "customProperties": {
                "NodeID_c": "A路口",  //可置空
                "PhaseID": "相位1",  //可置空
                "LightID": "信号灯1296"  //可置空
            }
        }
    ]
})

/** 信控删除 **/
App.TimSignal.DeleteTIMSignal({
    "list": ["12000002884"] // 上方创建的customId
})

/** 增加接入信控数据接口 **/
App.TimSignal.ConnectSignalControl({
    "URL":"ws://10.66.8.47:8765"
})

/** 引导线 **/
App.TimGuideLine.CreateTIMGuideLine({
    "DataUrl": "",
    "GuideLines": [{
        "vehicleId": "l1", // 车辆ID
        "Color_Pre": "#0F55F5", // 车前颜色
        "Color_Post": "#AA0005", // 车后颜色
        "polyline": [
            [
                117.30203333306301,
                38.90798229882037
            ],
            [
                117.30203530436518,
                38.907978015471384
            ],
            [
                117.30204699434899,
                38.90793433699546
            ],
            [
                117.30204874682879,
                38.90792761121343
            ],
            [
                117.3020503996861,
                38.90792086572872
            ]
        ]
    }, {
        "vehicleId": "l2",
        "Color_Pre": "#0F55F5",
        "Color_Post": "#AA0005",
        "polyline": [
            [
                117.30170785784569,
                38.90729196404028
            ],
            [
                117.30168191511423,
                38.9072786607969
            ],
            [
                117.30167335661509,
                38.907269545748234
            ],
            [
                117.30166669078757,
                38.90725953495349
            ],
            [
                117.30166207704999,
                38.90724883795114
            ],
            [
                117.30165962501801,
                38.90723772443371
            ]
        ]
    }]
})

/** 删除引导线 **/
App.TimGuideLine.DeleteTIMGuideLine(
    {
        "list": ["l1", "l2"]
    }
)

/** V2x 飞线 **/
App.TIMV2XLine.ConnectTIMV2XLine({
    "DataUrl": "ws://10.66.8.47:8765" //断开链接飞线删除
})
```


## License

Copyright (c) 2023-present, 51WORLD