What steps do I need to take to enable zooming on scroll in Angular using Konva?

After spending days trying to figure out how to implement zoom functionality in Konva for my Angular app, I finally found a solution. On my html page, I have multiple ko-image tags with different [config]. My goal is to enable zoom in and zoom out actions using the wheel event on the ko-stage.

Here's a snippet from my HTML file:

<ko-stage  [config]="configStage" >
    <ko-layer >
      <ko-image [config]="configImage[0]"> </ko-image>
      <ko-image [config]="configImage[1]"> </ko-image>
      <ko-image [config]="configImage[2]"> </ko-image>
      <ko-image [config]="configImage[3]"> </ko-image>
      <ko-image [config]="configImage[4]"> </ko-image>
    </ko-layer>
</ko-stage>

In my TypeScript file, I define the configurations for each Konva component:

import { Component, OnInit, EventEmitter } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { Observable, of, config } from 'rxjs';

// declare window to remove typescript warning
interface Window {
  Image: any;
}
declare const window: Window;

@Component({
  selector: 'app-konva',
  templateUrl: './konva.component.html',
  styleUrls: ['./konva.component.css']
})
export class KonvaComponent implements OnInit {

  public count:number = 0;

  stageScale:number = 1;
  stageX:number = 0;
  stageY:number = 0;

  public configStage: Observable<any> = of({
    width: 700,
    height: 1000,
    scaleX:this.stageScale,
    scaleY:this.stageScale,
    x:this.stageX,
    y:this.stageY
  });

  public configImage:Array<EventEmitter<any>> = new Array<EventEmitter<any>>();

  constructor(private route: ActivatedRoute) { }

  showImage(src: string,x: number,y: number,id:number) {  
    const image = new window.Image();
    image.src = src;
    image.onload = () => {
      this.configImage[id].emit({
        image: image,
        width:100,
        height:100,
        x:x,
        y:y
      })
    }
  }

   change(){
     console.log(this.count);
     if(this.count == 0)
     this.showImage("../../assets/static/photos/star.png",20,30,1);
     if(this.count == 1)
     this.showImage("../../assets/static/photos/maps.png",120,30,2);
     if(this.count == 2)
     this.showImage("../../assets/static/photos/pass_icon.png",60,0,3);
     if(this.count == 3)
     this.showImage("../../assets/static/photos/user_icon.png",80,130,4);
     this.count++;
   }

  ngOnInit() {
    this.configImage.push(new EventEmitter<any>());
    this.configImage.push(new EventEmitter<any>());
    this.configImage.push(new EventEmitter<any>());
    this.configImage.push(new EventEmitter<any>());
    this.configImage.push(new EventEmitter<any>());

    this.showImage("../../assets/static/photos/fb.png",50,150,0);
  }
}

Answer №1

Here is the solution for Angular:

import { Component, OnInit, EventEmitter } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { Observable, of, config, BehaviorSubject } from 'rxjs';

// declare window to remove typescript warning
interface Window {
  Image: any;
}
declare const window: Window;

@Component({
  selector: 'app-konva',
  templateUrl: './konva.component.html',
  styleUrls: ['./konva.component.css']
})
export class KonvaComponent implements OnInit {

  public count:number = 0;

  stageScale:number = 1;
  stageX:number = 1;
  stageY:number = 1;

  public configStage= new BehaviorSubject({
      width: 700,
      height: 1000,
      scaleX:this.stageScale,
      scaleY:this.stageScale,
      x:this.stageX,
      y:this.stageY
  });

  public configImage:Array<EventEmitter<any>> = new Array<EventEmitter<any>>();

  constructor(private route: ActivatedRoute) { }

  showImage(src: string,x: number,y: number,id:number) {  
    const image = new window.Image();
    image.src = src;
    image.onload = () => {
      this.configImage[id].emit({
        image: image,
        width:100,
        height:100,
        x:x,
        y:y
      })
    }
  }

   change(){
     console.log(this.count);
     if(this.count == 0)
     this.showImage("../../assets/static/photos/star.png",20,30,1);
     if(this.count == 1)
     this.showImage("../../assets/static/photos/maps.png",120,30,2);
     if(this.count == 2)
     this.showImage("../../assets/static/photos/pass_icon.png",60,0,3);
     if(this.count == 3)
     this.showImage("../../assets/static/photos/user_icon.png",80,130,4);
     this.count++;
   }

  test(e){
    e.preventDefault();
    console.log(e.pageX);

    const scaleBy = 1.02;
    const oldScale =this.stageScale
    const mousePointTo = {
      x: e.layerX / oldScale - this.stageX / oldScale,
      y: e.layerY / oldScale - this.stageY / oldScale
    };

    const newScale = e.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy;


    this.stageScale = newScale;


    this.stageX = -(mousePointTo.x - e.layerX / newScale) * newScale;
    this.stageY = -(mousePointTo.y - e.layerY / newScale) * newScale;

    this.configStage.next({
      width: 700,
      height: 1000,
      scaleX:this.stageScale,
      scaleY:this.stageScale,
      x:this.stageX,
      y:this.stageY
    });

    console.log(this.stageScale);

  }

  ngOnInit() {
    this.configImage.push(new EventEmitter<any>());
    this.configImage.push(new EventEmitter<any>());
    this.configImage.push(new EventEmitter<any>());
    this.configImage.push(new EventEmitter<any>());
    this.configImage.push(new EventEmitter<any>());

    this.showImage("../../assets/static/photos/fb.png",50,150,0);
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using Ajax script to transfer user information to a php file in order to refresh the modified row in a table

Recently, I created a table in PHP to display certain data. Here's how it looks: <?php echo '<table id="tableteste" class="table table-striped" width="100%">'; echo '<thead><tr>'; echo &apos ...

Modify the variable value only in React when the state undergoes a change

I'm facing a situation where I need to reset the stocksHelper class and instantiate it again whenever the component renders based on a change in the stocks' useState. This is essential because upon a change in stocks, a calculation needs to be pe ...

Automatic cancellation of AJAX request

Having a strange issue that I need help with. I am using a standard ajax call to upload avatars from the user's PC to the server. However, sometimes I notice in Firebug that the request is being "Aborted" and marked in red after loading for some time ...

Steps to create a conditional AJAX request triggered by the onbeforeload event depending on the value of a variable

My website script tracks user login status in real time using "onbeforeunload", ajax, and logout.php. This method updates the MySQL database with a value of 1 or 0 to indicate if a user is logged in. Unlike monitoring cookies, this approach allows accurate ...

establish a connection with the node server and initiate the automatic mask detection feature

Here's my issue: I have a node server running a game I'm developing. The server listens on an IP address in the network, such as 192.168.x.x (which can vary). The game "frontend" is a web page hosted on a domain (like paperplane.io) that links ...

The comparison of jQuery objects consistently returns false

Am I doing something wrong? I have searched Google and many sources suggest that using == is sufficient. However, when I execute the following code: <body> <button id="A" type="button>A</button> </body> <script> $(document ...

Modifying website elements with JavaScript

Can someone assist me with getting a script to work on my website that will allow me to switch between four different sets of content using buttons labeled 1, 2, 3, and 4? I have tried using addClass and removeClass but cannot seem to get it right. Here i ...

jQuery - Uh-oh! Looks like there is a syntax error and the

I encountered an issue with my fiddle where I am getting an error message. Any suggestions on how to effectively handle decimals and spaces within the code, specifically when using .split and join() functions, without causing an unrecognized expression e ...

The button is not activating the callback function when clicked. It is unclear why this is happening as no errors are being displayed in the console

Utilizing an event listener on the button element, the user is prompted to select a language first. Upon selection, the button in question is presented to them. Clicking on this button triggers a callback function that allows the user to begin the quiz. Ev ...

Setting up Jest for seamless compatibility with all imports

I'm new to using Jest and I'm struggling to set it up to work with files that have web app, expo, and multiple imports. Error: AIL screens/hiveInspection/HiveHealth.test.js ● Test suite failed to run Jest encountered an unexpected token Thi ...

What is causing the geolocation heading to remain "null" on Android devices when using Chrome?

Recently, I developed a compact geolocation watch using the following code snippet: navigator.geolocation.watchPosition( this.updateLocation.bind(this), this.errorLocation.bind(this), {enableHighAccuracy: true} ); The function updateLocation ...

Cease the video playback in the modal when the modal is closed

I've attempted several solutions found on stack overflow, but none of them seem to be effective. When I replace the video tag with an iframe, some solutions work, but the video autoplays again, causing issues with the solution. <div class="ico ...

How can I display the value of a radio button that has been chosen?

Would you mind sharing how to display the selected value of a radio button? I attempted it this way, but unfortunately, it did not work. You can view my code at this link. <mat-radio-group [(ngModel)]="favoriteName"> <mat-radio-button *ngFor="l ...

Exporting data from JSON to a CSV file

I am attempting to find a solution for converting JSON objects into CSV files. I tried using a 'for...in' loop within another 'for' loop, but encountered an issue where the object properties and length are different. JSON data: [ {"n ...

Move the navigation bullets of the Nivo Slider to the bottom instead of below the slider

Currently working on a website and have incorporated Nivo Slider to develop a jQuery slider. Encountering an issue with the bullets that indicate which slide the user is currently viewing. I'd like these bullets to be displayed on the images within t ...

In the readmore.js script, position the "readmore" link within a div instead of outside of it

I have added annotations that vary in length, so I am looking to integrate the readmore.js plugin. To ensure uniform sizing for all annotations (even empty ones), I need to set a minimum height for the div container. <annotation> <div style="wi ...

"Exploring the dynamic duo of JHipster and master

I have utilized Jhipster's .jdl file to create all of my classes. Currently, I have two classes with a master-detail relationship. This setup displays the master record (let's say A) at the top of my form and a list/table of detail records (for e ...

Use JavaScript or jQuery to calculate the total value of selected radio buttons and display it in the corresponding textbox

I'm looking to calculate the sum of values from radio buttons and display that sum in the corresponding textbox using either JavaScript or jQuery. Each radio button should have a unique class name for its results. So far, I've only managed to ...

Using JSON data to render images onto a canvas

I am encountering an issue with a JSON array that I'm receiving from PHP. The array is indexed and has the following format (larger in real scenario) [ [ [17, 28, 1, "z"], [28, 31, 6, "b"], [8, 29, 6, "b"] ...

Find a string that matches an element in a list

I currently have a list structured like this let array = [ { url: 'url1'}, { url: 'url2/test', children: [{url: 'url2/test/test'}, {url: 'url2/test2/test'}], { url: 'url3', children: [{url: & ...