CANVAS documenation
#ident "@(#)VOGLE:driver/html5.c - HTML 5.0 canvas driver"
#ident "@(#)VOGLE:author - John S. Urban"
#ident "@(#)VOGLE:version - 1.0, Dec 2007"
/*
===============================================================================
Usage Notes:
o assuming 10 units to a raster ; so a call for size 4000,4000 would create
a 400x400 pixel display surface. Default is 425x550 pixels.
o currently, only Apple, Mozilla/Firefox and Opera support a CANVAS -- this is a
preliminary specification.
o Use negative color values to specify line thickness in raster units in
this version of vogle
o making function that takes an array and draw a polyline or a polygon to make
files less verbose and to test effect on performance
Next Time:
o A line of zero length does not always print as a point even
when line terminators on; drawing a circle when a zero length line
is encountered.
o Is line weight always specified as scaled to local coordinate system size?
This would allow thickness to scale with a rescaled plot.
o Consider making JavaScript versions of the Hershey fonts so functions
can be made that print text so text strings are editable.
===============================================================================
*/
#include
#include
#include
#ifndef MINGW
#include
#include
#endif
#include
#include
#include
#include
#include "vogle.h"
extern FILE *_voutfile();
/* How to convert degrees to radians */
#ifndef PI
#define PI 3.14159265358979323844
#endif
#define d2r(x) ((x) * PI / 180.0)
#define r2d(x) ((x) * 180.0 / PI)
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define FLIPY(y) ((int)((vdevice.sizeSy)-(y)))
#define FALSE 0
#define TRUE 1
/* Assume 1000 units per inch, and default size of 4.25inx5.5in*/
/* total drawing area size in x direction */
#define CANVASYSIZE 5500
/* total drawing area size in y direction */
#define CANVASXSIZE 4250
/* scale factor for going from world coordinates to device coordinates. Make bigger to increase accuracy of vector data */
#define CANVASTORAS 10
static int points=0;
static int canvas_first_time = 1, drawn = 0, LAST_X = -1, LAST_Y = -1;/* last (x, y) drawn */
extern FILE *fp;
int CANVAS_MOVED=0;
#define CMAPSIZE 256
struct rgb_color {
unsigned short int red;
unsigned short int green;
unsigned short int blue;
};
struct rgb_color canvas_carr[CMAPSIZE];
/******************************************************************************/
static int PolyLineOpen = FALSE; /* PolyLine not open */
static int ObjectOpen = FALSE; /* Object not open */
static int curcol = 0; /* Current pen color (black) */
static int curwid = 1; /* Current pen color width */
static int curpat = 0; /* Current fill pattern*/
static int pgroup=1; /* groupid reserved for the entire page */
/******************************************************************************/
static int CANVAS_header() {
time_t tod;
#ifndef MINGW
struct utsname unstr, *un;
#endif
char *username;
struct passwd *pw;
fprintf(fp,"\n");
fprintf(fp,"\n");
time(&tod);
fprintf(fp,"\n",ctime(&tod));
fprintf(fp,"\n");
#endif
return(0);
}
/******************************************************************************/
/* change index i in the color map to the appropriate rgb value. */
int CANVAS_mapcolor(int i, int r, int g, int b) {
if (i >= CMAPSIZE || i < 0 ){
return(-1);
}
canvas_carr[i].red = (unsigned short)(r);
canvas_carr[i].green = (unsigned short)(g);
canvas_carr[i].blue = (unsigned short)(b);
return(0);
}
/******************************************************************************/
/* CANVAS_init set up the environment. Returns 1 on success. */
static int CANVAS_init(void) {
int prefx, prefy, prefxs, prefys;
int i;
int CANVAS_header();
fp = _voutfile();
if (!canvas_first_time) return(1);
CANVAS_header();
vogle_getprefposandsize(&prefx, &prefy, &prefxs, &prefys);
if (prefxs != -1 ) {
vdevice.sizeSy = prefys;
vdevice.sizeSx = prefxs;
vdevice.sizeX = vdevice.sizeY = MIN(prefys, prefxs );
} else{
vdevice.sizeSy = CANVASYSIZE; /* size in resolution rasters */
vdevice.sizeSx = CANVASXSIZE; /* size in resolution rasters */
vdevice.sizeX = vdevice.sizeY = MIN(CANVASXSIZE,CANVASYSIZE); /* current viewport to use */
}
fprintf(fp,"\n",
(float)vdevice.sizeSx/CANVASTORAS,(float)vdevice.sizeSy/CANVASTORAS,
vdevice.sizeSx,vdevice.sizeSy);
fprintf(fp,"\n");
fprintf(fp,"\n"); /* */
fprintf(fp, "\n"); /* */
fprintf(fp, "\n"); /* */
fprintf(fp, "\n"); /* */
for(ipages=0;ipages\n",
ipages+1,
(int)vdevice.sizeSx/CANVASTORAS,
(int)vdevice.sizeSy/CANVASTORAS); /* */
}
fprintf(fp, "\n"); /* */
fprintf(fp, "\n"); /* */
fprintf(fp, "\n"); /* */
fprintf(fp,"\n");
drawn = 0;
points = 0;
if (fp != stdout && fp != stderr ){
fflush(fp);
if(vdevice.writestoprocess == 2){
pclose(fp);
}else{
fclose(fp);
}
}
return (0);
}
/******************************************************************************/
/* CANVAS_draw draw to an x, y point. */
/* Note: (0, 0) is defined as the top left of the window in CANVAS. */
static int CANVAS_draw(int x, int y) {
static char linefeed[2] = {' ','\n'};
if (LAST_X != vdevice.cpVx || LAST_Y != vdevice.cpVy ){
closeline(); /* close line if required */
openObject(); /* start Object if required */
openline(); /* start line */
fprintf(fp,"ctx.beginPath();\n");
fprintf(fp, "ctx.moveTo(%d,%d);\n", vdevice.cpVx, FLIPY(vdevice.cpVy));
LAST_X=vdevice.cpVx;
LAST_Y=vdevice.cpVy;
CANVAS_MOVED=0;
points = 1;
}
openline(); /* start line if required */
if(points == 0){
fprintf(fp,"ctx.beginPath();\n");
fprintf(fp, "ctx.moveTo(%d,%d);", x ,FLIPY(y));
CANVAS_MOVED=0;
}else{
if(LAST_X!=x || LAST_Y!=y)CANVAS_MOVED=CANVAS_MOVED+1;
fprintf(fp, "%cctx.lineTo(%d,%d);", linefeed[(points % 8/7)], x ,FLIPY(y));
}
points++;
LAST_X = x;
LAST_Y = y;
drawn = 1;
return (0);
}
/******************************************************************************/
/* CANVAS_clear flush the current page without resetting the graphics state */
static int CANVAS_clear(void) {
closeline(); /* close line if required */
closeObject(); /* close Object if required */
if (drawn)
{
fprintf(fp,"ctx.restore();\n");
fprintf(fp, "}else{\n"); /* */
fprintf(fp, "alert('Your browser needs HTML CANVAS support to view this page');\n}\n"); /* */
fprintf(fp,"}// \n",pgroup); /* Page Clear, End of Page Group */
pgroup++; /* increment page id */
fprintf(fp,"function drawCanvas%d(){\n",pgroup);
fprintf(fp,"var canvas = document.getElementById(\"canvas%d\");\n", pgroup);
fprintf(fp,"if(canvas.getContext){\n");
fprintf(fp,"var ctx = canvas.getContext(\"2d\");\n");
fprintf(fp,"ctx.save();\n");
fprintf(fp,"ctx.scale(%f,%f);\n", 1.0/CANVASTORAS, 1.0/CANVASTORAS );
fprintf(fp,"ctx.lineCap='round';\n");
fprintf(fp,"ctx.lineJoin='round';\n");
}
drawn = 0;
points = 0;
CANVAS_MOVED=0;
return(0);
}
/******************************************************************************/
/*
* value sets raster line width
*/
static int CANVAS_setlw(int width) {
closeline(); /* close line if required */
closeObject(); /* close Object if required */
if ( width >= 0 ) {
curwid = width;
}
fprintf(fp,"ctx.lineWidth=%d;\n",MAX(1,vdevice.sizeX*curwid/10000));
return(0);
}
/******************************************************************************/
/* CANVAS_color change the color of the pen
* kludged so negative value sets raster line width
* if exceed allowable number of colors maybe pick a line style
* or something like a gradient fill style for fun
*/
static int CANVAS_color(int col) {
closeline(); /* close line if required */
closeObject(); /* close Object if required */
if ( col < 0 )
{
CANVAS_setlw(abs(col));
} else {
curpat = col/CMAPSIZE;
curcol = col % CMAPSIZE;
}
fprintf(fp,"ctx.fillStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
fprintf(fp,"ctx.strokeStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
return(0);
}
/******************************************************************************/
/* HTML CANVAS does not support hardware fonts directly */
static int CANVAS_font(char *fontname) {
vogle_font("futura.m");
}
/******************************************************************************/
/* CANVAS_string output a string. */
static int CANVAS_string(char *s) {
}
/******************************************************************************/
int CANVAS_char(char c){ /* CANVAS_char output a character */
char s[2];
s[0] = c;
s[1]='\0';
CANVAS_string(s);
return(0);
}
/******************************************************************************/
static int CANVAS_fill(int n, int x[], int y[]) { /* fill a polygon */
int i;
static char linefeed[2] = {' ','\n'};
closeline(); /* close line if required */
closeObject(); /* close line if required */
fprintf(fp,"// Polygon \n");
fprintf(fp,"ctx.fillStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
fprintf(fp,"ctx.strokeStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
fprintf(fp,"ctx.lineWidth=%d;\n", MAX(1,vdevice.sizeX*curwid/10000)); /* edge width */
fprintf(fp,"ctx.beginPath();\n");
fprintf(fp,"ctx.moveTo(%d,%d);\n", x[0],FLIPY(y[0]));
for (i = 1; i < n; i++)
{
fprintf(fp, "ctx.lineTo(%d,%d);%c", x[i], FLIPY(y[i]),linefeed[(i % 8/7)]);
}
/* close path */
fprintf(fp, "ctx.lineTo(%d,%d);", x[0], FLIPY(y[0]));
fprintf(fp,"ctx.fill()\n");
vdevice.cpVx = x[n - 1]; /* update current position */
vdevice.cpVy = y[n - 1];
LAST_X = vdevice.cpVx;
LAST_Y = vdevice.cpVy;
drawn = 1;
return(0);
}
/******************************************************************************/
/* no operations - do nothing but return -1 */
static int noop(void) { return(-1); }
static int noop2(int *x, int *y) { return(-1); }
/******************************************************************************/
static DevEntry canvasdev = {
"canvas", /* name of device */
"large", /* name of large font */
"small", /* name of small font */
noop, /* Set drawing in back buffer */
CANVAS_char, /* Draw a hardware character */
noop, /* Check if a key was hit */
CANVAS_clear, /* Clear the screen to current color */
CANVAS_color, /* Set current color */
CANVAS_draw, /* Draw a line */
CANVAS_exit, /* Exit graphics */
CANVAS_fill, /* Fill a polygon */
CANVAS_font, /* Set hardware font */
noop, /* Set drawing in front buffer */
noop, /* Wait for and get the next key hit */
CANVAS_init, /* Initialize the device */
noop2, /* Get mouse/cross hair position */
CANVAS_mapcolor, /* Set color indices */
CANVAS_setlw, /* Set line width */
CANVAS_string, /* Draw a hardware string */
noop, /* Swap front and back buffers */
noop /* Syncronize the display */
};
/******************************************************************************/
/* _CANVAS_devcpy copy the canvas device into vdevice.dev. */
int _CANVAS_devcpy() {
vdevice.dev = canvasdev;
return(0);
}
/******************************************************************************/