Up-down arrows buttons for the Tradingview Mobile Site chart

Creates up-down arrows buttons on chart

当前为 2025-02-03 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 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
}());