Up-down arrows buttons (Mobile)

Creates up-down arrows buttons on chart

您需要先安裝使用者腳本管理器擴展,如 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 (Mobile)
// @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       2.0.1
// @match         https://www.tradingview.com/chart/*
// @run-at        document-body
// @grant         GM_addStyle
// @noframes
// ==/UserScript==

/* jshint esversion: 8 */
/* eslint no-multi-spaces: 'off' */

(function() {
  'use strict';

  // The script creates an arrows inside of a buttons. Buttons represent the arrows hitboxes

  // Set to true to show a red outlines representing buttons hitboxes, or false to hide them
  const DEBUG_OUTLINE = false;

  // For a buttons/arrows sizes use these values:
  // '50px' to set 50 pixels or '50vw' to set 50% of view width or '50vh' for a view height.
  // Percents are not recommended because they're always based on width of a parent element

  const X_GAP_SIDE = 'right';    // 'left' or 'right'
  const Y_GAP_SIDE = 'bottom';   // 'top' or 'bottom'
  const BUTTONS_X_GAP = '0px';   // x gap size
  const BUTTONS_Y_GAP = '100px';  // y gap size

  const BUTTONS_WIDTH = '60px';
  const BUTTONS_HEIGHT = '55px';

  // This is useful when you're editing the arrows size related to the buttons hitboxes.
  // Fractional values like 1.4 or 0.7 are allowed too
  const ARROWS_SCALE = 0.85;

  // This is useful when you're editing the arrows position related to the buttons hitboxes.
  // Represents individual inner gaps of the buttons. 4 values representing the sides where
  // first value is the top gap, and the other three are right, bottom, left sides respectively.
  const UP_BUTTON_PADDING   = '5px 5px 0px 5px'; // top right bottom left
  const DOWN_BUTTON_PADDING = '0px 5px 5px 5px';
  const ARROWS_OPACITY = 0.8; // 1 is fully visible, 0.5 is half visible

  const ARROW_UP_ROTATE = 0; // clockwise, may take negative values
  const ARROW_DOWN_ROTATE = 180;

  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 btnsContainer = document.createElement('div');
  const btnUp = document.createElement('button');
  const btnDown = document.createElement('button');

  btnsContainer.classList.add('up-down-arrows');

  GM_addStyle(`
    div.up-down-arrows {
      position: fixed;
      user-select: none;
      z-index: 3;
      ${X_GAP_SIDE}: ${BUTTONS_X_GAP};
      ${Y_GAP_SIDE}: ${BUTTONS_Y_GAP};
    }

    div.up-down-arrows button {
      width: ${BUTTONS_WIDTH};
      height: ${BUTTONS_HEIGHT};
      display: block;
      padding: 0;
      box-sizing: border-box;
      cursor: pointer;
      overflow: hidden;
      background: none;
      border: ${DEBUG_OUTLINE ? '1px solid red' : 'none'};
    }

    div.up-down-arrows img {
      scale: ${ARROWS_SCALE};
      width: 100%;
      opacity: ${ARROWS_OPACITY};
      height: -moz-available;
      height: -webkit-fill-available;
      height: fill-available;
    }
  `);

  btnUp.append(document.createElement('img'));
  btnUp.addEventListener('click', () => pressKey('ArrowUp', 38));
  btnUp.style.padding = UP_BUTTON_PADDING;
  btnUp.firstChild.src = ARROW_UP_SRC;

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

  btnDown.append(document.createElement('img'));
  btnDown.addEventListener('click', () => pressKey('ArrowDown', 40));
  btnDown.style.padding = DOWN_BUTTON_PADDING;
  btnDown.firstChild.src = ARROW_DOWN_SRC;

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

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

  btnsContainer.append(btnUp, btnDown);
  document.body.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
}());