Best practices for creating a centralized fetch function in JavaScript to maintain flexibility [closed]

I’m working on a project where I want to centralize all API requests to maintain flexibility in case I need to switch from the native fetch API to another library (like Axios or Ky) in the future.

Goal:
Create a centralized function that wraps the fetch API and returns the fetch object itself without parsing the response. The idea is that all API calls use this centralized function so that switching to a different library only requires changes in one place.

An example of a simple centralized fetch function:

const customFetch = (url, options = {}) => {
  // Only wrap fetch here
  return fetch(url, options);
};

Questions:

What should a centralized fetch function generally handle?

Should this function be able to handle both GET and POST requests, or should separate abstract functions be created for different HTTP methods?
How powerful should this function be? Should it include things like default headers, error handling, retries, etc., or should it remain minimal and leave such concerns to the calling code?

Integrating with react-query:

What is the best practice for integrating a centralized fetch function with react-query? Should the centralized fetch function be directly used as the queryFn?
Is it advisable to create specific functions like fetchJson or postQuery that wrap the centralized fetch for particular use cases?
How could a centralized useQuery function be implemented in TypeScript, which incorporates this fetch function, making all data fetching logic consistent across the project?

How to download files from remote server in Apache Guacamole SSH connection type

Im using Apache Guacamole server version 1.5.3 to create SSH session for users via web browser, in order to communicate with the server I’m using the common-js api:

...
const tunnel = new Guacamole.WebSocketTunnel(wsURL);
tunnel.receiveTimeout = 60000;
tunnel.onerror = error => {
    showError(`Connection to the remote server failed.`, error);
}
const guac = new Guacamole.Client(tunnel);
const display = guac.getDisplay();
display.scale(1);
....

I’m able to create a tunnel and to communicate with the SSH server and upload files, but I’m unable to make download files working.
I saw that there is an event which fired when new file is created, that I can use to initiate file download in the browser, but I can’t make this event fire:

/**
     * Fired when a file stream is created. The stream provided to this event
     * handler will contain its own event handlers for received data.
     * 
     * @event
     * @param {Guacamole.InputStream} stream The stream that will receive data
     *                                       from the server.
     * @param {String} mimetype The mimetype of the file received.
     * @param {String} filename The name of the file received.
     */
    this.onfile = null;

I tried to set

guac.onfile = function downloadFile(fileStream, mimetype, filename) {
    console.log("ONFILE called", filename, mimetype, filename)
}

According to do docs here, the way to do it is to use a shell script guacctl that suppose to send some opcodes to the tunnel, I tried to scp the script to the remote server and run ./guacctl -d /path/to/file, but it does nothing, like nothing listen to the event.

Is there anyone here who had a chance to implement this? Most of the examples and guides I see in the web regarding file transfer is for RDP or VNC when you simply drag and drop the file and guacamole does everything behind the scene.

Question is, what are the steps I need to do in order to manually initiate file download using onfile event, or how can I make guacctl working? I feel like I’m missing something.

Change laravel variable value with javascript

<div class="form-group">
    <label for="parent_category">Category:</label>
    <select id="parent_category" name="parent_category" class="form-control" required>
        @foreach ($categories as $category)
            @if ($category->parent_category == null)
                <option value="{{ $category->id }}" {{ $selectedCategoryId = $category->id }}>
                    {{ $category->name }}
                </option>
            @endif
        @endforeach
    </select>
</div>

<div class="form-group">
    <label for="category_id">Sub-Category:</label>
        <select id="category_id" name="category_id" class="form-control" required>
            @foreach ($categories as $category)
                @if ($category->parent_category == $selectedCategoryId)
                    <option value="{{ $category->id }}">
                        {{ $category->name }}
                    </option>
                @endif
            @endforeach
        </select>
</div>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        var parent_category = document.getElementById('parent_category');

        parent_category.addEventListener('change', function() {
            console.log("changed")
        })
    });
</script>

i need to change $selectedCategoryId according to the user select, how can i do that ??
I have a table with, id, name, parent_id

the parent_id references an id from the table itself, if the value is null it is considered a “parent”.

in my first select I want to show only the parents (parent_id = null)
in the second select I want to show the “children” of the selected parent.

How to change text of a div element with multiple classes?

I am a beginner programmer and I am creating a website using the Tutor LMS Pro plugin. This plugin allows you to create a panel with courses, unfortunately it is not fully translated into my native language. I’m trying to translate individual headers using JavaScript, but for some reason it doesn’t work. I have previously translated another element that has the same class as the element I am currently trying to translate (tutor-mb-24). Therefore, both elements are translated in the same way. I thought that if the second element shares the tutor-mb-24 class but also has other classes, the code will only work for it, but it doesn’t work at all and is inferior to the code that only translates the tutor-mb-24 class for the other element. I don’t really understand the essence of the problem.

Element I’m working with:

<div class="tutor-col-12 tutor-col-md-8 tutor-col-lg-9">
<div class="tutor-dashboard-content">
<div class="tutor-fs-5 tutor-fw-medium tutor-color-black tutor-capitalize-text tutor-mb-24 tutor-dashboard-title">Text I want to change</div>
</div>
</div>

I tried:

document.getElementsByClassName("tutor-fs-5 tutor-fw-medium tutor-color-black tutor-capitalize-text tutor-mb-24 tutor-dashboard-title").textContent="New Text";
document.addEventListener('DOMContentLoaded', function() {
    var x1 = document.getElementsByClassName("tutor-fs-5 tutor-fw-medium tutor-color-black tutor-capitalize-text tutor-mb-24 tutor-dashboard-title");
    if (x1.length > 0) {
        x1[0].innerHTML = 'New Text';
    }

});

Setting Extrafields in Datalife Engine with URLs won’t insert into Database

I am using Datalife engine 13.2.
I have some Extrafields that are “Use fields values as cross-hyperlinks” and are inserted auto via a button using an api to scrape infos.

when i click on submit the article. those extrafields are empty even if they are set with the api.

here is the code i am using to set them.

extrafield named: country.

$(“#xf_country-tokenfield”).val(d.Country);

ScrollView not working after collecting data from API

Im learning react native and cant get my page to scroll, I have tried to simplify it and use simple text and not my call back but literally nothing is working

Any help would be great

My results screen:

import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, ScrollView, useWindowDimensions } from 'react-native';
import RenderHTML from 'react-native-render-html';

const ProgressScreen = ({ route }) => {
    const { plan, loading, error } = route.params || {};
    const [parsedPlan, setParsedPlan] = useState(null);
    const { width } = useWindowDimensions();

    useEffect(() => {
        if (plan) {
            try {
                const parsedData = JSON.parse(plan);
                setParsedPlan(parsedData);
            } catch (e) {
                console.error('Error parsing plan data:', e);
            }
        }
    }, [plan]);

    if (loading) {
        return (
            <View style={styles.container}>
                <ActivityIndicator size="large" color="#fff" />
                <Text style={styles.loadingText}>Loading...</Text>
            </View>
        );
    }

    if (error) {
        return (
            <View style={styles.container}>
                <Text style={styles.errorText}>{error}</Text>
            </View>
        );
    }

    if (!parsedPlan) {
        return (
            <View style={styles.container}>
                <Text style={styles.errorText}>No plan data available</Text>
            </View>
        );
    }

    return (
        <ScrollView style={styles.container} contentContainerStyle={styles.scrollContent}>
            <Text style={styles.titleText}>{parsedPlan.title}</Text>
            <Text style={styles.greetingText}>{parsedPlan.greeting}</Text>
            <Text style={styles.heading}>Ingredients:</Text>
            {parsedPlan.ingredients && (
                <RenderHTML
                    contentWidth={width}
                    source={{ html: parsedPlan.ingredients }}
                    baseStyle={{ color: '#fff' }}
                />
            )}
            <Text style={styles.heading}>Instructions:</Text>
            {parsedPlan.instructions && (
                <RenderHTML
                    contentWidth={width}
                    source={{ html: parsedPlan.instructions }}
                    baseStyle={{ color: '#fff' }}
                />
            )}
            <Text style={styles.heading}>Nutritional Value:</Text>
            <Text style={styles.nutritionalText}>{parsedPlan.nutritional_value}</Text>
        </ScrollView>
    );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'rgb(9, 9, 11)',
    },
    scrollContent: {
        padding: 20,  // padding for the content inside the ScrollView
    },
    loadingText: {
        color: '#fff',
        marginTop: 10,
    },
    errorText: {
        color: 'red',
    },
    titleText: {
        fontSize: 24,
        color: '#fff',
        marginBottom: 10,
    },
    greetingText: {
        fontSize: 16,
        color: '#fff',
        marginBottom: 20,
    },
    heading: {
        fontSize: 20,
        color: '#fff',
        marginTop: 20,
    },
    nutritionalText: {
        fontSize: 16,
        color: '#fff',
        marginTop: 10,
    },
});

export default ProgressScreen;

for context my screen thats navigating us to the progressScreen

import React, {useState} from 'react';
import {View, TextInput, Button, Text, StyleSheet, Image, TouchableOpacity, ActivityIndicator} from 'react-native';
import axios from 'axios';

const CustomCheckbox = ({isChecked, onPress}) => {
    return (
        <TouchableOpacity onPress={onPress} style={[styles.checkboxBase, isChecked && styles.checkboxChecked]}>
            {isChecked && <View style={styles.checkboxInner} />}
        </TouchableOpacity>
    );
};

const MainScreen = ({navigation}) => {
    const [loading, setLoading] = useState(false);
    const [textInput, setTextInput] = useState('');
    const [selectedPeople, setSelectedPeople] = useState('1');
    const [checkboxes, setCheckboxes] = useState({
        lowFODMAP: false,
        glutenFree: false,
        dairyFree: false,
        vegetarian: false,
        vegan: false,
        lowCalorie: false,
    });
    const handleCookPress = async () => {
    try {
        setLoading(true);
        const response = await axios.post('endpoint', {
            content: textInput,
            fodmap: checkboxes.lowFODMAP || false,
            dairy: checkboxes.dairyFree || false,
            gluten: checkboxes.glutenFree || false,
            veggie: checkboxes.vegetarian || false,
            vegan: checkboxes.vegan || false,
            calorie: checkboxes.lowCalorie || false,
            people: selectedPeople || 1,
        });


        if (response.data.status === 200) {
            setLoading(false);
            navigation.navigate('ProgressScreen', { plan: response.data.data, loading: false });
        } else {
            setLoading(false);
            navigation.navigate('ProgressScreen', { error: response.data.message, loading: false });
        }
    } catch (error) {
        console.error('Axios error:', error.response || error.message);
        navigation.navigate('ProgressScreen', { error: 'An error occurred', loading: false });
    }
};
    const handleCheckboxChange = (key) => {
        setCheckboxes({...checkboxes, [key]: !checkboxes[key]});
    };

    return (
        <View style={styles.container}>
            <Image
                source={{uri: '/img/icon.fb33606c.png'}} // Replace with your image URL
                style={styles.image}
                resizeMode="contain"
            />
            <TextInput
                style={styles.input}
                placeholder="I would like to make a cherry pie..."
                placeholderTextColor="#ccc"
                value={textInput}
                onChangeText={setTextInput}
            />
            <View style={styles.checkboxContainer}>
                <CustomCheckbox
                    isChecked={checkboxes.lowFODMAP}
                    onPress={() => handleCheckboxChange('lowFODMAP')}
                />
                <Text style={styles.label}>Low FODMAP</Text>
            </View>
            <View style={styles.checkboxContainer}>
                <CustomCheckbox
                    isChecked={checkboxes.glutenFree}
                    onPress={() => handleCheckboxChange('glutenFree')}
                />
                <Text style={styles.label}>Gluten and Wheat Free</Text>
            </View>
            <View style={styles.checkboxContainer}>
                <CustomCheckbox
                    isChecked={checkboxes.dairyFree}
                    onPress={() => handleCheckboxChange('dairyFree')}
                />
                <Text style={styles.label}>Dairy Free</Text>
            </View>
            <View style={styles.checkboxContainer}>
                <CustomCheckbox
                    isChecked={checkboxes.vegetarian}
                    onPress={() => handleCheckboxChange('vegetarian')}
                />
                <Text style={styles.label}>Vegetarian</Text>
            </View>
            <View style={styles.checkboxContainer}>
                <CustomCheckbox
                    isChecked={checkboxes.vegan}
                    onPress={() => handleCheckboxChange('vegan')}
                />
                <Text style={styles.label}>Vegan</Text>
            </View>
            <View style={styles.checkboxContainer}>
                <CustomCheckbox
                    isChecked={checkboxes.lowCalorie}
                    onPress={() => handleCheckboxChange('lowCalorie')}
                />
                <Text style={styles.label}>Low Calorie</Text>
            </View>
            <TouchableOpacity
            style={styles.button}
            onPress={handleCookPress}
            disabled={loading} // Optionally disable the button while loading
        >
            {loading ? (
                <ActivityIndicator size="small" color="#ffffff" />
            ) : (
                <Text style={styles.buttonText}>Get me a recipe</Text>
            )}
        </TouchableOpacity>
        </View>
    );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        padding: 20,
        backgroundColor: 'rgb(9, 9, 11)',
    },
    image: {
        width: '100%',
        height: 200,
        marginBottom: 20,
        marginTop: 30,
    },
    input: {
        borderWidth: 1,
        borderColor: '#fff',
        color: '#fff',
        padding: 10,
        marginBottom: 20,
        borderRadius: 5,
    },
    checkboxContainer: {
        flexDirection: 'row',
        alignItems: 'center',
        marginBottom: 10,
    },
    label: {
        marginLeft: 8,
        color: '#fff',
    },
    button: {
        backgroundColor: 'rgb(140, 7, 24)',
        padding: 15,
        borderRadius: 10,
        alignItems: 'center',
        marginTop: 20,
    },
    buttonText: {
        color: '#fff',
        fontSize: 16,
        fontWeight: 'bold',
    },
    checkboxBase: {
        width: 24,
        height: 24,
        borderRadius: 10,
        borderWidth: 2,
        borderColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
    },
    checkboxChecked: {
        backgroundColor: '#fff',
    },
    checkboxInner: {
        width: 12,
        height: 12,
        borderRadius: 10,
        backgroundColor: 'rgb(140, 7, 24)',
    },
});

export default MainScreen;

I have tried to use just lipsum text and not use API data but its not working.

closure’s in java script

why closure dosent work on this code?

const a = function () {
  const header = document.querySelector('h1');
  header.style.color = 'red';
};
a();
const b = function () {
  header.style.color = 'blue';
};
b();

I expected that in function b I would have access to header variables from function a because of closure, but it didn’t work that way. why is that?

Resize a textarea based on scrollHeight

I have the following component in my project made with ReactJS:

<TextArea
  className="flex-grow-1"
  style={{ height: textareaHeight, minHeight: "40px" }}
  onInput={handleInput}
  value={message}>

This textarea has a minimum height of 40px, and as the user types, the textarea increases in height until it reaches the limit of 200px.

After that, the overflow is added so that the user can scroll.

To represent this, I created the following command:

const maxHeight = 200;
const [textareaHeight, setTextareaHeight] = useState("40px");
const [message, setMessage] = useState("");

const handleInput = (event) => {
    const textarea = event.target;
    let newHeight = textarea.scrollHeight;

    console.log('newHeight: ' + newHeight);

    if (newHeight > maxHeight) {
      newHeight = maxHeight + "px";
      textarea.style.overflowY = "auto";
    } else {
      textarea.style.overflowY = "hidden";
    }

    setTextareaHeight(newHeight);
    setMessage(textarea.value);
};

The above command works perfectly. The only problem is when the user starts to delete the typed text, my textarea doesn’t resize until it goes back to 40px.

For example, if the user has typed a huge amount of text, the resize will start at 40px, then 80px, then 120px… until it reaches 200px.

But as the user deletes the text, the scrollHeight remains at 200px (or 120px, 80px…), that is, it doesn’t decrease.

I ended up realizing that the problem may be related to changing the height of the textarea, more specifically in the setTextareaHeight(newHeight) command.

Because if you try to remove it, the console message will follow the increase and decrease of the scrollHeight:

newHeight: 40 (user continue typping…).
newHeight: 80 (user continue typping…).
newHeight: 120 (user started deleting text…).
newHeight: 80 (user continue deleting text…).
newHeight: 40 (user continue deleting text…).

In this case, I believe that height and scrollHeight are closely linked.

So, how do I solve my problem?

borders in divs appearing when animating with jquery

I couldn’t find anything on this, so, basicly, when I animate the containers with this:

    
$(document).ready(function() {
  $('#startJourneyContainer').click(function() {
        $("#time").animate({color: "white"}, 800);
        $("#containerInside").animate({opacity: '0',left: '-=300px'}, 800);
        $("#containerInsideIniciar").animate({opacity: '1',left: '-=300px',}, 800);
    });
});

.containerInsideIniciar {
    position: absolute;
    overflow: hidden;
    height: 670px;
    width: 310px;
    border-radius: 50px;
    top: 38px;
    opacity: 0;
    /* left: 0px;  */
    left: 310px;  
    background: rgb(34,190,82);
    background: linear-gradient(187deg, rgba(34,190,82,1) 6%, rgba(33,169,196,1) 24%, rgba(255,255,255,1) 55%, rgba(255,255,255,1) 100%);
    pointer-events: none;
    z-index: 4;
}

.containerInside {
    position: absolute;
    overflow: hidden;
    height: 670px;
    width: 310px;
    border-radius: 50px;
    top: 38px;
    left: 0px;
    background-image: linear-gradient(white,#deeefa,#deeefa);
}

And, when they move, their borders appear there (in the image), how would I make them not show?

JavaScript slider not scrolling automatically from left to right

I’m trying to create a slider that automatically scrolls from left to right when the user reaches the end of the current item. I’ve tried using the following JavaScript code, but it’s not working as expected:

console.log("Slider");



// Get the slider container element
const sliderContainer = document.querySelector('.slider-container');

// Get all slider item elements
const sliderItems = document.querySelectorAll('.slider-item');

// Add event listener to the slider container
sliderContainer.addEventListener('scroll', () => {
  // Get the current scroll position
  const scrollPosition = sliderContainer.scrollLeft;

  // Loop through each slider item
  sliderItems.forEach((item, index) => {
    // Check if the item is in view
    if (scrollPosition >= item.offsetLeft && scrollPosition < item.offsetLeft + item.offsetWidth) {
      // Add the active class to the item
      item.classList.add('active');
    } else {
      // Remove the active class from the item
      item.classList.remove('active');
    }

    // Check if we've reached the end of the current item
    if (scrollPosition + sliderContainer.offsetWidth >= item.offsetLeft + item.offsetWidth) {
      // Automatically scroll to the next item
      sliderContainer.scrollLeft = item.offsetLeft + item.offsetWidth;
    }
  });
});

The slider container has a horizontal scrollbar, and I want it to automatically scroll to the next item when the user reaches the end of the current item. However, the slider is not scrolling automatically, and I’m not seeing any errors in the console.

I’ve tried modifying the condition to check if we’ve reached the end of the current item, but it’s still not working. Can anyone help me identify the issue or provide a solution to achieve the desired behavior?

html

<div class="slider-item">

            <img src="{% static './assets/images/banner-1.jpg' %}" alt="women's latest fashion sale" class="banner-img">

            <div class="banner-content">

              <p class="banner-subtitle">Trending item</p>

              <h2 class="banner-title">Women's latest fashion sale</h2>

              <p class="banner-text">
                starting at &dollar; <b>20</b>.00
              </p>

              <a href="#" class="banner-btn">Shop now</a>

            </div>

          </div>

          <div class="slider-item">

            <img src="{% static './assets/images/banner-2.jpg' %}" alt="modern sunglasses" class="banner-img">

            <div class="banner-content">

              <p class="banner-subtitle">Trending accessories</p>

              <h2 class="banner-title">Modern sunglasses</h2>

              <p class="banner-text">
                starting at &dollar; <b>15</b>.00
              </p>

              <a href="#" class="banner-btn">Shop now</a>

            </div>

          </div>

          <div class="slider-item">

            <img src="{% static './assets/images/banner-3.jpg' %}" alt="new fashion summer sale" class="banner-img">

            <div class="banner-content">

              <p class="banner-subtitle">Sale Offer</p>

              <h2 class="banner-title">New fashion summer sale</h2>

              <p class="banner-text">
                starting at &dollar; <b>29</b>.99
              </p>

              <a href="#" class="banner-btn">Shop now</a>

            </div>

          </div>

css:

.slider-container {
  display: flex;
  align-items: center;
  gap: 10px;
  border-radius: var(--border-radius-md);
  overflow-x: auto; /* Add this line */
  scroll-snap-type: inline mandatory;
  overscroll-behavior-inline: contain;
}

.slider-item {
  position: relative;
  min-width: 100%;
  max-height: 450px;
  aspect-ratio: 1 / 1;
  border-radius: var(--border-radius-md);
  overflow: hidden;
  scroll-snap-align: start;
}

.slider-item .banner-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: right;
}

Additional details:

  1. I want the slider to automatically scroll to the next item when the user reaches the end of the current item.
  2. I’m not sure if there are any specific browser or device requirements that might be affecting the behavior.

At what point does express-session validates a session?

I am coming from the background of jwt in nodejs. I know that when setting up your jwt using the jwt.sign() method, you also pass in your secret string.
And when you want to verify the jwt when it comes from the client, you use the jwt.verify() method and also provide your secret string. This working is understandable and anyone coding would understand how it works.
I want to use session authentication method for the first time and I have been reading about it.
I can see that when I use express-session, I can setup a session, provide a secret and some cookie settings like this:

app.use(session({
    store: new RedisStore({client: redisClient}),
    secret: sanitizedConfig.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    name: sanitizedConfig.SESSION_NAME,
   cookie:{
    maxAge: 1000 * 60 * 60,
    secure: process.env.NODE_ENV === 'production' ? true: false,
    httpOnly: process.env.NODE_ENV === 'production' ? true : false
   }
}))

And when I want to check if the the user is available, I have seen tutorials ask me to do this via middleware:

const authUser =(req, res, next)=>{
  if(!req.session && !req.session.userId){
   
   return res.status(401).json('Not authenticated)
 }

  next()
}

Then apply the middleware like this in protected routes:
route.post('profile', authUser, profileController);

My question is at what point did express-session help validate the session? I know that I am not heavily familiar with the working system but I would like to know. In jwt, I know that during my middleware authentication, I would use the jwt.verify() method to verify the token. When do we do that in express-session?

Codes provided above

Twitter Media Downloader script. Issue with svg loading button positioning

Full script code —> https://pastecord.com/giqydufyce.js

A function is on the 336 line. Loading SVG supposedly breaks the inherited styles (given the button itself is a cloned node ) and positions itself higher relatively to the nearest element. After the page reload it resets itself to the original position as if nothing happened.
Can’t understand why it’s happening.

button positioning demonstration

Tried applying styles expecting it not to break the layout, but to no avail.

How to Render Content in SSR with a Delayed API Response While Keeping It in the Source Code?

I’m working on a Quasar project where I use preFetch and SSR to render content on my PLP (Product Listing Page). However, one of my APIs (getTours) takes around 30 seconds to respond, causing the page to remain in a loading state (API pending) until the response is received. It’s crucial for me to include the content in the source code of the page for SEO purposes.

Here is a simplified version of my preFetch function:

await Promise.all([
  getTourMetaTag(requestParams),
  getTourFaqs(requestParams),
  getTourContents(requestParams),
  getExchangeRate(),
  getDestinationCities(),
  getTours(), // This API takes 30 seconds to respond
  getHotelNames(),
  getNeighborhoods(),
])
.then(async (results) => {
  const [
    tourMeta,
    tourFaqs,
    tourContents,
    exchangeRate,
    destinationCities,
    tours,
    hotelNames,
    neighborhoods,
  ] = results;
  // Further processing...
});

The getTours API is significantly delaying the page rendering. I want to avoid blocking the page rendering due to this slow API call. Instead, I’d like to:

  1. Render the page with placeholder or skeleton content while the getTours API is still pending.

  2. Ensure that once the getTours response is received, the full content is available in the page’s source code (important for SEO).

Bug of scaling images after changing the transform origin property in CSS

I have set the mouse movement monitoring event, which will change the ‘transform origin’. I will use ‘transform: scale’ to control the zoom of the image. When ‘transform: scale (1,1)’ is like this, there is no problem, but when ‘transform: scale (1.5,1.5)’ or ‘transform: scale (0.5, 0.5)’ is like this, moving the mouse to change the ‘transform origin’ will cause the image to move along with it

var multiple = 1
var max_multiple = 10
var min_multiple = 0.5

function f1() {
    const c = document.getElementById('img')
    c.onmousewheel = function (event) {
        event.preventDefault()
        if (event.wheelDelta > 0) {
            if (multiple < max_multiple) {
                multiple += 0.5
            }
            c.style.transform = 'scale(' + multiple + ',' + multiple + ')'
        } else {
            if (multiple > min_multiple) {
                multiple -= 0.5
            }
            c.style.transform = 'scale(' + multiple + ',' + multiple + ')'
        }
    }
}

function f2() {
    const c = document.getElementById('img')
    c.onmousemove = function (event) {
        c.style.transformOrigin = event.offsetX + 'px' + ' ' + event.offsetY + 'px'
    }
}

f1()
f2()

These are my code snippets

enter image description here

This is the effect of scaling to ‘transform: scale (1,1)’

enter image description here

This is the effect of scaling to ‘transform: scale (1.5,1.5)’

You can see that my image has shifted in position due to the “transform origin”. I know it’s because “transform: scale” changed the scaling factor, but I want to use “transform: scale” to change the scaling factor, and I hope this bug won’t happen again
May I ask if everyone has a good solution

How to unmute iframe stream when loading?

when i load stream with iframe embed tags it is automatically unmutes. Can i specifiy in iframe html code to set up it unmuted when unloading?

<iframe style="width:640px; height:480px;" allowfullscreen src="https://example.com/embed.html"></iframe>

tried to add allow=”unmute;”