Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor's MouseEventArgs coordinates for SVGs are wrong! #15440

Closed
Joebeazelman opened this issue Oct 26, 2019 · 5 comments
Closed

Blazor's MouseEventArgs coordinates for SVGs are wrong! #15440

Joebeazelman opened this issue Oct 26, 2019 · 5 comments
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-svg ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Status: Resolved
Milestone

Comments

@Joebeazelman
Copy link

Joebeazelman commented Oct 26, 2019

The coordinates obtained from MouseEventArgs, namely clientX and clientY, during a mousedown event is wrong. It seems there's a constant offset applied to the coordinates. I suspect there's some kind of miscalculation occurring in Blazor. I haven't tested this on other elements types other than SVG.

At first, I thought it might have something to do with relative coordinates of the SVG child elements, but after adjusting for it, the coordinates are the same. When I implemented it in JavaScript, JavaScript returned the correct coordinates. Whatever MouseEventArgs is doing to the coordinates, it is wrong:

@page "/counter"
@using System.Diagnostics
@using System.Drawing


<h1>Blazor version</h1>


<div>
    <svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" @onmousedown="OnMouseDown">
         <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red"/>

         @foreach (var center in centers)
         {
             <circle cx="@center.X" cy="@center.Y" r="10" stroke="black" stroke-width="0" fill="red"/>
         }
         Sorry, your browser does not support inline SVG.
    </svg>
</div>

@code{

  List<PointF> centers = new List<PointF>();

  public void OnMouseDown(MouseEventArgs e)
  {
      Debug.WriteLine(e.ClientX + " " + e.ClientY);
      centers.Add(new PointF((float) e.ClientX, (float) e.ClientY));
      StateHasChanged();
  }

}

Almost identical code implemented in pure JS without Blazor running (SvgPoint, translation of points makes no difference):

@page "/fetchdata"

<h1>Counter</h1>


<div>
    <svg xmlns="http://www.w3.org/2000/svg" id="template" height="100%" width="100%">
        <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red"/>
        
        Sorry, your browser does not support inline SVG.
    </svg>
</div>

<script>
var svg = document.getElementById("template"),
     NS = svg.getAttribute("xmlns"),
     local = svg.getElementById("local"),
     coords = document.getElementById("coords");
 
 // add a circle to the SVG
 svg.addEventListener(
     "mousedown", DOMToSvgCoordinate,
     false
 );
 
 // translate page to SVG co-ordinates
 function svgPoint(element, x, y) {
     var pt = svg.createSVGPoint();
     pt.x = x;
     pt.y = y;
     return pt.matrixTransform(element.getScreenCTM().inverse());
 }
 
 function DOMToSvgCoordinate(e) {
     var 
         x = e.clientX, 
         y = e.clientY,
         svgP = svgPoint(svg, x, y);
  
    var circle = document.createElementNS(NS, "circle");
    circle.setAttributeNS(null, "cx", Math.round(svgP.x));
    circle.setAttributeNS(null, "cy", Math.round(svgP.y));
    circle.setAttributeNS(null, "r", 10);
    circle.setAttributeNS(null, "stroke", "green");
    circle.setAttributeNS(null, "stroke-width", 3);
    circle.setAttributeNS(null, "fill", "yellow" );
    svg.appendChild(circle);
        
    console.log(svgP);
 }
</script>
@blowdart blowdart added the area-blazor Includes: Blazor, Razor Components label Oct 27, 2019
@javiercn
Copy link
Member

@Joebeazelman thanks for contacting us.

I believe there are several issues associated with SVG right now. @SteveSandersonMS do you know of the top of your head if this is one of those?

@SteveSandersonMS
Copy link
Member

I don't specifically know. Blazor doesn't calculate any coordinates, but rather just passes through whatever data is supplied with the event by the browser.

@mkArtakMSFT
Copy link
Member

Thanks for contacting us, @Joebeazelman.
We currently don't have proper SVG support: https://docs.microsoft.com/en-us/aspnet/core/blazor/components?view=aspnetcore-3.0#scalable-vector-graphics-svg-images

We do plan to improve this in the future (probably during 5.0).

@lowi
Copy link

lowi commented Apr 29, 2020

I have used JSRuntime.InvokeAsync to transform the clientX and clientY points to correct SVG points (working with 3.2.0-preview5.20216.8):

In index.html:

<script>
     window.getSVG_XY = (svg, x, y) => {
        var pt = svg.createSVGPoint();
        pt.x = x;
        pt.y = y;
        pt = pt.matrixTransform(svg.getScreenCTM().inverse());
        return pt.x + " " + pt.y;    
    };</script>

In the component:


<svg @ref="thesvg" width="500px" height="500px" @onclick="AddRect">
    @foreach (var r in rects)
    {
        <rect x="@r.x" y="@r.y" width="@r.w" height="@r.h" fill="transparent" stroke="blue">

        </rect>
    }
</svg>

@code {
    async Task AddRect(MouseEventArgs e)
    {
        var infoFromJs = await JSRuntime.InvokeAsync<string>("getSVG_XY", thesvg, e.ClientX, e.ClientY);

        var values = infoFromJs.Split(" ");
        double x = Double.Parse(values[0]);
        double y = Double.Parse(values[1]);

        Rect r = new Rect((int)x, (int)y, 100, 100);
        rects.Add(r);
        StateHasChanged();
    }

    public class Rect
    {
        public int x { get; set; }
        public int y { get; set; }
        public int w { get; set; }
        public int h { get; set; }

        public Rect(int x, int y, int w, int h)
        {
            this.x = x;
            this.y = y;
            this.w = w;
            this.h = h;
        }
    }

    List<Rect> rects = new List<Rect>();
    ElementReference thesvg;
}

@mkArtakMSFT
Copy link
Member

Closing as we will be tackling this as part of #18271

@mkArtakMSFT mkArtakMSFT added the ✔️ Resolution: Duplicate Resolved as a duplicate of another issue label May 14, 2020
@ghost ghost added the Status: Resolved label May 14, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Jun 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-svg ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Status: Resolved
Projects
None yet
Development

No branches or pull requests

7 participants