CANVAS documenation
#ident "@(#)VOGLE:driver/canvas.c - VOGLE driver for HTML 5.0 canvas element"
#ident "@(#)VOGLE:author:John S. Urban"
#ident "@(#)VOGLE:version:1.0, Mar 2007"
/*
===============================================================================
X.lineCap='round';
X.lineJoin='round';
X.fillStyle="#000000";
X.strokeStyle='black';
X.lineWidth=8;
Usage Notes:
o assuming 10 units to a raster 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 Note line weight is always specified as scaled to local coordinate system size.
This is good, as it allows thickness to simply scale with a rescaled plot.
Last Time:
o Changed scale(1) call so that changing the width and height values
causes the frame to stretch to fit the new area
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 making a function that takes an array and draws a polyline to make
files less verbose ( and collect line segments into polylines).
and made the canvas name a parameter to the drawCanvasNNN() function
so that it is easy to use the same plot more than once. That is,
change
drawCanvas1("canvas_id10");
to
drawCanvas1("canvas_id1");
drawCanvas1x("canvas_id10");
and
to
and the same drawing will show up twice at two sizes.
o Got fancy with adding resize buttons and such. Works with opera(1) and
firefox(1) browsers, but might have to back it out or dress it up
relatively soon.
Next Time:
o Should be able to make an animated movie like an mpeg
o extend functions so they call VML or SVG instead of CANVAS, or print
out values or convert to a PostScript or Adobe PDF file by writing to
document
o should default plot size be width of display?
o Consider making JavaScript versions of the Hershey fonts so functions
can be made that print text so text strings are editable.
===============================================================================
multiply X.lineWidth*FACTOR to keep line thickness constant
then change lines that say "X.lineWidth=" to "X.lineWidth=FACTOR*"
===============================================================================
*/
#include
#include
#include
#ifndef MINGW
#include
#include
#endif
#include
#include
#include
#include
#include "vogle.h"
extern FILE *_voutfile();
extern FILE *fp;
/* 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 */
int CANVAS_MOVED=0;
#define CMAPSIZE 256
struct rgb_color {
unsigned short int red;
unsigned short int green;
unsigned short int blue;
};
static 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 void CANVAS_header() {
time_t tod;
#ifndef MINGW
struct utsname unstr, *un;
#endif
char *username;
struct passwd *pw;
time(&tod);
fprintf(fp, "\n");
fprintf(fp, "\n");
fprintf(fp, "\n");
fprintf(fp, "\n");
/*
fprintf(fp, " Creator: VOGLE HTML CANVAS driver 1.0 2007-12-25\n");
*/
fprintf(fp, " Creator: VOGLE HTML CANVAS driver 1.2 2008-01-28\n");
fprintf(fp, " Author: John S. Urban\n");
fprintf(fp, " CreationDate: %s\n",ctime(&tod));
fprintf(fp, "\n");
fprintf(fp, "\n");
#endif
}
/******************************************************************************/
/* 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;
void 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"); /* */
fprintf(fp, "\n"); /* */
fprintf(fp, "\n"); /* */
fprintf(fp, "\n"); /* */
fprintf(fp, " \n");
for(ipages=0;ipagesThe CANVAS element is not displayed by this browser\n"); /* */
}
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, "A=[%d,%d", 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, "A=[%d,%d", x ,FLIPY(y));
CANVAS_MOVED=0;
}else{
if(LAST_X!=x || LAST_Y!=y)CANVAS_MOVED=CANVAS_MOVED+1;
fprintf(fp, "%c,%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, "X.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(canvasname){\n",pgroup);
fprintf(fp, "var canvas = document.getElementById(canvasname); // page %d\n", pgroup);
fprintf(fp, "if(canvas.getContext){\n");
fprintf(fp, "var X = canvas.getContext(\"2d\");\n");
fprintf(fp, "X.save();\n");
/*
fprintf(fp, "X.scale(%f,%f);\n", 1.0/CANVASTORAS, 1.0/CANVASTORAS );
The plot is being made to stretch to the canvas size so it is easy to change the plot size
*/
fprintf(fp, "X.scale(canvas.width/%d,canvas.height/%d);\n", vdevice.sizeSx, vdevice.sizeSy );
fprintf(fp, "X.lineCap='round';\n");
fprintf(fp, "X.lineJoin='round';\n");
fprintf(fp, "X.lineWidth=%d;\n",MAX(1,vdevice.sizeX*curwid/10000));
fprintf(fp, "X.fillStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
fprintf(fp, "X.strokeStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
}
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, "X.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, "X.fillStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
fprintf(fp, "X.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");
return(0);
}
/******************************************************************************/
/* CANVAS_string output a string. */
static int CANVAS_string(char *s) {
return(0);
}
/******************************************************************************/
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, "X.fillStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
fprintf(fp, "X.strokeStyle=\"#%2.2x%2.2x%2.2x\";\n",
canvas_carr[curcol].red,
canvas_carr[curcol].green,
canvas_carr[curcol].blue); /* fill color */
fprintf(fp, "X.lineWidth=%d;\n", MAX(1,vdevice.sizeX*curwid/10000)); /* edge width */
fprintf(fp, "A=[%d,%d ", x[0],FLIPY(y[0]));
for (i = 1; i < n; i++)
{
fprintf(fp, ",%d,%d%c", x[i], FLIPY(y[i]),linefeed[(i % 8/7)]);
}
/* close path */
fprintf(fp, " ,%d,%d", x[0], FLIPY(y[0]));
fprintf(fp, "];f(X,A)\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);
}
/******************************************************************************/