Jerky SVG Movement

The question IS: What is causing the event.offsetX & event.offsetY to SOMETIMES have a value +/-10 than what they should be. Things I have observed that affect this are:

  1. Passing through certain areas of an SVG.
  2. Preforming a console.log(event.offsetX) can remediate this depending on if it’s performed before or after other lines.

I do not know why either of these should have any impact. I have never experienced any other behavior like this.

The question IS NOT / answers ARE NOT:

  1. Why am I deleting and recreating an element? Both because I can, and this code is to just demonstrate the problem.
  2. How can I perform this differently. I am not looking for alternate solutions. I know how to do things differently. I am trying to understand what is causing the undesired results in THIS code.
  3. My viewbox is not set to the same size as the SVG element and I need to use a certain preserveAspectRatio setting. No I do not. There is no requirement for either of these. They are certainly allowed to be different.
  4. My SVG pointer does not line up with the HTML cursor. I know; that is not what I want it to do. I do not need answers showing me how to convert a HTML point to a SVG point. I know how to do this this is not what I am looking for.
  5. I need to use getCTM()/getSreecCTM(). No I do not. Those do not provide what I am looking to do, and are irrelevant to the question.
  6. This is working for some people. If you are getting some completely different error, I cannot help you with your device.
  7. This is not an SVG animation problem. Logging/debugging can show the offsetX & offsetY values sometimes have a value of +/-10 of what they should be.

I was working on an application to track movement in an SVG viewbox relative to the size of the SVG element itself. The sample code below has been reduced to remove any extra functions, variables, calculations, etc. as much as possible to demonstrate just the problem.

When moving the mouse cursor across the SVG, the green (purple & yellow edits added per comments) pointer tracker its x & y positions by 10px each when moving through the approximate zones marked by the red bands. Also moving left to right vs. right to left has slightly different trigger points.

const svg = document.getElementById('svg1');
svg.addEventListener('pointermove', event => {
    // console.log(event.offsetX);
    const id1 = 'pointer1';
    const id2 = 'pointer2';
    const id3 = 'pointer3';

    const pointerOld1 = document.getElementById(id1);
    if (pointerOld1) pointerOld1.remove();
    const pointerOld2 = document.getElementById(id2);
    if (pointerOld2) pointerOld2.remove();

    const x = event.offsetX;
    const y = event.offsetY;

    const pointerNew1 = document.createElementNS(svg.namespaceURI, 'circle');
    pointerNew1.setAttributeNS(null, 'id', id1);
    pointerNew1.setAttributeNS(null, 'cx', x * 0.25);
    pointerNew1.setAttributeNS(null, 'cy', y * 0.5);
    pointerNew1.setAttributeNS(null, 'r', '15px');
    pointerNew1.setAttributeNS(null, 'stroke', 'green');
    pointerNew1.setAttributeNS(null, 'stroke-width', '5px');
    pointerNew1.setAttributeNS(null, 'fill', 'none');
    svg.append(pointerNew1);

    const point = new DOMPoint(x, y).matrixTransform(svg.getCTM().inverse());
    const pointerNew2 = document.createElementNS(svg.namespaceURI, 'circle');
    pointerNew2.setAttributeNS(null, 'id', id2);
    pointerNew2.setAttributeNS(null, 'cx', point.x);
    pointerNew2.setAttributeNS(null, 'cy', point.y);
    pointerNew2.setAttributeNS(null, 'r', '15px');
    pointerNew2.setAttributeNS(null, 'stroke', 'purple');
    pointerNew2.setAttributeNS(null, 'stroke-width', '5px');
    pointerNew2.setAttributeNS(null, 'fill', 'none');
    svg.append(pointerNew2);

    const pointer3 = document.getElementById(id3);
    if (!pointer3) {
        const pointer3 = document.createElementNS(svg.namespaceURI, 'circle');
        pointer3.setAttributeNS(null, 'id', id3);
        pointer3.setAttributeNS(null, 'r', '10px');
        pointer3.setAttributeNS(null, 'stroke', 'yellow');
        pointer3.setAttributeNS(null, 'stroke-width', '5px');
        pointer3.setAttributeNS(null, 'fill', 'none');
        svg.append(pointer3);
    }
    else {
        pointer3.setAttributeNS(null, 'cx', x * 0.25);
        pointer3.setAttributeNS(null, 'cy', y * 0.5);
    }

});
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 100" width="400" height="200"
    style="border: 2px solid;">
    <line x1="0" y1="0" x2="100px" y2="100" stroke="blue" />
    <line x1="100" y1="0" x2="0" y2="100" stroke="blue" />
    <rect x="14" y="0" width="1" height="100" fill="red"></rect>
    <rect x="16" y="0" width="1" height="100" fill="red"></rect>
    <rect x="18" y="0" width="1" height="100" fill="red"></rect>
    <rect x="20" y="0" width="1" height="100" fill="red"></rect>
    <rect x="22" y="0" width="12" height="100" fill="red"></rect>
    <rect x="75" y="0" width="1" height="100" fill="red"></rect>
    <rect x="77" y="0" width="12" height="100" fill="red"></rect>
</svg>

I found some “work-arounds” including:

  1. If I uncomment the console.log(event.offsetX); line, it performs fine.
  2. If I move the x & y constant declarations before the if (pointerOld) pointerOld.remove(); line, it also works fine.

However, I am trying to understand why it is behaving like this in the first place? Am I doing something wrong? Or is this a bug (in HTML/JavaScript/SVG/web browser/OS)?

15

First of all, like herrstrietzel write in the comment, the coordinate system for the SVG is different from the HTML page. Use the screenToSVG() function mentioned here.

Second, you don’t need to create a new circle element on each event call back. Reuse the one that is already there.

const pointerMove = event => {
  let svg = event.target.closest('svg');
  let pointer = svg.querySelector('.pointer');

  let x = event.clientX;
  let y = event.clientY;
  let coordinates = screenToSVG(svg, x, y);
  
  pointer.setAttribute('cx', coordinates.x);
  pointer.setAttribute('cy',coordinates.y);
}

let svg1 = document.getElementById('svg1');
svg1.addEventListener('pointermove', pointerMove);

function screenToSVG(svg, screenX, screenY) {
   var p = svg.createSVGPoint();
    p.x = screenX;
    p.y = screenY;
    return p.matrixTransform(svg.getScreenCTM().inverse());
}
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 100" width="400" height="200" style="border: 2pt solid;">
    <line x1="0" y1="0" x2="100px" y2="100" stroke="blue" />
    <line x1="100" y1="0" x2="0" y2="100" stroke="blue" />
    <rect x="14" y="0" width="1" height="100" fill="red"></rect>
    <rect x="16" y="0" width="1" height="100" fill="red"></rect>
    <rect x="18" y="0" width="1" height="100" fill="red"></rect>
    <rect x="20" y="0" width="1" height="100" fill="red"></rect>
    <rect x="22" y="0" width="12" height="100" fill="red"></rect>
    <rect x="75" y="0" width="1" height="100" fill="red"></rect>
    <rect x="77" y="0" width="12" height="100" fill="red"></rect>
    <circle class="pointer" r="15" stroke="green" stroke-width="5" fill="none"/>
</svg>

5

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật