Capture an event of native browser window in Angular 8

“windows.open() – window to process login and allowing consent to fetch the documents from third-party server like any storage drive which contains files.”

now suppose I’m running angular application on http://localhost:4200/app and on the same page, opening the other browser window using windows.open(), in that same browser windows performing some task like login, accepting consent. after accepting consent the same window reloaded with redirect Uri(ex. https://testsite.com) and some parameters and window is not yet closed with an URL like https://testsite.com/app?code=12345&state=xyz

So, is it possible to extract the parameter from inner browser window and close it using angular code? is there any event that capture another windows from our application?

We have tried messageEventListener(event: MessageEvent) but no help and we tried using iframe it is not allowing to do that

how to open custom context menu on textarea if word highlighted using JavaScript-jquery

The first source is the context menu. The words change everything, but I want only those words to be highlighted, otherwise the context menu doesn’t open The second source highlights how these two sources can work together the words in the outside array should appear context menu in the textarea and When the context menu becomes no options selected, a word is deleted That’s how it’s going to be fixed second source
second source well run on xampp control.

let textarea = document.getElementsByTagName("textarea")[0];
let contextMenu = document.getElementsByClassName("custom-context-menu")[0];

contextMenu.setAttribute("open", true);

textarea.oncontextmenu = (event) => {
  event.preventDefault();

  let string = event.target.value;
  let words = string.split(' ');
  

  if (words.length > 0) {
    let x = event.pageX,
      y = event.pageY;
    contextMenu.style.left = x + "px";
    contextMenu.style.top = y + "px";
    contextMenu.style.display = "block";

    contextMenu.classList.add("on");
  }
}

document.onclick = (event) => {
  if (contextMenu.classList.contains("on")) {
    contextMenu.classList.remove("on");
    contextMenu.style.display = "none";

    let textContent = textarea.value;
    let start = Math.max(0, textContent.lastIndexOf(' ', textarea.selectionStart) + 1);
    let end = textContent.substr(textarea.selectionEnd);
    end = end.indexOf(' ');
    end = (end < 0 ? textContent.length : end) + textarea.selectionEnd;
    textarea.value = textContent.substr(0, start) +
      event.srcElement.innerText +
      textContent.substr(end);
  }
}
.custom-context-menu {
  z-index: 1100;
  display: none;
  position: absolute;
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid black;
  background: white;
}

.custom-context-menu li {
  padding: 5px;
  cursor: pointer;
}

.custom-context-menu li:hover {
  background-color: aqua;
}
<!DOCTYPE html>

<head>
  <link href="./main.css" rel="stylesheet" />
</head>

<body>
  <textarea rows=4 cols=50>hello This is some text. Click on any word and then do right click</textarea>
  <ul class="custom-context-menu">
    <li>rule</li>
    <li>slde</li>
    <li>rebaz</li>
  </ul>
</body>
<script src="./main.js" type="text/javascript"></script>

</html>

How to word-wrap chart title in chart.js by providing the text value of type string?

The chart title gets squashed when the title is bit long as compared to the width of the chart(snap below), so is there any option by which the chart title can enter into next line something like word-wrap.

plugins: {
               title: {
                  display: true,
                  text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In rutrum leo ut tellus tempor, venenatis vulputate nisl sagittis. Morbi id fringilla purus. Etiam imperdiet ipsum.',
                  color: 'navy',
                  position: 'top',
                  align: 'center',
                  font: {
                     weight: 'bold'
                  },
                  padding: 8,
               }
            }

Chart with Title squashed

Note: The text property must be of string type, not string of array type.

I expect the chart title to not getting squashed and enter into next line when the length of the title is longer than the width of the of the chart, something like below:

enter image description here

How to apply CSS to a parent element if only a certain child element exists?

Is a there a way using CSS to apply styles to a parent element only if the parent has a certain child element?

Here is my HTML:

<div class="Environment">
    <div class="col-md-6 interior_environment">
        <div class="aboutEnvironment">
            <div class="col-sm-12 col-md-12">
                <div class="title_environment"></div>
                <div class="description_environment">
                    <p><span>The natural environment or natural world encompasses all living and non-living things occurring naturally, meaning in this case not artificial. The term is most often applied to Earth or some parts of Earth.</span></p>
                </div>
            </div>
        </div>       
    </div>
</div>

I want add the following CSS(mentioned below) to .Environment and .interior_environment only if .aboutEnvironment class is present inside .Environment .interior_environment.

If .aboutEnvironment class is not present inside .Environment .interior_environment then this CSS should not be added to .Environment and .interior_environment.

.Environment
{
  display: block;
}
.interior_environment
{
  flex: 1;
}

Is there a way to do this using CSS or does it have to be done through JavaScript?

Next.js middleware and Link add query params to the url on links

I am having the issue on the Link and middleware that catch params.

Project structure of my Next.js 12.2

  1. pages/buy/[cid]
  2. middleware.ts

Middleware.ts

import { type NextRequest, NextResponse } from 'next/server';

const isAllowedPageQuery = (queryParam: string, pathname: string): boolean => {
    const searchPageParams = ['order', 'price', 'keywords'];

    return (
        queryParam.includes('page') ||
      )
    );
};
// Define a middleware function that takes a NextRequest object as a parameter.
export function middleware(req: NextRequest) {
    const { search, pathname, searchParams } = req.nextUrl;

    if (search) {
        const urlSearchParams = new URLSearchParams(search);
        const urlSearchParamsNew = new URLSearchParams('');
        const params = Object.fromEntries(urlSearchParams.entries());
        const ToDelete: Array<string> = [];

        Object.entries(params).map(([key, value]) => {
            // check if the query parameter is allowed
            // if allowed, add it to the new URLSearchParams object
            // if not allowed, add it to the blacklist array
            isAllowedPageQuery(key, pathname)
                ? urlSearchParamsNew.set(key, value)
                : ToDelete.push(key);
        });
        const newUrl = req.nextUrl.origin + pathname + urlSearchParamsNew;

        if (ToDelete.length > 0) {
            return NextResponse.redirect(req.nextUrl, 301);
        }
    }
    return NextResponse.next();
}

When I click on a Link href=”/buy/toy”, the link will be xxxx.com/buy/toy?cid=toy

Is there a way the middleware can hide the params when I use a dynamic link with . Otherwise because the params is not in the isAllowedPageQuery the page goes into a infinite loop (using Next.js 12.2)…

because the params is not in the isAllowedPageQuery in the middleware to Next.Js the page goes into a infinite loop

How can I fix remove the empty rows before saving the data?

I have a code and the link google sheet
the problem is when I fill in the data and then click on the button Submit at PrintForm sheet the data will be saved to PrintLog sheet but it includes the empty rows
so I would like to remove the empty rows before saving that data to RpintLog sheet but I don’t know how I can handle it, Looking forward to receiving your support

This is the input form

This is the output

Link google sheet

function Printting() {
  // We will add our code here. 
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  // collect the data
  const sourceRange = ss.getRangeByName("clearRange");
  const clearRange = sourceRange.getValues().flat();
  const SOLA_sourceRange = ss.getRangeByName("SOLA");
  const SOLA_sourceVals = SOLA_sourceRange.getValues().flat();

  const SOLB_sourceRange = ss.getRangeByName("SOLB");
  const SOLB_sourceVals = SOLB_sourceRange.getValues().flat();

  const SOLC_sourceRange = ss.getRangeByName("SOLC");
  const SOLC_sourceVals = SOLC_sourceRange.getValues().flat();

  const SOLD_sourceRange = ss.getRangeByName("SOLD");
  const SOLD_sourceVals = SOLD_sourceRange.getValues().flat();

  const SOLE_sourceRange = ss.getRangeByName("SOLE");
  const SOLE_sourceVals = SOLE_sourceRange.getValues().flat();

  const SOLF_sourceRange = ss.getRangeByName("SOLF");
  const SOLF_sourceVals = SOLF_sourceRange.getValues().flat();

  const SOLG_sourceRange = ss.getRangeByName("SOLG");
  const SOLG_sourceVals = SOLG_sourceRange.getValues().flat();

  const SOLH_sourceRange = ss.getRangeByName("SOLH");
  const SOLH_sourceVals = SOLH_sourceRange.getValues().flat();
  // Gather current dts and user email.
  const date = new Date();
  const email = Session.getActiveUser().getEmail();
  const SOLA_data = [date, email, ...SOLA_sourceVals];
  const SOLB_data = [date, email, ...SOLB_sourceVals];
  const SOLC_data = [date, email, ...SOLC_sourceVals];
  const SOLD_data = [date, email, ...SOLD_sourceVals];
  const SOLE_data = [date, email, ...SOLE_sourceVals];
  const SOLF_data = [date, email, ...SOLF_sourceVals];
  const SOLG_data = [date, email, ...SOLG_sourceVals];
  const SOLH_data = [date, email, ...SOLH_sourceVals];
  // append the data
  const destinationSheet = ss.getSheetByName("PrintLog");
  destinationSheet.appendRow(SOLA_data);
  destinationSheet.appendRow(SOLB_data);
  destinationSheet.appendRow(SOLC_data);
  destinationSheet.appendRow(SOLD_data);
  destinationSheet.appendRow(SOLE_data);
  destinationSheet.appendRow(SOLF_data);
  destinationSheet.appendRow(SOLG_data);
  destinationSheet.appendRow(SOLH_data);
  // clear the source sheet rows
  sourceRange.clearContent();
  ss.toast("Success: Item Added to the data Log!");

};

nodejs schema validation: get value of custom field in case of error using Ajv

I want to validate ‘data’ object and in case of validation error I want to print error + value of severityType (‘error’ or’warning’ or can be any value).
I have following nodeJs code:

const Ajv = require('ajv');
const addFormats = require('ajv-formats');
const ajv = new Ajv({allErrors: true, allowUnionTypes: true});
addFormats(ajv);

// addKeyword for severityType ??

const schema  = {
  $schema: 'http://json-schema.org/draft-07/schema#',
  type: 'object',
  properties: {
    slices: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          personId: { type: 'string', severityType: 'error' },
          position: { type: 'string', severityType: 'error' },
          networkId: { type: 'string', severityType: 'warning' },
        },
        required: ['personId', 'position', 'networkId'],
      },
    },
  },
  required: ['slices'],
}

const data = {
  slices: [
    {
      personId: 55, // This should trigger the severityType 'error'
      position: null, // This should trigger the severityType 'error'
      networkId: null, // This should trigger the severityType 'warning'
    },
  ],
};

const validateSchema = (data, schema) => {
  const validate = ajv.compile(schema);
  const isValid = validate(data);
  if (validate.errors) {
    logger.error(`Validation errors: ${JSON.stringify(validate.errors)}`);
    logger.error(`severityType : //print severityType `);
  }
  return {
    isValid,
    errors: validate.errors,
  };
};

I know it is not standard JSON validation schema, but I added it as custom filed to fetch its value to be able to act depend on severityType value in case of error of validation. How to be able to get severityType value?

Center elements over img

I would like to have “Hello” and the black box on the right centered exactly over the image. I dont want to use position: absolute and top: %. Please help me 🙁

How it looks now: https://imgur.com/a/vY4Qcpm
How I want it to look: https://imgur.com/a/ywkqrO2

HTML

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body style="margin: 0">

        <img id="background" src="img/background.jpeg">
        <div class="middle-part">
            <p id="text">Hello</span></p>
            <div id="field">
                <div id="field-content"></div>
            </div>
        </div>

    </body>
</html>

CSS

html {
    scroll-behavior: smooth;
}

#background {
    width: 100%;
    height: 80vh;
    object-fit: cover;
    pointer-events: none;
}

.middle-part {
    margin: 0 auto;
    max-width: 1300px;
}
#text {
    position: absolute;
    margin: 0;
    margin-left: 6px;

    font-size: 50px;
}
#field {
    display: flex;
    justify-content: flex-end;
}
#field-content {
    position: absolute;
    margin-right: 10px;

    width: 380px;
    height: 275px;
    background-color: black;
}

With position: absolute and top: % it seems to work but I am searching for a better mehr responsive solution.

I also tried to put the img into the middle-part below while using justify-content: center; but it won’t work either.

HTML login button not clicking , working , and zxcvbn result aren’t showing

password meteor application but html button not working. in js i tried doing calculations using zxcvbn but some variables are empty i guess.But when i tried parsing object button didn’t work.What should i do ?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="ganaa.css">
</head>
<body>
    <section>
        <div class="signin">
            <div class="content">
                <h2>Sign In</h2>
                <div class="form">
                    <div class="inputBox">
                        <input type="text" required> <i>Username</i>
                    </div>
                    <div class="inputBox">
                        <input type="password" id="password" required> <i>Password</i>
                    </div>
                    <div class="links">
                        <a href="#">Forgot Password</a> <a href="#">Signup</a>
                    </div>
                    <div class="inputBox">
                        <input type="submit" value="Login" onclick="checkPassword()">
                    </div>
                    <div id="message"></div>
                    <div id="timeToCrack"></div>
                </div>
            </div>
        </div>
    </section>
</body>
</html>

<script src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js"></script>

<script>
function checkPassword() {
    var password = document.getElementById("password").value;
    var message = document.getElementById("message");
    var timeToCrackDisplay = document.getElementById("timeToCrack");
    alert("ZAil")
    var result = zxcvbn(password);
    var timeToCrack = result.crack_time;
    
    var strength1 = result.score;

    if (password.length === 0) {
        message.innerText = "Password cannot be empty.";
        timeToCrackDisplay.innerText = "";
        return;
    }

    message.innerText = "Password strength: " + getStrengthText(strength1);
    timeToCrackDisplay.innerText = "Estimated time to crack: " + ;
    alert("hi");
    timeToCrackDisplay.innerText = "" + getNumberWords(numberWords)
}

function getStrengthText(score) {
    switch (score) {
        case 0:
            return "Very Weak";
        case 1:
            return "Weak";
        case 2:
            return "Medium";
        case 3:
            return "Strong";
        case 4:
            return "Very Strong";
        default:
            return "No Password";
    }
}

function toWords(number) {
    if(number<120){
        return getNumberWords(number)+" seconds";
        }
        var hour = 60*60;
        if(number<hour){
        minutes = number/60;
        return  getNumberWords(minutes)+" minutes";
        } 
        var day = hour * 24;
        if(number<(2*day)){
        hours = number/hour;
        return  getNumberWords(hours)+" hours";
        } 
        var month = day * 30;
        if(number<month){
        days = number/day;
        return  getNumberWords(days)+" days";
        } 
        var year = day * 365;
        if(number<year){
        months = number/month;
        return  getNumberWords(months)+" months";
        } 
        var century = year * 100;
        if(number<century*10){
        years = number/year;
        return  getNumberWords(years)+" years";
        } 
        if(number<century*100){
        centuries = number/century;
        return  getNumberWords(centuries)+" centuries";
        } 
        years = number/year;
        return  getNumberWords(years)+" years";
       }
        function getNumberWords(number){
        var numberWords = ""; 
        var trillion = Math.pow(10, 12);
        var billion = Math.pow(10, 9);
        var million = Math.pow(10, 6);
        var thousand = Math.pow(10, 4);
        var hundred = Math.pow(10, 3); 
        while(number/trillion >= 1){
        numberWords = " trillion " + numberWords;
        number = number/trillion;
        } 
        while(number/billion >= 1){
        numberWords = " billion " + numberWords;
        number = number/billion;
        } 
        while(number/million >= 1){
        numberWords = " million " + numberWords;
        number = number/million;
        } 
        while(number/thousand >= 1){
        numberWords = " thousand " + numberWords;
        number = number/thousand;
        } 
        while(number/hundred >= 1){
        numberWords = " hundred " + numberWords;
        number = number/hundred;
        } 
        if(twoDP){
        decimalPoint = 100;
        }else{
        decimalPoint = 1;
        }
        number = (Math.round(number*decimalPoint)/decimalPoint) 
        numberWords = number + numberWords; 
        return numberWords;
       } 

</script>

Im trying to do password meteor programm but login button not working zxcvbn parameters are empty i guess

button handler and awaitmessagecomponent

I’m trying to make a button that confirms an action within a command, but I can’t because my button handler prevents it. It understands that there is no function programmed for that button and rejects any action made there. Is there a way to resolve it?

Command

const response = await interaction.reply({
      embeds: ,
      components: [actionRow],
      ephemeral: true,
    });

    const collector = (i) => i.user.id === interaction.user.id;

    try {
      const confirmation = await response.awaitMessageComponent({
        filter: collector,
        time: 60000,
      });

      if (confirmation.customId === "channel_confirm") {
        await confirmation.update({
          content: `Mensagem enviada!`,
          components: [],
          embeds: [],
        });
      }
      if (confirmation.customId === "channel_cancelar") {
        await confirmation.update({
          content: `Ação cancelada.`,
          components: [],
          embeds: [],
        });
      }
    } catch (err) {
      await interaction.editReply({
        content: `Não recebi nenhuma confirmação em 1 minutos, acho que vou cancelar...`,
        components: [],
        embeds: [],
      });
    }

Button handler

if (interaction.isButton()) {
    const { buttons } = client;
    const { customId } = interaction;
    const button = buttons.get(customId);
    if (!button)
      return interaction.reply({
        content: `Esse botão ainda não possui nenhuma função.`,
        ephemeral: true,
      });
    try {
      await button.execute(client, interaction);
    } catch (err) {
      console.error(err);
    }
  }

Switch message based on if it’s before or after the end time

I’m targeting an element on a webpage and if it’s before a certain time I want to display one message with a countdown timer. If it’s after the designated end time I want to display a different message altogether.

This is what I tried, the countdown message shows and when it gets to the end time it just stops working. I need the “Order today, pick up tomorrow!” message to appear after the end time, instead.

`function getCurrentTime() {
    return new Date().getTime();
}

function getEndTime() {
    var endTime = new Date();
    endTime.setHours(18, 12, 0, 0);
    return endTime.getTime();
}

function isBeforeEndTime(currentTime, endTime) {
    return currentTime < endTime;
}

function calculateTimeDifference(currentTime, endTime) {
    return Math.abs(endTime - currentTime);
}

function formatTimeDifference(timeDifference) {
    var hours = Math.floor(timeDifference / (1000 * 60 * 60));
    var minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));

    if (hours > 0) {
        return { hours, minutes };
    } else {
        return { minutes };
    }
}

function showPickupMessage(isBefore1) {
    var pickupWrapper = document.querySelector(".nowrap");
    if (!pickupWrapper) return;

    var pickupMessageID = document.querySelector("#pickup-message");
    if (!pickupMessageID) {
        var pickupMessage = document.createElement("div");
        pickupMessage.id = "pickup-message";

        if (isBefore1) {
            var currentTime = getCurrentTime();
            var endTime = getEndTime();
            var timeDifference = calculateTimeDifference(currentTime, endTime);
            var formattedTime = formatTimeDifference(timeDifference);

            if (formattedTime.minutes > 1) {
                messageTemplate = "Order in the next <span id='countdown'></span> for some text here!";
            } else {
                messageTemplate = "Order other message!";
            }
        } else {
            messageTemplate = "Order other message!";
        }

        pickupMessage.innerHTML = `
            <p class="mb0">
                <span id="Label">${messageTemplate}</span>
                <span class="some-classes" data-toggle="modal" data-target="#question-faqs"></span>
            </p>
        `;

        var radioButtonOne = document.getElementsByClassName("radio-button-one-class")[0];
        var radioButtonTwo = document.getElementsByClassName("radio-button-one-class")[0];

        if (radioButtonOne && radioButtonTwo) {
            radioButtonOne.addEventListener('change', function () {
                var label = pickupMessage.querySelector('#Label');
                if (radioButtonOne.checked) {
                    label.style.fontWeight = 'bold';
                } else if (radioButtonTwo.checked) {
                    label.style.fontWeight = 'normal';
                }
            });

            radioButtonTwo.addEventListener('change', function () {
                var label = pickupMessage.querySelector('#Label');
                if (radioButtonOne.checked) {
                    label.style.fontWeight = 'bold';
                } else if (radioButtonTwo.checked) {
                    label.style.fontWeight = 'normal';
                }
            });
        }

        pickupWrapper.parentNode.replaceChild(pickupMessage, pickupWrapper);
    }
}

function updateCountdown() {
    var currentTime = getCurrentTime();
    var endTime = getEndTime();
    var isBefore1 = isBeforeEndTime(currentTime, endTime);

    var countdownElement = document.getElementById('countdown');
    var messageTemplate;

    if (isBefore1) {
        var timeDifference = calculateTimeDifference(currentTime, endTime);
        var formattedTime = formatTimeDifference(timeDifference);

        if (formattedTime.hours) {
            countdownElement.textContent = `${formattedTime.hours} hours, ${formattedTime.minutes} ${formattedTime.minutes === 1 ? 'minute' : 'minutes'}`;
        } else {
            countdownElement.textContent = `${formattedTime.minutes} ${formattedTime.minutes === 1 ? 'minute' : 'minutes'}`;
        }
    } else {
        messageTemplate = "Order other message!";
        countdownElement.textContent = ''; // Remove countdown text
    }

    showPickupMessage(isBefore1);
}

    const isRestrictedSite = document.getElementsByClassName("restricted-user");
    if (isRestrictedSite.length === 0) {
    const isEligible = document.querySelector('.eligible');

    if (isEligible) {
        const hasGreyLight = Array.from(isEligible.querySelectorAll('p.greyLight')).length > 0;
        if (!hasGreyLight) {
            var isBefore1 = isBeforeEndTime(getCurrentTime(), getEndTime());
            showPickupMessage(isBefore1);
        }
        }
    }

    updateCountdown();
    setInterval(updateCountdown, 60000);

Using Select Library in react but in generating pdf it does not show its items

I use the “Select” library in my React code. (import Select from ‘react-select’). I want to make the pdf from this page and use html2canvas to do that. But it does not show the select item in pdf.

<div className="row mb-1 mt-3">
      <Select
        isDisabled
        isMulti
        value={inspection?.inspectionEquiptmentOptions?.map((option: 
       IInspectionEquiptmentOption) =>
        ({
          value: option.id,
          label: option.name,
        }))}
      /> 
    </div>

and my pdf generating function is like below:

    const downloadPDF = () => {
setCreatingPDF(true);
setImgCount(0);
pdf = new jsPDF("p", "px", "a4");
pdf.html(document.getElementById("formDetails") as HTMLElement, {
  html2canvas: {
    scale: 0.33,
  },
  margin: [25, 0, 25, 0],
  x: 0.5,
  y: 0.5,
  callback: function (pdf) {
    pdf.save(`Inspection Date: ${FormatDateOptions(new Date(inspection?.inspectionDate!), DateFormatOptions.enAU, FormatType.ddmmyyyy)}`);
  },
});
if (components.length + actions.length > 9) {
  pdf.addPage();
}
if (components.length + actions.length > 9 + 49) {
  pdf.addPage();
}
if (components.length + actions.length > 9 + 49 + 49) {
  pdf.addPage();
}
const pages = pdf.getNumberOfPages();
if (imagesData.length > 0) {
  AddImages(imagesData, pages);
}

const pageWidth = pdf.internal.pageSize.width;
const pageHeight = pdf.internal.pageSize.height;

for (let p = 0; p < pages; p++) {
  let horizontalPos = pageWidth / 2;
  let verticalPos = pageHeight - 10;
  pdf.setFontSize(10);
  pdf.setPage(p + 1);
  pdf.text(`Page ${p + 1} of ${pages + imagesData.length}`, horizontalPos, verticalPos, {
    align: "center", //Optional text styling});
  });
  pdf.addImage(LOGO, "JPEG", pageWidth - 50, pageHeight - 20, 30, 11);
}

};

what is the problem with my code?

Can you explain what observable? click on the link for full question https://qr.ae/pKbuTN [closed]

Can you explain what observable? click on the link for full question

https://qr.ae/pKbuTN.

Observables can be created using operators like of, from, or by transforming existing data structures into observables. Subscribers can then subscribe to these observables to receive and react to emitted values. This subscription mechanism allows components and services to stay informed about changes in the application’s state.

https://qr.ae/pKbuTN.

Ray bouncing: How to invert a velocity vector to represent a perfect bounce?

I’m working on a voxel raytracing system in JavaScript, which odd as it may sound is quite doable in a simple form. I’m trying to figure out how to make a virtual ray bounce and can’t quite wrap my mind around the algorithm.

The concept is simple: Each ray is a virtual point with two properties, a position and a velocity, both stored as an x, y, z vector which is a dictionary. Each tick the velocity is added to the position, voxels at the new point are also searched at that point. The relevant part is something among the lines of:

for(let step = 0; step < dist_max; step++) {
    pos.x += vel.x;
    pos.y += vel.y;
    pos.z += vel.z;
    if(solid_at(pos)) {
        // A voxel was hit
    }
}

When a successful hit occurs, I need to do something to vel to reverse the direction of the ray and make it bounce like a rubber ball. Without making it lose or gain speed just change its direction. The surface can be considered to have no angle so no need to take any collider properties into account, it only needs to bounce as if it hits a flat plane facing right toward the ray… it would be useful if an amount between 0 and 1 can control how much the effect is applied so semi-transparent voxels may reflect / refract accordingly.

Clearly the secret isn’t to multiply all of the velocity by -1 as that would only make it go backwards: I think I need to invert just one or two of its axes, or swap the velocity of one axis with that of another. But how do I know which should be flipped when the ray could be going in any direction and have any amount of velocity in either X and Y and Z both positive or negative?

React Vite error Cannot read properties of null (reading ‘map’) [duplicate]

The page is working on running yarn dev, but if I’m going to build and preview it using yarn the page is empty and the error occurred “Cannot read properties of null (reading ‘map’)“.

enter image description here

It is working on codesandbox, I don’t now if i missed something else. But I think because of an empty array initilization?

Here is the code.

import { useState, useEffect } from "react";
import styled from 'styled-components';

const DivArea = styled.div`
    &.brdr-right {
        border-right: 1px solid white;
    }
`;

const AddSection = styled.div`
    padding: 1rem;
    border: 1px solid white;
    margin: 1rem 0;
    position: relative;
`;

const CloseBtn = styled.div`
    position:absolute;
    right:-.5rem;
    top:-.5rem;
    background-color:orange;
    font-size: 1rem;
    padding:.1rem .7rem;
    border-radius: .5rem;
    cursor: pointer;
`;


const MainWireframe = () => {
    const storedItems = JSON.parse(localStorage.getItem('getVal'));

    const [val,setVal] = useState(storedItems);
    const handleAdd = () =>{
        const addValue = `${val.length + 1}`;
        setVal([...val, addValue]);
    }
    const handleDelete = (index) =>{
        const deleteValue = val.filter((_, i) => i !== index);
        setVal(deleteValue);
    }

    useEffect(() => {
        localStorage.setItem('getVal', JSON.stringify(val));
      }, [val]);

  return (
    <>
        <DivArea className="three brdr-right">
                <div className="v--text-center">
                    {val.map((element, index)=>{
                        return(
                        <AddSection key={index} className="v-row-section" draggable="true">
                                <div>Element {element} / Index {index}</div>
                                <CloseBtn onClick={()=>handleDelete(index)}>x</CloseBtn>
                        </AddSection>
                        )
                    })}
                    <button onClick={()=>handleAdd()}>Add Section</button>
                </div>
        </DivArea>
    </>
  )
}

export default MainWireframe