2016-04-02 17 views
5

Zanim pomyślisz "dlaczego ten facet prosi o pomoc w tym problemie, na pewno został zaimplementowany 1000x" - podczas gdy w większości masz rację, próbowałem rozwiązać ten problem z kilkoma otwartymi źródło libs jeszcze tutaj jestem.SVG powiększanie myszy - model matematyczny

Próbuję zaimplementować oparte na SVG "powiększanie koła myszy, koncentrując się na myszy" od podstaw.

Wiem, że istnieje wiele bibliotek, które to umożliwiają, d3 i svg-pan-zoom, aby wymienić parę. Niestety, moje implementacje używające tych bibliotek nie spełniają moich oczekiwań. Miałem nadzieję, że mogę uzyskać pomoc od społeczności z bazowym modelem matematycznym dla tego typu funkcji interfejsu użytkownika.

Zasadniczo pożądane zachowanie przypomina Mapy Google, użytkownik ma wskaźnik myszy nad lokalizacją, przewija kółko myszy (do wewnątrz), a skala obrazu mapy rośnie, podczas gdy położenie, na którym się znajduje, staje się poziome i pionowe centrum rzutni.

Naturalnie, mam dostęp do szerokości/wysokości okna roboczego i x/y myszy.

W tym przykładzie, skupię się tylko na osi x, rzutnia ma szerokość 900 jednostek, na placu jest szeroka 100 jednostek, to x przesunięcie wynosi 400 jednostek, a skala wynosi 1: 1

<g transform="translate(0 0) scale(1)"> 

enter image description here

Przyjmując pozycję mysz x był na lub blisko 450 jednostek, jeśli użytkownik koła, aż skala osiągnęła 2: 1 I oczekiwać, że x offsetowe dotrzeć -450 sztuk, centrowanie punkt ostrości tak jak .

<g transform="translate(-450 0) scale(2)"> 

enter image description here

X i Y przesunięcia powinny być przeliczone na każde kolejne zwoju koło jako funkcji prądu przesunięcia waga/mysz.

Wszystkie moje próby są całkowicie pozbawione pożądanego zachowania, wszelkie porady są mile widziane.

Chociaż doceniam każdą pomoc, proszę nie odpowiadać z sugestiami do bibliotek zewnętrznych, wtyczek jQuery i tego typu rzeczy. Moim celem jest zrozumienie modelu matematycznego stojącego za tym problemem w sensie ogólnym, moje wykorzystanie SVG ma przede wszystkim charakter ilustracyjny.

Odpowiedz

5

Co zwykle robię, to utrzymuję trzy zmienne przesunięcie x przesunięcie y i skalę. Zostaną zastosowane jako transformacja do grupy kontenerów, np. Twój element <g transform="translate(0 0) scale(1)">.

Jeśli mysz byłaby nad źródłem, nowe tłumaczenie byłoby trywialne do obliczenia. Wystarczy pomnożyć przesunięcia xiy przez różnicę w skali:

offsetX = offsetX * newScale/scale 
offsetY = offsetY * newScale/scale 

Co można zrobić, to przetłumaczyć przesunięcie tak, że mysz jest na pochodzenie. Następnie przeskalujesz, a następnie przetłumaczysz każdą rzecz.Przyjrzeć się tej klasie maszynopis, że ma metodę scaleRelativeTo robić tylko to, co chcesz:

export class Point implements Interfaces.IPoint { 
    x: number; 
    y: number; 

    public constructor(x: number, y: number) { 
     this.x = x; 
     this.y = y; 
    } 

    add(p: Interfaces.IPoint): Point { 
     return new Point(this.x + p.x, this.y + p.y); 
    } 

    snapTo(gridX: number, gridY: number): Point { 
     var x = Math.round(this.x/gridX) * gridX; 
     var y = Math.round(this.y/gridY) * gridY; 
     return new Point(x, y); 
    } 

    scale(factor: number): Point { 
     return new Point(this.x * factor, this.y * factor); 
    } 

    scaleRelativeTo(point: Interfaces.IPoint, factor: number): Point { 

     return this.subtract(point).scale(factor).add(point); 
    } 

    subtract(p: Interfaces.IPoint): Point { 
     return new Point(this.x - p.x, this.y - p.y); 
    } 

    } 

Więc jeśli dałeś transformacji podane przez translate(offsetX,offsetY) scale(scale) i zdarzenie przewijania miało miejsce w (mouseX, mouseY) prowadzi do nowej skali newScale cię obliczy nową transformację:

offsetX = (offsetX - mouseX) * newScale/scale + mouseX 
offsetY = (offsetY - mouseY) * newScale/scale + mouseY 
+0

Tam na końcu, po prostu piękna - dziękuję – James