CanvasKit Error: Uncaught RuntimeError: index out of bounds

I’m making a animation engine, and it is being replaced and refactored with Canvaskit, I tried to use CanvasKit to load an animation, this is my code:

import { config } from "@newcar/utils";
import type { Canvas, CanvasKit, Paint, Surface } from "canvaskit-wasm";
import CanvasKitInit from "canvaskit-wasm";
import mitt from "mitt";

import type { Scene } from "./scene";

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type CarHookEventMap = {
  "before-frame-update": Car;
  "frame-updated": Car;
};

export class Car {
  private _playing!: boolean;
  private lastUpdateTime!: number;
  // readonly context: CanvasRenderingContext2D;
  readonly canvasKitLoaded = CanvasKitInit({
    locateFile(_file) {
      return config.canvaskitWasmFile;
    },
  });

  canvaskit: CanvasKit;
  paint: Paint;
  surface: Surface;
  events: {
    "ready-to-play": (() => any)[];
  } = {
    "ready-to-play": [],
  };

  readonly hook = mitt<CarHookEventMap>();

  constructor(public element: HTMLCanvasElement, public scene: Scene) {
    this.playing = false;
    this.element.style.backgroundColor = "black";
    // this.context = this.element.getContext("2d")!;
    this.canvasKitLoaded.then((canvaskit) => {
      this.canvaskit = canvaskit;
      this.surface = canvaskit.MakeWebGLCanvasSurface(this.element);
      this.paint = new canvaskit.Paint();
      for (const callback of this.events["ready-to-play"]) {
        callback();
      }
    });
  }

  static update(car: Car): void {
    car.hook.emit("before-frame-update", car);

    let elapsed: number;
    switch (config.timing) {
      case "frame": {
        elapsed = 1;
        break;
      }
      case "second": {
        const currentTimestamp = performance.now();
        const intervalTime = (currentTimestamp - car.lastUpdateTime) / 1000;
        car.lastUpdateTime = currentTimestamp;
        elapsed = intervalTime;
        break;
      }
    }
    car.scene.elapsed += elapsed;
    // car.context.clearRect(0, 0, car.element.width, car.element.height);

    for (const update of car.scene.updates) {
      update(car.scene.elapsed);
    }
    (function f(objects: typeof car.scene.objects) {
      for (const object of objects) {
        object.beforeUpdate(car);
        for (const animation of object.animations) {
          if (animation.elapsed <= animation.duration) {
            animation.elapsed += elapsed;
            animation.animate(
              object,
              animation.elapsed / animation.duration,
              animation.by,
              animation.params ?? {},
            );
          }
        }
        f(object.children);
        object.updated(car);
      }
    })(car.scene.objects);

    try {
      car.surface.drawOnce((canvas: Canvas) => { // The problem is start from this column.
        canvas.clear(car.canvaskit.BLACK);
        for (const object of car.scene.objects) {
          object.update(car.paint, canvas, car.canvaskit);
          object.updated(car);
        }
      });
    } catch (err) {}
    car.hook.emit("frame-updated", car);

    if (car.playing) {
      requestAnimationFrame(() => Car.update(car));
    }
  }

  play(at?: number): this {
    this.playing = true;
    if (typeof at !== "undefined") {
      this.scene.elapsed = at;
    }

    return this;
  }

  stop(at?: number): this {
    this.playing = false;
    if (typeof at !== "undefined") {
      this.scene.elapsed = at;
    }

    return this;
  }

  on(event: "ready-to-play", callback: () => any): this {
    switch (event) {
      case "ready-to-play": {
        this.events[event].push(callback);
        break;
      }
    }

    return this;
  }

  get playing(): boolean {
    return this._playing;
  }

  set playing(playing: boolean) {
    this._playing = playing;
    if (playing) {
      this.lastUpdateTime = performance.now();
      requestAnimationFrame(() => Car.update(this));
    }
  }
}

It erred: Uncaught RuntimeError: index out of bounds

and the browser tips is refering to canvaskit-wasm.js:3787 and the problem seems to be at 92th column, in car.surface.drawOnce (I have signed it in codes, and you can find it in https://github.com/Bug-Duck/newcar/blob/093b14704951d2986ecfe5313f9ae3bec6874f88/packages/core/src/car.ts

I hope the animation could be ran directly.

How to Resolve Y-Axis Gap in ChartJS Line Graph

I have a line graph created using ChartJS that represents the fluctuation in material prices over dates. Most materials have prices ranging from the $200s to $600s.
However, there is one material with a significantly higher price in the $2000s.
(I am currently using Metronic)

Due to this high-priced material, there is a large empty space on the Y-axis.

enter image description here
enter image description here

Is there a way to omit this empty space or perhaps create a secondary Y-axis on the right side of the chart to accommodate the higher price range of this specific material?
I’m looking for a solution to minimize the empty space and effectively represent the chart.
Thank you!

enter image description here

I tried adding the “ticks” option to the Scales, but it didn’t turn out to be the method I was looking for.

matSortHeader does work, is because it is added to async block

anyone has an idea why the mat sort header arrow and sorting number is not showing when I assign sortParams and sortDirs inside an async call which is the getUserData() , I called it inside getUserData because it contains the default sorting params from the API. The sorting works but the arrow and the number is not showing on load.

I try to assign sortData after the component view is already rendered.

But then I try to put for example in ngOnit like this.requestsListTable.sortParams = ['requestTitle', 'requestorName'] the numbers is showing. I also tried adding this.changeDetectorRef.detectChanges(); but it does not solve it either. Ideas would be much appreciated. Thanks.

— it should show the mat sorting arrow like belo

screenshot

#ts code
requestsListTable: TableData;

    constructor(
        public dialog: MatDialog,
        private route: Router,
        private _projectIntakeService: ProjectIntakeService,
        private _notificationService: NotificationService,
        private _storageService: StorageService,
        private _workflowApprovalService : WorkflowApprovalService,
        private _picklistService: PicklistService,
        private _reportService: ReportService,
        private _userService: UserService,
        private changeDetectorRef: ChangeDetectorRef
      ) {
    
        this.requestsListTable = new TableData<any>([]);
    
        this.requestsListTable.pageSize = 10;
        this.requestsListTable.pageIndex = 0;
    
      }
    
    
      ngOnInit(): void {
        this.currAcct = JSON.parse(this._storageService.getCurrAcct());
        this.isProjectTeamData = this.currAcct.isProjectTeamData;
        this.isRequestIntakeReadOnly = this.currAcct.isRequestIntakeReadOnly;
        this.isRequestIntakeSubmitter = this.currAcct.isRequestIntakeSubmitter;
        this.requestsListTable.dataSource = new MatMultiSortTableDataSource(this.sort, this.CLIENT_SIDE);
        this.requestsListTable.nextObservable.subscribe(() => { this.initRequestsList(); });
        this.requestsListTable.sortObservable.subscribe(() => { this.initRequestsList(); });
        this.requestsListTable.previousObservable.subscribe(() => { this.initRequestsList(); });
        this.requestsListTable.sizeObservable.subscribe(() => { this.initRequestsList(); });
    
        
        this.getProjectIntakeDepartments();
        this.getRequestsCount();
        this.checkPageAccess();    
        // setTimeout(() => {
        //   this.requestsListTable.sortParams = ['requestTitle', 'requestorName']
        //   this.requestsListTable.sortDirs = ['asc', 'asc'];
    
        // }, 2000)
      }
    
      ngAfterViewInit(): void {
        fromEvent<any>(this.searchInput.nativeElement, 'keyup')
          .pipe(
            map(event => event.target.value.trim()),
            startWith(''),
            debounceTime(500),
            distinctUntilChanged(),
            tap(search => {
              if (search) {
                this.requestsListTable.pageIndex =  0;
              }
              this.setDefaultFilters();
            }),
            switchMap(search => {``
              return this.filtersSubject.pipe(
                tap(() => {
                  this.getUserData();
                })
              );
            })
          )
          .subscribe({
            next: () => {
            },
            error: (err) => console.error(err),
            complete: () => noop
          });
      }
    
      initRequestsList() {
        console.log("12")
        const currAcct = JSON.parse(this._storageService.getCurrAcct());
    
        const sortKey = (this.requestsListTable.sortParams.length > 0) ? this.requestsListTable.sortParams : ['requestTitle'];
        const sortOrder = (this.requestsListTable.sortDirs.length > 0) ? this.requestsListTable.sortDirs : ['asc'];
    
        const isMyRequests = (this.selectedOption === '1') ? currAcct.userId : null;
        
        this.isLoading = true;  
    
        this._projectIntakeService
          .getRequestsList(
            currAcct.accountId,
            isMyRequests,
            this.requestsListTable.sortParams,
            this.requestsListTable.sortDirs,
            this.searchInput.nativeElement.value || '',
            this.requestsListTable.pageIndex + 1,
            this.requestsListTable.pageSize,
            this.selectedDepartmentIds,
            this.selectedStatusIds
          )
          .pipe(finalize(() => (this.isLoading = false)))
          .subscribe({
            error: (err) => this._notificationService.showError(err),
            next: (res) => {
              this.firstItemPosition = res.firstItemOnPage;
              this.lastItemPosition = res.lastItemOnPage;
              this.dataSource = res.items;
              this.requestsListTable.data = res.items;
              this.lastItemOnPage = res.lastItemOnPage;
              this.totalItemCount = res.totalItemCount;
            },
            complete: _.noop,
          });
      }

getUserData() {
    this._userService.getUserProfile(this.currAcct.userId, this.currAcct.accountId)
      .subscribe(
        res => {
          if (res.isSuccess) {
            const filteredAccounts = this.filterAccountsByName(res.data.userAccountDto, this.currAcct.accountName);
            this.projectIntakeSettings = JSON.parse(filteredAccounts[0].projectIntakeSettings);

            if (this.projectIntakeSettings) {
              
               //request type  
                this.selectedOption = (this.projectIntakeSettings.UserId) ? '1' : '2';

                
                // Check if sortKey and sortOrder are provided in projectIntakeSettings
                const sortKey = this.projectIntakeSettings.SortKey ? JSON.parse(this.projectIntakeSettings.SortKey) : ['requestTitle'];
                const sortOrder = this.projectIntakeSettings.SortOrder ? JSON.parse(this.projectIntakeSettings.SortOrder) : ['asc'];

                // console.log('this.requestsListTable', this.requestsListTable)
                // Assign sortParams and sortDirs
                this.requestsListTable.sortParams = sortKey;
                this.requestsListTable.sortDirs = sortOrder;

                //page
                this.requestsListTable.pageIndex = (this.projectIntakeSettings.Page) ? this.projectIntakeSettings.Page - 1 : 0
                this.requestsListTable.pageSize = (this.projectIntakeSettings.PageSize) ? this.projectIntakeSettings.PageSize : 10;

                this.changeDetectorRef.detectChanges();

                this.initRequestsList();


            }

          }
        },
        err => {
          AppUtils.errorHandler(err, this._notificationService, null);
        }
      )

  }

#html code

<table
                      mat-table
                      [dataSource]="requestsListTable.dataSource"
                      matMultiSort
                      [@animateStagger]="{value:'50'}"
                      (matSortChange)="requestsListTable.onSortEvent()"  
                     >

                    <ng-container matColumnDef="requestTitle" sticky>
                      <th mat-multi-sort-header="requestTitle" mat-header-cell *matHeaderCellDef>Request Title</th>
                      <td mat-cell *matCellDef="let element">
                        <div class="checkbox-container td-value-name">
                          <mat-checkbox matTooltip="{{ isNotAllowedBulk(element) ? 'Unable to batch approve' : '' }}"
                            [checked]="isSelected(element)" [disabled]="isNotAllowedBulk(element)" class="no-navigation"
                            color="primary" (change)="onChangeSelect(element, $event, 'request')"></mat-checkbox>
                          <div style="width:180px;" [matTooltip]="element.requestTitle" class="td-value-name request-title">{{
                            element.requestTitle?.length > 45 ? element.requestTitle.slice(0,45) + '...' : element.requestTitle }}</div>
                        </div>
                      </td>
                    </ng-container>

                    <ng-container matColumnDef="requestorName">
                      <th mat-multi-sort-header="requestorName" mat-header-cell *matHeaderCellDef>Requestor Name</th>
                      <td mat-cell *matCellDef="let element">
                        <div class="td-value-name">
                          {{element.requestorName}}
                        </div>
                      </td>
                    </ng-container>

Could not add entry to cache (/Users/android/.gradle/7.5.1/checksums/sha1-checksums.bin). > java.io.IOException: Bad file descriptor

I was getting these 2 errors while running my react native project.

  • What went wrong:
    Could not add entry ‘/Users/saadafridi/.gradle/.tmp/gradle_download14928641310389655157bin’ to cache sha1-checksums.bin (/Users/saadafridi/Desktop/mobileapp/android/.gradle/7.5.1/checksums/sha1-checksums.bin).

java.io.IOException: Bad file descriptor

FAILURE: Build failed with an exception.

  • What went wrong:
    Gradle could not start your build.

Could not create service of type ChecksumService using BuildSessionScopeServices.createChecksumService().
Cannot lock checksums cache (/Users/saadafridi/Desktop/mobileapp/android/.gradle/7.5.1/checksums) as it has already been locked by this process.

I ran the following 2 cmds.

  1. yarn android

  2. cd android –> ./gradlew clean

legacy jquery datatables sort on Australian date format

According to the jQuery Datatables docs, the sType parameter which is used to define the sorting behaviour of a column:

… allows you to specify how the data for this column will be
sorted. Four types (string, numeric, date and html (which will strip
HTML tags before sorting)) are currently available. Note that only
date formats understood by Javascript’s Date() object will be accepted
as type date. For example: “Mar 26, 2008 5:03 PM”. May take the
values: ‘string’, ‘numeric’, ‘date’ or ‘html’ (by default). Further
types can be adding through plug-ins.

However, when values in the columns are of the format dd/MMM/yyyy (eg <td>08/Mar/2024</td>), the column does not sort properly.

Javascript definitely understands 08/Mar/2024 as being a valid date:

new Date("08/Mar/2024");
Fri Mar 08 2024 00:00:00 GMT+1100 (Australian Eastern Daylight Time)

So what exactly can i do to sort it using Australian date format?

How can I reduce the download time of a Javascript fetch request?

I am having trouble with long fetch requests that slow down my code. I am trying to build a google chrome extension that works on top of www.amazon.com and includes fetch requests to other amazon product pages (after scraping them from the DOM model of the current page). My code works, but it is slow, with each requets taking 2.5-3 seconds, and the sum of requets often taking up to 10. Here is the Network Request. As seen in the network request, a vast majority of this time is download for the fetch, which takes ~2 seconds, even though the html to be downloaded is not all that large. Are there any good ways to speed this process up?

I have tried looking into whether I could compress the files from my fetch command, but this was already done automatically by Amazon and did not improve my speed. I have also tried seeing if I could find a way to only get a selective portion of the html I’m trying to fetch, but haven’t had any success.

Thanks for any advice!

How to put signature to an existing pdf using JS

I’ve been working on placing a signature in a specific location within a PDF, such as next to the word ‘Signature’ at the top. If I want to achieve this, how can I do it using HTML, CSS, JavaScript, or any frameworks like React or Svelte?

We have a PDF with forms that may or may not be filled. The PDF includes a designated area for the signature, and we need to insert the signature accordingly. This is the task I need to accomplish. How can I do it?

thank you.

i tried some libraries like signature-pad to create signature. but couldn’t put it to existing pdf. but with the help of JSPDF i could create a pdf. which is not i want.

Make asynchronies execution

      const convert = async(value) => setTimeout(() => value.split('').reverse().join(''), 100) 

const data = {
        result: [
            {
                "test 1": [
                   { number : "12356789"},
                   { number : "12356789"}
                ],
                "test 2": [
                    {number: "12356789"}
                ],
                "test 3": [
                    {number: "12356789"}
                ]
            },
            {
                total: {
                    records: 3
                }
            }
        ]
    }

How do i convert each number value using async convert function ?

Tried with forEach with multiple loop, but did not work. So logic should be synchronies. any suggestion much appreciate.

Page Object Model in playwright typscript gets Linting Error of Parsing error: Unexpected token

I’m new to playwright and I was doing page object model using typescript. The script is working fine unless when running check for linting. In github, linting is part of Pull Request Check so it is failing there.

This is my login page where it fails on linting check

import { Page } from "@playwright/test";

export class LoginPage {
    readonly page: Page;
    readonly userName: any;
    readonly password: any;
    readonly loginButton: any;

    constructor(page: Page) {
        this.page = page;
        this.userName = this.page.locator('[data-qa="login-input-email"]');
        this.password = this.page.locator('[data-qa="login-input-password"]');
        this.loginButton = this.page.locator('[data-qa="login-button"]');
    }

    /**
     * @param {string} text
     */
    async enterUsername(text) {
        await this.userName.fill(text);
    }

    /**
     * @param {string} text
     */
    async enterPassword(text) {
        await this.password.fill(text);
    }

    async clickLoginBtn() {
        await this.loginButton.click();
    }
}

And when running the lint command below in the terminal

npx eslint “./src/**” –cache

This is the error it is getting

C:UserspathDesktoppathWorkspacepathpathsrcportallocatorscommonCommonPage.ts
5:13 error Parsing error: Unexpected token (5:13)

This is the content of .eslintrc.js

module.exports = {
    "env": {
        "es2021": true,
        "node": true
    },

    "extends": "eslint:recommended",
    "overrides": [
        {
            "env": {
            "node": true
        },
        "files": [
            ".eslintrc.{js,cjs}"
        ],
        "parserOptions": {
            "sourceType": "script",
            }
        }
    ],
    "parser": "@babel/eslint-parser",
    "parserOptions": {
    "requireConfigFile": false,
    "ecmaVersion": 2020,
    "sourceType": "module",
    "babelOptions": {
          "babelrc": false,
          "configFile": false
        },
    },
    "rules": {
    }
}

Does anyone has an idea on this? Thank you

How do I prevent image clipping from enlarging images?

I’ve been trying to create a gallery where clicking an image would enlarge it, and clicking it again reverts it back to its original size. as of right now, enlarging an image will clip into subsequent images if those images have also been clicked on.

This is my html

<table>
        <tr>
            <th>Source of Image</th>
            
        </tr>
        <tr>
            <th>Need For Speed Heat</th>
            <div id="enlarge">
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img1)" onclick="focusImg()" id="img1"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img2)" onclick="focusImg()" id="img2"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img3)" onclick="focusImg()" id="img3"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img4)" onclick="focusImg()" id="img4"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img5)" onclick="focusImg()" id="img5"></td>
        </div>
        </tr>
        <tr>
            <th>Reality</th>
            <div id="enlarge">
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img6)" onclick="ensmallImg()" id="img6"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img7)" onclick="ensmallImg()" id="img7"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img8)" onclick="ensmallImg()" id="img8"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img9)" onclick="ensmallImg()" id="img9"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img10)" onclick="ensmallImg()" id="img10"></td>
        </div>
        </tr>
        <tr>
            <th>Sketches</th>
            <div id="enlarge">
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img11)" onclick="focusImg()" id="img11"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img12)" onclick="ensmallImg()" id="img12"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img13)" onclick="ensmallImg()" id="img13"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img14)" onclick="ensmallImg()" id="img14"></td>
            <td><img src="images/0016.jpg" alt="" width="100%" onclick="toggleEnlargeImg(img15)" onclick="ensmallImg()" id="img15"></td>
        </div>
        </tr>
       </table>

This is my javascript

let enlarged=0;
        function toggleEnlargeImg(img) {
     if (enlarged===0){
        document.getElementById("enlarge").style.zIndex = "999";
        img.style.transform = "scale(2.5)";
       img.style.transition =
       "transform 0.25s ease";
       enlarged = 1;
     }
     else{
        document.getElementById("enlarge").style.zIndex = "1";
       img.style.transform = "scale(1)";
       img.style.transition =
       "transform 0.25s ease";
       enlarged = 0;
     }
     return enlarged;
  }

I tried to use zindex to forcefully change the layering but it doesn’t work. Any help would be greatly appreciated as I’m still very new to this.

I tried to use zindex to forcefully change the layering but it doesn’t work. I think a if else statement is probably the key to fixing this but I’m not sure how to implement it(that’s what the ensmalling in my html was supposed to be for). Any help would be greatly appreciated as I’m still very new to this.

How can I mock a function in jest?

I’m trying to mock an api call inside a function here using jest. The idea is not to call the api, instead just mock the call, return some data and do the assert. It doesn’t seem to work in the way I wanted. I looked at jest documentation for hours and still couldn’t come to a conclusion.

const apiFunction = async () => {
    try {
      const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
      return response.data;
    } catch (error) {
      console.error("Failed to fetch data: ", error.response || error);
      return [];
    }
  }

  const dependencyFunction = async () => {
    const data = await apiFunction();
    return data;
  }

Test

import { dependencyFunction } from '../tests/utils';
import * as utils from '../tests/utils';

afterEach(() => {
  jest.restoreAllMocks();
});

jest.mock('../tests/utils', () => ({
  ...jest.requireActual('../tests/utils'),
  apiFunction: jest.fn().mockResolvedValue(['data1', 'data2']),
}));


describe('dependency function', () => {
  it('should call apiFunction and return its results', async () => {
    const mockFunction = jest.spyOn(utils, 'apiFunction').mockResolvedValue(['data1', 'data2']);

    const result = await utils.dependencyFunction();

    expect(mockFunction).toHaveBeenCalled();
    expect(result).toEqual(['data1', 'data2']);
  });
});

My test is broken with the error Expected number of calls: >= 1 Received number of calls: 0. I’m bit confused here. Any help would be greatly appreciated.

How to wrap a function (method) with try-catch in modern javascript using decorators (native)?

how can I do something like:

class LambdaFunctionExample {

  lambdaResponse = [1, 2 , 3]

  @tryCatchWrapper
  async handler(event) {
    const data = this.lambdaResponse;
    const result = await fetch(...)

    return {
      statusCode: 200,
      data,
      result
    };
  }

}

and catch errors/events for POC purposes.

this.value always comes back undefined – React

I am working on adding a value to localstorage with an Onclick event. It is supposed to take the innerHTML from the button and put the value into the local storage as the “Cemetery” value.

I have tried multiple different ways of getting the value but I keep getting undefined. If you could give me a hand and some pointers, that would be great!

const CemeteryPage = () => {
 
  
function setCemetery(ListItem) {
  
    localStorage.setItem("Cemetery", ListItem.value)

 

}
  return (
    <>
    <div className='Header'>
        <h1>What <span>cemetery</span> is this stone going to?</h1>
       <div className='Line'></div>
    </div>
     <div class="CemeteryList">
        <div className="ListItem" onClick={function(){setCemetery(this)}}>
        St Anthony's Cemetery
        </div>
        <div className="ListItem" onClick={function(){setCemetery(this)}}>
       Hillside Cemetery
        </div>
      </div>
        
    </>
  )
}

I tried using .getAttribute, .attributes[], I tried adding a value attribute and pulling it from there but still got undefined.

Moving a SVG along another SVG with Javascript

I’m encountering some difficulties in creating an animation to move an SVG element along SVG element when clicked (using the onclick event) using JavaScript.
That’s mean, i have a road and i want to my character move one this road.
Specifically, I want the SVG element with the id ‘main-character’ to move along the path with the id ‘global-main-path’.
Here is my code, including CSS and HTML.

Character
HTML

<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
  <g clip-path="url(#clip0_72_161)">
    <path d="M18.6686 25.3457C16.9206 21.0107 12.0961 17.235 8.04079 16.9903C2.0976 16.6757 -1.32848 11.7463 0.489442 5.62833C2.9716 6.88689 5.34887 10.9422 8.14567 8.14544C10.8376 5.41857 7.37655 3.00633 5.66351 0.803856C10.3481 -1.36366 16.4312 0.978656 16.5361 5.94297C16.7109 12.7951 21.5004 15.6618 25.3809 19.5773C25.4159 20.5912 25.9403 21.1156 26.9541 21.1505C29.5761 23.8425 32.1632 26.5344 34.7851 29.2263C35.4843 29.9255 36.1486 30.5198 37.3023 30.38C43.1755 29.6458 46.1821 32.967 48.0699 37.9313V41.2875C46.7065 41.8818 45.6577 41.3574 44.8536 40.2387C43.2455 38.1061 40.7983 37.5118 39.1202 39.2598C37.7218 40.7281 38.1413 43.2452 40.2389 44.6786C42.4763 46.2168 41.008 47.0908 39.6795 47.9998H36.3234C32.6875 45.0981 30.555 41.9517 30.0306 36.7427C29.646 32.932 25.311 29.6808 21.1857 27.7929H21.2556C21.2556 27.5133 21.2556 27.1986 21.2906 26.884C20.976 26.884 20.6613 26.884 20.3467 26.9189L20.4166 26.9889C20.4166 26.6742 20.4166 26.3596 20.4516 26.0449C20.1369 26.0449 19.8223 26.0449 19.5077 26.0799L19.5776 26.1498C19.5776 25.8352 19.5776 25.5205 19.6125 25.2059C19.2979 25.2059 18.9833 25.2059 18.6686 25.2409H18.7036L18.6686 25.3457Z" fill="url(#paint0_radial_72_161)"/>
    <path d="M21.1158 27.828C20.941 29.576 19.9622 31.2891 21.9199 32.8623C22.9687 33.7013 21.6752 34.5753 21.0459 35.2395C17.8995 38.4209 14.7881 41.6372 11.5018 44.6787C8.56521 47.4056 4.6497 47.3357 2.09762 44.7486C-0.524371 42.0917 -0.559331 38.3859 2.2025 35.3444C4.37002 32.9671 6.60746 30.6598 9.05465 28.5622C10.9775 26.8841 12.3409 22.6889 16.1515 26.3248C16.4312 26.5695 17.7946 25.6955 18.6686 25.3459L18.6337 25.3109C18.354 26.1849 18.6337 26.4996 19.5426 26.2199L19.4727 26.15C19.193 27.024 19.4727 27.3386 20.3817 27.0589L20.3118 26.989C20.0321 27.863 20.3118 28.1776 21.2207 27.8979H21.1508L21.1158 27.828ZM9.57905 40.6583C9.85873 40.3786 10.1384 40.099 10.4181 39.8193C10.6978 39.5396 10.9775 39.2599 11.2571 38.9803C11.5368 38.7006 11.8165 38.4209 12.0962 38.1412L12.9352 37.3022C13.2149 37.0225 13.4946 36.7428 13.7742 36.4631C14.0539 36.1835 14.3336 35.9038 14.6133 35.6241C15.2426 35.3444 15.9767 34.6452 15.5222 34.1907C14.7182 33.3867 14.1938 34.4005 13.7043 34.9948C13.4246 35.2745 13.145 35.5542 12.8653 35.8339C12.5856 36.1135 12.3059 36.3932 12.0262 36.6729C11.7466 36.9526 11.4669 37.2323 11.1872 37.5119C10.9075 37.7916 10.6279 38.0713 10.3482 38.351C10.0685 38.6307 9.78881 38.9103 9.50913 39.19C9.22945 39.4697 8.94977 39.7843 8.63513 40.064C8.39041 40.1689 8.21561 40.3437 8.14569 40.5884C7.72618 40.973 6.81722 41.2876 7.30666 41.9518C7.83106 42.651 8.39041 42.1266 8.74001 41.4974C9.01969 41.2177 9.29937 40.938 9.57905 40.6583ZM7.23674 37.8266C7.51642 37.5469 7.83106 37.2672 8.11073 36.9526C8.39041 36.6729 8.67009 36.3932 8.94977 36.1135C9.22945 35.8339 9.50913 35.5542 9.78881 35.2745C10.0685 34.9948 10.3482 34.7151 10.6279 34.4355C10.9075 34.1558 11.1872 33.8761 11.4669 33.5964C12.0612 32.9671 13.5295 32.5127 12.5506 31.4988C11.9563 30.9045 11.2571 31.9883 10.8376 32.6875C10.5579 32.9671 10.2783 33.2468 9.99857 33.5265C9.71889 33.8062 9.43921 34.0859 9.15953 34.3655C8.87985 34.6452 8.60017 34.9249 8.32049 35.2046C8.04082 35.4843 7.76114 35.7639 7.48146 36.0436C7.20178 36.3233 6.9221 36.603 6.64242 36.8827C6.36274 37.1623 6.08306 37.442 5.80338 37.7217C5.10418 38.1063 4.05538 38.8055 4.6497 39.3648C5.62858 40.2738 6.15298 38.9453 6.71234 38.2811C6.95706 38.1762 7.0969 38.0363 7.20178 37.7916L7.23674 37.8266Z" fill="url(#paint1_radial_72_161)"/>
    <path d="M26.0102 19.4024C25.9752 18.843 25.6606 18.004 25.9053 17.7942C31.1843 13.2494 33.9461 6.32736 40.134 2.65657C40.973 2.16713 41.847 1.57281 42.6511 2.65657C43.4202 3.70537 45.378 4.33465 44.6788 5.94281C43.8048 7.93552 42.791 10.6274 41.1129 11.3616C36.8128 13.2844 34.0859 16.7454 31.0444 19.8918C29.6111 21.3951 28.4574 20.7658 27.059 20.4861C26.7094 20.1365 26.3598 19.7869 26.0102 19.4373V19.4024Z" fill="url(#paint2_radial_72_161)"/>
    <path d="M26.0102 19.4028C26.3598 19.7524 26.7094 20.102 27.059 20.4516C27.0939 20.6963 27.059 20.941 26.8842 21.1508C25.8703 21.1158 25.3459 20.5914 25.311 19.5776C25.5207 19.4028 25.7305 19.3678 26.0102 19.4028Z" fill="url(#paint3_radial_72_161)"/>
  </g>
  <defs>
    <radialGradient id="paint0_radial_72_161" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(24.0357 23.9946) scale(18.4275 43.9139)">
      <stop offset="0.23" stop-color="#BE3538"/>
      <stop offset="0.32" stop-color="#B7333A"/>
      <stop offset="0.44" stop-color="#A63041"/>
      <stop offset="0.58" stop-color="#8A2A4D"/>
      <stop offset="0.73" stop-color="#63235D"/>
      <stop offset="0.89" stop-color="#321971"/>
      <stop offset="1" stop-color="#0B1282"/>
    </radialGradient>
    <radialGradient id="paint1_radial_72_161" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(11.2237 35.7945) scale(8.50498 19.9617)">
      <stop offset="0.23" stop-color="#BE3538"/>
      <stop offset="0.32" stop-color="#B7333A"/>
      <stop offset="0.44" stop-color="#A63041"/>
      <stop offset="0.58" stop-color="#8A2A4D"/>
      <stop offset="0.73" stop-color="#63235D"/>
      <stop offset="0.89" stop-color="#321971"/>
      <stop offset="1" stop-color="#0B1282"/>
    </radialGradient>
    <radialGradient id="paint2_radial_72_161" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(35.32 11.4513) scale(7.28932 17.2075)">
      <stop offset="0.23" stop-color="#BE3538"/>
      <stop offset="0.32" stop-color="#B7333A"/>
      <stop offset="0.44" stop-color="#A63041"/>
      <stop offset="0.58" stop-color="#8A2A4D"/>
      <stop offset="0.73" stop-color="#63235D"/>
      <stop offset="0.89" stop-color="#321971"/>
      <stop offset="1" stop-color="#0B1282"/>
    </radialGradient>
    <radialGradient id="paint3_radial_72_161" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(26.1911 20.2706) scale(0.674784 1.61015)">
      <stop offset="0.23" stop-color="#BE3538"/>
      <stop offset="0.32" stop-color="#B7333A"/>
      <stop offset="0.44" stop-color="#A63041"/>
      <stop offset="0.58" stop-color="#8A2A4D"/>
      <stop offset="0.73" stop-color="#63235D"/>
      <stop offset="0.89" stop-color="#321971"/>
      <stop offset="1" stop-color="#0B1282"/>
    </radialGradient>
    <clipPath id="clip0_72_161">
      <rect width="48" height="48" fill="white"/>
    </clipPath>
  </defs>
</svg>

CSS


#welcome-scr #main-character {
    display: block;
    position: absolute;
    top: 336px;
    left: 755px;
    transition: 2s ease-in-out;
    z-index: 2;
}

and the SVG

 <div class="global-road">
            <svg width="829" height="317" viewBox="0 0 829 317" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path
                    d="M822.194 21.8311C822.194 21.8311 735.075 131.366 620.751 177.866C517.807 219.737 399.411 179.597 276.197 242.257C97.7668 332.997 -17.9017 299.821 -17.9017 299.821"
                    stroke="#1A3D96" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" />
                <path
                    d="M827.976 27.0832C827.976 27.0832 744.117 142.302 629.793 188.802C526.85 230.672 408.454 190.532 285.24 253.193C106.81 343.933 -17.7849 308.836 -17.7849 308.836"
                    stroke="#1A3D96" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" />
                <path id="global-main-path"
                    d="M802.552 21.9653C802.552 21.9653 719.654 105.689 605.33 152.188C502.386 194.059 382.28 135.33 259.066 197.99C80.6355 288.73 -25.9762 239.894 -25.9762 239.894"
                    stroke="#1A3D96" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"
                    stroke-dasharray="20 20" />
                <path
                    d="M803.042 1.49833C803.042 1.49833 711.487 89.9355 593.518 126.206C487.293 158.865 372.884 108.473 244.639 160.06C58.9224 234.764 -46.4897 191.919 -46.4897 191.919"
                    stroke="#1A3D96" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round" />
            </svg>
        </div>

and CSS

#welcome-scr .global-road {
    position: absolute;
    left: 0;
    top: 555px;
}

Hope you understand my terrible grammar.
Thanks for reading!!!

Janus-gateway “join” http call return “ack” only

I am new to Janus with javascript, I have a room like this:

{
    "janus": "success",
    "session_id": 266646464364358,
    "transaction": "MUcPg6Wu5jhr",
    "sender": 4377145860586972,
    "plugindata": {
        "plugin": "janus.plugin.videoroom",
        "data": {
            "videoroom": "success",
            "list": [
                {
                    "room": 11,
                    "description": "Room 11",
                    "pin_required": false,
                    "is_private": false,
                    "max_publishers": 3,
                    "bitrate": 0,
                    "fir_freq": 0,
                    "require_pvtid": false,
                    "require_e2ee": false,
                    "dummy_publisher": false,
                    "notify_joining": false,
                    "audiocodec": "opus",
                    "videocodec": "vp8",
                    "opus_fec": true,
                    "record": false,
                    "lock_record": false,
                    "num_participants": 0,
                    "audiolevel_ext": true,
                    "audiolevel_event": false,
                    "videoorient_ext": true,
                    "playoutdelay_ext": true,
                    "transport_wide_cc_ext": true
                }
            ]
        }
    }

THen I using join request with body like this:

join params {
  janus: 'message',
  plugin: 'janus.plugin.videoroom',
  session_id: 8568607942621781,
  handle_id: 3267543887867048,
  transaction: 'VeENHRbBTHWI',
  body: { request: 'join', room: 11, ptype: 'publisher', display: 'test' }
}

But the response is ack only, I dont know why it’s not return joined event, can someone help?

{
    "janus": "ack",
    "session_id": 8568607942621781,
    "transaction": "VeENHRbBTHWI"
}

Note that after this, I checked the participants inside room but it’s still empty:

{
    "janus": "success",
    "session_id": 4397550774641519,
    "transaction": "h8LgvUJxVXGk",
    "sender": 8580331991428173,
    "plugindata": {
        "plugin": "janus.plugin.videoroom",
        "data": {
            "videoroom": "participants",
            "room": 11,
            "participants": []
        }
    }
}

All my https call work nomally(such as create video room/ destroy, listroom, list participants,…) but only joinroom api have trouble, here is my javascript code:

joinRoom = async(options) => {
        await this.ensureAttachedToSessionId()
        const promise = new Promise((resolve, reject) => {
            const params = {
                janus: 'message',
                plugin: this.plugin,
                session_id: this.sessionID,
                handle_id: this.handleID,
                transaction: JanusUtils.randomString(12),
                body: {
                    request: 'join',
                    ...options
                }
            }
            console.log('join params', params)
            fetch(this.janusUrl, {
                method: 'POST',
                body: JSON.stringify(params),
                ...JanusUtils.defaultHeader()
            }).then(result => result.json())
            .then(result => {
                resolve(result) 
            })
            .catch(error => { reject(error) })
        })
        return promise
    }