La transformation de traduction
Découvrez comment utiliser la transformation de traduction pour décaler les graphiques SkiaSharp
Le type de transformation le plus simple dans SkiaSharp est la transformation de traduction ou de traduction . Cette transformation déplace les objets graphiques dans les directions horizontales et verticales. Dans un sens, la traduction est la transformation la plus inutile, car vous pouvez généralement accomplir le même effet en modifiant simplement les coordonnées que vous utilisez dans la fonction de dessin. Toutefois, lors du rendu d’un chemin, toutes les coordonnées sont encapsulées dans le chemin. Il est donc beaucoup plus facile d’appliquer une transformation de traduction pour déplacer l’intégralité du chemin.
La traduction est également utile pour l’animation et pour les effets de texte simples :
La Translate
méthode présente SKCanvas
deux paramètres qui entraînent le déplacement horizontal et vertical des objets graphiques dessinés par la suite :
public void Translate (Single dx, Single dy)
Ces arguments peuvent être négatifs. Une deuxième Translate
méthode combine les deux valeurs de traduction dans une seule SKPoint
valeur :
public void Translate (SKPoint point)
La page Traduction cumulée de l’exemple de programme montre que plusieurs appels de la Translate
méthode sont cumulatifs. La AccumulatedTranslatePage
classe affiche 20 versions du même rectangle, chaque décalage du rectangle précédent suffit pour qu’ils s’étendent le long de la diagonale. Voici le PaintSurface
gestionnaire d’événements :
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint strokePaint = new SKPaint())
{
strokePaint.Color = SKColors.Black;
strokePaint.Style = SKPaintStyle.Stroke;
strokePaint.StrokeWidth = 3;
int rectangleCount = 20;
SKRect rect = new SKRect(0, 0, 250, 250);
float xTranslate = (info.Width - rect.Width) / (rectangleCount - 1);
float yTranslate = (info.Height - rect.Height) / (rectangleCount - 1);
for (int i = 0; i < rectangleCount; i++)
{
canvas.DrawRect(rect, strokePaint);
canvas.Translate(xTranslate, yTranslate);
}
}
}
Les rectangles successifs se déplacent vers le bas de la page :
Si les facteurs de traduction cumulés sont dx
et dy
le point que vous spécifiez dans une fonction de dessin est (x
, y
), l’objet graphique est rendu au point (x'
, ), y'
où :
x' = x + dx
y' = y + dy
Il s’agit des formules de transformation pour la traduction. Les valeurs par défaut et dx
dy
pour une nouvelle SKCanvas
valeur sont 0.
Il est courant d’utiliser la transformation de traduction pour les effets d’ombre et des techniques similaires, comme le montre la page Traduire des effets de texte. Voici la partie pertinente du PaintSurface
gestionnaire dans la TranslateTextEffectsPage
classe :
float textSize = 150;
using (SKPaint textPaint = new SKPaint())
{
textPaint.Style = SKPaintStyle.Fill;
textPaint.TextSize = textSize;
textPaint.FakeBoldText = true;
float x = 10;
float y = textSize;
// Shadow
canvas.Translate(10, 10);
textPaint.Color = SKColors.Black;
canvas.DrawText("SHADOW", x, y, textPaint);
canvas.Translate(-10, -10);
textPaint.Color = SKColors.Pink;
canvas.DrawText("SHADOW", x, y, textPaint);
y += 2 * textSize;
// Engrave
canvas.Translate(-5, -5);
textPaint.Color = SKColors.Black;
canvas.DrawText("ENGRAVE", x, y, textPaint);
canvas.ResetMatrix();
textPaint.Color = SKColors.White;
canvas.DrawText("ENGRAVE", x, y, textPaint);
y += 2 * textSize;
// Emboss
canvas.Save();
canvas.Translate(5, 5);
textPaint.Color = SKColors.Black;
canvas.DrawText("EMBOSS", x, y, textPaint);
canvas.Restore();
textPaint.Color = SKColors.White;
canvas.DrawText("EMBOSS", x, y, textPaint);
}
Dans chacun des trois exemples, Translate
on appelle l’affichage du texte pour le décaler de l’emplacement donné par les variables et y
les x
variables. Ensuite, le texte s’affiche à nouveau dans une autre couleur sans effet de traduction :
Chacun des trois exemples montre un moyen différent de négation de l’appel Translate
:
Le premier exemple appelle Translate
simplement à nouveau, mais avec des valeurs négatives. Étant donné que les Translate
appels sont cumulatifs, cette séquence d’appels restaure simplement la traduction totale en valeurs par défaut de zéro.
Le deuxième exemple appelle ResetMatrix
. Ainsi, toutes les transformations retournent à leur état par défaut.
Le troisième exemple enregistre l’état de l’objet SKCanvas
avec un appel, Save
puis restaure l’état avec un appel à Restore
. Il s’agit de la façon la plus polyvalente de manipuler des transformations pour une série d’opérations de dessin. Ces Save
fonctions et Restore
appellent comme une pile : vous pouvez appeler plusieurs fois, puis appeler Restore
Save
dans la séquence inverse pour revenir aux états précédents. La Save
méthode retourne un entier et vous pouvez passer cet entier pour RestoreToCount
appeler Restore
efficacement plusieurs fois. La SaveCount
propriété retourne le nombre d’états actuellement enregistrés sur la pile.
Vous pouvez également utiliser la SKAutoCanvasRestore
classe pour restaurer l’état du canevas. Le constructeur de cette classe est destiné à être appelé dans une using
instruction ; l’état du canevas est automatiquement restauré à la fin du using
bloc.
Toutefois, vous n’avez pas à vous soucier des transformations qui passent d’un appel du PaintSurface
gestionnaire à l’autre. Chaque nouvel appel pour PaintSurface
remettre un objet frais SKCanvas
avec des transformations par défaut.
Une autre utilisation courante de la transformation consiste à restituer un objet visuel qui a été créé à l’origine Translate
à l’aide de coordonnées pratiques pour le dessin. Par exemple, vous pouvez spécifier des coordonnées pour une horloge analogique avec un centre au point (0, 0). Vous pouvez ensuite utiliser des transformations pour afficher l’horloge où vous le souhaitez. Cette technique est illustrée dans la page [Hendecagram Array]. La HendecagramArrayPage
classe commence par créer un SKPath
objet pour une étoile à 11 pointes. L’objet HendecagramPath
est défini comme public, statique et en lecture seule afin qu’il soit accessible à partir d’autres programmes de démonstration. Il est créé dans un constructeur statique :
public class HendecagramArrayPage : ContentPage
{
...
public static readonly SKPath HendecagramPath;
static HendecagramArrayPage()
{
// Create 11-pointed star
HendecagramPath = new SKPath();
for (int i = 0; i < 11; i++)
{
double angle = 5 * i * 2 * Math.PI / 11;
SKPoint pt = new SKPoint(100 * (float)Math.Sin(angle),
-100 * (float)Math.Cos(angle));
if (i == 0)
{
HendecagramPath.MoveTo(pt);
}
else
{
HendecagramPath.LineTo(pt);
}
}
HendecagramPath.Close();
}
}
Si le centre de l’étoile est le point (0, 0), tous les points de l’étoile se trouvent sur un cercle entourant ce point. Chaque point est une combinaison de valeurs de sinus et de cosinus d’un angle qui augmente de 5/11e de 360 degrés. (Il est également possible de créer une étoile à 11 pointes en augmentant l’angle par 2/11e, 3/11e ou 4/11e du cercle.) Le rayon de ce cercle est défini sur 100.
Si ce chemin d’accès est rendu sans transformation, le centre est positionné en haut à gauche du coin supérieur gauche, SKCanvas
et seul un quart de celui-ci sera visible. Le PaintSurface
gestionnaire d’utilisation à HendecagramPage
la place pour Translate
vignetter le canevas avec plusieurs copies de l’étoile, chacun d’eux couleur aléatoire :
public class HendecagramArrayPage : ContentPage
{
Random random = new Random();
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
for (int x = 100; x < info.Width + 100; x += 200)
for (int y = 100; y < info.Height + 100; y += 200)
{
// Set random color
byte[] bytes = new byte[3];
random.NextBytes(bytes);
paint.Color = new SKColor(bytes[0], bytes[1], bytes[2]);
// Display the hendecagram
canvas.Save();
canvas.Translate(x, y);
canvas.DrawPath(HendecagramPath, paint);
canvas.Restore();
}
}
}
}
Voici le résultat :
Les animations impliquent souvent des transformations. La page Animation hendecagram déplace l’étoile à 11 pointes autour d’un cercle. La HendecagramAnimationPage
classe commence par certains champs et remplacements des OnAppearing
méthodes OnDisappearing
pour démarrer et arrêter un Xamarin.Forms minuteur :
public class HendecagramAnimationPage : ContentPage
{
const double cycleTime = 5000; // in milliseconds
SKCanvasView canvasView;
Stopwatch stopwatch = new Stopwatch();
bool pageIsActive;
float angle;
public HendecagramAnimationPage()
{
Title = "Hedecagram Animation";
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
protected override void OnAppearing()
{
base.OnAppearing();
pageIsActive = true;
stopwatch.Start();
Device.StartTimer(TimeSpan.FromMilliseconds(33), () =>
{
double t = stopwatch.Elapsed.TotalMilliseconds % cycleTime / cycleTime;
angle = (float)(360 * t);
canvasView.InvalidateSurface();
if (!pageIsActive)
{
stopwatch.Stop();
}
return pageIsActive;
});
}
protected override void OnDisappearing()
{
base.OnDisappearing();
pageIsActive = false;
}
...
}
Le angle
champ est animé de 0 degrés à 360 degrés toutes les 5 secondes. Le PaintSurface
gestionnaire utilise la angle
propriété de deux façons : pour spécifier la teinte de la couleur dans la SKColor.FromHsl
méthode, et comme argument pour les méthodes et Math.Cos
pour Math.Sin
régir l’emplacement de l’étoile :
public class HendecagramAnimationPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.Translate(info.Width / 2, info.Height / 2);
float radius = (float)Math.Min(info.Width, info.Height) / 2 - 100;
using (SKPaint paint = new SKPaint())
{
paint.Style = SKPaintStyle.Fill;
paint.Color = SKColor.FromHsl(angle, 100, 50);
float x = radius * (float)Math.Sin(Math.PI * angle / 180);
float y = -radius * (float)Math.Cos(Math.PI * angle / 180);
canvas.Translate(x, y);
canvas.DrawPath(HendecagramPage.HendecagramPath, paint);
}
}
}
Le PaintSurface
gestionnaire appelle la Translate
méthode deux fois, d’abord pour se traduire au centre du canevas, puis pour traduire vers la circonférence d’un cercle centré autour (0, 0). Le rayon du cercle est aussi grand que possible tout en conservant l’étoile dans les limites de la page :
Notez que l’étoile conserve la même orientation qu’elle tourne autour du centre de la page. Il ne fait pas pivoter du tout. C’est un travail pour une transformation de rotation.