2010-02-01 9 views
22

Die Browser, die Teile der SVG-Spezifikation (Firefox usw.) implementiert haben, testen für uns kostenlos - wenn ich einen Mousedown-Listener an ein SVG-Objekt anschließe, werde ich benachrichtigt, sobald die Form angeklickt wird. Dies ist besonders bei komplexen Polygonformen erstaunlich.Hit-Test SVG Formen?

Ich frage mich, ob es eine Möglichkeit gibt, ich kann diese Funktion für ein bisschen mehr Hit-Tests verwenden. Ich möchte wissen, ob ein gegebenes Rechteck irgendeine meiner SVG-Formen schneidet.

Zum Beispiel füge ich meinem Element 3 komplexe Polygone hinzu. Jetzt möchte ich wissen, ob ein Rechteck (40, 40, 100, 100) eines von ihnen schneidet. Hat jemand eine Idee, wie ich möglicherweise in die bereits große Hit-Test-Unterstützung eingreifen könnte, anstatt diesen ganzen Code selbst hinzuzufügen?

Dank

Antwort

13

Ich kenne keine Möglichkeit, ein ganzes Rechteck zu schneiden. Sie können jedoch einen Punkt schneiden, so dass Sie könnte einen komplizierteren Scheck aus, dass bauen:

var el= document.elementFromPoint(x, y); 

werden Sie das höchsten gestapelte Element an einer bestimmten Seiten relativer Koordinaten. Sie erhalten das <svg> Element, wenn keine Formen innerhalb des SVG getroffen werden.

Dies ist ein Nicht-Standard Mozilla extension, aber es funktioniert auch auf WebKit. Leider, obwohl es in Opera existiert, wird es nicht nach innen schauen <svg>, so dass auf diesem Browser das Element immer das SVGSVGElement sein wird.

+2

Vielen Dank, dass Sie darauf hingewiesen haben, dass Ihre Lösung zu dieser Zeit nicht Standard war. Es ist immer noch ein Working Draft, aber glücklicherweise hat diese Methode es in die (sehr praktische!) CSSOM-Spezifikation geschafft: http://dev.w3.org/csswg/cssom-view/#dom-document-elementfrompoint – natevw

+0

Vielen vielen Dank dafür ... – Sudarshan

+0

Die in elementFromPoint() verwendeten Koordinaten sind absolut. Wenn Ihr SVG also nicht bei 0,0 beginnt, müssen Sie zwischen absoluten und relativen Koordinaten einstellen. –

21

Der SVG 1.1 DOM hat genau die richtige Methode (leider ist es noch nicht in mozilla implementiert):

var nodelist = svgroot.getIntersectionList(hitrect, null); 

Für ein vollständiges Arbeitsbeispiel here sehen.

+0

großartig! Also zwischen uns haben wir alle wichtigen Browser. Naja, bis auf * das *, natürlich ... – bobince

+0

Ok, wir müssen nur warten, bis dies im Webkit implementiert ist, dann müssen Safari und Chrome dann eine neue Version veröffentlichen, die gegen diese Änderungen gebaut wurde. – user246114

+1

Der Blogpost ist weg. –

0

getIntersectionList funktioniert gut in Opera. Mein Problem ist, dass die Funktionen in der SVG 1.1 Full-Spezifikation in Bezug darauf erfordert, dass Elemente gerendert werden müssen (und ein mögliches Ziel für Zeigerereignisse), um als Treffer erkannt zu werden. Leider macht dies diese Funktionen für Hit-Tests in einer Spielwelt nutzlos, in der nur ein Teil der Welt gegenwärtig sichtbar ist.

+2

'opacity: 0' oder' visibility: hidden' bedeutet immer noch, dass die fraglichen Elemente nach Svg gerendert werden, aber die Elemente unsichtbar sind. Sie sollten in der Lage sein, 'Zeiger-Ereignisse' zu ​​optimieren, um auf diese unsichtbaren Elemente gut anzuwenden. –

0

Chrome Version von checkIntersection (und getIntersectionList) testet die Element Bounding-Boxen, anstatt die Elemente selbst. Ich konnte meine eigene checkIntersection schreiben, die auf chrome arbeitet, indem ich eine Leinwand mit diesem ziemlich komplizierten Ansatz verwende, die gut für kleine Rechtecke zu funktionieren scheint und für große Rechtecke langsam ist, also ist es gut für Hit-Tests. Diese Technik funktioniert als Polyfill für checkIntersection in Chrome, für kleine Rechtecke und möglicherweise für andere Browser, die Implementierungen von checkIntersection durchbrochen haben.

  1. ein Bild erstellen, die eine Daten URI verwendet Ihre SVG Outerhtml enthält (Sie darin Stilregeln und umfassen müssen können), wie so (dieses Bild auf der Seite sein, muss nicht). Sie können einen onload-Ereignishandler verwenden, um bei Bedarf festzustellen, wann er geladen wurde.
  2. eine Leinwand erstellen für den Treffertest Rechteck zu verwenden (diese Leinwand braucht nicht auf der Seite zu sein)

Um zu testen, ob ein Rechteck mit einem Ihren Formen schneidet, dies zu tun:

  1. sicherstellen, dass die Leinwand die gleiche Größe wie das Rechteck ist (gesetzt seine Breite und Höhe)
  2. Klar die Leinwand Leinwand Kontext clearRect() Methode
  3. zeichnen Sie die SVG auf der Leinwand bei -x verwenden, -y so dass der Teil des Das Bild, das die Zeichenfläche überlappt, entspricht dem zu testenden Bereich. Verwenden Sie dazu drawImage()
  4. . Rufen Sie die ImageData des Zeichenbereichs mit dem Kontext des Kontexts ab. Jedes vierte Element des Datenarrays ist das Alpha-Byte und ein Wert ungleich Null bedeutet, dass ein Teil Ihres SVG das Rechteck überlappt. Wenn alle 4. Bytes 0 sind, schneidet Ihr SVG das Rechteck nicht.