pvbrowser manual
Back Content Forward

SVG графики

A Scalable Vector Graphic е XML спецификация и файлов формат за описване на статични и динамични двуизмерни векторни графики Има отворен стандарт, създаден от SVG работна група на W3C.

<?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 примерен код

Може да създавате SVG графики със специализирани програми като Inkscape или да използвате конвертор, за да преобразувате други формати като DXF от CAD програми към SVG.

Можете да използвате тези графики в pvbrowser. Просто добавете Draw/SVG елемент и използвайте rlSvgAnimator за визуализиране и анимиране на графиката. Използвайки този клас, графиката ще бъде изпратена от вашия pvserver до pvbrowser клиента. След като графиката е заредена в pvbrowser клиента, rlSvgAnimator може да бъде използван, за да се промени (анимира). Вашият pvserver ще получава събития, когато щраквате върку обекти от SVG графиката. Ще получите и някой събития от мишката.

Следният код показва как да се зареди SVG графика в pvbrowser клиент и да се визуализира.

//
// 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;
}

Следните методи на класа rlSvgAnimator се използват за промяна и анимиране на заредената SVG графика.

int svgPrintf(const char *objectname, const char *tag, const char *format, ...);
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);

Името на обекта се използва за обръщение към графичен обект в SVG ( id="objectname" ) от графиката. Използвайки SVG графична програма, потребителят може да променя id-то както желае.

Текстов обект може да бъде променян по следния начин.

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

Графичен обект може да бъде скриван или показван.

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

Всяко свойство на обекта може да бъде променяно.

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

Можете да определяте трансформиращата матрица на обект. (промяна/въртене/мащаб)

// sx    := мащабиращ фактор
// alpha := ъгъл на въртене в радиани
// x0,y0 := позиция
// cx,cy := център на въртене
d->svgAnimator.setMatrix(const char *objectname, float sx, float alpha, float x0, float y0, float cx, float cy);
// или
d->svgAnimator.setMatrix(const char *objectname, rlSvgPosition &pos);

rlSvgPosition е дефиниран по следния начин.

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);
};

Първоначално rlSvgPozition е инициализиран, с непроменена матрица (без преместване, без въртене, мащаб 1.0).

След променяне на всички обекти в SVG графиката, трябва да я преначертаете използвайки функцията "drawSVG(p,svgExample,d);".

Когато използвате маската над SVG графика, ще получите събития за следните функции.

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;
}

Ако искате да получавате събитие, когато потребителя щракне на графичен обект, то id-то му трябва да започва с "@".

Пример: id="@testclick"

Тогава функцията "slotTextEvent(PARAM *p, int id, DATA *d, const char *text)" ще бъде извикана.

slotTextEvent не се използва само в случай на щракване. Има други случаи, които завършват като такова събитие. Затова предоставяме функционалност за парсиране на текста вътре в slotTextEvent.

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))" ще разпознае всички възможни събития.

Случаят "case SVG_BOUNDS_ON_ELEMENT:" възниква в случай на извикването на

pvRequestSvgBoundsOnElement(p, svgExample, "testobject");

с която можете да поискате геометричната информация на графичен обект от SVG графиката.

"svgObjectName(text)" ще извлече името на SVG обекта от текстово събитие.

Използване на метода

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

от rlSvgAnimator заменяте компонентите на свойствата. Това е полезно например ако желаете да промените части от свойството style.

Допълнително има методи за рекурсивна работа върху групирани графични обекти.

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);

Методът

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

който изпраща SVG графиката към браузъра има опционален параметър "inifile". Ако го използвате, той ще бъде запълнен със свойствата от SVG графиката. Свойствата id от SVG съответстват на имената на секции във файла "inifile" Предложение: Можете да вкарате собствени свойства като your:tag="примерна стойност" в SVG, които не се интерпретират от рендера. Тези свойства могат да се използват свободно от програмата ви.

Ето някои примери:

Прост SVG
Прост SVG
Механична визуализация
Механична визуализация
SVG на процес
SVG на процес
SVG с движещи се обекти и плъзгачи
SVG с движещи се обекти и плъзгачи

Първите 2 примера са от сървъра pvsexample, включен в pvbrowser. Последния пример може да бъде свален от тук .


Back Content Forward