您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds highlights and tools to WME to supplement the lanes feature
- "use strict";
- // ==UserScript==
- // @name WME LaneTools
- // @namespace https://github.com/SkiDooGuy/WME-LaneTools
- // @version 2025.06.26.001
- // @description Adds highlights and tools to WME to supplement the lanes feature
- // @author SkiDooGuy, Click Saver by HBiede, Heuristics by kndcajun, assistance by jm6087
- // @match https://www.waze.com/editor*
- // @match https://www.waze.com/*/editor*
- // @match https://beta.waze.com/editor*
- // @match https://beta.waze.com/*/editor*
- // @exclude https://www.waze.com/user/editor*
- // @require https://gf.qytechs.cn/scripts/24851-wazewrap/code/WazeWrap.js
- // @require https://cdn.jsdelivr.net/npm/@turf/turf@7.2.0/turf.min.js
- // @require https://cdn.jsdelivr.net/npm/proj4@2.17.0/dist/proj4.min.js
- // @grant GM_xmlhttpRequest
- // @grant unsafeWindow
- // @connect gf.qytechs.cn
- // @contributionURL https://github.com/WazeDev/Thank-The-Authors
- // ==/UserScript==
- /* global W */
- /* global WazeWrap */
- // import type { KeyboardShortcut, Node, Segment, Selection, Turn, UserSession, WmeSDK } from "wme-sdk-typings";
- // import type { Position } from "geojson";
- // import _ from "underscore";
- // import * as turf from "@turf/turf";
- // import WazeWrap from "https://gf.qytechs.cn/scripts/24851-wazewrap/code/WazeWrap.js";
- // import proj4 from "proj4";
- let sdk;
- unsafeWindow.SDK_INITIALIZED.then(() => {
- if (!unsafeWindow.getWmeSdk) {
- throw new Error("SDK is not installed");
- }
- sdk = unsafeWindow.getWmeSdk({
- scriptId: "wme-lane-tools",
- scriptName: "WME LaneTools",
- });
- console.log(`SDK v ${sdk.getSDKVersion()} on ${sdk.getWMEVersion()} initialized`);
- sdk.Events.once({ eventName: "wme-ready" }).then(ltInit);
- });
- function ltInit() {
- let Direction;
- (function (Direction) {
- Direction[Direction["REVERSE"] = -1] = "REVERSE";
- Direction[Direction["ANY"] = 0] = "ANY";
- Direction[Direction["FORWARD"] = 1] = "FORWARD";
- })(Direction || (Direction = {}));
- let LT_ROAD_TYPE;
- (function (LT_ROAD_TYPE) {
- // Streets
- LT_ROAD_TYPE[LT_ROAD_TYPE["NARROW_STREET"] = 22] = "NARROW_STREET";
- LT_ROAD_TYPE[LT_ROAD_TYPE["STREET"] = 1] = "STREET";
- LT_ROAD_TYPE[LT_ROAD_TYPE["PRIMARY_STREET"] = 2] = "PRIMARY_STREET";
- // Highways
- LT_ROAD_TYPE[LT_ROAD_TYPE["RAMP"] = 4] = "RAMP";
- LT_ROAD_TYPE[LT_ROAD_TYPE["FREEWAY"] = 3] = "FREEWAY";
- LT_ROAD_TYPE[LT_ROAD_TYPE["MAJOR_HIGHWAY"] = 6] = "MAJOR_HIGHWAY";
- LT_ROAD_TYPE[LT_ROAD_TYPE["MINOR_HIGHWAY"] = 7] = "MINOR_HIGHWAY";
- // Other drivable
- LT_ROAD_TYPE[LT_ROAD_TYPE["DIRT_ROAD"] = 8] = "DIRT_ROAD";
- LT_ROAD_TYPE[LT_ROAD_TYPE["FERRY"] = 14] = "FERRY";
- LT_ROAD_TYPE[LT_ROAD_TYPE["PRIVATE_ROAD"] = 17] = "PRIVATE_ROAD";
- LT_ROAD_TYPE[LT_ROAD_TYPE["PARKING_LOT_ROAD"] = 20] = "PARKING_LOT_ROAD";
- // Non-drivable
- LT_ROAD_TYPE[LT_ROAD_TYPE["WALKING_TRAIL"] = 5] = "WALKING_TRAIL";
- LT_ROAD_TYPE[LT_ROAD_TYPE["PEDESTRIAN_BOARDWALK"] = 10] = "PEDESTRIAN_BOARDWALK";
- LT_ROAD_TYPE[LT_ROAD_TYPE["STAIRWAY"] = 16] = "STAIRWAY";
- LT_ROAD_TYPE[LT_ROAD_TYPE["RAILROAD"] = 18] = "RAILROAD";
- LT_ROAD_TYPE[LT_ROAD_TYPE["RUNWAY"] = 19] = "RUNWAY";
- })(LT_ROAD_TYPE || (LT_ROAD_TYPE = {}));
- const MIN_DISPLAY_LEVEL = 14;
- const MIN_ZOOM_NON_FREEWAY = 17;
- // const DisplayLevels = {
- // MIN_ZOOM_ALL: 14,
- // MIN_ZOOM_NONFREEWAY: 17,
- // };
- let HeuristicsCandidate;
- (function (HeuristicsCandidate) {
- HeuristicsCandidate[HeuristicsCandidate["ERROR"] = -2] = "ERROR";
- HeuristicsCandidate[HeuristicsCandidate["FAIL"] = -1] = "FAIL";
- HeuristicsCandidate[HeuristicsCandidate["NONE"] = 0] = "NONE";
- HeuristicsCandidate[HeuristicsCandidate["PASS"] = 1] = "PASS";
- })(HeuristicsCandidate || (HeuristicsCandidate = {}));
- if (!WazeWrap.Ready) {
- setTimeout(() => {
- ltInit();
- }, 100);
- return;
- }
- const LANETOOLS_VERSION = `${GM_info.script.version}`;
- const GF_LINK = "https://gf.qytechs.cn/en/scripts/537219-wme-lanetools";
- const DOWNLOAD_URL = "https://gf.qytechs.cn/en/scripts/537219-wme-lanetools";
- const FORUM_LINK = "https://www.waze.com/discuss/t/script-wme-lanetools/53136";
- const LI_UPDATE_NOTES = `NEW:<br>
- - Conversion to WME SDK<br>
- - <b>ENABLE LT Layers To See Markings on the Map</b><br>
- - Point Updates to GF vs. GITHUB<br><br>
- KNOWN ISSUE:<br>
- - Some tab UI enhancements may not work as expected.<br>`;
- const LANETOOLS_DEBUG_LEVEL = 5;
- const configArray = {};
- const RBSArray = { failed: false };
- const IsBeta = location.href.indexOf("beta.waze.com") !== -1;
- const env = IsBeta ? "beta" : "production";
- const TAB_TRANSLATIONS = {
- // Default english values
- default: {
- enabled: "Enabled",
- disabled: "Disabled",
- toggleShortcut: "Toggle Shortcut",
- UIEnhance: "Tab UI Enhancements",
- autoWidth: "Auto-open road width",
- autoOpen: "Auto-open lanes tab",
- autoExpand: "Auto-expand lane editor",
- autoFocus: "Auto-focus lane input",
- reOrient: "Re-orient lane icons",
- enClick: "Enable ClickSaver",
- clickStraight: "All straight lanes",
- clickTurn: "Turn lanes",
- mapHighlight: "Map Highlights",
- laneLabel: "Lane labels",
- nodeHigh: "Node highlights",
- LAOHigh: "Lane angle overrides",
- CSOHigh: "Continue straight overrides",
- heuristics: "Lane heuristics candidates",
- posHeur: "Positive heuristics candidate",
- negHeur: "Negative heuristics candidate",
- highColor: "Highlight Colors",
- colTooltip: "Click to toggle color inputs",
- selAllTooltip: "Click on turn name to toggle all lane associations",
- fwdCol: "Fwd (A>B)",
- revCol: "Rev (B>A)",
- labelCol: "Labels",
- errorCol: "Lane errors",
- laneNodeCol: "Nodes with lanes",
- nodeTIOCol: "Nodes with TIOs",
- LAOCol: "Segs with TIOs",
- viewCSCol: "View only CS",
- hearCSCol: "View and hear CS",
- heurPosCol: "Lane heuristics likely",
- heurNegCol: "Lane heuristics - not qualified",
- advTools: "Advanced Tools",
- quickTog: "Quick toggle all lanes",
- showRBS: "Use RBS heuristics",
- delFwd: "Delete FWD Lanes",
- delRev: "Delete Rev Lanes",
- delOpp: "This segment is one-way but has lanes set in the opposite direction. Click here to delete them",
- csIcons: "Highlight CS Icons",
- highlightOverride: "Only highlight if segment layer active",
- addTIO: "Include TIO in lanes tab",
- labelTIO: "TIO",
- defaultTIO: "Waze Selected",
- noneTIO: "None",
- tlTIO: "Turn Left",
- trTIO: "Turn Right",
- klTIO: "Keep Left",
- krTIO: "Keep Right",
- conTIO: "Continue",
- elTIO: "Exit Left",
- erTIO: "Exit Right",
- uturnTIO: "U-Turn",
- enIcons: "Display lane icons on map",
- IconsRotate: "Rotate map icons with segment direction",
- },
- "en-us": {
- enabled: "Enabled",
- disabled: "Disabled",
- toggleShortcut: "Toggle Shortcut",
- UIEnhance: "Tab UI Enhancements",
- autoWidth: "Auto-open road width",
- autoOpen: "Auto-open lanes tab",
- autoExpand: "Auto-expand lane editor",
- autoFocus: "Auto-focus lane input",
- reOrient: "Re-orient lane icons",
- enClick: "Enable ClickSaver",
- clickStraight: "All straight lanes",
- clickTurn: "Turn lanes",
- mapHighlight: "Map Highlights",
- laneLabel: "Lane labels",
- nodeHigh: "Node highlights",
- LAOHigh: "Lane angle overrides",
- CSOHigh: "Continue straight overrides",
- heuristics: "Lane heuristics candidates",
- posHeur: "Positive heuristics candidate",
- negHeur: "Negative heuristics candidate",
- highColor: "Highlight Colors",
- colTooltip: "Click to toggle color inputs",
- selAllTooltip: "Click on turn name to toggle all lane associations",
- fwdCol: "Fwd (A>B)",
- revCol: "Rev (B>A)",
- labelCol: "Labels",
- errorCol: "Lane errors",
- laneNodeCol: "Nodes with lanes",
- nodeTIOCol: "Nodes with TIOs",
- LAOCol: "Segs with TIOs",
- viewCSCol: "View only CS",
- hearCSCol: "View and hear CS",
- heurPosCol: "Lane heuristics likely",
- heurNegCol: "Lane heuristics - not qualified",
- advTools: "Advanced Tools",
- quickTog: "Quick toggle all lanes",
- showRBS: "Use RBS heuristics",
- delFwd: "Delete FWD Lanes",
- delRev: "Delete Rev Lanes",
- delOpp: "This segment is one-way but has lanes set in the opposite direction. Click here to delete them",
- csIcons: "Highlight CS Icons",
- highlightOverride: "Only highlight if segment layer active",
- addTIO: "Include TIO in lanes tab",
- labelTIO: "TIO",
- defaultTIO: "Waze Selected",
- noneTIO: "None",
- tlTIO: "Turn Left",
- trTIO: "Turn Right",
- klTIO: "Keep Left",
- krTIO: "Keep Right",
- conTIO: "Continue",
- elTIO: "Exit Left",
- erTIO: "Exit Right",
- uturnTIO: "U-Turn",
- enIcons: "Display lane icons on map",
- IconsRotate: "Rotate map icons with segment direction",
- },
- };
- let MAX_LEN_HEUR; // Maximum length of segment where lane heuristics applied (Specified in Wiki).
- let MAX_PERP_DIF; // Updated 2020-09, based on experiments
- let MAX_PERP_DIF_ALT; // New 2020-09, based on experiments
- let MAX_PERP_TO_CONSIDER; // Don't even consider perp angles outside of this tolerance
- let MAX_STRAIGHT_TO_CONSIDER; // Don't even consider straight angles inside of this tolerance
- let MAX_STRAIGHT_DIF; // IN TESTING; updated 2020-09
- let lt_scanArea_recursive = 0;
- let LtSettings;
- let strings;
- // let _turnInfo = [];
- let _turnData = {};
- let laneCount = 0;
- const LTHighlightLayer = { name: "LT Highlights Layer" };
- const LTNamesLayer = { name: "LT Names Layer" };
- const LTLaneGraphics = { name: "LT Lane Graphics" };
- let _pickleColor;
- let UpdateObj;
- let MultiAction;
- let SetTurn;
- let shortcutsDisabled = false;
- let isRBS = false;
- let allowCpyPst = false;
- let langLocality = "default";
- let LANG;
- let seaPickle;
- function applyNodeHightlightStyle(properties) {
- return properties.styleName === "nodeStyle" && properties.layerName === LTHighlightLayer.name;
- }
- function applyVectorHightlightStyle(properties) {
- return properties.styleName === "vectorStyle" && properties.layerName === LTHighlightLayer.name;
- }
- function applyBoxStyle(properties) {
- return properties.styleName === "boxStyle" && properties.layerName === LTLaneGraphics.name;
- }
- function applyIconBoxStyle(properties) {
- return properties.styleName === "iconBoxStyle" && properties.layerName === LTLaneGraphics.name;
- }
- function applyIconStyle(properties) {
- return properties.styleName === "iconStyle" && properties.layerName === LTLaneGraphics.name;
- }
- const styleConfig = {
- styleContext: {
- nameStyleLabelColor: (context) => {
- return LtSettings.LabelColor;
- },
- nameStyleLaneNum: (context) => {
- return context?.feature?.properties?.style?.laneNumLabel;
- },
- highlightStrokeColor: (context) => {
- return context?.feature?.properties?.style?.stroke;
- },
- hightlightStrokeWidth: (context) => {
- return context?.feature?.properties?.style?.strokeWidth;
- },
- hightlightStrokeOpacity: (context) => {
- return context?.feature?.properties?.style?.strokeOpacity;
- },
- hightlightStrokeDashStyle: (context) => {
- return context?.feature?.properties?.style?.strokeDashstyle;
- },
- highlightFillColor: (context) => {
- return context?.feature?.properties?.style?.fillColor;
- },
- highlightPointRadius: (context) => {
- return context?.feature?.properties?.style?.pointRadius;
- },
- externalGraphic: (context) => {
- return context?.feature?.properties?.style?.externalGraphic;
- },
- graphicHeight: (context) => {
- return context?.feature?.properties?.style?.graphicHeight;
- },
- graphicWidth: (context) => {
- return context?.feature?.properties?.style?.graphicWidth;
- },
- rotation: (context) => {
- return context?.feature?.properties?.style?.rotation;
- },
- backgroundGraphic: (context) => {
- return context?.feature?.properties?.style?.backgroundGraphic;
- },
- backgroundHeight: (context) => {
- return context?.feature?.properties?.style?.backgroundHeight;
- },
- backgroundWidth: (context) => {
- return context?.feature?.properties?.style?.backgroundWidth;
- },
- backgroundXOffset: (context) => {
- return context?.feature?.properties?.style?.backgroundXOffset;
- },
- backgroundYOffset: (context) => {
- return context?.feature?.properties?.style?.backgroundYOffset;
- },
- },
- styleRules: [
- {
- predicate: (properties) => { return properties.layerName === LTNamesLayer.name; },
- style: {
- fontFamily: "Open Sans, Alef, helvetica, sans-serif, monospace",
- labelColor: "${nameStyleLabelColor}",
- labelText: "${nameStyleLaneNum}",
- labelOutlineColor: "black",
- fontColor: "${nameStyleLabelColor}",
- fontSize: "16",
- labelXOffset: 15,
- labelYOffset: -15,
- labelOutlineWidth: "3",
- label: "${nameStyleLaneNum}",
- angle: "",
- labelAlign: "cm",
- strokeWidth: 0,
- pointRadius: 0,
- },
- },
- {
- predicate: applyNodeHightlightStyle,
- style: {
- fillColor: "${highlightFillColor}",
- pointRadius: "${highlightPointRadius}",
- fillOpacity: 0.9,
- strokeWidth: 0,
- },
- },
- {
- predicate: applyVectorHightlightStyle,
- style: {
- strokeColor: "${highlightStrokeColor}",
- stroke: "${highlightStrokeColor}",
- strokeWidth: "${hightlightStrokeWidth}",
- strokeOpacity: "${hightlightStrokeOpacity}",
- strokeDashstyle: "${hightlightStrokeDashStyle}",
- },
- },
- {
- predicate: applyBoxStyle,
- style: {
- strokeColor: "#ffffff",
- strokeOpacity: 1,
- strokeWidth: 8,
- fillColor: "#ffffff",
- },
- },
- {
- predicate: applyIconBoxStyle,
- style: {
- strokeColor: "#000000",
- strokeOpacity: 1,
- strokeWidth: 1,
- fillColor: "#26bae8",
- },
- },
- {
- predicate: applyIconStyle,
- style: {
- externalGraphic: "${externalGraphic}",
- graphicHeight: "${graphicHeight}",
- graphicWidth: "${graphicWidth}",
- fillColor: "#26bae8",
- fillOpacity: 1,
- backgroundColor: "#26bae8",
- strokeColor: "#26bae8",
- rotation: "${rotation}",
- backgroundGraphic: "${backgroundGraphic}",
- backgroundHeight: "${backgroundHeight}",
- backgroundWidth: "${backgroundWidth}",
- backgroundXOffset: "${backgroundXOffset}",
- backgroundYOffset: "${backgroundYOffset}",
- },
- },
- ],
- };
- console.log("LaneTools: initializing...");
- function laneToolsBootstrap(tries = 0) {
- console.log("Lane Tools: Initializing...");
- initLaneTools();
- console.log("Lane Tools: Initialization Finished.");
- }
- function initLaneTools() {
- startScriptUpdateMonitor();
- seaPickle = sdk.State.getUserInfo();
- UpdateObj = require("Waze/Action/UpdateObject");
- MultiAction = require("Waze/Action/MultiAction");
- SetTurn = require("Waze/Model/Graph/Actions/SetTurn");
- const ltCss = [
- '.lt-wrapper {position:relative;width:100%;font-size:12px;font-family:"Rubik", "Boing-light", sans-serif;user-select:none;}',
- ".lt-section-wrapper {display:block;width:100%;padding:4px;}",
- ".lt-section-wrapper.border {border-bottom:1px solid grey;margin-bottom:5px;}",
- ".lt-option-container {padding:3px;}",
- ".lt-option-container.color {text-decoration:none;}",
- 'input[type="checkbox"].lt-checkbox {position:relative;top:3px;vertical-align:top;margin:0;}',
- 'input[type="text"].lt-color-input {position:relative;width:70px;padding:3px;border:2px solid black;border-radius:6px;}',
- 'input[type="text"].lt-color-input:focus {outline-width:0;}',
- "label.lt-label {position:relative;max-width:90%;font-weight:normal;padding-left:5px}",
- ".lt-Toolbar-Container {display:none;position:absolute;background-color:orange;border-radius:6px;border:1.5px solid;box-size:border-box;z-index:1050;}",
- ".lt-Toolbar-Wrapper {position:relative;padding:3px;}",
- ".lt-toolbar-button-container {display:inline-block;padding:5px;}",
- ".lt-toolbar-button {position:relative;display:block;width:60px;height:25px;border-radius:6px;font-size:12px;}",
- ".lt-add-Width {display:inline-block;width:15px;height:15px;border:1px solid black;border-radius:8px;margin:0 3px 0 3px;line-height: 1.5;text-align:center;font-size:10px;}",
- ".lt-add-Width:hover {border:1px solid #26bae8;background-color:#26bae8;cursor:pointer;}",
- ".lt-add-lanes {display:inline-block;width:15px;height:15px;border:1px solid black;border-radius:8px;margin:0 3px 0 3px;line-height: 1.5;text-align:center;font-size:10px;}",
- ".lt-add-lanes:hover {border:1px solid #26bae8;background-color:#26bae8;cursor:pointer;}",
- ".lt-chkAll-lns {display:inline-block;width:20px;height:20px;text-decoration:underline;font-weight:bold;font-size:10px;padding-left:3px;cursor:pointer;}",
- ".lt-tio-select {max-width:80%;color:rgb(32, 33, 36);background-color:rgb(242, 243, 244);border:0px;border-radius:6px;padding:0 16px 0 10px;cursor:pointer;}",
- "#lt-color-title {display:block;width:100%;padding:5px 0 5px 0;font-weight:bold;text-decoration:underline;cursor:pointer;}",
- ].join(" ");
- const $ltTab = $("<div>");
- $ltTab.html = [
- `<div class='lt-wrapper' id='lt-tab-wrapper'>
- <div class='lt-section-wrapper' id='lt-tab-body'>
- <div class='lt-section-wrapper border' style='border-bottom:2px double grey;'>
- <a href='https://www.waze.com/forum/viewtopic.php?f=819&t=301158' style='font-weight:bold;font-size:12px;text-decoration:underline;' target='_blank'>LaneTools - v${LANETOOLS_VERSION}</a>
- <div>
- <div style='display:inline-block;'><span class='lt-trans-tglshcut'></span>:<span id='lt-EnableShortcut' style='padding-left:10px;'></span></div>
- <div class='lt-option-container' style='float:right;'>
- <input type=checkbox class='lt-checkbox' id='lt-ScriptEnabled' />
- <label class='lt-label' for='lt-ScriptEnabled'><span class='lt-trans-enabled'></span></label>
- </div>
- </div>
- </div>
- <div class='lt-section-wrapper' id='lt-LaneTabFeatures'>
- <div class='lt-section-wrapper border'>
- <span style='font-weight:bold;'><span id='lt-trans-uiEnhance'></span></span>
- <div class='lt-option-container' style='float:right;'>
- <input type=checkbox class='lt-checkbox' id='lt-UIEnable' />
- <label class='lt-label' for='lt-UIEnable'><span class='lt-trans-enabled'></span></label>
- </div>
- </div>
- <div id='lt-UI-wrapper'>
- <div class='lt-option-container' style='margin-bottom:5px;'>
- <div style='display:inline-block;'><span class='lt-trans-tglshcut'></span>:<span id='lt-UIEnhanceShortcut' style='padding-left:10px;'></span></div>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-AutoOpenWidth' />
- <label class='lt-label' for='lt-AutoOpenWidth'><span id='lt-trans-autoWidth'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-AutoLanesTab' />
- <label class='lt-label' for='lt-AutoLanesTab'><span id='lt-trans-autoTab'></span></label>
- </div>
- <div class='lt-option-container' style='display:none;'>
- <input type=checkbox class='lt-checkbox' id='lt-AutoExpandLanes' />
- <label class='lt-label' for='lt-AutoExpandLanes'><span title="Feature disabled as of Aug 27, 2022 to prevent flickering issue" id='lt-trans-autoExpand'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-AutoFocusLanes' />
- <label class='lt-label' for='lt-AutoFocusLanes'><span id='lt-trans-autoFocus'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-highlightCSIcons' />
- <label class='lt-label' for='lt-highlightCSIcons'><span id='lt-trans-csIcons'></span></label>
- </div>
- <div class='lt-option-container' style='display:none;'>
- <input type=checkbox class='lt-checkbox' id='lt-ReverseLanesIcon' />
- <label class='lt-label' for='lt-ReverseLanesIcon'><span title="Feature disabled as of July 21, 2023 because lanes displayed wrong" id='lt-trans-orient'></span></label>
- </div>
- <div class='lt-option-container' style='display:none;'>
- <input type=checkbox class='lt-checkbox' id='lt-AddTIO' />
- <label class='lt-label' for='lt-AddTIO'><span id='lt-trans-AddTIO'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-ClickSaveEnable' />
- <label class='lt-label' for='lt-ClickSaveEnable'><span id='lt-trans-enClick'></span></label>
- </div>
- <div class='lt-option-container clk-svr' style='padding-left:10%;'>
- <input type=checkbox class='lt-checkbox' id='lt-ClickSaveStraight' />
- <label class='lt-label' for='lt-ClickSaveStraight'><span id='lt-trans-straClick'></span></label>
- </div>
- <div class='lt-option-container clk-svr' style='padding-left:10%;'>
- <input type=checkbox class='lt-checkbox' id='lt-ClickSaveTurns' />
- <label class='lt-label' for='lt-ClickSaveTurns'><span id='lt-trans-turnClick'></span></label>
- </div>
- </div>
- </div>
- <div class='lt-section-wrapper'>
- <div class='lt-section-wrapper border'>
- <span style='font-weight:bold;'><span id='lt-trans-mapHigh'></span></span>
- <div class='lt-option-container' style='float:right;'>
- <input type=checkbox class='lt-checkbox' id='lt-HighlightsEnable' />
- <label class='lt-label' for='lt-HighlightsEnable'><span class='lt-trans-enabled'></span></label>
- </div>
- </div>
- <div id='lt-highlights-wrapper'>
- <div class='lt-option-container' style='margin-bottom:5px;'>
- <div style='display:inline-block;'><span class='lt-trans-tglshcut'></span>:<span id='lt-HighlightShortcut' style='padding-left:10px;'></span></div>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-IconsEnable' />
- <label class='lt-label' for='lt-IconsEnable'><span id='lt-trans-enIcons'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-IconsRotate' />
- <label class='lt-label' for='lt-IconsRotate'><span id='lt-trans-IconsRotate'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-LabelsEnable' />
- <label class='lt-label' for='lt-LabelsEnable'><span id='lt-trans-lnLabel'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-NodesEnable' />
- <label class='lt-label' for='lt-NodesEnable'><span id='lt-trans-nodeHigh'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-LIOEnable' />
- <label class='lt-label' for='lt-LIOEnable'><span id='lt-trans-laOver'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-CSEnable' />
- <label class='lt-label' for='lt-CSEnable'><span id='lt-trans-csOver'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-highlightOverride' />
- <label class='lt-label' for='lt-highlightOverride'><span id='lt-trans-highOver'></span></label>
- </div>
- </div>
- </div>
- <div class='lt-section-wrapper'>
- <div class='lt-section-wrapper border'>
- <span style='font-weight:bold;'><span id='lt-trans-heurCan'></span></span>
- <div class='lt-option-container' style='float:right;'>
- <input type=checkbox class='lt-checkbox' id='lt-LaneHeuristicsChecks' />
- <label class='lt-label' for='lt-LaneHeuristicsChecks'><span class='lt-trans-enabled'></span></label>
- </div>
- </div>
- <div id='lt-heur-wrapper'>
- <div class='lt-option-container' style='margin-bottom:5px;'>
- <div style='display:inline-block;'><span class='lt-trans-tglshcut'></span>:<span id='lt-LaneHeurChecksShortcut' style='padding-left:10px;'></span></div>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-LaneHeurPosHighlight' />
- <label class='lt-label' for='lt-LaneHeurPosHighlight'><span id='lt-trans-heurPos'></span></label>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-LaneHeurNegHighlight' />
- <label class='lt-label' for='lt-LaneHeurNegHighlight'><span id='lt-trans-heurNeg'></span></label>
- </div>
- </div>
- </div>
- <div class='lt-section-wrapper'>
- <div class='lt-section-wrapper'>
- <span id='lt-color-title' data-original-title='${TAB_TRANSLATIONS[langLocality].colTooltip}'><span id='lt-trans-highCol'></span>:</span>
- <div id='lt-color-inputs' style='display:none;'>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-ABColor' />
- <label class='lt-label' for='lt-ABColor' id='lt-ABColorLabel'><span id='lt-trans-fwdCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-BAColor' />
- <label class='lt-label' for='lt-BAColor' id='lt-BAColorLabel'><span id='lt-trans-revCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-LabelColor' />
- <label class='lt-label' for='lt-LabelColor' id='lt-LabelColorLabel'><span id='lt-trans-labelCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-ErrorColor' />
- <label class='lt-label' for='lt-ErrorColor' id='lt-ErrorColorLabel'><span id='lt-trans-errorCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-NodeColor' />
- <label class='lt-label' for='lt-NodeColor' id='lt-NodeColorLabel'><span id='lt-trans-nodeCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-TIOColor' />
- <label class='lt-label' for='lt-TIOColor' id='lt-TIOColorLabel'><span id='lt-trans-tioCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-LIOColor' />
- <label class='lt-label' for='lt-TIOColor' id='lt-LIOColorLabel'><span id='lt-trans-laoCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-CS1Color' />
- <label class='lt-label' for='lt-CS1Color' id='lt-CS1ColorLabel'><span id='lt-trans-viewCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-CS2Color' />
- <label class='lt-label' for='lt-CS2Color' id='lt-CS2ColorLabel'><span id='lt-trans-hearCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-HeurColor' />
- <label class='lt-label' for='lt-HeurColor' id='lt-HeurColorLabel'><span id='lt-trans-posCol'></span></label>
- </div>
- <div class='lt-option-container color'>
- <input type=color class='lt-color-input' id='lt-HeurFailColor' />
- <label class='lt-label' for='lt-HeurFailColor' id='lt-HeurFailColorLabel'><span id='lt-trans-negCol'></span></label>
- </div>
- </div>
- </div>
- </div>
- <div class='lt-section-wrapper' id='lt-adv-tools' style='display:none;'>
- <div class='lt-section-wrapper border'>
- <span style='font-weight:bold;'><span id='lt-trans-advTools'>></span></span>
- </div>
- <div class='lt-option-container'>
- <input type=checkbox class='lt-checkbox' id='lt-SelAllEnable' />
- <label class='lt-label' for='lt-SelAllEnable' ><span id='lt-trans-quickTog'></span></label>
- </div>
- <div class='lt-option-container' id='lt-serverSelectContainer' style='display:none;'>
- <input type=checkbox class='lt-checkbox' id='lt-serverSelect' />
- <label class='lt-label' for='lt-serverSelect'><span id='lt-trans-heurRBS'></span></label>
- </div>
- <div class='lt-option-container' id='lt-cpy-pst' style='display:none;'>
- <input type=checkbox class='lt-checkbox' id='lt-CopyEnable' />
- <label class='lt-label' for='lt-CopyEnable'>Copy/Paste Lanes</label>
- <span style='font-weight: bold;'>(**Caution** - double check results, feature still in Dev)</span>
- </div>
- <div id='lt-sheet-link' style='display:none;'>
- <a href='https://docs.google.com/spreadsheets/d/1_3sF09sMOid_us37j5CQqJZlBGGr1vI_3Rrmp5K-KCQ/edit?usp=sharing' target='_blank'>LT Config Sheet</a>
- </div>
- </div>
- </div>
- </div>`,
- ].join(" ");
- const $ltButtons = $("<div>");
- $ltButtons.html([
- `<div class='lt-Toolbar-Container' id="lt-toolbar-container">
- <div class='lt-Toolbar-Wrapper'>
- <div class='lt-toolbar-button-container'>
- <button type='button' class='lt-toolbar-button' id='copyA-button'>Copy A</button>
- </div>
- <div class='lt-toolbar-button-container'>
- <button type='button' class='lt-toolbar-button' id='copyB-button'>Copy B</button>
- </div>
- <div class='lt-toolbar-button-container'>
- <button type='button' class='lt-toolbar-button' id='pasteA-button'>Paste A</button>
- </div>
- <div class='lt-toolbar-button-container'>
- <button type='button' class='lt-toolbar-button' id='pasteB-button'>Paste B</button>
- </div>
- </div>
- </div>`,
- ].join(" "));
- _pickleColor = seaPickle?.rank;
- const proceedReady = _pickleColor && _pickleColor >= 0;
- if (proceedReady) {
- // WazeWrap.Interface.Tab("LT", $ltTab.html, setupOptions, "LT");
- sdk.Sidebar.registerScriptTab().then((r) => {
- r.tabLabel.innerHTML = "LT";
- r.tabPane.innerHTML = $ltTab.html;
- setupOptions().then(() => {
- scanArea();
- lanesTabSetup();
- displayLaneGraphics();
- });
- });
- $(`<style type="text/css">${ltCss}</style>`).appendTo("head");
- $("#map").append($ltButtons.html());
- WazeWrap.Interface.ShowScriptUpdate(GM_info.script.name, GM_info.script.version, LI_UPDATE_NOTES, GF_LINK, FORUM_LINK);
- console.log("LaneTools: loaded");
- }
- else {
- console.error("LaneTools: loading error....");
- }
- }
- function startScriptUpdateMonitor() {
- try {
- const updateMonitor = new WazeWrap.Alerts.ScriptUpdateMonitor(GM_info.script.name, GM_info.script.version, DOWNLOAD_URL, GM_xmlhttpRequest, DOWNLOAD_URL);
- updateMonitor.start();
- }
- catch (ex) {
- // Report, but don't stop if ScriptUpdateMonitor fails.
- console.error("WME LaneTools:", ex);
- }
- }
- async function setupOptions() {
- function setOptionStatus() {
- // Set check boxes based on last use
- setChecked("lt-ScriptEnabled", LtSettings.ScriptEnabled);
- setChecked("lt-UIEnable", LtSettings.UIEnable);
- setChecked("lt-AutoOpenWidth", LtSettings.AutoOpenWidth);
- setChecked("lt-AutoExpandLanes", LtSettings.AutoExpandLanes);
- setChecked("lt-AutoLanesTab", LtSettings.AutoLanesTab);
- setChecked("lt-HighlightsEnable", LtSettings.HighlightsEnable);
- setChecked("lt-LabelsEnable", LtSettings.LabelsEnable);
- setChecked("lt-NodesEnable", LtSettings.NodesEnable);
- setChecked("lt-LIOEnable", LtSettings.LIOEnable);
- setChecked("lt-CSEnable", LtSettings.CSEnable);
- setChecked("lt-highlightOverride", LtSettings.highlightOverride);
- setChecked("lt-CopyEnable", LtSettings.CopyEnable);
- setChecked("lt-SelAllEnable", LtSettings.SelAllEnable);
- setChecked("lt-serverSelect", LtSettings.serverSelect);
- setChecked("lt-AutoFocusLanes", LtSettings.AutoFocusLanes);
- setChecked("lt-ReverseLanesIcon", LtSettings.ReverseLanesIcon);
- setChecked("lt-ClickSaveEnable", LtSettings.ClickSaveEnable);
- setChecked("lt-ClickSaveStraight", LtSettings.ClickSaveStraight);
- setChecked("lt-ClickSaveTurns", LtSettings.ClickSaveTurns);
- setChecked("lt-LaneHeurPosHighlight", LtSettings.LaneHeurPosHighlight);
- setChecked("lt-LaneHeurNegHighlight", LtSettings.LaneHeurNegHighlight);
- setChecked("lt-LaneHeuristicsChecks", LtSettings.LaneHeuristicsChecks);
- setChecked("lt-highlightCSIcons", LtSettings.highlightCSIcons);
- setChecked("lt-AddTIO", LtSettings.AddTIO);
- setChecked("lt-IconsEnable", LtSettings.IconsEnable);
- setChecked("lt-IconsRotate", LtSettings.IconsRotate);
- setValue("lt-ABColor", LtSettings.ABColor);
- setValue("lt-BAColor", LtSettings.BAColor);
- setValue("lt-LabelColor", LtSettings.LabelColor);
- setValue("lt-ErrorColor", LtSettings.ErrorColor);
- setValue("lt-NodeColor", LtSettings.NodeColor);
- setValue("lt-TIOColor", LtSettings.TIOColor);
- setValue("lt-LIOColor", LtSettings.LIOColor);
- setValue("lt-CS1Color", LtSettings.CS1Color);
- setValue("lt-CS2Color", LtSettings.CS2Color);
- setValue("lt-HeurColor", LtSettings.HeurColor);
- setValue("lt-HeurFailColor", LtSettings.HeurFailColor);
- if (!getId("lt-ClickSaveEnable")?.checked) {
- $(".lt-option-container.clk-svr").hide();
- }
- if (!getId("lt-UIEnable")?.checked) {
- $("#lt-UI-wrapper").hide();
- }
- if (!getId("lt-HighlightsEnable")?.checked) {
- $("#lt-highlights-wrapper").hide();
- }
- if (!getId("lt-LaneHeuristicsChecks")?.checked) {
- $("#lt-heur-wrapper").hide();
- }
- function setChecked(checkboxId, checked) {
- $(`#${checkboxId}`).prop("checked", checked);
- }
- function setValue(inputId, color) {
- const inputElem = $(`#${inputId}`);
- inputElem.attr("value", color);
- inputElem.css("border", `2px solid ${color}`);
- }
- }
- await loadSettings();
- await loadSpreadsheet();
- initLaneGuidanceClickSaver();
- // Layer for highlights
- sdk.Map.addLayer({
- layerName: LTHighlightLayer.name,
- styleRules: styleConfig.styleRules,
- zIndexing: true,
- styleContext: styleConfig.styleContext,
- });
- sdk.LayerSwitcher.addLayerCheckbox(LTHighlightLayer);
- sdk.Map.setLayerVisibility({
- layerName: LTHighlightLayer.name,
- visibility: LtSettings.highlightsVisible && LtSettings.HighlightsEnable,
- });
- // LTHighlightLayer = new OpenLayers.Layer.Vector("LTHighlightLayer", { uniqueName: "_LTHighlightLayer" });
- // W.map.addLayer(LTHighlightLayer);
- // LTHighlightLayer.setVisibility(true);
- // Layer for future use of lane association icons...
- // LTLaneGraphics = new OpenLayers.Layer.Vector("LTLaneGraphics", { uniqueName: "LTLaneGraphics" });
- // W.map.addLayer(LTLaneGraphics);
- // LTLaneGraphics.setVisibility(true);
- sdk.Map.addLayer({
- layerName: LTLaneGraphics.name,
- styleRules: styleConfig.styleRules,
- zIndexing: true,
- styleContext: styleConfig.styleContext,
- });
- sdk.LayerSwitcher.addLayerCheckbox(LTLaneGraphics);
- sdk.Map.setLayerVisibility({
- layerName: LTLaneGraphics.name,
- visibility: LtSettings.ltGraphicsVisible,
- });
- sdk.Events.on({
- eventName: "wme-layer-checkbox-toggled",
- eventHandler: (payload) => {
- sdk.Map.setLayerVisibility({
- layerName: payload.name,
- visibility: payload.checked,
- });
- if (payload.name === LTLaneGraphics.name) {
- LtSettings.ltGraphicsVisible = payload.checked;
- }
- else if (payload.name === LTHighlightLayer.name) {
- LtSettings.highlightsVisible = payload.checked;
- }
- else if (payload.name === LTNamesLayer.name) {
- LtSettings.ltNamesVisible = payload.checked;
- }
- saveSettings();
- if (payload.checked)
- scanArea();
- },
- });
- sdk.Events.on({
- eventName: "wme-save-finished",
- eventHandler: (payload) => {
- if (payload.success) {
- scanArea();
- lanesTabSetup();
- displayLaneGraphics();
- }
- },
- });
- sdk.Map.addLayer({
- layerName: LTNamesLayer.name,
- styleRules: styleConfig.styleRules,
- zIndexing: true,
- styleContext: styleConfig.styleContext,
- });
- // Layer for lane text
- sdk.LayerSwitcher.addLayerCheckbox(LTNamesLayer);
- sdk.Map.setLayerVisibility({
- layerName: LTNamesLayer.name,
- visibility: LtSettings.ltNamesVisible,
- });
- sdk.LayerSwitcher.setLayerCheckboxChecked({
- name: LTLaneGraphics.name,
- isChecked: LtSettings.ltGraphicsVisible,
- });
- sdk.LayerSwitcher.setLayerCheckboxChecked({
- name: LTHighlightLayer.name,
- isChecked: LtSettings.highlightsVisible,
- });
- sdk.LayerSwitcher.setLayerCheckboxChecked({ name: LTNamesLayer.name, isChecked: LtSettings.ltNamesVisible });
- sdk.Events.on({
- eventName: "wme-map-move-end",
- eventHandler: () => {
- scanArea();
- displayLaneGraphics();
- },
- });
- sdk.Events.on({
- eventName: "wme-map-zoom-changed",
- eventHandler: () => {
- scanArea();
- displayLaneGraphics();
- },
- });
- sdk.Events.on({
- eventName: "wme-selection-changed",
- eventHandler: () => {
- scanArea();
- lanesTabSetup();
- displayLaneGraphics();
- },
- });
- // Add keyboard shortcuts
- try {
- const enableHighlightsShortcut = {
- shortcutId: "enableHighlights",
- description: "Toggle lane highlights",
- callback: toggleHighlights,
- shortcutKeys: "",
- };
- sdk.Shortcuts.createShortcut(enableHighlightsShortcut);
- // new WazeWrap.Interface.Shortcut(
- // "enableHighlights",
- // "Toggle lane highlights",
- // "wmelt",
- // "Lane Tools",
- // LtSettings.enableHighlights,
- // toggleHighlights,
- // null
- // ).add();
- const enableUIEnhancementsShortcut = {
- callback: toggleUIEnhancements,
- shortcutId: "enableUIEnhancements",
- description: "Toggle UI Enhancements",
- shortcutKeys: "",
- };
- sdk.Shortcuts.createShortcut(enableUIEnhancementsShortcut);
- // new WazeWrap.Interface.Shortcut(
- // "enableUIEnhancements",
- // "Toggle UI enhancements",
- // "wmelt",
- // "Lane Tools",
- // LtSettings.enableUIEnhancements,
- // toggleUIEnhancements,
- // null
- // ).add();
- const enableHeuristicsShortcut = {
- callback: toggleLaneHeuristicsChecks,
- shortcutId: "enableHeuristics",
- description: "Toggle heuristic highlights",
- shortcutKeys: "",
- };
- sdk.Shortcuts.createShortcut(enableHeuristicsShortcut);
- // new WazeWrap.Interface.Shortcut(
- // "enableHeuristics",
- // "Toggle heuristic highlights",
- // "wmelt",
- // "Lane Tools",
- // LtSettings.enableHeuristics,
- // toggleLaneHeuristicsChecks,
- // null
- // ).add();
- const enableScriptShortcut = {
- shortcutId: "enableScript",
- description: "Toggle script",
- callback: toggleScript,
- shortcutKeys: "",
- };
- sdk.Shortcuts.createShortcut(enableScriptShortcut);
- // new WazeWrap.Interface.Shortcut(
- // "enableScript",
- // "Toggle script",
- // "wmelt",
- // "Lane Tools",
- // LtSettings.enableScript,
- // toggleScript,
- // null
- // ).add();
- }
- catch (e) {
- console.log("LT: Error creating shortcuts. This feature will be disabled.");
- $("#lt-EnableShortcut").text(`${TAB_TRANSLATIONS[langLocality].disabled}`);
- $("#lt-HighlightShortcut").text(`${TAB_TRANSLATIONS[langLocality].disabled}`);
- $("#lt-UIEnhanceShortcut").text(`${TAB_TRANSLATIONS[langLocality].disabled}`);
- $("#lt-LaneHeurChecksShortcut").text(`${TAB_TRANSLATIONS[langLocality].disabled}`);
- shortcutsDisabled = true;
- }
- // Setup user options now that the settings are loaded
- const highlights = $("#lt-HighlightsEnable");
- const colorTitle = $("#lt-color-title");
- const heurChecks = $("#lt-LaneHeuristicsChecks");
- setOptionStatus();
- setTimeout(() => {
- updateShortcutLabels();
- }, 50);
- setHeuristics();
- setLocalisation();
- if (_pickleColor && _pickleColor > 0) {
- let featureList = "LaneTools: The following special access features are enabled: ";
- $("#lt-adv-tools").css("display", "block");
- const quickTog = $("#lt-trans-quickTog");
- quickTog.attr("data-original-title", `${strings.selAllTooltip}`);
- quickTog.tooltip();
- _.each(RBSArray, (u) => {
- if (seaPickle !== null && u[0] === seaPickle.userName) {
- if (u[1] === "1") {
- isRBS = true;
- }
- if (u[2] === "1") {
- allowCpyPst = true;
- }
- }
- });
- if (isRBS) {
- $("#lt-serverSelectContainer").css("display", "block");
- featureList += "RBS Heuristics";
- }
- if (allowCpyPst) {
- $("#lt-sheet-link").css({
- display: "block",
- margin: "2px",
- });
- const ltSheetLinkAnchor = $("#lt-sheet-link > a");
- ltSheetLinkAnchor.css({
- padding: "2px",
- border: "2px solid black",
- "border-radius": "6px",
- "text-decoration": "none",
- });
- ltSheetLinkAnchor
- .on("mouseenter", function () {
- $(this).css("background-color", "orange");
- })
- .on("mouseleave", function () {
- $(this).css("background-color", "#eeeeee");
- });
- // $('#lt-cpy-pst').css('display', 'block');
- // $('.lt-Toolbar-Container').draggable({ containment: 'parent', zIndex: '100' });
- // WazeWrap.Events.register('selectionchanged', null, displayToolbar);
- $(".lt-toolbar-button").on("click", function () {
- if ($(this)[0].id === "copyA-button") {
- copyLaneInfo("A");
- }
- if ($(this)[0].id === "copyB-button") {
- copyLaneInfo("B");
- }
- if ($(this)[0].id === "pasteA-button") {
- pasteLaneInfo("A");
- }
- if ($(this)[0].id === "pasteB-button") {
- pasteLaneInfo("B");
- }
- });
- featureList = isRBS ? `${featureList}, Copy/Paste` : `${featureList}Copy/Paste`;
- }
- if (isRBS || allowCpyPst) {
- console.log(featureList);
- }
- }
- else {
- $("#lt-LaneTabFeatures").css("display", "none");
- }
- $(".lt-checkbox").on("click", function () {
- const settingName = $(this)[0].id.substring(3);
- LtSettings[settingName] = this.checked;
- saveSettings();
- });
- $(".lt-color-input").on("change", function () {
- const settingName = $(this)[0].id.substring(3);
- LtSettings[settingName] = this.value;
- saveSettings();
- $(`#lt-${settingName}`).css("border", `2px solid ${this.value}`);
- removeHighlights();
- scanArea();
- });
- $("#lt-ScriptEnabled").on("click", () => {
- if (getId("lt-ScriptEnabled")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- removeLaneGraphics();
- }
- });
- highlights.on("click", () => {
- if (getId("lt-HighlightsEnable")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- }
- scanArea();
- });
- $("#lt-LabelsEnable").on("click", () => {
- if (getId("lt-LabelsEnable")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- scanArea();
- }
- });
- $("#lt-NodesEnable").on("click", () => {
- if (getId("lt-NodesEnable")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- scanArea();
- }
- });
- $("#lt-LIOEnable").on("click", () => {
- if (getId("lt-LIOEnable")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- scanArea();
- }
- });
- $("#lt-IconsEnable").on("click", () => {
- if (getId("lt-IconsEnable")?.checked) {
- displayLaneGraphics();
- }
- else {
- removeLaneGraphics();
- }
- });
- $("#lt-highlightOverride").on("click", () => {
- if (getId("lt-highlightOverride")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- scanArea();
- }
- });
- colorTitle.on("click", () => {
- $("#lt-color-inputs").toggle();
- });
- $("#lt-ClickSaveEnable").on("click", () => {
- $(".lt-option-container.clk-svr").toggle();
- });
- $("#lt-UIEnable").on("click", () => {
- $("#lt-UI-wrapper").toggle();
- removeLaneGraphics();
- });
- highlights.on("click", () => {
- $("#lt-highlights-wrapper").toggle();
- });
- heurChecks.on("click", () => {
- $("#lt-heur-wrapper").toggle();
- });
- heurChecks.on("click", () => {
- if (getId("lt-LaneHeuristicsChecks")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- scanArea();
- }
- });
- $("#lt-LaneHeurPosHighlight").on("click", () => {
- if (getId("lt-LaneHeurPosHighlight")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- scanArea();
- }
- });
- $("#lt-LaneHeurNegHighlight").on("click", () => {
- if (getId("lt-LaneHeurNegHighlight")?.checked) {
- scanArea();
- }
- else {
- removeHighlights();
- scanArea();
- }
- });
- $("#lt-serverSelect").on("click", () => {
- setHeuristics();
- removeHighlights();
- scanArea();
- });
- // Watches for the shortcut dialog to close and updates UI
- const el = $.fn.hide;
- $.fn.hide = function () {
- this.trigger("hide");
- return el.apply(this, arguments);
- };
- $("#keyboard-dialog").on("hide", () => {
- checkShortcutsChanged();
- });
- colorTitle.tooltip();
- }
- async function loadSettings() {
- const localSettings = JSON.parse(localStorage.getItem("LT_Settings"));
- const serverSettings = await WazeWrap.Remote.RetrieveSettings("LT_Settings");
- if (!serverSettings) {
- console.error("LaneTools: Error communicating with WW settings server");
- }
- const defaultSettings = {
- lastSaveAction: 0,
- ScriptEnabled: true,
- UIEnable: true,
- AutoOpenWidth: false,
- AutoExpandLanes: false,
- AutoLanesTab: false,
- HighlightsEnable: true,
- LabelsEnable: true,
- NodesEnable: true,
- ABColor: "#990033",
- BAColor: "#0033cc",
- LabelColor: "#FFAD08",
- ErrorColor: "#F50E0E",
- NodeColor: "#66ccff",
- TIOColor: "#ff9900",
- LIOColor: "#ff9900",
- CS1Color: "#04E6F6",
- CS2Color: "#8F47FA",
- HeurColor: "#00aa00",
- HeurFailColor: "#E804F6",
- CopyEnable: false,
- SelAllEnable: false,
- serverSelect: false,
- LIOEnable: true,
- CSEnable: true,
- AutoFocusLanes: true,
- ReverseLanesIcon: false,
- ClickSaveEnable: true,
- ClickSaveStraight: false,
- ClickSaveTurns: true,
- enableScript: "",
- enableHighlights: "",
- enableUIEnhancements: "",
- enableHeuristics: "",
- LaneHeurNegHighlight: false,
- LaneHeurPosHighlight: false,
- LaneHeuristicsChecks: false,
- highlightCSIcons: false,
- highlightOverride: true,
- AddTIO: false,
- IconsEnable: true,
- IconsRotate: true,
- highlightsVisible: false,
- ltGraphicsVisible: false,
- ltNamesVisible: false,
- };
- LtSettings = $.extend({}, defaultSettings, localSettings);
- if (serverSettings && serverSettings.lastSaveAction > LtSettings.lastSaveAction) {
- $.extend(LtSettings, serverSettings);
- // console.log('LaneTools: server settings used');
- }
- else {
- // console.log('LaneTools: local settings used');
- }
- }
- async function saveSettings() {
- const { ScriptEnabled, HighlightsEnable, LabelsEnable, NodesEnable, UIEnable, AutoLanesTab, AutoOpenWidth, AutoExpandLanes, ABColor, BAColor, LabelColor, ErrorColor, NodeColor, TIOColor, LIOColor, CS1Color, CS2Color, CopyEnable, SelAllEnable, serverSelect, LIOEnable, CSEnable, AutoFocusLanes, ReverseLanesIcon, ClickSaveEnable, ClickSaveStraight, ClickSaveTurns, enableScript, enableHighlights, enableUIEnhancements, enableHeuristics, HeurColor, HeurFailColor, LaneHeurPosHighlight, LaneHeurNegHighlight, LaneHeuristicsChecks, highlightCSIcons, highlightOverride, AddTIO, IconsEnable, IconsRotate, highlightsVisible, ltGraphicsVisible, ltNamesVisible, } = LtSettings;
- const localSettings = {
- lastSaveAction: Date.now(),
- ScriptEnabled,
- HighlightsEnable,
- LabelsEnable,
- NodesEnable,
- UIEnable,
- AutoOpenWidth,
- AutoLanesTab,
- AutoExpandLanes,
- ABColor,
- BAColor,
- LabelColor,
- ErrorColor,
- NodeColor,
- TIOColor,
- LIOColor,
- CS1Color,
- CS2Color,
- CopyEnable,
- SelAllEnable,
- serverSelect,
- LIOEnable,
- CSEnable,
- AutoFocusLanes,
- ReverseLanesIcon,
- ClickSaveEnable,
- ClickSaveStraight,
- ClickSaveTurns,
- enableScript,
- enableHighlights,
- enableUIEnhancements,
- enableHeuristics,
- HeurColor,
- HeurFailColor,
- LaneHeurPosHighlight,
- LaneHeurNegHighlight,
- LaneHeuristicsChecks,
- highlightCSIcons,
- highlightOverride,
- AddTIO,
- IconsEnable,
- IconsRotate,
- highlightsVisible,
- ltGraphicsVisible,
- ltNamesVisible,
- };
- // Grab keyboard shortcuts and store them for saving
- // for (const name in W.accelerators.Actions) {
- // const { shortcut, group } = W.accelerators.Actions[name];
- // if (group === "wmelt") {
- for (const shortcut of sdk.Shortcuts.getAllShortcuts()) {
- localSettings[shortcut.shortcutId] = shortcut.shortcutKeys;
- }
- // Required for the instant update of changes to the keyboard shortcuts on the UI
- LtSettings = localSettings;
- if (localStorage) {
- localStorage.setItem("LT_Settings", JSON.stringify(localSettings));
- }
- const serverSave = await WazeWrap.Remote.SaveSettings("LT_Settings", localSettings);
- if (serverSave === null) {
- console.warn("LaneTools: User PIN not set in WazeWrap tab");
- }
- else {
- if (serverSave === false) {
- console.error("LaneTools: Unable to save settings to server");
- }
- }
- }
- async function loadSpreadsheet() {
- let connected = false;
- const apiKey = "AIzaSyDZjmkSx5xWc-86hsAIzedgDgRgy8vB7BQ";
- const settingsFailFunc = (jqXHR, _textStatus, errorThrown) => {
- console.error("LaneTools: Error loading settings:", errorThrown);
- };
- const rbsFailFunc = (_jqXHR, _textStatus, errorThrown) => {
- console.error("LaneTools: Error loading RBS:", errorThrown);
- if (!RBSArray.failed) {
- WazeWrap.Alerts.error(GM_info.script.name, "Unable to load heuristics data for LG. This feature will not be available");
- RBSArray.failed = true;
- }
- };
- const translationsFailFunc = (jqXHR, textStatus, errorThrown) => {
- console.error("LaneTools: Error loading trans:", errorThrown);
- };
- try {
- await $.getJSON(`https://sheets.googleapis.com/v4/spreadsheets/1_3sF09sMOid_us37j5CQqJZlBGGr1vI_3Rrmp5K-KCQ/values/Translations!A2:C?key=${apiKey}`)
- .done(async (transArray) => {
- if (transArray.values.length > 0) {
- _.each(transArray.values, (t) => {
- if (!TAB_TRANSLATIONS[t[1]] && Number.parseInt(t[2], 10) === 1) {
- TAB_TRANSLATIONS[t[1]] = JSON.parse(t[0]);
- }
- });
- }
- else {
- translationsFailFunc(null, null, "Failed to get any translations");
- }
- })
- .fail(translationsFailFunc);
- }
- catch (e) {
- translationsFailFunc(null, null, e);
- }
- try {
- await $.getJSON(`https://sheets.googleapis.com/v4/spreadsheets/1_3sF09sMOid_us37j5CQqJZlBGGr1vI_3Rrmp5K-KCQ/values/Angles!A2:B?key=${apiKey}`)
- .done((serverSettings) => {
- if (serverSettings.values.length > 0) {
- _.each(serverSettings.values, (v) => {
- if (!configArray[v[1]]) {
- configArray[v[1]] = JSON.parse(v[0]);
- }
- });
- connected = true;
- }
- else {
- settingsFailFunc();
- }
- })
- .fail(settingsFailFunc);
- }
- catch (e) {
- settingsFailFunc(null, null, e);
- }
- try {
- await $.getJSON(`https://sheets.googleapis.com/v4/spreadsheets/1_3sF09sMOid_us37j5CQqJZlBGGr1vI_3Rrmp5K-KCQ/values/RBS_Access!A2:C?key=${apiKey}`)
- .done((allowedRBS) => {
- if (allowedRBS.values.length > 0) {
- for (let i = 0; i < allowedRBS.values.length; i++) {
- RBSArray[i] = allowedRBS.values[i];
- }
- RBSArray.failed = false;
- }
- else {
- rbsFailFunc();
- }
- })
- .fail(rbsFailFunc);
- }
- catch (e) {
- rbsFailFunc(null, null, e);
- }
- if (connected) {
- _.each(configArray, (serverKey) => {
- for (const k in serverKey) {
- if (serverKey.hasOwnProperty(k)) {
- const keyValue = serverKey[k];
- serverKey[k] = Number.parseFloat(keyValue);
- }
- }
- });
- }
- }
- function setLocalisation() {
- // langLocality = I18n.currentLocale().toLowerCase();
- const locale = sdk.Settings.getLocale();
- LANG = locale.localeCode.toLowerCase();
- if (!(LANG in TAB_TRANSLATIONS))
- langLocality = "en-us";
- else
- langLocality = LANG;
- if (!(langLocality in TAB_TRANSLATIONS)) {
- langLocality = "en";
- }
- if (TAB_TRANSLATIONS[langLocality]) {
- strings = TAB_TRANSLATIONS[langLocality];
- }
- else if (langLocality.includes("-") && TAB_TRANSLATIONS[langLocality.split("-")[0]]) {
- strings = TAB_TRANSLATIONS[langLocality.split("-")[0]];
- }
- // If there is no value set in any of the translated strings then use the defaults
- for (const transString of Object.keys(strings)) {
- if (strings[transString] === "") {
- strings[transString] = TAB_TRANSLATIONS.default[transString];
- }
- }
- $(".lt-trans-enabled").text(strings.enabled);
- $(".lt-trans-tglshcut").text(strings.toggleShortcut);
- $("#lt-trans-uiEnhance").text(strings.UIEnhance);
- $("#lt-trans-autoTab").text(strings.autoOpen);
- $("#lt-trans-autoWidth").text(strings.autoWidth);
- $("#lt-trans-autoExpand").text(strings.autoExpand);
- $("#lt-trans-autoFocus").text(strings.autoFocus);
- $("#lt-trans-orient").text(strings.reOrient);
- $("#lt-trans-enClick").text(strings.enClick);
- $("#lt-trans-straClick").text(strings.clickStraight);
- $("#lt-trans-turnClick").text(strings.clickTurn);
- $("#lt-trans-mapHigh").text(strings.mapHighlight);
- $("#lt-trans-lnLabel").text(strings.laneLabel);
- $("#lt-trans-nodeHigh").text(strings.nodeHigh);
- $("#lt-trans-laOver").text(strings.LAOHigh);
- $("#lt-trans-csOver").text(strings.CSOHigh);
- $("#lt-trans-heurCan").text(strings.heuristics);
- $("#lt-trans-heurPos").text(strings.posHeur);
- $("#lt-trans-heurNeg").text(strings.negHeur);
- $("#lt-trans-highCol").text(strings.highColor);
- $("#lt-trans-fwdCol").text(strings.fwdCol);
- $("#lt-trans-revCol").text(strings.revCol);
- $("#lt-trans-labelCol").text(strings.labelCol);
- $("#lt-trans-errorCol").text(strings.errorCol);
- $("#lt-trans-nodeCol").text(strings.laneNodeCol);
- $("#lt-trans-tioCol").text(strings.nodeTIOCol);
- $("#lt-trans-laoCol").text(strings.LAOCol);
- $("#lt-trans-viewCol").text(strings.viewCSCol);
- $("#lt-trans-hearCol").text(strings.hearCSCol);
- $("#lt-trans-posCol").text(strings.heurPosCol);
- $("#lt-trans-negCol").text(strings.heurNegCol);
- $("#lt-trans-advTools").text(strings.advTools);
- $("#lt-trans-quickTog").text(strings.quickTog);
- $("#lt-trans-heurRBS").text(strings.showRBS);
- $("#lt-trans-csIcons").text(strings.csIcons);
- $("#lt-trans-highOver").text(strings.highlightOverride);
- $("#lt-trans-AddTIO").text(strings.addTIO);
- $("#lt-trans-enIcons").text(strings.enIcons);
- $("#lt-trans-IconsRotate").text(strings.IconsRotate);
- $("#lt-color-title").attr("data-original-title", strings.colTooltip);
- if (shortcutsDisabled) {
- $("#lt-EnableShortcut").text(`${strings.disabled}`);
- $("#lt-HighlightShortcut").text(`${strings.disabled}`);
- $("#lt-UIEnhanceShortcut").text(`${strings.disabled}`);
- $("#lt-LaneHeurChecksShortcut").text(`${strings.disabled}`);
- }
- }
- function setHeuristics() {
- if (RBSArray.failed) {
- return;
- }
- const angles = isRBS && getId("lt-serverSelect").checked ? configArray.RBS : configArray.RPS;
- MAX_LEN_HEUR = angles.MAX_LEN_HEUR;
- MAX_PERP_DIF = angles.MAX_PERP_DIF;
- MAX_PERP_DIF_ALT = angles.MAX_PERP_DIF_ALT;
- MAX_PERP_TO_CONSIDER = angles.MAX_PERP_TO_CONSIDER;
- MAX_STRAIGHT_TO_CONSIDER = angles.MAX_STRAIGHT_TO_CONSIDER;
- MAX_STRAIGHT_DIF = angles.MAX_STRAIGHT_DIF;
- }
- // Checks the WME value of a shortcut (from the shortcut menu) against the scripts value and saves if they are different
- function checkShortcutsChanged() {
- let triggerSave = false;
- for (const name in W.accelerators.Actions) {
- const { shortcut, group } = W.accelerators.Actions[name];
- if (group === "wmelt") {
- let TempKeys = "";
- if (shortcut) {
- if (shortcut.altKey === true) {
- TempKeys += "A";
- }
- if (shortcut.shiftKey === true) {
- TempKeys += "S";
- }
- if (shortcut.ctrlKey === true) {
- TempKeys += "C";
- }
- if (TempKeys !== "") {
- TempKeys += "+";
- }
- if (shortcut.keyCode) {
- TempKeys += shortcut.keyCode;
- }
- }
- else {
- TempKeys = "-1";
- }
- if (LtSettings[name] !== TempKeys) {
- triggerSave = true;
- console.log(`LaneTools: Stored shortcut ${name}: ${LtSettings[name]} changed to ${TempKeys}`);
- break;
- }
- }
- }
- if (triggerSave) {
- saveSettings();
- setTimeout(() => {
- updateShortcutLabels();
- }, 200);
- }
- }
- // Pulls the keyboard shortcuts from the script and returns a machine value
- function getKeyboardShortcut(shortcut) {
- if (shortcut === null)
- return null;
- const keys = LtSettings[shortcut];
- if (typeof keys !== "string")
- return null;
- let val = "";
- if (keys.indexOf("+") > -1) {
- const specialKeys = keys.split("+")[0];
- for (let i = 0; i < specialKeys.length; i++) {
- if (val.length > 0) {
- val += "+";
- }
- if (specialKeys[i] === "C") {
- val += "Ctrl";
- }
- if (specialKeys[i] === "S") {
- val += "Shift";
- }
- if (specialKeys[i] === "A") {
- val += "Alt";
- }
- }
- if (val.length > 0) {
- val += "+";
- }
- let num = Number.parseInt(keys.split("+")[1]);
- if (num >= 96 && num <= 105) {
- // Numpad keys
- num -= 48;
- val += "[num pad]";
- }
- val += String.fromCharCode(num);
- }
- else {
- let num = Number.parseInt(keys, 10);
- if (num >= 96 && num <= 105) {
- // Numpad keys
- num -= 48;
- val += "[num pad]";
- }
- val += String.fromCharCode(num);
- }
- return val;
- }
- // Updates the UI tab with the shortcut values
- function updateShortcutLabels() {
- if (!shortcutsDisabled) {
- $("#lt-EnableShortcut").text(getKeyboardShortcut("enableScript") || "");
- $("#lt-HighlightShortcut").text(getKeyboardShortcut("enableHighlights") || "");
- $("#lt-UIEnhanceShortcut").text(getKeyboardShortcut("enableUIEnhancements") || "");
- $("#lt-LaneHeurChecksShortcut").text(getKeyboardShortcut("enableHeuristics") || "");
- }
- }
- function getLegacySegObj(id) {
- return W.model.segments.getObjectById(id);
- }
- function getSegObj(id) {
- if (!id)
- return null;
- return sdk.DataModel.Segments.getById({ segmentId: id });
- }
- function getNodeObj(id) {
- if (id === null)
- return null;
- return sdk.DataModel.Nodes.getById({ nodeId: id });
- }
- function getLegacyNodeObj(id) {
- return W.model.nodes.getObjectById(id);
- }
- function lanesTabSetup() {
- // hook into edit panel on the left
- if (getId("edit-panel")?.getElementsByTagName("wz-tabs").length === 0) {
- setTimeout(lanesTabSetup, 500);
- //console.log('Edit panel not yet loaded.');
- return;
- }
- // const selSeg = W.selectionManager.getSelectedWMEFeatures();
- const selection = sdk.Editing.getSelection();
- let fwdDone = false;
- let revDone = false;
- let isRotated = false;
- let expandEditTriggered = false;
- // Highlights junction node when hovering over left panel
- function hoverNodeTo() {
- // W.model.nodes.getObjectById(W.selectionManager.getSegmentSelection().segments[0].attributes.toNodeID)
- // .attributes.geometry;
- // W.model.nodes.get(W.selectionManager.getSegmentSelection().segments[0].attributes.toNodeID).attributes.geometry
- const selSeg = isSegmentSelected(selection)
- ? sdk.DataModel.Segments.getById({ segmentId: selection?.ids[0] })
- : null;
- const nodeB = selSeg?.toNodeId ? sdk.DataModel.Nodes.getById({ nodeId: selSeg.toNodeId }) : null;
- nodeB && document.getElementById(nodeB?.id.toString());
- // document.getElementById(
- // W.model.nodes.getObjectById(W.selectionManager.getSegmentSelection().segments[0].attributes.toNodeID)
- // .attributes.geometry.id
- // );
- // document.getElementById(W.model.nodes.get(W.selectionManager.getSegmentSelection().segments[0].attributes.toNodeID).attributes.geometry.id)
- console.log("hovering to B");
- }
- function hoverNodeFrom() {
- // W.model.nodes.getObjectById(W.selectionManager.getSegmentSelection().segments[0].attributes.fromNodeID)
- // .attributes.geometry;
- const selSeg = isSegmentSelected(selection)
- ? sdk.DataModel.Segments.getById({ segmentId: selection?.ids[0] })
- : null;
- const nodeA = selSeg?.fromNodeId ? sdk.DataModel.Nodes.getById({ nodeId: selSeg.fromNodeId }) : null;
- nodeA && document.getElementById(nodeA?.id.toString());
- // W.model.nodes.get(W.selectionManager.getSegmentSelection().segments[0].attributes.fromNodeID).attributes.geometry
- // document.getElementById(
- // W.model.nodes.getObjectById(W.selectionManager.getSegmentSelection().segments[0].attributes.fromNodeID)
- // .attributes.geometry.id
- // );
- // document.getElementById(W.model.nodes.get(W.selectionManager.getSegmentSelection().segments[0].attributes.fromNodeID).attributes.geometry.id)
- console.log("hovering to A");
- }
- function showAddLaneGuidance(laneDir) {
- insertSelAll(laneDir);
- addLnsBtns(laneDir);
- adjustSpace();
- focusEle();
- applyButtonListeners();
- // if (getId("lt-AddTIO")?.checked) addTIOUI(laneDir);
- }
- function updateUI() {
- // if (eventInfo !== null) {
- // eventInfo.stopPropagation();
- // }
- // if (getId('lt-ReverseLanesIcon').checked && !isRotated) {
- // rotateArrows();
- // }
- if (getId("lt-highlightCSIcons")?.checked) {
- colorCSDir();
- }
- // Add delete buttons and preselected lane number buttons to UI
- if (_pickleColor && _pickleColor >= 1) {
- const selSeg = isSegmentSelected(selection)
- ? sdk.DataModel.Segments.getById({ segmentId: selection?.ids[0] })
- : null;
- if (getId("li-del-opp-btn"))
- $("#li-del-opp-btn").remove();
- if (getId("li-del-fwd-btn"))
- $("#li-del-fwd-btn").remove();
- if (getId("li-del-rev-btn"))
- $("#li-del-rev-btn").remove();
- const $fwdButton = $(`<button type="button" id="li-del-fwd-btn" style="height:20px;background-color:white;border:1px solid grey;border-radius:8px;">${strings.delFwd}</button>`);
- const $revButton = $(`<button type="button" id="li-del-rev-btn" style="height:20px;background-color:white;border:1px solid grey;border-radius:8px;">${strings.delRev}</button>`);
- const $oppButton = $(`<button type="button" id="li-del-opp-btn" style="height:auto;background-color:orange;border:1px solid grey;border-radius:8px; margin-bottom:5px;">${strings.delOpp}</button>`);
- const $btnCont1 = $('<div style="display:inline-block;position:relative;" />');
- const $btnCont2 = $('<div style="display:inline-block;position:relative;" />');
- const $btnCont3 = $('<div style="display:inline-block;position:relative;" />');
- $fwdButton.appendTo($btnCont1);
- $revButton.appendTo($btnCont2);
- $oppButton.appendTo($btnCont3);
- const delFwd = $("#li-del-fwd-btn");
- const delRev = $("#li-del-rev-btn");
- const delOpp = $("#li-del-opp-btn");
- delFwd.off();
- delRev.off();
- delOpp.off();
- if (!getId("li-del-rev-btn") && !revDone && selSeg?.toNodeLanesCount && selSeg.toNodeLanesCount > 0) {
- if ($(".rev-lanes > div.lane-instruction.lane-instruction-from > div.instruction").length > 0) {
- $btnCont2.prependTo(".rev-lanes > div.lane-instruction.lane-instruction-from > div.instruction");
- $(".rev-lanes > div.lane-instruction.lane-instruction-from > div.instruction").css("border-bottom", `4px dashed ${LtSettings.BAColor}`);
- }
- else if (selSeg.isAtoB) {
- //jm6087
- $oppButton.prop("title", "rev");
- $oppButton.prependTo("#edit-panel > div > div > div > div.segment-edit-section > wz-tabs > wz-tab.lanes-tab");
- }
- }
- else {
- $(".rev-lanes > div.lane-instruction.lane-instruction-from > div.instruction").css("border-bottom", `4px dashed ${LtSettings.BAColor}`);
- }
- if (!getId("li-del-fwd-btn") &&
- !fwdDone &&
- selSeg?.fromNodeLanesCount &&
- selSeg.fromNodeLanesCount > 0) {
- if ($(".fwd-lanes > div.lane-instruction.lane-instruction-from > div.instruction").length > 0) {
- $btnCont1.prependTo(".fwd-lanes > div.lane-instruction.lane-instruction-from > div.instruction");
- $(".fwd-lanes > div.lane-instruction.lane-instruction-from > div.instruction").css("border-bottom", `4px dashed ${LtSettings.ABColor}`);
- }
- else if (selSeg.isBtoA) {
- //jm6087
- $oppButton.prop("title", "fwd");
- $oppButton.prependTo("#edit-panel > div > div > div > div.segment-edit-section > wz-tabs > wz-tab.lanes-tab");
- }
- }
- else {
- $(".fwd-lanes > div.lane-instruction.lane-instruction-from > div.instruction").css("border-bottom", `4px dashed ${LtSettings.ABColor}`);
- }
- $("#li-del-fwd-btn").on("click", () => {
- delLanes("fwd");
- fwdDone = true;
- setTimeout(() => {
- updateUI();
- }, 200);
- });
- $("#li-del-rev-btn").on("click", () => {
- delLanes("rev");
- revDone = true;
- setTimeout(() => {
- updateUI();
- }, 200);
- });
- $("#li-del-opp-btn").on("click", function () {
- const dir = $(this).prop("title");
- delLanes(dir);
- if (dir === "rev") {
- revDone = true;
- }
- else {
- fwdDone = true;
- }
- updateUI();
- });
- }
- waitForElementLoaded(".fwd-lanes > div.lane-instruction.lane-instruction-to > div.instruction > div.lane-edit > .edit-lane-guidance").then((elem) => {
- $(elem).off();
- $(elem).on("click", () => {
- showAddLaneGuidance("fwd");
- });
- });
- waitForElementLoaded(".rev-lanes > div.lane-instruction.lane-instruction-to > div.instruction > div.lane-edit > .edit-lane-guidance").then((elem) => {
- $(elem).off();
- $(elem).on("click", () => {
- showAddLaneGuidance("rev");
- });
- });
- if (!fwdDone && !revDone && !expandEditTriggered) {
- expandEdit();
- }
- adjustSpace();
- }
- function applyButtonListeners() {
- $(".apply-button.waze-btn.waze-btn-blue").off();
- $(".cancel-button").off();
- const fwdLanes = $(".fwd-lanes");
- const revLanes = $(".rev-lanes");
- fwdLanes.find(".apply-button.waze-btn.waze-btn-blue").on("click", () => {
- fwdDone = true;
- updateUI();
- });
- revLanes.find(".apply-button.waze-btn.waze-btn-blue").on("click", () => {
- revDone = true;
- updateUI();
- });
- fwdLanes.find(".cancel-button").on("click", () => {
- fwdDone = true;
- updateUI();
- });
- revLanes.find(".cancel-button").on("click", () => {
- revDone = true;
- updateUI();
- });
- }
- function expandEdit() {
- expandEditTriggered = true;
- if (getId("lt-AutoExpandLanes")?.checked) {
- if (!fwdDone) {
- }
- if (!revDone) {
- }
- }
- if (getId("lt-AutoOpenWidth")?.checked) {
- if (!fwdDone) {
- $(".fwd-lanes").find(".set-road-width > wz-button").trigger("click"); // ADDED
- }
- if (!revDone) {
- $(".rev-lanes").find(".set-road-width > wz-button").trigger("click"); // ADDED
- }
- }
- }
- function adjustSpace() {
- $(".fwd-lanes > div > .direction-lanes").css({ padding: "5px 5px 10px", "margin-bottom": "10px" });
- $(".rev-lanes > div > .direction-lanes").css({ padding: "5px 5px 10px", margin: "0px" });
- $(".fwd-lanes > div > .lane-instruction.lane-instruction-to > .instruction > .lane-edit > .edit-region > div > .controls.direction-lanes-edit").css("padding-top", "10px");
- $(".rev-lanes > div > .lane-instruction.lane-instruction-to > .instruction > .lane-edit > .edit-region > div > .controls.direction-lanes-edit").css("padding-top", "10px");
- $(".fwd-lanes > div.lane-instruction.lane-instruction-to > div.instruction > div.edit-region > div > div > div:nth-child(1)").css("margin-bottom", "4px");
- $(".rev-lanes > div.lane-instruction.lane-instruction-to > div.instruction > div.edit-region > div > div > div:nth-child(1)").css("margin-bottom", "4px");
- }
- function getLaneItems(count, class_names_list) {
- const itemsList = [];
- const classString = class_names_list.join(" ");
- const idStringBase = class_names_list.join("-");
- for (let i = 1; i <= count; ++i) {
- const idString = `${idStringBase}-${i.toString()}`;
- const selectorString = `<div class="${classString}" id="${idString}">${i.toString()}</div>`;
- const newItem = $(selectorString).css({
- padding: "1px 1px 1px 1px",
- margin: "0 3px 0 3px",
- border: "1px solid black",
- "border-radius": "8px",
- "border-color": "black",
- height: "15px",
- width: "15px",
- "text-align": "center",
- "line-height": "1.5",
- "font-size": "10px",
- display: "inline-block",
- });
- $(selectorString).on("hover", function () {
- $(this).css({
- border: "1px solid #26bae8",
- "background-color": "#26bae8",
- cursor: "pointer",
- });
- });
- itemsList.push(newItem);
- }
- return itemsList;
- }
- function setupLaneCountControls(parentSelector, classNamesList) {
- const jqueryClassSelector = `.${classNamesList.join(".")}`;
- $(jqueryClassSelector).on("click", function () {
- $(jqueryClassSelector).css({ "background-color": "transparent", color: "black" });
- $(this).css({ "background-color": "navy", color: "white" });
- });
- }
- function addLnsBtns(laneDir) {
- // Add predetermined lane values
- if (laneDir !== "fwd" && laneDir !== "rev") {
- throw new Error(`Direction ${laneDir} is not supported`);
- }
- const dirLanesClass = `.${laneDir}-lanes`;
- const addLanesTag = `lt-${laneDir}-add-lanes`;
- const addWidthTag = `lt-${laneDir}-add-Width`;
- const lanes = $(dirLanesClass);
- if (lanes.find(".lane-instruction-to").children().length > 0x0 && !getId(addLanesTag)) {
- const addLanesItem = $(`<div style="display:inline-flex;flex-direction:row;justify-content:space-around;margin-top:4px;position:relative;" id="${addLanesTag}" />`);
- const classNamesList = ["lt-add-lanes", laneDir];
- const laneCountsToAppend = getLaneItems(10, classNamesList);
- for (let idx = 0; idx < laneCountsToAppend.length; ++idx) {
- addLanesItem.append(laneCountsToAppend[idx]);
- }
- const prependSelector = `${dirLanesClass} > div.lane-instruction.lane-instruction-to > div.instruction > div.edit-region > div`;
- // let prependSelector = dirLanesClass + "> div > div > div.lane-instruction.lane-instruction-to > div.instruction > div.edit-region > div.controls.direction-lanes-edit > div.form-group > div.controls-container";
- waitForElementLoaded(prependSelector).then((elm) => {
- const prependElement = $(prependSelector);
- prependElement.prepend(addLanesItem);
- setupLaneCountControls(lanes, classNamesList);
- $(".lt-add-lanes").on("click", function () {
- const numAddStr = $(this).text();
- const numAdd = Number.parseInt(numAddStr, 10);
- if ($(this).hasClass(`lt-add-lanes ${laneDir}`)) {
- // As of React >=15.6. Triggering change or input events on the input form cannot be
- // done via jquery selectors. Which means that they have to be triggered via
- // React native calls.
- const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
- const inputForm = document.querySelector(`wz-card${dirLanesClass} input[name=laneCount]`);
- nativeInputValueSetter.call(inputForm, numAdd);
- const inputEvent = new Event("input", { bubbles: true });
- inputForm?.dispatchEvent(inputEvent);
- const changeEvent = new Event("change", { bubbles: true });
- inputForm?.dispatchEvent(changeEvent);
- }
- });
- });
- }
- // if (revLanes.find(".direction-lanes").children().length > 0x0 && !getId("lt-rev-add-lanes")) {
- // let revLanesItem = $(
- // '<div style="display:inline-flex;flex-direction:row;justify-content:space-around;margin-top:4px;" id="lt-rev-add-lanes" />'),
- // classNamesList = [ "lt-add-lanes", "rev" ], laneCountsToAppend = getLaneItems(10, classNamesList);
- // for (let idx = 0; idx < laneCountsToAppend.length; ++idx) {
- // revLanesItem.append(laneCountsToAppend[idx]);
- // }
- // let prependSelector = '.rev-lanes > div > div > div.lane-instruction.lane-instruction-to > div.instruction > div.edit-region > div.controls.direction-lanes-edit > div.form-group > div.controls-container';
- // waitForElementLoaded(prependSelector).then((elm) => {
- // let revPrependTo = $(prependSelector);
- // revPrependTo.prepend(revLanesItem);
- // // revLanesItem.appendTo('.rev-lanes > div > div > div.lane-instruction.lane-instruction-to > div.instruction > div.edit-region > div > div > div:nth-child(1)');
- // setupLaneCountControls(revLanes, classNamesList);
- // $('.lt-add-lanes').on("click",function () {
- // let numAdd = $(this).text();
- // numAdd = Number.parseInt(numAdd, 10);
- // if ($(this).hasClass('lt-add-lanes rev')) {
- // // As of React >=15.6. Triggering change or input events on the input form cannot be
- // // done via jquery selectors. Which means that they have to be triggered via
- // // React native calls.
- // let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
- // let inputForm = document.querySelector("div.rev-lanes input[name=laneCount]");
- // nativeInputValueSetter.call(inputForm, numAdd);
- // let inputEvent = new Event('input', {bubbles: true});
- // inputForm.dispatchEvent(inputEvent);
- // let changeEvent = new Event('change', {bubbles: true});
- // inputForm.dispatchEvent(changeEvent);
- // }
- // });
- //
- // })
- // }
- //if (lanes.find(".direction-lanes").children().length > 0 && !getId(addWidthTag)) {
- // let addFwdLanes =
- // $('<div style="display:inline-flex;flex-direction:row;width:100%;" id="'+addWidthTag+'" />'),
- // classNamesList = ["lt-add-Width", laneDir], laneCountsToAppend = getLaneItems(8, classNamesList);
- // for (let idx = 0; idx < laneCountsToAppend.length; ++idx) {
- // addFwdLanes.append(laneCountsToAppend[idx]);
- // }
- // let lnSelector = $(dirLanesClass + " > div > .lane-instruction.lane-instruction-from > .instruction > .road-width-edit > div > div > div > .lane-width-card")
- // addFwdLanes.prependTo(lnSelector);
- // setupLaneCountControls(lnSelector, classNamesList);
- //}
- // if (revLanes.find(".direction-lanes").children().length > 0 && !getId("lt-rev-add-Width")) {
- // let appendRevLanes =
- // $('<div style="display:inline-flex;flex-direction:row;width:100%;" id="lt-rev-add-Width" />'),
- // classNamesList = [ "lt-add-Width", "rev" ], laneCountsToAppend = getLaneItems(8, classNamesList);
- // for (let idx = 0; idx < laneCountsToAppend.length; ++idx) {
- // appendRevLanes.append(laneCountsToAppend[idx]);
- // }
- // let lnSelector = $(".rev-lanes > div > div > .lane-instruction.lane-instruction-from > .instruction > .road-width-edit > div > div > div > .lane-width-card");
- // appendRevLanes.prependTo(lnSelector);
- // setupLaneCountControls(lnSelector, classNamesList);
- // }
- $(".lt-add-Width").on("click", function () {
- const numAddStr = $(this).text();
- const numAdd = Number.parseInt(numAddStr, 10);
- if ($(this).hasClass(`lt-add-Width ${laneDir}`)) {
- const lanes = $(dirLanesClass);
- lanes.find("#number-of-lanes").val(numAdd);
- lanes.find("#number-of-lanes").trigger("change");
- lanes.find("#number-of-lanes").trigger("focus");
- }
- // if ($(this).hasClass('lt-add-Width rev')) {
- // const revLanes = $('.rev-lanes');
- // revLanes.find('#number-of-lanes').val(numAdd);
- // revLanes.find('#number-of-lanes').trigger("change");
- // revLanes.find('#number-of-lanes').trigger("focus");
- // }
- });
- }
- function focusEle() {
- // Places the focus on the relevant lanes # input if the direction exists
- const autoFocusLanes = getId("lt-AutoFocusLanes");
- if (autoFocusLanes?.checked) {
- const fwdLanes = $(".fwd-lanes");
- const revLanes = $(".rev-lanes");
- if (fwdLanes.find(".edit-region").children().length > 0 && !fwdDone) {
- fwdLanes.find(".form-control").trigger("focus");
- }
- else if (revLanes.find(".edit-region").children().length > 0 && !revDone) {
- revLanes.find(".form-control").trigger("focus");
- }
- }
- }
- function insertSelAll(dir) {
- const setAllEnable = getId("lt-SelAllEnable");
- if (setAllEnable?.checked) {
- $(".street-name").css("user-select", "none");
- const inputDirection = dir === "fwd" ? $(".fwd-lanes").find(".form-control")[0] : $(".rev-lanes").find(".form-control")[0];
- const startVal = $(inputDirection).val();
- // Toggles all checkboxes in turns row
- $(inputDirection).on("change", function () {
- let boxDirection;
- if ($(this).parents(".fwd-lanes").length) {
- boxDirection = $(".fwd-lanes").find(".controls-container.turns-region");
- }
- else if ($(this).parents(".rev-lanes").length) {
- boxDirection = $(".rev-lanes").find(".controls-container.turns-region");
- }
- boxDirection = $(".street-name", boxDirection);
- for (let p = 0; p < boxDirection.length; p++) {
- $(boxDirection[p]).off();
- $(boxDirection[p]).on("click", function () {
- const secParent = $(this).get(0);
- const contParent = secParent.parentElement;
- const chkBxs = $(".checkbox-large.checkbox-white", contParent);
- const firstCheckInv = !getId(chkBxs[0].id)?.checked;
- for (let i = 0; i < chkBxs.length; i++) {
- const checkBox = $(`#${chkBxs[i].id}`);
- checkBox.prop("checked", firstCheckInv);
- checkBox.change();
- }
- });
- }
- });
- if (startVal > 0) {
- $(inputDirection).trigger("change");
- }
- }
- }
- function colorCSDir() {
- const selSeg = isSegmentSelected(selection) && selection?.objectType === "segment"
- ? sdk.DataModel.Segments.getById({ segmentId: selection.ids[0] })
- : null;
- if (!selSeg)
- return;
- const fwdNode = getNodeObj(selSeg?.toNodeId);
- const revNode = getNodeObj(selSeg?.fromNodeId);
- const fwdConfig = checkLanesConfiguration(selSeg, fwdNode, fwdNode ? fwdNode.connectedSegmentIds : [], selSeg?.toNodeLanesCount);
- const revConfig = checkLanesConfiguration(selSeg, revNode, revNode ? revNode.connectedSegmentIds : [], selSeg?.fromNodeLanesCount);
- if (fwdConfig.csMode > 0) {
- const csColor = fwdConfig.csMode === 1 ? LtSettings.CS1Color : LtSettings.CS2Color;
- const arrowDiv = $("#segment-edit-lanes > div > div > div.fwd-lanes > div.lane-instruction.lane-instruction-to > div.instruction > div.lane-arrows > div").children();
- for (let i = 0; i < arrowDiv.length; i++) {
- if (arrowDiv[i].title === fwdConfig.csStreet) {
- $(arrowDiv[i]).css("background-color", csColor);
- }
- }
- }
- if (revConfig.csMode > 0) {
- const csColor = revConfig.csMode === 1 ? LtSettings.CS1Color : LtSettings.CS2Color;
- const arrowDiv = $("#segment-edit-lanes > div > div > div.rev-lanes > div.lane-instruction.lane-instruction-to > div.instruction > div.lane-arrows > div").children();
- for (let i = 0; i < arrowDiv.length; i++) {
- if (arrowDiv[i].title === revConfig.csStreet) {
- $(arrowDiv[i]).css("background-color", csColor);
- }
- }
- }
- }
- // Rotates lane display arrows in lane tab for South directions
- // Function written by Dude495 and modified by SkiDooGuy to fit into LaneTools better
- function rotateArrows() {
- const direction = document.getElementsByClassName("heading");
- const boxDiv = $(".lane-arrows > div").get();
- for (let i = 0; i < direction.length; i++) {
- if (direction[i]?.textContent?.includes("south")) {
- const arrows = $(boxDiv[i]).children();
- $(arrows).css("transform", "rotate(180deg)");
- $(boxDiv[i]).append(arrows.get().reverse());
- }
- }
- isRotated = true;
- }
- // Begin lanes tab enhancements
- if (getId("lt-UIEnable")?.checked && getId("lt-ScriptEnabled")?.checked) {
- if (isSegmentSelected(selection)) {
- // Check to ensure that there is only one segment object selected, then setup click event
- waitForElementLoaded(".lanes-tab").then((elm) => {
- formatLanesTab(getId("lt-AutoLanesTab")?.checked || elm.isActive);
- });
- //$('.lanes-tab').on("click",(event) => {
- // fwdDone = false;
- // revDone = false;
- // updateUI(event);
- //});
- }
- else if (selection && selection.ids.length === 2) {
- // We have exactly TWO features selected. Check heuristics and highlight
- scanHeuristicsCandidates(selection);
- }
- }
- function formatLanesTab(clickTab = false, tries = 0) {
- if ($(".tabs-labels > div:nth-child(3)", $(".segment-edit-section > wz-tabs")[0].shadowRoot).length > 0) {
- fwdDone = false;
- revDone = false;
- $(".tabs-labels > div:nth-child(3)", $(".segment-edit-section > wz-tabs")[0].shadowRoot).on("click", () => {
- fwdDone = false;
- revDone = false;
- updateUI();
- });
- if (clickTab) {
- // If the auto open lanes option is enabled, initiate a click event on the Lanes tab element
- waitForElementLoaded(".lanes-tab").then((elm) => {
- $(".tabs-labels > div:nth-child(3)", $(".segment-edit-section > wz-tabs")[0].shadowRoot).trigger("click");
- });
- }
- }
- else if (tries < 500) {
- setTimeout(() => {
- formatLanesTab(clickTab, tries + 1);
- }, 200);
- }
- else {
- console.error("LaneTools: Failed to click lanes tab");
- }
- }
- }
- // Toggles parts of script when the keyboard shortcut is used
- function toggleScript() {
- $("#lt-ScriptEnabled").trigger("click");
- }
- function toggleHighlights() {
- $("#lt-HighlightsEnable").trigger("click");
- }
- function toggleUIEnhancements() {
- $("#lt-UIEnable").trigger("click");
- }
- function toggleLaneHeuristicsChecks() {
- $("#lt-LaneHeuristicsChecks").trigger("click");
- }
- function displayToolbar() {
- const objSelected = sdk.Editing.getSelection();
- const scriptEnabled = getId("lt-ScriptEnabled");
- const copyEnable = getId("lt-CopyEnable");
- if (scriptEnabled?.checked && copyEnable && copyEnable.checked && objSelected && objSelected.ids.length === 1) {
- if (objSelected.objectType === "segment") {
- const map = sdk.Map.getMapViewportElement();
- $("#lt-toolbar-container").css({
- display: "block",
- left: map.width() * 0.1,
- top: map.height() * 0.1,
- });
- }
- }
- else {
- $("#lt-toolbar-container").css("display", "none");
- }
- }
- function getId(ele) {
- return document.getElementById(ele);
- }
- function isSegment(obj) {
- return obj && "roadType" in obj;
- }
- function isSegmentSelected(selection) {
- return (selection && selection.objectType === "segment") || false;
- }
- // returns true if object is within window bounds and above zoom threshold
- function onScreen(obj, curZoomLevel) {
- if (!obj || !obj.geometry) {
- return false;
- }
- // Either FREEWAY or Zoom >=4
- if (curZoomLevel >= MIN_ZOOM_NON_FREEWAY || (isSegment(obj) && obj.roadType === LT_ROAD_TYPE.FREEWAY)) {
- // var ext = W.map.getOLExtent();
- var ext = sdk.Map.getMapExtent();
- return true;
- }
- return false;
- }
- // borrowed from JAI
- function getCardinalAngle(nodeId, segment) {
- if (nodeId == null || segment == null) {
- return null;
- }
- let ja_dx;
- let ja_dy;
- if (segment.fromNodeId === nodeId) {
- const sp = lt_get_second_point(segment);
- const fp = lt_get_first_point(segment);
- if (!sp || !fp)
- return null;
- ja_dx = sp[0] - fp[0];
- ja_dy = sp[1] - fp[1];
- }
- else {
- const next_to_last = lt_get_next_to_last_point(segment);
- const last_point = lt_get_last_point(segment);
- if (!next_to_last || !last_point)
- return null;
- ja_dx = next_to_last[0] - last_point[0];
- ja_dy = next_to_last[1] - last_point[1];
- }
- const angle_rad = Math.atan2(ja_dy, ja_dx);
- let angle_deg = ((angle_rad * 180) / Math.PI) % 360;
- if (angle_deg < 0)
- angle_deg = angle_deg + 360;
- // console.log('Cardinal: ' + Math.round(angle_deg));
- return Math.round(angle_deg);
- }
- // borrowed from JAI
- function lt_get_first_point(segment) {
- return segment?.geometry.coordinates[0];
- // return segment.geometry.components[0];
- }
- // borrowed from JAI
- function lt_get_last_point(segment) {
- return segment?.geometry.coordinates.at(-1);
- // return segment.geometry.components[segment.geometry.components.length - 1];
- }
- // borrowed from JAI
- function lt_get_second_point(segment) {
- return segment?.geometry.coordinates[1];
- // return segment.geometry.components[1];
- }
- // borrowed from JAI
- function lt_get_next_to_last_point(segment) {
- return segment?.geometry.coordinates.at(-2);
- // return segment.geometry.components[segment.geometry.components.length - 2];
- }
- function delLanes(dir) {
- const selObjs = W.selectionManager.getSelectedWMEFeatures();
- const selSeg = selObjs[0]._wmeObject;
- const turnGraph = W.model.getTurnGraph();
- const mAction = new MultiAction();
- let node;
- let conSegs;
- let updates = {};
- // mAction.setModel(W.model);
- if (dir === "fwd") {
- updates.fwdLaneCount = 0;
- node = getLegacyNodeObj(selSeg.attributes.toNodeID);
- conSegs = node.getSegmentIds();
- // const fwdLanes = $('.fwd-lanes');
- // fwdLanes.find('.form-control').val(0);
- // fwdLanes.find('.form-control').trigger("change");
- }
- if (dir === "rev") {
- updates.revLaneCount = 0;
- node = getLegacyNodeObj(selSeg.attributes.fromNodeID);
- conSegs = node.getSegmentIds();
- // const revLanes = $('.rev-lanes');
- // revLanes.find('.form-control').val(0);
- // revLanes.find('.form-control').trigger("change");
- }
- mAction.doSubAction(W.model, new UpdateObj(selSeg, updates));
- for (let i = 0; i < conSegs.length; i++) {
- let turnStatus = turnGraph.getTurnThroughNode(node, selSeg, getLegacySegObj(conSegs[i]));
- let turnData = turnStatus.getTurnData();
- if (turnData.hasLanes()) {
- turnData = turnData.withLanes();
- turnStatus = turnStatus.withTurnData(turnData);
- mAction.doSubAction(W.model, new SetTurn(turnGraph, turnStatus));
- }
- }
- mAction._description = "Deleted lanes and turn associations";
- W.model.actionManager.add(mAction);
- }
- function removeHighlights() {
- sdk.Map.removeAllFeaturesFromLayer({ layerName: LTHighlightLayer.name });
- sdk.Map.removeAllFeaturesFromLayer({ layerName: LTNamesLayer.name });
- }
- function removeLaneGraphics() {
- sdk.Map.removeAllFeaturesFromLayer({ layerName: LTLaneGraphics.name });
- }
- function applyName(geo, fwdLnsCount, revLnsCount) {
- // if (!fwdLnsCount) fwdLnsCount = 0;
- // if (!revLnsCount) revLnsCount = 0;
- const laneNum = `${fwdLnsCount} / ${revLnsCount}`;
- const lnLabel = turf.point(geo, { styleName: "nameStyle", layerName: LTNamesLayer.name, style: { laneNumLabel: laneNum } }, { id: `point_${geo.toString()}` });
- sdk.Map.addFeatureToLayer({ feature: lnLabel, layerName: LTNamesLayer.name });
- }
- function highlightSegment(objGeo, direction, applyDash, applyLabels, fwdLnsCount, revLnsCount, applyLioHighlight, csMode, isBad, heur, heurOverHighlight) {
- const VectorStyle = {
- DASH_THIN: 1,
- DASH_THICK: 2,
- HIGHLIGHT: 10,
- OVER_HIGHLIGHT: 20,
- };
- // fwdLnsCount = !fwdLnsCount ? 0 : fwdLnsCount;
- // revLnsCount = !revLnsCount ? 0 : revLnsCount;
- // const geo = objGeo.clone();
- const applyCSHighlight = getId("lt-CSEnable")?.checked;
- // Need to rework this to account for segment length, cause of geo adjustment and such
- if (objGeo.length > 2) {
- const geoLength = objGeo.length;
- const geoMiddle = geoLength / 2;
- const fwdPoint = geoLength % 2 ? Math.ceil(geoMiddle) - 1 : Math.ceil(geoMiddle);
- const revPoint = geoLength % 2 ? Math.floor(geoMiddle) + 1 : Math.floor(geoMiddle);
- if (direction === Direction.FORWARD) {
- const newString = buildGeoComponentString(objGeo, fwdPoint, geoLength);
- if (applyDash) {
- createVector(newString, LtSettings.ABColor, VectorStyle.DASH_THIN);
- } // draw dashed line
- drawHighlight(newString, applyLioHighlight, isBad, heur, heurOverHighlight); // draw highlight
- }
- else if (direction === Direction.REVERSE) {
- const newString = buildGeoComponentString(objGeo, 0, revPoint);
- if (applyDash) {
- createVector(newString, LtSettings.BAColor, VectorStyle.DASH_THIN);
- }
- drawHighlight(newString, applyLioHighlight, isBad, heur, heurOverHighlight);
- }
- // Add the label only on the forward pass, or reverse if there are no forward lanes
- if (applyLabels && (direction === Direction.FORWARD || fwdLnsCount === 0)) {
- if (geoLength % 2) {
- applyName(objGeo[fwdPoint], fwdLnsCount, revLnsCount);
- }
- else {
- const p0 = objGeo[revPoint - 1];
- const p1 = objGeo[fwdPoint];
- const newPoint = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
- // let newPoint = new OpenLayers.getOLGeometry().Point((p0.x + p1.x) / 2, (p0.y + p1.y) / 2);
- // let newPoint = new OpenLayers.Geometry.Point((p0.x + p1.x) / 2, (p0.y + p1.y) / 2);
- // var newPoint = {
- // id: "pointNode_" + (p0[0] + p1[0]) / 2 + " " + (p0[1] + p1[1]) / 2,
- // geometry: {
- // coordinates: [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2],
- // type: "Point",
- // },
- // type: "Feature",
- // properties: { styleName: "styleNode", layerName: LTHighlightLayer.name },
- // };
- applyName(newPoint, fwdLnsCount, revLnsCount);
- }
- }
- }
- else {
- const p0 = objGeo[0];
- const p1 = objGeo[1];
- // let point1 = new OpenLayers.getOLGeometry().Point((p0.x + p1.x) / 2, (p0.y + p1.y) / 2);
- // let point1 = new OpenLayers.Geometry.Point((p0.x + p1.x) / 2, (p0.y + p1.y) / 2);
- const p1C = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
- const pVector = [p1C];
- // var point1 = {
- // id: "pointNode_" + (p0[0] + p1[0]) / 2 + " " + (p0[1] + p1[1]) / 2,
- // geometry: {
- // coordinates: p1C,
- // type: "Point",
- // },
- // type: "Feature",
- // properties: { styleName: "vectorStyle", layerName: LTHighlightLayer.name },
- // };
- if (direction === Direction.FORWARD) {
- const p2C = [objGeo[1][0], objGeo[1][1]];
- pVector.push(p2C);
- const newString = turf.lineString(pVector, { styleName: "vectorStyle", layerName: LTHighlightLayer.name }, { id: `line_${pVector.toString()}` });
- if (applyDash) {
- createVector(newString, LtSettings.ABColor, VectorStyle.DASH_THIN);
- }
- drawHighlight(newString, applyLioHighlight, isBad, heur, heurOverHighlight);
- }
- else if (direction === Direction.REVERSE) {
- const p2C = [objGeo[0][0], objGeo[0][1]];
- pVector.push(p2C);
- const newString = turf.lineString(pVector, { styleName: "vectorStyle", layerName: LTHighlightLayer.name }, { id: `line_${pVector.toString()}` });
- if (applyDash) {
- createVector(newString, LtSettings.BAColor, VectorStyle.DASH_THIN);
- }
- drawHighlight(newString, applyLioHighlight, isBad, heur, heurOverHighlight);
- }
- // Add the label only on the forward pass, or reverse if there are no forward lanes
- if (applyLabels && (direction === Direction.FORWARD || fwdLnsCount === 0)) {
- applyName(p1C, fwdLnsCount, revLnsCount);
- }
- }
- function buildGeoComponentString(geometry, from, to) {
- const components = [];
- let cIdx = 0;
- for (let i = from; i < to; i++) {
- components[cIdx++] = geometry[i];
- }
- return turf.lineString(components, { styleName: "vectorStyle", layerName: LTHighlightLayer.name }, { id: `line_${components.toString()}` });
- }
- function drawHighlight(newString, lio, bad, heurNom, heurOverHighlight = false) {
- if (bad) {
- createVector(newString, LtSettings.ErrorColor, VectorStyle.OVER_HIGHLIGHT);
- return;
- }
- if (lio) {
- createVector(newString, LtSettings.LIOColor, VectorStyle.HIGHLIGHT);
- }
- if (csMode === 1 && applyCSHighlight) {
- createVector(newString, LtSettings.CS1Color, VectorStyle.HIGHLIGHT);
- }
- if (csMode === 2 && applyCSHighlight) {
- createVector(newString, LtSettings.CS2Color, VectorStyle.HIGHLIGHT);
- }
- if (heurNom === HeuristicsCandidate.PASS) {
- createVector(newString, LtSettings.HeurColor, heurOverHighlight ? VectorStyle.OVER_HIGHLIGHT : VectorStyle.HIGHLIGHT);
- }
- else if (heurNom === HeuristicsCandidate.FAIL) {
- createVector(newString, LtSettings.HeurFailColor, heurOverHighlight ? VectorStyle.OVER_HIGHLIGHT : VectorStyle.HIGHLIGHT);
- }
- }
- function createVector(geoCom, lineColor, style) {
- // let newVector = new OpenLayers.Feature.Vector(geoCom, {}, {});
- // LTHighlightLayer.addFeatures([newVector]);
- const stroke = lineColor;
- let strokeOpacity = 1;
- let strokeWidth = 15;
- let strokeDashArray = [];
- switch (style) {
- case VectorStyle.DASH_THICK:
- strokeWidth = 8;
- strokeDashArray = [8, 10];
- break;
- case VectorStyle.DASH_THIN:
- strokeWidth = 4;
- strokeDashArray = [10, 10];
- break;
- case VectorStyle.HIGHLIGHT:
- strokeWidth = 15;
- strokeOpacity = 0.6;
- break;
- case VectorStyle.OVER_HIGHLIGHT:
- strokeWidth = 18;
- strokeOpacity = 0.85;
- break;
- default:
- break;
- }
- geoCom.properties = geoCom.properties ? geoCom.properties : {};
- geoCom.properties.style = {
- strokeColor: stroke,
- stroke: stroke,
- strokeWidth: strokeWidth,
- strokeOpacity: strokeOpacity,
- strokeDashstyle: strokeDashArray.join(" "),
- };
- sdk.Map.addFeatureToLayer({ feature: geoCom, layerName: LTHighlightLayer.name });
- }
- // LTHighlightLayer.setZIndex(2880);
- }
- function highlightNode(objGeo, color, overSized = false) {
- // const geo = objGeo.clone();
- // const highlight = new OpenLayers.Feature.Vector(geo, {});
- if (!objGeo)
- return;
- const newString = {
- id: `Node_${objGeo.toString()}`,
- geometry: {
- type: "Point",
- coordinates: objGeo,
- },
- type: "Feature",
- properties: {
- styleName: "nodeStyle",
- layerName: LTHighlightLayer.name,
- style: {
- fillColor: color,
- pointRadius: overSized ? 18 : 10,
- },
- },
- };
- // let nodeStyle = {
- // fillColor: color,
- // pointRadius: overSized ? 18 : 10,
- // fillOpacity: 0.9,
- // strokeWidth: 0,
- // };
- // Object.assign(styleRules.nodeHighlightStyle.style, nodeStyle);
- // LTHighlightLayer.addFeatures([highlight]);
- sdk.Map.addFeatureToLayer({ feature: newString, layerName: LTHighlightLayer.name });
- // const node = document.getElementById(geo.id);
- // if (node) {
- // node.setAttribute("fill", color);
- // node.setAttribute("r", overSized ? "18" : "10");
- // node.setAttribute("fill-opacity", "0.9");
- // node.setAttribute("stroke-width", "0");
- // }
- }
- const lt_scanArea_timer = {
- timeoutID: -1,
- start: function () {
- this.cancel();
- this.timeoutID = window.setTimeout(() => {
- this.calculate();
- }, 500);
- },
- calculate: function () {
- scanArea_real();
- this.timeoutID = -1;
- },
- cancel: function () {
- if (typeof this.timeoutID === "number") {
- window.clearTimeout(this.timeoutID);
- this.timeoutID = -1;
- lt_scanArea_recursive = 0;
- }
- },
- };
- function scanArea() {
- // Use a delay timer to ensure the DOM is settled
- lt_scanArea_recursive = 3;
- scanArea_real();
- }
- function scanArea_real() {
- const isEnabled = getId("lt-ScriptEnabled")?.checked;
- const mapHighlights = getId("lt-HighlightsEnable")?.checked;
- const heurChecks = getId("lt-LaneHeuristicsChecks")?.checked;
- // const zoomLevel = W.map.getZoom() != null ? W.map.getZoom() : 16;
- const zoomLevel = sdk.Map.getZoomLevel();
- const highOverride = getId("lt-highlightOverride")?.checked; // jm6087
- const layerCheck = W.layerSwitcherController.getTogglerState("ITEM_ROAD") ||
- W.layerSwitcherController.getTogglerState("ITEM_ROAD_V2"); //jm6087
- removeHighlights();
- // console.log(zoomLevel);
- if (zoomLevel < MIN_DISPLAY_LEVEL) {
- return;
- }
- // If segment layer is checked (true) or (segment layer is not checked (false) and highlight override is set to show only when segment layer on - not checked (false)
- if (layerCheck || (!layerCheck && !highOverride)) {
- //jm6087
- if (isEnabled && (mapHighlights || heurChecks)) {
- scanSegments(sdk.DataModel.Segments.getAll(), false);
- }
- if (isEnabled && heurChecks) {
- // const selFeat = W.selectionManager.getSelectedWMEFeatures();
- const selectedFeat = sdk.Editing.getSelection();
- if (selectedFeat?.objectType === "segment")
- scanHeuristicsCandidates(selectedFeat);
- }
- } //jm6087
- }
- // Given two features, checks if they are segments, and their path qualifies for heuristics; then highlight
- function scanHeuristicsCandidates(selection) {
- const segs = [];
- let count = 0;
- for (let idx = 0; selection && idx < selection.ids.length; ++idx) {
- if (typeof selection.ids[idx] === "string") {
- lt_log(`Segment ID: ${selection.ids[idx]} reported as Segment ID incorrectly`, 1);
- }
- const seg = sdk.DataModel.Segments.getById({ segmentId: selection.ids[idx] });
- if (!seg)
- continue;
- count = segs.push(seg);
- }
- // _.each(features, (f) => {
- // if (f && f._wmeObject && f._wmeObject.type === "segment") {
- // count = segs.push(f._wmeObject);
- // }
- // });
- scanSegments(segs, true);
- return count;
- }
- // Check all given segments for heuristics qualification
- function scanSegments(segments, selectedSegsOverride = false) {
- const heurChecks = getId("lt-LaneHeuristicsChecks")?.checked ?? false;
- const heurScan_PosHighlight = heurChecks && (getId("lt-LaneHeurPosHighlight")?.checked ?? false);
- const heurScan_NegHighlight = heurChecks && (getId("lt-LaneHeurNegHighlight")?.checked ?? false);
- const mapHighlights = getId("lt-HighlightsEnable")?.checked ?? false;
- const applyLioHighlight = mapHighlights && (getId("lt-LIOEnable")?.checked ?? false);
- const applyLabels = mapHighlights && (getId("lt-LabelsEnable")?.checked ?? false);
- const zoomLevel = sdk.Map.getZoomLevel();
- // const turnGraph = W.model.getTurnGraph();
- // console.log(zoomLevel);
- _.each(segments, (s) => {
- if (onScreen(s, zoomLevel)) {
- // const sAtts = s.getAttributes();
- const tryRedo = false;
- const segLength = s.length; //lt_segment_length(s);
- // FORWARD
- tryRedo || scanSegment_Inner(s, Direction.FORWARD, segLength, tryRedo);
- // If errors encountered, scan again. (Usually this is an issue with first loading of DOM after zoom or long pan)
- if (tryRedo && lt_scanArea_recursive > 0) {
- lt_log("LT errors found, scanning again", 2);
- removeHighlights();
- lt_scanArea_recursive--;
- lt_scanArea_timer.start();
- return;
- }
- tryRedo || scanSegment_Inner(s, Direction.REVERSE, segLength, tryRedo);
- // If errors encountered, scan again. (Usually this is an issue with first loading of DOM after zoom or long pan)
- if (tryRedo && lt_scanArea_recursive > 0) {
- lt_log("LT errors found, scanning again", 2);
- removeHighlights();
- lt_scanArea_recursive--;
- lt_scanArea_timer.start();
- }
- }
- });
- function scanSegment_Inner(seg, direction, segLength, tryRedo) {
- const fwdLaneCount = seg.fromNodeLanesCount;
- const revLaneCount = seg.toNodeLanesCount;
- if (fwdLaneCount + revLaneCount === 0)
- return;
- let node = getNodeObj(seg.toNodeId);
- let oppNode = getNodeObj(seg.fromNodeId);
- let laneCount = fwdLaneCount;
- let oppLaneCount = revLaneCount;
- if (direction !== Direction.FORWARD) {
- node = getNodeObj(seg.fromNodeId);
- oppNode = getNodeObj(seg.toNodeId);
- laneCount = revLaneCount;
- oppLaneCount = fwdLaneCount;
- }
- let tlns = false;
- let tio = false;
- let badLn = false;
- let lio = false;
- let csMode = 0;
- let heurCand = HeuristicsCandidate.NONE;
- let entrySeg = null;
- const entrySegRef = {
- seg: 0,
- direction: Direction.ANY,
- };
- // CHECK LANES & HEURISTICS
- if (node !== null && onScreen(node, zoomLevel)) {
- const nodeSegs = node.connectedSegmentIds;
- if (laneCount && laneCount > 0) {
- const config = checkLanesConfiguration(seg, node, nodeSegs, laneCount);
- tlns = config.tlns;
- tio = config.tio;
- lio = config.lio;
- badLn = config.badLn;
- csMode = config.csMode;
- tryRedo = badLn || tryRedo;
- }
- // 1/1/21: Only check for heuristics on segments <50m. IMPORTANT because now we're checking segments regardless of lanes
- if (heurChecks && segLength <= MAX_LEN_HEUR) {
- // Check Heuristics regardless of heurChecks, because we want to report Errors even if Heur highlights are off
- heurCand = isHeuristicsCandidate(seg, node, nodeSegs, oppNode, laneCount, segLength, entrySegRef);
- if (heurCand === HeuristicsCandidate.ERROR) {
- // fwdHeurCand = HeuristicsCandidate.NONE;
- badLn = true;
- }
- if (!heurChecks) {
- heurCand = HeuristicsCandidate.NONE;
- }
- else if (heurCand !== HeuristicsCandidate.NONE) {
- entrySeg = { ...entrySegRef };
- }
- }
- }
- // HIGHLIGHTS
- if (!selectedSegsOverride) {
- // Full scan highlights
- let heur = HeuristicsCandidate.NONE;
- if ((heurScan_PosHighlight && heurCand === HeuristicsCandidate.PASS) ||
- (heurScan_NegHighlight && heurCand === HeuristicsCandidate.FAIL)) {
- heur = heurCand;
- }
- if (laneCount && (laneCount > 0 || heur !== null || badLn)) {
- highlightSegment(seg.geometry.coordinates, direction, mapHighlights, applyLabels, fwdLaneCount, revLaneCount, lio && applyLioHighlight, csMode, badLn, heur, false);
- }
- // Nodes highlights
- if (mapHighlights && getId("lt-NodesEnable")?.checked) {
- if (tlns) {
- highlightNode(node?.geometry.coordinates, LtSettings.NodeColor);
- // highlightNode(node.geometry, `${LtSettings.NodeColor}`);
- }
- if (tio) {
- highlightNode(node?.geometry.coordinates, LtSettings.TIOColor);
- // highlightNode(node.geometry, `${LtSettings.TIOColor}`);
- }
- }
- }
- else {
- // Selected segment highlights
- lt_log(`candidate(f):${heurCand}`);
- if (heurCand !== HeuristicsCandidate.NONE) {
- if (entrySeg && segments.findIndex((element) => element.id === entrySeg.seg) > -1) {
- const nodeColor = heurCand === HeuristicsCandidate.PASS ? LtSettings.NodeColor : LtSettings.HeurFailColor;
- highlightSegment(seg.geometry.coordinates, direction, false, false, 0, 0, false, csMode, badLn, heurCand, true);
- const eSeg = sdk.DataModel.Segments.getById({ segmentId: entrySeg.seg });
- if (eSeg) {
- highlightSegment(eSeg?.geometry.coordinates, entrySeg.direction, false, false, 0, 0, false, 0, false, heurCand, true);
- }
- highlightNode(node?.geometry.coordinates, nodeColor, true);
- highlightNode(oppNode?.geometry.coordinates, nodeColor, true);
- }
- }
- }
- return tryRedo;
- }
- }
- function checkLanesConfiguration(s, node, segs, numLanes) {
- const laneConfig = {
- tlns: false,
- tio: false,
- badLn: false,
- lio: false,
- csMode: 0,
- csStreet: null,
- };
- const turnLanes = [];
- // const turnGraph = W.model.getTurnGraph();
- // const pturns = turnGraph.getAllPathTurns();
- const fromTurns = sdk.DataModel.Turns.getTurnsFromSegment({ segmentId: s.id });
- const toTurns = sdk.DataModel.Turns.getTurnsToSegment({ segmentId: s.id });
- const pturns = fromTurns.filter((t) => t.isPathTurn);
- pturns.push(...toTurns.filter((t) => t.isPathTurn));
- const jpturns = fromTurns.filter((t) => t.isJunctionBoxTurn);
- jpturns.push(...toTurns.filter((t) => t.isJunctionBoxTurn));
- const zoomLevel = sdk.Map.getZoomLevel();
- function addTurns(fromLns, toLns) {
- if (toLns === undefined || fromLns === undefined)
- return;
- for (let k = fromLns; k < toLns + 1; k++) {
- let newValue = true;
- for (let j = 0; j < turnLanes.length; j++) {
- if (turnLanes[j] === k) {
- newValue = false;
- }
- }
- if (newValue) {
- turnLanes.push(k);
- }
- }
- }
- for (let i = 0; i < segs.length; i++) {
- if (segs[i] === s.id)
- continue;
- const seg2 = getSegObj(segs[i]);
- const turnsThrough = !node ? [] : sdk.DataModel.Turns.getTurnsThroughNode({ nodeId: node?.id });
- for (let idx = 0; idx < turnsThrough.length; ++idx) {
- const t = turnsThrough[idx];
- if (t.isUTurn || (t.fromSegmentId !== s.id && t.toSegmentId !== segs[i]))
- continue;
- // const turnData = turnGraph.getTurnThroughNode(node, s, seg2).getTurnData();
- if (t.isAllowed) {
- // Check for turn instruction override
- if (t.instructionOpCode !== null) {
- laneConfig.tio = true;
- }
- // Check for lanes
- if (t.lanes !== null) {
- laneConfig.tlns = true;
- // Check for lane angle override
- if (t.lanes.angleOverride !== null) {
- laneConfig.lio = true;
- }
- // Check for Continue Straight override
- // 1 is for view only, 2 is for view and hear
- const primaryStreetId = seg2?.primaryStreetId;
- if (primaryStreetId && primaryStreetId !== null && s.primaryStreetId === primaryStreetId) {
- if (t.lanes.guidanceMode === "display") {
- laneConfig.csMode = 1;
- laneConfig.csStreet = sdk.DataModel.Streets.getById({
- streetId: primaryStreetId,
- })?.name;
- }
- else if (t.lanes.guidanceMode === "display-and-voice") {
- laneConfig.csMode = 2;
- laneConfig.csStreet = sdk.DataModel.Streets.getById({
- streetId: primaryStreetId,
- })?.name;
- }
- }
- const fromLns = t.lanes.fromLaneIndex;
- const toLns = t.lanes.toLaneIndex;
- addTurns(fromLns, toLns);
- }
- }
- }
- }
- // check paths
- for (let i = 0; i < pturns.length; i++) {
- if (pturns[i].lanes !== null) {
- const fromLns = pturns[i].lanes?.fromLaneIndex;
- const toLns = pturns[i].lanes?.toLaneIndex;
- addTurns(fromLns, toLns);
- }
- }
- // check turns in JBs
- // const jb = W.model.bigJunctions.getObjectArray();
- for (let t = 0; t < jpturns.length; t++) {
- const tdat = jpturns[t].lanes;
- if (tdat) {
- addTurns(tdat.fromLaneIndex, tdat.toLaneIndex);
- }
- }
- turnLanes.sort();
- for (let z = 0; z < turnLanes.length; z++) {
- if (turnLanes[z] !== z) {
- laneConfig.badLn = true;
- }
- }
- if (numLanes && turnLanes.length < numLanes && onScreen(node, zoomLevel)) {
- laneConfig.badLn = true;
- }
- return laneConfig;
- }
- function setTurns(direction) {
- const clickSaveEnabled = getId("lt-ClickSaveEnable");
- if (!clickSaveEnabled?.checked) {
- return;
- }
- const lanesPane = document.getElementsByClassName(direction)[0];
- if (!lanesPane)
- return;
- const left = lanesPane.getElementsByClassName("angle--135").length > 0
- ? "angle--135"
- : lanesPane.getElementsByClassName("angle--90").length > 0
- ? "angle--90"
- : "angle--45";
- const right = lanesPane.getElementsByClassName("angle-135").length > 0
- ? "angle-135"
- : lanesPane.getElementsByClassName("angle-90").length > 0
- ? "angle-90"
- : "angle-45";
- const turnSections = lanesPane.getElementsByClassName("turn-lane-edit-container");
- let setLeft = false;
- let setRight = false;
- const alreadySet = [].slice
- .call(turnSections)
- .reduce((acc, turn) => acc +
- [].slice
- .call(turn.getElementsByTagName("input"))
- .reduce((acc, input) => (input.checked === true ? acc + 1 : acc), 0), 0);
- if (alreadySet === 0) {
- for (let i = 0; i < turnSections.length; i++) {
- const turnSection = turnSections[i];
- // Check if the lanes are already set. If already set, don't change anything.
- const laneCheckboxes = turnSection.getElementsByTagName("wz-checkbox");
- if (laneCheckboxes && laneCheckboxes.length > 0) {
- if (getId("lt-ClickSaveTurns")?.checked) {
- if (turnSection.getElementsByClassName(left).length > 0 &&
- laneCheckboxes[0].checked !== undefined &&
- laneCheckboxes[0].checked === false) {
- setLeft = true;
- laneCheckboxes[0].click();
- }
- else if (turnSection.getElementsByClassName(right).length > 0 &&
- laneCheckboxes[laneCheckboxes.length - 1].checked !== undefined &&
- laneCheckboxes[laneCheckboxes.length - 1].checked === false) {
- setRight = true;
- laneCheckboxes[laneCheckboxes.length - 1].click();
- }
- }
- }
- }
- for (let i = 0; i < turnSections.length; i++) {
- const turnSection = turnSections[i];
- const laneCheckboxes = turnSection.getElementsByTagName("wz-checkbox");
- if (setRight) {
- // Clear All Lanes Except the Right most for right turn
- if (turnSection.getElementsByClassName(right).length > 0) {
- for (let j = 0; j < laneCheckboxes.length - 1; ++j) {
- waitForElementLoaded("input[type='checkbox']", laneCheckboxes[j].shadowRoot);
- if (laneCheckboxes[j].checked)
- laneCheckboxes[j].click();
- }
- }
- }
- if (setLeft) {
- // Clear all Lanes except left most for left turn
- if (turnSection.getElementsByClassName(left).length > 0) {
- for (let j = 1; j < laneCheckboxes.length; ++j) {
- waitForElementLoaded("input[type='checkbox']", laneCheckboxes[j].shadowRoot);
- if (laneCheckboxes[j].checked)
- laneCheckboxes[j].click();
- }
- }
- }
- if (turnSection.getElementsByClassName("angle-0").length > 0) {
- // Set all lanes for straight turns
- for (let j = 0; j < laneCheckboxes.length; j++) {
- waitForElementLoaded("input[type='checkbox']", laneCheckboxes[j].shadowRoot);
- if (laneCheckboxes[j].checked === false) {
- if (j === 0 && (LtSettings.ClickSaveStraight || setLeft === false)) {
- laneCheckboxes[j].click();
- }
- else if (j === laneCheckboxes.length - 1 &&
- (LtSettings.ClickSaveStraight || setRight === false)) {
- laneCheckboxes[j].click();
- }
- else if (j !== 0 && j !== laneCheckboxes.length - 1) {
- laneCheckboxes[j].click();
- }
- }
- }
- }
- }
- }
- }
- function waitForElementLoaded(selector, root = undefined) {
- return new Promise((resolve) => {
- if (!root) {
- if (document.querySelector(selector)) {
- return resolve(document.querySelector(selector));
- }
- const observer = new MutationObserver((mutations) => {
- if (document.querySelector(selector)) {
- observer.disconnect();
- resolve(document.querySelector(selector));
- }
- });
- observer.observe(document.body, {
- childList: true,
- subtree: true,
- });
- }
- else {
- if (root.querySelector(selector)) {
- return resolve(root.querySelector(selector));
- }
- const observer = new MutationObserver((mutations) => {
- if (root.querySelector(selector)) {
- observer.disconnect();
- resolve(root.querySelector(selector));
- }
- });
- observer.observe(root, {
- childList: true,
- subtree: true,
- });
- }
- });
- }
- function processLaneNumberChange() {
- const parent = $(this).parents().eq(8);
- const elem = parent[0];
- const className = elem.className;
- const numLanes = Number.parseInt($(this).val(), 10);
- waitForElementLoaded(".turn-lane-checkbox").then((elem) => {
- setTurns(className, numLanes);
- });
- const laneCountNums = $(this).parents().find(".lt-add-lanes");
- if (laneCountNums.length > 0) {
- const counterClassName = laneCountNums[0].className;
- const selectorClassName = `.${counterClassName.replace(" ", ".")}`;
- const counterClassToSelectName = `#${counterClassName.replace(" ", "-")}-${numLanes.toString()}`;
- $(selectorClassName).css({ "background-color": "transparent", color: "black" });
- $(counterClassToSelectName).css({ "background-color": "navy", color: "white" });
- }
- }
- function initLaneGuidanceClickSaver() {
- const laneObserver = new MutationObserver((mutations) => {
- // if (
- // W.selectionManager.getSelectedWMEFeatures()[0] &&
- // W.selectionManager.getSelectedWMEFeatures()[0].featureType === "segment" &&
- // getId("lt-ScriptEnabled").checked
- // )
- const selection = sdk.Editing.getSelection();
- if (selection?.objectType === "segment" && getId("lt-ScriptEnabled")?.checked) {
- const laneCountElement = document.getElementsByName("laneCount");
- for (let idx = 0; idx < laneCountElement.length; idx++) {
- laneCountElement[idx].addEventListener("keyup", processLaneNumberChange, false);
- laneCountElement[idx].addEventListener("change", processLaneNumberChange, false);
- }
- }
- });
- laneObserver.observe(document.getElementById("edit-panel"), {
- childList: true,
- subtree: true,
- });
- // console.log('LaneTools: Click Saver Module loaded');
- }
- function isHeuristicsCandidate(segCandidate, curNodeExit, nodeExitSegIds, curNodeEntry, laneCount, segLength, inSegRef) {
- // CRITERIA FOR HEURISTICS, as described on the wiki: https://wazeopedia.waze.com/wiki/USA/User:Nzahn1/Lanes#Mapping_lanes_on_divided_roadways
- // 1. Both left and right turns are possible at the intersection;
- // 2. The two portions of the divided roadway are essentially parallel to each other;
- // 3. The two intersecting roads are more or less perpendicular to each other;
- // 4. The median segment in question is 50 m or shorter; and
- // 5. The number of lanes entering the intersection is equal to the total number of lanes exiting the intersection
- // (total number of lanes exiting intersection = number of lanes on the median segment +
- // number of right-turn only lanes on the entry segment -- other words, no new lanes are added in the median).
- // MY OBSERVATIONS
- // 11. We must have an incoming segment supplemenatary to outgoing segment 1. (alt-incoming)
- // 12. That alt-incoming segment must be within perpendicular tolerance to BOTH the median segment and the incoming segment.
- if (nodeExitSegIds == null || curNodeEntry == null || laneCount == null || inSegRef == null) {
- lt_log("isHeuristicsCandidate received bad argument (null)", 1);
- return HeuristicsCandidate.NONE;
- }
- let outSeg2 = null;
- let outTurnAngle2 = null;
- let outSeg2IsHeurFail = 0;
- let inSeg = null;
- let inAzm = null;
- let inTurnAngle = null;
- let inSegIsHeurFail = 0;
- let altIncomingSeg = null;
- let altInAzm = null;
- let altInIsHeurFail = 0;
- let inNumLanesThrough = 0;
- // #4 first: Check the length (and get outta' here if not)
- // 1/1/21: This is now redundant with outer loop. But leaving it in just in case...
- if (segLength > MAX_LEN_HEUR) {
- return HeuristicsCandidate.NONE;
- }
- // Get current segment heading at the node
- const segId = segCandidate.id;
- const segEndAzm = lt_getBearing(curNodeExit.id, segCandidate, true);
- const segBeginAzm = lt_getBearing(curNodeEntry.id, segCandidate);
- let out1TargetAngle = -90.0; // For right-hand side of the road countries (right-turn)
- let out2TargetAngle = 90.0; // (left-turn)
- const segAddress = sdk.DataModel.Segments.getAddress({ segmentId: segCandidate.id });
- if (segAddress.street === null) {
- lt_log(`Unable to process Heuristics on Segment: ${segCandidate.id} as it has no Primary Street Set`, 1);
- return HeuristicsCandidate.NONE;
- }
- if (segAddress.country?.isLeftHandTraffic) {
- out1TargetAngle = 90.0; // left turn
- out2TargetAngle = -90.0; // right turn
- }
- lt_log("==================================================================================", 2);
- lt_log(`Checking heuristics candidate: seg ${segId} node ${curNodeExit.id} azm ${segEndAzm} nodeExitSegIds:${nodeExitSegIds.length}`, 2);
- // Find the incoming segment, and validate angle to cursegment
- const nodeEntrySegIds = curNodeEntry.connectedSegmentIds;
- for (let ii = 0; ii < nodeEntrySegIds.length; ii++) {
- let thisTimeFail = 0;
- if (nodeEntrySegIds[ii] === segId) {
- continue;
- } // ignore same segment as our original
- const is = getSegObj(nodeEntrySegIds[ii]);
- // Check turn from this seg to candidate seg
- if (is !== null && !lt_is_turn_allowed(is, curNodeEntry, segCandidate)) {
- continue;
- }
- const ia = lt_getBearing(curNodeEntry.id, is, true); // absolute math azimuth
- // const ita: number | null = lt_turn_angle(ia, segBeginAzm); // turn angle
- const ita = lt_turn_angle_seg_to_seg(is, curNodeEntry, segCandidate);
- lt_log(`Turn angle from inseg ${nodeEntrySegIds[ii]}: ${ita}(${ia},${segBeginAzm})`, 3);
- if (ita !== null && Math.abs(ita) > MAX_STRAIGHT_DIF) {
- // tolerance met?
- if (Math.abs(ita) > MAX_STRAIGHT_TO_CONSIDER) {
- continue;
- }
- lt_log(` Not eligible as inseg: ${ita}`, 2);
- thisTimeFail = HeuristicsCandidate.FAIL;
- }
- // const turnsThrough = turnGraph.getTurnThroughNode(curNodeEntry, is, segCandidate);
- // const turnData = turnsThrough.getTurnData();
- // const turnsThrough = sdk.DataModel.Turns.getTurnsThroughNode({ nodeId: curNodeEntry.id });
- // let turnData = turnsThrough[tidx];
- function getMatchingTurn(node, from, to) {
- const turns = sdk.DataModel.Turns.getTurnsThroughNode({ nodeId: node.id });
- if (from !== null) {
- for (let idx = 0; idx < turns.length; ++idx) {
- if (turns[idx].fromSegmentId === from.id && turns[idx].toSegmentId === to.id)
- return turns[idx];
- }
- }
- return null;
- }
- const turnData = getMatchingTurn(curNodeEntry, is, segCandidate);
- if (turnData === null || !turnData.lanes) {
- lt_log(`Straight turn has no lanes:${nodeEntrySegIds[ii]} to ${segId}`, 3);
- continue; // No lanes? Don't even think about it. (Not a candidate)
- }
- // #5 Ensure this (straight) turn motion has lanes, and lane count matches; otherwise ERROR
- // 1/1/21: One exception. If laneCount is 0, and there is exactly 1 straight incoming lane, then treat it as equal. (Conversation with @jm6087)
- const nl = turnData.lanes.toLaneIndex - turnData.lanes.fromLaneIndex + 1;
- if (nl !== laneCount && !(laneCount === 0 && nl === 1)) {
- lt_log("Straight turn lane count does not match", 2);
- thisTimeFail = HeuristicsCandidate.ERROR; // Failed lane match should give us an ERROR
- }
- // Only one segment allowed // TBD ??? For now, don't allow more than one.
- if (inSeg !== null && thisTimeFail >= inSegIsHeurFail) {
- if (inSegIsHeurFail === 0 && thisTimeFail === 0) {
- lt_log(`Error: >1 qualifying entry segment for ${segCandidate.id}: ${inSeg.id},${is?.id}`, 2);
- lt_log("==================================================================================", 2);
- return 0; // just stop here
- }
- }
- inSeg = is;
- inAzm = ia;
- inTurnAngle = ita;
- inNumLanesThrough = nl;
- inSegIsHeurFail = thisTimeFail;
- if (!inSegRef) {
- const newSegRef = {
- seg: 0,
- direction: Direction.ANY,
- };
- inSegRef = newSegRef;
- }
- if (inSeg)
- inSegRef.seg = inSeg.id;
- inSegRef.direction = inSeg?.toNodeId === curNodeEntry.id ? Direction.FORWARD : Direction.REVERSE;
- }
- if (inSeg === null) {
- lt_log("== No inseg found ==================================================================", 2);
- return 0; // otherwise wait for later
- }
- lt_log(`Found inseg candidate: ${inSeg.id} ${inSegIsHeurFail === 0 ? "" : "(failed)"}`, 2);
- // #3(a) Determine the outgoing segment 2 (the 2nd turn) and validate turn angle
- for (let ii = 0; ii < nodeExitSegIds.length; ii++) {
- let thisTimeFail = 0;
- if (nodeExitSegIds[ii] === segId) {
- continue;
- } // ignore same segment as our original
- const os = getSegObj(nodeExitSegIds[ii]);
- // Check turn from candidate seg to this seg
- if (!lt_is_turn_allowed(segCandidate, curNodeExit, os)) {
- continue;
- }
- const oa = lt_getBearing(curNodeExit.id, os); // absolute math azimuth
- const ota = lt_turn_angle_seg_to_seg(segCandidate, curNodeExit, os); // turn angle
- lt_log(`Turn angle to outseg2 ${nodeExitSegIds[ii]}: ${ota}(${segEndAzm},${oa})`, 2);
- // Just to be sure, we can't do Heuristics if there's a chance to turn right (RH)
- if (ota !== null && Math.abs(out1TargetAngle - ota) < MAX_PERP_TO_CONSIDER) {
- // tolerance met?
- return HeuristicsCandidate.NONE;
- }
- // Ok now check our turn angle
- if (ota !== null && Math.abs(out2TargetAngle - ota) > MAX_PERP_DIF) {
- // tolerance met?
- if (Math.abs(out2TargetAngle - ota) > MAX_PERP_TO_CONSIDER) {
- continue;
- } // too far out of tolerance to care (don't consider it a candidate at all)
- lt_log(` Not eligible as outseg2: ${ota}`, 2);
- thisTimeFail = HeuristicsCandidate.FAIL;
- }
- // Only one segment allowed // TBD ??? For now, don't allow more than one.
- if (outSeg2 !== null && thisTimeFail >= outSeg2IsHeurFail) {
- if (outSeg2IsHeurFail === 0 && thisTimeFail === 0) {
- lt_log(`Error: >1 qualifying exit2 segment for ${segCandidate.id}: ${outSeg2.id},${os?.id}`, 2);
- lt_log("==================================================================================", 2);
- return 0; // just stop here
- }
- }
- outSeg2 = os;
- outTurnAngle2 = ota;
- outSeg2IsHeurFail = thisTimeFail;
- }
- if (outSeg2 === null) {
- lt_log("== No Outseg2 found ==================================================================", 2);
- return 0;
- }
- lt_log(`Found outseg2 candidate: ${outSeg2.id} ${outSeg2IsHeurFail === 0 ? "" : "(failed)"}`, 2);
- // #11 & 12: The Segment 1 that matters is the incoming (parallel to outgoing seg2)
- for (let ii = 0; ii < nodeEntrySegIds.length; ii++) {
- if (nodeEntrySegIds[ii] === segId || nodeEntrySegIds[ii] === inSeg.id) {
- // ignore same segment as our original
- continue;
- }
- const ai1 = getSegObj(nodeEntrySegIds[ii]);
- let thisTimeFail = 0;
- // Ensure the segment is one-way TOWARD the node (incoming direction)
- const sourceSegment = ((ai1?.isBtoA && ai1.fromNodeId === curNodeEntry.id) || (ai1?.isAtoB && ai1.toNodeId === curNodeEntry.id));
- if ((ai1?.isAtoB && ai1.toNodeId !== curNodeEntry.id) || (ai1?.isBtoA && ai1.fromNodeId !== curNodeEntry.id)) {
- continue;
- }
- // Check turn from this seg to our segment
- const ia = lt_getBearing(curNodeEntry.id, ai1, true); // absolute math azimuth
- // 12. Check angle from inseg to this seg (se)
- // Since we already have azm of this seg TOWARD the node, just check the supplementary turn angle. Must also be within tolerance. (See Geometry proof :)
- // const tta: number | null = lt_turn_angle(inAzm, ia);
- let tta;
- if (sourceSegment) {
- tta = lt_turn_angle_seg_to_seg(ai1, curNodeEntry, inSeg);
- }
- else
- tta = lt_turn_angle_seg_to_seg(inSeg, curNodeEntry, ai1);
- lt_log(`Turn angle from inseg (supplementary) ${nodeEntrySegIds[ii]}: ${tta}(${inAzm},${ia})`, 3);
- if (tta !== null && Math.abs(out1TargetAngle - tta) > MAX_PERP_DIF_ALT) {
- // tolerance met?
- if (Math.abs(out1TargetAngle - tta) > MAX_PERP_TO_CONSIDER) {
- // too far out of tolerance to care (don't consider it a candidate at all)
- continue;
- }
- lt_log(` Not eligible as altIn1: ${tta}`, 3);
- thisTimeFail = HeuristicsCandidate.FAIL;
- }
- // Only one segment allowed // TBD ??? For now, don't allow more than one.
- if (altIncomingSeg !== null) {
- // If the new candidate is worse than what we already have, just move on
- if (thisTimeFail < altInIsHeurFail) {
- continue;
- }
- // If they both are good, then error
- if (altInIsHeurFail === 0 && thisTimeFail === 0) {
- lt_log(`Error: >1 qualifying segment for ${segCandidate.id}: ${altIncomingSeg.id},${ai1?.id}`, 2);
- lt_log("==================================================================================", 2);
- return HeuristicsCandidate.FAIL;
- }
- } // If the new candidate is better than the old, then assign our candidate to the new one (below)
- altIncomingSeg = ai1;
- altInAzm = ia;
- altInIsHeurFail = thisTimeFail;
- }
- if (altIncomingSeg === null) {
- lt_log("== No alt incoming-1 segment found ==================================================================", 2);
- return 0;
- }
- lt_log(`Alt incoming-1 segment found: ${altIncomingSeg.id} ${altInIsHeurFail === 0 ? "" : "(failed)"}`, 2);
- // Have we found a failure candidate?
- if (inSegIsHeurFail < 0 || altInIsHeurFail < 0 || outSeg2IsHeurFail < 0) {
- lt_log(`Found a failed candidate for ${segId} ( ${Math.min(inSegIsHeurFail, altInIsHeurFail, outSeg2IsHeurFail)})`, 2);
- // NOTE: IF any seg is a FAIL, then return FAIL (not Error)
- if (inSegIsHeurFail === HeuristicsCandidate.FAIL ||
- altInIsHeurFail === HeuristicsCandidate.FAIL ||
- outSeg2IsHeurFail === HeuristicsCandidate.FAIL) {
- return HeuristicsCandidate.FAIL;
- }
- return HeuristicsCandidate.ERROR;
- }
- // We have a winner!!!
- lt_log(`Found a heuristics candidate! ${segId} to ${outSeg2.id} at ${outTurnAngle2}`, 2);
- return 1;
- ////////////////////////////////////////////// end of func /////////////////////////////////////////////////////////
- // get the absolute angle for a segment at an end point - borrowed from JAI
- function lt_getBearing(nodeId, segment, toNode = false) {
- if (nodeId === null || segment === null) {
- return null;
- }
- // let ja_dx: number;
- // let ja_dy: number;
- let startPos, endPos;
- if (segment.fromNodeId === nodeId) {
- const secondPoint = lt_get_second_point(segment);
- const firstPoint = lt_get_first_point(segment);
- if (!secondPoint || !firstPoint) {
- throw new Error("Missing Start and end Point of the Segment");
- }
- // ja_dx = secondPoint[0] - firstPoint[0];
- // ja_dy = secondPoint[1] - firstPoint[1];
- if (toNode) {
- startPos = secondPoint;
- endPos = firstPoint;
- }
- else {
- startPos = firstPoint;
- endPos = secondPoint;
- }
- }
- else {
- const nextToLastPoint = lt_get_next_to_last_point(segment);
- const lastPoint = lt_get_last_point(segment);
- if (!nextToLastPoint || !lastPoint) {
- throw new Error("Missing Points at the End of the Segment");
- }
- // ja_dx = nextToLastPoint[0] - lastPoint[0];
- // ja_dy = nextToLastPoint[1] - lastPoint[1];
- if (toNode) {
- endPos = lastPoint;
- startPos = nextToLastPoint;
- }
- else {
- startPos = lastPoint;
- endPos = nextToLastPoint;
- }
- }
- // const angle_rad = Math.atan2(ja_dy, ja_dx);
- // const angle_deg = ((angle_rad * 180) / Math.PI) % 360;
- const angle_deg = turf.bearing(startPos, endPos);
- lt_log(`Azm from node ${nodeId} / ${segment.id}: ${angle_deg}`, 3);
- return angle_deg;
- }
- // function lt_getBearing_to_node(nodeId: number | null, segment: Segment | null) {
- // if (!nodeId || !segment) return null;
- // const fromAzm = lt_getBearing(nodeId, segment);
- // if (fromAzm === null) return null;
- // let toAzm = fromAzm + 180.0;
- // if (toAzm >= 180.0) {
- // toAzm -= 360.0;
- // }
- // lt_log(`Azm to node ${nodeId} / ${segment.id}: ${toAzm}`, 3);
- // return toAzm;
- // }
- /** Get absolute angle between 2 inputs.
- * @param aIn absolute s_in angle (to node)
- * @param aOut absolute s_out angle (from node)
- * @returns {number}
- */
- function lt_turn_angle(aIn, aOut) {
- if (aIn === null || aOut === null)
- return null;
- let angleInAdjusted = aIn;
- let angleOutAdjusted = aOut;
- while (aOut > 180.0) {
- angleOutAdjusted -= 360.0;
- }
- while (aOut < -180.0) {
- angleOutAdjusted += 360.0;
- }
- while (aIn > 180.0) {
- angleInAdjusted -= 360.0;
- }
- while (aIn < -180.0) {
- angleInAdjusted += 360.0;
- }
- let a = angleOutAdjusted - angleInAdjusted;
- a += a > 180 ? -360 : a < -180 ? 360 : 0;
- lt_log(`Turn ${angleInAdjusted},${angleOutAdjusted}: ${a}`, 3);
- return a;
- }
- function lt_turn_angle_seg_to_seg(inSeg, connectorNode, outSeg) {
- let inPoint;
- let outPoint;
- if (inSeg.fromNodeId === connectorNode.id) {
- inPoint = lt_get_second_point(inSeg);
- }
- else if (inSeg.toNodeId === connectorNode.id) {
- inPoint = lt_get_next_to_last_point(inSeg);
- }
- if (outSeg.fromNodeId === connectorNode.id) {
- outPoint = lt_get_second_point(outSeg);
- }
- else if (outSeg.toNodeId === connectorNode.id) {
- outPoint = lt_get_next_to_last_point(outSeg);
- }
- if (!inPoint || !outPoint)
- return null;
- let turnAngle = turf.angle(inPoint, connectorNode.geometry.coordinates, outPoint);
- turnAngle -= (turnAngle > 180 ? 360 : 0);
- turnAngle = (turnAngle > 0) ? 180 - turnAngle : -180 - turnAngle;
- return turnAngle;
- }
- function lt_is_turn_allowed(s_from, via_node, s_to) {
- const turnsThrough = sdk.DataModel.Turns.getTurnsThroughNode({ nodeId: via_node.id });
- function isTurnAllowedBySegDirections(from, to) {
- const result = {
- allowedBySegDirections: false,
- allowed: false,
- };
- if (from !== null && to !== null) {
- for (let tidx = 0; tidx < turnsThrough.length; ++tidx) {
- if (turnsThrough[tidx].fromSegmentId === from.id && turnsThrough[tidx].toSegmentId === to.id) {
- result.allowed = turnsThrough[tidx].isAllowed;
- result.allowedBySegDirections = true;
- break;
- }
- }
- }
- return result;
- }
- const permissions = isTurnAllowedBySegDirections(s_from, s_to);
- lt_log(`Allow from ${s_from.id} to ${s_to !== null ? s_to.id : 0} via ${via_node.id}? ${permissions.allowedBySegDirections} | ${permissions.allowed}`, 3);
- // Is there a driving direction restriction?
- if (!permissions.allowedBySegDirections) {
- lt_log("Driving direction restriction applies", 3);
- return false;
- }
- // Is turn allowed by other means (e.g. turn restrictions)?
- if (!permissions.allowed) {
- lt_log("Other restriction applies", 3);
- return false;
- }
- // TBD: Do we need to consider restrictions?
- /*if(s_to.attributes.fromNodeID === via_node.attributes.id) {
- lt_log("FWD direction",3);
- return ja_is_car_allowed_by_restrictions(s_to.attributes.fwdRestrictions);
- } else {
- lt_log("REV direction",3);
- return ja_is_car_allowed_by_restrictions(s_to.attributes.revRestrictions);
- } */
- return true;
- }
- }
- // Segment Length - borrowed from JAI
- // function lt_segment_length(segment: Segment) {
- // // let len = segment.geometry.getGeodesicLength(W.map.olMap.projection);
- // // let len = olSphere.getLength(segment.geometry);
- // const len = 0;
- // // let len = segment.geometry.getGeodesicLength(W.map.olMap.projection);
- // lt_log(`segment: ${segment.id} computed len: ${len} `, 3);
- // return len;
- // }
- function lt_log(lt_log_msg, lt_log_level = 1) {
- // ##NO_FF_START##
- // Firefox addons should not use console.(log|error|debug), so these lines
- // are removed by the FF addon packaging script.
- if (lt_log_level <= LANETOOLS_DEBUG_LEVEL) {
- console.log("LaneTools Dev Msg: ", lt_log_msg);
- }
- // ##NO_FF_END##
- }
- function copyLaneInfo(side) {
- _turnInfo = [];
- const selFeatures = sdk.Editing.getSelection();
- const seg = selFeatures[0]._wmeObject;
- const segAtt = seg.getFeatureAttributes();
- const segGeo = seg.geometry.components;
- const nodeID = side === "A" ? segAtt.fromNodeID : segAtt.toNodeID;
- laneCount = side === "A" ? segAtt.revLaneCount : segAtt.fwdLaneCount;
- console.log(laneCount);
- const node = getNodeObj(nodeID);
- const conSegs = node.getSegmentIds();
- // const turnGraph = W.model.getTurnGraph();
- let geoPoint1;
- if (side === "A") {
- geoPoint1 = segGeo[1];
- }
- else {
- geoPoint1 = segGeo[segGeo.length - 2];
- }
- let ja_dx = geoPoint1.x - node.geometry.x;
- let ja_dy = geoPoint1.y - node.geometry.y;
- let angleRad = Math.atan2(ja_dy, ja_dx);
- const angleDeg = ((angleRad * 180) / Math.PI) % 360;
- for (let i = 0; i < conSegs.length; i++) {
- const seg2 = getSegObj(conSegs[i]);
- const seg2Att = seg2?.getFeatureAttributes();
- const seg2Geo = seg2?.geometry.components;
- let geoPoint2;
- let seg2Dir;
- const turnInfo = turnGraph.getTurnThroughNode(node, seg, seg2).getTurnData();
- if (turnInfo.state === 1 && turnInfo.lanes) {
- if (seg2Att.fromNodeID === nodeID) {
- seg2Dir = "A";
- }
- else {
- seg2Dir = "B";
- }
- if (seg2Dir === "A") {
- geoPoint2 = seg2Geo[1];
- }
- else {
- geoPoint2 = seg2Geo[seg2Geo.length - 2];
- }
- ja_dx = geoPoint2.x - node.geometry.x;
- ja_dy = geoPoint2.y - node.geometry.y;
- angleRad = Math.atan2(ja_dy, ja_dx);
- let tempAngle = ((angleRad * 180) / Math.PI) % 360;
- if (angleDeg < 0)
- tempAngle = angleDeg - tempAngle;
- _turnData = {};
- let laneData = turnInfo.getLaneData();
- _turnData.id = seg2.attributes.id;
- _turnData.order = tempAngle;
- _turnData.lanes = laneData;
- _turnInfo.push(_turnData);
- }
- _turnInfo.sort((a, b) => (a.order > b.order ? 1 : -1));
- }
- console.log(_turnInfo);
- }
- function pasteLaneInfo(side) {
- const mAction = new MultiAction();
- // mAction.setModel(W.model);
- const selFeatures = W.selectionManager.getSelectedWMEFeatures();
- const seg = selFeatures[0]._wmeObject;
- const segGeo = seg.geometry.components;
- const segAtt = seg.getFeatureAttributes();
- const nodeID = side === "A" ? segAtt.fromNodeID : segAtt.toNodeID;
- // let sortA = _cpyDir == side ? 1 : -1;
- // let sortB = _cpyDir == side ? -1 : 1;
- let geoPoint1;
- const node = getNodeObj(nodeID);
- const conSegs = node.getSegmentIds();
- // const turnGraph = W.model.getTurnGraph();
- let pasteData = {};
- const pasteInfo = [];
- if (side === "A") {
- geoPoint1 = segGeo[1];
- }
- else {
- geoPoint1 = segGeo[segGeo.length - 2];
- }
- let ja_dx = geoPoint1.x - node.geometry.x;
- let ja_dy = geoPoint1.y - node.geometry.y;
- let angleRad = Math.atan2(ja_dy, ja_dx);
- const angleDeg = ((angleRad * 180) / Math.PI) % 360;
- for (let i = 0; i < conSegs.length; i++) {
- const seg2 = getSegObj(conSegs[i]);
- const seg2Att = seg2.attributes;
- const seg2Geo = seg2.geometry.components;
- let geoPoint2 = {};
- let seg2Dir;
- const turnInfo = turnGraph.getTurnThroughNode(node, seg, seg2).getTurnData();
- if (seg2Att.fromNodeID === nodeID) {
- seg2Dir = "A";
- }
- else {
- seg2Dir = "B";
- }
- if (seg2Dir === "A") {
- geoPoint2 = seg2Geo[1];
- }
- else {
- geoPoint2 = seg2Geo[seg2Geo.length - 2];
- }
- if (turnInfo.state === 1) {
- pasteData = {};
- ja_dx = geoPoint2.x - node.geometry.x;
- ja_dy = geoPoint2.y - node.geometry.y;
- angleRad = Math.atan2(ja_dy, ja_dx);
- let tempAngle = ((angleRad * 180) / Math.PI) % 360;
- if (angleDeg < 0)
- tempAngle = angleDeg - tempAngle;
- pasteData.id = seg2Att.id;
- pasteData.order = tempAngle;
- pasteInfo.push(pasteData);
- }
- pasteInfo.sort((a, b) => (a.order > b.order ? 1 : -1));
- }
- console.log(pasteInfo);
- if (_turnInfo.length === pasteInfo.length) {
- if (side === "A") {
- mAction.doSubAction(W.model, new UpdateObj(seg, { revLaneCount: laneCount }));
- }
- else {
- mAction.doSubAction(W.model, new UpdateObj(seg, { fwdLaneCount: laneCount }));
- }
- for (let k = 0; k < pasteInfo.length; k++) {
- const pasteTurn = {};
- // Copy turn data into temp object
- for (let q = 0; q < _turnInfo.length; q++) {
- pasteTurn[q] = _turnInfo[q];
- }
- // If pasting in the opposite direction, reverse the lane associations
- /* if (_cpyDir != side) {
- for (let z=0;z < pasteTurn.length; z++) {
- pasteTurn[z].lanes.arrowAngle = pasteTurn[z].lanes.arrowAngle * -1;
- }
- } */
- const toSeg = getSegObj(pasteInfo[k].id);
- let turnStatus = turnGraph.getTurnThroughNode(node, seg, toSeg);
- let turnData = turnStatus.getTurnData();
- turnData = turnData.withLanes(pasteTurn[k].lanes);
- turnStatus = turnStatus.withTurnData(turnData);
- mAction.doSubAction(W.model, new SetTurn(turnGraph, turnStatus));
- }
- mAction._description = "Pasted some lane stuff";
- W.model.actionManager.add(mAction);
- lanesTabSetup.formatLanesTab(true);
- }
- else {
- WazeWrap.Alerts.warning(GM_info.script.name, "There are a different number of enabled turns on this segment/node");
- }
- }
- function getIcons(dir) {
- const tempEle = [];
- let svgcount = 0;
- for (let i = 0; i < dir.length; i++) {
- //if (dir[i].id !== "") {
- const temp = {
- uturn: false,
- miniuturn: false,
- svg: [],
- };
- const uTurnDisplay = $(dir[i])
- .find(".uturn")
- .css("display");
- const miniUturnDisplay = $(dir[i])
- .find(".small-uturn")
- .css("display");
- temp.uturn = uTurnDisplay && uTurnDisplay !== "none";
- temp.miniuturn = miniUturnDisplay && miniUturnDisplay !== "none";
- temp.svg = $(dir[i])
- .find("svg")
- .map(function () {
- return this;
- })
- .get();
- if (temp.svg.length > 0) {
- svgcount++;
- }
- tempEle[i] = temp;
- }
- return svgcount > 0 ? tempEle : false;
- }
- function convertToBase64(svgs) {
- const serial = new XMLSerializer();
- _.each(svgs, (obj) => {
- try {
- const svg = obj.svg[0];
- const tmp = serial.serializeToString(svg);
- obj.svg = `data:image/svg+xml;base64,${window.btoa(tmp)}`;
- }
- catch (e) {
- // console.log(e);
- }
- });
- return svgs;
- }
- function getStartPoints(node, featDis, numIcons, sign, isLeftDrive) {
- const start = !featDis || !featDis.start ? 0 : featDis.start;
- const boxheight = !featDis || !featDis.boxheight ? 0 : featDis.boxheight;
- const boxincwidth = !featDis || !featDis.boxincwidth ? 0 : featDis.boxincwidth;
- const nodePos = proj4("EPSG:4326", "EPSG:3857", node.geometry.coordinates);
- const leftDriveModifier = isLeftDrive ? -1 : 1;
- const leftOffset = isLeftDrive ? featDis.leftOffset : 0;
- switch (sign) {
- case 0:
- return proj4("EPSG:3857", "EPSG:4326", [nodePos[0] + leftDriveModifier * start * 2 - leftOffset, nodePos[1] + boxheight]);
- // x: node.geometry.x + (featDis.start * 2),
- // y: node.geometry.y + (featDis.boxheight)
- case 1:
- return proj4("EPSG:3857", "EPSG:4326", [nodePos[0] + leftDriveModifier * boxheight - leftOffset, nodePos[1] + boxincwidth * numIcons]);
- // x: node.geometry.x + featDis.boxheight,
- // y: node.geometry.y + (featDis.boxincwidth * numIcons/1.8)
- case 2:
- return proj4("EPSG:3857", "EPSG:4326", [
- nodePos[0] - leftDriveModifier * (start + boxincwidth * numIcons),
- nodePos[1] + boxheight,
- ]);
- // x: node.geometry.x - (featDis.start + (featDis.boxincwidth * numIcons)),
- // y: node.geometry.y + (featDis.start + featDis.boxheight)
- case 3:
- return proj4("EPSG:3857", "EPSG:4326", [
- nodePos[0] + leftDriveModifier * (start + boxincwidth) - leftOffset,
- nodePos[1] - (start + boxheight),
- ]);
- // x: node.geometry.x + (featDis.start + featDis.boxincwidth),
- // y: node.geometry.y - (featDis.start + featDis.boxheight)
- case 4:
- return proj4("EPSG:3857", "EPSG:4326", [
- nodePos[0] - leftDriveModifier * (start + boxheight * 3) - leftOffset,
- nodePos[1] + (boxincwidth + numIcons * 0.5),
- ]);
- // x: node.geometry.x - (featDis.start + (featDis.boxheight * 1.5)),
- // y: node.geometry.y - (featDis.start + (featDis.boxincwidth * numIcons * 1.5))
- case 5:
- return proj4("EPSG:3857", "EPSG:4326", [nodePos[0] + leftDriveModifier * (start + boxincwidth) - leftOffset, nodePos[1] + start]);
- // x: node.geometry.x + (featDis.start + featDis.boxincwidth/2),
- // y: node.geometry.y + (featDis.start/2)
- case 6:
- return proj4("EPSG:3857", "EPSG:4326", [
- nodePos[0] - leftDriveModifier * start - leftOffset,
- nodePos[1] - start * ((boxincwidth * numIcons) / 2),
- ]);
- // x: node.geometry.x - (featDis.start),
- // y: node.geometry.y - (featDis.start * (featDis.boxincwidth * numIcons/2))
- case 7:
- return proj4("EPSG:3857", "EPSG:4326", [
- nodePos[0] - leftDriveModifier * start * boxincwidth * numIcons - leftOffset,
- nodePos[1] + start,
- ]);
- // x: node.geometry.x - (featDis.start * (featDis.boxincwidth * numIcons/2)),
- // y: node.geometry.y - (featDis.start)
- default:
- break;
- }
- return [];
- }
- function getFeatDistance() {
- const label_distance = {
- start: undefined,
- boxheight: undefined,
- boxincwidth: undefined,
- iconbordermargin: undefined,
- iconborderheight: undefined,
- iconborderwidth: undefined,
- graphicHeight: undefined,
- graphicWidth: undefined,
- leftOffset: undefined
- };
- switch (sdk.Map.getZoomLevel()) {
- case 22:
- label_distance.start = 2;
- label_distance.boxheight = 1.7;
- label_distance.boxincwidth = 1.1;
- label_distance.iconbordermargin = 0.1;
- label_distance.iconborderheight = 1.6;
- label_distance.iconborderwidth = 1;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 2;
- break;
- case 21:
- label_distance.start = 2;
- label_distance.boxheight = 3.2;
- label_distance.boxincwidth = 2.2;
- label_distance.iconbordermargin = 0.2;
- label_distance.iconborderheight = 3;
- label_distance.iconborderwidth = 2;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 2;
- break;
- case 20:
- label_distance.start = 2;
- label_distance.boxheight = 5.2;
- label_distance.boxincwidth = 3.8;
- label_distance.iconbordermargin = 0.3;
- label_distance.iconborderheight = 4.9;
- label_distance.iconborderwidth = 3.5;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 8;
- break;
- case 19:
- label_distance.start = 3;
- label_distance.boxheight = 10.0;
- label_distance.boxincwidth = 7.2;
- label_distance.iconbordermargin = 0.4;
- label_distance.iconborderheight = 9.6;
- label_distance.iconborderwidth = 6.8;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 8;
- break;
- case 18:
- label_distance.start = 3;
- label_distance.boxheight = 20.0;
- label_distance.boxincwidth = 14.0;
- label_distance.iconbordermargin = 0.5;
- label_distance.iconborderheight = 19.5;
- label_distance.iconborderwidth = 13.5;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 16;
- break;
- case 17:
- label_distance.start = 10;
- label_distance.boxheight = 39.0;
- label_distance.boxincwidth = 28.0;
- label_distance.iconbordermargin = 1.0;
- label_distance.iconborderheight = 38.0;
- label_distance.iconborderwidth = 27.0;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 16;
- break;
- case 16:
- label_distance.start = 15;
- label_distance.boxheight = 80.0;
- label_distance.boxincwidth = 55;
- label_distance.iconbordermargin = 2.0;
- label_distance.iconborderheight = 78.0;
- label_distance.iconborderwidth = 53;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 32;
- break;
- case 15:
- label_distance.start = 2;
- label_distance.boxheight = 120.0;
- label_distance.boxincwidth = 90;
- label_distance.iconbordermargin = 3.0;
- label_distance.iconborderheight = 117.0;
- label_distance.iconborderwidth = 87;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 32;
- break;
- case 14:
- label_distance.start = 2;
- label_distance.boxheight = 5.2;
- label_distance.boxincwidth = 3.8;
- label_distance.iconbordermargin = 0.3;
- label_distance.iconborderheight = 4.9;
- label_distance.iconborderwidth = 3.5;
- label_distance.graphicHeight = 42;
- label_distance.graphicWidth = 25;
- label_distance.leftOffset = 32;
- break;
- // case 13:
- // label_distance.start = 2;
- // label_distance.boxheight = 5.2;
- // label_distance.boxincwidth = 3.8;
- // label_distance.iconbordermargin = .3;
- // label_distance.iconborderheight = 4.9;
- // label_distance.iconborderwidth = 3.5;
- // label_distance.graphicHeight = 42;
- // label_distance.graphicWidth = 25;
- // break;
- }
- return label_distance;
- }
- function drawIcons(seg, node, imgs, isLeftDrive = false) {
- if (!seg || !node)
- return;
- const featDis = getFeatDistance();
- let deg = getCardinalAngle(node.id, seg);
- if (!deg)
- return;
- const points = [];
- let operatorSign = 0;
- const numIcons = imgs.length;
- // Orient all icons straight up if the rotate option isn't enabled
- if (!getId("lt-IconsRotate")?.checked)
- deg = -90;
- // Rotate in the style is clockwise, the rotate() func is counterclockwise
- if (deg === 0) {
- deg += 180;
- operatorSign = 1;
- }
- else if (deg > 0 && deg <= 30) {
- deg += 2 * (90 - deg);
- // console.log('Math stuff2: ' + deg);
- operatorSign = 1;
- }
- else if (deg >= 330 && deg <= 360) {
- deg -= 180 - 2 * (360 - deg);
- // console.log('Math stuff2: ' + deg);
- operatorSign = 1;
- }
- else if (deg > 30 && deg < 60) {
- deg -= 90 - 2 * (360 - deg);
- // console.log('Math stuff3: ' + deg);
- operatorSign = 2;
- }
- else if (deg >= 60 && deg <= 120) {
- deg -= 90 - 2 * (360 - deg);
- // console.log('Math stuff4: ' + deg);
- operatorSign = 2;
- }
- else if (deg > 120 && deg < 150) {
- deg -= 90 - 2 * (360 - deg);
- // console.log('Math stuff5: ' + deg);
- operatorSign = 7;
- }
- else if (deg >= 150 && deg <= 210) {
- deg = 180 - deg;
- // console.log('Math stuff6: ' + deg);
- operatorSign = 4;
- }
- else if (deg > 210 && deg < 240) {
- deg -= 90 - 2 * (360 - deg);
- // console.log('Math stuff7: ' + deg);
- operatorSign = 6;
- }
- else if (deg >= 240 && deg <= 300) {
- deg -= 180 - 2 * (360 - deg);
- // console.log('Math stuff8: ' + deg);
- operatorSign = 3;
- }
- else if (deg > 300 && deg < 330) {
- deg -= 180 - 2 * (360 - deg);
- // console.log('Math stuff9: ' + deg);
- operatorSign = 5;
- }
- else {
- console.log("LT: icon angle is out of bounds");
- }
- const iconRotate = deg > 315 ? deg : deg + 90;
- const boxRotate = 360 - iconRotate;
- // console.log(deg);
- // console.log(operatorSign);
- // Determine start point respective to node based on segment angle
- // let boxRotate = deg * -1;
- const startPoint = getStartPoints(node, featDis, numIcons, operatorSign, isLeftDrive);
- if (!startPoint[0] || !startPoint[1])
- return;
- // Box coords
- // var boxPoint1 = new OpenLayers.Geometry.Point(startPoint.x, startPoint.y + featDis.boxheight);
- // var boxPoint2 = new OpenLayers.Geometry.Point(
- // startPoint.x + featDis.boxincwidth * numIcons,
- // startPoint.y + featDis.boxheight
- // );
- // var boxPoint3 = new OpenLayers.Geometry.Point(startPoint.x + featDis.boxincwidth * numIcons, startPoint.y);
- // var boxPoint4 = new OpenLayers.Geometry.Point(startPoint.x, startPoint.y);
- let boxPoint1 = proj4("EPSG:4326", "EPSG:3857", startPoint);
- boxPoint1[1] += !featDis || !featDis.boxheight ? 0 : featDis.boxheight;
- boxPoint1 = proj4("EPSG:3857", "EPSG:4326", boxPoint1);
- let boxPoint2 = proj4("EPSG:4326", "EPSG:3857", startPoint);
- boxPoint2[0] += !featDis || !featDis.boxincwidth ? 0 : featDis.boxincwidth * numIcons;
- boxPoint2[1] += !featDis || !featDis.boxheight ? 0 : featDis.boxheight;
- boxPoint2 = proj4("EPSG:3857", "EPSG:4326", boxPoint2);
- let boxPoint3 = proj4("EPSG:4326", "EPSG:3857", startPoint);
- boxPoint3[0] += !featDis || !featDis.boxincwidth ? 0 : featDis.boxincwidth * numIcons;
- boxPoint3 = proj4("EPSG:3857", "EPSG:4326", boxPoint3);
- const boxPoint4 = startPoint;
- points.push(boxPoint1, boxPoint2, boxPoint3, boxPoint4, boxPoint1);
- // Object.assign(styleRules.boxStyle.style, {
- // strokeColor: "#ffffff",
- // strokeOpacity: 1,
- // strokeWidth: 8,
- // fillColor: "#ffffff",
- // // rotate: boxRotate
- // });
- // let boxRing = new OpenLayers.Geometry.LinearRing(points);
- // centerPoint = boxRing.getCentroid();
- // boxRing.rotate(boxRotate, centerPoint);
- // let boxVector = new OpenLayers.Feature.Vector(boxRing, null, boxStyle);
- let turfBoxRing = turf.polygon([points]);
- turfBoxRing = turf.transformRotate(turfBoxRing, -1 * boxRotate);
- const centerPoint = turf.centroid(turfBoxRing);
- const boxRing = turf.polygon(turfBoxRing.geometry.coordinates, { styleName: "boxStyle", layerName: LTLaneGraphics.name }, { id: `polygon_${points.toString()}` });
- // LTLaneGraphics.addFeatures([boxVector]);
- sdk.Map.addFeatureToLayer({ feature: boxRing, layerName: LTLaneGraphics.name });
- let num = 0;
- _.each(imgs, (img) => {
- const iconPoints = [];
- // Icon Background
- // var iconPoint1 = new OpenLayers.Geometry.Point(
- // startPoint.x + featDis.boxincwidth * num + featDis.iconbordermargin,
- // startPoint.y + featDis.iconborderheight
- // );
- let iconPoint1 = proj4("EPSG:4326", "EPSG:3857", startPoint);
- iconPoint1[0] += !featDis
- ? 0
- : (!featDis.boxincwidth ? 0 : featDis.boxincwidth) * num +
- (!featDis.iconbordermargin ? 0 : featDis.iconbordermargin);
- iconPoint1[1] += !featDis || !featDis.iconborderheight ? 0 : featDis.iconborderheight;
- iconPoint1 = proj4("EPSG:3857", "EPSG:4326", iconPoint1);
- // var iconPoint2 = new OpenLayers.Geometry.Point(
- // startPoint.x + featDis.boxincwidth * num + featDis.iconborderwidth,
- // startPoint.y + featDis.iconborderheight
- // );
- let iconPoint2 = proj4("EPSG:4326", "EPSG:3857", startPoint);
- iconPoint2[0] += !featDis
- ? 0
- : (!featDis.boxincwidth ? 0 : featDis.boxincwidth) * num +
- (!featDis.iconborderwidth ? 0 : featDis.iconborderwidth);
- iconPoint2[1] += !featDis || !featDis.iconborderheight ? 0 : featDis.iconborderheight;
- iconPoint2 = proj4("EPSG:3857", "EPSG:4326", iconPoint2);
- // var iconPoint3 = new OpenLayers.Geometry.Point(
- // startPoint.x + featDis.boxincwidth * num + featDis.iconborderwidth,
- // startPoint.y + featDis.iconbordermargin
- // );
- let iconPoint3 = proj4("EPSG:4326", "EPSG:3857", startPoint);
- iconPoint3[0] += !featDis
- ? 0
- : (!featDis.boxincwidth ? 0 : featDis.boxincwidth) * num +
- (!featDis.iconborderwidth ? 0 : featDis.iconborderwidth);
- iconPoint3[1] += !featDis || !featDis.iconbordermargin ? 0 : featDis.iconbordermargin;
- iconPoint3 = proj4("EPSG:3857", "EPSG:4326", iconPoint3);
- // var iconPoint4 = new OpenLayers.Geometry.Point(
- // startPoint.x + featDis.boxincwidth * num + featDis.iconbordermargin,
- // startPoint.y + featDis.iconbordermargin
- // );
- let iconPoint4 = proj4("EPSG:4326", "EPSG:3857", startPoint);
- iconPoint4[0] += !featDis
- ? 0
- : (!featDis.boxincwidth ? 0 : featDis.boxincwidth) * num +
- (!featDis.iconbordermargin ? 0 : featDis.iconbordermargin);
- iconPoint4[1] += !featDis || !featDis.iconbordermargin ? 0 : featDis.iconbordermargin;
- iconPoint4 = proj4("EPSG:3857", "EPSG:4326", iconPoint4);
- iconPoints.push(iconPoint1, iconPoint2, iconPoint3, iconPoint4, iconPoint1);
- // Object.assign(styleRules.iconBoxStyle.style, {
- // strokeColor: "#000000",
- // strokeOpacity: 1,
- // strokeWidth: 1,
- // fillColor: "#26bae8",
- // // rotate: boxRotate
- // });
- // let iconBoxRing = new OpenLayers.Geometry.LinearRing(iconPoints);
- let turfIconBoxRing = turf.polygon([iconPoints]);
- turfIconBoxRing = turf.transformRotate(turfIconBoxRing, -1 * boxRotate, { pivot: centerPoint.geometry });
- const iconBoxRing = turf.polygon(turfIconBoxRing.geometry.coordinates, { styleName: "iconBoxStyle", layerName: LTLaneGraphics.name }, { id: `polygon_${iconPoints.toString()}` });
- // iconBoxRing.rotate(boxRotate, centerPoint);
- // let iconBoxVector = new OpenLayers.Feature.Vector(iconBoxRing, null, iconBoxStyle);
- // LTLaneGraphics.addFeatures([iconBoxVector]);
- sdk.Map.addFeatureToLayer({ feature: iconBoxRing, layerName: LTLaneGraphics.name });
- // Icon coords
- const arrowOrigin = turf.centroid(turfIconBoxRing);
- // let iconStart = new OpenLayers.Geometry.Point(arrowOrigin.x, arrowOrigin.y);
- let ulabel = "";
- const usize = {
- x: undefined,
- y: undefined,
- };
- const uoffset = {
- x: undefined,
- y: undefined,
- };
- if (img.uturn === true) {
- ulabel = `https://web-assets.waze.com/webapps/wme/${sdk.getWMEVersion()}-${env}/font/989fe58ac11ed7d3/u-turn-small.svg`;
- usize.x = 0.6;
- usize.y = 0.6;
- uoffset.x = -7;
- uoffset.y = -12;
- }
- if (img.miniuturn === true) {
- ulabel = `https://web-assets.waze.com/webapps/wme/${sdk.getWMEVersion()}-${env}/font/989fe58ac11ed7d3/u-turn-small.svg`;
- usize.x = 0.3;
- usize.y = 0.25;
- uoffset.x = -8;
- uoffset.y = 4;
- }
- const iconStart = turf.point(arrowOrigin.geometry.coordinates, {
- styleName: "iconStyle",
- layerName: LTLaneGraphics.name,
- style: {
- externalGraphic: img.svg,
- graphicHeight: featDis.graphicHeight,
- graphicWidth: featDis.graphicWidth,
- fillColor: "#26bae8",
- fillOpacity: 1,
- backgroundColor: "#26bae8",
- strokeColor: "#26bae8",
- rotation: iconRotate,
- backgroundGraphic: ulabel,
- backgroundHeight: !featDis || !featDis.graphicHeight || !usize.y
- ? undefined
- : featDis.graphicHeight * usize.y,
- backgroundWidth: !featDis || !featDis.graphicWidth || !usize.x ? undefined : featDis.graphicWidth * usize.x,
- backgroundXOffset: uoffset.x,
- backgroundYOffset: uoffset.y,
- },
- }, { id: `point_${iconPoints.toString()}` });
- sdk.Map.addFeatureToLayer({ layerName: LTLaneGraphics.name, feature: iconStart });
- num++;
- });
- // LTLaneGraphics.setZIndex(2890);
- }
- function displayLaneGraphics() {
- removeLaneGraphics();
- const selection = sdk.Editing.getSelection();
- if (!getId("lt-ScriptEnabled")?.checked ||
- !getId("lt-IconsEnable")?.checked ||
- selection == null ||
- selection?.objectType !== "segment" ||
- (selection.ids && selection.ids.length !== 1))
- return;
- const seg = sdk.DataModel.Segments.getById({ segmentId: selection.ids[0] });
- if (!seg)
- return;
- const zoomLevel = sdk.Map.getZoomLevel();
- if (zoomLevel < 15 ||
- (seg.roadType !== (LT_ROAD_TYPE.FREEWAY || LT_ROAD_TYPE.MAJOR_HIGHWAY || LT_ROAD_TYPE.MINOR_HIGHWAY) &&
- zoomLevel < 16))
- return;
- let isLeftDrive = false;
- if (seg.primaryStreetId) {
- let primaryStreet = sdk.DataModel.Streets.getById({ streetId: seg.primaryStreetId });
- if (primaryStreet?.cityId) {
- let city = sdk.DataModel.Cities.getById({ cityId: primaryStreet.cityId });
- if (city?.countryId) {
- let country = sdk.DataModel.Countries.getById({ countryId: city.countryId });
- isLeftDrive = country?.isLeftHandTraffic || false;
- }
- }
- }
- waitForElementLoaded(".lanes-tab > .lanes > div > .direction-lanes").then(() => {
- const fwdEle = seg?.fromNodeLanesCount && seg.fromNodeLanesCount > 0
- ? getIcons($(".fwd-lanes")
- .find(".lane-arrow")
- .map(function () {
- return this;
- })
- .get())
- : false;
- const revEle = seg?.toNodeLanesCount && seg.toNodeLanesCount > 0
- ? getIcons($(".rev-lanes")
- .find(".lane-arrow")
- .map(function () {
- return this;
- })
- .get())
- : false;
- const fwdImgs = fwdEle !== false ? convertToBase64(fwdEle) : false;
- const revImgs = revEle !== false ? convertToBase64(revEle) : false;
- if (fwdEle) {
- if (fwdEle.length === 0) {
- // setTimeout(displayLaneGraphics, 200);
- return;
- }
- drawIcons(seg, !seg || !seg.toNodeId ? null : sdk.DataModel.Nodes.getById({ nodeId: seg?.toNodeId }), fwdImgs, isLeftDrive);
- }
- if (revEle) {
- if (revEle.length === 0) {
- // setTimeout(displayLaneGraphics, 200);
- return;
- }
- drawIcons(seg, !seg || !seg.fromNodeId ? null : sdk.DataModel.Nodes.getById({ nodeId: seg?.fromNodeId }), revImgs, isLeftDrive);
- }
- });
- // There are now 23 zoom levels where 22 is fully zoomed and currently 14 is where major road types load data and 16 loads the rest
- }
- laneToolsBootstrap();
- }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址