UNPKG

signalk-ais-target-prioritizer

Version:

A SignalK plugin that priorizes AIS targets according to guard and CPA criteria.

646 lines (590 loc) 30.8 kB
<!doctype html> <html lang="en" data-bs-theme="light"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title>SignalK AIS Target Prioritizer</title> <link rel="stylesheet" href="assets/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/css/leaflet.css" /> <link rel="stylesheet" href="assets/css/easy-button.css" /> <style> body { padding: 0; margin: 0; } html, body, #map { height: 100%; width: 100vw; } #map { color: var(--bs-body-color); background-color: var(--bs-body-bg); } .leaflet-bar a, .leaflet-bar button, .leaflet-bar button:hover, .leaflet-touch .leaflet-control-layers-toggle, .leaflet-control-layers-expanded, .leaflet-container .leaflet-control-attribution { color: var(--bs-secondary-color); background-color: var(--bs-secondary-bg); } .leaflet-bar a:hover, .leaflet-bar a:focus { background-color: var(--bs-tertiary-bg); } .leaflet-tooltip { color: var(--bs-body-color); } .leaflet-layer { background-color: var(--bs-body-bg); } .leaflet-tooltip.map-labels { border: none; background-color: unset; box-shadow: none; } .leaflet-tooltip.map-labels::before { opacity: 0; } .bi { width: 1em; height: 1em; vertical-align: -.125em; fill: currentcolor; } .bi::before, [class^="bi-"]::before, [class*=" bi-"]::before { display: inline-block; font-family: bootstrap-icons !important; font-style: normal; font-weight: normal !important; font-variant: normal; text-transform: none; line-height: 1; vertical-align: -.125em; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } button.easy-button-button { padding-inline: 0; padding-block: 0; font-size: 16px; } .leaflet-touch .leaflet-control-layers-toggle { /* background-image: url(assets/icons/layers-fill.svg); */ background-image: unset; /* fill: currentcolor; */ /* background-size: 16px; */ width: 30px; height: 30px; text-align: center; font-size: 16px; line-height: 30px; } #offcanvasEditProfiles { width: 100%; } @media screen and (min-width: 768px) { #offcanvasEditProfiles { width: 575px; } } #offcanvasTargetList { width: 100%; } @media screen and (min-width: 992px) { #offcanvasTargetList { width: 768px; } } #tableOfTargetsBody { cursor: pointer; } #tableOfTargetsBody td { text-align: right; } .blueStuff { z-index: 1000; } #targetCounts { position: absolute; top: 0; right: 0; width: 7em; z-index: 500; } </style> </head> <body> <div id='map'></div> <div class="container"> <div id='targetCounts' class="text-center user-select-none pe-none" tabindex="-1"> <p class="display-3 text-info mb-0" id="totalTargetCountUI">0</p> <p class="text-secondary small">TARGETS</p> <p class="display-3 text-primary mb-0" id="filteredTargetCountUI">0</p> <p class="text-secondary small">FILTERED</p> <p class="display-3 text-danger mb-0" id="alarmTargetCountUI">0</p> <p class="text-secondary small">ALARMS</p> </div> <!-- ERROR MODAL --> <svg xmlns="http://www.w3.org/2000/svg" class="d-none"> <symbol id="exclamation-triangle-fill" viewBox="0 0 16 16"> <path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z" /> </symbol> </svg> <div class="modal" tabindex="-1" id="modalAlert"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="alert alert-danger mb-0" role="alert"> <div class="alert-dismissible"> <span class="h4 alert-heading"> <svg class="bi flex-shrink-0 me-2" role="img"> <use xlink:href="#exclamation-triangle-fill" /> </svg> Error</span> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <hr> <p class="mb-0" id="errorMessage"></p> </div> </div> </div> </div> <div class="modal" tabindex="-1" id="modalAlarm"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content bg-danger-subtle text-danger-emphasis border-danger-subtle"> <div class="modal-header border-danger-subtle"> <h5 class="modal-title"> <svg class="bi flex-shrink-0 me-2" role="img"> <use xlink:href="#exclamation-triangle-fill" /> </svg> Alarm</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body" id="alarmDiv"> </div> <div class="modal-footer border-danger-subtle"> <button type="button" class="btn btn-outline-danger" data-bs-dismiss="modal" id="buttonMuteAllAlarms">Mute All Alarms</button> <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button> </div> </div> </div> </div> <div class="modal" tabindex="-1" id="modalClosebyBoats"> <div class="modal-dialog modal-dialog-centered modal-sm"> <div class="modal-content"> <div class="list-group" id="listOfClosebyBoats"> </div> </div> </div> </div> <div class="modal" tabindex="-1" id="modalSelectedVesselProperties"> <div class="modal-dialog modal-dialog-centered modal-sm"> <div class="modal-content"> <div class="modal-header"> <div class="col-2"> <button type="button" class="btn btn-outline-secondary" id="buttonMuteToggle"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-volume-up-fill" viewBox="0 0 16 16"> <path d="M11.536 14.01A8.47 8.47 0 0 0 14.026 8a8.47 8.47 0 0 0-2.49-6.01l-.708.707A7.48 7.48 0 0 1 13.025 8c0 2.071-.84 3.946-2.197 5.303z"> </path> <path d="M10.121 12.596A6.48 6.48 0 0 0 12.025 8a6.48 6.48 0 0 0-1.904-4.596l-.707.707A5.48 5.48 0 0 1 11.025 8a5.48 5.48 0 0 1-1.61 3.89z"> </path> <path d="M8.707 11.182A4.5 4.5 0 0 0 10.025 8a4.5 4.5 0 0 0-1.318-3.182L8 5.525A3.5 3.5 0 0 1 9.025 8 3.5 3.5 0 0 1 8 10.475zM6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06"> </path> </svg> </button> </div> <div class="col"> <h5 class="modal-title text-center" id="target.name"></h5> </div> <div class="col-2 text-end"> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> </div> <div class="modal-body"> <div id="alertPlaceholder"></div> <h6 class="alert alert-warning text-center d-none" role="alert" id="selectedVesselAlert"> </h6> <table class="table table-sm"> <tbody> <tr> <th scope="row">Last Seen</th> <td><span id="target.lastSeen"></span> secs</td> </tr> <tr> <th scope="row">CPA</th> <td><span id="target.cpaFormatted"></span></td> </tr> <tr> <th scope="row">TCPA</th> <td id="target.tcpaFormatted"></td> </tr> <tr> <th scope="row">Range</th> <td><span id="target.rangeFormatted"></span></td> </tr> <tr> <th scope="row">Bearing</th> <td><span id="target.bearingFormatted"></span></td> </tr> <tr> <th scope="row">SOG</th> <td><span id="target.sogFormatted"></span></td> </tr> <tr> <th scope="row">COG</th> <td><span id="target.cogFormatted"></span></td> </tr> <tr> <th scope="row">HDG</th> <td><span id="target.hdgFormatted"></span></td> </tr> <!-- ${target.aisClass == 'A' ? ` --> <tr class="ais-class-a d-none"> <th scope="row">Rate of Turn</th> <td><span id="target.rotFormatted"></span> deg/s</td> <tr> <th scope="row">Callsign</th> <td id="target.callsign"></td> </tr> <tr> <th scope="row">MMSI</th> <td><span id="target.mmsi"></span> (<a href="#" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="" id="target.mmsiCountryCode"></a>) </td> </tr> <tr> <th scope="row">Type</th> <td id="target.type"></td> </tr> <tr> <th scope="row">Class</th> <td id="target.aisClassFormatted"></td> </tr> <tr class="ais-class-a d-none"> <th scope="row">Status</th> <td id="target.status"></td> <tr> <th scope="row">Size</th> <td id="target.sizeFormatted"></td> </tr> <tr class="ais-class-a d-none"> <th scope="row">Draft</th> <td id="target.draft"></td> </tr> <tr class="ais-class-a d-none"> <th scope="row">Destination</th> <td id="target.destination"></td> </tr> <tr class="ais-class-a d-none"> <th scope="row">ETA</th> <td id="target.eta"></td> </tr> <tr class="ais-class-a d-none"> <th scope="row">IMO</th> <td id="target.imoFormatted"></td> </tr> <tr> <th scope="row">Lat</th> <td id="target.latitudeFormatted"></td> </tr> <tr> <th scope="row">Lon</th> <td id="target.longitudeFormatted"></td> </tr> <!--navigation.specialManeuver--> </tbody> </table> </div> </div> </div> </div> <div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasTargetInfo"> <div class="offcanvas-header"> <h5 class="offcanvas-title">Target Info</h5> <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button> </div> <div class="offcanvas-body" id="offcanvasTargetInfoBody"> </div> </div> <div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasTargetList"> <div class="offcanvas-header"> <h5 class="offcanvas-title">AIS Targets (<span id="numberOfAisTargets"></span>)</h5> <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button> </div> <div class="offcanvas-body"> <table class="table"> <thead> <tr> <th scope="col">NAME</th> <th scope="col" class="text-end">BRG</th> <th scope="col" class="text-end">RNG</th> <th scope="col" class="text-end">SOG</th> <th scope="col" class="text-end">CPA</th> <th scope="col" class="text-end">TCPA</th> <!-- <th scope="col" class="text-end">ORDER</th> --> </tr> </thead> <tbody id="tableOfTargetsBody" /> </table> </div> </div> <div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasSettings"> <div class="offcanvas-header"> <h5 class="offcanvas-title">Settings</h5> <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button> </div> <div class="offcanvas-body"> <div class="collapse multi-collapse show" id="collapseSettings"> <div class="card card-body"> <form> <div class="mb-3"> <label for="selectActiveProfile" class="form-label">Active Profile</label> <select class="form-select fw-bold" id="selectActiveProfile"> <option value="anchor">Anchored</option> <option value="harbor">Harbor</option> <option value="coastal">Coastal</option> <option value="offshore">Offshore</option> </select> </div> <button type="button" class="btn btn-primary col-12 mb-3" id="buttonEditProfiles"> Edit Profiles </button> <button type="button" class="btn btn-danger col-12 mb-3" id="buttonMuteAllAlarms2"> Mute All Alarms </button> <div class="form-check mb-3"> <input class="form-check-input" type="checkbox" id="checkNoSleep"> <label class="form-check-label" for="checkNoSleep"> Prevent screen sleeping in iOS and Android </label> </div> <div class="form-check mb-3"> <input class="form-check-input" type="checkbox" id="checkDarkMode"> <label class="form-check-label" for="checkDarkMode"> Dark Mode </label> </div> <div class="form-check mb-3"> <input class="form-check-input" type="checkbox" id="checkFullScreen"> <label class="form-check-label" for="checkFullScreen"> Fullscreen Mode </label> </div> </form> </div> </div> </div> </div> <div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasEditProfiles"> <div class="offcanvas-header"> <h5 class="offcanvas-title">Edit Profiles</h5> <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button> </div> <div class="offcanvas-body"> <label for="selectProfileToEdit" class="form-label">Select profile to edit</label> <div class="row mb-3"> <div class="col-6"> <select class="form-select fw-bold" id="selectProfileToEdit"> <option value="anchor" selected>Anchored</option> <option value="harbor">Harbor</option> <option value="coastal">Coastal</option> <option value="offshore">Offshore</option> </select> </div> <div class="col-6 d-grid"> <button type="button" class="btn btn-warning" id="buttonRestoreDefaults"> Restore Defaults </button> </div> </div> <div class="card mb-3"> <ul class="list-group list-group-flush"> <!--collision warning--> <li class="h5 bg-body-secondary list-group-item"> Collision Warning </li> <li class="list-group-item"> <p class="card-text">Targets that meet all three of the conditions below will be set to a <code>warning</code> state and shown in <code>orange</code> in the plotter. </p> <div class="row mb-3"> <div class="col-3 pe-0"> <label for="configWarningCpaRange" class="form-label">CPA Less Than</label> </div> <div class="col-7"> <input type="range" class="form-range" id="configWarningCpaRange" min="0" max="19" step="1" data-target="configWarningCpa" data-alarm-type="warning" data-alarm-criteria="cpa"> </div> <div class="col-2 text-end"> <span id="configWarningCpa" class="fw-bold">2.0</span><span id="configWarningCpaUnits"> NM</span> </div> </div> <div class="row mb-3"> <div class="col-3 pe-0"> <label for="configWarningTcpaRange" class="form-label">TCPA Less Than</label> </div> <div class="col-7"> <input type="range" class="form-range" id="configWarningTcpaRange" min="1" max="12" step="1" data-target="configWarningTcpa" data-alarm-type="warning" data-alarm-criteria="tcpa"> </div> <div class="col-2 text-end"> <span id="configWarningTcpa" class="fw-bold">10</span><span> Min</span> </div> </div> <div class="row mb-3"> <div class="col-3 pe-0"> <label for="configWarningSogRange" class="form-label">Speed Exceeds</label> </div> <div class="col-7"> <input type="range" class="form-range" id="configWarningSogRange" min="0" max="10" step="1" data-target="configWarningSog" data-alarm-type="warning" data-alarm-criteria="speed"> </div> <div class="col-2 text-end"> <span id="configWarningSog" class="fw-bold">2.0</span><span> Knots</span> </div> </div> </li> <!--end collision warning--> <!--collision alarm--> <li class="h5 bg-body-secondary list-group-item"> Collision Alarm </li> <li class="list-group-item"> <p class="card-text">Targets that meet all three of the conditions below will be set to a <code>danger</code> state and shown in <code>red</code> in the plotter. </p> <div class="row mb-3"> <div class="col-3 pe-0"> <label for="configAlarmCpaRange" class="form-label">CPA Less Than</label> </div> <div class="col-7"> <input type="range" class="form-range" id="configAlarmCpaRange" min="0" max="19" step="1" data-target="configAlarmCpa" data-alarm-type="danger" data-alarm-criteria="cpa"> </div> <div class="col-2 text-end"> <span id="configAlarmCpa" class="fw-bold">2.0</span><span id="configAlarmCpaUnits"> NM</span> </div> </div> <div class="row mb-3"> <div class="col-3 pe-0"> <label for="configAlarmTcpaRange" class="form-label">TCPA Less Than</label> </div> <div class="col-7"> <input type="range" class="form-range" id="configAlarmTcpaRange" min="1" max="12" step="1" data-target="configAlarmTcpa" data-alarm-type="danger" data-alarm-criteria="tcpa"> </div> <div class="col-2 text-end"> <span id="configAlarmTcpa" class="fw-bold">10</span><span> Min</span> </div> </div> <div class="row mb-3"> <div class="col-3 pe-0"> <label for="configAlarmSogRange" class="form-label">Speed Exceeds</label> </div> <div class="col-7"> <input type="range" class="form-range" id="configAlarmSogRange" min="0" max="10" step="1" data-target="configAlarmSog" data-alarm-type="danger" data-alarm-criteria="speed"> </div> <div class="col-2 text-end"> <span id="configAlarmSog" class="fw-bold">2.0</span><span> Knots</span> </div> </div> </li> <!--end collision alarm--> <!--guard alarm--> <li class="h5 bg-body-secondary list-group-item"> Guard Alarm </li> <li class="list-group-item"> <p class="card-text">Targets that meet both of the conditions below will be set to a <code>danger</code> state and shown in <code>red</code> in the plotter. </p> <div class="row mb-3"> <div class="col-3 pe-0"> <label for="configGuardRangeRange" class="form-label">Range Within</label> </div> <div class="col-7"> <input type="range" class="form-range" id="configGuardRangeRange" min="0" max="19" step="1" data-target="configGuardRange" data-alarm-type="guard" data-alarm-criteria="range"> </div> <div class="col-2 text-end"> <span id="configGuardRange" class="fw-bold">2.0</span><span id="configGuardRangeUnits"> NM</span> </div> </div> <div class="row mb-3"> <div class="col-3 pe-0"> <label for="configGuardSogRange" class="form-label">Speed Exceeds</label> </div> <div class="col-7"> <input type="range" class="form-range" id="configGuardSogRange" min="0" max="10" step="1" data-target="configGuardSog" data-alarm-type="guard" data-alarm-criteria="speed"> </div> <div class="col-2 text-end"> <span id="configGuardSog" class="fw-bold">2.0</span><span> Knots</span> </div> </div> </li> <!--end guard alarm--> </ul> </div> <!--end card--> </div> <!--end offcanvas-body--> </div> <!--end offcanvasProfile--> </div> <!--end container--> <script src="assets/js/bootstrap.bundle.min.js"></script> <script src="assets/js/leaflet.js"></script> <script src="assets/js/rbush.min.js"></script> <script src="assets/js/labelgun.min.js"></script> <script src="assets/js/easy-button.js"></script> <script src="assets/js/protomaps-leaflet.js"></script> <script src="assets/js/basemaps.js"></script> <script src="assets/js/NoSleep.min.js"></script> <script src="assets/js/script.js" type="module"></script> </body> </html>