Up-down arrows buttons for the Tradingview Mobile Site chart

Creates up-down arrows buttons on chart

目前為 2025-02-03 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name          Up-down arrows buttons for the Tradingview Mobile Site chart
// @description   Creates up-down arrows buttons on chart
// @author        Konf
// @namespace     https://greasyfork.org/users/424058
// @icon          https://www.google.com/s2/favicons?sz=64&domain=tradingview.com
// @version       1.1.0
// @match         https://www.tradingview.com/*
// @require       https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js#sha512-wkU3qYWjenbM+t2cmvw2ADRRh4opbOYBjkhrPGHV7M6dcE/TR0oKpoDkWXfUs3HrulI2JFuTQyqPLRih1V54EQ==
// @run-at        document-body
// @grant         none
// @noframes
// ==/UserScript==

/* jshint esversion: 8 */

(function() {
  'use strict';

  const DEBUG_OUTLINE = false;       // true adds red outlines to show hitboxes, false hides them

  const BUTTONS_WIDTH = '100%';      // set to 100% to adapt dynamically to price column, or use '50px'
  const BUTTONS_HEIGHT = '60px';     // can't use percents here
  const BUTTONS_BOTTOM_GAP = '40px'; // bottom padding, can't use percents here

  const ARROWS_SCALE = 1;      // can be fractional values like 1.4, maybe width is not even needed
  const ARROWS_WIDTH = '40px'; // can not go well over 100%, use scale instead
  const ARROWS_OPACITY = 0.8;  // 1 is fully visible and 0 is fully transparent, 0.5 is half
  const ARROW_UP_SRC = 'https://img.icons8.com/fluency-systems-filled/2962ff/128/triangle.png';
  const ARROW_DOWN_SRC = 'https://img.icons8.com/fluency-systems-filled/2962ff/128/triangle.png';
  const ARROW_UP_ROTATE = 0;   // clockwise, may take negative values
  const ARROW_DOWN_ROTATE = 180;

  const Q = {
    priceAxis: 'div.price-axis',
  };

  document.arrive(Q.priceAxis, { existing: true }, (priceAxis) => {
    const btnsContainer = document.createElement('div');
    const btnUp = document.createElement('button');
    const btnDown = document.createElement('button');

    btnUp.addEventListener('click', () => pressKey('ArrowUp', 38));
    btnDown.addEventListener('click', () => pressKey('ArrowDown', 40));

    for (const btn of [btnUp, btnDown]) {
      btn.style.width = '100%';
      btn.style.height = BUTTONS_HEIGHT;
      btn.style.padding = '0';
      btn.style.boxSizing = 'border-box';
      btn.style.cursor = 'pointer';
      btn.style.overflow = 'hidden';
      btn.style.background = 'none';

      if (DEBUG_OUTLINE) {
        btn.style.border = '1px solid red';
      } else {
        btn.style.border = 'none';
      }

      const img = document.createElement('img');

      img.style.scale = ARROWS_SCALE;
      img.style.width = ARROWS_WIDTH;
      img.style.opacity = ARROWS_OPACITY;

      btn.append(img);
    }

    btnUp.firstChild.src = ARROW_UP_SRC;
    btnDown.firstChild.src = ARROW_DOWN_SRC;

    if (ARROW_UP_ROTATE) {
      btnUp.firstChild.style.transform = `rotate(${ARROW_UP_ROTATE}deg)`;
    }

    if (ARROW_DOWN_ROTATE) {
      btnDown.firstChild.style.transform = `rotate(${ARROW_DOWN_ROTATE}deg)`;
    }

    btnsContainer.style.width = BUTTONS_WIDTH;
    btnsContainer.style.position = 'absolute';
    btnsContainer.style.bottom = BUTTONS_BOTTOM_GAP;
    btnsContainer.style.right = '0';
    btnsContainer.style.zIndex = '3';

    for (const el of [
      btnsContainer, btnUp, btnDown, btnUp.firstChild, btnDown.firstChild,
    ]) {
      el.style.userSelect = 'none';
      el.setAttribute('draggable', 'false');
      el.addEventListener('dragstart', (ev) => {
        ev.preventDefault();
        ev.stopImmediatePropagation();
      });
    }

    btnsContainer.append(btnUp, btnDown);
    priceAxis.parentElement.append(btnsContainer);
  });

  // utils ----------------------------------------------------------------------

  function pressKey(key, code) {
    const event = new KeyboardEvent('keydown', {
      key,
      code,
      keyCode: code,
      which: code,
      bubbles: true,
    });

    document.body.dispatchEvent(event);
  }

  // ---------------------------------------------------------------------- utils
}());