pvbrowser manual
Zurück Inhalt Vor

SVG Grafiken

Die Scalable Vector Graphic ist eine XML Spezifikation und ein Dateiformat, um zwei-dimensionale Vector Grafiken zu beschreiben, sowohl statisch als auch animiert. Es ist ein offener Standard, der vom der W3C SVG Working Group erstellt wurde.

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
   "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 <svg xmlns="http://www.w3.org/2000/svg"
      width="1000"
      height="600"
      viewBox="0 0 5 5">
    <rect id="black_stripe"
          fill="#000"
          width="5"
          height="1"/>
    <rect id="gray_i"
          fill="#444"
          width="5"
          height="1" y="1"/>
    <rect id="gray_ii"
          fill="#888"
          width="5"
          height="1" y="2"/>
    <rect id="gray_iii"
          fill="#ccc"
          width="5"
          height="1" y="3"/>
    <rect id="white"
          fill="#fff"
          width="5"
          height="1" y="4"/>
 </svg>
SVG Beispiel Code

SVG Grafiken können mit darauf spezialisierten Zeichenprogrammen, wie Inkscape erstellt werden. Alternativ kann man auch Konverter verwenden, die CAD Formate wie DXF in SVG umwandeln.

Diese Grafiken können nun in pvbrowser verwendet werden. Fügen Sie einfach ein Draw/SVG Widget ein und benutzen rlSvgAnimator , um die Grafik zu zeichen und zu animieren. Unter Verwendung dieser Klasse wird die SVG Grafik vom Server zum pvbrowser Client gesendet. Wenn die Grafik erst einmal im pvbrowser Client ist, wird rlSvgAnimator verwendet, um die Grafik zu verändern (animieren). Der Server empfängt Ereignisse, wenn Sie Objekte der SVG Grafik anclicken. Darüber hinaus werden einige Maus Ereignisse gesendet.

Der folgende Code zeigt, wie eine SVG Grafik in den pvbrowser Client geladen und dann gezeichnet wird.

//
// this is extracted from a maskX_slot.h file
//

typedef struct // (todo: define your data structure here)
{
  rlSvgAnimator svgAnimator;
  // further members ...
}
DATA;

static int drawSVG(PARAM *p, int id, DATA *d)
{
  if(d == NULL) return -1;
  gBeginDraw(p,id);
  d->svgAnimator.writeSocket();
  gEndDraw(p);
  return 0;
}

static int slotInit(PARAM *p, DATA *d)
{
  if(p == NULL || d == NULL) return -1;

  // load svg into pvbrowser client
  d->svgAnimator.setSocket(&p->s);           // register the socket
  d->svgAnimator.setId(svgExample);          // set the id of the widget
  d->svgAnimator.read("img/myExample.svg");  // load a svg file into pvbrowser client

  // set the zoom factor (negative values -> keep aspect ratio)
  pvSetZoomX(p, svgExample, -1.0f);
  pvSetZoomY(p, svgExample, -1.0f);

  // draw svg
  drawSVG(p,svgExample,d);

  return 0;
}

Wenn Sie die SVG Grafik erst einmal geladen haben und in der Lage sind, sie neu zu zeichnen, können Sie die Grafik animieren (verändern), indem Sie rlSvgAnimator verwenden. Die folgenden Methoden von rlSvgAnimator werden dazu benutzt.

int svgPrintf(const char *objectname, const char *tag, const char *format, ...);
int svgRecursivePrintf(const char *objectname, const char *tag, const char *format, ...);
int svgSearchAndReplace(const char *objectname, const char *tag, const char *before, const char *after);
                                                                // before kann wildcards enthalten
int svgRecursiveSearchAndReplace(const char *objectname, const char *tag, const char *before, const char *after);
                                                                // before kann wildcards enthalten
int svgTextPrintf(const char *objectname, const char *format, ...);
int show(const char *objectname, int state); // state := 0|1
int setMatrix(const char *objectname, float sx, float alpha, float x0, float y0, float cx, float cy);
int setMatrix(const char *objectname, rlSvgPosition &pos);

Der Objektname wird benutzt, um die graphischen Objekte in SVG zu adressieren ( id="objectname" ). Mit dem SVG Zeichenprogramm, kann man die id wie gewünscht setzen.

Einen Text kann man wie folgt verändern.

d->svgAnimator.svgTextPrintf("HelloObject", "Hello World");

Ebenso kann das Objekt versteckt oder wieder angezeigt werden.

d->svgAnimator.show("HelloObject", 0); // hide HelloObject
d->svgAnimator.show("HelloObject", 1); // show HelloObject

Beliebige Eigenschaften des Objektes können verändert werden.

d->svgAnimator.svgPrintf("HelloObject", "fill=", "#000"); // set a property

Die Transformationsmatrix eines Objektes kann geändert werden. (verschieben/rotieren/skalieren)

// sx    := scale factor
// alpha := rotation angle in radiant
// x0,y0 := position
// cx,cy := position around which to rotate
d->svgAnimator.setMatrix(const char *objectname, float sx, float alpha, float x0, float y0, float cx, float cy);
// or using
d->svgAnimator.setMatrix(const char *objectname, rlSvgPosition &pos);

rlSvgPosition ist wie folgt definiert.

class rlSvgPosition
{
  public:
    rlSvgPosition();
    rlSvgPosition(float sx_init, float a_init, float x0_init, float y0_init, float cx_init, float cy_init);
    virtual ~rlSvgPosition();
    float sx, alpha, x0, y0, cx, cy;
    struct rlPositionInit {float sx, alpha, x0, y0, w, h;} init;
    void setInit(float x0_init, float y0_init, float w_init, float h_init);
    void move(float x, float y);
    void moveRelative(float dx, float dy);
    void scale(float s);
    void scaleRelative(float ds);
    void rotate(float alpha, float cx, float cy);
};

Nach dem Anlegen einer Instanz von rlSvgPosition ist die Matrix auf die Werte der Identitätsmatrix gesetzt (keine Verschiebung, keine Rotation, Skalierungsfaktor 1.0).

Nachdem alle Objekte in der SVG Grafik wie gewünscht modifiziert worden sind, muss sie neu gezeichnet werden, "drawSVG(p,svgExample,d);" wie schon oben gezeigt.

Wenn man die Maus oberhalb der SVG Grafik benutzt, bekommt der Server die folgenden Ereignisse in den dazugehörigen slot Funktionen.

static int slotMouseMovedEvent(PARAM *p, int id, DATA *d, float x, float y)
{
  if(p == NULL || id == 0 || d == NULL || x < -1000 || y < -1000) return -1;
  return 0;
}

static int slotMousePressedEvent(PARAM *p, int id, DATA *d, float x, float y)
{
  if(p == NULL || id == 0 || d == NULL || x < -1000 || y < -1000) return -1;
  return 0;
}

static int slotMouseReleasedEvent(PARAM *p, int id, DATA *d, float x, float y)
{
  if(p == NULL || id == 0 || d == NULL || x < -1000 || y < -1000) return -1;
  return 0;
}

Falls Sie ein Ereignis haben wollen, wenn ein graphisches Objekt in der SVG Grafik angeclickt wird, muss die id des Objektes mit "@" beginnen.

Beispiel: id="@testclick"

Dann wird "slotTextEvent(PARAM *p, int id, DATA *d, const char *text)" aufgerufen.

Wenn der Name mit 2 @ beginnt id="@@textclick" wird pvbrowser eine visuelle Rückkopplung geben, indem sich der Maus Cursor in ein Qt::PointingHandCursor verwandelt, wenn der Benutzer die Maus über das Objekt führt. Damit lassen sich beispielsweise "Buttons" mit visueller Rückkopplung erzeugen.

slotTextEvent wird nicht nur für dieses Click Ereignis benutzt, sondern es gibt mehrere Funktionen, die slotTextEvent auslösen. Dafür gibt es ein paar Hilfsfunktionen, die den Text entsprechend interpretieren.

static int slotTextEvent(PARAM *p, int id, DATA *d, const char *text)
{
  float x,y,w,h;

  if(p == NULL || id == 0 || d == NULL || text == NULL) return -1;
  switch(textEventType(text))
  {
    case PLAIN_TEXT_EVENT:
      printf("plain\n");
      break;
    case SVG_LEFT_BUTTON_PRESSED:
      printf("left pressed %s\n", svgObjectName(text));
      break;
    case SVG_MIDDLE_BUTTON_PRESSED:
      printf("middle pressed %s\n", svgObjectName(text));
      break;
    case SVG_RIGHT_BUTTON_PRESSED:
      printf("right pressed %s\n", svgObjectName(text));
      break;
    case SVG_LEFT_BUTTON_RELEASED:
      printf("left released %s\n", svgObjectName(text));
      break;
    case SVG_MIDDLE_BUTTON_RELEASED:
      printf("middle released %s\n", svgObjectName(text));
      break;
    case SVG_RIGHT_BUTTON_RELEASED:
      printf("right released %s\n", svgObjectName(text));
      break;
    case SVG_BOUNDS_ON_ELEMENT:
      getSvgBoundsOnElement(text, &x, &y, &w, &h);
      printf("bounds object=%s xywh=%f,%f,%f,%f\n",svgObjectName(text),x,y,w,h);
      break;
    default:
      printf("default\n");
      break;
  }
  return 0;
}

"switch(textEventType(text))" detektiert die möglichen Ereignisse.

"case SVG_BOUNDS_ON_ELEMENT:" ist eine Antwort auf

pvRequestSvgBoundsOnElement(p, svgExample, "testobject");

mit welchem man die Geometrie des einschliessenden Rahmens eines Objektes in der SVG Grafik erfragen kann.

"svgObjectName(text)" extrahiert den Objektnamen aus dem Text von slotTextEvent().

Mit der Methode

int svgSearchAndReplace(const char *objectname, const char *tag, const char *before, const char *after);

aus rlSvgAnimator kann man Bestandteile von Eigenschaften ersetzen. Dies ist z.B. nützlich, wenn man einzelne Elemente einer style Eigenschaft ersetzen möchte. Der "before" Parameter kann auch Wildcards wie * (beliebige Zeichen) ? (ein beliebiges Zeichen) enthalten.

Es stehen ausserdem Methoden zur Verfügung, mit denen man recursiv auf alle Elemente unterhalb eines graphischen Objektes arbeiten kann.

int svgRecursivePrintf(const char *objectname, const char *tag, const char *format,...);
int svgRecursiveSearchAndReplace(const char *objectname, const char *tag, const char *before, const char *after);

Bei der Methode

int read(const char *infile, rlIniFile *inifile=NULL);

,die die SVG Grafik an den Browser sendet, kann man noch einen optionalen Parameter inifile anhängen. Dieser wird dann mit den Eigenschaften in der SVG Grafik gefüllt. Dabei entsprechen die id's der graphischen Objekte den Sektionen einer Ini Datei. Tipp: Sie können eigene Eigenschaften der Form your:tag="any value" in der SVG eingeben, die nicht vom SVG Renderer interpretiert werden. Diese Eigenschaften können von Ihnen ganz nach Belieben verwendet werden.

Zum Zoomen und Verschieben der gesamten SVG Grafik benutzen Sie bitte folgende Methoden:

int setMainObject(const char *main_object); // set get MainObject name
const char *mainObject();
int setXY0(float x0, float y0);             // set/get origin
float x0();
float y0();
int setMouseXY0(float x0, float y0);        // set/get mouse position 0 for the MainObject
float mouseX0();
float mouseY0();
int setMouseXY1(float x1, float y1);        // set/get mouse position 1 for the MainObject
float mouseX1();
float mouseY1();
int setScale(float scale);                  // set/get the scaling factor for the MainObject
float scale();
int zoomCenter(float newScale);             // zooms the whole SVG graphic keeping it centered to the viewport
int zoomRect();                             // zooms the whole SVG graphic so that the visible section is from x0,x0 to x1,y1
int setMainObjectMatrix();                  // sets the MainObject matrix according to scale,x0,y0
int setWindowSize(int width, int height);   // call this method when the widget is resized
float windowWidth();
float windowHeight();
int moveMainObject(float x, float y);       // move MainObject to position x,y

Ein Beispiel, wie diese Methoden benutzt werden ist in pvbaddon.tar.gz directory pvbaddon/templates/weblayout/ enthalten.

Hier sind ein paar Beispiele.

Eine Einfache SVG
Eine Einfache SVG
Eine mechanische Zeichnung
Eine mechanische Zeichnung
Eine SVG eines Prozesses
Eine SVG eines Prozesses
Eine SVG mit sich bewegenden Pakten auf einem Förderband
Eine SVG mit sich bewegenden Pakten auf einem Förderband

Die ersten beiden Beispiele stammen aus pvsexample, dass mit pvbrowser mitgeliefert wird. Das letzte Beispiel kann von hier heruntergeladen werden.


Zurück Inhalt Vor