yargs Parsing Issue: Why Does -hx Show Help Menu Instead of Error?

I’m facing this issue with yargs where the combined flag -hx seems to trigger the help menu instead of an error, even though -h is intended to be a help flag and -x is an alias for another option.

import chalk from "chalk";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import {
  ArgumentColor,
  HeadingColor,
  SnippetColor,
  SubHeadingColor,
  ValueColor,
} from "../constants";

// Color-related functions
const colorize = {
  subHeading: (text: string) => chalk.hex(SubHeadingColor)(text),
  argument: (text: string) => chalk.hex(ArgumentColor)(text),
  value: (text: string) => chalk.hex(ValueColor)(text),
  heading: (text: string) => chalk.hex(HeadingColor)(text),
  snippet: (text: string) => chalk.hex(SnippetColor)(text),
};

// Create colored argument
const createColoredArg = (arg: string, value: string) =>
  `${colorize.argument(arg)}${colorize.value(value)}`;

// Command examples
const commandExamples = {
  createDefaultStack: ($0: string, args: string[]) =>
    `${colorize.subHeading("Command to Create Stack by provided Defaults:n")}${$0} ${args.join(" ")}`,
  overrideDefaults: ($0: string, args: string[]) =>
    `n${colorize.subHeading("Command to Override Default Parameters:n")}${$0} ${args.join(" ")}`,
  useConfigFile: ($0: string, arg: string) =>
    `n${colorize.subHeading("Command to use file for all arguments:n")}${$0} ${arg}`,
  createAndCheckStatus: ($0: string, args: string[]) =>
    `n${colorize.subHeading("Command to Create Stack and Check Status:n")}${$0} ${args.join(" ")}`,
  createAndDeleteOnFailure: ($0: string, args: string[]) =>
    `n${colorize.subHeading("Command to Create Stack and Delete on Failure:n")}${$0} ${args.join(" ")}`,
  deleteStack: ($0: string, args: string[]) =>
    `n${colorize.subHeading("Command to Delete Stack:n")}${$0} ${args.join(" ")}`,
};

// yargs configuration
const configureYargs = () => {
  const $0 = colorize.argument("npx @invisinet/stackhub");
  const commonArgs = [
    createColoredArg("--region=", "<region>"),
    createColoredArg("--stack=", "<stack-name>"),
    createColoredArg("--access=", "<access-key-id>"),
    createColoredArg("--secret=", "<secret-access-key>"),
  ];

  return yargs(hideBin(process.argv))
    .strict()
    .strictOptions(true)
    .strictCommands(true)
    .showHelpOnFail(
      false,
      `${colorize.heading("Refer Package Documentation or Exec Below Command")}n${colorize.snippet("npx @invisinet/stackhub --help")}`,
    )
    .help("help")
    .alias("help", "h")
    .version(
      "version",
      "Show Version Info",
      process.env?.npm_package_version ?? "",
    )
    .alias("version", "v")
    .wrap(110)
    .usage("npx @invisinet/stackhub [COMMANDS] [OPTIONS]")
    .example([
      [commandExamples.createDefaultStack($0, commonArgs)],
      [
        commandExamples.overrideDefaults($0, [
          ...commonArgs,
          createColoredArg("--defaults=", "</path/to/CustomDefaults.json>"),
        ]),
      ],
      [
        commandExamples.useConfigFile(
          $0,
          createColoredArg("--config=", "</path/to/CustomConfig.json>"),
        ),
      ],
      [
        commandExamples.createAndCheckStatus($0, [
          ...commonArgs,
          colorize.argument("--check"),
        ]),
      ],
      [
        commandExamples.createAndDeleteOnFailure($0, [
          ...commonArgs,
          colorize.argument("--deleteOnFailure"),
        ]),
      ],
      [
        commandExamples.deleteStack($0, [
          ...commonArgs,
          colorize.argument("--terminate"),
        ]),
      ],
    ])
    .alias({
      region: ["r"],
      stack: ["s", "stackName"],
      access: ["a", "accessKeyId"],
      secret: ["x", "secretAccessKey"],
      defaults: ["d", "overrideParameterDefaults"],
      config: ["c", "configuration"],
      check: ["k", "checkStatusAsync"],
      cleanUp: ["f", "deleteOnFailure"],
      delete: ["t", "terminate"],
    })
    .options({
      region: {
        type: "string",
        demandOption: true,
        describe: "AWS Region Name",
      },
      stack: {
        type: "string",
        demandOption: true,
        describe: "Desired Stack Name in Alphanumeric",
      },
      access: {
        type: "string",
        demandOption: true,
        describe: "Access Key ID Provided by Invisinet",
      },
      secret: {
        type: "string",
        demandOption: true,
        describe: "Secret Access Key Provided by Invisinet",
      },
      defaults: {
        type: "string",
        demandOption: false,
        describe: "Override the Defaults By JSON or YAML",
      },
      check: {
        type: "boolean",
        demandOption: false,
        describe: "Flag to track stack events until completion",
      },
      cleanUp: {
        type: "boolean",
        demandOption: false,
        describe: "Flag to delete stack on creation failure",
      },
      delete: {
        type: "boolean",
        demandOption: false,
        describe: "Flag to Toggle Delete Stack",
      },
    });
};

export default async function initYargs(): Promise<yargs.Arguments> {
  const params = configureYargs();
  return params.argv;
}

Issue:

When I run the command with -hx, yargs displays the help menu instead of an error. The -h flag is meant to trigger help, and -x is an alias for the secret option. My expectation is that -hx should result in an error, but it seems that -h is being prioritized.

Question:

Why does -hx show the help menu rather than an error? How can I configure yargs to ensure that -hx is treated as an error rather than a valid command?

Tried Adding below lines, Still not able fix the issue

    .strict()
    .strictOptions(true)
    .strictCommands(true)

Netsuite: Oauth 2.0 Machine to machine invalid request

I’m trying to setup the Oauth 2.0 authentication Machine to machine in Postman to get an access token for Netsuite.
Postman => Netsuite
I already have created TBA (Oauth 1.0) issue token endpoint and 3ways flow.
I also already have created code that were using Oauth 2.0 Authorization code grant flow.
But this time I can’t manage to successfully get the access token

I followed the documentation regarding the connection, but I always get invalid_request.
Here is the documentation:

I have created the integration, the certificates and the mapping.
I also have compared the JWT created with the help of https://jwt.io/#debugger-io and it work well.
But while sending the request with Postman, it said that this is an invalid request.

Here is the pre-request script in Postman:

const CryptoJS = require('crypto-js');
const CERTIFICATE_ID = pm.environment.get("CERTIFICATE_ID");
const CLIENT_ID = pm.environment.get("CLIENT_ID");
const ACCOUNT_ID = pm.environment.get("ACCOUNT_ID");
const AUD = "https://" + ACCOUNT_ID + ".suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token";
const SIGNATURE_CERTIFICATE = pm.environment.get("SIGNATURE_CERTIFICATE");
let iat = Date.now();
let interval = 1000 * 60 * 30;
let exp = iat + interval;
iat = Math.floor(iat / 1000);
exp = Math.floor(exp / 1000);
let grant_type = "client_credentials";
let client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
let client_assertion_type_encoded = encodeURIComponent(client_assertion_type)
let client_assertion = "";
let header;
let header_encoded;
let payload;
let payload_encoded;
let signature;

// 1) Create the header
header = {
    typ : "JWT",
    alg : "ES256",
    kid : CERTIFICATE_ID
}

// 2) Encode the header
header_encoded = base64url(CryptoJS.enc.Utf8.parse(JSON.stringify(header)))

// 3) Create the paypload
payload = {
    "iss" : CLIENT_ID,
    "scope" : "rest_webservices",
    "aud" : AUD,
    "exp" : exp,
    "iat" : iat
}

// 4) Encode the payload
payload_encoded = base64url(CryptoJS.enc.Utf8.parse(JSON.stringify(payload)))

// 5) Create the signature
signature = base64url(CryptoJS.SHA256(SIGNATURE_CERTIFICATE, header_encoded + "." + payload_encoded))

// 6) Merge the information to create the client assertion
client_assertion = header_encoded + "." + payload_encoded + "." + signature

// 7) Update the variable
// post_parameter = "grant_type=" + grant_type + "&client_assertion_type=" + client_assertion_type + "&client_assertion=" + client_assertion
pm.environment.set("GRANT_TYPE", grant_type);
pm.environment.set("CLIENT_ASSERTION_TYPE", client_assertion_type_encoded);
pm.environment.set("CLIENT_ASSERTION", client_assertion)
// pm.environment.set("CONCATENED_PARAMS", post_parameter);
console.log("URL encoded values", {
    grant_type, client_assertion_type, client_assertion
})

function base64url(source) {
    // Encode in classical base64
    encodedSource = CryptoJS.enc.Base64.stringify(source)
    
    // Remove padding equal characters
    encodedSource = encodedSource.replace(/=+$/, '')
    
    // Replace characters according to base64url specifications
    encodedSource = encodedSource.replace(/+/g, '-')
    encodedSource = encodedSource.replace(///g, '_')
    
    return encodedSource
}

enter image description here
enter image description here

Did I miss something?

How to handle the Chunk Load Error in JavaScript -React Webpack project

I am working on a React Webpack project . I have done the minification and the JS files will be loaded in chunks .

Since we have dynamic imports , Chunk Load Error rarely occurs when the browser encounters an error in fetching some JavaScript files.

How to handle these errors ? I was able to reproduce or see this error happening only once ( I assume it was due to cache ) when we refresh the page it is gone. what are the better ways to handle this ?

I have added Error Boundary to handle the exception. however that doesnt fix the problem . it only handles the exception.

How to fetch username in an tableau extension

I am trying to create a tableau extension for which I need the username… can anyone help me how to extract the username dynamically from tableau to my extension can anyone help me with this solution
when i try to fetch the username it shows undefined..

const getSheetDataForUsername = (worksheets, index) => {
    console.log(worksheets);
    return new Promise(function (resolve, reject) {
      const summaryOptions = {
        maxRows: 0, // Max rows to return. Use 0 to return all rows
        ignoreAliases: false,
        ignoreSelection: false,
        includeAllColumns: true,
        summary: true,
        tableauDataTranspose: true,
      };
      if (index < worksheets.length) {
        // const sheetName = worksheets;
        // const sheetName = worksheets[index].name;
        const sheetName = worksheets[index].Worksheet;
        console.log("Sheetname " + sheetName);
        getSheetData(sheetName, summaryOptions, worksheets)
          .then(function (sheetData) {
            const dataRow = sheetData && sheetData.length ? sheetData[0] : {};
            if (dataRow.hasOwnProperty("AsUser")) {
              UserName = dataRow.AsUser;
              console.log("Found AsUser wb -->: ", UserName);
              setUsername(UserName);
              resolve(UserName);
              alert(username);
            } else {
              console.log("here");
              resolve(getSheetDataForUsername(worksheets, ++index));
            }
          })
          .catch(function (error) {
            console.log("Error getting data for sheet: ", error);
            resolve(UserName);
          });
      } else {
        resolve(UserName);
      }
    });
  };
`

navigator.mediaDevices.getUserMedia, No camera feedback when using mobile browsers but works perfectly in Desktop browsers

When accessing thru desktop browser its working locally and using https:// connection
but when im using mobile (android and IOS) browser (safari for IOS)(chrome and brave) for testing no feedback from my function, not even hitting my message logger and its not also hitting the try catch if theres some error using mobile browser.

Note : Permission on app settings and site setting for browsers are enabled for camera.
I also have secured connection because it was deployed on the server.

here is my code but its not working on mobile browsers, hoping anyone can help me

THankssss.

html

   <video id="video" muted autoplay playsinline width="557" height="418"></video>

js

const video = document.getElementById('video');

   try {
       const stream = await navigator.mediaDevices.getUserMedia({ audio: false, video: true });
       video.srcObject = stream;
       document.getElementById('lblcam').innerHTML = 'it works!!!';

   } catch (err) {
       document.getElementById('lblcam').innerHTML = 'errrr: ' + error.message + '! ';
   }

I also tried this

const videotag = document.getElementById('video');

  try {

      navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
          .then(stream => {


              videotag.srcObject = stream;
              videotag.onloadedmetadata = () => {
                  videotag.play();
              };

              document.querySelectorAll('.btn-cam').forEach(elem => {
                  elem.disabled = false;
              });


          }).catch(err => {

              document.getElementById('lblcam').innerHTML = 'Unable to access the camera: ' + err.message + '!';
              document.querySelectorAll('.btn-cam').forEach(elem => {
                  elem.disabled = true;
              });

          });


  } catch (error) {

      document.getElementById('lblcam').innerHTML = 'Error accessing the camera: ' + error.message + '! ';
      document.querySelectorAll('.btn-cam').forEach(elem => {
          elem.disabled = true;
      });

  }

Tried parameters that suggested from docs and yet no camera feedback from mobile browsers

Suitelt 2.0 Sublist Name shows unwanted behavior

In NetSuite Suitelet Development, sub-list labels often become clickable links due to the default system behavior. We want to display these labels as plain text without any link functionality. Is there any way to achieve this? We don’t want the right-click window as shown in the screenshot to appear or It should be simple plain text.Screenshot

We tried different sublist types but we can’t use them because we want sublist lines to be editable.

How to not violate Open/Closed Principle when checking for type is needed

I am writing a back-end for a program that manages surveys in TypeScript but don’t know how to design my Survey and SurveyRepository class without violating the Open/Closed Principle (OCP)

My survey class looks like this

class Survey {
    private readonly metadata: SurveyMetadata
    private readonly options: SurveyOptions
    private title: string
    private description: string
    private readonly questions: Question[]

//getter setter
}
class Question {

    private readonly metadata: QuestionMetadata
    private required: boolean
    private question: string

}

Now I have a class for every question type

class TextQuestion extends Question {
    //just a super call

}
class ChoiceQuestion extends Question {

    private answerOptions: AnswerOptions
    private isMultiple: boolean
 
}

Now to store my data in the database I wrote a repository class

class SurveyRepository extends IRepositroy {

    public insert(survey: Survey): number

}

Now if I want to insert a survey into a database I also need to store the questions for that I need to know the type of the question and the only way I know to do this is like this:

for(const question of questions){
   
   switch(instanceof question){
    
    case TextQuestion:
        //code to store text question
        break;
    case ChoiceQuestion:
        //code to store choice question
        break;
    }
}

But this violates the OCP.

Solutions I thought of:

Make a repository for every question type would be an option but that way the survey repository wouldn’t make any sense

I read about the visitor pattern would that work in this case?

Unable to use the treemap.js module with highcharts V11.4

There’s a specific graph I need called a ‘treemap with a colour axis’ which requires two modules. treemap.js and heatmap.js.

I’ve tried a few different methods but I keep getting strange errors when I try to include them in my project such as:

TypeError: Cannot read properties of undefined (reading ‘indexOf’)
at pushUnique (script?v=vX17qqiPDxzKs18Nj2Vt_4PDjBMkk_DMrxvt8ZpUlvY1:47720:323)
at x.compose (treemap.js:8:2115)
at treemap.js:8:25053
at i (treemap.js:8:368)
at treemap.js:8:24845
at treemap.js:8:219
at treemap.js:8:271

I’ve tried including both modules when it lazy loads the page:

lazy: [‘$ocLazyLoad’, function ($ocLazyLoad) {
return $ocLazyLoad.load([{
name: ‘HerdManagementWeb’,
files: [
‘https://code.highcharts.com/modules/heatmap.js’,
‘https://code.highcharts.com/modules/treemap.js’,
url(“/version/resource?path=~/bundles/milkcomposition&ext=.js”)
]
}]);
}]

The treemap file was just the Highcharts module relabeled.

I’ve also tried downloading the modules myself and including them in the pages bundle:
scriptBundle.Include(“~/Scripts/libraries/highcharts11/heatmap.js”);
scriptBundle.Include(“~/Scripts/libraries/highcharts11/treemap.js”);

Same problem as before, treemap is the wrong file.

I figured maybe treemap is already included in the highcharts module, so I removed the treemap.js module and it complains that I don’t have treemap:

Error: Highcharts error #17: www.highcharts.com/errors/17/?missingModuleFor=treemap

  • missingModuleFor: treemap

So if it won’t let me download the correct file, it won’t load it via the direct link provided by HighCharts in their own documentation and treemap is not included in the HighCharts module, what am I supposed to do?

504 gateway timeout error when bigquery is performing slowly

Context: I am naive developer. My team has an array of services deployed in k8lens. 2 services are there, service_1 : self-service, service_2: user-journey. self-service is a fullstack jhipster spring-boot and react app for internal purpose and user-journey is an apache-camel spring boot based microservice. self-service communicates with user-journey using grpc call.

service architecture

Issue: Everyday from 9-11 am IST, bigquery is down for us. During this time when we query from self-service, then request flows till user-journey, job gets submitted to BQ and then after around 2-3 mins response is available with user-journey which it sends back (via the grpc response) to self-service which then should render on frontend (response of the http get call).
But it is not rendering it on frontend and before that only gateway timeout error 504 is comming.
response on frontend
under network

(please ignore the time-stamps in the pictures above, and focus on the issue.)

On the frontend code, i have set the timeout of 1400 sec (verified from the request object sent via axios), on the backend it sends a grpc call to the user-journey and gets response after 2-3 mins (verified from the logs)
self-service
user-journey

front-end code:

// user-journey

const onSubmit = async () => {
    setLoading(true);
    setResponse([]);
    setSummary({});
    setFilterList([]);
    const requestUrl = `api/user-journey/range?startTs=${
      Math.round(startDate.valueOf()) / 1000
    }&field=user_id&fieldValue=${fieldValue}&endTs=${Math.round(endDate.valueOf()) / 1000}`;
    
    console.log('Request URL from user-journey:', requestUrl);
    
    try {
      const payload = await axios.get(requestUrl);
      
      console.log('Payload from user-journey:', payload);
      
      const { filterData, res } = _calFilterData(payload.data.activity);
      setResponse(res);
      setSummary(filterData);
      setFilterList(Object.keys(filterData));
    } catch (e) {
      console.error('Error:', e);
      toast.error(e.response?.data?.customErrorMessage || e.response?.data?.detail);
    }
    setLoading(false);
  };
//axios-global-interceptor code

const TIMEOUT = 1 * 1400 * 1000;
axios.defaults.timeout = TIMEOUT;
axios.defaults.baseURL = SERVER_API_URL;

const setupAxiosInterceptors = onUnauthenticated => {
  const onRequestSuccess = config => {
    const token = Storage.local.get('jhi-authenticationToken') || Storage.session.get('jhi-authenticationToken');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  };
  const onResponseSuccess = response => response;
  const onResponseError = err => {
    const status = err.status || (err.response ? err.response.status : 0);
    if (status === 403 || status === 401) {
      onUnauthenticated();
    }
    return Promise.reject(err);
  };
  axios.interceptors.request.use(onRequestSuccess);
  axios.interceptors.response.use(onResponseSuccess, onResponseError);
};

export default setupAxiosInterceptors;

Only during the mentioned hours, when BQ is slow for us, the frontend gives 504 error. but the response is still comming as we can see on the logs of self-service and user-journey.

I tried to reproduce this error on my local, by putting thread.sleep(300_000) in backend code as well as multiple breakpoints on frontend. Frontend still renders the response even when the response comes at a delay of more than 30 mins. but on production it gives timeout 504 issue.

What could be the error ? how to resolve this ?

Things I have verified:

  1. Frontend does set the timeout of around 1400 secs.
  2. backend gets the response from the user-journey.
  3. but frontend gives 504 error only in prod during the mentioned hours.

more context: 2 instances of both the service is deployed on k8lens. jhipster uses undertow as its server.

How to Make QR Codes Generated by qrcodejs2 and zxing Consistent in Pixel Alignment?

I am working on a project where QR codes are generated on both the frontend and backend. On the frontend, I am using the qrcodejs2 library, and on the backend, I am using the zxing library(J). However, I need to ensure that the QR codes generated by both libraries are visually consistent in terms of pixel alignment.

Problem Description:

I need to ensure that QR codes generated by qrcodejs2 (JavaScript library on the frontend) and zxing (Java library on the backend) have consistent pixel alignment.(It is necessary to adjust the parameters of the back end so that the QR code generated by the back end and the pixels of the front end are always maintained)
Currently, The QR code scans generated by these libraries are consistent, but their pixels are misaligned
Libraries Used:

qrcodejs2 (JavaScript library for frontend QR code generation)
zxing (Java library for backend QR code generation)
Configuration Details:
java library:

        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.4.1</version>
        </dependency>

js library:
"qrcodejs2": "^0.0.2",

java code:

 public static void generateQRCode(String content, String filePath) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.MARGIN, 1);
        hints.put(EncodeHintType.ERROR_CORRECTION, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.L);
        BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300, hints);
        Path path = FileSystems.getDefault().getPath(filePath);
        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
    }

    public static void main(String[] args) throws IOException, WriterException {
        generateQRCode(
                "https://www.google.com", "qrcode.png");
    }

js code:

        new QRCode("qrcode2", {
          text: "https://www.google.com",
          width: this.env === 0 ? 160 : 150,
          height: this.env === 0 ? 160 : 150,
          colorDark: "#000000",
          colorLight: "#ffffff",
          correctLevel: QRCode.CorrectLevel.L,
        })

java result
enter image description here

js result
enter image description here

PushManager subscription – AbortError: DOMException: Error retrieving push-subscription – Firefox for Android

On Firefox for Android / Fennec (newest version) I cannot subscribe to push-notifications.
You can check it out on cleverpush.com.
It’s the same problem as mine.

My script subscribe.js should do the following:

  1. Get permissions for sending Notifications – works fine

  2. check for an existing subscription of this browser / device (ServiceWorkerRegistration.pushManager.getSubscription();) – this works fine on Safari, Chrome and Firefox for Windows, Linux and macOS. It fails on Firefox for Android / Fennec (F-Droid).
    The error is an AbortError: DOMException: Could not retrieve push subscription.. The same error happens on cleverpush.com with Firefox for Android / Fennec.

  3. When the user clicks a Button “Register for Push-Notifications”, it executes const subscription = await ServiceWorkerRegistration.pushManager.subscribe(...);. Same error like in (2.)

Many thanks if someone can tell me “this is a bug from mozilla” or “you made some mistake, here the explanation” or “this question has already answers here: …”!

How to add colorbar legend on openlayers heatmap?

https://openlayers.org/en/latest/examples/heatmap-earthquakes.html

When I reviewed the API documentation for the HeatmapLayer, I couldn’t find any explanation about the legend. While searching for a solution, I managed to create a gradient legend manually, but it doesn’t seem to accurately represent the values derived from the data. Specifically, the part where ctx.fillText(‘7.0’, 25, 140); is used to display min, median, and max values separately makes me question if it’s a proper representation of the heatmap’s data. Therefore, I am looking for a way to implement a legend that reflects changes well when the data provided by OpenLayers changes while using the HeatmapLayer.

const vector = new HeatmapLayer({
  source: new VectorSource({
    url: 'data/kml/2012_Earthquakes_Mag5.kml',
    format: new KML({
      extractStyles: false,
    }),
  }),
  blur: parseInt(blur.value, 10),
  radius: parseInt(radius.value, 10),
  weight: function (feature) {
    // 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a
    // standards-violating <magnitude> tag in each Placemark.  We extract it from
    // the Placemark's name instead.
    const name = feature.get('name');
    const magnitude = parseFloat(name.substr(2));
    return magnitude - 5;
  },
});


const updateLegend = function () {
  const canvas = document.getElementById('legend');
  const ctx = canvas.getContext('2d');
  const gradient = ctx.createLinearGradient(0, 0, 0, 150);

  // Example color stops for the legend
  gradient.addColorStop(0, 'rgba(0, 0, 255, 1)');
  gradient.addColorStop(0.5, 'rgba(0, 255, 0, 1)');
  gradient.addColorStop(1, 'rgba(255, 0, 0, 1)');

  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, 20, 150);

  // Add labels for magnitude values
  ctx.fillStyle = '#000';
  ctx.font = '12px Arial';
  ctx.fillText('5.0', 25, 10);
  ctx.fillText('9.0', 25, 75);
  ctx.fillText('7.0', 25, 140);
};


    <div id="legend-container">
      <canvas id="legend" width="150" height="150"></canvas>
    </div>

here’s what i tried.

https://codesandbox.io/s/heatmap-earthquakes-forked-p6tx9x?file=/main.js:2561-2591

manually drawn gradient legend

How can I calculate months in setInterval [closed]

There was a project that required me to calculate months, so I used setInterval to update it every month, but there was something abnormal, as it did not count it as a month, but rather counted it as if it were less than seconds. Here is the code.

setInterval(function(){}, (1000 * 60 * 60 * 24 * 30));

I tried to change the number, but the account remains the same and the problem is not solved