Placera, skala och rotera en bild. Matriser och musrörelser
Det aktiva koordinatsystemet i Context har vi precis visat går att manipulera. (translate, rotate och scale). Det gör att de positioner, koordinater, som vi får från musrörelser är relaterade till webbläsarens fönster eller canvasens mått, inte till det koordinatsystem som just nu är aktuellt i context. Krångligt, javisst!
Låt oss kolla lite på matematiken bakom metoderna translate, scale och rotate. När man pratar koordinater och vektorer hamnar man förr eller senare i matrisernas värld. I HTML5 SVG/Canvas-världen är det ändå rätt enkelt eftersom vi bara har två dimensioner, x och y. Bakom metoderna döljer sig inget annat än en så kallad transform (avbildning), en speciell matris som man multiplicerar med koordinaterna (som ju kan skrivas på matrisform ) för att få fram en ny koordinat med egenskaper från transformmatrisen. I grafiksammanhang använder man transformer av typen ”Affina transformer” denna typ har fördelen att den enkelt hanterar räta linjer. Man gör det genom att lägga till en extra dimension och alltid sätta den till 1.
En enhetsmatris, en matris som inte påverkar resultatet, ser ut så här:
I den Affina transformationen blir den matematiska tolkningen av förflyttning, translate, tx och ty.
Samma för en skalning av axlarna, sx och sy.
Rotation är lite svårare eftersom den relativt det yttre koordinatsystemet påverkar båda axlarna.
Skevning av koordinatsystemet, icke rätvinkligt system får man genom
De 6 positionerna som ändras brukar benämnas a, b, c, d, e, f eller i vektorform
När man jobbar med transformmatriser i javascript är det på denna form man får den tillgänglig via objekttyper som heter DOMMatrix eller SVGmatrix beroende på webbläsare. Stödet för att ändra i transformmatrisen är än så länge begränsat i många webbläsare. Parametrarna är enklast tillgängliga via metoderna translate, rotate och scale. Alla webbläsare har heller inte implementerat samma och alla metoder som finns i utkasten till standard.
Musrörelser och koordinater
I ett av exemplen flyttade vi en grön kvadrat över canvas genom att radera (clearRect()) och måla kvadraten en bit åt höger vid varje iteration. Vi ska nu titta på hur vi kan göra en förflyttning med hjälp av musrörelser, drag n’ drop. Lägg till två eventlistners på mousedown resp mouseup. En variabel, moveStart håller reda på startpunkten.
Lägg särskilt märke till hur vi i denna kod måste radera (clearRect()) canvas från det vi tidigare målat. (Här raderar vi hela canvas för att visa metoderna save(), restore() och setTransform() . Save() sparar transformmatrisen (typ ”push”) och restore() lägger tillbaka (”pop”). setTransform() utan parameter sätter transformen till enhetsmatrisen ( ). Det koden mellan kommentarmärkena gör är alltså:
- Spara transformen
- Nollställ contexten (nollställ vridningar, skalning och sätt origo till canvas (0,0)
- Radera en rektangel lika stor som canvas
- Lägg tillbaka transformen (med tidigare värden)
Det koordinatsystem som glaset målas i är inte det samma som vi raderar i.
Nu kan vi flytta runt glaset på canvas från en punkt till en annan genom att klicka, dra och släppa.
Lägg till visning av bilden under dragningen
Lägg till en eventListner för mousemove och flytta koden som raderar och målar upp glaset till den nya funktionen.
När vi nu flyttar glaset följer bilden med i rörelsen tills vi släpper. (Eventet mouseleave stoppar också förflyttningen.)
Funktionalitet för att rotera och zooma.
Vi lägger till några knappar för att även kunna ändra rotationen och zoomningen i bilden.
Nu har vi alla delar för att kunna bygga en enkel bildvisare med Panorering, Rotation och Zoomning med hjälp av HTML 5 och Canvas.
Den färdiga lösningen
Den lösning som levererats till kund är kompletterad med kod för att centrera bilden, zoomning och vridning sker kring centrum av bilden. Man kan även zoom med musens scrollhjul. Zoomningen sker då med muspekaren som centrum.
Detta komplicerar koden en del då vi inte bara behöver hålla reda på aktuell position, rotation och skalning utan även bildens storlek i den aktuella skalan och rotationen för att beräkna bildens centrum i koordinatsystemet.
Några länkar
Allmänt om Canvas API
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
Några exempel på stackoverflow, det finns många ofta länkade.
https://stackoverflow.com/questions/5189968/zoom-canvas-to-mouse-cursor/5526721
En bra implementation av context tracking och koordinatkonvertering
https://gist.github.com/dzhang123/2a3a611b3d75a45a3f41
Enkla exempel på w3schools
https://www.w3schools.com/tags/ref_canvas.asp
W3C Working draft Canvas 2D Context