How can I add drag & drop functionality to my file input HTML tag which I have customized as an image?

I am currently designing a form using HTML, CSS, and JavaScript which includes an input type=file. I customized the form, so that the input now uses an image which can be clicked to browse and select files from the user’s machine. However, I’d also like it to have drag & drop capabilities.

Below is the code I currently have. This code is enough to do a couple of things:

  1. It replaces the default ‘Choose File’ button that is rendered when using the input tag with type=file with the image called in the img tag.
  2. It uses some JavaScript for the span tag to indicate to the user which file they have selected or if no file has been selected.

The reason those are possible is because of the CSS used to change the default behavior in the input tag where type=file. However, I haven’t found code to implement drag & drop to my current solution. Can somebody please help?

<style>
    .required-file::after {
    content: "*";
    color: red;
    }
    .custom-upload {
    display: inline-block;
    padding: 6px 12px;
    cursor: pointer;
    }
    input[type="file"] {
    display: none;
    }
    </style>
    <script>
    $(function() {
    const fileUploadElement = document.getElementById('fileUpload');
    const chosenFileElement = document.getElementById('chosen-file');
    fileUploadElement.addEventListener('change', function(){
    chosenFileElement.textContent = this.files[0].name;
    });
    });
    </script>
    <label for="fileUpload" class="custom-upload">
    <img src="/fakepath/image.png" width="100" height="100">
    </label>
    <input type="file" id="fileUpload" name="fileUpload" >
    <span class="required-file" id="chosen-file">No file chosen</span>

How to pass a form into Angular Material dialog

I need to create a reusable form dialog to visualize different forms. I am using Angular 17 and Angular Material. In my component I am trying to define a form like that:

    <form #myForm="ngForm" (ngSubmit)="submitForm(myForm)">
  <mat-form-field>
    <input matInput [matDatepicker]="picker" placeholder="Choose a date" name="date" ngModel required>
    <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
    <mat-datepicker #picker></mat-datepicker>
    <mat-error *ngIf="myForm.controls.date.invalid && myForm.controls.date.touched">Please choose a date.</mat-error>
  </mat-form-field>

  <mat-form-field>
    <input matInput placeholder="First Name" name="firstName" ngModel required>
    <mat-error *ngIf="myForm.controls.firstName.invalid && myForm.controls.firstName.touched">Please enter a first name.</mat-error>
  </mat-form-field>

  <button mat-raised-button color="primary" type="submit" [disabled]="myForm.invalid">Submit</button>
</form>

In my .ts file I have a method to open a dialog:

 @ViewChild('myForm', { static: true }) public myForm: ElementRef;

public openDialog(): void {
        const dialogRef = this.dialog.open(FilterFormDialogComponent, {
            width: '460px',
            disableClose: true,
            autoFocus: false,
            panelClass: 'form-dialog',
            data: {
              form: this.myForm // reference to the form previously defined
            },
        });
    }

In my filterFormDialogComponent I am trying to visualize the inserted form in its html by using ng-content. However, I am unable to visualize the form.

Is it possible to pass a form or another component into a dialog by using MAT_DIALOG_DATA? If so, how to display it properly into the html of the dialog?

Why I’m hitting time limit!? LeetCode Linked List Cycle (Solved but explanation needed!)

I’m working on solving this problem on leetcode (https://leetcode.com/problems/linked-list-cycle/description/) and my original solution exceeded the time limit (Example A). I was eventually able to make the solution fast enough by changing two lines of code and the solution was accepted and some how more performant. Why is example B faster than example A? Why is the variable assignment faster/more performant than using the original object?

I changed this…

Example A (Failing Solution)

var hasCycle = function(head) {
// some code ...
   let fastPointer = null;

   fastPointer = head?.next?.next || null;
// ...
}

to this …

Example B (Working Solution)

var hasCycle = function(head) {
// some code ...
   let fastPointer = head;

   fastPointer = fastPointer?.next?.next || null;
// ...
}

Here is the full code for both solutions…

Example A (Failing Solution)….

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
   // create a fast pointer
   let fastPointer = null;

   // create a while loop that lasts for as long as head exists

   while (head) {
    // move fast pointer over by 2
    fastPointer = head?.next?.next || null;

    // if fastpointer is null, this indicates that there is no cycle so return false
    if (fastPointer === null) return false;

    // compare fastPointer to the slow pointer, if they are ever equal to the same node then the list contains a cycle.
    if (fastPointer === head) return true;

    // move head by 1
    head = head.next;


   }




   // if the while loop ends, it indicates the there is no cycle so return false

   return false;
};   

Example B (Working Solution)…

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
   // create a fast pointer
   let fastPointer = head;

   // create a while loop that lasts for as long as head exists

   while (head) {
    // move fast pointer over by 2 
    // !!!CHANGE HAPPENED HERE and solution worked!!!!
    fastPointer = fastPointer?.next?.next || null;

    // if fastpointer is null, this indicates that there is no cycle so return false
    if (fastPointer === null) return false;

    // compare fastPointer to the slow pointer, if they are ever equal to the same node then the list contains a cycle.
    if (fastPointer === head) return true;

    // move head by 1
    head = head.next;


   }


   // if the while loop ends, it indicates the there is no cycle so return false

   return false;
};   

Small telegram web extension client

I would like to create a browser extension which will make a custom buttons on Gitlab pages. On click these buttons will send a message to telegram chat with content from page (parse html tags, page url and other). I want to make my work processes simply with this extension

I have an experience of make sites, and I can make an extension, but I dont know, how I can send messages to telegram in JS code authored me (not bot)

I cant found info about telegram REST API, only libs as Tdlib and other. I would like make and use something like web client, with authorization, select chat and message pattern in my extension popup, after it make a button on page – onclick send pattern message with parsed page data to selected chat

However I would like to do this without backend, only fronted extension code

If you have similar experience or you can write a plan of actions to realise my idea – please, write it here 🙂

Now I make a small extension which placed in Merge Request Page a button which put a pattern message with parsed page data to buffer

But I cant use it, because telegram dont parse markdown links on messages sended users so i cant paste message from buffer and press Enter – formatting dont work 🙁

I would like to make my extension so better, make function of right sending to telegram messages with customising patterns

Make inward collision detection with phaser

enter image description here

What I need to achieve is the collision detection for the smaller hitbox inside player (protagonist) against the wall so that it gives a image of player being able to walk next to the wall. This should be pretty straightforward but the collision detection doenst work. Relevant parts are walls layer and hitbox sprote. Here is my code:

preload(){
  //all the assets here
}
create() {
  console.log('create method executed');


  const characterPositionInWorldMap = 3700;
  this.hitbox = this.physics.add.sprite(characterPositionInWorldMap, 250, null); // we need collision for this
  this.protagonist = this.physics.add.sprite(characterPositionInWorldMap, 250, 'protagonist');
  
   // Initialize the hitbox sprite for collision detection
  
  this.hitbox.setSize(10, 10); // Set hitbox size (adjust as needed)

  
  this.protagonist.setDepth(3);
  this.hitbox.setDepth(3);
  const map = this.make.tilemap({ key: 'map' });
  this.animatedTiles.init(map);
  this.physics.world.createDebugGraphic();

// Add the tilesets...



// Create layers from tilemap data using different tilesets
const groundLayer = map.createLayer('Groundlayer', darkTileset, 0, 0);
const waterLayer = map.createLayer('waterlayer', darkTileset, 0, 0);
const grassLayer = map.createLayer('grass_and_tree_layer', darkTileset, 0, 0);
const stoneLayer = map.createLayer('stones_n_stuff', darkTileset, 0, 0);

// Create hut layer using the hut tileset
const hutLayer = map.createLayer('hutLayer', hutTileset, 0, 0);
const transportlayer = map.createLayer('transportlayer', hutTileset, 0, 0);
const walls = map.createLayer('walls', hutTileset, 0, 0);


  // Adjust the depth of layers as needed
  groundLayer.setDepth(1);
  waterLayer.setDepth(0);
  grassLayer.setDepth(1);
  stoneLayer.setDepth(2);
  hutLayer.setDepth(3);
  walls.setDepth(4);
  transportlayer.setDepth(10);

  // Enable collision detection between player and walls layer
  const collidableTileIndexes = [
    1279,1278,1244,1225,1257,1267,1302,1302,1320,1305,1277,1298,1307,1288,1319,1320,1321,1225,1223,1244
];

  collidableTileIndexes.forEach(index => {
    map.setCollision(index, true, walls);
});


  //animations....
 
  // Enable physics for the protagonist
  this.physics.world.setBounds(0, 0, map.widthInPixels, map.heightInPixels);

  // Listen for collision between hitbox and walls
this.physics.add.collider(this.hitbox, walls, () => {
// Disable movement controls for the protagonist
//this.protagonist.setVelocity(0); // Stop the protagonist's movement
console.log("hitbox hit")
});

// Listen for when hitbox stops colliding with walls
this.physics.add.collider(this.hitbox, walls, () => {
// Re-enable movement controls for the protagonist
// You may need to adjust this depending on how your movement controls are implemented
// For example, if you're using velocity-based movement, reset the velocity to allow movement
this.protagonist.setVelocity(0); // Reset velocity
});

this.groundLayer = groundLayer;
this.waterLayer = waterLayer;
this.grassLayer = grassLayer;
this.stoneLayer = stoneLayer;
this.hutLayer = hutLayer;
this.walls = walls;
this.transportlayer = transportlayer;


 // Set up camera to follow the player
 this.cameras.main.startFollow(this.protagonist);

}

update() {
  // Reset velocity
  this.protagonist.setVelocity(0);
  
  this.physics.collide(this.hitbox, this.walls, this.handleWallCollision, null, this);
    // Update the hitbox sprite position to match the player sprite
    this.hitbox.setPosition(this.protagonist.x, this.protagonist.y);
    ...
}

to call parameterized onclick function in html why use string format?

to call parameterized onclick function in html why use string formate?

<td><button onclick="deleteArticle(this,'<%= article.articleId %>')">Delete</button></td>
<script>
        async function deleteArticle(e,id){           
            const response = await fetch(`/article/delete/${id}`);
            const data = JSON.parse(await response.json());            
            if(data.message == 'ok'){
                alert('Record deleted successfully');
                const parentNode = e.parentNode.parentNode;
                parentNode.remove();
            }
            else if(message.response=='error'){
                alert('Something went wrong');
            }
        }
    </script>

Filtering DataFrames in a Django Dashboard

I am trying to build a Dashboard with Django… I wish to filter the dashboard with category, month and Year. The dataFrame is coming from python code than I am adding the charts with JS.

I don’t know how to proceed to be able to filter it as I want.

views.py:

def get_expense_api_data(request, *args, **kwargs):

    sort_order = ['January','February','March','April','May','June','July','August','September','October','November','December']

    exp_df = pd.DataFrame(Expenses.objects.filter(user=request.user).all().values('date_created', 'amount'))
    categories = dict()

    if exp_df.empty:
        default_items_exp = [0]
        labels_exp = [0]
    
    else:
        categories['expenses'] = pd.unique(pd.DataFrame(Expenses.objects.filter(user=request.user).all().values('categories')).categories.values).tolist()
    
        exp_df['date_created'] = pd.to_datetime(exp_df['date_created'])
        exp_df = pd.DataFrame(exp_df.groupby(exp_df['date_created'].dt.strftime('%B'))['amount'].sum())
        exp_df["date_created"] = exp_df.index
        exp_df.index = pd.CategoricalIndex(exp_df["date_created"], categories=sort_order, ordered=True)
        exp_df = exp_df.sort_index().reset_index(drop=True)

        default_items_exp = exp_df.amount.tolist()
        labels_exp = exp_df.date_created.tolist()
    
    inc_df = pd.DataFrame(Incomes.objects.filter(user=request.user).all().values('date_created', 'amount'))
    

    if inc_df.empty:
        default_items_inc = [0]
        labels_inc = [0]
    
    else:
        categories['incomes'] = pd.unique(pd.DataFrame(Incomes.objects.filter(user=request.user).all().values('categories')).categories.values).tolist()
        
        inc_df['date_created'] = pd.to_datetime(inc_df['date_created'])
        inc_df = pd.DataFrame(inc_df.groupby(inc_df['date_created'].dt.strftime('%B'))['amount'].sum())
        inc_df["date_created"] = inc_df.index
        inc_df.index = pd.CategoricalIndex(inc_df["date_created"], categories=sort_order, ordered=True)
        inc_df = inc_df.sort_index().reset_index(drop=True)
        
        default_items_inc = inc_df.amount.tolist()
        labels_inc = inc_df.date_created.tolist()
    try:
        net_df = pd.merge(inc_df, exp_df, how='outer', on='date_created')
        net_df = net_df.fillna(0)
        net_df['amount'] = net_df['amount_x'] - net_df['amount_y']
        net_df.index = pd.CategoricalIndex(net_df["date_created"], categories=sort_order, ordered=True)
        net_df = net_df.sort_index().reset_index(drop=True)

        default_items_net = net_df.amount.tolist()
        labels_net = net_df.date_created.tolist()

    except KeyError:
        if inc_df.empty:
            net_df = exp_df
        
        elif exp_df.empty:
            net_df = inc_df
        
        net_df.index = pd.CategoricalIndex(net_df["date_created"], categories=sort_order, ordered=True)
        net_df = net_df.sort_index().reset_index(drop=True)

        default_items_net = net_df.amount.tolist()
        labels_net = net_df.date_created.tolist()
        
    savings_df = pd.DataFrame(Savings.objects.filter(user=request.user).all().values('date_created', 'amount'))

    if savings_df.empty:
        default_items_savings = [0]
        labels_savings = [0]

    else:
        categories['savings'] = pd.unique(pd.DataFrame(Savings.objects.filter(user=request.user).all().values('categories')).categories.values).tolist()
        
        savings_df['date_created'] = pd.to_datetime(savings_df['date_created'])
        savings_df = pd.DataFrame(savings_df.groupby(savings_df['date_created'].dt.strftime('%B'))['amount'].sum())
        savings_df["date_created"] = savings_df.index
        savings_df.index = pd.CategoricalIndex(savings_df["date_created"], categories=sort_order, ordered=True)
        savings_df = savings_df.sort_index().reset_index(drop=True)

        default_items_savings = savings_df.amount.tolist()
        labels_savings = savings_df.date_created.tolist()

    labels = {'expenses': labels_exp, 
              'incomes': labels_inc,
              'net': labels_net,
              'savings': labels_savings}
    
    default_items = {'expenses': default_items_exp,
                     'incomes': default_items_inc,
                     'net': default_items_net,
                     'savings': default_items_savings}

    data = {
        'labels': labels,
        'default': default_items,
        'categories': categories
    }

    return JsonResponse(data, safe=False) 

home.js:

let chartUsed = null;

document.getElementById("showExpChart").addEventListener("click", funShowExpChart, false);
document.getElementById("showIncChart").addEventListener("click", funShowIncChart, false);
document.getElementById("showNetChart").addEventListener("click", funShowNetChart, false);
document.getElementById("showSaveChart").addEventListener("click", funShowSaveChart, false);

chartInsToDel = document.getElementById("chart-instruc")

function funShowExpChart() {
    var endpoint = 'expenses/api/data'
    var defaultData = []
    var labels = []
    if(chartUsed != null){
    chartUsed.destroy();
    };
    try {
    chartInsToDel.remove();
    }
    finally {
    console.log('Deleted already.')
    }
    
    $.ajax({
        method:"GET",
        url: endpoint,
        success: function(data){
        labels = data.labels
        defaultData = data.default

        categories = data.categories.expenses
        
        $('#category')
            .find('option')
            .remove()
            .end()
            .append('<option value="">category</option>')
            .val('whatever');

        newSelect = document.getElementById("category");

        for(element in categories)
        {
            var opt = document.createElement("option");
            opt.value= categories[element];
            opt.innerHTML = categories[element]; // whatever property it has

            // then append it to the select element
            newSelect.appendChild(opt);
        }

        const chartEle = document.getElementById('myChart').getContext("2d");
        chartUsed = new Chart(chartEle, {
            type: 'line',
            data: {
            labels: labels.expenses,
            datasets: [{
                label: 'Expenses',
                data: defaultData.expenses,
                borderWidth: 1
            }]
            },
            options: {
            scales: {
                y: {
                xAxes: [{
                    type: 'time'
                }]
                }
            },
            responsive: true,
            maintainAspectRatio: false
            }
        }
        );
        
        },
        error: function(error_data){
        console.log("error")
        console.log(error_data)
        }
    })
    
};

function funShowIncChart() {
    var endpoint = 'expenses/api/data'
    var defaultData = []
    var labels = []
    if(chartUsed != null){
    chartUsed.destroy();
    };
    
    try {
    chartInsToDel.remove();
    }
    finally {
    console.log('Deleted already.')
    }

    $.ajax({
    method:"GET",
    url: endpoint,
    success: function(data){
        labels = data.labels
        defaultData = data.default
        
        categories = data.categories.incomes
        
        $('#category')
            .find('option')
            .remove()
            .end()
            .append('<option value="">category</option>')
            .val('whatever');

        newSelect = document.getElementById("category");

        for(element in categories)
        {
            var opt = document.createElement("option");
            opt.value= categories[element];
            opt.innerHTML = categories[element]; // whatever property it has

            // then append it to the select element
            newSelect.appendChild(opt);
        }

        const chartEle = document.getElementById('myChart').getContext("2d");
        chartUsed = new Chart(chartEle, {
        type: 'line',
        data: {
            labels: labels.incomes,
            datasets: [{
            label: 'Incomes',
            data: defaultData.incomes,
            borderWidth: 1
            }]
        },
        options: {
            scales: {
            y: {
                xAxes: [{
                type: 'time'
                }]
            }
            },
            responsive: true,
            maintainAspectRatio: false
        }
        }
        );
    },
    error: function(error_data){
        console.log("error")
        console.log(error_data)
    }
    })
};

function funShowNetChart() {
    var endpoint = 'expenses/api/data'
    var defaultData = []
    var labels = []
    if(chartUsed != null){
    chartUsed.destroy();
    };
    
    try {
    chartInsToDel.remove();
    }
    finally {
    console.log('Deleted already.')
    }

    $.ajax({
    method:"GET",
    url: endpoint,
    success: function(data){
        labels = data.labels
        defaultData = data.default

        $('#category')
            .find('option')
            .remove()
            .end()
            .append('<option value="">category</option>')
            .val('whatever');
        
        const chartEle = document.getElementById('myChart').getContext("2d");
        chartUsed = new Chart(chartEle, {
        type: 'line',
        data: {
            labels: labels.net,
            datasets: [{
            label: 'Net',
            data: defaultData.net,
            borderWidth: 1
            }]
        },
        options: {
            scales: {
            y: {
                xAxes: [{
                type: 'time'
                }]
            }
            },
            responsive: true,
            maintainAspectRatio: false
        }
        }
        );
    },
    error: function(error_data){
        console.log("error")
        console.log(error_data)
    }
    })
};


function funShowSaveChart() {
    var endpoint = 'expenses/api/data'
    var defaultData = []
    var labels = []
    if(chartUsed != null){
    chartUsed.destroy();
    };
    
    try {
    chartInsToDel.remove();
    }
    finally {
    console.log('Deleted already.')
    }

    $.ajax({
    method:"GET",
    url: endpoint,
    success: function(data){
        labels = data.labels
        defaultData = data.default

        categories = data.categories.savings
        
        $('#category')
            .find('option')
            .remove()
            .end()
            .append('<option value="">category</option>')
            .val('whatever');

        newSelect = document.getElementById("category");

        for(element in categories)
        {
            var opt = document.createElement("option");
            opt.value= categories[element];
            opt.innerHTML = categories[element]; // whatever property it has

            // then append it to the select element
            newSelect.appendChild(opt);
        }
        
        const chartEle = document.getElementById('myChart').getContext("2d");
        chartUsed = new Chart(chartEle, {
        type: 'line',
        data: {
            labels: labels.savings,
            datasets: [{
            label: 'Savings',
            data: defaultData.savings,
            borderWidth: 1
            }]
        },
        options: {
            scales: {
            y: {
                xAxes: [{
                type: 'time'
                }]
            }
            },
            responsive: true,
            maintainAspectRatio: false
        }
        }
        );
    },
    error: function(error_data){
        console.log("error")
        console.log(error_data)
    }
    })
};

home.html:

{% extends "boost/base.html" %}

{% load static %}

{% block content %}
    <!-- Main Content Area -->
<div class="content">
    
  <h2>Hello {{ request.user }}</h2>
    
</div>
<div class="container">
  <div class="container overflow-hidden">
    <div class="row gx-5">
      <div class="col">
        <div class="card text-white bg-info mb-3" style="max-width: 18rem;">
          <div class="card-chart">
            <a id="showExpChart">
            <div class="card-header text-center"><h2 class="card-title">Expenses</h2></div>
            <div class="card-body">
              <h3 class="card-text text-center">{{expenses_total}}</h3>
            </div>
            </a>
          </div>
          
        </div>
        
       </div>
      <div class="col">
        <div class="card text-white bg-info mb-3" style="max-width: 18rem;">
          <div class="card-chart">
            <a id="showIncChart">
          <div class="card-header text-center"><h2 class="card-title">Incomes</h2></div>
          <div class="card-body">
            <h3 class="card-text text-center">{{incomes_total}}</h3>
          </div>
        </a>
      </div>
        </div>
      </div>
      <div class="col">
        <div class="card text-white bg-info mb-3" style="max-width: 18rem;">
          <div class="card-chart">
            <a id="showNetChart">
              <div class="card-header text-center"><h2 class="card-title">Net</h2></div>
              <div class="card-body">
                <h3 class="card-text text-center">{{net}}</h3>
              </div>
            </a>
        </div>
      </div>
        
      </div>
      <div class="col">
        <div class="card text-white bg-info mb-3" style="max-width: 18rem;">
          <div class="card-chart">
            <a id="showSaveChart">
              <div class="card-header text-center"><h2 class="card-title">Savings</h2></div>
              <div class="card-body">
                <h3 class="card-text text-center">{{savings_total}}</h3>
              </div>
            </a>
        </div>
      </div>
      
    </div>
    <div id='app'>
      <div id='dateFilter'>
        <h4>Filter by month, year or category</h4>
        <table class='optionsTable'>
          <tr class='optionsRow'>
            <td>
              <select id='month' name="month">
                <option value='' selected='selected'>Month</option>
                <option value='1'>January</option>
                <option value='2'>February</option>
                <option value='3'>March</option>
                <option value='4'>April</option>
                <option value='5'>May</option>
                <option value='6'>June</option>
                <option value='7'>July</option>
                <option value='8'>August</option>
                <option value='9'>September</option>
                <option value='10'>October</option>
                <option value='11'>November</option>
                <option value='12'>December</option>      
              </select>
            </td>
            
            <td>
              <input id='year' name="year_to_filter" placeholder='{{year}}' type='number' min='1900' max='2020'/>
            </td>

            <td>
              <select id='category' name="category">
                <option value='' selected='selected'>Category</option>

              </select>
            </td>

          </tr>
        </table>
      </div>
      
    </div>
    <h3 id="chart-instruc" class="text-center" style="margin-top: 10rem;">Click on the cards above to show a chart!</h3>
    <div style="height: 30rem;">
      <canvas id="myChart"></canvas>
    </div>
    
    
  </div>
  
</div>

<div class="row">
  <div class="col-sm-12" url-endpoin='{% url "boost:api_expenses_data" %}'>
    
  </div>
</div>



<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="{% static 'boost/js/home.js' %}"></script>

{% endblock content %}

I hope I would be able to filter… I don’t know if it is easier to send the raw data to JS and then apply the filters with JS or if it is easier to continue with Python.

Collision Detection in JavaScript for a ball and square

I am attempting to recreate a mobile app called ballz within javascript. This is my first project so I apologize if it hurts your head to read through it.

The ball is shot using the mouse to determine its velocity.
The ball should continually check for collision with a static block.
Depending on if the ball hits a corner or side of the block, the velocity is calculated using the code I provided.

The issue is that the collision response is all over the place. Sometimes the sideCollisionReponse works flawlessly, sometimes the cornerCollisionResponse works flawlessly. However, most of the time, the ball clips through blocks, reflects sporadically, or a combination of the two.

document.addEventListener('DOMContentLoaded', function() {
    const canvas = document.querySelector('canvas');
    const c = canvas.getContext("2d");

    canvas.width = 360;
    canvas.height = 600;
    let isDragging = false;
    let aimX = 0;
    let aimY = 0;

    function drawPoints(points) {
        c.font = '24px Arial';
        c.fillStyle = 'white';
        c.textAlign = 'center';
        c.fillText('Points: ' + points, canvas.width / 2, 30);
    }

    class Sprite {
        constructor(position) {
            this.position = position;
            this.velocity = {
                x: 0,
                y: 0
            };
            this.isShooting = false;
            this.isStuck = false;
            this.points = 0;
            this.radius = 10;
        }

        // May be able to optimize by defining the ball size into a variable for size specific calls
        draw() {
            c.beginPath();
            c.arc(this.position.x, this.position.y, 10, 0, 2 * Math.PI);
            c.fillStyle = "orange";
            c.fill();
        }

        checkCollision() {

            this.wallsCollisionResponse();

            for (let i = 0; i < blocks.length; i++) {
                let block = blocks[i];
                const topLeftDist = Math.sqrt((this.position.x - block.x) ** 2 + (this.position.y - block.y) ** 2);
                const topRightDist = Math.sqrt((this.position.x - block.x - block.width) ** 2 + (this.position.y - block.y) ** 2);
                const bottomLeftDist = Math.sqrt((this.position.x - block.x) ** 2 + (this.position.y - block.y - block.height) ** 2);
                const bottomRightDist = Math.sqrt((this.position.x - block.x - block.width) ** 2 + (this.position.y - block.y - block.height) ** 2);
                const isCornerCollision = (topLeftDist <= this.radius || topRightDist <= this.radius || bottomLeftDist <= this.radius || bottomRightDist <= this.radius)

                if (!isCornerCollision) {
                    this.sidesCollisionResponse(block);
                } else if (isCornerCollision) {
                    this.cornerCollisionResponse(block);
                }
            }
        };

        wallsCollisionResponse() {
            let x = this.position.x
            let y = this.position.y

            // Check collision with walls
            if (x - this.radius <= 0 || x + this.radius >= canvas.width) {
                this.velocity.x = -this.velocity.x; // Reverse horizontal velocity
                this.position.x = Math.max(this.radius, Math.min(canvas.width - this.radius, x)); // Limit position within bounds
            }
            if (y - this.radius <= 40 || y + this.radius >= canvas.height) {
                this.velocity.y = -this.velocity.y; // Reverse vertical velocity
                this.position.y = Math.max(this.radius + 40, Math.min(canvas.height - this.radius, y)); // Limit position within bounds
            }

            // Check if ball hits bottom
            if (y + this.radius >= canvas.height) {
                this.isStuck = true;
                this.velocity = {
                    x: 0,
                    y: 0
                };
            }
        }


        cornerCollisionResponse(block) {
            // get line from ball center to corner
            const v1x = this.position.x - block.x
            const v1y = this.position.y - block.y;

            // normalize the line and rotated 90deg to get tanget
            const len = (v1x ** 2 + v1y ** 2) ** 0.5;
            const tx = -v1y / len;
            const ty = v1x / len;

            const dot = (this.velocity.x * tx + this.velocity.y * ty) * 2;

            this.velocity.x = -this.velocity.x + tx * dot;
            this.velocity.y = -this.velocity.y + ty * dot;

            block.decreaseValue();
        }


        sidesCollisionResponse(block) {
            let x = this.position.x
            let y = this.position.y
            let maxSpeed = 20;
            if (
                block.x + block.width >= x - this.radius &&
                block.x <= x + this.radius &&
                block.y + block.height >= y - this.radius &&
                block.y <= y + this.radius
            ) {
                // Calculate collision normal (assuming block is axis-aligned)
                let normalX = 0;
                let normalY = 0;
                if (x < block.x) {
                    normalX = -1; // Collision from left
                } else if (x > block.x + block.width) {
                    normalX = 1; // Collision from right
                }
                if (y < block.y) {
                    normalY = -1; // Collision from top
                } else if (y > block.y + block.height) {
                    normalY = 1; // Collision from bottom
                }

                console.log('Initial velocity1:', this.velocity);

                // Reflect velocity using dot product with normal vector
                let dotProduct = this.velocity.x * normalX + this.velocity.y * normalY;
                this.velocity.x -= 2 * dotProduct * normalX;
                this.velocity.y -= 2 * dotProduct * normalY;

                console.log('Initial velocity2:', this.velocity);

                // Limit velocity to maxSpeed
                const currentSpeed = Math.sqrt(this.velocity.x * this.velocity.x + this.velocity.y * this.velocity.y);
                if (currentSpeed > maxSpeed) {
                    const ratio = maxSpeed / currentSpeed;
                    this.velocity.x *= ratio;
                    this.velocity.y *= ratio;
                }

                this.limitVelocity();

                // Adjust position to prevent clipping
                const overlapX = Math.abs(x - block.x - block.width);
                const overlapY = Math.abs(y - block.y - block.height);
                const separationX = overlapX * normalX;
                const separationY = overlapY * normalY;
                //this.position.x += separationX;
                //this.position.y += separationY;

                block.decreaseValue();
            }
        }


        limitVelocity() {
            // Limit velocity to maxSpeed
            const maxValue = 20;
            if (this.velocity.x > maxValue) {
                this.velocity.x = maxValue;
            } else if (this.velocity.x < -maxValue) {
                this.velocity.x = -maxValue
            }
            if (this.velocity.y > maxValue) {
                this.velocity.y = maxValue;
            } else if (this.velocity.y < -maxValue) {
                this.velocity.y = -maxValue
            }
        }


        update() {
            if (this.isShooting && !this.isStuck) {
                this.move();
                this.checkCollision();
            }
        }

        move() {
            this.position.x += this.velocity.x;
            this.position.y += this.velocity.y;
            // Simulate gravity
            // this.velocity.y += 0.2;
        }


        shoot(mouseX, mouseY) {
            // Calculate direction vector from ball to mouse
            const dx = mouseX - this.position.x;
            const dy = mouseY - this.position.y;
            const magnitude = Math.sqrt(dx * dx + dy * dy);

            const maxSpeed = 20; // Maximum speed limit

            if (magnitude !== 0) {
                const normalizedDx = dx / magnitude;
                const normalizedDy = dy / magnitude;
                const speed = Math.min(magnitude, maxSpeed); // Limit speed to maximum speed
                this.velocity.x = normalizedDx * speed;
                this.velocity.y = normalizedDy * speed;
            }
            this.isShooting = true;
        }


        reset(position) {
            this.position = position; // Maintains last position on reset
            this.velocity = {
                x: 0,
                y: 0
            };
            this.isShooting = false; // this may be unneccessary
            this.isStuck = false;
        }

        getPoints() {
            this.points++;
            return this.points;
        }
    }
    const player = new Sprite({
        x: 180,
        y: 590
    });


    class Block {
        constructor(x, y, width, height, value) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.value = value + 1;
        }

        draw() {
            c.fillStyle = 'green';
            c.fillRect(this.x, this.y, this.width, this.height);
            // Text
            c.fillStyle = 'white';
            c.font = '12px Arial'; // Adjust the font size and style as needed
            c.fillText(this.value.toString(), this.x + this.width / 2, this.y + this.height / 1.75);
        }

        decreaseValue() {
            if (this.value > 0) {
                this.value - 1;
                if (this.value === 0) {
                    // Remove block if value reaches 0
                    blocks.splice(blocks.indexOf(this), 1);
                }
            }
        }

        shiftDown() {
            this.y += this.height + 6
        }
    }
    const blocks = [];

    function createBlocks() {
        const blockWidth = 40;
        const blockHeight = 40;
        const numBlocks = 1;
        //Math.floor(canvas.width / blockWidth);

        for (let i = 0; i < numBlocks; i++) {
            const blockValue = player.points;
            blocks.push(new Block(120, 80, blockWidth, blockHeight, blockValue));
        }
    }

    createBlocks();

    function animate() {
        requestAnimationFrame(animate); // clears canvas before next frame
        c.clearRect(0, 0, canvas.width, canvas.height);
        c.fillStyle = '#4D4D4D'; // Top bar color
        c.fillRect(0, 0, canvas.width, 40);


        if (isDragging && !player.isShooting) {
            const dx = aimX - player.position.x;
            const dy = aimY - player.position.y;
            const magnitude = Math.sqrt(dx * dx + dy * dy);
            const maxSegments = 20; // Maximum number of segments
            const totalTime = 1; // Total time for preview (adjust as needed)

            for (let i = 0; i < maxSegments; i++) {
                const progress = i / maxSegments; // Progress along the trajectory
                const time = progress * totalTime; // Time at this segment
                const previewX = player.position.x + dx * time;
                const previewY = player.position.y + dy * time; // Vertical motion with gravity + 0.5 * 9.81 * time * time
                c.beginPath();
                c.arc(previewX, previewY, player.radius, 0, 2 * Math.PI);
                const alpha = 1 - i * (0.5 / maxSegments); // Decrease transparency for each segment
                c.fillStyle = `rgba(255, 165, 0, ${alpha})`; // Transparent orange
                c.fill();
            }
        }


        player.draw();
        player.update();

        drawPoints(player.points);

        blocks.forEach((block, index) => {
            block.draw();
        });

        if (player.isStuck) {
            player.reset({
                x: player.position.x,
                y: player.position.y
            })
            player.getPoints();
            blocks.forEach((block, index) => {
                block.shiftDown();
            })
            createBlocks();

        }
    }

    animate();

    canvas.addEventListener("mousedown", (event) => {
        const rect = canvas.getBoundingClientRect();
        const mouseX = event.clientX - rect.left;
        const mouseY = event.clientY - rect.top;

        if (!player.isShooting && mouseX >= 0 && mouseX <= canvas.width && mouseY >= 0 && mouseY <= canvas.height - 20) {
            isDragging = true;
            aimX = mouseX;
            aimY = mouseY;
        }
    })

    canvas.addEventListener("mouseup", (event) => {
        if (isDragging) {
            isDragging = false;
            const rect = canvas.getBoundingClientRect();
            const mouseX = event.clientX - rect.left;
            const mouseY = event.clientY - rect.top;
            if (mouseX >= 0 && mouseX <= canvas.width && mouseY >= 0 && mouseY <= canvas.height - 20) {
                player.shoot(aimX, aimY); // Pass aim position to shoot method
            }
        }
    })

    canvas.addEventListener("mousemove", (event) => {
        if (isDragging) {
            const rect = canvas.getBoundingClientRect();
            aimX = event.clientX - rect.left;
            aimY = event.clientY - rect.top;
        }
    })
});

Stolen characters in the variable

`
let text = ‘hello world’,
missingText = ‘helo word’;// Here is a “l”;

function theMissingText () {

return missingLetter;

}

// If the variable contains a missing character, it returns the leading character
// If it has no missing character, it returns -1

// How to return this character in any variable, regardless of where it is in the text, Example:


let $_text = "original text",
    $_missingText = 'original ext'; // here is "t"

// & here is 

let $_text_2 = "original text",
    $_missingText_2 = 'orignal text'; // here is "i";
`

What files are needed to create a successful front and back end of webpage?

I am getting started in my journey to becoming a developer and I wanted more clarity on certain things when building websites in relation to the front end and the backend.

For example is Javascript in the front end built in a different .js file to the backend on the server side?

Also I am currently learning about EJS and based on the information I have seen, does this replace HTML? or do they kind of work together to build more dynamic webpages?

Any help would be appreciated 🙂

as per the above, I just need more information on front end and back end

How to ensure html2canvas snapshots are within x and y coordinates?

I have a simple React component for testing, it has an initial rectangle which can be move and reshaped, I also have a button on the screen which is supposed to allow me to take a snapshot of the Body within the rectangle but at the moment, the snapshot seems to be misaligned?


import React from "react";
import html2canvas from "html2canvas";

function TestPlayground() {
  const defaultPosition = {
    startX: 1036,
    startY: 470,
    endX: 511,
    endY: 170,
  };

  const [state, setState] = React.useState({
    startX: defaultPosition.startX,
    startY: defaultPosition.startY,
    endX: defaultPosition.endX,
    endY: defaultPosition.endY,
    isDragging: false,
    isResizing: false,
    offsetX: 0,
    offsetY: 0,
    resizeHandle: "",
  });

  const width = Math.abs(state.endX - state.startX);
  const height = Math.abs(state.endY - state.startY);
  const left = Math.min(state.startX, state.endX);
  const top = Math.min(state.startY, state.endY);

  function handleMouseDown(e) {
    const { clientX, clientY } = e;
    const resizeHandle = getResizeHandle(clientX, clientY);

    if (resizeHandle) {
      setState((prevState) => ({
        ...prevState,
        isResizing: true,
        offsetX: clientX - state.endX,
        offsetY: clientY - state.endY,
        resizeHandle: resizeHandle,
      }));
    } else {
      setState((prevState) => ({
        ...prevState,
        isDragging: true,
        offsetX: clientX - left,
        offsetY: clientY - top,
      }));
    }
  }

  function handleMouseUp() {
    setState((prevState) => ({
      ...prevState,
      isDragging: false,
      isResizing: false,
      resizeHandle: "",
    }));
  }

  function handleMouseMove(e) {
    const { clientX, clientY } = e;

    if (state.isDragging) {
      const newStartX = clientX - state.offsetX;
      const newStartY = clientY - state.offsetY;
      setState((prevState) => ({
        ...prevState,
        startX: newStartX,
        startY: newStartY,
        endX: newStartX + width,
        endY: newStartY + height,
      }));
    } else if (state.isResizing) {
      const newEndX = clientX - state.offsetX;
      const newEndY = clientY - state.offsetY;
      setState((prevState) => ({
        ...prevState,
        endX: newEndX,
        endY: newEndY,
      }));
    }
  }

  function getResizeHandle(clientX, clientY) {
    const handleSize = 10;

    const handlePositions = {
      nw: { x: left, y: top },
      ne: { x: left + width, y: top },
      sw: { x: left, y: top + height },
      se: { x: left + width, y: top + height },
    };

    for (let handle in handlePositions) {
      const { x, y } = handlePositions[handle];
      if (
        clientX >= x - handleSize &&
        clientX <= x &&
        clientY >= y - handleSize &&
        clientY <= y
      ) {
        return handle;
      }
    }

    return null;
  }

  const takeSnapShot = () => {
    const body = document.querySelector("body");

    if (body) {
      html2canvas(body).then((canvas) => {
        const croppedCanvas = document.createElement("canvas");
        const croppedCanvasContext = croppedCanvas.getContext("2d");

        const width = Math.abs(state.endX - state.startX);
        const height = Math.abs(state.endY - state.startY);
        const left = Math.min(state.startX, state.endX);
        const top = Math.min(state.startY, state.endY);

        croppedCanvas.width = width;
        croppedCanvas.height = height;

        if (croppedCanvasContext) {
          // Draw the cropped region onto the new canvas
          croppedCanvasContext.drawImage(
            canvas,
            top, // sx: x-axis coordinate of the top-left corner of the sub-rectangle
            left, // sy: y-axis coordinate of the top-left corner of the sub-rectangle
            width, // sWidth: width of the sub-rectangle to draw
            height, // sHeight: height of the sub-rectangle to draw
            0, // dx: x-axis coordinate in the destination canvas to place the top-left corner of the source image
            0, // dy: y-axis coordinate in the destination canvas to place the top-left corner of the source image
            width, // dWidth: width to draw the image in the destination canvas (optional, will default to sWidth)
            height // dHeight: height to draw the image in the destination canvas (optional, will default to sHeight)
          );
        }

        const imageData = croppedCanvas.toDataURL("image/jpeg");
        console.log(imageData);
      });
    }
  };

  return (
    <div>
      <div
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUp}
        onMouseMove={handleMouseMove}
        style={{
          position: "absolute",
          left: `${left}px`,
          top: `${top}px`,
          width: `${width}px`,
          height: `${height}px`,
          border: "2px dotted black",
          zIndex: "99",
          backgroundColor: "rgba(0, 0, 0, 0)", // Transparent background
          cursor: state.isDragging || state.isResizing ? "grabbing" : "grab",
          resize: "both",
          overflow: "auto",
        }}
      />
      <div>
        <div style={{ display: "flex", width: 1000 }}>
          <div
            style={{
              backgroundColor: "red",
              width: 500,
              height: 200,
              alignSelf: "end",
            }}
          />
        </div>
        <button onClick={() => takeSnapShot()}>TAKE SNAPSNOT</button>
      </div>
    </div>
  );
}

export default TestPlayground;

Is my top and left value off? am I missing something here?

Thanks for the help.

Read more button deactivates

The read more button deactivates when i make another one in another paragraph but as long as i make 2 or 3 read more button at the same paragraph it works. I want all the buttons activated how can i fix this problem ?

const parentContainer = document.querySelector('.read-more-container');
parentContainer.addEventListener('click', event => {
  const current = event.target;
  const isReadMoreBtn = current.className.includes('read-more-btn');
  if (!isReadMoreBtn) return;
  const currentText = event.target.parentNode.querySelector('.read-more-text');
  currentText.classList.toggle('read-more-text--show');
  current.textContent = current.textContent.includes('Read More') ? "Read Less..." : "Read More...";
})
<div class="read-more-container">
  <div class="container">
    <p>
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Unde, facere? Quae distinctio reprehenderit soluta fugiat, alias, doloremque similique tenetur magni voluptate a, perspiciatis quaerat! Necessitatibus velit consectetur expedita consequatur assumenda!
      <span class="read-more-text">
                                             Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio quasi quaerat, amet explicabo magnam, nulla porro dolorem itaque
                                         </span>
    </p>
    <span class="read-more-btn">Read More...</span>
  </div>
  <div class="container">
    <p>
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Unde, facere? Quae distinctio reprehenderit soluta fugiat, alias, doloremque similique tenetur magni voluptate a, perspiciatis quaerat! Necessitatibus velit consectetur expedita consequatur assumenda!
      <span class="read-more-text">
                                             Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio quasi quaerat, amet explicabo magnam, nulla porro dolorem itaque
                                         </span>
    </p>
    <span class="read-more-btn">Read More...</span>
  </div>
</div>
<div class="card-courses-list admin-courses">
</div>
<div class="card-courses-full-dec">
  <div class="card-courses-title">
    <h4></h4>
  </div>
  <div class="card-courses-list-bx">
    <ul class="card-courses-view">
      <li class="card-courses-user">
        <div class="card-courses-user-pic">
        </div>
        <div class="card-courses-user-info">
          <h5>Client</h5>
          <h4>Khaled Ahmed Yasser</h4>
        </div>
      </li>
      <li class="card-courses-user-info">
        <h5>Request Date</h5>
        <h4>28/02/2024</h4>
      </li>
      <li class="card-courses-user-info">
        <h5>Total Meals</h5>
        <h4>15</h4>
      </li>
      <li class="card-courses-price">
        <del></del>
        <h5 class="text-primary"></h5>
      </li>
    </ul>
  </div>
  <div class="row card-courses-dec">
    <div class="col-md-12">
      <h6 class="m-b10">Request details</h6>
      <p>Start Date: 29/02/2024
        <div style="white-space: pre-wrap;"></div>
        <p>End Date: 15/03/2024 </p>
        <p>City: Nasr City</p>
        <p>Address: 8th district 9 Al zomor street </p>
    </div>
    <div class="col-md-12">
      <a href="#" class="btn gray outline radius-xl ">View Meals Details</a>
    </div>
  </div>
  <div class="read-more-container0">
    <div class="container">
      <p>
        Lorem ipsum dolor sit, amet consectetur adipisicing elit. Unde, facere? Quae distinctio reprehenderit soluta fugiat, alias, doloremque similique tenetur magni voluptate a, perspiciatis quaerat! Necessitatibus velit consectetur expedita consequatur assumenda!
        <span class="read-more-text">
                        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio quasi quaerat, amet explicabo magnam, nulla porro dolorem itaque
                    </span>
      </p>
      <span class="read-more-btn">Read More...</span>
    </div>
    <div class="container">
      <p>
        Lorem ipsum dolor sit, amet consectetur adipisicing elit. Unde, facere? Quae distinctio reprehenderit soluta fugiat, alias, doloremque similique tenetur magni voluptate a, perspiciatis quaerat! Necessitatibus velit consectetur expedita consequatur assumenda!
        <span class="read-more-text">
                        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio quasi quaerat, amet explicabo magnam, nulla porro dolorem itaque
                    </span>
      </p>
      <span class="read-more-btn">Read More...</span>
    </div>
  </div>

(javascript object) if the next values greater of first value by 1 add the values in new object, if not, ignore the values

I have an object and a variable that represents 1 as a value. It can be more, for example: 1,2,3,4,5.....etc.

What I want is to compare the following values with the first value in the object, and if the result of subtracting the first value is greater than or equal to 1, add these values to a new object.
For example:
The first value is 10. The next value is 10.5, which is the largest of 10. We subtract 10 from 10.5. The result is 0.5. This result is less than 1, so we ignore it.

We move to the next value, which is 11, and since 11 is greater than 10.5, we subtract 10 from 11 and not 10.5 from 11. The result is 1, we add it in the new object, and the result is like this: {pr:10, pr:11}.

We move to the next value, which is 11.3, and since 11.3 is greater than 11, we subtract 10from 11.3. The result is 1.3, and now we add it to the new object, and the result is like this: {pr:10, pr:11, pr:11.3}.

We move to the next value, which is 12, which is larger than the previous value, 11.3. we subtract 10 from 12. The result is 2, and now we add it to the new object, and the result is like this: {pr:10, pr:11, pr:11.3, pr:12 }.

We move to the next value, which is 11.5, and we notice that this value is smaller than the previous value, 12. Therefore, we do not subtract 11.5 from 10, but from the previous value, which is 12, and the result is 0.5, so we do not add it to the new object.

We move to the next value, which is 12, and since the previous value was not added to the new object, we compare it with the value that was before 11.5, which is 12, and since the values are equal, we do not add anything to the new object.
So the new object remains as it is.{pr:10, pr:11, pr:11.3, pr:12}.

We move to the next value, which is 11, and since 11 is less than 12, we subtract 11 from 12, and the result is 1, so we add 11 to the new object. The result is: {pr:10, pr:11, pr:11.3, pr:12, pr:11}.

I spent a lot of time trying to reach a conclusion but I couldn’t.
Anyone who can help me, I appreciate this, and thanks to everyone.

let lists = [
  { id: "1", price: 10,  },
  { id: "2", price: 10.5 },
  { id: "3", price: 11,  },
  { id: "4", price: 11.3,},
  { id: "5", price: 12,  },
  { id: "6", price: 11.5 },
  { id: "7", price: 12,  },
  { id: "8", price: 11,  },
]
let finalList = [
  { id: "1", price: 10,  },
  { id: "3", price: 11,  },
  { id: "4", price: 11.3,},
  { id: "5", price: 12,  },
  { id: "8", price: 11,  },
]

JS append malfunction

I’m trying to make a page where you type in a url and it opens the url, but then appends the page content to the tab. So far my js code is this:

<script>
    var url = "<?php echo $_GET['url']; ?>";
    var tab = window.open(url, "_blank");
    tab.appendChild("<?php echo file_get_contents($_GET['url']); ?>");
</script>

Based on what I understand, it should open the requested page, then append the code to the page. Any help would be much appreciated, thank you.

How to make sure a page only available for a period of time

I’m doing a project recording the attendance of the students using html, php and js. The students should not be able to record their attendance after some time.

I’m struggling to find a way to make sure the page that records the attendance should not be available after the set time. The period should be a user input. Hope I’ll be assisted on this. Thanks