0

I have made a page in my Django webapp that displays an image and allows the user to click on the image and should place a circle on top of the image where the user clicked. The following code is able to get the location of the mouse click on the image, and adds a tag to the html in the right place, but it won't actually show up on the page. If I hard code a circle into the html, it shows up just fine. It also seems like the mouse is on a different coordinate system than the SVG element... I have tried event.x, event.pageX, and event.clientX but noticed no difference. Even if I hard code the position of the circle, it won't show up on the click

html:

{% extends 'main/base.html' %}

{% block head_content %}
{% load static %}
<script type="text/javascript" src="{% static 'js/click.js' %}"></script>
{% endblock %}

{% block content %}

<div class="my-div">

    <div>
        <h1>The Page!</h1>
    </div>
    <form enctype="multipart/form-data" method="POST" action="/mysite/nextpage/">
        {% csrf_token %}

        <svg id="svg">
            <image href="data:image/png;base64,{{ my_img }}"/>
            <!-- Placing a circle manually works just fine! -->
            <circle cx='50' cy='150' r='50' fill='red'/>
            
        </svg>

        <input type="submit" name="submit" class="submit-btn"></input>
    </form>

</div>

{% endblock %}

Javascript:

this.window.addEventListener('DOMContentLoaded', (event) => {
    const svgElem = this.document.getElementsByTagName("svg")

    if (svgElem != undefined && svgElem.length != 0) {
        const svg = svgElem[0]
        const image = svg.firstChild
        svg.onclick = function(event) {
            
            var newCircle = document.createElement('circle')
            newCircle.setAttribute('cx', event.clientX)
            newCircle.setAttribute('cy', event.clientY)
            newCircle.setAttribute('r', '50')
            newCircle.setAttribute('fill', 'red')
            svg.append(newCircle)
        }
    }
});
JasonFitz
  • 183
  • 1
  • 11
  • 2
    When you need to create a new svg element use [createElementNS](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS) instead of createElement – enxaneta Apr 29 '21 at 14:11
  • @enxaneta thank you!! The circles now render properly, but still not in the spot of the mouse click – JasonFitz Apr 29 '21 at 14:19
  • [The clientX read-only property of the MouseEvent interface provides the horizontal coordinate within the application's viewport](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/clientX). In order to detect the position of the mouse over the svg element please try something like this: https://stackoverflow.com/questions/54799299/click-event-coordinates-in-svg/54804984#54804984 – enxaneta Apr 29 '21 at 14:30

1 Answers1

2

Thanks to @enxaneta in the comments for suggesting createElementNS, and thanks to this post (also credit @enxaneta) for helping translate the coordinates, I got the code to work.

this.window.addEventListener('DOMContentLoaded', (event) => {
    const svgElem = this.document.getElementsByTagName("svg")

    if (svgElem != undefined && svgElem.length != 0) {
        const svg = svgElem[0]
        const image = svg.firstChild
        svg.onclick = function(event) {
            
            var newCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle')
            let m = mousePositionSVG(event)
            newCircle.setAttribute('cx', m.x)
            newCircle.setAttribute('cy', m.y)
            newCircle.setAttribute('r', '50')
            newCircle.setAttribute('fill', 'red')
            svg.append(newCircle)
        }
    }
});

function mousePositionSVG(e) {
    let svg = document.querySelector('svg')
    var p = svg.createSVGPoint()
    p.x = e.clientX
    p.y = e.clientY
    var ctm = svg.getScreenCTM().inverse();
    var p =  p.matrixTransform(ctm);
    return p;
}
JasonFitz
  • 183
  • 1
  • 11