2010-05-08 9 views
4

Je dessine un graphique en utilisant Cairo (pycairo en particulier) et j'ai besoin de savoir comment dessiner un texte dans un cercle sans le superposer, en le maintenant dans les limites du cercle. J'ai ce simple extrait de code qui dessine une lettre « a » à l'intérieur du cercle:Comment garder du texte dans un cercle en utilisant Cairo?

''' 
Created on May 8, 2010 

@author: mrios 
''' 
import cairo, math 

WIDTH, HEIGHT = 1000, 1000 

#surface = cairo.PDFSurface ("/Users/mrios/Desktop/exampleplaces.pdf", WIDTH, HEIGHT) 
surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, WIDTH, HEIGHT) 
ctx = cairo.Context (surface) 

ctx.scale (WIDTH/1.0, HEIGHT/1.0) # Normalizing the canvas 


ctx.rectangle(0, 0, 1, 1) # Rectangle(x0, y0, x1, y1) 
ctx.set_source_rgb(255,255,255) 
ctx.fill() 

ctx.arc(0.5, 0.5, .4, 0, 2*math.pi) 
ctx.set_source_rgb(0,0,0) 
ctx.set_line_width(0.03) 
ctx.stroke() 

ctx.arc(0.5, 0.5, .4, 0, 2*math.pi) 
ctx.set_source_rgb(0,0,0) 
ctx.set_line_width(0.01) 
ctx.set_source_rgb(255,0,255) 
ctx.fill() 
ctx.set_source_rgb(0,0,0) 

ctx.select_font_face("Georgia", 
      cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) 
ctx.set_font_size(1.0) 
x_bearing, y_bearing, width, height = ctx.text_extents("a")[:4] 
print ctx.text_extents("a")[:4] 
ctx.move_to(0.5 - width/2 - x_bearing, 0.5 - height/2 - y_bearing) 
ctx.show_text("a") 

surface.write_to_png ("/Users/mrios/Desktop/node.png") # Output to PNG 

Le problème est que mes étiquettes ont quantité variable de caractères (avec une limite de 20) et je dois définir la taille la police dynamiquement. Il doit s'adapter à l'intérieur du cercle, peu importe la taille du cercle ou la taille de l'étiquette. En outre, chaque étiquette a une ligne de texte, pas d'espaces, pas de sauts de ligne.

Une suggestion?

+0

P.S. Vous devriez utiliser des flottants (0-1.0) lors de l'appel de set_source_rgb(). Voir http://cairographics.org/documentation/pycairo/2/reference/context.html#class-context – dkamins

Répondre

3

J'ai eu un problème similaire, où j'ai besoin d'ajuster la taille de la police pour garder le nom de mon objet dans les limites des rectangles, pas des cercles. J'ai utilisé une boucle while, et j'ai continué à vérifier la taille de l'extension de texte de la chaîne, en diminuant la taille de la police jusqu'à ce que cela corresponde.

Voici ce que j'ai fait: (ceci utilise C++ sous Kylix, une dérivée Delphi).

double fontSize = 20.0; 
    bool bFontFits = false; 

    while (bFontFits == false) 
    { 
     m_pCanvas->Font->Size = (int)fontSize; 
     TSize te = m_pCanvas->TextExtent(m_name.c_str()); 
     if (te.cx < (width*0.90)) // Allow a little room on each side 
     { 
      // Calculate the position 
      m_labelOrigin.x = rectX + (width/2.0) - (te.cx/2); 
      m_labelOrigin.y = rectY + (height/2.0) - te.cy/2); 
      m_fontSize = fontSize; 
      bFontFits = true; 
      break; 
     } 
     fontSize -= 1.0; 
} 

Bien sûr, cela ne montre pas la vérification des erreurs. Si le rectangle (ou votre cercle) est trop petit, vous devrez sortir de la boucle.

3

Étant donné que la taille du cercle n'a pas d'importance, vous devez les dessiner dans l'ordre inverse de votre code.

  1. Imprimer le texte sur l'écran
  2. Calculer les limites de texte (en utilisant des degrés de texte)
  3. dessiner un cercle autour du texte qui est juste un peu plus grand du texte.