svgdotjs / svg.js

The lightweight library for manipulating and animating SVG
https://svgjs.dev
Other
11.01k stars 1.07k forks source link

Documentation: Basic Events should include example with mouseEvent and coordinate transform #1213

Closed katzlbt closed 11 months ago

katzlbt commented 3 years ago

This is the example given in the doc. It is way too spartanic and even omits all parameters passed to the click handler.

element.click(function() {
  this.fill({ color: '#f06' })
})

Also the documentation does not give an example of how to transform the coordinates of the MouseEvent to the SVG-view-box coordinates, which is probably the standard case for using click events. So I have prepared an example for a standard use-case (after searching for the point() function for hours). It is a little bit elaborate, but that does not hurt, as it is almost a copy-paste solution. I hope this is a useful contribution.

Full Object-Oriented Example with coordinate transform:

class AddPointOnClickModelViewController {
constructor()
{
    this.svg = SVG("#svgElement"); // this is our HTML svg drawing area (View of our MVC).
        // We retrieve it by ID (for a Singleton)

    // now we register the click handler to this instance
    let me = this;
    this.svg.click(function(mouseEvent) {
      // mouseEvent is type MouseEvent with coordinates offsetX, offsetY relative to the top left of the svg dom element 
      // this is type SVG and is the clicked element
      me.onClickSvg(this, mouseEvent); // forward to MC instance
    });
}

onClickSvg(svg, mouseEvent)
{
    // The global variable "event" declared at this point is the same as mouseEvent
    let id = svg.attr().id;  // svg and this.svg are the same
    console.log("SVG element clicked has id:", id)
    console.log("offsetX offsetY modifierKeys:", mouseEvent.offsetX, mouseEvent.offsetY, mouseEvent.shiftKey, mouseEvent.altKey, mouseEvent.metaKey);
    // transform click location to viewbox coordinates 
    let { x, y } = svg.point(mouseEvent.pageX, mouseEvent.pageY);
    console.log("Coordinates transformed:", x, y);
    // add a circle at the clicked coordinates to the SVG-View
    let newPoint = svg.ellipse([5,5]).cx(x).cy(y).fill("red").stroke({width:1, color: '#000'});
    // at this point we could register a click-to-remove function on the circle/ellipse
    // now you may want to store the new point in your data-model ...
}

In my opinion the function "point()" is misnamed. One expects a shape like line() not a transform. SVG.transformPageCoordinates() or transformMouseEventCoordinates() would be a great alias. Trading saved keystrokes for code understandability never appealed to me, otherwise nice library!

https://svgjs.dev/docs/3.1/events/#basic-events

trasherdk commented 3 years ago

Well :smiley:

element.click(function() {
  this.fill({ color: '#f06' })
})

does seem a bit thin, compared to

class AddPointOnClickModelViewController {
  constructor() {
    this.svg = SVG("#svgElement"); // this is our HTML svg drawing area (View of our MVC).
    // We retrieve it by ID (for a Singleton)

    // now we register the click handler to this instance
    let me = this;

    this.svg.click(function (mouseEvent) {
      // mouseEvent is type MouseEvent with coordinates offsetX, offsetY relative to the top left of the svg dom element 
      // this is type SVG and is the clicked element
      me.onClickSvg(this, mouseEvent); // forward to MC instance
    });
  }

  onClickSvg(svg, mouseEvent) {
    // The global variable "event" declared at this point is the same as mouseEvent
    let id = svg.attr().id;  // svg and this.svg are the same

    console.log("SVG element clicked has id:", id)
    console.log("offsetX offsetY modifierKeys:", mouseEvent.offsetX, mouseEvent.offsetY, mouseEvent.shiftKey, mouseEvent.altKey, mouseEvent.metaKey);

    // transform click location to viewbox coordinates 
    let { x, y } = svg.point(mouseEvent.pageX, mouseEvent.pageY);
    console.log("Coordinates transformed:", x, y);

    // add a circle at the clicked coordinates to the SVG-View
    let newPoint = svg.ellipse([5, 5]).cx(x).cy(y).fill("red").stroke({ width: 1, color: '#000' });

    // at this point we could register a click-to-remove function on the circle/ellipse
    // now you may want to store the new point in your data-model ...
  }

  ...