Frage

Ich habe eine analytische Datenvisualisierung-Engine für Canvas gebaut und wurden aufgefordert, Tooltip-like schweben über Datenelemente hinzuzufügen unter dem Cursor detaillierte Metriken für den Datenpunkt angezeigt werden soll.

Für eine einfache Bar & Gaant Diagramme, Baumdiagramme und Knotenkarten mit einfachen quadratischen Flächen oder bestimmten Punkten von Interesse, konnte ich dies durch Überlagerung implementieren absolut positionierte DIVs mit: schweben Attribute, aber es gibt einige komplizierteren Visualisierungen solcher als Tortendiagramme und ein Verkehrsfluss-Rendering, die Hunderte von getrennten Bereichen definiert durch bezeir Kurven hat.

Sie ist möglich, irgendwie ein Overlay anhängen oder ein Ereignis auslösen, wenn der Nutzer die Maus über einen bestimmten Pfad geschlossen?

Jede Fläche, für die Bedürfnisse schweben angegeben definiert werden wie folgt:

context.beginPath();
context.moveTo(segmentRight, prevTop);
context.bezierCurveTo(segmentRight, prevTop, segmentLeft, thisTop, segmentLeft, thisTop);
context.lineTo(segmentLeft, thisBottom);
context.bezierCurveTo(segmentLeft, thisBottom, segmentRight, prevBottom, segmentRight, prevBottom);
/*
 * ...define additional segments...
 */
// <dream> Ideally I would like to attach to events on each path:
context.setMouseover(function(){/*Show hover content*/});
// </dream>
context.closePath();

Die Bindung an ein Objekt wie dieses fast trivial ist in Flash oder Silverlight zu implementieren, da aber die aktuelle Canvas Implementierung hat den Vorteil, direkt an unsere bestehenden Javascript API und Integration mit anderen Ajax-Elemente verwenden, wir hoffen, setzen Blitz in zu vermeiden die Mischung.

Irgendwelche Ideen?

War es hilfreich?

Lösung

Sie können das mousemove- Ereignis behandeln und die x erhalten, y-Koordinaten von der Veranstaltung. Dann werden Sie wahrscheinlich über alle Pfade durchlaufen müssen, um zu testen, ob der Punkt, über den Weg. Ich hatte ein ähnliches Problem dass haben könnte einige Code, den Sie verwenden könnte.

Looping über die Dinge auf diese Weise kann langsam sein, vor allem auf IE. Eine Möglichkeit, Sie könnten möglicherweise es zu beschleunigen - und das ist ein Hack, aber es wäre sehr effektiv sein - wären die Farbe zu ändern, dass jeder Pfad mit gezogen wird, so dass es nicht auffällt von Menschen, sondern so, dass jeder Pfad gezeichnet wird in eine andere Farbe. Haben Sie eine Tabelle Farben Wege zu suchen und nachschlagen nur die Farbe des Pixels unter der Maus.

Andere Tipps

Schatten Leinwand

Die beste Methode, die ich habe an anderer Stelle für die Mouseover-Erkennung gesehen ist der Teil Ihrer Zeichnung zu wiederholen, die Sie auf eine versteckt erkennen wollen, gelöscht Leinwand. Dann speichern Sie die Imagedata-Objekt. Sie können dann für das Pixel von Interesse, die Imagedata Array überprüfen und true zurück, wenn der Alpha-Wert größer als 0 ist.

// slow part
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(100,100,canvas.width-100,canvas.height-100);
var pixels = ctx.getImageData(0,0,canvas.width,canvas.height).data;

// fast part
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (pixels[idx]) { // alpha > 0
  ...
}

Vorteile

  • Sie können alles, was Sie erkennen wollen, da Sie nur die Kontext Methoden zu wiederholen. Dies funktioniert mit PNG alpha, verrückt Verbindung Formen, Text, etc.
  • Wenn Ihr Bild ziemlich statisch ist, dann müssen Sie nur dieses ein Mal pro Gebiet von Interesse tun.
  • Der „Maske“ ist langsam, aber das Pixel aufzublicken ist spottbillig. So ist der „schnelle Teil“ ist für die Mouseover-Erkennung.

Nachteile

  • Dies ist ein Speicher Schwein. Jede Maske ist W * H * 4 Werte. Wenn Sie einen kleinen Leinwand-Bereich oder wenige Bereiche zu maskieren haben, ist es nicht so schlimm. Verwenden Sie Chrome Task-Manager Speichernutzung zu überwachen.
  • Es ist ein bekanntes Problem mit getImageData in Chrome und Firefox. Die Ergebnisse sind nicht Müll sofort erhoben, wenn Sie die Variable zunichte machen, so dass, wenn Sie dies auch häufig tun, werden Sie Speicher steigen schnell sehen. Es geht schließlich Müll gesammelt und es sollte den Browser nicht abstürzen, aber es kann auf Maschinen mit geringen Mengen an RAM besteuern.

A Hack speichern Speicher

Anstatt das gesamte Array zu speichern Imagedata, können wir nur daran erinnern, Alpha-Werte, welche Pixel haben. Es spart viel Speicher, fügt aber hinzu, um eine Schleife zu dem Maskenprozess.

var mask = {};
var len = pixels.length;
for (var i=3;i<len;i+=4) if ( pixels[i] ) mask[i] = 1;

// this works the same way as the other method
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (mask[idx]) {
  ...
}

Dies könnte die Methode ctx.isPointInPath erfolgen verwenden, aber es ist in excanvas für IE nicht implementiert. Aber eine andere Lösung wäre es, HTML-Karten zu verwenden, wie ich für diese kleine Bibliothek haben: http :. //phenxdesign.net/projects/phenx-web/graphics/example.htm Inspiration von ihm zu bekommen, aber es ist immer noch ein wenig Buggy

Ich würde vorschlagen, ein Bild Karte mit der richtigen Koordinaten festgelegt auf die Bereiche überlagern Ihre Leinwand-gezeichneten Elemente anzupassen. Auf diese Weise, Sie Tooltips erhalten und eine ganze Menge anderer DOM / Browser-Funktionalität kostenlos.

Ich brauchte Mausklicks für ein Raster von Quadraten (wie Zellen einer Excel-Tabelle) zu tun erkennen. Zur Beschleunigung it up, teilte ich das Gitter in Regionen rekursiv zu halbieren, bis eine kleine Anzahl von Zellen blieb, zum Beispiel für ein 100x100 Gitter, wobei die ersten vier Regionen könnten die 50x50 Gitter sein, die die vier Quadranten. Diese könnten dann in einem weiteren 4 jeweils (daher 16 Regionen von 25x25 jedem ergibt) unterteilt werden. Dies erfordert eine kleine Anzahl von Vergleichen und schließlich kann das 25x25 Raster für jede Zelle (625 Vergleiche in diesem Beispiel) getestet werden.

Es gibt ein Buch von Eric Rowell dem Namen "HTML5-Canvas-Kochbuch". In diesem Buch gibt es ein Kapitel namens „mit der Leinwand-Interacting: Anbringen Ereignis-Listener an Formen und Regionen“. mousedown-, mouseup, Mouseover, mouseout, mousemove-, Berührungsstart, touchend und Berührungsbewegungsereignisse umgesetzt werden können. Ich schlage vor, Sie dringend, lesen.

Das kann nicht (zumindest nicht so leicht) durchgeführt werden, da Objekte, die Sie auf der Leinwand (Pfade) ziehen nicht als die gleichen Objekte in der Leinwand dargestellt. Was ich meine ist, dass es nur ein einfacher 2D-Kontext ist, und wenn Sie etwas auf sie gezogen, es vergisst völlig, wie sie gezogen wurde. Es ist nur ein Satz von Pixeln für sie.

Um Mouseover- und die Gleichen für sie zu sehen, müssen Sie irgendeine Art von Vektorgrafiken Leinwand, dass SVG oder Ihre eigene Implementierung auf vorhandenen (was Sam Hasler vorgeschlagen)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top