JRPredecision Label

Decision label. Try to take over the world!

// ==UserScript==
// @name         JRPredecision Label
// @namespace    http://baidu.com/
// @version      0.5.10
// @description  Decision label. Try to take over the world!
// @author       You
// @match        http://ov.baidu-int.com/*
// @match        http://yf.baidu-int.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=baidu-int.com
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://update.greasyfork.org/scripts/491896/1355860/Copy%20Text%20and%20HTML%20to%20Clipboard.js
// @license MIT
// @grant        none
// ==/UserScript==

(function () {
  "use strict";
  let label_list = [];
  let cur_label = {};
  let ads_id = -1;
  let start_pre_seq = -1;
  let end_pre_seq = -1;
  let cur_pre_seq = -1;
  let cur_obs_id = -1;
  let is_label_panel_show = false;
  let old_info;
  var initialMouseX, initialMouseY, initialElementX, initialElementY;

  function set_cur_info() {
    var _ads_id = parseInt(
      $("section").children("p").children("span")[1].textContent
    );
    var _cur_pre_seq = parseInt(
      $(".seq-wrap>div>p:nth-child(4)").text().replace("PreSeq:", "")
    );
    // var _cur_obs_id = parseInt($(".viz-detail-text")[9].textContent.replace("id: ", "").trim());
    var _cur_obs_id = null;
    $(".viz-detail-text").each(function () {
          var textContent = $(this).text();
          if (textContent.startsWith('id')) {
              _cur_obs_id = parseInt(textContent.replace("id: ", "").trim());
              console.log("抓取障碍物id", _cur_obs_id);
          }
    });

    if (window.location.host == "yf.baidu-int.com") {
      _ads_id = getUrlParam("ads_id");
      if (_ads_id != null) {
        _ads_id = parseInt(_ads_id);
      } else {
        _ads_id = -1;
      }
      $(".dashboard_value").each(function (index) {
        if (this.textContent.startsWith('PLA')) {
          _cur_pre_seq = parseInt(this.textContent.split("\n")[1].replace("PRE:", "").trim());
          console.log("当前预测帧", _cur_pre_seq);
        }
    });
    }
    if (_cur_pre_seq == null) {
      console.log("抓取帧号失败", _cur_obs_id);
      return;
    }
    if (_cur_obs_id == null) {
      console.log("抓取障碍物id失败", _cur_obs_id);
      return;
    }
    ads_id = isNaN(_ads_id) ? ads_id : _ads_id;
    cur_pre_seq = isNaN(_cur_pre_seq) ? cur_pre_seq : _cur_pre_seq;
    cur_obs_id = isNaN(_cur_obs_id) ? cur_obs_id : _cur_obs_id;
    $("#ads_id").text(ads_id);
    $("#seq_num").text(cur_pre_seq);
    $("#obs_id").text(cur_obs_id);
    cur_label.ads_id = ads_id;
    console.log(ads_id);
    console.log(cur_pre_seq);
    console.log(cur_obs_id);
  }

  function getUrlParam(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
    var value = window.location.search.substr(1).match(reg);
    if (value != null) return unescape(value[2]);
    return null;
  }

  function copy2clipboard(str) {
      var $temp = $("<textarea>");
      $("body").append($temp);
      $temp.val(str).select();
      document.execCommand('copy', false, null);
      $temp.remove();
      console.log(str);
      //alert("复制成功");
      showToast('复制成功', 'success');
  }

  function setStartSeq() {
    set_cur_info();
    cur_label.start_seq = cur_pre_seq;
    console.log("set start seq", cur_label.start_seq);
  }
  function setEndSeq() {
    set_cur_info();
    cur_label.end_seq = cur_pre_seq;
    console.log("set end seq", cur_label.end_seq);
  }
  //<textarea id="decision_label_show_list" placeholder="" rows="6" style="width:100%;background-color: #292f42;padding: 10px;max-width: 100%;max-height: 100%;line-height: 1.5;border-radius: 5px;border: 1px solid #ccc;"></textarea>
  function showLabelList() {
    $("#decision_label_show_list").empty();
    for (let i = 0; i < label_list.length; i++) {
      var label = label_list[i];
      var str =
        label.ads_id +
        "\t" +
        label.obs_id +
        "\t" +
        label.start_seq +
        "\t" +
        label.end_seq +
        "\t" +
        label.dec_label;
      var text_ele = $("<textarea>", {
        id: `label${i}`,
        text: str,
        placeholder: "",
        rows: "1",
        style:
          "width:80%;background-color: #008844;margin-left: 5px;margin-right:5px;margin-top: 5px;",
      });
      $(`label${i}`).on("input", function () {
        this.styel.height = "auto";
        this.style.height = this.scrollHeight + "px";
      });
      var button_ele = $("<button>", {
        text: "删除",
        style:
          "background-color: #008844;margin-left: 10px;margin-right:5px;margin-top: 5px;",
      });
      button_ele.click(function () {
        if (i >= 0 && i < label_list.length) {
          label_list.splice(i, 1);
          console.log("删除" + toString(i));
          showLabelList();
        }
      });
      var div = $("<div>", {
        style: "display: flex;",
      });
      // div.append(text_ele);
      div.append(text_ele).append(button_ele);
      $("#decision_label_show_list").append(div);
      console.log("add show string", str);
    }
  }

  function copyLabels() {
    var res = '';
    for (let i = 0; i < label_list.length; i++) {
      var label = label_list[i];
      var str =
        label.ads_id +
        "\t" +
        label.obs_id +
        "\t" +
        label.start_seq +
        "\t" +
        label.end_seq +
        "\t" +
        label.dec_label;
        res = str + '\n' + res;
    }
    copy2clipboard(res);
  }

  function clearLabels() {
      $("#decision_label_show_list").empty();
      label_list = [];
  }

  function checkOverlaps(labels, cur_label) {
    for (let i = 0; i < labels.length; i++) {
      var label = labels[i];
      if (cur_label.obs_id != label.obs_id) {
        continue;
      }
      // 检查重叠:如果一个区间的开始在另一个区间的开始和结束之间,或者反之亦然
      if (
        (cur_label.start_seq < label.end_seq &&
          cur_label.end_seq > label.start_seq) ||
        (label.start_seq < cur_label.end_seq &&
          label.end_seq > cur_label.start_seq)
      ) {
        if (cur_label.label != label.dec_label) {
          console.log(`障碍物${cur_label.obs_id}与第${i}个标签冲突`);
          alert(`障碍物${cur_label.obs_id}与第${i}个标签冲突`);
          return true;
        } else {
          console.log(`障碍物${label.obs_id}区间重复标注`);
          console.warn();
          `障碍物${label.obs_id}区间重复标注`;
          return false;
        }
      }
    }
    return false; // 没有重叠
  }

  function onLabel(dec_label) {
    $("#label_btn_" + dec_label.toString()).click(function () {
      // 添加类以实现按钮变亮效果
      $("#label_btn_" + dec_label.toString()).addClass("clicked");

      // 在 300 毫秒后移除类以恢复按钮原始状态
      setTimeout(function () {
        $("#label_btn_" + dec_label.toString()).removeClass("clicked");
      }, 300);
    });
    if (
      isNaN(ads_id) ||
      isNaN(cur_obs_id) ||
      isNaN(cur_label.start_seq) ||
      isNaN(cur_label.end_seq) ||
      isNaN(dec_label)
    ) {
      return;
    }
    if (ads_id <= 0 && getUrlParam("ads_id") != null) {
      alert("ads id 不合法:" + ads_id.toString());
      return;
    }
    if (cur_obs_id <= 0) {
      alert("obs id 不合法:" + cur_obs_id.toString());
      return;
    }
    if (dec_label < 0) {
      alert("label 不合法" + dec_label.toString());
      return;
    }
    cur_label.ads_id = ads_id;
    cur_label.obs_id = cur_obs_id;
    cur_label.dec_label = dec_label;
    console.log("add decision label to list", cur_label);
    if (checkOverlaps(label_list, cur_label)) {
      return;
    }
    label_list.push(cur_label);
    showLabelList();
    cur_label = {};
  }

  function showDecisionLabelPanel() {
    $("#decision_label_panel").css(
      "z-index",
      -1 * $("#decision_label_panel").css("z-index")
    );
    console.log(
      "move decision label panel to z index ",
      $("#decision_label_panel").css("z-index")
    );
  }
  // Your code here...
  var label_tab = `
      <button type="button" onclick="showDecisionLabelPanel()" class="ant-btn ant-btn-default ant-btn-sm" style="margin-right: 10px;">
          <div class="ant-space ant-space-horizontal ant-space-align-center" style="gap: 8px;">
              <div class="ant-space-item">
                  决策标注
              </div>
          </div>
      </button>
      `;

  var label_panel_html = `
  <div class="container-fluid" id="decision_label_panel"
  style="position: absolute; top: 55%; right: 20px;width: 500px;height:30%;background-color: #292f42;z-index: -9999;">
  <div class="col-md-2 column" style="float: center;">
  </div>
  <div class="row clearfix">
      <div class="col-md-2 column" style="float: center;">
          <div class="row clearfix">
              <label>
                  ads_id:
              </label>
              <label id='ads_id'>
                  -1
              </label>
              <label>
                  obs_id:
              </label>
              <label id='obs_id'>
                  -1
              </label>
              <label>
                  seq_num:
              </label>
              <label id='seq_num'>
                  -1
              </label>
          </div>
      </div>
      <div class="col-md-2 column">
          <div class="row clearfix" style="float: center;">
              <button style="width:45%;margin-left: 3%;background-color: red;transition: background-color 0.3s ease;"
                  onclick="setStartSeq()">
                  seq_start
              </button>
              <button style="width:45%;margin-left: 2%;background-color: green;" onclick="setEndSeq()">
                  seq_end
              </button>
          </div>
          <br>
          <div class="btn-group" style="margin-left: 2%">
              <button style="background-color: #FFBBFF;margin-left: 5px;margin-top: 5px;" id="label_btn_0"
                  type="button" value="0" onclick="onLabel(0)">
                  Ignore(0)
              </button>
              <button style="background-color: #00DDDD;margin-left: 5px;margin-top: 5px;" id="label_btn_1"
                  type="button" value="1" onclick="onLabel(1)">
                  Follow(1)
              </button>
              <button style="background-color: #8C0044;margin-left: 5px;margin-top: 5px;" id="label_btn_2"
                  type="button" value="2" onclick="onLabel(2)">
                  Yield(2)
              </button>
              <button style="background-color: #886600;margin-left: 5px;margin-top: 5px;" id="label_btn_3"
                  type="button" value="3" onclick="onLabel(3)">
                  Overtake(3)
              </button>
              <button style="background-color: #008844;margin-left: 5px;margin-top: 5px;" id="label_btn_4"
                  type="button" value="4" onclick="onLabel(4)">
                  NudgeYield(4)
              </button>
              <button style="background-color: #008888;margin-left: 5px;margin-top: 5px;" id="label_btn_5"
                  type="button" value="5" onclick="onLabel(5)">
                  NudgeOvetake(5)
              </button>
              <button style="background-color: #0000CD;margin-left: 5px;margin-top: 5px;" id="label_btn_6"
                  type="button" value="6" onclick="onLabel(6)">
                  NudgeIgnore(6)
              </button>
              <button style="background-color: #BDB76B;margin-left: 5px;margin-top: 5px;" id="label_btn_7"
                  type="button" value="7" onclick="onLabel(7)">
                  Caution(7)
              </button>
          </div>
          <br>
          <div>
              <div id="decision_label_show_list" style="width:100%">
              </div>
          </div>
          <br>
          <div class="row clearfix" style="float: center;">
              <button id="copy_to_clipboard_btn" style="width:45%;margin-left: 3%;background-color: blue;transition: background-color 0.3s ease;"
                  onclick="copyLabels()">
                  复制
              </button>
              <button style="width:45%;margin-left: 2%;background-color: red;" onclick="clearLabels()">
                  清除
              </button>
          </div>
          <br>
      </div>
  </div>
</div>
</div>

`;

    // 插入 Toast 容器和样式
    function injectToast() {
        // 如果 Toast 容器已经存在,则不重复插入
        if (document.getElementById('toastContainer')) return;

        // 插入 Toast 容器
        const toastContainer = document.createElement('div');
        toastContainer.id = 'toastContainer';
        document.body.appendChild(toastContainer);

        // 插入 Toast 样式
        const style = document.createElement('style');
        style.textContent = `
            /* Toast container */
            #toastContainer {
                position: fixed;
                bottom: 20px;
                right: 20px;
                z-index: 9999;
            }

            /* Individual toast style */
            .toast {
                display: flex;
                align-items: center;
                background-color: #333;
                color: #fff;
                padding: 10px 20px;
                margin-bottom: 10px;
                border-radius: 5px;
                box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
                opacity: 0;
                transform: translateY(20px);
                transition: opacity 0.3s ease, transform 0.3s ease;
            }

            /* Toast visible class */
            .toast.show {
                opacity: 1;
                transform: translateY(0);
            }

            /* Close button */
            .toast .close-btn {
                margin-left: auto;
                background: none;
                border: none;
                color: #fff;
                font-size: 16px;
                cursor: pointer;
            }

            .toast.success {
                background-color: #4caf50;
            }

            .toast.error {
                background-color: #f44336;
            }

            .toast.info {
                background-color: #2196f3;
            }

            .toast.warning {
                background-color: #ff9800;
            }
        `;
        document.head.appendChild(style);
    }

    // 显示 Toast 消息
    function showToast(message, type = 'info') {
        const toastContainer = document.getElementById('toastContainer');

        // 创建 Toast 元素
        const toast = document.createElement('div');
        toast.className = `toast show ${type}`;
        toast.innerHTML = `
            <span>${message}</span>
            <button class="close-btn">×</button>
        `;

        // 关闭按钮事件
        toast.querySelector('.close-btn').addEventListener('click', () => {
            closeToast(toast);
        });

        // 添加到容器中
        toastContainer.appendChild(toast);

        // 自动移除
        setTimeout(() => {
            closeToast(toast);
        }, 3000);
    }

    // 关闭 Toast
    function closeToast(toast) {
        toast.classList.remove('show');
        setTimeout(() => toast.remove(), 300); // 等待动画完成后移除
    }


  function clearLabel() {
    return;
    $("#decision_label_show_list").val("");
    label_list = [];
  }

  function onMouseMove(event) {
    // 计算鼠标偏移量
    var offsetX = event.clientX - initialMouseX;
    var offsetY = event.clientY - initialMouseY;

    // 将偏移量应用于元素的位置
    $("#decision_label_panel").css({
      left: initialElementX + offsetX + "px",
      top: initialElementY + offsetY + "px",
    });
  }

  // 鼠标释放事件处理程序
  function onMouseUp() {
    // 移除事件监听器
    $(document).off("mousemove", onMouseMove);
    $(document).off("mouseup", onMouseUp);
  }

  window.onMouseMove = onMouseMove;
  window.onMouseUp = onMouseUp;
  window.set_cur_info = set_cur_info;
  window.showDecisionLabelPanel = showDecisionLabelPanel;
  window.setStartSeq = setStartSeq;
  window.setEndSeq = setEndSeq;
  window.onLabel = onLabel;
  window.clearLabel = clearLabel;
  window.showLabelList = showLabelList;
  window.copyLabels = copyLabels;
  window.clearLabels = clearLabels;

  setTimeout(function () {
    console.log("3s time out");
    // 初始化 Toast 容器
    injectToast();
    $(".if-header-operations").prepend(label_tab);
    $(".ov-header-operations").prepend(label_tab);
    $("body").append(label_panel_html);
    $("#decision_label_panel").mousedown(function (event) {
      var elementTop = $("#decision_label_panel").offset().top;
      var mouseY = event.clientY;
      console.log("elementTop", elementTop, "mouseY", mouseY);
      if (mouseY > elementTop + 10) {
        return; // 如果不在顶部,则忽略拖动
      }
      // 记录鼠标位置和元素初始位置
      initialMouseX = event.clientX;
      initialMouseY = event.clientY;
      initialElementX = $("#decision_label_panel").offset().left;
      initialElementY = $("#decision_label_panel").offset().top;
      console.log("initialMouseX", initialMouseX);

      // 添加事件监听器
      $(document).mousemove(onMouseMove);
      $(document).mouseup(onMouseUp);
    });

  }, 3000); // 等待3秒
})();