tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

shapes-utils.js (5831B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 /**
      8 * Get the distance between two points on a plane.
      9 *
     10 * @param {number} x1 the x coord of the first point
     11 * @param {number} y1 the y coord of the first point
     12 * @param {number} x2 the x coord of the second point
     13 * @param {number} y2 the y coord of the second point
     14 * @returns {number} the distance between the two points
     15 */
     16 const getDistance = (x1, y1, x2, y2) => {
     17  return Math.round(Math.hypot(x2 - x1, y2 - y1));
     18 };
     19 
     20 /**
     21 * Determine if the given x/y coords are along the edge of the given ellipse.
     22 * We allow for a small area around the edge that still counts as being on the edge.
     23 *
     24 * @param {number} x the x coordinate of the click
     25 * @param {number} y the y coordinate of the click
     26 * @param {number} cx the x coordinate of the center of the ellipse
     27 * @param {number} cy the y coordinate of the center of the ellipse
     28 * @param {number} rx the x radius of the ellipse
     29 * @param {number} ry the y radius of the ellipse
     30 * @param {number} clickWidthX the width of the area that counts as being on the edge
     31 *                             along the x radius.
     32 * @param {number} clickWidthY the width of the area that counts as being on the edge
     33 *                             along the y radius.
     34 * @returns {boolean} whether the click counts as being on the edge of the ellipse.
     35 */
     36 const clickedOnEllipseEdge = (
     37  x,
     38  y,
     39  cx,
     40  cy,
     41  rx,
     42  ry,
     43  clickWidthX,
     44  clickWidthY
     45 ) => {
     46  // The formula to determine if something is inside or on the edge of an ellipse is:
     47  // (x - cx)^2/rx^2 + (y - cy)^2/ry^2 <= 1. If > 1, it's outside.
     48  // We make two ellipses, adjusting rx and ry with clickWidthX and clickWidthY
     49  // to allow for an area around the edge of the ellipse that can be clicked on.
     50  // If the click was outside the inner ellipse and inside the outer ellipse, return true.
     51  const inner =
     52    (x - cx) ** 2 / (rx - clickWidthX) ** 2 +
     53    (y - cy) ** 2 / (ry - clickWidthY) ** 2;
     54  const outer =
     55    (x - cx) ** 2 / (rx + clickWidthX) ** 2 +
     56    (y - cy) ** 2 / (ry + clickWidthY) ** 2;
     57  return inner >= 1 && outer <= 1;
     58 };
     59 
     60 /**
     61 * Get the distance between a point and a line defined by two other points.
     62 *
     63 * @param {number} x1 the x coordinate of the first point in the line
     64 * @param {number} y1 the y coordinate of the first point in the line
     65 * @param {number} x2 the x coordinate of the second point in the line
     66 * @param {number} y2 the y coordinate of the second point in the line
     67 * @param {number} x3 the x coordinate of the point for which the distance is found
     68 * @param {number} y3 the y coordinate of the point for which the distance is found
     69 * @returns {number} the distance between (x3,y3) and the line defined by
     70 *          (x1,y1) and (y1,y2)
     71 */
     72 const distanceToLine = (x1, y1, x2, y2, x3, y3) => {
     73  // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points
     74  const num = Math.abs((y2 - y1) * x3 - (x2 - x1) * y3 + x2 * y1 - y2 * x1);
     75  const denom = getDistance(x1, y1, x2, y2);
     76  return num / denom;
     77 };
     78 
     79 /**
     80 * Get the point on the line defined by points a,b that is closest to point c
     81 *
     82 * @param {number} ax the x coordinate of point a
     83 * @param {number} ay the y coordinate of point a
     84 * @param {number} bx the x coordinate of point b
     85 * @param {number} by the y coordinate of point b
     86 * @param {number} cx the x coordinate of point c
     87 * @param {number} cy the y coordinate of point c
     88 * @returns {Array} a 2 element array that contains the x/y coords of the projected point
     89 */
     90 const projection = (ax, ay, bx, by, cx, cy) => {
     91  // https://en.wikipedia.org/wiki/Vector_projection#Vector_projection_2
     92  const ab = [bx - ax, by - ay];
     93  const ac = [cx - ax, cy - ay];
     94  const scalar = dotProduct(ab, ac) / dotProduct(ab, ab);
     95  return [ax + scalar * ab[0], ay + scalar * ab[1]];
     96 };
     97 
     98 /**
     99 * Get the dot product of two vectors, represented by arrays of numbers.
    100 *
    101 * @param {Array} a the first vector
    102 * @param {Array} b the second vector
    103 * @returns {number} the dot product of a and b
    104 */
    105 const dotProduct = (a, b) => {
    106  return a.reduce((prev, curr, i) => {
    107    return prev + curr * b[i];
    108  }, 0);
    109 };
    110 
    111 /**
    112 * Determine if the given x/y coords are above the given point.
    113 *
    114 * @param {number} x the x coordinate of the click
    115 * @param {number} y the y coordinate of the click
    116 * @param {number} pointX the x coordinate of the center of the point
    117 * @param {number} pointY the y coordinate of the center of the point
    118 * @param {number} radiusX the x radius of the point
    119 * @param {number} radiusY the y radius of the point
    120 * @returns {boolean} whether the click was on the point
    121 */
    122 const clickedOnPoint = (x, y, pointX, pointY, radiusX, radiusY) => {
    123  return (
    124    x >= pointX - radiusX &&
    125    x <= pointX + radiusX &&
    126    y >= pointY - radiusY &&
    127    y <= pointY + radiusY
    128  );
    129 };
    130 
    131 const roundTo = (value, exp) => {
    132  // If the exp is undefined or zero...
    133  if (typeof exp === "undefined" || +exp === 0) {
    134    return Math.round(value);
    135  }
    136  value = +value;
    137  exp = +exp;
    138  // If the value is not a number or the exp is not an integer...
    139  if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
    140    return NaN;
    141  }
    142  // Shift
    143  value = value.toString().split("e");
    144  value = Math.round(+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
    145  // Shift back
    146  value = value.toString().split("e");
    147  return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
    148 };
    149 
    150 exports.getDistance = getDistance;
    151 exports.clickedOnEllipseEdge = clickedOnEllipseEdge;
    152 exports.distanceToLine = distanceToLine;
    153 exports.projection = projection;
    154 exports.clickedOnPoint = clickedOnPoint;
    155 exports.roundTo = roundTo;