WebClient.UploadValues PHP Script not Retrieving Variables Values Fiddler Shows Variables defined and Values

I have upload my variables via WebClient.UploadValues and that appears to have worked according to Fiddler Request Headers as shown on the WebForms tab. I can see both my variables in the Body section just below the query string section above it. My variables are UploadFilename & UploadFilepath and both variable are showing their correct values. The code below show the WebClient code I use to do this.

 public static string PostValuesToURL(string url, string param1, string param2)
    {
        using (WebClient wc = new WebClient())
        {
            wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            NameValueCollection formData = new NameValueCollection();
            formData["UploadFilename"]= param1;
            formData["UploadFilepath"]= param2;
            byte[] response = wc.UploadValues(url, "POST", formData);
            string responseString = System.Text.Encoding.UTF8.GetString(response);
            wc.Dispose();
            return responseString;
        }
    }

The way I use the above code is a call to PostValuestoURL as follows. I am developing on my localhost. By specifying localhost or 127.0.0.1 did not work for me in the WebClient URL, I had to use my machine name in the URL. I had success with that.

PostValuesToURL("http://your machine name/somesite/index.php", filename, filePath);

Observing again in Fiddler I could see the variables defined and their values in the WebForms tab of Request Header. They had uploaded correctly. Now the php code to retrieve the variables is as below.

if (isset($_POST['UploadFilename'])){
    $UploadFilename=filter_var($_POST["UploadFilename"],FILTER_SANITIZE_STRING); //Sanatize the input
}else{
    
    //$body = file_get_contents('php//input');
    //echo $body;
    $UploadFilename="Variable Not Set...";
}

if (isset($_POST['UploadFilepath'])){
    $UploadFilepath=filter_var($_POST["UploadFilepath"],FILTER_SANITIZE_STRING); //Sanatize the input
}else{
    
    $UploadFilepath="Variable Not Set...";
}

Again observing in Fiddler this time the request body and looking at either the SyntaxView or the Raw tabs, I could see my values as they should be in the index.php script. Now Oddly even though the values are shown in Fiddler, the isset fails in my index.php script and both variables are to “Variable not Set…” the else side of the IF statement for both variables. I can’t explain the activity in Fiddler and yes the index.php says the variables are not set. Ultimately I am trying to retrieve the two variables values via php UploadFilename & Uploadfileapth and inject them into two Javascript variables as shown below.

var UploadFilename = "<?php echo $UploadFilename ?>";
var UploadFilepath = "<?php echo $UploadFilepath ?>";

The values saved to both JavaScript is “Variable not set…”

Can anybody explain this? I am reasonably new to Fiddler. Maybe Fiddler is playing tricks with me. Any help much appreciated.

Parsing a GPX file

I am using Nextjs and I want to modify a locally saved GPX file.
Somehow the modify operation doesn’t work. Without the modifyGpxFile operation I can do console.log and see my object. Does someone know how to work with gpx-parser-builder or has an example? BR K

import React, { useState, useEffect } from "react";

export default function Home() {
  const [gpxData, setGpxData] = useState(null);

  useEffect(() => {
    async function loadAndParseGPX() {
      try {
        // Dynamically import the GPX module
        const GPXModule = await import("gpx-parser-builder");
        const GPX = GPXModule.default ? GPXModule.default : GPXModule;

        // Fetch the GPX file content
        const response = await fetch("./Bester.gpx");
        const gpxFileContent = await response.text();

        // Parse the GPX file content
        // Adjust this line based on the actual API of gpx-parser-builder
        const gpx = GPX.parse(gpxFileContent); // Adjust this line as necessary
        setGpxData(gpx);
        // console.dir(gpx);
        console.dir(gpxData);
        // console.dir(gpx.trk);
      } catch (error) {
        console.error("Failed to fetch or parse GPX file:", error);
      }
    }

    loadAndParseGPX();
  }, []);

  const modifyGpxFile = () => {
    if (!gpxData || !gpxData.tracks) {
      console.error("No GPX data or tracks available to modify.");
      return;
    }

    // Clone the original GPX data to avoid direct state mutation
    const modifiedGpxData = JSON.parse(JSON.stringify(gpxData));

    modifiedGpxData.trk.forEach((track) => {
      track.trkseg.forEach((segment) => {
        segment.trkpt.forEach((point) => {
          if (point.time) {
            // Parse the time, add one second, and set it back in ISO string format
            const originalTime = new Date(point.time);
            const modifiedTime = new Date(originalTime.getTime() + 1000); // Add 1000 milliseconds
            point.time = modifiedTime.toISOString();
          }
        });
      });
    });

    // Update state with modified GPX data
    setGpxData(modifiedGpxData);
  };

  return (
    <div>
      <button onClick={modifyGpxFile}>Modify GPX File</button>
    </div>
  );
}

How do I make sure my Select Content GA4 event doesn’t remove the type and ID values?

I’m trying to set up the select_content event as laid out in the GA4 Recommended Events page.

However, my current organization wants to use the dataLayer syntax to push this event to GTM instead of gtag.js. The way I’ve set it up looks like this:

const dataLayerObjectToPush: {
    event: "select_content",
    content_type: "type_string",
    content_id: "id_string"
};

window.dataLayer = window.dataLayer || [];
window.dataLayer.push(dataLayerObjectToPush);

However, when I send it through to be processed through GTM, the content_type and content_id values get stripped. What’s happening here, and how can I make sure those values don’t get removed?

How to wait for one api call to complete before making another api call without using `await` in vue pinia store

  • I am working on project in group where my senior suggested that we can use vue’s reactivity to handle file upload and make final post request, however it’s confusing to me what they are suggesting, below is my implementation, can some one suggest is there any better way of doing this?

App.vue

const isLoading = ref(0)

function Requester(url, method, data = null, callback = null) {
  // TODO: Remove primitive request counting technique and use reactive pattern
  isLoading.value++
  axios(url, { method: method, data: data })
    .then((response) => {
      if (callback) callback(response)
    })
    .catch((reason) => {
      alert(reason)
    })
    .finally(() => {
      isLoading.value--
    })
}

store.js

export const documentLibraryStore = defineStore('documentLibrary', () => {
  const useDocStore = doctore()
  const useGeneratedDocStore = generatedDocStore()
  const document = useGeneratedDocStore.newDocument
  const files = ref([])

  function isUploadDoneForAllFiles(uploadCount, extraFileCount) {
    return document.files.length - uploadCount == extraFileCount
  }

  function uploadPdfs() {
    let uploadCount = 0
    let extraFileCount = 0
    document.files.forEach((doc) => {
      if (!doc.id) { // id is undefind for non uploaded file
        add(doc.fileData, (value) => {
          uploadCount++
          doc.id = value.id
          // Here I am checking if files are uploaded or not
          if (isUploadDoneForAllFiles(uploadCount, extraFileCount)) {
            publish(document)
          }
        })
      } else {
        extraFileCount++
        if (extraFileCount == document.files.length) publish(document)
      }
    })
  }

  function formatPublishPayload() {
    document.files = document.files.map((file) => {
      return {
        id: file.id,
        fileId: file.fileId
      }
    })
  }
  // This should only called once we have id's for files uploaded
  function publish(documentset) {
    formatPublishPayload()
    if (document) {
      request('URL_TO_UPLOAD_DOCUMENT', 'POST', documentset, (response) => {
        useDocStore.appendDocumentSets(response.data)
        useGeneratedDocStore.clearNewDocumentSet()
      })
    }
  }

  function add(uploadFile, setID) {
    if (uploadFile) {
      const formData = new FormData()
      formData.append('file', uploadFile)
      request('URL_TO_UPLOAD_FILE', 'POST', formData, (value) => {
        files.value.push(value.data[0])
        // this is call back I am using to set id received from backend to set for uploaded files
        setID(value.data[0]) 
      })
    }
  }

  function publishDocumentSet() {
    uploadPdfs()
  }
  return { files, add, publishDocumentSet }
})

JQGrid Grouping Rows at Multiple Levels with No Pagination Performance Degrade

I have a requirement in which I need to group a JQGrid table in 5 different row levels and I am not allowed to use any pagination. So all the data need to show up. the table has 5000 rows in total. When I try to expand the rows the page is unresponsive and performance is really poor.
If I group only one level it seems ok to respond. Is there a way to insert rows as you expand the rows. I use onClickGroup function but it seems it reloads the table and still with grouping page gets stuck. Any help is appreciated.

I tried to load table with one level grouping and when I clcik the button I regrouped to 2 levels. but I lost the cursor and it reloaded the whole table. I was expecting only the selected row should be grouped. As I went down further grouping, it got slower and slower to respond. I expected it to be more responsive.

How to Replace String Concatenation with JavaScript DOM Methods Properly

This is part 2 of my Calendar of Events school assignment.

The teacher has us swapping out some code that has not used best practices.
Task: Improve their code by replacing the string concatenation and output with Document Object Model methods.

Here is a mixture of the code provided by the teacher and my code inserted from the assignment 1.

// declare an object Calendar
function Calendar(elem) {

    // HTML element in which to display the calendar
    this.elem = elem;
    
    // array containing list of names of the days of the week 
    this.dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    
    /** Returns the month name of the year for a given month index.
     * @param monthIndex {number} zero-based index of the month of the year (0 = January, 11 = December)
     * @returns {string} the name of the given month
     */
    this.getMonth = function(monthIndex) {  
  
      // replace this with your solution from Assignment 1!
      switch(monthIndex) {
        case 0:
          return "January";
        case 1:
          return "February";
        case 2:
          return "March";
        case 3:
          return "April";
        case 4:
          return "May";
        case 5:
          return "June";
        case 6:
          return "July";
        case 7:
          return "August";
        case 8:
          return "September";
        case 9:
          return "October";
        case 10:
          return "November";
        case 11:
          return "December";
    }
    if (!isNaN(monthIndex))
      return("Unknown");      
      }
      
    
    /** Returns the number of days in the month for a given zero-based month index and year.
     * @param monthIndex {number} zero-based index of the month of the year (0 = January, 11 = December)
     * @param year {number} a 4-digit year
     * @returns {number} the number of days in the given month and year
     */
    this.getDaysInMonth = function(monthIndex, year) {
      
      // replace this with your solution from Assignment 1!
      if (monthIndex <= -1) {
        return "-1";
    }
      if (typeof year == 'string') {
        return "-1";
    }
      if (monthIndex === 0) {
        return "28";
    }
       if (monthIndex >= 12) {
         return "-1";
    }
      if (year % 400 === 0) {
        return "29";
    }
      if (typeof year == 'string') {
        return "-1";
    }
      if (monthIndex == 1) {
        return "28";
    }
      if (monthIndex == 2) {
        return "31";
    }
      if (monthIndex == 3) {
        return "30";
    }
      if (monthIndex == 4) {
        return "31";
    }
      if (monthIndex == 5) {
        return "30";
    }
      if (monthIndex == 6) {
        return "31";
    }
      if (monthIndex == 7) {
        return "30";
    }
      if (monthIndex == 8) {
        return "30";
    }
      if (monthIndex == 9) {
        return "31";
    }
      if (monthIndex == 10) {
        return "30";
    }
      if (monthIndex == 11) {
        return "31";
    }
      if (monthIndex = typeof str) {
        return "-1";
    }
      if (year == typeof str) {
        return "-1";
    }
      if (monthIndex = 0, year = "twenty twenty-three") {
        return "-1";
    }
        
      }
     
    // method display generates calendar HTML
    // the displayDate parameter indicates the year and month to render (display) 
    this.display = function(displayDate = new Date()) {
      
      // clear the calendar element
      this.elem.innerHTML = "";
      
      // get the number of days in the month
      let daysInMonth = this.getDaysInMonth(displayDate.getMonth(), displayDate.getFullYear());
      
      // get array of days to display
      let days = [];
      for (let i = 1; i <= daysInMonth; i++) {
        days.push(new Date(displayDate.getFullYear(), displayDate.getMonth(),i));
      }
      
      let iHTML = '';
      
      // generate tabular calendar
      iHTML += '<table>';
      iHTML += '<thead>';
      
      // a row containing the previous month button, month name and year, and next month button 
      // the previous and next month buttons call the cal.display() method when clicked
      // with parameters of year displayed, but previous or next month
      // dates will "carry forward", increasing or decreasing the year automatically
      iHTML += '<tr>';
      iHTML += '<td>';
      iHTML += '<button 
                  value="Previous Month" 
                  onclick="cal.display(new Date(' + displayDate.getFullYear() + ',' + (displayDate.getMonth() - 1) + '));">';
      iHTML += '&lt;&lt;';
      iHTML += '</button>';
      iHTML += '</td>';
      iHTML += '<td colspan="5">';
      iHTML += '<h1>';
      iHTML += this.getMonth(displayDate.getMonth()) + " " + displayDate.getFullYear();
      iHTML += '</h1>';
      iHTML += '</td>';
      iHTML += '<td>';
      iHTML += '<button 
                  value="Next Month" 
                  onclick="cal.display(new Date(' + displayDate.getFullYear() + ',' + (displayDate.getMonth() + 1) + '));">';
      iHTML += '&gt;&gt;';
      iHTML += '</button>';
      iHTML += '</td>';
      iHTML += '</tr>';
    
      // row of weekday name headers
      // loop through the array, creating a table header cell for each element in the array 
      iHTML += "<tr>";
      for (const elem of this.dayNames) {
        iHTML += '<th>';
        iHTML += elem;
        iHTML += '</th>';
      }
      iHTML += '</tr>';
      
      // end the table head section, and start the table body section 
      iHTML += '</thead>';
      iHTML += '<tbody>';
      
  
      // calendar table body rows (days of the month)
      // start with blank cells until 1st of month
      iHTML += '<tr>';
      
      // loop from 0 until the first day of the month (Sunday, until the day of the week of the first day of the month)
      // create an empty table cell for each blank day 
      for (let i = 0; i < days[0].getDay(); i++) {
        iHTML += '<td></td>';
      }
      
      // for each day within the month, create a table cell containing the date 
      for (let i = 0; i < days.length; i++) {
        // if this day is a Sunday, end the previous week table row, and start a new row 
        if (days[i].getDay() == 0) {
          iHTML += '</tr>';
          iHTML += '<tr>';
        }
        
        // create a table cell with the CSS class "day", and the text value of the day of the month 
        iHTML += '<td class="day">';
        iHTML += days[i].getDate();
        iHTML += '</td>';
      }
      // last week of month empty cells to fill the week 
      // create an empty table cell for each blank day 
      for (let i = days.at(-1).getDay() + 1; i < 7; i++) {
        iHTML += '<td></td>';
      }
      iHTML += '</tr>';
      
      
      // end the table body section and calendar table 
      iHTML += '</tbody>';
      iHTML += '</table>';
      
      // output the calendar to the HTML element
      this.elem.innerHTML += iHTML;
    }
  }
  
  // declare a instance of Calendar
  const cal = new Calendar(document.getElementById("calendar"));
  
  // call the display() method
  cal.display();

I have spent countless hours using the school’s material, classmates, and online resources without success.

At the moment, my Calendar appears are a black page.

Here is what I have written in JS, and HTML follows.

JavaScript:

// declare an object Calendar
function Calendar(elem) {

  // HTML element in which to display the calendar
  this.elem = elem;
  
  // array containing list of names of the days of the week 
  this.dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
  
  /** Returns the month name of the year for a given month index.
   * @param monthIndex {number} zero-based index of the month of the year (0 = January, 11 = December)
   * @returns {string} the name of the given month
   */
  this.getMonth = function(monthIndex) {  
  // replace this with your solution from Assignment 1!
    switch(monthIndex) {
    case 0:
      return "January";
    case 1:
      return "February";
    case 2:
      return "March";
    case 3:
      return "April";
    case 4:
      return "May";
    case 5:
      return "June";
    case 6:
      return "July";
    case 7:
      return "August";
    case 8:
      return "September";
    case 9:
      return "October";
    case 10:
      return "November";
    case 11:
      return "December";
}
if (!isNaN(monthIndex))
  return("Unknown");      
  }
  
  /** Returns the number of days in the month for a given zero-based month index and year.
   * @param monthIndex {number} zero-based index of the month of the year (0 = January, 11 = December)
   * @param year {number} a 4-digit year
   * @returns {number} the number of days in the given month and year
   */
  this.getDaysInMonth = function(monthIndex, year) {
    
    // replace this with your solution from Assignment 1!
    if (monthIndex <= -1) {
    return "-1";
}
  if (typeof year == 'string') {
    return "-1";
}
  if (monthIndex === 0) {
    return "28";
}
   if (monthIndex >= 12) {
     return "-1";
}
  if (year % 400 === 0) {
    return "29";
}
  if (typeof year == 'string') {
    return "-1";
}
  if (monthIndex == 1) {
    return "28";
}
  if (monthIndex == 2) {
    return "31";
}
  if (monthIndex == 3) {
    return "30";
}
  if (monthIndex == 4) {
    return "31";
}
  if (monthIndex == 5) {
    return "30";
}
  if (monthIndex == 6) {
    return "31";
}
  if (monthIndex == 7) {
    return "30";
}
  if (monthIndex == 8) {
    return "30";
}
  if (monthIndex == 9) {
    return "31";
}
  if (monthIndex == 10) {
    return "30";
}
  if (monthIndex == 11) {
    return "31";
}
  if (monthIndex = typeof str) {
    return "-1";
}
  if (year == typeof str) {
    return "-1";
}
  if (monthIndex = 0, year = "twenty twenty-three") {
    return "-1";
}
    
  }

   
  // the displayDate parameter indicates the year and month to render (display) 
  this.display = function(displayDate = new Date()) {
    
    // clear the calendar element
    this.elem.innerHTML = "";
    
    // get the number of days in the month
    let daysInMonth = this.getDaysInMonth(displayDate.getMonth(), displayDate.getFullYear());
    
    // get array of days to display
    let days = [];
    for (let i = 1; i <= daysInMonth; i++) {
      days.push(new Date(displayDate.getFullYear(), displayDate.getMonth(), i));
    }
    
    // Creating the table
    var table = document.createElement(table);
    document.body.appendChild(table);

    // Creating the table header within the table
    var thead = document.createElement(thead);
    document.body.appendChild(thead);

    // Creating the table header row
    var headerRow = document.createElement(tr);

    // Creating previous month button
    var prevMonthButton = document.createElement(button);
    prevMonthButton.value = "Previous Month";
    prevMonthButton.onclick = function() {
      cal.display(new Date(displayDate.getFullYear(), displayDate.getMonth() - 1));
    };
    prevMonthButton.textContent = '<<';

    var prevMonthCell = document.createElement(td);
    prevMonthCell.appendChild(prevMonthButton);
    headerRow.appendChild(prevMonthCell);

  
    // Creating Month and Year Header
    var monthYearCell = document.createElement(td);
    monthYearCell.colSpan = "5";
    var monthYearHeading = document.createElement(h1)
    monthYearHeading.textContent = this.getMonth(displayDate.getMonth()) + " " + displayDate.getFullYear();
    monthYearCell.appendChild(monthYearHeading);
    headerRow.appendChild(monthYearCell);

    // Creating next month button
    var nextMonthButton = document.createElement(button);
    nextMonthButton.value = "Next Month";
    nextMonthButton.onclick = function() {
      cal.display(new Date(displayDate.getFullYear(), displayDate.getMonth() + 1));
    };
    nextMonthButton.textContent = '>>';

    var nextMonthCell = document.createElement(td);
    nextMonthCell.appendChild(nextMonthButton);
    headerRow.appendChild(nextMonthCell);

    thead.appendChild(headerRow);

    // Create calendar table body element
    var tbody = document.createElement(tbody);
    table.appendChild(tbody);

    // Create row of weekday name headers
    var dayNamesRow = document.createElement(tr);
    this.dayNames.forEach(function(dayName) {
      let th = document.createElement(th);
      th.textContent = dayName;
      dayNamesRow.appendChild(th);
    });
    thead.appendChild(dayNamesRow);

    // Create calendar table body rows (days of the month)
    var currentRow;
    days.forEach(function(day, index) {
      if (index % 7 == 0) {
        currentRow = document.createElement(tr);
        tbody.appendChild(currentRow);
      }
      var dayCell = document.createElement(td);
      dayCell.classList.add(day);
      dayCell.textContent = day.getDate();
      currentRow.appendChild(dayCell);
    });

    // Create last week of month empty cells to fill the week
    if (currentRow) {
      var remainingCells = 7 - currentRow.children.length;
      for (let i = 0; i < remainingCells; i++) {
        let emptyCell = document.createElement(td);
        currentRow.appendChild(emptyCell);
      }
    }
    
    this.elem.appendChild(table);
  }
}

// declare a instance of Calendar
const cal = new Calendar(document.getElementById("Calendar"));

// call the display() method
cal.display();

HTML:

<html>

  <head>
  
    <link rel="stylesheet" href="assets/calendar.css">
  
  </head>
  <body>
    <div id="calendar"></div>
    <table>
    
    </table>
  </body>
  <script src="assets/calendar.js"></script>
</html>

I have used the browser console to ensure no JS errors are present.

Additionally, I’ve been using MDN’s Document resource webpage.

I suspect I have a cal.display issue or issue with appending the table onto the DOM.

Lastly, I’m not necessarily looking for a simple fix. More of a guide. I am serious about stepping up my front end skills.

Thank you in advance.

How to distribute n number of points into a svg polygon javascript

In actual I want to create a 2d styler and I will have place n number of lights in to that. Walls of the home can be polygon and we have to place n lights in that polygon such that each of them are are evenly distributed. Current I did some work work it is not actually working because it is actually consider the enlosing rectangle of the polygon and distributing lights in that.

Here is the example.

function distributePoints(polygon, numberOfPoints) {
    const bounds = getPolygonBounds(polygon);
    const area = polygonArea(polygon);
    const spacing = Math.sqrt(area / numberOfPoints);
    const cols = Math.floor((bounds.maxX - bounds.minX) / spacing);
    const rows = Math.floor((bounds.maxY - bounds.minY) / spacing);
    const distributedPoints = [];
    for (let i = 0; i <= rows; i++) {
        for (let j = 0; j <= cols; j++) {
            const point = {
                x: bounds.minX + j * spacing,
                y: bounds.minY + i * spacing,
            };
            if (isPointInPolygon(point, polygon)) {
                distributedPoints.push(point);
            }
        }
    }
    return distributedPoints;
}
function getPolygonBounds(polygon) {
    let minX = Infinity;
    let maxX = -Infinity;
    let minY = Infinity;
    let maxY = -Infinity;
    polygon.points.forEach((point) => {
        if (point.x < minX)
            minX = point.x;
        if (point.x > maxX)
            maxX = point.x;
        if (point.y < minY)
            minY = point.y;
        if (point.y > maxY)
            maxY = point.y;
    });
    return { minX, maxX, minY, maxY };
}
function polygonArea(polygon) {
    let area = 0;
    const { points } = polygon;
    const n = points.length;
    for (let i = 0; i < n; i++) {
        const j = (i + 1) % n;
        area += points[i].x * points[j].y;
        area -= points[j].x * points[i].y;
    }
    return Math.abs(area / 2.0);
}
function isPointInPolygon(point, polygon) {
    let inside = false;
    const { x, y } = point;
    const { points } = polygon;
    const n = points.length;
    for (let i = 0, j = n - 1; i < n; j = i++) {
        const xi = points[i].x, yi = points[i].y;
        const xj = points[j].x, yj = points[j].y;
        const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
        if (intersect)
            inside = !inside;
    }
    return inside;
}
// Generate a random polygon within the bounds of the SVG
function generateRandomPolygon(numberOfVertices, maxX, maxY) {
    const points = [];
    for (let i = 0; i < numberOfVertices; i++) {
        points.push({
            x: Math.random() * maxX,
            y: Math.random() * maxY,
        });
    }
    return { points };
}
function generateRandomSimplePolygon(numberOfVertices, maxX, maxY) {
    const points = [];
    // Generate random points
    for (let i = 0; i < numberOfVertices; i++) {
        points.push({
            x: Math.random() * maxX,
            y: Math.random() * maxY,
        });
    }
    // Compute the centroid of the points
    const centroid = points.reduce((acc, point) => {
        acc.x += point.x / points.length;
        acc.y += point.y / points.length;
        return acc;
    }, { x: 0, y: 0 });
    // Sort points by angle from centroid to ensure a simple polygon
    points.sort((a, b) => {
        const angleA = Math.atan2(a.y - centroid.y, a.x - centroid.x);
        const angleB = Math.atan2(b.y - centroid.y, b.x - centroid.x);
        return angleA - angleB;
    });
    return { points };
}
const randomPolygon = generateRandomSimplePolygon(30, 700, 700);
const points = distributePoints(randomPolygon, 4);
renderVisualization(randomPolygon, points);
// Render the polygon and points on an SVG element
function renderVisualization(polygon, points) {
    const svgNS = "http://www.w3.org/2000/svg";
    const svgElement = document.createElementNS(svgNS, "svg");
    svgElement.setAttribute("width", "700");
    svgElement.setAttribute("height", "700");
    svgElement.style.border = "1px solid black";
    // Render the polygon
    const polygonElement = document.createElementNS(svgNS, "polygon");
    polygonElement.setAttribute("points", polygon.points.map((p) => `${p.x},${p.y}`).join(" "));
    polygonElement.setAttribute("stroke", "black");
    polygonElement.setAttribute("fill", "transparent");
    svgElement.appendChild(polygonElement);
    // Render the points
    points.forEach((point) => {
        const pointElement = document.createElementNS(svgNS, "circle");
        pointElement.setAttribute("cx", point.x.toString());
        pointElement.setAttribute("cy", point.y.toString());
        pointElement.setAttribute("r", "3");
        pointElement.setAttribute("fill", "red");
        svgElement.appendChild(pointElement);
    });
    document.body.appendChild(svgElement);
}

Not loading model in three Js

Im doing my project with Python(Django) and three.js, I’ve got the following code. It should animate pyramid and when the real model is loaded change the pyramid by it. But when object is loaded I just see a spinable white cube and error message ‘HREE.Object3D.add: object not an instance of THREE.Object3D’. Please help, and advice how to fix it.

{% load static %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js Basic Scene with Controls and Model Loading</title>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three/examples/js/controls/OrbitControls.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three/examples/js/loaders/GLTFLoader.js"></script>
    <script>
        let scene, camera, renderer, controls, objectToRotate;

        init();
        animate();

        function init() {
            // Scene
            scene = new THREE.Scene();

            // Camera
            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            camera.position.z = 5;

            // Renderer
            renderer = new THREE.WebGLRenderer();
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            // OrbitControls
            controls = new THREE.OrbitControls(camera, renderer.domElement);

            // Pyramid
            const pyramidGeometry = new THREE.ConeGeometry(1, 1.5, 4);
            const pyramidMaterial = new THREE.MeshBasicMaterial({ color: 0x808080 });
            const pyramid = new THREE.Mesh(pyramidGeometry, pyramidMaterial);
            scene.add(pyramid);
            objectToRotate = pyramid;

            //Light
            const ambient = new THREE.WebGLRenderer(0xffffff, 1);
            scene.add(ambient)

            let light = new THREE.PointLight(0xc4c4c4,1);
            light.position.set(0, 300, 500);
            scene.add(light)

            let light2 = new THREE.PointLight(0xc4c4c4,1);
            light2.position.set(500, 300, 500);
            scene.add(light2)

            // Resize
            window.addEventListener('resize', onWindowResize);

            // Mouse events
            document.addEventListener('mousedown', onMouseDown);
            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);

            // Load GLTF Model
            const gltfLoader = new THREE.GLTFLoader();
            gltfLoader.load(
                '{% static "img/scene.gltf" %}',
                function (gltf) {
                    scene.remove(objectToRotate);
                    objectToRotate = gltf.scene;
                    scene.add(objectToRotate);
                },
                function (xhr) {
                    console.log('GLTF model ' + (xhr.loaded / xhr.total * 100) + '% loaded');
                },
                function (error) {
                    console.error('Error loading GLTF model:', error);
                }
            );
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        function onMouseDown(event) {
            controls.enabled = false;
        }

        function onMouseMove(event) {
            // Rotate
            if (controls.enabled === false) {
                const deltaX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
                const deltaY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
                objectToRotate.rotation.y -= deltaX * 0.01;
                objectToRotate.rotation.x -= deltaY * 0.01;
            }
        }

        function onMouseUp(event) {
            controls.enabled = true;
        }

        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }
    </script>
</body>
</html>

Invalid key length,?

Well, I’m trying to send an encrypted payload to an array of user notifications, I can encrypt it and send it, but when data.vote === 1, I can’t get this decrypted notification, because it gives an error: Invalid key length

my code:

// eslint-disable-next-line @typescript-eslint/no-var-requires
    const crypto = require('crypto');
    function descriptografarNotificacao(notificacaoCriptografada) {
      const [chaveHex, ivHex, notificacaoCriptografadaHex] = notificacaoCriptografada.split(':');

      // Convertendo chaves e iv de hexadecimal para buffer
      const chave = Buffer.from(chaveHex, 'hex');
      const iv = Buffer.from(ivHex, 'hex');

      // Criando um objeto de decifra AES
      const decipher = crypto.createDecipheriv('aes-256-cbc', chave, iv);
  
      // Descriptografando a notificação
      let payloadString = decipher.update(notificacaoCriptografadaHex, 'hex', 'utf8');
      payloadString += decipher.final('utf8');
      
      // Convertendo a string JSON de volta para objeto
      // Dentro da função descriptografarNotificacao
      console.log("notificacaoCriptografada:", notificacaoCriptografada);
      console.log("chaveHex:", chaveHex);
      console.log("ivHex:", ivHex);
      console.log("notificacaoCriptografadaHex:", notificacaoCriptografadaHex);
      console.log(payloadString)
      try {
        payloadString = decipher.update(notificacaoCriptografadaHex, 'hex', 'utf8');
        payloadString += decipher.final('utf8');
      } catch (error) {
        console.error('Erro ao descriptografar a notificação:', error);
        return null;
      }
      return JSON.parse(payloadString);
    }
    const payload: payload = {
      idUser: idUsuario,
      idPergunta: IdPergunta,

    }
    if(dados.voto > 0){
      
      const payloadString = JSON.stringify(payload);
      
      // Criando uma chave e um iv (initialization vector) - Chaves e IVs devem ser armazenados com segurança
      const chave = crypto.randomBytes(32); // 32 bytes para AES-256
      const iv = crypto.randomBytes(16); // 16 bytes para AES
      
      // Criando um objeto de cifra AES
      const cipher = crypto.createCipheriv('aes-256-cbc', chave, iv);
      
      // Criptografando o payload
      let notificacaoP = cipher.update(payloadString, 'utf8', 'hex');
      notificacaoP += cipher.final('hex');
      
      // Adicionando informações de chave e iv ao início da notificação criptografada
      notificacaoP = ` ${chave.toString('hex')}:${iv.toString('hex')}:${notificacaoP}`;
      
      
      if (dados.voto === 0) {
        // Suponha que você tenha recebido os parâmetros do usuário
        const idUserParametro = `${idUsuario}`;
        const idPerguntaParametro = `${idPergunta}`;

        // Percorrer o array de notificações do usuário2
        for (let i = 0; i < usuario2.notificacoes.length; i++) {
          const notificacaoCriptografada = usuario2.notificacoes[i];

          // Descriptografar a notificação
          const payload = descriptografarNotificacao(notificacaoCriptografada);

          // Verificar se a notificação corresponde aos parâmetros recebidos
          if (payload.idUser === String(idUserParametro) && payload.idPergunta === String(idPerguntaParametro)) {
              // Remover a notificação se corresponder
              usuario2.notificacoes.splice(i, 1);
              console.log("Notificação removida com sucesso.");
              break; // Uma vez que a notificação é removida, saia do loop
          } else {
            console.log('nao tem nada ai')
            return dados.voto = 0
          } 
        }  
      }
      if (dados.voto === 1) {
        console.log('voto === 1, entrou no if')
        // Verificar se já existe uma notificação para a mesma pergunta e usuário
        
        const notificacaoExistente = usuario2.notificacoes.find(notificacao => {
          console.log('notificao descrypt')
            const payload = descriptografarNotificacao(notificacao); // Descriptografar a notificação existente
            return payload.idUser === String(idUsuario) && payload.idPergunta === String(idPergunta);
        });
        console.log('saiu descrypt')
    
        if (notificacaoExistente) {
            console.log(`Usuario: ${idUsuario} ja fez seu voto`);
        } else {
            // Adicionar a notificação criptografada ao array de notificações do usuário
            usuario2.notificacoes.push(notificacaoP);
        }
    }
    }

if you want to see how my notificacao(notification) looks in the array, maybe can help:

"notificacoes": [
            " d68e3fd2888df52536f82e954b6f44f9ba2b6d2e96cc37eb6ef49f8b4b197db5:63df8ded4b6661c99e2bf3cb4a6d4e31:f0acaa8ed21062e8c25f28d01695ed4b229ecfc8e3e953e55683e91428dc395393818b7a6aa447006082e00b5a1a64bfba95a819cdaf8fd574bc9f1bdcad0fd70d5f3fc5b20cbe5e46207bd7f5b2a21d4a93c2ab4422697bbdfd8c6799491cf7e028d4a5075fcc21ca9214c51e9887c2"
        ],

someone to help?

the payload is interface:

export interface payload {
  idUser: string
  idPergunta: string
}

idUsuario = user if, first id parameter

Pergunta = question found, the id comes from postman request parameter

Container size not adjusting and items being hidden behind things

I have 2 containers, one to register an account and one to login to an account. The issue is with the register account container. The top and bottoms parts of the inside of the container are being cutoff. I’ve tried to adjust multiple off the containers themselves and of other css things, but nothing is making it so that all of the items in the container are being shown at once like for the login container.

window.onload = function() {
  document.getElementById('personnelBtn').classList.add('selected');
};

function myMenuFunction() {
  var i = document.getElementById("navMenu");
  if (i.className === "nav-menu") {
    i.className += " responsive";
  } else {
    i.className = "nav-menu";
  }
}

var a = document.getElementById("loginBtn");
var b = document.getElementById("registerBtn");
var x = document.getElementById("login");
var y = document.getElementById("register");

function login() {
  x.style.left = "4px";
  y.style.right = "-520px";
  a.className += " white-btn";
  b.className = "btn";
  x.style.opacity = 1;
  y.style.opacity = 0;
}

function register() {
  x.style.left = "-510px";
  y.style.right = "5px";
  a.className = "btn";
  b.className += " white-btn";
  x.style.opacity = 0;
  y.style.opacity = 1;
}

function selectAccount(type) {
  console.log("Selected account type: " + type);
  document.getElementById('personnelBtn').classList.remove('selected');
  document.getElementById('entrepriseBtn').classList.remove('selected');
  document.getElementById(type + 'Btn').classList.add('selected');

  var firstNameInput = document.getElementById('firstNameInput');
  var lastNameInput = document.getElementById('lastNameInput');
  var companyNameInput = document.getElementById('companyNameInput');

  if (type === 'personnel') {
    firstNameInput.style.display = 'block';
    lastNameInput.style.display = 'block';
    companyNameInput.style.display = 'none';
  } else if (type === 'entreprise') {
    firstNameInput.style.display = 'none';
    lastNameInput.style.display = 'none';
    companyNameInput.style.display = 'block';
  }
}
/* POPPINS FONT */

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Poppins', sans-serif;
}

body {
  overflow: hidden;
}

.wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 110vh;
  background: rgba(39, 39, 39, 0.4);
}

.nav {
  position: fixed;
  top: 0;
  display: flex;
  justify-content: space-around;
  width: 100%;
  height: 100px;
  line-height: 100px;
  background: linear-gradient(rgba(39, 39, 39, 0.6), transparent);
  z-index: 100;
}

.nav-logo p {
  color: white;
  font-size: 25px;
  font-weight: 600;
}

.nav-menu ul {
  display: flex;
}

.nav-menu ul li {
  list-style-type: none;
}

.nav-menu ul li .link {
  text-decoration: none;
  font-weight: 500;
  color: #fff;
  padding-bottom: 15px;
  margin: 0 25px;
}

.link:hover,
.active {
  border-bottom: 2px solid #fff;
}

.nav-button .btn {
  width: 130px;
  height: 40px;
  font-weight: 500;
  background: rgba(255, 255, 255, 0.4);
  border: none;
  border-radius: 30px;
  cursor: pointer;
  transition: .3s ease;
}

.btn:hover {
  background: rgba(255, 255, 255, 0.3);
}

#registerBtn {
  margin-left: 15px;
}

.btn.white-btn {
  background: rgba(255, 255, 255, 0.7);
}

.btn.btn.white-btn:hover {
  background: rgba(255, 255, 255, 0.5);
}

.nav-menu-btn {
  display: none;
}

.form-box {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 512px;
  height: 420px;
  overflow: hidden;
  z-index: 2;
}

.login-container,
.register-container {
  position: absolute;
  width: 500px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  transition: .5s ease-in-out;
  z-index: 3;
}

.login-container {
  left: 4px;
  height: auto;
}

.register-container {
  right: -520px;
  height: auto;
  /* Adjusted height to auto */
  max-height: calc(100vh - 100px);
  /* Added max-height */
  overflow-y: auto;
  /* Added overflow-y */
}

.top span {
  color: #fff;
  font-size: small;
  padding: 10px 0;
  display: flex;
  justify-content: center;
}

.top span a {
  font-weight: 500;
  color: #fff;
  margin-left: 5px;
}

header {
  color: #fff;
  font-size: 30px;
  text-align: center;
  padding: 10px 0 30px 0;
}

.two-forms {
  display: flex;
  gap: 10px;
}

.input-field {
  font-size: 15px;
  background: rgba(255, 255, 255, 0.2);
  color: #fff;
  height: 50px;
  width: 100%;
  padding: 0 10px 0 45px;
  border: none;
  border-radius: 30px;
  outline: none;
  transition: .2s ease;
}

.input-field:hover,
.input-field:focus {
  background: rgba(255, 255, 255, 0.25);
}

::-webkit-input-placeholder {
  color: #fff;
}

.input-box i {
  position: relative;
  top: -35px;
  left: 17px;
  color: #fff;
}

.submit {
  font-size: 15px;
  font-weight: 500;
  color: black;
  height: 45px;
  width: 100%;
  border: none;
  border-radius: 30px;
  outline: none;
  background: rgba(255, 255, 255, 0.7);
  cursor: pointer;
  transition: .3s ease-in-out;
}

.submit:hover {
  background: rgba(255, 255, 255, 0.5);
  box-shadow: 1px 5px 7px 1px rgba(0, 0, 0, 0.2);
}

.two-col {
  display: flex;
  justify-content: space-between;
  color: #fff;
  font-size: small;
  margin-top: 10px;
}

.two-col .one {
  display: flex;
  gap: 5px;
}

.two label a {
  text-decoration: none;
  color: #fff;
}

.two label a:hover {
  text-decoration: underline;
}

@media only screen and (max-width: 786px) {
  .nav-button {
    display: none;
  }
  .nav-menu.responsive {
    top: 100px;
  }
  .nav-menu {
    position: absolute;
    top: -800px;
    display: flex;
    justify-content: center;
    background: rgba(255, 255, 255, 0.2);
    width: 100%;
    height: 90vh;
    backdrop-filter: blur(20px);
    transition: .3s;
  }
  .nav-menu ul {
    flex-direction: column;
    text-align: center;
  }
  .nav-menu-btn {
    display: block;
  }
  .nav-menu-btn i {
    font-size: 25px;
    color: #fff;
    padding: 10px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 50%;
    cursor: pointer;
    transition: .3s;
  }
  .nav-menu-btn i:hover {
    background: rgba(255, 255, 255, 0.15);
  }
}

@media only screen and (max-width: 540px) {
  .wrapper {
    min-height: 100vh;
  }
  .form-box {
    width: 100%;
    height: 500px;
  }
  .register-container,
  .login-container {
    width: 100%;
    padding: 0 20px;
  }
  .register-container .two-forms {
    flex-direction: column;
    gap: 0;
  }
}

.back-video {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -1;
  -o-filter: blur(15px);
  filter: blur(15px);
}

.account-type {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}

.account-btn {
  width: 180px;
  height: 50px;
  margin: 0 20px;
  border: none;
  border-radius: 25px;
  background-color: rgba(255, 255, 255, 0.7);
  color: #000;
  font-weight: bold;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.account-btn.selected {
  background-color: #4CAF50;
  color: white;
}

#companyNameInput {
  width: 100%;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href='https://unpkg.com/[email protected]/css/boxicons.min.css' rel='stylesheet'>
  <link rel="stylesheet" href="inscriptionstyle.css">
  <title>Connexion & Inscription</title>
</head>

<body>
  <div class="wrapper">
    <video id="video1" src="Background VideosBackground_Video_Connection.mp4" autoplay muted loop plays-inline class="back-video"></video>
    <nav class="nav">
      <div class="nav-logo">
        <p>Clipper Link MTL .</p>
      </div>
      <div class="nav-menu" id="navMenu">
        <ul>
          <li><a href="#" class="link">Acceuil</a></li>
          <li><a href="#" class="link">Services</a></li>
          <li><a href="#" class="link">À propos</a></li>
          <li><a href="#" class="link">Contact</a></li>
          <li><a href="#" class="link active">Connexion/Inscription</a></li>
        </ul>
      </div>
      <div class="nav-button">
        <button class="btn white-btn" id="loginBtn" onclick="login()">Connexion</button>
        <button class="btn" id="registerBtn" onclick="register()">Inscription</button>
      </div>
      <div class="nav-menu-btn">
        <i class="bx bx-menu" onclick="myMenuFunction()"></i>
      </div>
    </nav>
    <!----------------------------- Form box ----------------------------------->
    <div class="form-box">

      <!------------------- login form -------------------------->
      <div class="login-container" id="login">
        <div class="top">
          <span>Pas de compte? <a href="#" onclick="register()">Inscription</a></span>
          <header>Connexion</header>
        </div>
        <div class="input-box">
          <input type="text" class="input-field" placeholder="Courriel">
          <i class="bx bx-user"></i>
        </div>
        <div class="input-box">
          <input type="password" class="input-field" placeholder="Mot de passe">
          <i class="bx bx-lock-alt"></i>
        </div>
        <div class="input-box">
          <input type="submit" class="submit" value="Connecter">
        </div>
        <div class="two-col">
          <div class="one">
            <input type="checkbox" id="login-check">
            <label for="login-check"> Rapelle toi de moi</label>
          </div>
          <div class="two">
            <label><a href="#">Mot de passe oublié?</a></lzabel>
                </div>
            </div>
        </div>
        <!------------------- registration form -------------------------->
        <div class="register-container" id="register">
            <div class="top">
                <span>T'a déjà un compte? <a href="#" onclick="login()">Connecte toi</a></span>
                <header>Inscription</header>
                <div class="account-type">
                    <button class="account-btn" id="personnelBtn" onclick="selectAccount('personnel')">Personnel</button>
                    <button class="account-btn" id="entrepriseBtn" onclick="selectAccount('entreprise')">Entreprise</button>
                </div>
            </div>
            
            <div class="two-forms">
                <div class="input-box" id="firstNameInput">
                    <input type="text" class="input-field" placeholder="Prénom">
                    <i class="bx bx-user"></i>
                </div>
                <div class="input-box" id="lastNameInput">
                    <input type="text" class="input-field" placeholder="Nom de famille">
                    <i class="bx bx-user"></i>
                </div>
                <div class="input-box" id="companyNameInput" style="display: none;">
                    <input type="text" class="input-field" placeholder="Nom de l'entreprise">
                    <i class="bx bx-building"></i>
                </div>
            </div>
            <div class="input-box">
                <input type="text" class="input-field" placeholder="Courriel">
                <i class="bx bx-envelope"></i>
            </div>
            <div class="input-box">
                <input type="password" class="input-field" placeholder="Mot de passe">
                <i class="bx bx-lock-alt"></i>
            </div>
            <div class="input-box">
                <input type="submit" class="submit" value="Inscrire">
            </div>
            <div class="two-col">
                <div class="one">
                    <input type="checkbox" id="register-check">
                    <label for="register-check"> Rapelle toi de moi</label>
          </div>
          <div class="two">
            <label><a href="#">Terms & conditions</a></label>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script src="inscription.js"></script>
</body>

</html>

As stated, ive tried adjusting the parameters of multiple css things.

built a wordpress website, but google console giving me javascript log

i’ve built my own WordPress website and think I’ve done a “good” job, but certainly not that technical to fix issues,

although i did fix 6/7 errors i had, and chuffed with that.

but i have something coming up on google search console,

Array(0) []
https://example.co.uk/about-us/:46

this appears on every page i have,

my question –

is this actually a issue? or am i trying to find a fix for something that isn’t a issue?

i can’t find anything on page inspection, so it just seems to come up on google search console, any suggestions will be welcomed.

n/a, not advanced enough XD

How to use D3 Update and remove function on Sunburst Chart

i have built a sunburst chart with D3.js and the instructions of https://gist.github.com/denjn5/e1cdbbe586ac31747b4a304f8f86efa5. Everything works so far.

Now I would like to use the update and remove function.For now, I have written an initialization function “initialize_sun”, an update function “update_sun” and delete all slices before the update. Is it possible to use the update and remove function of D3.js?

In other D3.js charts I have built, I have always been able to use the merge() function to update my elements without having to delete everything.

Afterwards I would like to use the transition() function.

Can anyone please help me with this?

King Regards

Jegor

 const data1= {
                        "name": "TOPICS", "children": [{
                            "name": "Topic A",
                            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
                        }, {
                            "name": "Topic B",
                            "children": [{"name": "Sub B1", "size": 3}, {"name": "Sub B2", "size": 3}, {
                                "name": "Sub B3", "size": 3}]
                        }, {
                            "name": "Topic C",
                            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
                        }]
                    };

        const data2= {
                        "name": "TOPICS", "children": [{
                            "name": "Topic A",
                            "children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
                        }, {
                            "name": "Topic B",
                            "children": [{"name": "Sub B1", "size": 3}, {"name": "Sub B2", "size": 3}, {
                                "name": "Sub B3", "size": 3}]
                        }]
                    };
                    
                /*declare variables*/
        var i_region_static_id = "sunburst",
            parentDiv = document.getElementById(i_region_static_id),
            boost = 'N',
            svg, 
            result,
            jsObj,
            root, 
            rootDepth,
            x, 
            y, 
            arc,
            middleArcLine,
            middleAngle,
            slice,
            lastActivatedNode,
            width = parentDiv.clientWidth, 
            height = 450, 
            maxRadius,
            color;
            maxRadius = (Math.min(width, height) / 2) - 5; 
            
        //-----------------------------------------------------------------------------------
        //SVG-Element
        svg = d3.select('#' + i_region_static_id).append('svg') 
            .style('width', width) //'100vw')
            .style('height', height) //'100vh')
            .attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`)
            .on('dblclick',  d => {
                    if(event.detail === 2) focusOn() //double click
                    }
                ); // Reset      zoom on canvas click 
        //-----------------------------------------------------------------------------------
        // X-Scale
        x = d3.scaleLinear()
            .range([0, 2 * Math.PI])
            .clamp(true);

        //-----------------------------------------------------------------------------------
        // Y-Scale
        y = d3.scaleSqrt()
            .range([maxRadius*.1, maxRadius]);

        const partition = d3.partition();

        /*text-fit constant*/
        const textFits = d => {
                const CHAR_SPACE = 6;

                const deltaAngle = x(d.x1) - x(d.x0);
                const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2);
                const perimeter = r * deltaAngle;

                return d.data.name.length * CHAR_SPACE < perimeter;
            };

        //-------------------------------------------------------------------------------------------
        /* initialize sun */
        function initialize_sun(pData){
            /*set default color scheme*/
            switch('COLOR20'){
                case 'COLOR20': color = d3.scaleOrdinal(d3.schemeCategory20); break; 
                case 'COLOR20B': color = d3.scaleOrdinal(d3.schemeCategory20b); break;
                case 'COLOR20C': color = d3.scaleOrdinal(d3.schemeCategory20c); break;
                case 'COLOR10': color = d3.scaleOrdinal(d3.schemeCategory10);
            }

            arc = d3.arc()
                .startAngle(d => x(d.x0))
                .endAngle(d => x(d.x1))
                .innerRadius(d => Math.max(0, y(d.y0)))
                .outerRadius(d => Math.max(0, y(d.y1)));

            middleArcLine = d => {
                const halfPi = Math.PI/2;
                const angles = [x(d.x0) - halfPi, x(d.x1) - halfPi];
                const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2);

            middleAngle = (angles[1] + angles[0]) / 2;
                const invertDirection = middleAngle > 0 && middleAngle < Math.PI; // On lower quadrants write text ccw
                if (invertDirection) { angles.reverse(); }

                const path = d3.path();
                path.arc(0, 0, r, angles[0], angles[1], invertDirection);
                return path.toString();
            };

            root = d3.hierarchy(pData); //set data

            root.sum(d =>
                    (d.children == undefined) ? ((d.size == undefined) ? 1 : d.size) : 0 //parent value defined by childrens values
                );

            slice = svg.selectAll('g.slice')
                                        .data(
                                            partition(root)
                                            .descendants()
                                            );

            slice.exit().remove();

            const newSlice = slice.enter()
                                    
                                    .append('g').attr('class', 'slice')
                                    .attr('display', d => d.depth < 2 ? null : 'none') //hide levels lower depth
                                    .on('dblclick', d => {
                                        if (event.detail === 2){ //double click
                                            d3.event.stopPropagation();
                                            focusOn(d);
                                        }
                                    })
                                    .on('click', d => {
                                        if (event.detail === 1) { //single click
                                            if('Y' == 'Y') activateNode(d); //visual selection if highlight setting activated by developer 
                                        }
                                    })
            
            newSlice.append('path')
                .attr('class', 'main-arc')
                .style('fill', d => (d.data.color == undefined) ? color((d.children ? d : d.parent).data.name) : d.data.color) //set source color, otherwise default color
                .attr('d', arc);

            newSlice.append('path')
                .attr('class', 'hidden-arc')
                .attr('id', (_, i) => `hiddenArc${i}`)
                .attr('d', middleArcLine);

            const text = newSlice.append('text')
                .attr('display', d => textFits(d) ? null : 'none'); //hide text on lower levels

            text.append('textPath')
                .attr('startOffset','50%')
                .attr('xlink:href', (_, i) => `#hiddenArc${i}` )
                .text(d => d.data.name) //set text in sector 
                .attr('fill', d => calculateContrast(d));
        }
            
        //-------------------------------------------------------------------------------------------
        /*update sun (similar to initialize sun with some adjustments)*/
        function update_sun(pData){         
            console.log(pData)
            svg = d3.select('#' + i_region_static_id).selectAll('svg');
            var svg_helper = d3.select('#' + i_region_static_id).selectAll('svg')._groups[0]; 
            
            /*remove children*/
            while (svg_helper[0].firstChild) {
                svg_helper[0].removeChild(svg_helper[0].lastChild);
            }
            
            /*get region size before update -> so region size will not change when updated*/
            width = parseInt(svg_helper[0].style.width);
            height = parseInt(svg_helper[0].style.height);
            maxRadius = (Math.min(width, height) / 2) - 5;  

            arc = d3.arc()
                .startAngle(d => x(d.x0))
                .endAngle(d => x(d.x1))
                .innerRadius(d => Math.max(0, y(d.y0)))
                .outerRadius(d => Math.max(0, y(d.y1)));

            middleArcLine = d => {
                const halfPi = Math.PI/2;
                const angles = [x(d.x0) - halfPi, x(d.x1) - halfPi];
                const r = Math.max(0, (y(d.y0) + y(d.y1)) / 2);

                const middleAngle = (angles[1] + angles[0]) / 2;
                const invertDirection = middleAngle > 0 && middleAngle < Math.PI; // On lower quadrants write text ccw
                if (invertDirection) { angles.reverse(); }

                const path = d3.path();
                path.arc(0, 0, r, angles[0], angles[1], invertDirection);
                return path.toString();
            };
            
            svg.style('width', width) //'100vw')
                .style('height', height) //'100vh')
                .attr('viewBox', `${-width / 2} ${-height / 2} ${width} ${height}`)
                .on('dblclick',  d => {
                        if(event.detail === 2) focusOn() //double click
                        }
                    ); // Reset zoom on canvas click  

                //root = JSON.parse(pData); //set updated data
            root = d3.hierarchy(pData);
            root.sum(d =>
                    (d.children == undefined) ? ((d.size == undefined) ? 1 : d.size) : 0
                );

            slice = svg.selectAll('g.slice')
                                        .data(
                                            partition(root)
                                            .descendants()
                                            );

            slice.exit().remove();

            const newSlice = slice.enter()
                                    .append('g').attr('class', 'slice')
                                    .attr('display', d => d.depth < 2 ? null : 'none') ////hide levels lower depth
                                    .on('dblclick', d => {
                                        if (event.detail === 2){ //double click
                                            d3.event.stopPropagation();
                                            focusOn(d);
                                        }
                                    })
                                    .on('click', d => {
                                        if (event.detail === 1) { //single click
                                        if('Y' == 'Y') activateNode(d); //visual selection if highlight setting activated by developer 
                                        }
                                    })

            newSlice.append('path')
                .attr('class', 'main-arc')
                .style('fill', d => (d.data.color == undefined) ? color((d.children ? d : d.parent).data.name) : d.data.color) //set source color, otherwise default color
                .attr('d', arc);

            newSlice.append('path')
                .attr('class', 'hidden-arc')
                .attr('id', (_, i) => `hiddenArc${i}`)
                .attr('d', middleArcLine);

            const text = newSlice.append('text')
                .attr('display', d => textFits(d) ? null : 'none');

            text.append('textPath')
                .attr('startOffset','50%')
                .attr('xlink:href', (_, i) => `#hiddenArc${i}` )
                .text(d => d.data.name)
                .attr('fill', d => calculateContrast(d));
        }

        //-------------------------------------------------------------------------------------------
        /* visually select a node */
        function activateNode(elD){ 
            //if other node has been activated -> deactivated node 
            if(lastActivatedNode != undefined){
                lastActivatedNode
                .selectAll('.main-arc')
                .style('stroke', null)
                .style('stroke-width', null)
            
                lastActivatedNode
                .selectAll('text')
                .style('font-weight', 'normal');
            } 
            
            //find clicked node
            var nodeSlice = svg.selectAll(".slice")
                        .filter(d => d === elD);
            
            //set lastActivatedNode for upcoming deactivation
            lastActivatedNode = nodeSlice;
            
            //foreground node  
            nodeSlice.each(function(d) {
                    this.parentNode.appendChild(this)
                });

            //add highlighting 
            nodeSlice.selectAll('.main-arc')
            .style('stroke', '#000')
            .style('stroke-width', '2px')

            //highlight text
            nodeSlice.selectAll('text')
            .style('font-weight', 'bold'); 
        }

        //-------------------------------------------------------------------------------------------
        /*Returns Black/White depending on node color*/
        function calculateContrast(d){
            var nodeColor = (d.data.color == undefined) ? color((d.children ? d : d.parent).data.name) : d.data.color; 
            var rgb = /^#?([a-fd]{2})([a-fd]{2})([a-fd]{2})$/i.exec(nodeColor); 
            const o = (rgb != undefined) ? Math.round(((parseInt(rgb[1], 16) * 299) + (parseInt(rgb[2], 16) * 587) + (parseInt(rgb[3], 16) * 114)) /1000) : 0;
            return o < 150 ? 'white' : 'black'  
        }
        
        //-------------------------------------------------------------------------------------------
        /*check if node in depth*/
        function maxDepth(d){
            if(rootDepth == undefined){ //if user clicks next to sun = root undefined
                rootDepth = 0; 
            }
            return ((d.depth - rootDepth) < 2 ); 
        }

        //-------------------------------------------------------------------------------------------
        function focusOn(d = { x0: 0, x1: 1, y0: 0, y1: 1 }) {
            // Reset to top-level if no data point specified
            
            // Activate top-level node if no data point specified 
            if(d.data == undefined){
                svg.selectAll(".slice")
                    .filter(d => d.parent == undefined && d.children != undefined)
                    .each(function(d){
                                    activateNode(d);            
                                }
                    ); 
            }
            
            root = d; // root-node
            rootDepth = root.depth; /*root node depth for maxDepth(d)*/

            const transition = svg.transition()
                .duration(750)
                .tween('scale', () => {
                    const xd = d3.interpolate(x.domain(), [d.x0, d.x1]),
                        yd = d3.interpolate(y.domain(), [d.y0, 1]);
                    return t => { x.domain(xd(t)); y.domain(yd(t)); };
                });

            transition.selectAll('.slice')
                .attr('display', d => maxDepth(d) ? null : 'none'); //display nodes only in depth for transition
            
            transition.selectAll('path.main-arc')
                .filter(d => maxDepth(d))    
                .attrTween('d', d => () => arc(d));     

            transition.selectAll('path.hidden-arc')
                .filter(d => maxDepth(d))
                .attrTween('d', d => () => middleArcLine(d));    

            transition.selectAll('text')
                .filter(d => maxDepth(d))
                .attrTween('display', d => () => textFits(d)? null : 'none'); //display text only in depth

            moveStackToFront(d);

            /*foreground nodes -> inner nodes higher than outer nodes*/
            function moveStackToFront(elD) {
                svg.selectAll('.slice').filter(d => d === elD)
                    .each(function(d) {
                        this.parentNode.appendChild(this);
                        if (d.parent) { moveStackToFront(d.parent); }
                    })
            }
        }


        //-------------------------------------------------------------------------------------------
           
        
            initialize_sun(data2)
            
            let i = 0;
            d3.interval(() => {
                if (i++ % 2 === 0) {
                    update_sun(data1);
                } else {
                    update_sun(data2);
                }

            }, 4000)
.slice {
    cursor: pointer;
}

.slice .main-arc {
    stroke: #fff;
    stroke-width: 1px;
}

.slice .hidden-arc {
    fill: none;
}

.slice text {
    pointer-events: none;
    text-anchor: middle;
}
    <div id="sunburst"></div>
    <script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
    <script src="https://unpkg.com/d3fc" charset="utf-8"></script>

Using javascript to copy “td” element to clipboard without button, but display what has been copied to user with timeout

Okay, firstly I need to own up to having no JavaScript coding experience. So I am going cap in hand for some help on this please.

I would like the user of a webpage to be able to click on a value contained within a table (‘td’) and for it to be copied to the clipboard. So that the user knows that this has happened, I’d like a message to appear briefly letting them know that they have copied something and what that was.

Hopefully this makes sense?

I have found the following code (apologies for not remembering where) which copies the value to the clipboard okay, but this is where I am stuck and cannot get the tooltip part going.

function copy(event) {
  console.log("Triggered")
  var target = event.target || event.srcElement;
  console.log("Targeted", target)
  var copyText = target.innerText || target.textContent;
  navigator.clipboard.writeText(copyText)

  // select the cell
  var range = document.createRange();
  range.selectNode(target);
  window.getSelection().removeAllRanges();
  window.getSelection().addRange(range);
}

document.querySelectorAll("td")
  .forEach(elem => elem.addEventListener("click", copy))

Hoping that somebody can enlighten me!

Performance implications of multiple websocket connections from one session

I am creating an app that has three (3) graphs shown to the user displaying radio data streamed from a server. The rendering of these graphs is relatively expensive; one currently uses a web worker to prevent jitter, and I am considering moving the other two to their own workers as well to free up performance on the main thread.

While the workers are effective in helping page performance, one of the issues is receiving the stream data in the worker. The data describing each graph is a relatively large piece of memory and cannot be sent without using transferable objects. My current solution for the one graph is to pack the data into a binary format, transfer it to the worker, and then parse it back. This creates a passable solution, but is somewhat hacky, and I am concerned is not viable given more than one graph. Another issue with this solution is desync between the rendering time of the canvas and its axes, which are rendered on the worker and the DOM respectively, creating a delay.

One solution I am considering is to connect to the websocket one time in each web worker, creating three connections from the one browser session. This would eliminate the need to transfer any data to the workers and theoretically should improve performance of the main thread, as well as avert desync issues. However, I am not sure if the performance overhead of three workers and multiple websocket connections will outweigh the benefits.

I first checked this question but it only addresses singular connections from workers. I am not sure if this solution will scale well to more than one worker. Is my solution viable, or is there a better way to share the stream data between multiple workers?

How does Google Docs handle file uploads without an

I working on an browser extension that looks for all input-nodes and listens to change handlers. My solution works on every possible page I have tried it on, except for docs.google.com when using this button:

enter image description here


  • My initial guess was that they use document.createElement(“input”) but after scanning their source code I could not see any use case of this.

  • When adding breakpoints in the source code I can see that there is a hidden that is not placed in the DOM. I have no idea where this input is created.

enter image description here