• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed JS - mouseover event, jak pobrać dokładny punkt przecięcia elementu html?

Object Storage Arubacloud
+1 głos
111 wizyt
pytanie zadane 5 września 2020 w JavaScript przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 5 września 2020 przez Jakub 0

Witam, mam mały problem ze zdarzeniem mouseover, kwestia jest taka że nie jest pobierana dokładna pozycja przecięcia przez kursor elementu html, lecz dostaje inne współrzędne w zależności od prędkości ruchu myszy ( czyli jeśli ruszam wolno to jest ok, ale jeśli szybko to dostaje bzdurne informacje ). 

Piszę prostego painta, i sprawa wygląda tak:

Jak widać, gdy kursor szybko opuści pole rysowania ( canvas'a ), a następnie szybko tam wróci to pojawi się takowy błąd ( widać po współrzędnej x ).

Czyli podsumowując, moim celem jest dokładne pobranie punktu przecięcia elementu, a nie dowolnych współrzędnych. Oczywiście rozwiązanie mojego problemu może być inne, dlatego daje kod:

HTML 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./main.js" defer></script>

    <style>
        canvas {
            outline: 1px solid black;
        }
        .active {
            background-color: rgb(0, 206, 0);
        }
    </style>
</head>
<body>
    <canvas width="600" height="500" id="canvas"></canvas>

    <div class="settings-panel">
        <label for="color-picker">Set color</label>
        <input type="color" id="color-picker">

        <input type="range" min="1" max="200" id="pen-weight-range">
        <label for="pen-weight-range">Set pen weight</label>

        <button type="button" id="clean-btn">Clean</button>
    </div>
</body>
</html>

JS


class Paint {

    // config

    constructor(canvasID) {

        this.canvas = document.querySelector(canvasID);
        this.ctx = canvas.getContext('2d');

        this.draw = false;
        this.clean = false;
        this.color = 'black';

        this.bindMouseEvents();
        this.bindControllers();

        this.ctx.lineWidth = 40;
        this.ctx.lineCap = 'round';
        this.ctx.lineJoin = 'round';
    }

    bindMouseEvents() {
        this.canvas.addEventListener('mousedown', e => { this.mouseDown(e); });
        this.canvas.addEventListener('mousemove', e => { this.mouseMove(e); });
        window.addEventListener('mouseup', e => { this.mouseUp(e); });
        this.canvas.addEventListener('mouseout', e => { this.mouseLeft(e); });
        this.canvas.addEventListener('mouseover', e => { this.mouseOn(e); });
    }

    bindControllers() {

        const colorPicker = document.querySelector('#color-picker');
        const penWeightRange = document.querySelector('#pen-weight-range');
        const cleanBtn = document.querySelector('#clean-btn');
        
        colorPicker.addEventListener('change', () => {
            this.ctx.strokeStyle = colorPicker.value;
            this.color = colorPicker.value;
        });

        penWeightRange.addEventListener('change', e => {
            this.ctx.lineWidth = penWeightRange.value;
        });

        cleanBtn.addEventListener('click', e => {
            this.clean = !this.clean;
            e.target.classList.toggle('active');
            this.ctx.strokeStyle = this.clean ? 'white' : this.color;
        })
    }

    // mouse events

    mouseDown(e) {
        if (e.button === 0) {
            this.initPoint(e);
        }
    }

    mouseMove(e) {
        if (this.draw) {
            this.appendPoint(e);
        }
    } 

    mouseUp(_) {
        this.draw = false;
    }

    mouseLeft(e) {
        this.mouseMove(e);
        this.ctx.beginPath();
    }

    mouseOn(e) {
        let mousePos = this.getMousePos(e);
        this.mouseMove(e);
        console.log(mousePos);
    }

    // draw

    initPoint(e) {
        let mousePos = this.getMousePos(e);
        this.draw = true;
        this.ctx.beginPath();
        this.ctx.moveTo(mousePos.x, mousePos.y);
        this.ctx.lineTo(mousePos.x, mousePos.y);
        this.ctx.stroke();
    }

    appendPoint(e) {
        let mousePos = this.getMousePos(e);
        this.ctx.lineTo(mousePos.x, mousePos.y);
        this.ctx.stroke();
    }

    // helpers

    getMousePos(e) {
        let rect = this.canvas.getBoundingClientRect();
        return {
            x: e.clientX - rect.left,
            y: e.clientY - rect.top
        };
    }
}

document.addEventListener('DOMContentLoaded', () => {
    const p = new Paint('#canvas');
})

Z góry dziękuje za pomoc i pozdrawiam :)

komentarz zamknięcia: problem rozwiązany

1 odpowiedź

+2 głosów
odpowiedź 5 września 2020 przez Bizuma Gaduła (3,650 p.)
wybrane 5 września 2020 przez Jakub 0
 
Najlepsza

No to na początek wyjaśnienie czemu to nie działa. Problem polega na tym, że podczas twojego ruchu myszą twój mouseEvent wykonywany jest pewną ograniczoną ilość razy a twoje rysowanie odbywa się poprzez rysowanie wielu małych linii z punktu do punktu (w momentach kiedy ten mouseEvent jest triggerowany).

W momencie kiedy szybko wyjeżdżasz kursorem za canvasi na niego wracasz to twój mouseEvent wykonuje się ze zbyt małą częstotliwością aby idealnie "wstrzelić" się w moment wejścia/wyjścia z canvasu.

Tutaj podeślę nawet przykład z dokumentacji, który robi dokładnie to samo co twój kod, i uwaga.. jest tam ten sam problem co u Ciebie.

Przykład z dokumentacji

No ale sytuacja nie jest taka beznadziejna bo dalej można to poprawić.

nic nie stoi na przeszkodzie aby w metodach canvasu, podczas rysowania, podawać pozycje, które wykraczają za canvas, a więc możesz przenieść swoje event listenery z canvasu do np body.

na canvasie zostawiłbym tylko listener, który sprawdza czy został wciśnięty przycisk myszy odpowiedzialny za rysowanie i rysowałbym tak długo aż ten przycisk nie zostanie puszczony, niezależnie od tego czy będzie on nad canvasem czy nie.

Tylko teraz pojawi nam się mały problem z różnymi pozycjami myszki i tego gdzie rysujemy (zależnie od ustawienia elementów nasza linia może się pojawiać w innym miejscu niż kliknęliśmy). No ale to nie problem, bo znamy nasz aktualny scroll strony, możemy też odczytać pozycję naszego canvasu względem rodziców lub całego ekranu więc możemy dokonać obliczeń korygujących pozycję.

 

Jeszcze tylko pokażę jak zmieniając jedno słowo rozwiązać ten problem w przykładzie z dokumentacji.

Myślę, że będzie to pomocne też dla innych bo jest to dokładnie ten sam problem co w pytaniu.

/* oryginał */
myPics.addEventListener('mousemove', e => {
  if (isDrawing === true) {
    drawLine(context, x, y, e.offsetX, e.offsetY);
    x = e.offsetX;
    y = e.offsetY;
  }
});

/* zmiana */
document.addEventListener('mousemove', e => {
  if (isDrawing === true) {
    drawLine(context, x, y, e.offsetX, e.offsetY);
    x = e.offsetX;
    y = e.offsetY;
  }
});

 

komentarz 5 września 2020 przez Jakub 0 Pasjonat (23,120 p.)
To było tak oczywiste... Dzięki :)

Podobne pytania

0 głosów
0 odpowiedzi 101 wizyt
pytanie zadane 3 stycznia 2020 w Grafika i multimedia przez Konrad Polit Początkujący (410 p.)
0 głosów
0 odpowiedzi 97 wizyt
pytanie zadane 8 marca w C i C++ przez TOWaD Mądrala (5,700 p.)

92,575 zapytań

141,424 odpowiedzi

319,649 komentarzy

61,960 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...