Subversion Repositories wimsdev

Rev

Rev 18635 | Rev 18639 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
15111 schaersvoo 1
/*27/7/2013 version  0.01
7614 schaersvoo 2
"Inspired" by FLY program: http://martin.gleeson.com/fly
3
*********************************************************************************
18552 bpr 4
* J.M. Evers 7/2013        *
5
* This is all just amateur scriblings... So no copyrights.      *
6
* This source code file, and compiled objects derived from it,      *
7
* can be used and distributed without restriction, including for commercial use  *
8
* No warrenty whatsoever      *
7614 schaersvoo 9
*********************************************************************************
10
*/
18552 bpr 11
#define VERSION    "0.5"
18104 georgesk 12
 
13
#define _GNU_SOURCE
14
#include <string.h>
15
 
7848 bpr 16
#include "canvasdraw.h"
15348 bpr 17
void *tmp_buffer;
18552 bpr 18
FILE  *js_include_file;
7614 schaersvoo 19
/******************************************************************************
20
**  Internal Functions
21
******************************************************************************/
18552 bpr 22
void  add_to_buffer(char *tmp); /* add tmp_buffer to the buffer */
23
void  sync_input(FILE *infile);/* proceed with inputfile */
24
void  reset();/* reset some global variables like "use_filled", "use_dashed" */
25
int  get_token(FILE *infile); /* read next char until EOL*/
18623 bpr 26
char *fillcolor;
27
int  x2px(double x);
28
int  y2px(double y);
18606 bpr 29
 
18552 bpr 30
double   px2x(int x);
31
double   px2y(int y);
32
double  get_real(FILE *infile,int last); /* read a value; calculation and symbols allowed */
33
char  *str_replace ( const char *word, const char *sub_word, const char *rep_word );
18623 bpr 34
char  *get_color(FILE *infile,int last); /* read hex-color or colorname -> hex */
18552 bpr 35
char  *get_string(FILE *infile,int last); /* get the string at the end of a command */
36
char  *get_string_argument(FILE *infile,int last); /* the same, but with "comma" as  separator */
18558 bpr 37
int hypgeodaux(double *q, double* res, int full);
18552 bpr 38
char   *convert_hex2rgb(char *hexcolor);
39
void  make_js_include(int canvas_root_id);
40
void  check_string_length(int length);/* checks if the length of string argument of command is correct */
41
FILE   *js_include_file;
42
FILE  *get_file(int *line_number, char **filename);
43
FILE   *infile;    /* will be stdin */
7614 schaersvoo 44
/******************************************************************************
45
** global
46
******************************************************************************/
47
int finished = FALSE;/* main variable for signalling the end of the fly-script ; if finished = 1 ; write to stdout or canvasz */
48
int line_number = 1;/* used in canvas_error() ; keep track of line number in canvasdraw/fly - script */
49
/* set some variables to avoid trouble (NaN) in case of syntax and other usage errors */
50
int xsize = 320;
51
int ysize = 320;
52
double xmin = 0.0;
53
double xmax = 320.0;
54
double ymin = 0.0;
55
double ymax = 320.0;
11893 schaersvoo 56
double tmax = 0;
57
double tmin = 0;
7614 schaersvoo 58
/* flag to indicate parsing of line status */
8224 bpr 59
int done = FALSE;
7614 schaersvoo 60
int type; /* eg command number */
15111 schaersvoo 61
int onclick = 0;
62
/*
15116 bpr 63
 
64
1 = onclick ;
65
2 = draggable ;
66
3 = click+slideable ;
67
4 = slideable without click
15111 schaersvoo 68
5 = draggable + slideable
69
*/
14208 schaersvoo 70
char *slider_type="0";
15111 schaersvoo 71
char *my_sliders = "[-1]";
72
int use_slider = -1;
73
int last_slider = 0;
74
double double_data[MAX_INT+1];
75
int int_data[MAX_INT+1];
76
int dragstuff[MAX_DRAGSTUFF];
77
int js_function[MAX_JS_FUNCTIONS]; /* javascript functions include objects on demand basis: only once per object type */
78
double affine_matrix[] = {1,0,0,1,0,0};
7785 schaersvoo 79
int use_affine = FALSE;
7614 schaersvoo 80
int use_rotate = FALSE;
14078 bpr 81
int use_filled = 0; /* 0:no fill, 1:fill,2=grid?,3=hatch?,4=diamond?,5=dot?,6=image? */
82
int use_dashed = FALSE; /* dashing not natively supported in firefox, for now... */
15111 schaersvoo 83
double angle = 0.0;
7614 schaersvoo 84
char buffer[MAX_BUFFER];/* contains js-functions with arguments ... all other basic code is directly printed into js-include file */
9329 schaersvoo 85
char *getfile_cmd = "";
15111 schaersvoo 86
int reply_format = 0;
87
unsigned int canvas_root_id;
88
char *css_class;
89
int font_size;
90
char *draw_type;
91
int jsplot_cnt = -1;     /* keepint track on the curve identity */
92
int input_cnt = 0;
93
int dashtype[2] = { 4 , 4 }; /* just line_px and space_px: may have more arguments...if needed in future */
94
char *function_label = "[\"f(x)=\",\"g(x)=\",\"h(x)=\"]";
95
int drag_type = -1;/* 0,1,2: xy,x,y */
96
int use_offset = 0;/* use_offset only for text shape objects... 0=none;1=yoffset;2=xoffset;3=xyoffset;4=centered*/
97
int linegraph_cnt = 0; /* identifier for command 'linegraph' ; multiple line graphs may be plotted in a single plot*/
98
int barchart_cnt = 0; /* identifier for command 'barchart' ; multiple charts may be plotted in a single plot*/
99
int legend_cnt = -1; /* to allow multiple legends to be used, for multiple piecharts etc  */
100
int use_axis = FALSE;
101
int use_axis_numbering = -1;
102
int no_reset = FALSE;
103
 
7614 schaersvoo 104
/******************************************************************************
105
** Main Program
106
******************************************************************************/
107
int main(int argc, char *argv[]){
18552 bpr 108
  /* need unique id for every call to canvasdraw: rand(); is too slow...will result in many identical id's */
109
  struct timeval tv;struct timezone tz;gettimeofday(&tv, &tz);
110
  canvas_root_id = (unsigned int) tv.tv_usec;
111
  infile = stdin;/* read flyscript via stdin */
112
  int i,c;
113
  for(i=0;i<MAX_DRAGSTUFF;i++){dragstuff[i] = 0;}
114
  for(i=0;i<MAX_INT;i++){int_data[i]=0;double_data[i]=0;}
115
  int use_snap = 0; /* 0 = none 1=grid: 2=x-grid: 3=y-grid: 4=snap to points */
116
  int print_drag_params_only_once = FALSE;/* avoid multiple useless identical lines about javascript precision and use_dragdrop */
18589 bpr 117
  int line_width = 2;
18552 bpr 118
  int decimals = 2;
119
  int use_dragstuff = 0;
120
  int precision = 100; /* 10 = 1;100=2;1000=3 decimal display for mouse coordinates or grid coordinate.May be redefined before every object */
121
  int use_userdraw = 0; /* 0=none,1=userdraw,2=multidraw flag to indicate user interaction */
122
  int use_tooltip = -1; /* 1= tooltip 2= popup window*/
123
  int use_parametric = FALSE;/* will be reset after parametric plotting */
124
  char *tooltip_text = "Click here";
125
  char *temp = ""; /* */
126
  char *bgcolor = "";/* used for background of canvas_div ; default is tranparent */
127
  char *stroke_color = "255,0,0";
128
  char *fill_color = "255,255,255";
129
  char *font_family = "12px Arial"; /* commands xaxistext,yaxistext,legend,text/textup/string/stringup may us this */
130
  char *font_color = "#00000";
131
  draw_type = "points";
132
  char *fly_font = "normal";
133
  css_class = "none";
134
  char *flytext = "";
135
  int canvas_type = DRAG_CANVAS; /* to use a specific canvas  for filling etc */
136
  int pixelsize = 1;
137
  int fill_cnt = 0;
138
  int use_zoom = 0;
139
  font_size = 12;/* this may lead to problems when using something like <code>fontfamily Italic 24px Arial</code> the ''fontsize`` value is not substituted into fontfamily !! */
140
  int fly_font_size = 12; /*fly_font_size is relative to this... */
141
  for(i=0;i<MAX_JS_FUNCTIONS;i++){js_function[i]=0;}
142
  int arrow_head = 8; /* size in px needed for arrow based  userdraw:  "userdraw arrow,color" */
143
  int crosshair_size = 5; /* size in px*/
144
  int plot_steps = 250;/* the js-arrays with x_data_points and y_data_points will have size 250 each: use with care !!! use jscurve when precise plots are required  */
145
  int found_size_command = 0; /* 1 = found size ; 2 = found xrange; 3 = found yrange: just to flag an error message */
146
  int object_cnt = 0; /*counter to identify the "onclick" ojects ; 0 is first object set onclick: reply[object_cnt]=1 when clicked ; otherwise reply[object_cnt]=0 ; object_cnt is only increased when another object is set  again */
147
  int clock_cnt = 0; /* counts the amount of clocks used -> unique object clock%d */
148
  int boxplot_cnt = 0;
149
  int drawxml_cnt = 0;
150
  int numberline_cnt = 0;
151
  int snap_to_points_cnt = 0;
152
  int reply_precision = 100; /* used for precision of student answers / drawings */
153
  char *rotation_center = "null";/* needs to be removed... but is used for canvas CTX based rotation*/
154
  double rotationcenter[] = {0,0}; /* use for recalculating x/y values on rotation() */
155
  int use_animate = 0; /* used for jscurve / js parametric  */
156
  int use_input_xy = 0; /* 1= input fields 2= textarea 3=calc y value*/
157
  size_t string_length = 0; /* measure the size of the user input fly-string */
18609 bpr 158
  double stroke_opacity = 0.95; /* use some opacity as default */
18552 bpr 159
  double fill_opacity = 0.5;/* use some opacity as default */
160
  char *URL = "http://localhost/images";
161
  memset(buffer,'\0',MAX_BUFFER);
162
  void *tmp_buffer = "";
18615 bpr 163
  double res[10];
18552 bpr 164
  /* default writing a unzipped js-include file into wims getfile directory */
165
  char *w_wims_session = getenv("w_wims_session");
166
  if( w_wims_session == NULL || *w_wims_session == 0 ){canvas_error("Hmmm, your wims environment does not exist...\nCanvasdraw should be used within wims.");}
167
  int L0=strlen(w_wims_session) + 21;
168
  char *getfile_dir = my_newmem(L0); /* create memory to fit string precisely */
169
  snprintf(getfile_dir,L0, "../sessions/%s/getfile",w_wims_session);/* string will fit precisely  */
170
  mode_t process_mask = umask(0); /* check if file exists */
171
  int result = mkdir(getfile_dir, S_IRWXU | S_IRWXG | S_IRWXO);
172
  if( result == 0 || errno == EEXIST ){
173
    umask(process_mask); /* be sure to set correct permission */
174
    char *w_session = getenv("w_session");
175
    int L1 = (int) (strlen(w_session)) + find_number_of_digits(canvas_root_id) + 48;
176
    getfile_cmd = my_newmem(L1); /* create memory to fit string precisely */
177
    snprintf(getfile_cmd,L1,"wims.cgi?session=%s&cmd=getfile&special_parm=%d.js",w_session,canvas_root_id);/* extension ".gz" is MANDATORY for webserver */
13306 obado 178
    /* write the include tag to html page:<script src="wims.cgi?session=%s&cmd=getfile&special_parm=11223344_js"></script> */
7614 schaersvoo 179
    /* now write file into getfile dir*/
14066 bpr 180
    char *w_wims_home = getenv("w_wims_home"); /* "/home/users/wims": we need absolute path for location */
7614 schaersvoo 181
    int L2 = (int) (strlen(w_wims_home)) + (int) (strlen(w_wims_session)) + find_number_of_digits(canvas_root_id) + 23;
182
    char *location = my_newmem(L2); /* create memory to fit string precisely */
183
    snprintf(location,L2,"%s/sessions/%s/getfile/%d.js",w_wims_home,w_wims_session,canvas_root_id);/*absolute path */
184
    js_include_file = fopen(location,"w");/* open the file location for writing */
14066 bpr 185
    /* check on opening...if nogood: mount readonly? disk full? permissions not set correctly? */
186
    if(js_include_file == NULL){ canvas_error("SHOULD NOT HAPPEN: could not write to javascript include file...check your system logfiles !" );}
7614 schaersvoo 187
 
188
/* ----------------------------------------------------- */
11997 schaersvoo 189
 
18552 bpr 190
/*  while more lines to process */
7614 schaersvoo 191
 
192
    while(!finished){
18552 bpr 193
      if(line_number>1 && found_size_command == 0 && use_tooltip != 2 ){canvas_error("command \"size xsize,ysize\" needs to come first ! ");}
194
      type = get_token(infile);
195
      done = FALSE;
196
  /*
197
  @ canvasdraw
198
  @ Canvasdraw will try use the same basic syntax structure as flydraw
18627 bpr 199
  @ General syntax <ul><li>The transparency of all objects can be controlled by command <a href="#opacity">opacity [0-255],[0,255]</a></li><li>Line width of any object can be controlled by command <a href="#linewidth">linewidth int</a></li><li>Any may be dashed by using keyword <a href="#dashed">dashed</a> before the object command.<br> the dashing type can be controled by command <a href="#dashtype">dashtype int,int</a>please note: dashing may have different spacing depending on the angle of the line<br>see https://wimsedu.info/?topic=dashed-arrows-not-dashed-in-canvasdraw</li><li>A fillable object can be set fillable by starting the object command with an ''f`` (like ''frect``,''fcircle``,''ftriangle`` ...) or by using the keyword <a href="#filled">filled</a> before the object command.<br>Non-solid filling (grid,hatch,diamond,dot,text) is provided using command <a href="#fillpattern">fillpattern a_pattern</a><br>note: do not use a <b>f</b> with this non-solid pattern filling.<br>For <a href="#filltoborder">filltoborder x0,y0,bordercolor,color</a> (fill a region around x0,y0 with color until a border of color borderolor is encountered) or <a href="#filltoborder">fill x0,y0,color</a> type filling (fill a region around x0,y0 with color until a border is encountered), there are non-solid pattern fill analogues:<ul><li><a href="#gridfill">gridfill x,y,dx,dy,color</a></li><li><a href="#hatchfill">hatchfill x,y,dx,dy,color</a></li><li><a href="#diamondfill">diamondfill x,y,dx,dy,color</a></li><li><a href="#dotfill">dotfill x,y,dx,dy,color</a></li><li><a href="#textfill">textfill x,y,color,sometext_or_char</a></li></ul></li><li>All draggable objects may have a <a href="#slider">slider</a> for translation / rotation; several objects may be translated / rotated by a single slider</li><li>A draggable object can be set draggable by a preceding command <a href="#drag">drag x/y/xy</a><br>The translation can be read by javascript:read_dragdrop();The replyformat is: object_number : x-orig : y-orig : x-drag : y-drag<br>The x-orig/y-orig will be returned in maximum precision (javascript float)...<br>the x-drag/y-drag will be returned in defined ''precision`` number of decimals<br>Multiple objects may be set draggable / clickable (no limit)<br>not all flydraw objects may be dragged / clicked<br>Only draggable / clickable objects will be scaled on <a href="#zoom">zoom</a> and will be translated in case of panning.</li><li>A ''onclick object`` can be set ''clickable`` by the preceding keyword <a href="#onclick">onclick</a><br>Not all flydraw objects can be set clickable</li><li><b>Remarks using a '';`` as command separator</b>. Commands with only numeric or color arguments may be using a '';`` as command separator (instead of a new line). Commands with a string argument may not use a '';`` as command separator.<br>These exceptions are not really straight forward... so keep this in mind.</li><li>Almost every <a href="#userdraw">userdraw object,color</a> or <a href="#multidraw">multidraw</a> command ''family`` may be combined with keywords <a href="#snaptogrid">"snaptogrid | xsnaptogrid | ysnaptogrid | snaptofunction</a> or command <code>snaptopoints x1,y1,x2,y2,...</code></li><li>Every draggable | onclick object may be combined with keywords <a href="#snaptogrid">snaptogrid | xsnaptogrid | ysnaptogrid | snaptofunction</a> or command <code>snaptopoints x1,y1,x2,y2,...</code></li><li>Almost every command for a single object has a multiple objects counterpart: <ul>general syntax rule:<li><code>object x1,y1,...,color</code></li><li><code>objects color,x1,y1,...</code></li></ul><li>All inputfields or textareas generated, can be styled individually using command <a href="#css">css some_css</a>: the fontsize used for labeling these elements can be controlled by command <a href="#fontsize">fontsize int</a> command <code>fontfamily</code> is <b>not</b> active for these elements.</li></ul>
200
  @ If needed multiple interactive scripts (*) may be used in a single webpage.<br>A function <code>read_canvas()</code> and / or <code>read_dragdrop()</code> can read all interactive userdata from these images.<br>The global array <code>canvas_scripts</code>will contain all unique random "canvas_root_id" of the included scripts.<br>The included local javascript "read" functions ''read_canvas%d()`` and ''read_dragdrop%d()`` will have this ''%d = canvas_root_id``<br>e.g. canvas_scripts[0] will be the random id of the first script in the page and will thus provide a function<br><code>fun = eval("read_canvas"+canvas_scripts[0])</code> to read user based drawings / inputfield in this first image.<br>The read_dragdrop is analogue.<br>If the default reply formatting is not suitable, use command <a href='#replyformat'>replyformat</a> to format the replies for an individual canvas script,<br>To read all user interactions from all included canvas scripts, use something like:<br><code>function read_all_canvas_images(){<br>&nbsp;var script_len = canvas_scripts.length;<br>&nbsp;var draw_reply = "";<br>&nbsp;var found_result = false;<br>&nbsp;for(var p = 0 ; p < script_len ; p++){<br>&nbsp;&nbsp;var fun = eval("read_canvas"+canvas_scripts[p]);<br>&nbsp;&nbsp;if( typeof fun === 'function'){<br>&nbsp;&nbsp;&nbsp;var result = fun();<br>&nbsp;&nbsp;&nbsp;if( result&nbsp;&nbsp;&& result.length != 0){<br>&nbsp;&nbsp;&nbsp;&nbsp;if(script_len == 1 ){.return result;};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;found_result = true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw_reply = draw_reply + result + "newline";<br>&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;};<br>&nbsp;if( found_result ){return draw_reply;}else{return null;};<br>};</code> <br>(*) Note: the speed advantage over <em>canvas-do-it-all</em> libraries is reduced to zero, when multiple canvasdraw scripts are present in a single page... For example a typical canvasdraw script is between 5 and 40 kB...a large library like JSXgraph is approx 600 kB. In these cases it would be much faster to load a static general HTML5 canvas javascript draw library and parse it multiple raw fly instructions.
201
  @ Canvasdraw can be used to paint a html5 bitmap image by generating a tailor-made javascript include file: providing only the js-functionality needed to perform the job, thus ensuring a minimal strain on the client browser (unlike some popular ''canvas-do-it-all`` libraries, who have proven to be not suitable for low-end computers found in schools...)
18552 bpr 202
  @ You can check the javascript reply format in the wims tool <a href="http://localhost/wims/wims.cgi?lang=en&module=tool/directexec">direct exec</a>
203
  @ For usage within OEF (without anstype ''draw``), something like this (a popup function plotter) will work:<br><code>\\text{popup_grapher=wims(exec canvasdraw <br>popup<br>size 400,400<br>xrange -10,10<br>yrange -10,10<br>axis<br>axisnumbering<br>opacity 100,100<br>grid 2,2,grey,2,2,6,black<br>snaptogrid<br>linewidth 2<br>jsplot red,5*sin(1/x)<br>strokecolor green<br>functionlabel f(x)=<br>userinput function<br>mouse blue,22<br>)<br>}<br>\\statement{<br>\\popup_grapher<br>}</code>.
18627 bpr 204
  @ Be aware that older browsers will probably not work correctly. no effort has been undertaken to add glue code for older browsers !! In any case it is not wise to use older browsers...not just for canvasdraw.
18552 bpr 205
  @ Be aware that combining several different objects and interactivity may lead to problems.
206
  @ If you find flaws, errors or other incompatibilities -not those mentioned in this document- send <a href='mailto:jm.evers-at-schaersvoorde.nl'>me</a> an email with screenshots and the generated javascript include file.
18627 bpr 207
  @ There is limited support for touch devices: touchstart, touchmove and touchend in commands <a href="#userdraw">userdraw primitives </a>, <a href="#multidraw">multidraw primitives </a>, <a href="#protractor">protractor</a>, <a href="#ruler">ruler</a> and probably a few others... Only single finger gestures are supported (for now). The use of a special pen is advised for interactive drawing on touch devices. For more accurate user-interaction (numeric, eg keyboard driven drawings) with canvasdraw on touch devices: use the command family <a href="#userinput_xy">userinput</a>.
18552 bpr 208
  */
209
      switch(type){
210
        case END:finished = 1;done = TRUE;break;
211
        case 0:sync_input(infile);break;
212
        case AFFINE:
213
  /*
18556 bpr 214
  @ affine a,b,c,d,tx,ty
215
  @ defines a transformation matrix for subsequent objects
216
  @ use keyword <a href='#killaffine'>killaffine</a> to end the transformation...the next objects will be drawn in the original x/y-range
217
  @ a: Scales the drawings horizontally
218
  @ b: Skews the drawings horizontally
219
  @ c: Skews the drawings vertically
220
  @ d: Scales the drawings vertically
221
  @ tx: Moves the drawings horizontally in xrange coordinate system
222
  @ ty: Moves the drawings vertically in yrange coordinate system
223
  @ the data precision may be set by preceding command ''precision int``
224
  @ <b>note</b>: not all affine operations on canvasdraw objects will be identical to flydraw's behaviour. Make sure to check !
225
  @%affine%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%#use larger linewith to improve selecting a draggable object !%linewidth 4%drag xy%frect 0,5,3,3,red%affine cos(pi/4),sin(pi/4),-cos(pi/2),sin(pi/2),-5,-5%drag xy%frect 0,5,3,3,red
226
  @%affine+latex%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%strokecolor blue%fontfamily 42px Arial%centered%drag xy%latex 5,5,\\frac{123}{\\pi^{234}}%affine cos(pi/4),sin(pi/4),-cos(pi/2),sin(pi/2),-5,-5%drag xy%latex 5,5,\\frac{123}{\\pi^{234}}
18552 bpr 227
  */
228
          for(i = 0 ; i<6;i++){
229
            switch(i){
230
              case 0: affine_matrix[0] = get_real(infile,0);break;
231
              case 1: affine_matrix[1] = get_real(infile,0);break;
232
              case 2: affine_matrix[2] = get_real(infile,0);break;
233
              case 3: affine_matrix[3] = get_real(infile,0);break;
234
              case 4: affine_matrix[4] = get_real(infile,0);break;
235
              case 5: affine_matrix[5] = get_real(infile,1);
236
              use_affine = TRUE;
237
              break;
238
              default: break;
239
            }
240
          }
241
          break;
14394 schaersvoo 242
        case ALLOW_DUPLICATES:
18556 bpr 243
  /*
244
  @ duplicates || allowdups
245
  @ keyword (no arguments)
246
  @ only useful in case of a <a href="#multidraw">multidraw</a> student reply.
247
  @ only useful in default <a href="#replyformat">replyformat</a> (eg in case of a not specified replyformat).
248
  @ if set, duplicate (x:y) coordinates will not be removed from the student reply.
249
  @ technical: a javascript variable "allow_duplicate_answer = 1;" is declared.
250
  @ default for command multidraw is: removal of duplicates.
251
  */
18552 bpr 252
          fprintf(js_include_file,"var allow_duplicate_answers = 1;");
253
          break;
254
        case ANGLE:
18556 bpr 255
  /*
256
  @ angle xc,yc,width,start_angle,end_angle,color
257
  @ width is in x-range
258
  @ angles are in degrees
259
  @ not compatible with ''flydraw``
260
  @ will zoom in/out
261
  @ may be set onclick or drag&amp;drop
262
  @ if angle size is controlled by command <a href='#slider'>slider</a>, use radians to set limits of slider
263
  @ ''angle`` and <a href="#arc">arc</a>  are exceptions in case of sliders...they are always active (e.g. not click-activated)
264
  @%angle%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor orange%angle 0,0,4,10,135,blue
265
  @%angle_slider%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 3%strokecolor blue%slider -2*pi,2*pi,260,28,angle active degree,blue arrow%arrow 0,0,8,0,8,blue%fillpattern diamond%angle 0,0,2,0,0,blue%killslider%strokecolor red%slider -2*pi,2*pi,260,28,angle active radian,red arrow%arrow 0,1,8,1,8,red%fillpattern dot%angle 0,1,2,0,0,red
266
  */
18552 bpr 267
          for(i=0;i<7;i++){
268
            switch(i){
269
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
270
              case 1:double_data[1] = get_real(infile,0);
271
              if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
272
              if(use_affine == TRUE ){ transform(2,2);}
273
              break; /* y-values */
274
              case 2:double_data[2] = get_real(infile,0);break; /* width x-range ! */
275
              case 3:double_data[3] = 0.0174532925*(get_real(infile,0) - angle);break; /* start angle in degrees -> radians  */
276
              case 4:double_data[4] = 0.0174532925*(get_real(infile,0) - angle);break; /* end angle in degrees -> radians */
277
              case 5:stroke_color = get_color(infile,1);/* name or hex color */
278
              if( use_slider != -1 ){ onclick = 3; }/* always active in case of slider */
279
              decimals = find_number_of_digits(precision);
18557 bpr 280
              tmp_buffer=my_newmem(MAX_BUFFER);
281
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,17,[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[0],decimals,double_data[1],decimals,double_data[1],decimals,double_data[2],decimals,double_data[2],decimals,double_data[3],decimals,double_data[4],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 282
              add_to_buffer(tmp_buffer);
283
              dragstuff[17] = 1;
284
              if(use_dragstuff == 0 ){ use_dragstuff = 1; }
285
              if(onclick != 0){object_cnt++;}/* object_cnt++;*/
286
              break;
287
            }
288
          }
289
          break;
290
        case ANIMATE:
291
  /*
18556 bpr 292
  @ animate
293
  @ keyword
294
  @ if set, it will animate a point on a curve
295
  @ all other canvas object or group of objects (like lines,circles,rects,points...images,svg,latex,mathml etc)<br>may be animated using command <a href='#slider'>slider</a> with keyword 'anim'
18627 bpr 296
  @ the animated point is a filled rectangle ; adjust color with command <code>fillcolor colorname/hexnumber</code>
18556 bpr 297
  @ use linewidth to adjust size of the points
298
  @ will animate a point on -only- the next <a href='#jsplot'>jsplot/jscurve command</a>. Only a single call to <code>animate</code> is allowed...in case of multiple <code>animate</code> keywords, only the last one is valid
299
  @ only usable in combination with command <a href='#jsplot'>jsplot</a> (normal functions or parametric)
300
  @ moves repeatedly from <a href='#xrange'>xmin to xmax</a> or in case of a parametric function from <a href='#trange'>tmin to tmax</a>
301
  @ use commands <a href='#multilinewidth'>multilinewidth</a>, <a href='#multistrokecolor'>multistrokecolor</a> etc in case of multiple animated functions.<br>use multiple functions as argument in a single call to <a href='#jsplot'>jsplot color,fun1,fun2,fun3...fun_n</a>
302
  @%animate_1%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 100%linewidth 4%fillcolor red%animate%trange -2*pi,2*pi%linewidth 1%opacity 255,50%canvastype 100%fill 1.2,1.2,red%canvastype 101%fill -1.2,-1.2,blue%jsplot blue,7*cos(x),5*sin(2*x)
303
  @%animate_2%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 100%linewidth 4%fillcolor red%animate%trange -2*pi,2*pi%linewidth 1%opacity 255,50%canvastype 100%fill 1.2,1.2,red%canvastype 101%fill -1.2,-1.2,blue%multistrokecolors blue,blue,green,green,orange,orange%multilinewidth 2,2,3,3,1,1%jsplot blue,7*cos(x),5*sin(2*x),9*sin(x),5*cos(x),x^2,x
18552 bpr 304
  */
305
          use_animate++;
306
          if( use_animate == 1 ){
307
            fprintf(js_include_file,"\nvar trace_canvas  = create_canvas%d(%d,xsize,ysize);\
308
              var trace_ctx = trace_canvas.getContext('2d');\
309
              trace_ctx.fillStyle = 'rgba(%s,%f)';\
310
              trace_ctx.strokeStyle = 'rgba(%s,%f)';\
311
              trace_ctx.lineWidth = %d;var anim_pos = 0;\n\
312
              function animate_this(){\
313
              var sync;\
314
              var synchrone = Math.floor(animation_steps/animation_funs);\
315
              trace_ctx.clearRect(0,0,xsize,ysize);\
316
              for(var p=0; p<animation_funs;p++){\
317
               sync = p*synchrone;\
318
               trace_ctx.fillRect(x_anim_points[sync+anim_pos]-%d, y_anim_points[sync+anim_pos]-%d,%d,%d);\
319
              };\
320
              setTimeout(function(){\
321
               requestAnimationFrame(animate_this);  anim_pos++;}, 50\
322
              );\
323
              if(anim_pos >= animation_steps){anim_pos = 0;};\
324
              };",canvas_root_id,ANIMATE_CANVAS,fill_color,fill_opacity,stroke_color,stroke_opacity,line_width,line_width,line_width,2*line_width,2*line_width);
325
          } else {
326
            canvas_error("animate can only be used once<br>multiple curves may be animated using something like:<br>jsplot red,sin(x),cos(x),x^2,sin(2*x)");
327
          }
328
          break;
329
        case ARC:
330
  /*
18556 bpr 331
  @ arc xc,yc,x-width,y-height,start_angle,end_angle,color
332
  @ may be set ''onclick`` or ''drag xy``
333
  @ compatible with ''flydraw``
334
  @ attention: width &amp; height in x/y-range
335
  @ for arrow hats on an arc, see  command <a href='#arcarrow'>arcarrow or arrowarc</a>
336
  @ better use command <a href='#angle'>angle</a> for use with a <a href='#slider'>slider</a>
337
  @%arc%size 400,400%xrange -10,10%yrange -10,10%arc 0,0,4,4,10,135,red
338
  @%arc_filled%size 400,400%xrange -10,10%yrange -10,10%opacity 255,60%filled%fillcolor green%arc 0,0,4,4,10,135,red
18552 bpr 339
  */
340
          for(i=0;i<7;i++){
341
            switch(i){
342
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
343
              case 1:double_data[1] = get_real(infile,0);
344
              if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
345
              if(use_affine == TRUE ){ transform(4,2);}
346
              break; /* y-values */
347
              case 2:double_data[2] = get_real(infile,0);break; /* width x-range no pixels ! */
348
              case 3:double_data[3] = get_real(infile,0);
349
              break; /* height y-range no pixels ! */
350
              case 4:double_data[4] = get_real(infile,0) - angle ;break; /* start angle in degrees */
351
              case 5:double_data[5] = get_real(infile,0) - angle;break; /* end angle in degrees */
352
              case 6:stroke_color = get_color(infile,1);/* name or hex color */
353
        /* in Shape library:
354
      x[0] = x[1] = xc = double_data[0]
355
      y[0] = y[1] = yc = double_data[1]
356
      w[0] = width = double_data[2]
357
      w[1] = height = double_data[3]
358
      h[0] = start_angle = double_data[4]
359
      h[1] = end_angle = double_data[5]
360
        */
18555 bpr 361
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
362
                decimals = find_number_of_digits(precision);
18557 bpr 363
 
364
                tmp_buffer=my_newmem(MAX_BUFFER);
365
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,12,[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[0],decimals,double_data[1],decimals,double_data[1],decimals,double_data[2],decimals,double_data[3],decimals,double_data[4],decimals,double_data[5],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18555 bpr 366
                add_to_buffer(tmp_buffer);reset();
367
                dragstuff[12] = 1;
368
                if(onclick != 0){object_cnt++;}
369
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
18552 bpr 370
              break;
371
            }
372
          }
373
          break;
374
        case ARCARROW:
375
  /*
18556 bpr 376
  @ arrowarc xc,yc,x-width,y-height,start_angle,end_angle,color,type
377
  @ alternative: arcarrow
378
  @ uses same syntax as <a href='#arc'>arc</a>
379
  @ for arrow hat: type = 1 : right<br>type = 2 : left<br>type = 3 : left&amp;right
380
  @ if the default arrow hat/head is not satisfactory , the size of the arrow may be set with command <a href='#arrowhead'>arrowhead</a>
381
  @ no other arrow types are implemented...yet
382
  @ may be set draggable or onclick
383
  @ attention: when width ad height are very different, the arrow hat is not drawn correctly. This is a flaw and not a feature...(for now: too much calculations to correct)
384
  @%arcarrow%size 400,400%xrange -10,10%yrange -10,10%noreset%onclick%arcarrow 0,0,7,7,50,275,blue,3%arcarrow 0,0,8,8,50,275,red,2%arcarrow 0,0,9,9,50,275,green,1
18552 bpr 385
  */
386
          for(i=0;i<8;i++){
387
            switch(i){
388
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
389
              case 1:double_data[1] = get_real(infile,0);
390
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
391
                if(use_affine == TRUE ){ transform(4,2);}
392
                break; /* y-values */
393
              case 2:double_data[2] = get_real(infile,0);break; /* width x-range no pixels ! */
394
              case 3:double_data[3] = get_real(infile,0);
395
                break; /* height y-range no pixels ! */
396
              case 4:double_data[4] = get_real(infile,0) - angle ;break; /* start angle in degrees */
397
              case 5:double_data[5] = get_real(infile,0) - angle;break; /* end angle in degrees */
398
              case 6:stroke_color = get_color(infile,0);/* name or hex color */
399
                break;
400
              case 7:int_data[0] = (int) get_real(infile,1);
401
                switch(int_data[0]){
402
                  case 1: int_data[1] = 24;break; /* right */
403
                  case 2: int_data[1] = 25;break; /* left */
404
                  case 3: int_data[1] = 26;break; /* left&right */
405
                  default:int_data[1] = 24;break;
406
                }
407
              if(int_data[0] == 1 ){int_data[1] = 24;}
408
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
409
              decimals = find_number_of_digits(precision);
18557 bpr 410
 
411
              tmp_buffer=my_newmem(MAX_BUFFER);
412
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"var arrow_head = %d;dragstuff.addShape(new Shape(%d,%d,%d,%d,%d,[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",arrow_head,drag_type,object_cnt,onclick,use_snap,int_data[1],decimals,double_data[0],decimals,double_data[0],decimals,double_data[1],decimals,double_data[1],decimals,double_data[2],decimals,double_data[3],decimals,double_data[4],decimals,double_data[5],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 413
              add_to_buffer(tmp_buffer);
414
              dragstuff[int_data[1]] = 1;
415
              if(onclick != 0){object_cnt++;}
416
              if(use_dragstuff == 0 ){ use_dragstuff = 1; }
417
              js_function[JS_ARROWHEAD] = 1;
418
              reset();
419
            }
420
          }
421
          break;
422
        case ARROW:
423
  /*
424
  @ arrow x1,y1,x2,y2,h,color
425
  @ alternative: vector
426
  @ draw a single headed arrow / vector from (x1:y1) to (x2:y2)<br>with arrowhead size h in px and in color ''color``
427
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
428
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
429
  @%arrow_drag%size 400,400%xrange -10,10%yrange -10,10%cursor move%linewidth 2%drag xy%arrow 0,0,4,3,8,blue%drag xy%arrow 0,0,-4,3,8,green%drag xy%arrow 0,0,4,-3,8,orange%drag xy%arrow 0,0,-4,-3,8,cyan
430
  @%arrow_click%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%%onclick%arrow 0,0,4,4,8,blue%onclick%arrow 0,0,-4,5,8,green%onclick%arrow 0,0,4,-6,8,orange%onclick%arrow 0,0,-4,-2,8,cyan
431
  */
432
          for(i=0;i<6;i++){
433
            switch(i){
434
              case 0: double_data[0] = get_real(infile,0);break; /* x */
435
              case 1: double_data[1] = get_real(infile,0);break; /* y */
436
              case 2: double_data[2] = get_real(infile,0);break; /* x */
437
              case 3: double_data[3] = get_real(infile,0);break; /* y */
438
              case 4: arrow_head = (int) get_real(infile,0);break;/* h */
439
              case 5: stroke_color = get_color(infile,1);/* name or hex color */
440
                if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
441
                if(use_affine == TRUE ){ transform(4,2);}
442
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
443
                decimals = find_number_of_digits(precision);
18557 bpr 444
                tmp_buffer=my_newmem(MAX_BUFFER);
445
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,8,[%.*f,%.*f],[%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[1],decimals,double_data[3],arrow_head,arrow_head,arrow_head,arrow_head,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 446
                if(onclick != 0){object_cnt++;}
447
          /* object_cnt++;*/
448
                add_to_buffer(tmp_buffer);reset();
449
                dragstuff[8] = 1;
450
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
451
              break;
452
            }
453
          }
454
          break;
455
        case ARROWS:
456
  /*
457
  @ arrows color,head (px),x1,y1,x2,y2...x_n,y_n
458
  @ alternative: vectors
459
  @ draw single headed arrows / vectors from (x1:y1) to (x2:y2) ... (x3:y3) to (x4:y4) etc ... in color 'color'
460
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
461
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
462
  @%arrows_click%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%arrows red,8,0,0,4,3,0,0,2,4,0,0,-2,4,0,0,-3,-4,0,0,3,-2%
463
  @%arrows_drag%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag xy%arrows red,8,0,0,4,3,0,0,2,4,0,0,-2,4,0,0,-3,-4,0,0,3,-2%
464
  @%arrows_drag_slider%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag xy%# Click arrow(s) to activate %slider 0,2*pi,300,30,angle degrees,Rotate%slider -5,5*pi,300,30,x display,move in x-direction%slider -10,10*pi,300,30,y display,move in y-direction%arrows red,8,0,0,4,3,0,0,2,4,0,0,-2,4,0,0,-3,-4,0,0,3,-2%
465
  */
466
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
467
          fill_color = stroke_color;
468
          arrow_head = (int) get_real(infile,0);/* h */
469
          i=0;
470
          while( ! done ){     /* get next item until EOL*/
471
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
472
            if(i%2 == 0 ){
473
              double_data[i] = get_real(infile,0); /* x */
474
            } else {
475
              double_data[i] = get_real(infile,1); /* y */
476
            }
477
          i++;
478
          }
479
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
480
          if( use_affine == TRUE ){ transform(i-1,2);}
481
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
482
          decimals = find_number_of_digits(precision);
483
          for(c = 0 ; c < i-1 ; c = c+4){
18557 bpr 484
            tmp_buffer=my_newmem(MAX_BUFFER);
485
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,8,[%.*f,%.*f],[%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+1],decimals,double_data[c+3],arrow_head,arrow_head,arrow_head,arrow_head,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 486
            add_to_buffer(tmp_buffer);
487
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
488
          }
489
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
490
          dragstuff[8] = 1;
491
          reset();
492
          break;
493
        case ARROW2:
494
  /*
495
  @ arrow2 x1,y1,x2,y2,h,color
496
  @ draw a double headed arrow/vector from (x1:y1) to (x2:y2)<br>with arrowhead size h in px and in color ''color``
497
  @ use command <code>arrowhead int</code> to adjust the arrow head size
498
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
499
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
500
  @%arrow2%size 400,400%xrange -10,10%yrange -10,10%drag xy%arrow2 0,0,4,3,8,blue%
501
  */
502
          for(i=0;i<6;i++){
503
            switch(i){
504
              case 0: double_data[0] = get_real(infile,0);break; /* x */
505
              case 1: double_data[1] = get_real(infile,0);break; /* y */
506
              case 2: double_data[2] = get_real(infile,0);break; /* x */
507
              case 3: double_data[3] = get_real(infile,0);break; /* y */
508
              case 4: arrow_head = (int) get_real(infile,0);break;/* h */
509
              case 5: stroke_color = get_color(infile,1);/* name or hex color */
510
                if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
511
                if( use_affine == 1 ){ transform(4,2);}
512
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
513
                decimals = find_number_of_digits(precision);
18557 bpr 514
                tmp_buffer=my_newmem(MAX_BUFFER);
515
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,10,[%.*f,%.*f],[%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[1],decimals,double_data[3],arrow_head,arrow_head,arrow_head,arrow_head,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 516
                add_to_buffer(tmp_buffer);
517
                if(onclick != 0){object_cnt++;}/* object_cnt++;*/
518
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
519
                dragstuff[10] = 1;
520
                reset();
521
                break;
522
            }
523
          }
524
          break;
525
        case ARROWS2:
526
  /*
527
  @ arrows2 color,head (px),x1,y1,x2,y2...x_n,y_n
528
  @ draw double headed arrows / vectors from (x1:y1) to (x2:y2) ... (x3:y3) to (x4:y4) etc ... in color ''color``
529
  @ use command <code>linewidth int</code> to adjust thickness of the arrows
530
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
531
  @%arrows2%size 400,400%xrange -10,10%yrange -10,10%onclick%arrows2 red,8,0,0,4,3,1,1,2,4,2,2,-2,4,3,3,-3,-4,0,0,3,-2%
532
  */
533
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
534
          fill_color = stroke_color;
535
          arrow_head = (int) get_real(infile,0);/* h */
536
          i=0;
537
          while( ! done ){     /* get next item until EOL*/
538
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
539
            if(i%2 == 0 ){
540
              double_data[i] = get_real(infile,0); /* x */
541
            } else {
542
              double_data[i] = get_real(infile,1); /* y */
543
            }
544
            i++;
545
          }
546
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
547
          if( use_affine == 1 ){ transform(i-1,2);}
548
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
8386 schaersvoo 549
 
18552 bpr 550
          decimals = find_number_of_digits(precision);
551
          for(c = 0 ; c < i-1 ; c = c+4){
18557 bpr 552
            tmp_buffer=my_newmem(MAX_BUFFER);
553
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,10,[%.*f,%.*f],[%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+1],decimals,double_data[c+3],arrow_head,arrow_head,arrow_head,arrow_head,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 554
            add_to_buffer(tmp_buffer);
555
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
556
          }
557
          dragstuff[10] = 1;
558
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
559
          reset();
560
          break;
561
        case ARROWHEAD:
562
  /*
563
  @ arrowhead int
564
  @ default 8 (pixels)
565
  */
566
          arrow_head = (int) (get_real(infile,1));
567
          break;
568
        case AUDIO:
569
  /*
570
  @ audio x,y,w,h,loop,visible,audiofile location
571
  @ x,y: left top corner of audio element (in xrange / yrange)
572
  @ w,y: width and height in pixels
573
  @ loop: 0 or 1 ( 1 = loop audio fragment)
574
  @ visible: 0 or 1 (1 = show controls)
575
  @ audio format may be in *.mp3 or *.ogg
576
  @ If you are using *.mp3: be aware that FireFox will not (never) play this ! (Pattented format)
577
  @ if you are using *.ogg: be aware that Microsoft based systems not support it natively
578
  @ To avoid problems supply both types (mp3 and ogg) of audiofiles.<br>the program will use both as source tag
579
  */
580
          js_function[DRAW_AUDIO] = 1;
581
          for(i=0;i<7;i++){
582
            switch(i){
583
              case 0: int_data[0] = x2px(get_real(infile,0)); break; /* x in x/y-range coord system -> pixel */
584
              case 1: int_data[1] = y2px(get_real(infile,0)); break; /* y in x/y-range coord system  -> pixel */
585
              case 2: int_data[2] = (int) (get_real(infile,0)); break; /* pixel width */
586
              case 3: int_data[3] = (int) (get_real(infile,0)); break; /* height pixel height */
587
              case 4: int_data[4] = (int) (get_real(infile,0)); if(int_data[4] != TRUE){int_data[4] = FALSE;} break; /* loop boolean */
588
              case 5: int_data[5] = (int) (get_real(infile,0)); if(int_data[5] != TRUE){int_data[5] = FALSE;} break; /* visible boolean */
589
              case 6:
590
                temp = get_string(infile,1);
591
                if( strstr(temp,".mp3") != 0 ){ temp = str_replace(temp,".mp3","");}
592
                if( strstr(temp,".ogg") != 0 ){ temp = str_replace(temp,".ogg","");}
18557 bpr 593
                tmp_buffer=my_newmem(MAX_BUFFER);
594
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_audio(%d,%d,%d,%d,%d,%d,%d,\"%s.ogg\",\"%s.mp3\");\n", canvas_root_id, int_data[0],int_data[1],int_data[2],int_data[3],int_data[4],int_data[5],temp,temp));
18552 bpr 595
                add_to_buffer(tmp_buffer);
596
                break;
597
              default:break;
598
            }
599
          }
600
          reset();
601
          break;
602
        case AXIS_NUMBERING:
603
  /*
18556 bpr 604
  @ axisnumbering
605
  @ keyword (no arguments required)
606
  @ for special numbering of x-axis or y-axis see grid related commands <a href="#axis">axis</a> <a href="#xaxis">xaxis</a>, <a href="#xaxisup">xaxisup</a>, <a href="#noxaxis">noxaxis</a>, <a href="#yaxis">yaxis</a>, <a href="#yaxisup">yaxisup</a>, <a href="#noyaxis">noyaxis</a>
607
  @ to be used before command grid (see <a href="#grid">command grid</a>)
18552 bpr 608
  */
609
          use_axis_numbering++;
610
          break;
611
        case AXIS:
612
  /*
18556 bpr 613
  @ axis
614
  @ keyword (no arguments required)
615
  @ to be used before command grid (see <a href="#grid">command grid</a>)
8386 schaersvoo 616
 
18552 bpr 617
  */
618
          use_axis = TRUE;
619
          break;
620
        case BARCHART:
621
  /*
622
  @ barchart x_1:y_1:color_1:x_2:y_2:color_2:...x_n:y_n:color_n
623
  @ may <b>only</b> to be used together with command <a href='#grid'>grid</a>
624
  @ can be used together with freestyle x-axis/y-axis texts: see commands <a href='#xaxis'>xaxis</a>,<a href='#xaxisup'>xaxisup</a> and <a href='#yaxis'>yaxis</a>
625
  @ use command <a href='#legend'>legend</a> to provide an optional legend in right-top-corner
626
  @ multiple barchart command may be used in a single script
627
  @ also see command <a href='#piechart'>piechart</a>
628
  @ note: your arguments are not checked by canvasdraw: use your javascript console in case of trouble...
629
  @%barchart%size 400,400%xrange -1,10%yrange -2,14%legend legend Z:legend A:this is B:C:D:E:F:G:H:X%legendcolors green:red:orange:lightblue:cyan:gold:purple:darkred:yellow:lightgreen%xaxis 0:Z:1:A:2:B:3:C:4:D:5:E:6:F:7:G:8:H:9:X%noyaxis%precision 1%fontfamily bold 15px Arial%grid 1,1,white%barchart 0:5.5:green:2:5.5:red:4:6.5:orange:6:8:lightblue:8:11:cyan:1:5.5:gold:3:9:purple:5:4:darkred:7:7:yellow:9:1:lightgreen%mouse red,14
630
  */
631
          temp = get_string(infile,1);
632
          if( strstr( temp,":" ) != 0 ){ temp = str_replace(temp,":","\",\""); }
633
          fprintf(js_include_file,"var barchart_%d = [\"%s\"];",barchart_cnt,temp);
634
          barchart_cnt++;
635
          reset();
636
          break;
637
        case BEZIER:
638
  /*
639
  @ bezier color,x_start,y_start,x_first,y_first,x_second,y_second,x_end,y_end
640
  @ draw a bezier curve between points, starting from (x_start:y_start)
641
  @ can <b>not</b> be dragged or set onclick
642
  */
643
          js_function[DRAW_BEZIER] = 1;
644
          decimals = find_number_of_digits(precision);
645
          for(i = 0 ; i < 9; i++){
646
            switch(i){
647
              case 0: stroke_color = get_color(infile,0);break;
648
              case 1: double_data[0] = get_real(infile,0);break;/* start x */
649
              case 2: double_data[1] = get_real(infile,0);break;/* start y */
650
              case 3: double_data[2] = get_real(infile,0);break;/*The x-coordinate of the first Bézier control point */
651
              case 4: double_data[3] = get_real(infile,0);break;/*The y-coordinate of the first Bézier control point */
652
              case 5: double_data[4] = get_real(infile,0);break;/*The x-coordinate of the second Bézier control point */
653
              case 6: double_data[5] = get_real(infile,0);break;/*The y-coordinate of the second Bézier control point */
654
              case 7: double_data[6] = get_real(infile,0);break;/*The x-coordinate of the Bézier end point */
655
              case 8: double_data[7] = get_real(infile,1);/*The y-coordinate of the Bézier end point */
656
                if(use_rotate == TRUE ){rotate(8,angle,rotationcenter,2);}
657
                if(use_affine == TRUE ){ transform(2,5);}
18557 bpr 658
                tmp_buffer=my_newmem(MAX_BUFFER);
659
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"draw_bezier(%d,%d,[%f,%f,%f,%f,%f,%f,%f,%f],\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.2f);",STATIC_CANVAS,line_width,double_data[0],double_data[1],double_data[2],double_data[3],double_data[4],double_data[5],double_data[6],double_data[7],fill_color,fill_opacity,stroke_color,stroke_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle));
18552 bpr 660
                add_to_buffer(tmp_buffer);
661
                break;
662
              default: break;
663
            }
664
          }
665
          reset();
666
          break;
667
        case BGCOLOR:
668
  /*
18556 bpr 669
  @ bgcolor colorname or #hex
670
  @ use this color as background of the "div" containing the canvas(es)
671
  @%bgcolor%size 400,400%xrange -10,10%yrange -10,10%bgcolor lightblue
18552 bpr 672
  */
673
  /* [255,255,255]*/
674
          bgcolor = get_string(infile,1);
675
          if(strstr(bgcolor,"#") == NULL){ /* convert colorname -> #ff00ff */
676
            int found = 0;
677
            for( i = 0; i < NUMBER_OF_COLORNAMES ; i++ ){
678
              if( strcmp( colors[i].name , bgcolor ) == 0 ){
679
                bgcolor = colors[i].hex;
680
                found = 1;
681
              break;
682
              }
683
            }
684
            if(found == 0){canvas_error("your bgcolor is not in my rgb.txt data list: use hexcolor...something like #a0ffc4");}
685
          }
686
          fprintf(js_include_file,"/* set background color of canvas div */\ncanvas_div.style.backgroundColor = \"%s\";canvas_div.style.opacity = %f;\n",bgcolor,fill_opacity);
687
          break;
688
        case BGIMAGE:
689
  /*
18556 bpr 690
  @ bgimage image_location
691
  @ use an image as background; technical: we use the background of ''canvas_div``
692
  @ the background image will be resized to match "width = xsize" and "height = ysize"
693
  @%bgimage%size 400,400%xrange -10,10%yrange -10,10%bgimage https://wims.unice.fr/wims/gifs/en.gif
18552 bpr 694
  */
695
          URL = get_string(infile,1);
696
          fprintf(js_include_file,"/* set background image to canvas div */\ncanvas_div.style.backgroundImage = \"url(%s)\";canvas_div.style.backgroundSize = \"%dpx %dpx\";\n",URL,xsize,ysize);
697
          break;
698
        case BLINK:
699
  /*
18556 bpr 700
  @ blink time(seconds)
701
  @ NOT IMPLEMETED -YET
18552 bpr 702
  */
703
          break;
704
        case BOXPLOT:
705
  /*
706
  @ boxplot x_or_y,box-height_or_box-width,position,min,Q1,median,Q3,max
707
  @ example:<br><code>xrange 0,300<br>yrange 0,10<br>boxplot x,4,8,120,160,170,220,245</code><br>meaning: create a boxplot in x-direction, with height 4 (in yrange) and centered around line y=8
708
  @ example:<br><code>xrange 0,10<br>yrange 0,300<br>boxplot y,4,8,120,160,170,220,245</code><br>meaning: create a boxplot in y-direction, with width 4 (in xrange) and centered around line x=8
709
  @ use command <a href='#filled'>filled</a> to fill the box<br><b>note:</b> the strokecolor is used for filling Q1, the fillcolor is used for filling Q3
710
  @ use command <a href='#fillpattern'>fillpattern some_pattern</a> to use a (diamond for Q1, hatch for Q3) pattern.
18627 bpr 711
  @ use command <a href='#opacity'>opacity</a> to adjust fill_opacity of stroke and fill colors
18552 bpr 712
  @ use command <a href='#legend'>legend</a> to automatically create a legend <br>unicode allowed in legend<br>use command <a href='#fontfamily'>fontfamily</a> to set the font of the legend.
713
  @ there is no limit to the number of boxplots used.
714
  @ can <b>not</b> be set draggable and <a href='#onclick'>onclick</a> is not ready yet
715
  @ use keyword <a href="#userboxplot">userboxplot</a> before command boxplot, if a pupil must draw a boxplot (using his own min,Q1,median,Q3,max data)
716
  @ use keyword <a href="#userboxplotdata">userboxplotdata</a> before command boxplot, if a pupil must generate the data by some means.
717
  @ use command <a href="#boxplotdata">boxplotdata</a> when the boxplot should be drawn from wims-generated raw statistical date
718
  @%boxplot_1%size 400,400%xrange 0,300%yrange 0,10%opacity 120,50%filled%fillcolor orange%strokecolor blue%linewidth 2%boxplot x,4,8,120,160,170,220,245
719
  @%boxplot_2%size 400,400%xrange 0,10%yrange 0,300%opacity 120,50%filled%fillcolor orange%strokecolor blue%linewidth 2%boxplot y,4,8,120,160,170,220,245
720
  @%boxplot_3%size 400,400%xrange 0,100%yrange 0,10%fillpattern hatch%linewidth 3%fillcolor red%strokecolor green%boxplot x,1,2,4,14,27,39,66%strokecolor blue%boxplot x,1,4,15,45,50,66,87%strokecolor red%boxplot x,1,6,45,70,80,90,100%strokecolor orange%boxplot x,1,8,28,38,48,56,77%mouse red,16
721
  */
722
          js_function[DRAW_BOXPLOT] = 1;
723
          for(i=0;i<8;i++){
724
            switch(i){
725
              case 0: temp = get_string_argument(infile,0);
726
                if( strstr(temp,"x") != 0){int_data[0] = 1;}else{int_data[0] = 0;} break; /* x or y */
727
              case 1: double_data[0] = get_real(infile,0);break;/* height | width  */
728
              case 2:
729
                if( js_function[DRAW_JSBOXPLOT] == 0 ){
730
                  double_data[1] = get_real(infile,0);
731
                  fprintf(js_include_file,"var boxplot_source = 0;\n");/* we use given min,Q1,median,Q3,max */
732
                }
733
                else {
734
                  double_data[1] = get_real(infile,1);
735
                  double_data[2] = 1;
736
                  double_data[3] = 1;
737
                  double_data[4] = 1;
738
                  double_data[5] = 1;
739
                  double_data[6] = 1;
740
                  double_data[7] = 1;
741
                  i=8;
742
                }
743
                break;/* center value x or y */
744
              case 3: double_data[2] = get_real(infile,0); break;/* min */
745
              case 4: double_data[3] = get_real(infile,0); break;/* Q1 */
746
              case 5: double_data[4] = get_real(infile,0); break;/* median */
747
              case 6: double_data[5] = get_real(infile,0); break;/* Q3 */
748
              case 7: double_data[6] = get_real(infile,1); break;/* max */
749
              default:break;
750
            }
751
          }
752
          decimals = find_number_of_digits(precision);
753
          /*function draw_boxplot(canvas_type,xy,hw,cxy,data,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype0,dashtype1)*/
18557 bpr 754
          tmp_buffer=my_newmem(MAX_BUFFER);
755
          check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"draw_boxplot(%d,%d,%.*f,%.*f,[%.*f,%.*f,%.*f,%.*f,%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d);\n",BOXPLOT_CANVAS+boxplot_cnt,int_data[0],decimals,double_data[0],decimals,double_data[1],decimals,double_data[2],decimals,double_data[3],decimals,double_data[4],decimals,double_data[5],decimals,double_data[6],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1]));
18552 bpr 756
          add_to_buffer(tmp_buffer);
757
          boxplot_cnt++;
758
          reset();
759
          break;
760
        case BOXPLOTDATA:
761
  /*
762
  @ boxplotdata some_data
763
  @ 'some_data' are a list of numbers separated by a comma "," (items)
764
  @ only be used before command <code>boxplot</code>: the command <a href="#boxplot">boxplot</a> will provide the boxplot drawing of the data.
765
  @ xrange 0,100<br>yrange 0,10<br>boxplotdata 11,22,13,15,23,43,12,12,14,2,45,32,44,13,21,24,13,19,35,21,24,23<br>boxplot x,4,5
766
  @ note: wims will not check your data input | format. use js-error console to debug any problems.
767
  @ a javascript function <code>statistics()</code> will parse the data and calculate the values [min,Q1,median,Q3,max] and hand them to the boxplot draw function.
768
  @ only a single call to <code>boxplotdata</code> can be made. If multiple boxplots should be present in a single canvas, then use multiple calls to command <a href='#boxplot'>boxplot</a>
769
  @%boxplotdata%size 400,400%xrange 0,100%yrange 0,10%strokecolor orange%fillpattern hatch%linewidth 3%strokecolor green%boxplotdata 11,22,13,15,23,43,12,12,14,2,45,32,44,13,21,24,13,19,35,21,24,23%boxplot x,2,2%mouse red,16
770
  */
771
          js_function[DRAW_JSBOXPLOT] = 1;
772
          js_function[DRAW_BOXPLOT] = 1;
773
          fprintf(js_include_file,"var boxplot_source = 1;var jsboxplot_data = [%s];\n",get_string(infile,1));
774
          break;
775
        case CANVASTYPE:
776
          canvas_type = (int) (get_real(infile,1));
777
  /*
778
  @ canvastype TYPE
779
  @ for now only useful before commands filltoborder / floodfill / clickfill etc operations<br>Only the images of this TYPE will be scanned and filled
780
  @ default value of TYPE is DRAG_CANVAS e.g. 5 (all clickable / draggable object are in this canvas)
781
  @ use another TYPE, if you know what you are doing...
18627 bpr 782
  @ other possible canvasses (e.g. transparent PNG pictures, xsize &times; ysize on top of each other)<ul><li>EXTERNAL_IMAGE_CANVAS 0</li><li>BG_CANVAS   1</li><li> STATIC_CANVAS  2</li><li> MOUSE_CANVAS  3</li><li> GRID_CANVAS  4</li><li> DRAG_CANVAS  5</li><li> DRAW_CANVAS  6</li><li> TEXT_CANVAS  7</li><li> CLOCK_CANVAS  8</li><li> ANIMATE_CANVAS  9</li><li> TRACE_CANVAS  10</li><li>BOXPLOT_CANVAS 11</li><li> JSPLOT_CANVAS  100, will increase with every call</li><li> FILL_CANVAS  200, will increase with every call</li><li> USERDRAW_JSPLOT 300, will increase with every call</li><li>CLICKFILL_CANVAS 400, will increase with every call/click</li><li>BOXPLOT_CANVAS 500, will increase with every call</li></ul>
18552 bpr 783
  */
784
          break;
785
        case CENTERED:
786
          use_offset = 4;
787
   /*
18556 bpr 788
  @ centered
789
  @ keyword ; to place the text centered (in width and height) on the text coordinates(x:y)
790
  @ may be used for text exactly centered on its (x;y)
791
  @ use <a href="#fontfamily">fontfamily</a> for setting the font
792
  @ may be active for commands <a href="#text">text</a> and <a href="#string">string</a> (e.g. objects in the ''drag/drop/onclick-library``)
793
  @%centered%size 400,400%xrange -10,10%yrange -10,10%fontfamily 12pt Arial%string blue,-9,-9,no offset%point -9,-9,red%centered%string blue,-6,-6,centered%point -6,-6,red%xoffset%string blue,-3,-3,xoffset%point -3,-3,red%yoffset%string blue,0,0,yoffset%point 0,0,red%xyoffset%string blue,3,3,xyoffset%point 3,3,red%resetoffset%string blue,6,6,resetoffset%point 6,6,red
18552 bpr 794
  */
18556 bpr 795
          break;
18552 bpr 796
        case CENTERSTRING:
797
  /*
18556 bpr 798
  @ centerstring color,y-value,the text string
799
  @ title color,y-value,the text string
800
  @ draw a string centered on the canvas at y = y-value
801
  @ can not be set ''onclick`` or ''drag xy`` (...)
802
  @ unicode supported: <code>centerstring red,5,\\u2232</code>
803
  @ use a command like <code>fontfamily italic 24pt Arial</code> to set fonts on browser that support font change
804
  @%centerstring%size 400,400%xrange -10,10%yrange -10,10%bgcolor lightblue%fontfamily italic 22pt Courier%centerstring blue,7,the center
18552 bpr 805
  */
806
          js_function[DRAW_CENTERSTRING] = 1;
807
          for(i=0;i<3;i++){
808
            switch(i){
809
              case 0: stroke_color = get_color(infile,0);break;/* name or hex color */
810
              case 1: double_data[0] = get_real(infile,0);break; /* y in xrange*/
811
              case 2: temp = get_string_argument(infile,1);
812
                /* draw_text = function(canvas_type,y,font_family,stroke_color,stroke_opacity,text) */
813
                decimals = find_number_of_digits(precision);
18557 bpr 814
                tmp_buffer=my_newmem(MAX_BUFFER);
815
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_centerstring(%d,%.*f,\"%s\",\"%s\",%.2f,\"%s\");\n",canvas_root_id,decimals,double_data[0],font_family,stroke_color,stroke_opacity,temp));
18552 bpr 816
                add_to_buffer(tmp_buffer);
817
                break;
818
              default:break;
819
            }
820
          }
821
          break;
822
        case CHEMTEX:
823
  /*
824
  chemtex
825
  keyword...needs to be the first command in the script (even before the ''size`` command)
826
  only for KaTeX enabled typesetting !
827
  will include 80kB large js-library for chemisty typesetting
828
  using <a href="http://85.148.206.56/wims/download/katex.for.wims.tar.gz">KaTeX</a> : <code>katex x,y,\\ce{ chemistry tex code} like : \\ce{ Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2- }</code>
829
  using MathJaX : <code>latex x,y,\\ce{ chemistry tex code} like : \\ce{ Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2- }</code>
830
  see https://mhchem.github.io/MathJax-mhchem/
831
  %chemtex_katex_mathjax%chemtex%size 400,400%xrange -10,10%yrange -10,10%snaptogrid%fontfamily 22px Arial%strokecolor red%drag xy%centered%latex 0,8,\\ce{Hg^2+}%drag xy%centered%latex 0,4,\\ce{\\xrightarrow{\\text{I}^{-}}}%drag xy%centered%latex 0,0,\\ce{HgI2}%centered%drag xy%latex 0,-4,\\ce{\\xrightarrow{\\text{I}^{-}}}%drag xy%centered%latex 0,-8,\\ce{[Hg^{II}I4]^2-}
832
  */
833
          found_size_command = 1;
834
          fprintf(stdout,"\n<script src=\"scripts/js/KaTeX/mhchem.js\" defer></script>\n");
835
          break;
8386 schaersvoo 836
 
18552 bpr 837
        case CIRCLE:
838
  /*
839
  @ circle xc,yc,width (2*r in pixels),color
840
  @ use command <code>fcircle xc,yc,d,color</code>
841
  @ alternative: disk
842
  @ use command <code>fillcolor color</code> to set the fillcolor
843
  @ may be set <a href='#drag'>draggable</a> / <a href='#onclick'>onclick</a>
844
  @ will shrink / expand on zoom out / zoom in
845
  @%circle%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor lightblue%opacity 255,50%drag xy%circle 0,0,60,red%zoom red
846
  */
847
          for(i=0;i<4;i++){
848
            switch(i){
849
              case 0: double_data[0] = get_real(infile,0);break; /* x */
850
              case 1: double_data[1] = get_real(infile,0);break; /* y */
851
              case 2: double_data[2] = px2x((get_real(infile,0))/2) - px2x(0);break; /* for zoom in/out: radius in 'dx' xrange*/
852
              case 3: stroke_color = get_color(infile,1);/* name or hex color */
18623 bpr 853
                if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 854
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
855
                if(use_affine == TRUE ){ transform(2,2);}
856
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
857
                decimals = find_number_of_digits(precision);
18557 bpr 858
                tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 859
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,13,[%.*f],[%.*f],[%.3f],[%.3f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[1],double_data[2],double_data[2],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 860
                add_to_buffer(tmp_buffer);
861
                if(onclick != 0){object_cnt++;}/* object_cnt++;*/
862
                dragstuff[13] = 1;
863
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
864
                reset();
865
                break;
866
              default : break;
867
            }
868
          }
869
          break;
870
        case CIRCLES:
871
  /*
872
  @ circles color,xc1,yc1,r1,xc2,yc2,r2...xc_n,yc_n,r_n
873
  @ <b>attention</b> r = radius in x-range (!)
874
  @ use keyword <code>filled</code> or command <code>fcircles</code> to produce solid circles
875
  @ alternative: disks
876
  @ use command <code>fillcolor color</code> to set the fillcolor
877
  @ may be set <a href='#drag'>draggable</a> / <a href='#onclick'>onclick</a> (individually)
878
  @ will shrink / expand on zoom out / zoom in
879
  @%circles_drag%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor lightblue%opacity 255,50%drag xy%circles blue,0,0,2,2,2,3,-3,-3,3,3,3,4,3,-4,2%zoom red
880
  @%circles_onclick%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor lightblue%opacity 255,50%onclick%circles blue,0,0,2,2,2,3,-3,-3,3,3,3,4,3,-4,2%zoom red
881
  @%circles_drag_slider%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag xy%# Click circles(s) to activate%opacity 200,50%fillcolor orange%rotationcenter 2,3%slider 0,2*pi,300,30,angle degrees,Rotate%slider -5,5*pi,300,30,x display,move in x-direction%slider -10,10*pi,300,30,y display,move in y-direction%fcircles blue,0,0,0.5,2,2,1,-3,-3,1.5,3,3,0.5,3,-4,0.5
882
  */
883
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
18623 bpr 884
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 885
          i=1;
886
          while( ! done ){     /* get next item until EOL*/
887
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
888
            switch (i%3){
889
              case 1:double_data[i-1] = get_real(infile,0);break; /* x */
890
              case 2:double_data[i-1] = get_real(infile,0);break; /* y */
891
              case 0:double_data[i-1] = get_real(infile,1);break; /* r */
892
            }
893
            i++;
894
          }
895
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,3);}
896
          if(use_affine == TRUE ){ transform(i-1,3);}
897
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
8386 schaersvoo 898
 
18552 bpr 899
          decimals = find_number_of_digits(precision);
900
          for(c = 0 ; c < i-1 ; c = c+3){
18557 bpr 901
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 902
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,13,[%.*f],[%.*f],[%.3f],[%.3f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+1],double_data[c+2],double_data[c+2],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 903
            add_to_buffer(tmp_buffer);
904
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
905
          }
906
          reset();
907
          dragstuff[13] = 1;
908
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
909
          break;
910
        case CLEARBUTTON:
911
  /*
18556 bpr 912
  @ clearbutton value
913
  @ alternative: delete
914
  @ alternative: erase
915
  @ adds a button to clear the <a href="#userdraw">userdraw</a> canvas with text ''value``
18572 bpr 916
  @ <b>attention</b> command <code>clearbutton</code> is incompatible with <a href="#multidraw">multidraw</a> based drawings<br>(in <code>multidraw</code> there is always a remove_object_button for every draw primitive)
18556 bpr 917
  @ normally <a href="#userdraw">userdraw</a> primitives have the option to use middle/right mouse button on<br> a point of the object to remove this specific object...this clear button will remove all drawings
918
  @ uses the tooltip placeholder div element: may not be used with command <code>intooltip</code>
919
  @ use command <a href="#css">css</a> to style the button...
920
  @ the clearbutton will have id="canvas_scripts[%d]" ; starting with %d=0 for the first script<br>to change the style of all ''clearbutton`` of all included canvasdraw scripts, use something like<br><code>if(document.getElementById("clearbutton"+canvas_scripts[0])){<br>&nbsp;var p = 0;<br>&nbsp;while(document.getElementById("clearbutton"+canvas_scripts[p])){<br>&nbsp;&nbsp;document.getElementById("clearbutton"+canvas_scripts[p]).className="some_class_name";<br>&nbsp;&nbsp;&lt;!&minus;&minus;</code> or <code>document.getElementById("clearbutton"+canvas_scripts[p]).setAttribute("style","some_style"); &minus;&minus;&gt;<br>&nbsp;&nbsp;p++;<br>&nbsp;};<br>};</code>
921
  @%clearbutton%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor lightblue%opacity 255,50%userdraw circles,red%clearbutton Remove All
18552 bpr 922
  */
923
          if(reply_format == 29){/* eg multidraw is selected */
924
  // canvas_error("command clearbutton incompatible with multidraw...only suitable for userdraw");
925
          }
926
          add_clear_button(css_class,get_string(infile,1));
927
          break;
928
        case CLOCK:
929
  /*
930
  @ clock x,y,r(px),H,M,S,type hourglass,interactive [ ,H_color,M_color,S_color,background_color,foreground_color ]
931
  @ use command <code>opacity stroke-opacity,fill-opacity</code> to adjust foreground (stroke) and background (fill) transparency
932
  @ type hourglass:<br>type = 0: only segments<br>type = 1: only numbers<br>type = 2: numbers and segments
18627 bpr 933
  @ colors are optional: if not defined, default values will be used<br>default colors: clock 0,0,60,4,35,45,1,2<br>custom colors: clock 0,0,60,4,35,45,1,2,,,,yellow,red<br>custom colors: clock 0,0,60,4,35,45,1,2,white,green,blue,black,yellow
18552 bpr 934
  @ if you don't want a seconds hand (or minutes...), just make it invisible by using the background color of the hourglass...
935
  @ interactive <ul><li>0: not interactive, just clock(s)</li><li>1: function read_canvas() will read all active clocks in H:M:S format<br>The active clock(s) can be adjusted by pupils</li><li>2: function read_canvas() will return the clicked clock <br>(like multiplechoice; first clock in script in nr. 0 )</li><li>3: no prefab buttons...create your own buttons (or other means) to make the clock(s) adjustable by javascript function set_clock(num,type,diff)<br>wherein: num = clock id (starts with 0) ; type = 1 (hours) ; type = 2 (minutes) ; type = 3 (seconds) <br>and diff = the increment of 'type' (positive or negative)</li></ul>
936
  @ canvasdraw will not check validity of colornames...the javascript console is your best friend
937
  @ no combinations with other reply_types allowed, for now
938
  @ if interactive is set to ''1``, 6 buttons per clock will be displayed for adjusting a clock (H+ M+ S+ H- M- S-)<br> set_clock(clock_id,type,incr) <br>first clock has clock_id=0 ; type: H=1,M=2,S=3 ; incr: increment integer
18627 bpr 939
  @ note: if you need multiple -interactive- clocks on a webpage, use multiple ''clock`` commands in a single script<br>and <i>not multiple canvas scripts</i> in a single page
18552 bpr 940
  @ note: clocks will not zoom or pan, when using command <a href='#zoom'>zoom</a>
941
  @%clock_1%size 400,400%xrange -10,10%yrange -10,10%clock 0,0,120,4,35,45,0,0,red,green,blue,lightgrey,black
942
  @%clock_2%size 400,400%xrange -10,10%yrange -10,10%clock 0,0,120,4,35,45,1,1,red,green,blue,lightgrey,black
943
  @%clock_3%size 400,400%xrange -10,10%yrange -10,10%clock -5,0,80,4,35,45,2,2,red,green,blue,lightgrey,black%clock 5,0,80,3,15,65,2,2,red,green,blue,lightgrey,black
944
  @%clock_4%size 400,400%xrange -10,10%yrange -10,10%clock 0,0,120,4,35,45,0,0,red,green,blue,lightgrey,black
945
  @%clock_5%size 400,400%xrange -10,10%yrange -10,10%clock 0,0,120,4,35,45,1,1,red,green,blue,lightgrey,black
946
  @%clock_6%size 400,400%xrange -10,10%yrange -10,10%clock -5,0,80,4,35,45,2,2,red,green,blue,lightgrey,black%clock 5,0,80,8,55,15,2,2,red,green,blue,lightgrey,black
947
  @%clock_7%size 400,400%xrange -10,10%yrange -10,10%clock 0,0,120,4,35,45,2,0,red,green,blue,lightgrey,black
948
  */
949
          js_function[DRAW_CLOCK] = 1;
950
          js_function[INTERACTIVE] = 1;
8386 schaersvoo 951
 
18552 bpr 952
  /*    var clock = function(xc,yc,radius,H,M,S,h_color,m_color,s_color,bg_color,fg_color) */
953
          for(i=0;i<9;i++){
954
            switch(i){
955
              case 0: int_data[0] = x2px(get_real(infile,0)); break; /* xc */
956
              case 1: int_data[1] = y2px(get_real(infile,0)); break; /* yc */
957
              case 2: int_data[2] = get_real(infile,0);break;/* radius in px */
958
              case 3: int_data[3] = get_real(infile,0);break;/* hours */
959
              case 4: int_data[4] = get_real(infile,0);break;/* minutes */
960
              case 5: int_data[5] = get_real(infile,0);break;/* seconds */
961
              case 6: int_data[6] = get_real(infile,0);if(int_data[6] < 0 || int_data[6] > 2){canvas_error("hourglass can be 0,1 or 2");}break;/* type hourglass */
962
              case 7: int_data[7] = (int)(get_real(infile,1));/* interactive 0,1,2*/
963
                switch(int_data[7]){
964
                  case 0:break;
965
                  case 1:
966
                    if(clock_cnt == 0){
967
                      if( reply_format == 0 ){
968
                        reply_format = 18; /* user sets clock */
18557 bpr 969
                  /*
970
                     tmp_buffer=my_newmem(MAX_BUFFER);
971
                     check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "set_clock = function(num,type,diff){var name = eval(\"clocks\"+num);switch(type){case 1:name.H = parseInt(name.H+diff);break;case 2:name.M = parseInt(name.M+diff);break;case 3:name.S = parseInt(name.S+diff);break;default: break;};name = clock(name.xc,name.yc,name.radius,name.H,name.M,name.S,name.type,name.interaction,name.H_color,name.M_color,name.S_color,name.bg_color,name.fg_color);};\n"));
18552 bpr 972
                     add_to_buffer(tmp_buffer);
973
                 */
974
                        fprintf(js_include_file,"set_clock = function(num,type,diff){if(wims_status == \"done\"){return;};var name = eval(\"clocks\"+num);switch(type){case 1:name.H = parseInt(name.H+diff);break;case 2:name.M = parseInt(name.M+diff);break;case 3:name.S = parseInt(name.S+diff);break;default: break;};name = new clock(name.xc,name.yc,name.radius,name.H,name.M,name.S,name.type,name.interaction,name.H_color,name.M_color,name.S_color,name.bg_color,name.fg_color);};\n");
975
                      }
976
                      else {
977
                        canvas_error("interactive clock may not be used together with other reply_types...");
978
                      }
979
                    }
980
                    fprintf(stdout,"<p style=\"text-align:center\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,1,1)\" value=\"H+\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,2,1)\" value=\"M+\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,3,1)\" value=\"S+\"><br><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,1,-1)\" value=\"H&minus;\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,2,-1)\" value=\"M&minus;\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,3,-1)\" value=\"S&minus;\"></p>",css_class,clock_cnt,css_class,clock_cnt,css_class,clock_cnt,css_class,clock_cnt,css_class,clock_cnt,css_class,clock_cnt);
981
                    break;
982
                  case 3:
983
                    if(clock_cnt == 0){
984
                      if( reply_format == 0 ){
985
                        reply_format = 18; /* user sets clock */
986
                        fprintf(js_include_file,"set_clock = function(num,type,diff){if(wims_status == \"done\"){return;};var name = eval(\"clocks\"+num);switch(type){case 1:name.H = parseInt(name.H+diff);break;case 2:name.M = parseInt(name.M+diff);break;case 3:name.S = parseInt(name.S+diff);break;default: break;};name = new clock(name.xc,name.yc,name.radius,name.H,name.M,name.S,name.type,1,name.H_color,name.M_color,name.S_color,name.bg_color,name.fg_color);};\n");
987
                       }
988
                      else {
989
                        canvas_error("interactive clock may not be used together with other reply_types...");
990
                      }
991
                    }
992
          /*
993
          fprintf(stdout,"<p style=\"text-align:center\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,1,1)\" value=\"H+\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,2,1)\" value=\"M+\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,3,1)\" value=\"S+\"><br><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,1,-1)\" value=\"H&minus;\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,2,-1)\" value=\"M&minus;\"><input class=\"%s\" type=\"button\" onclick=\"javascript:set_clock(%d,3,-1)\" value=\"S&minus;\"></p>",css_class,clock_cnt,css_class,clock_cnt,css_class,clock_cnt,css_class,clock_cnt,css_class,clock_cnt,css_class,clock_cnt);
994
         */
995
                  break;
996
                  case 2:
997
                    if( reply_format == 0 ){
998
                      reply_format = 19; /* "onclick */
999
                      js_function[INTERACTIVE] = 1;
1000
                      fprintf(js_include_file,"\n/* begin onclick handler for clocks */\nvar reply = new Array();canvas_div.addEventListener( 'mousedown', user_click,false);\n\nfunction user_click(evt){if(evt.button == 1){var canvas_rect = clock_canvas.getBoundingClientRect();var x = evt.clientX - canvas_rect.left;var y = evt.clientY - canvas_rect.top;var p = 0;var name;var t = true;while(t){try{name = eval('clocks'+p);if( x < name.xc + name.radius && x > name.xc - name.radius ){if( y < name.yc + name.radius && y > name.yc - name.radius ){reply[0] = p;name = new clock(name.xc,name.yc,name.radius,name.H,name.M,name.S,name.type,name.interaction,name.H_color,name.M_color,name.S_color,\"lightblue\",name.fg_color);};}else{clock_ctx.clearRect(name.xc-name.radius,name.yc-name.radius,name.xc+name.radius,name.yc+name.radius);name = new clock(name.xc,name.yc,name.radius,name.H,name.M,name.S,name.type,name.interaction,name.H_color,name.M_color,name.S_color,name.bg_color,name.fg_color);};p++;}catch(e){t=false;};};};};\n");
1001
                    }
1002
                    else {
1003
                      if( reply_format != 19){
1004
                        canvas_error("clickable clock(s) may not be used together with other reply_types...");
1005
                      }
1006
                    }
1007
                    break;
1008
                  default: canvas_error("interactive must be set 0,1 or 2");break;
1009
                }
1010
                break;
1011
              case 8:
1012
                if(clock_cnt == 0 ){ /* set opacity's just once .... it should be a argument to clock(), for now it's OK */
1013
                  fprintf(js_include_file,"var clock_bg_opacity = %.2f;var clock_fg_opacity = %.2f;",fill_opacity,stroke_opacity);
1014
                }
1015
                temp = get_string(infile,3);/* optional colors, like: ,,red,,blue*/
1016
                if( strstr( temp,",") != 0 ){ temp = str_replace(temp,",","\",\""); }
1017
                else{
1018
                /* h_color,m_color,s_color,bg_color,fg_color */
1019
                  temp = ",black\",\"black\",\"black\",\"white\",\"black";}
18557 bpr 1020
                tmp_buffer=my_newmem(MAX_BUFFER);
1021
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "clocks%d = new clock(%d,%d,%d,%d,%d,%d,%d,%d,\"%s\");\n",clock_cnt,int_data[0],int_data[1],int_data[2],int_data[3],int_data[4],int_data[5],int_data[6],int_data[7],temp));
18552 bpr 1022
                add_to_buffer(tmp_buffer);
1023
                fprintf(js_include_file,"var clocks%d;",clock_cnt);
1024
                clock_cnt++;
1025
                break;
1026
              default:break;
1027
            }
1028
          }
1029
          break;
1030
        case COLORPALETTE:
1031
  /*
18556 bpr 1032
  @ colorpalette color_name_1,color_name_2,...,color_name_8
1033
  @ opacity will be the same for all colors and is set by command <a href="#opacity">opacity [0-255],[0-255]</a>
1034
  @ can be used with command <a href='#userdraw'>userdraw clickfill,color</a> when more than one fillcolor is wanted.<br>in that case use for example <a href='#replyformat'>replyformat 10</a> ... reply=x1:y1:color1,x2:y2:color2...<br>the pupil can choose from the given colors by clicking small coloured buttons.<br> the click coordinates and corresponding fillcolor will be stored in read_canvas()...when using the appropriate replyformat.<br>the first color of the palette is color=0
1035
  @ make sure to include the ''remove button`` by using command <a href='#clearbutton'>clearbutton some_text</a>
18552 bpr 1036
  */
1037
          if( use_tooltip == 1 ){canvas_error("command 'colorpalette' is incompatible with command 'intooltip tip_text'");}
1038
          fprintf(js_include_file,"var multifillcolors = [];var palettecolors = [");
1039
          while( ! done ){
1040
            temp = get_color(infile,1);
1041
            fprintf(js_include_file,"\"%s\",",temp);
1042
          }
1043
          fprintf(js_include_file,"];");/* add black to avoid trouble with dangling comma... */
1044
          add_color_palette(css_class);
1045
          break;
15111 schaersvoo 1046
 
18552 bpr 1047
        case COMMENT:
1048
          sync_input(infile);
1049
          break;
11806 schaersvoo 1050
 
18552 bpr 1051
        case COPY:
1052
  /*
1053
  @ copy x,y,x1,y1,x2,y2,[filename URL]
1054
  @ The image may be "bitmap" or "SVG"
1055
  @ Insert the region from (x1,y1) to (x2,y2) (in pixels) of [filename] to (x,y) in x/y-range
1056
  @ If x1=y1=x2=y2=-1, the whole [filename URL] is copied.
1057
  @ [filename] is the URL of the image
1058
  @ <em>TODO:move special image functions to generic 'dragstuff' library</em>
1059
  @ URL is normal URL of network reachable image file location
1060
  @ if command <a href="#drag">drag x/y/xy</a> is set before command ''copy``, the images will be draggable<br>javascript function read_canvas(); will return the x/y coordinate data in xrange/yrange of all -including non draggable- images<br>the command drag is only valid for the next image<br>draggable / non-draggable images may be mixed<br>may be used together with preceding keywords ''snaptogrid``, ''xsnaptogrid``, ''ysnaptogrid`` or <code>snaptopoints x1,y1,x2,y2...</code>.
1061
  @ if keyword <a href="#onclick">onclick</a> is set before command ''copy`` the image(s) is clickable (marked with a green rectangle around the image)<br>use 'read_dragdrop' to get the number of the clicked image(s)<br>use command 'clearbutton some_text' to reset the reply/click array.<br>example: 4 images; student clicked on image 2 and 3: reply = 0,1,1,0<br>after clicking the clear button: reply = 0,0,0,0<br>May be mixed with commands ''drag x|y|xy`` (use javascript read_canvas to get the new coordinates
1062
  @ ''onclick`` for external images may be mixed with canvas generated stuff (like lines,curves, embeded XML etc)
1063
  @ you may draw / userdraw / drag other stuff on top of an "imported" image
1064
  @ the use of a slider is not possible: if needed, use command <a href='#html'>html x,y,&lt;img src=my_image.svg /&gt; </a>
1065
  @ use keyword <a href='#centered'>centered</a> before command ''copy`` to place image center at given coordinates.
1066
  @%copy_onclick%size 400,400%xrange -10,10%yrange -10,10%onclick%copy -5,5,-1,-1,-1,-1,gifs/fr.gif%onclick%copy 5,5,-1,-1,-1,-1,gifs/en.gif%onclick%copy 5,-5,-1,-1,-1,-1,gifs/it.gif%onclick%copy -5,-5,-1,-1,-1,-1,gifs/cn.gif
1067
  @%copy_drag_xy%size 400,400%xrange -10,10%yrange -10,10%# attention: left mouse click on the image will activate dragging...%# keep left mouse button pressed while moving the image !%drag xy%copy -5,5,-1,-1,-1,-1,gifs/fr.gif%drag xy%copy 5,5,-1,-1,-1,-1,gifs/en.gif%drag xy%copy 5,-5,-1,-1,-1,-1,gifs/it.gif%drag xy%copy -5,-5,-1,-1,-1,-1,gifs/cn.gif
1068
  @%copy_drag_xy_snaptogrid%size 400,400%xrange -10,10%yrange -10,10%grid 2,2,grey%# attention: left mouse click on the image will activate dragging...%# keep left mouse button pressed while moving the image !%drag xy%# a function read_canvas_images() %copy -6,6,-1,-1,-1,-1,gifs/fr.gif%snaptogrid%drag xy%copy 6,6,-1,-1,-1,-1,gifs/en.gif%snaptogrid%drag xy%copy 6,-6,-1,-1,-1,-1,gifs/it.gif%snaptogrid%drag xy%copy -6,-6,-1,-1,-1,-1,gifs/cn.gif
1069
  */
1070
          for(i = 0 ; i<7;i++){
1071
            switch(i){
1072
              case 0: double_data[0]=get_real(infile,0);break; /* x left top corner in x/y range  */
1073
              case 1: double_data[1]=get_real(infile,0);break; /* y left top corner in x/y range */
1074
              case 2: int_data[2]=(int)(get_real(infile,0));break;/* x1 in px of external image */
1075
              case 3: int_data[3]=(int)(get_real(infile,0));break;/* y1 in px of external image */
1076
              case 4: int_data[4]=(int)(get_real(infile,0));break;/* x2 --> width  */
1077
              case 5: int_data[5]=(int)(get_real(infile,0)) ;break;/* y2 --> height */
1078
              case 6: URL = get_string(infile,1);
1079
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
1080
                if(use_affine == TRUE ){transform(2,2);}
1081
                int_data[0] = x2px(double_data[0]);
1082
                int_data[1] = y2px(double_data[1]);
1083
                int_data[6] = int_data[4] - int_data[2];/* swidth & width (if not scaling )*/
1084
                int_data[7] = int_data[5] - int_data[3];/* sheight & height (if not scaling )*/
1085
                if( onclick == 0 ){ /* no mouse needed static image copy  */
1086
                  if(js_function[DRAW_EXTERNAL_IMAGE] == 0){/* create canvas just once */
1087
                    fprintf(js_include_file,"var image_copy_canvas = create_canvas%d(%d,xsize,ysize);",canvas_root_id,STATIC_IMAGE_CANVAS);
1088
                    js_function[DRAW_EXTERNAL_IMAGE] = 1;
1089
                  }
18557 bpr 1090
                  tmp_buffer=my_newmem(MAX_BUFFER);
1091
                  check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_external_image(\"%s\",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d);\n",URL,int_data[2],int_data[3],int_data[6],int_data[7],int_data[0],int_data[1],int_data[6],int_data[7],use_offset,int_data[10]));
18552 bpr 1092
                }
1093
                else /* onclick or drag & drop external copy images */
1094
                {
1095
                  js_function[DRAG_EXTERNAL_IMAGE] = 1;
18557 bpr 1096
                  tmp_buffer=my_newmem(MAX_BUFFER);
1097
                  check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "drag_external_image(\"%s\",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d);\n",URL,int_data[2],int_data[3],int_data[6],int_data[7],int_data[0],int_data[1],int_data[6],int_data[7],onclick,object_cnt,use_offset,use_snap,int_data[10]));
18552 bpr 1098
                }
1099
                add_to_buffer(tmp_buffer);
1100
                object_cnt++;
1101
                break;
1102
              default: break;
1103
            }
1104
          }
1105
          reset();
1106
          break;
11806 schaersvoo 1107
/*
1108
HTML5 specs:
1109
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
18552 bpr 1110
img   Specifies the image, canvas, or video element to use
1111
sx   The x coordinate where to start clipping: x1 = int_data[0]
1112
sy   The y coordinate where to start clipping: x2 = int_data[1]
1113
swidth   The width of the clipped image: int_data[2] - int_data[0]
14066 bpr 1114
sheight The height of the clipped image: int_data[3] - int_data[1]
18552 bpr 1115
x   The x coordinate where to place the image on the canvas: dx1 = int_data[4]
1116
y   The y coordinate where to place the image on the canvas: dy1 = int_data[5]
1117
width   The width of the image to use (stretch or reduce the image): dx2 - dx1 = int_data[6]
1118
height   The height of the image to use (stretch or reduce the image): dy2 - dy1 = int_data[7]
11806 schaersvoo 1119
*/
18552 bpr 1120
        case COPYRESIZED:
1121
  /*
1122
  @ copyresized x1,y2,x2,y2,dx1,dy1,dx2,dy2,image_file_url
1123
  @ The image may be any "bitmap" or "SVG"
1124
  @ Insert the region from (x1,y1) to (x2,y2) (in pixels) of [ filename], <br>possibly resized,<br>to the region of (dx1,dy1) to (dx2,dy2) in x/y-range
1125
  @ (dx1:dy1) must be left top corner; (dx2:dy2) must be right bottom corner of inserted image
1126
  @ If x1=y1=x2=y2=-1, the whole [filename / URL ] is copied and resized.
1127
  @ URL is normal URL of network reachable image file location<br>(as seen from public_html-root or network reachable 'http://some_server/my_images/test.gif'<br>(eg no special wims paths are searched !!)
1128
  @ if command <a href="#drag">drag x/y/xy</a> is set before command ''copy``, the images will be draggable<br>javascript function read_canvas(); will return the x/y coordinate data in xrange/yrange of all -including non draggable- images<br>the command drag is only valid for the next image<br>draggable / non-draggable images may be mixed<br>may be used together with preceding keywords ''snaptogrid``,''xsnaptogrid``,''ysnaptogrid`` or <code>snaptopoints x1,y1,x2,y2...</code>
1129
  @ if keyword <a href="#onclick">onclick</a> is set before command ''copy`` the image(s) is clickable (marked with a green rectangle around the image)<br>use ''read_dragdrop`` to get the number of the clicked image(s)<br>use command 'clearbutton some_text' to reset the reply/click array.<br>example: 4 images; student clicked on image 2 and 3: reply = 0,1,1,0<br>after clicking the clear button: reply = 0,0,0,0<br>May be mixed with commands ''drag x|y|xy`` (use javascript read_canvas to get the new coordinates
1130
  @ ''onclick`` for external images may be mixed with canvas generated stuff (like lines,curves etc)
1131
  @ you may draw / userdraw / drag stuff on top of an "imported" image
1132
  @ when set draggable, there will be special function 'read_canvas_images()'<br>now dragging external images may be combined with 'read_canvas()' from <a href='#userdraw'>userdraw</a> or <a href='#multidraw'>multidraw</a><br>set command <a href='#precision'>precision</a> before command ''copy``
1133
  @ use keyword <a href='#centered'>centered</a> before command 'copyresized' to place image center at given coordinates.
1134
  @ <em>TODO:move special image functions to generic 'dragstuff' library</em>
1135
  */
1136
          for(i = 0 ; i<9;i++){
1137
           switch(i){
1138
            case 0: int_data[0] = (int)(get_real(infile,0));break; /* x1 */
1139
            case 1: int_data[1] = (int)(get_real(infile,0));break; /* y1 */
1140
            case 2: int_data[2] = (int)(get_real(infile,0));break;/* x2 */
1141
            case 3: int_data[3] = (int)(get_real(infile,0));break;/* y2 */
1142
            case 4: int_data[4] = x2px(get_real(infile,0));break;/* dx1 */
1143
            case 5: int_data[5] = y2px(get_real(infile,0));break;/* dy1 */
1144
            case 6: int_data[6] = x2px(get_real(infile,0));break;/* dx2 */
1145
            case 7: int_data[7] = y2px(get_real(infile,0));break;/* dy2 */
1146
            case 8: URL = get_string(infile,1);
1147
              if( int_data[1] == -1 ){ int_data[10] = 1; }else{int_data[10] = 0; }/* resized / not resized */
1148
          /* flag error when wrong diagonal:  copyresized -1,-1,-1,-1,0,0,7,7,testfig.gif */
1149
              if( int_data[7] < int_data[5] || int_data[6] < int_data[4]){
1150
                canvas_error("in copyresized,  use:<br>left top corner (dx1:dy1) and right bottom corner (dx2:dy2) ! ");
1151
              }
1152
              int_data[2] = abs(int_data[2] - int_data[0]);/* swidth */
1153
              int_data[3] = abs(int_data[3] - int_data[1]);/* sheight */
1154
              int_data[6] = abs(int_data[6] - int_data[4]);/* width */
1155
              int_data[7] = abs(int_data[7] - int_data[5]);/* height */
1156
              if( onclick == 0 ){ /* no mouse needed static image copy  */
1157
                if(js_function[DRAW_EXTERNAL_IMAGE] == 0){
1158
                  fprintf(js_include_file,"var image_copy_canvas = create_canvas%d(%d,xsize,ysize);",canvas_root_id,STATIC_IMAGE_CANVAS);
1159
                  js_function[DRAW_EXTERNAL_IMAGE] = 1;
1160
                }
18557 bpr 1161
                tmp_buffer=my_newmem(MAX_BUFFER);
1162
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_external_image(\"%s\",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d);\n",URL,int_data[0],int_data[1],int_data[2],int_data[3],int_data[4],int_data[5],int_data[6],int_data[7],use_offset,int_data[10]));
18552 bpr 1163
              }
1164
              else /* onclick or drag & drop external copy images */
1165
              {
1166
                js_function[DRAG_EXTERNAL_IMAGE] = 1;
18557 bpr 1167
                tmp_buffer=my_newmem(MAX_BUFFER);
1168
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "drag_external_image(\"%s\",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d);\n",URL,int_data[0],int_data[1],int_data[2],int_data[3],int_data[4],int_data[5],int_data[6],int_data[7],onclick,object_cnt,use_offset,use_snap,int_data[10]));
18552 bpr 1169
                object_cnt++;
1170
              }
1171
              add_to_buffer(tmp_buffer);
1172
              break;
1173
            default: break;
1174
            }
1175
          }
1176
          reset();
1177
          break;
8386 schaersvoo 1178
 
18552 bpr 1179
        case CROSSHAIR:
1180
  /*
1181
  @ crosshair x,y,color
1182
  @ draw a single crosshair point at (x;y) in color ''color``
1183
  @ use command <code>crosshairsize int</code> and / or <code>linewidth int</code> to adjust
1184
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1185
  @%crosshair%size 400,400%xrange -10,10%yrange -10,10%opacity 255,255%linewidth 2%onclick%crosshair 0,0,red%linewidth 1%onclick%crosshair 1,1,blue%linewidth 3%onclick%crosshair 3,3,green%linewidth 4%xrosshair 4,4,orange
1186
  */
1187
          for(i=0;i<3;i++){
1188
            switch(i){
1189
              case 0: double_data[0] = get_real(infile,0);break; /* x */
1190
              case 1: double_data[1] = get_real(infile,0);break; /* y */
1191
              case 2: stroke_color = get_color(infile,1);/* name or hex color */
1192
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
1193
                if(use_affine == TRUE ){ transform(2,2);}
1194
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1195
                decimals = find_number_of_digits(precision);
18557 bpr 1196
                tmp_buffer=my_newmem(MAX_BUFFER);
1197
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,7,[%.*f],[%.*f],[%d],[%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[1],crosshair_size,crosshair_size,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,0,0,0,use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1198
                add_to_buffer(tmp_buffer);
1199
                if(onclick != 0){object_cnt++;}
1200
          /* object_cnt++ */
1201
                reset();
1202
                dragstuff[7] = 1;
1203
                break;
1204
              default:break;
1205
            }
1206
          }
1207
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1208
          break;
11806 schaersvoo 1209
 
18552 bpr 1210
        case CROSSHAIRS:
1211
  /*
1212
  @ crosshairs color,x1,y1,x2,y2,...,x_n,y_n
1213
  @ draw multiple crosshair points at given coordinates in color ''color``
1214
  @ use command <code>crosshairsize int</code> and / or <code>linewidth int</code> to adjust
1215
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
1216
  @%crosshairs_1%size 400,400%xrange -10,10%yrange -10,10%opacity 255,255%snaptogrid%linewidth 2%drag xy%crosshairs red,0,0,1,1,2,2,3,3%drag x%crosshairs blue,0,1,1,2,2,3,3,4
1217
  @%crosshairs_2%size 400,400%xrange -10,10%yrange -10,10%opacity 255,255%linewidth 2%onclick%crosshairs red,0,0,1,1,2,2,3,3%onclick%crosshairs blue,0,1,1,2,2,3,3,4
12107 schaersvoo 1218
*/
18552 bpr 1219
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
1220
          fill_color = stroke_color;
1221
          i=0;
1222
          while( ! done ){     /* get next item until EOL*/
1223
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1224
            if(i%2 == 0 ){
1225
              double_data[i] = get_real(infile,0); /* x */
1226
            }
1227
            else {
1228
              double_data[i] = get_real(infile,1); /* y */
1229
            }
1230
            i++;
1231
          }
1232
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
1233
          if(use_affine == TRUE ){ transform(i-1,2);}
1234
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1235
          decimals = find_number_of_digits(precision);
1236
          for(c=0 ; c < i-1 ; c = c+2){
18557 bpr 1237
            tmp_buffer=my_newmem(MAX_BUFFER);
1238
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,7,[%.*f],[%.*f],[%d],[%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+1],crosshair_size,crosshair_size,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,1,0,0,0,use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1239
            add_to_buffer(tmp_buffer);
1240
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
1241
          }
1242
          dragstuff[7] = 1;
1243
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1244
          reset();
1245
          break;
1246
        case CROSSHAIRSIZE:
1247
  /*
1248
  @ crosshairsize int
1249
  @ default 8 (px)
1250
  */
1251
          crosshair_size = (int) (get_real(infile,1));
1252
          break;
1253
        case CSS:
1254
  /*
1255
  @ css css_class
1256
  @ may be used before any ''style-able`` html object (like inputfields or buttons) or some html objects that are generated by some canvasdraw commands
1257
  @ in case of <a href="#multidraw">multidraw</a> this command must be a table css class, for example "wimstable"
1258
  @%css%size 400,400%xrange -10,10%yrange -10,10%css wims_button_help%input 0,0,10,1,Hello
1259
  */
1260
          css_class = get_string(infile,1);
1261
          break;
1262
        case CURSOR:
1263
  /*
1264
  @ cursor some CSS cursor_style
1265
  @ alternative: pointer
1266
  @ style can be any valid CSS property value
1267
  @ choose from these types:<br>alias,all-scroll,auto,cell,context-menu,col-resize,copy,crosshair,default,e-resize,<br>ew-resize,grab,grabbing,help,move,n-resize,ne-resize,nesw-resize,ns-resize,nw-resize,<br>nwse-resize,no-drop,none,not-allowed,pointer,progress,row-resize,s-resize,se-resize,<br>sw-resize,text,url(myBall.cur),auto,vertical-text,w-resize,wait,zoom-in,zoom-out,initial
1268
  @ note: wims will not check the validity of your cursor declaration
1269
  @%cursor_css%size 400,400%xrange -10,10%yrange -10,10%cursor move%linewidth 3%drag xy%opacity 200,75%fcircles blue,-5,5,3,-4,-2,6,0,0,5,3,4,2,4,-5,4
1270
  */
1271
          fprintf(js_include_file,"canvas_div%d.style.cursor = \"%s\";",canvas_root_id,get_string(infile,1));
1272
         break;
1273
        case CURVE:
1274
  /*
18556 bpr 1275
  @ curve color,formula(x)
1276
  @ alternative: plot
18572 bpr 1277
  @ use command <a href="#trange">trange</a> in parametric functions before <b>every</b> command curve / plot <code>trange -pi,pi<br>curve color,formula1(t),formula2(t)</code><br>A next parametric curve will only be correctly plot when trange is set again !<br>this is a design flaw and not a feature...
18556 bpr 1278
  @ use command <a href="#precision">precision</a> to increase the number of digits of the plotted points
1279
  @ use command <a href="#plotsteps">plotsteps</a> to increase / decrease the amount of plotted points (default 150)
1280
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1281
  @ if you need a plot beyond xrange / yrange, use <a href="#jsplot">jsplot</a> (command ''curve`` will only calculate points within the xrange)
18569 bpr 1282
  @%curve%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%xlabel x-axis%ylabel y-axis%precision 1%grid 2,2,grey,2,2,6,grey%precision 1000%curve red,4*sqrt(x)%curve green,2*sqrt(abs(x))%curve blue,3*1/sqrt(x)%curve orange,4*sin(4/x)%dashed%curve red,4*cos(x)
18552 bpr 1283
  */
1284
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
11806 schaersvoo 1285
 
18552 bpr 1286
          if( use_parametric == TRUE ){ /* parametric color,fun1(t),fun2(t)*/
1287
            use_parametric = FALSE;
1288
            stroke_color = get_color(infile,0);
1289
            char *fun1 = get_string_argument(infile,0);
1290
            char *fun2 = get_string_argument(infile,1);
1291
            if( strlen(fun1) == 0 || strlen(fun2) == 0 ){canvas_error("parametric functions are NOT OK !");}
18557 bpr 1292
            tmp_buffer=my_newmem(MAX_BUFFER);
18634 schaersvoo 1293
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,9,%s,[%d],[%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,eval_parametric(xsize,ysize,fun1,fun2,xmin-10,xmax+10,ymin-10,ymax+10,tmin,tmax,plot_steps,precision,rotationcenter),2*line_width,2*line_width,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1294
            add_to_buffer(tmp_buffer);
1295
          }
1296
          else{
1297
            stroke_color = get_color(infile,0);
1298
            char *fun1 = get_string_argument(infile,1);
1299
            if( strlen(fun1) == 0 ){canvas_error("function is NOT OK !");}
18557 bpr 1300
            tmp_buffer=my_newmem(MAX_BUFFER);
18634 schaersvoo 1301
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,9,%s,[%d],[%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,eval(xsize,ysize,fun1,xmin-10,xmax+10,ymin-10,ymax+10,plot_steps,precision,rotationcenter),line_width,line_width,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1302
            add_to_buffer(tmp_buffer);
1303
          }
1304
          if(onclick != 0){object_cnt++;}/* object_cnt++; */
1305
          dragstuff[9] = 1;
1306
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1307
          reset();
1308
          break;
1309
        case CURVEDARROW:
14038 schaersvoo 1310
    /*
18556 bpr 1311
  @ curvedarrow x1,y1,xc,yc,x2,y2,color
1312
  @ draw a single headed curved arrow from (x1:y1) in direction of (xc:yc) to point (x2:y2)<br> note: the curve will <b>not go through</b> point (xc:yc)
1313
  @ use command <a href='#arrowhead'>arrowhead</a> to set the size of the arrow head.
1314
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
1315
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1316
  @%curvedarrow_drag%size 400,400%xrange -10,10%yrange -10,10%cursor move%linewidth 2%drag xy%curvedarrow -5,0,0,10,5,0,blue
1317
  @%curvedarrow_click%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%%onclick%curvedarrow -5,0,0,-10,5,0,blue%onclick%curvedarrow -8,0,0,5,8,3,green
11806 schaersvoo 1318
 
14029 schaersvoo 1319
h[0] = arrowhead
14066 bpr 1320
h[1] = type: 1 = single 2=double arrow
15111 schaersvoo 1321
function Shape(object_cnt,onclick,direction,type,x,y,w,h,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype0,dashtype1,use_rotate,angle,text,font_size,font_family,use_slider,rotation_center,use_offset)
14038 schaersvoo 1322
    */
18552 bpr 1323
          for(i=0;i<7;i++){
1324
            switch(i){
1325
              case 0: double_data[0] = get_real(infile,0);break; /* x1 */
1326
              case 1: double_data[1] = get_real(infile,0);break; /* y1 */
1327
              case 2: double_data[2] = get_real(infile,0);break; /* xc */
1328
              case 3: double_data[3] = get_real(infile,0);break; /* yc */
1329
              case 4: double_data[4] = get_real(infile,0);break; /* y3 */
1330
              case 5: double_data[5] = get_real(infile,0);break; /* y3 */
1331
              case 6: stroke_color = get_color(infile,1);/* name or hex color */
1332
                if(use_rotate == TRUE ){rotate(6,angle,rotationcenter,2);}
1333
                if(use_affine == TRUE ){ transform(6,2);}
1334
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1335
                decimals = find_number_of_digits(precision);
18557 bpr 1336
                tmp_buffer=my_newmem(MAX_BUFFER);
1337
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,21,[%.*f,%.*f,%.*f],[%.*f,%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[4],decimals,double_data[1],decimals,double_data[3],decimals,double_data[5],arrow_head,arrow_head,arrow_head,1,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1338
                add_to_buffer(tmp_buffer);
1339
                if(onclick != 0){object_cnt++;}/* object_cnt++;*/
1340
                reset();
1341
                break;
1342
            }
1343
          }
1344
          dragstuff[21] = 1;
1345
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1346
          break;
1347
        case CURVEDARROW2:
14038 schaersvoo 1348
    /*
18556 bpr 1349
  @ curvedarrow2 x1,y1,xc,yc,x2,y2,color
1350
  @ draw a double headed curved arrow from (x1:y1) in direction of (xc:yc) to point (x2:y2)<br> note: the curve will <b>not go through</b> point (xc:yc)
1351
  @ use command <a href='#arrowhead'>arrowhead</a> to set the size of the arrow head.
1352
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
1353
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1354
  @%curvedarrow_drag%size 400,400%xrange -10,10%yrange -10,10%cursor move%linewidth 2%drag xy%curvedarrow2 -5,0,0,10,5,0,blue
18569 bpr 1355
  @%curvedarrow_click%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%%onclick%curvedarrow2 -5,0,0,-10,5,0,blue%onclick%curvedarrow -8,0,0,5,8,3,green
14029 schaersvoo 1356
 
1357
h[0] = arrowhead
14066 bpr 1358
h[1] = type: 1 = single 2=double arrow
15111 schaersvoo 1359
function Shape(object_cnt,onclick,direction,type,x,y,w,h,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype0,dashtype1,use_rotate,angle,text,font_size,font_family,use_slider,rotation_center,use_offset)
14038 schaersvoo 1360
    */
18552 bpr 1361
          for(i=0;i<7;i++){
1362
            switch(i){
1363
              case 0: double_data[0] = get_real(infile,0);break; /* x1 */
1364
              case 1: double_data[1] = get_real(infile,0);break; /* y1 */
1365
              case 2: double_data[2] = get_real(infile,0);break; /* xc */
1366
              case 3: double_data[3] = get_real(infile,0);break; /* yc */
1367
              case 4: double_data[4] = get_real(infile,0);break; /* y3 */
1368
              case 5: double_data[5] = get_real(infile,0);break; /* y3 */
1369
              case 6: stroke_color = get_color(infile,1);/* name or hex color */
1370
              if(use_rotate == TRUE ){rotate(6,angle,rotationcenter,2);}
1371
              if(use_affine == TRUE ){ transform(6,2);}
1372
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1373
              decimals = find_number_of_digits(precision);
18557 bpr 1374
              tmp_buffer=my_newmem(MAX_BUFFER);
1375
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,21,[%.*f,%.*f,%.*f],[%.*f,%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[4],decimals,double_data[1],decimals,double_data[3],decimals,double_data[5],arrow_head,arrow_head,arrow_head,2,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1376
              add_to_buffer(tmp_buffer);
1377
              if(onclick != 0){object_cnt++;}/* object_cnt++;*/
1378
              dragstuff[21] = 1;
1379
              if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1380
              reset();
1381
              break;
1382
            }
1383
          }
1384
          break;
1385
        case CURVEDARROWS:
14038 schaersvoo 1386
    /*
18556 bpr 1387
  @ curvedarrows color,x1,y1,xc,yc,x2,y2,...,x_(n-1),y_(n-1),xc,yc,x_n,y_n
1388
  @ draw curved arrows from (x1:y1) in direction of (xc:yc) to point (x2:y2), etc<br> note: the curve will <b>not go through</b> point (xc:yc)
1389
  @ use command <a href='#arrowhead'>arrowhead</a> to set the size of the arrow head.
1390
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
1391
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1392
  @%curvedarrows_drag%size 400,400%xrange -10,10%yrange -10,10%cursor move%linewidth 2%drag xy%curvedarrows red,-8,0,0,8,8,0,-5,5,0,-10,6,3
1393
  @%curvedarrows_click%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%%onclick%curvedarrows red,-8,0,0,8,8,0,-5,5,0,-10,6,3
14029 schaersvoo 1394
 
14030 schaersvoo 1395
h[0] = arrowhead
14066 bpr 1396
h[1] = type: 1 = single 2=double arrow
15111 schaersvoo 1397
function Shape(object_cnt,onclick,direction,type,x,y,w,h,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype0,dashtype1,use_rotate,angle,text,font_size,font_family,use_slider,rotation_center,use_offset)
14038 schaersvoo 1398
    */
18552 bpr 1399
          stroke_color = get_color(infile,0);/* name or hex color */
1400
          i = 0;
1401
          decimals = find_number_of_digits(precision);
1402
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1403
          while( ! done ){
1404
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1405
            double_data[0] = get_real(infile,0); /* x1 */
1406
            double_data[1] = get_real(infile,0); /* y1 */
1407
            double_data[2] = get_real(infile,0); /* xc */
1408
            double_data[3] = get_real(infile,0); /* yc */
1409
            double_data[4] = get_real(infile,0); /* x3 */
1410
            double_data[5] = get_real(infile,1); /* y3 */
18557 bpr 1411
            tmp_buffer=my_newmem(MAX_BUFFER);
1412
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,21,[%.*f,%.*f,%.*f],[%.*f,%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[4],decimals,double_data[1],decimals,double_data[3],decimals,double_data[5],arrow_head,arrow_head,arrow_head,1,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1413
            add_to_buffer(tmp_buffer);
1414
            if(onclick != 0){object_cnt++;}
1415
            i = i + 6;
1416
          }
1417
          if(use_rotate == TRUE ){rotate(i-6,angle,rotationcenter,2);}
1418
          if(use_affine == TRUE ){ transform(i-6,2);}
1419
          dragstuff[21] = 1;
1420
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1421
          reset();
1422
          break;
1423
        case CURVEDARROWS2:
14038 schaersvoo 1424
    /*
18556 bpr 1425
  @ curvedarrows2 color,x1,y1,xc,yc,x2,y2,...x_(n-1),y_(n-1),xc,yc,x_n,y_n
1426
  @ draw double headed curved arrows from (x1:y1) in direction of (xc:yc) to point (x2:y2), etc. <br> note: the curve will <b>not go through</b> point (xc:yc)
1427
  @ use command <a href='#arrowhead'>arrowhead</a> to set the size of the arrow head.
1428
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
1429
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1430
  @%curvedarrows2_drag%size 400,400%xrange -10,10%yrange -10,10%cursor move%linewidth 2%drag xy%curvedarrows2 red,-8,0,0,8,8,0,-5,5,0,-10,6,3
1431
  @%curvedarrows2_click%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%%onclick%curvedarrow -5,0,0,-10,5,0,blue%onclick%curvedarrows2 red,-8,0,0,8,8,0,-5,5,0,-10,6,3
14030 schaersvoo 1432
 
1433
h[0] = arrowhead
14066 bpr 1434
h[1] = type: 1 = single 2=double arrow
15111 schaersvoo 1435
function Shape(object_cnt,onclick,direction,type,x,y,w,h,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype0,dashtype1,use_rotate,angle,text,font_size,font_family,use_slider,rotation_center,use_offset)
14038 schaersvoo 1436
    */
18552 bpr 1437
          stroke_color = get_color(infile,0);/* name or hex color */
1438
          i = 0;
1439
          decimals = find_number_of_digits(precision);
1440
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1441
          while( ! done ){
1442
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1443
            double_data[0] = get_real(infile,0); /* x1 */
1444
            double_data[1] = get_real(infile,0); /* y1 */
1445
            double_data[2] = get_real(infile,0); /* xc */
1446
            double_data[3] = get_real(infile,0); /* yc */
1447
            double_data[4] = get_real(infile,0); /* x3 */
1448
            double_data[5] = get_real(infile,1); /* y3 */
18557 bpr 1449
            tmp_buffer=my_newmem(MAX_BUFFER);
1450
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,21,[%.*f,%.*f,%.*f],[%.*f,%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[4],decimals,double_data[1],decimals,double_data[3],decimals,double_data[5],arrow_head,arrow_head,arrow_head,2,line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1451
            add_to_buffer(tmp_buffer);
1452
            if(onclick != 0){object_cnt++;}
1453
            i = i + 6;
1454
          }
1455
          if(use_rotate == TRUE ){rotate(i-6,angle,rotationcenter,2);}
1456
          if(use_affine == TRUE ){ transform(i-6,2);}
1457
          dragstuff[21] = 1;
1458
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1459
          reset();
1460
          break;
1461
        case DASHED:
1462
  /*
1463
  @ dashed
1464
  @ keyword (no arguments required)
1465
  @ next object will be drawn with a dashed line
1466
  @ change dashing scheme by using command <a href="#dashtype">dashtype</a>
1467
  @%dashed%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%line -5,-5,-5,5,red%dashtype 1,1%dline -4,-5,-4,5,green%dashtype 2,2%dline -3,-5,-3,5,blue%dashtype 3,3%dline 0,-5,0,5,orange%dashtype 4,4%dline 3,-5,3,5,brown
1468
  */
1469
          use_dashed = TRUE;
1470
          break;
1471
        case DASHTYPE:
1472
  /*
1473
  @ dashtype line_width_px,space_width_px
1474
  @ every indiviual object may have its own dashtype, if needed...
1475
  @ When keyword <a href='#dashed'>dashed</a> is set, the objects will be drawn with this dashtype
1476
  @ default value <code>dashtype 2,2</code> e.g. 2px line and 2px space
1477
  @ HTML5 canvas specification supports more arguments (dashing schemes) ... but not all modern browsers are yet capable
1478
  @%dashtype%size 400,400%xrange -10,10%yrange -10,10%dashtype 1,1%dhline 0,9,red%dashtype 2,2%dhline 0,8,red%dashtype 4,4%dhline 0,7,red%dashtype 6,6%dhline 0,6,red%dashtype 8,8%dhline 0,5,red%dashtype 10,10%dhline 0,4,red%dashtype 1,2%dhline 0,3,red%dashtype 2,4%dhline 0,2,red%dashtype 3,6%dhline 0,1,red%dashtype 4,8%dhline 0,0,red%linewidth 2%dashtype 1,1%dhline 0,-9,red%dashtype 2,2%dhline 0,-8,red%dashtype 4,4%dhline 0,-7,red%dashtype 6,6%dhline 0,-6,red%dashtype 8,8%dhline 0,-5,red%dashtype 10,10%dhline 0,-4,red%dashtype 1,2%dhline 0,-3,red%dashtype 2,4%dhline 0,-2,red%dashtype 4,8%dhline 0,-1,red
1479
  */
1480
          for(i=0;i<2;i++){
1481
            switch(i){
1482
              case 0 : dashtype[0] = (int) line_width*( get_real(infile,0)) ; break;
1483
              case 1 : dashtype[1] = (int) line_width*( get_real(infile,1)) ; break;
1484
            }
1485
          }
1486
          break;
1487
        case DIAMONDFILL:
1488
  /*
1489
  @ diamondfill x0,y0,dx,dy,color
1490
  @ x0,y0 in xrange / yrange
1491
  @ distances dx,dy in pixels
1492
  @ there is also a command <a href="#userdraw">userdraw diamondfill,color</a>
1493
  @%diamondfill%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%circles red,-4,0,6,4,0,6%linewidth 1%diamondfill 0,0,5,8,blue%diamondfill 0,7,8,8,lightgreen
1494
  */
1495
          js_function[DRAW_DIAMONDFILL] = 1;
1496
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1497
            js_function[DRAW_FILLTOBORDER] = 1;
1498
            add_js_filltoborder(canvas_type);
1499
          }
1500
          decimals = find_number_of_digits(precision);
1501
          for(i=0;i<5;i++){
1502
            switch(i){
1503
              case 0: double_data[0] = get_real(infile,0); break; /* x */
1504
              case 1: double_data[1] = get_real(infile,0); break; /* y  */
1505
              case 2: int_data[0] = (int) (get_real(infile,0)); break; /* dx pixel */
1506
              case 3: int_data[1] = (int) (get_real(infile,0)); break; /* dy pixel*/
1507
              case 4: stroke_color = get_color(infile,1);
1508
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
1509
                if(use_affine == TRUE ){ transform(2,2);}
18573 bpr 1510
              /* draw_diamondfill(ctx,x0,y0,dx,dy,linewidth,color,opacity,xsize,ysize) */
18557 bpr 1511
                tmp_buffer=my_newmem(MAX_BUFFER);
1512
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_diamondfill(%d,%.*f,%.*f,%d,%d,%d,\"%s\",%.2f,%d,%d);\n",STATIC_CANVAS+fill_cnt,decimals,double_data[0],decimals,double_data[1],int_data[0],int_data[1],line_width,stroke_color,stroke_opacity,xsize,ysize));
18552 bpr 1513
                add_to_buffer(tmp_buffer);
1514
                fill_cnt++;
1515
                reset();
1516
                break;
1517
              default:break;
1518
            }
1519
          }
1520
          break;
1521
        case DOTFILL:
1522
  /*
1523
  @ dotfill x0,y0,dx,dy,color
1524
  @ x0,y0 in xrange / yrange
1525
  @ distances dx,dy in pixels
1526
  @ radius of dots is linewidth
1527
  @ there is also a command <a href="#userdraw">userdraw dotfill,color</a>
1528
  @%dotfill%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%circles red,-4,0,6,4,0,6%dotfill 0,0,5,8,blue%dotfill 0,7,8,8,lightgreen
1529
  */
1530
          js_function[DRAW_DOTFILL] = 1;
1531
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1532
            js_function[DRAW_FILLTOBORDER] = 1;
1533
            add_js_filltoborder(canvas_type);
1534
          }
1535
          decimals = find_number_of_digits(precision);
1536
          for(i=0;i<5;i++){
1537
            switch(i){
1538
              case 0: double_data[0] = get_real(infile,0); break; /* x in px */
1539
              case 1: double_data[1] = get_real(infile,0); break; /* y in py */
1540
              case 2: int_data[0] = (int) (get_real(infile,0)); break; /* dx pixel */
1541
              case 3: int_data[1] = (int) (get_real(infile,0)); break; /* dy pixel*/
1542
              case 4: stroke_color = get_color(infile,1);
1543
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
1544
                if(use_affine == TRUE ){ transform(2,2);}
1545
        /* draw_dotfill(ctx,x0,y0,dx,dy,radius,color,opacity,xsize,ysize) */
18557 bpr 1546
                tmp_buffer=my_newmem(MAX_BUFFER);
1547
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_dotfill(%d,%.*f,%.*f,%d,%d,%d,\"%s\",%.2f,%d,%d);\n",FILL_CANVAS+fill_cnt,decimals,double_data[0],decimals,double_data[1],int_data[0],int_data[1],line_width,stroke_color,stroke_opacity,xsize,ysize));
18552 bpr 1548
                add_to_buffer(tmp_buffer);
1549
                fill_cnt++;
1550
                reset();
1551
                break;
1552
              default:break;
1553
            }
1554
          }
1555
          break;
1556
        case DRAG:
1557
  /*
18556 bpr 1558
  @ drag [x][y][xy]
1559
  @ the next object will be draggable in x / y / xy direction
1560
  @ the displacement can be read by <code>javascript:read_dragdrop();</code>
1561
  @ the precision (default 2 decimals) in the student reply may be set with command <a href="#precision">precision</a>.<br>Use this 'precision' command before this command 'drag x|y|xy' !
1562
  @ <a href='#onclick'>onclick</a> and ''drag x|y|xy`` may be combined (for different objects: a single object can either be onclick or drag, not both )
1563
  @ ''multi_objects`` will be numbered in the given x/y-sequence (example: points red,0,0,1,1,2,2,3,3: point (0:0) is object_number 1)
1564
  @ <b>attention</b>: static objects and ''onclick/drag`` objects of the same type (like point,circle,etc) with the same coordinates (e.g. objects that overlap) will give problems in the ''recognition algorithm``) in this example<br> <code>linewidth 4<br>point 0,0,red<br>drag xy<br>point 0,0,blue</code><br>the red point will not be recognised as draggable ! in the example<br><code>linewidth 4<br>drag xy<br>point 0,0,red<br>drag xy<br>point 0,0,blue</code><br>both points will be recognised
1565
  @ the answer is: drag_or_onclick_object_number : Xorg : Yorg : Xnew : Ynew<br>wherein object_number is the sequence number of the draggable &amp; onclick objects in your script.<br>Only draggable & onclick objects will have an object_number (e.g things like point,crosshair,line,segment,circle,rect,triangle...etc)
1566
  @ use keyword <a href='#snaptogrid'>snaptogrid</a>, <a href='#xsnaptogrid'>xsnaptogrid</a>, <a href='#ysnaptogrid'>ysnaptogrid</a> or command <a href='#snaptopoints'>snaptopoints x1,y1,x2,y2,...</a> to switch from free to discrete movement
1567
  @ in case of external images (commands copy / copyresized) the external image can be set draggable ; always xy. <br>The function javascript;read_canvas() will return the xy-coordinates of all images.
1568
  @%drag_x%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor lightblue%opacity 200,40%drag x%linewidth 2%circles blue,-5,0,3,0,0,2,5,0,4,0,4,3,0,-3,4
1569
  @%drag_y%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor lightblue%opacity 200,40%drag y%linewidth 2%circles blue,-5,0,3,0,0,2,5,0,4,0,4,3,0,-3,4
1570
  @%drag_xy%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor lightblue%opacity 200,40%drag xy%linewidth 2%circles blue,-5,0,3,0,0,2,5,0,4,0,4,3,0,-3,4
18552 bpr 1571
  */
1572
          temp = get_string(infile,1);
1573
          if(strstr(temp,"xy") != NULL ){
1574
            drag_type = 0;
1575
          } else {
1576
            if(strstr(temp,"x") != NULL ){
1577
              drag_type = 1;
1578
            }
1579
            else { drag_type = 2;}
1580
          }
1581
      /* assuming all drag&drop coordinates the same precision: so set only once */
1582
          if( print_drag_params_only_once == FALSE ){
1583
            fprintf(js_include_file,"dragdrop_precision = %d;use_dragdrop_reply = true;",precision);
1584
            print_drag_params_only_once = TRUE;
1585
          }
1586
          onclick = 2;
1587
      /* if(use_userdraw == TRUE ){canvas_error("\"drag & drop\" may not be combined with \"userdraw\" or \"pan and zoom\" \n");} */
1588
          use_dragstuff = 2;
1589
          js_function[INTERACTIVE] = 1;
1590
          break;
1591
        case ELLIPSE:
1592
  /*
1593
  @ ellipse xc,yc,width_x,height_y,color
1594
  @ ellipses with center xc/yc and width/height in x/y-range etc (this differs from flydraw syntax!)
1595
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1596
  @ will shrink / expand on zoom out / zoom in
1597
  @%ellipse%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor orange%opacity 200,40%linewidth 3%drag xy%ellipse 0,0,6,4,green%zoom blue
1598
  */
1599
          for(i=0;i<5;i++){
1600
            switch(i){
1601
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
1602
              case 1:double_data[1] = get_real(infile,0);break; /* y-values */
1603
              case 2:double_data[2] = get_real(infile,0);break; /* rx -> px */
1604
              case 3:double_data[3] = get_real(infile,0);break; /* ry -> px */
1605
              case 4:stroke_color = get_color(infile,1);/* name or hex color */
1606
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,4);}
1607
                if(use_affine == TRUE ){ transform(2,4);}
1608
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1609
                decimals = find_number_of_digits(precision);
18557 bpr 1610
                tmp_buffer=my_newmem(MAX_BUFFER);
1611
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,3,[%.*f],[%.*f],[%.*f],[%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[1],decimals,double_data[2],decimals,double_data[3],line_width,stroke_color,stroke_opacity,stroke_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1612
                add_to_buffer(tmp_buffer);
1613
                if(onclick != 0){object_cnt++;}/* object_cnt++; */
1614
                dragstuff[3] = 1;
1615
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1616
                reset();
1617
              break;
1618
            }
1619
          }
1620
          break;
1621
        case ELLIPSES:
1622
  /*
1623
  @ ellipses color,xc1,yc1,width_x1,height_y1,xc2,yc2,width_x2,height_y2,xc3,yc3,width_x3,height_y3,...
1624
  @ ellipses with center and height in x/y-range etc (this differs from flydraw syntax!)
1625
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1626
  @ will shrink / expand on zoom out / zoom in
1627
  @%ellipses%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor orange%opacity 200,40%linewidth 3%onclick%ellipses red,-3,0,2,4,0,0,4,2,3,0,6,2
1628
  */
8224 bpr 1629
 
18552 bpr 1630
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1631
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
18623 bpr 1632
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 1633
          i=1;
1634
          while( ! done ){     /* get next item until EOL*/
1635
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1636
            switch (i%4){
1637
              case 1:double_data[i-1] = get_real(infile,0);break; /* x */
1638
              case 2:double_data[i-1] = get_real(infile,0);break; /* y */
1639
              case 3:double_data[i-1] = get_real(infile,0);break; /* rx */
1640
              case 0:double_data[i-1] = get_real(infile,1);break; /* ry */
1641
              default: break;
1642
            }
1643
            i++;
1644
          }
1645
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,4);}
1646
          if(use_affine == TRUE ){ transform(i-1,4);}
1647
          decimals = find_number_of_digits(precision);
1648
          for(c = 0 ; c < i-1 ; c = c+4){
18623 bpr 1649
            check_string_length(string_length);
1650
            tmp_buffer=my_newmem(MAX_BUFFER);
1651
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,3,[%.*f],[%.*f],[%.*f],[%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+1],decimals,double_data[c+2],decimals,double_data[c+3],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 1652
            add_to_buffer(tmp_buffer);
1653
            if(onclick != 0){object_cnt++;} /* object_cnt++; */
1654
          }
1655
          reset();
1656
          dragstuff[3] = 1;
1657
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1658
          break;
1659
        case FILLALL:
1660
  /*
1661
  @ fillall color,x1,y1,x2,y2...x_n,y_n
18615 bpr 1662
  @ fill all the region containing points (x1:y1),(x2:y2)...(x_n:y_n) with color 'color'
1663
  @ any color (object) in the <a href="#canvastype">canvastype</a> will act as border to the bucket fill
18552 bpr 1664
  @ use this command after all boundary objects are declared.
1665
  @ Use command 'userdraw clickfill,color' for user click driven flood fill.
1666
  @ use command <a href="#canvastype">canvastype </a> to fill another canvas (default should be fine: DRAG_CANVAS = 5)
1667
  @ note: the fill-family of commands are very (client) cpu intensive operations!<br>filling is done pixel by pixel e.g. image size of 400x400 uses 160000 pixels: each pixel contains 4 data (R,G,B,Opacity) = 640000 data.<br>on every data a few operations / comparisons are done...<br>So have pity on your students CPU..
1668
  @%fillall%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%vlines black,-5,0,-5,0,-4,0,-4,0,3,0,3,0%hlines black,-5,0,-5,0,-5,4,-5,4,-5,-2,-5,-2%circles green,0,0,2,3,3,5,-5,-5,3%opacity 240,50%fillall blue,1,1,8,8,-8,-8
1669
  */
1670
          decimals = find_number_of_digits(precision);
1671
          fill_color=get_color(infile,0); /* how nice: now the color comes first...*/
1672
          i=0;
1673
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1674
            js_function[DRAW_FILLTOBORDER] = 1;
1675
            add_js_filltoborder(canvas_type);
1676
          }
1677
          while( ! done ){     /* get next item until EOL*/
1678
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1679
            if(i%2 == 0 ){
1680
              double_data[i] = get_real(infile,0); /* x */
1681
            }
1682
            else {
1683
              double_data[i] = get_real(infile,1); /* y */
18557 bpr 1684
              tmp_buffer=my_newmem(MAX_BUFFER);
18609 bpr 1685
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "setTimeout(function(){filltoborder(%.*f,%.*f,false,[%s,%d],%d,false,null);},1000);\n",decimals,double_data[i-1],decimals,double_data[i],fill_color,(int) (fill_opacity/0.0039215),FILL_CANVAS+fill_cnt));
18552 bpr 1686
              add_to_buffer(tmp_buffer);
1687
              fill_cnt++;
1688
            }
1689
            i++;
1690
          }
1691
          break;
1692
        case FILLED:
1693
  /*
1694
  @ filled
1695
  @ keyword (no arguments required)
1696
  @ the next ''fillable`` object (only the next !) will be filled
1697
  @ use command <a href="#fillcolor">fillcolor color</a> to set fillcolor
1698
  @ use <a href="#fillpattern">fillpattern</a> for non-solid color filling.
1699
  @ use command <code>opacity 0-255,0-255</code> to set stroke and fill-opacity
1700
  @ use command <a href='#fill'>fill x,y,color</a> or <a href="#floodfill">floodfill x,y,color</a> to fill the space around (x;y) with color <br>pixel operation implemented in javascript: use with care !
1701
  */
1702
          use_filled = 1;
1703
          break;
1704
        case FILLCOLOR:
1705
  /*
1706
  @ fillcolor colorname or #hex
1707
  @ set the color: mainly used for command 'userdraw obj,stroke_color'
18635 bpr 1708
  @ or in forms as polygon, rects and so on (add filled it the form is not already filled, so if you use rect, need to put filled, if you use frect, no need).
18552 bpr 1709
  @ see <a href="#fillpattern">fillpattern</a> for non-solid color filling.
1710
  */
18623 bpr 1711
          fillcolor = get_color(infile,1);
18635 bpr 1712
          fill_color = fillcolor;
18552 bpr 1713
          break;
1714
        case FILLPATTERN:
1715
  /*
1716
  @ fillpattern grid | hatch | diamond | dot | image_url
1717
  @ alternative: settile image_url
1718
  @ use a pattern as fillstyle
1719
  @ suitable for all fillable object including the <a href="#userdraw">userdraw objects' family</a>
18627 bpr 1720
  @ note: do not use the ''f`` for a fillable object : this is used exclusively for solid color filling.
18569 bpr 1721
  @ the fillcolor is set by the object command, for example:<br><code>size 370,370<br>xrange -5,5<br>yrange -5,5<br>opacity 165,150<br>fillpattern grid<br>circle -6,3,160,blue<br>fillpattern dot<br>circle -3,-3,160,red<br>fillpattern hatch<br>circle 0,3,160,green<br>fillpattern diamond<br>circle 3,-3,160,cyan<br>userdraw dotfill,blue<br>zoom red</code>
18552 bpr 1722
  @ the pattern dimensions are hardcoded (linewidth, radius,dx,dy are fixed)
1723
  @ the pattern color is set by command <a href='#fillcolor'>fillcolor</a> and <a href='#opacity'>opacity</a>
1724
  @ see <a href="#fillcolor">fillcolor</a> for solid color filling.
18569 bpr 1725
  @ when using an image-url, make sure it contains an ''/`` in the filename...''fillpattern &#36;module_dir/gifs/test.jpg`` will fill the next fillable object with this image.|<br>the argument to html5 canvas routine 'createPattern(img,argument)' is set to ''repeat`` e.g. if the image is smaller then the canvas, multiple copies will be used to fill the area ( e.g. ctx.fillStyle() = pattern)<br>for example:<br><code>size 150,150<br>xrange -5,5<br>yrange -5,5<br>drag xy<br>fillpattern gifs/en.gif<br>circle 0,0,100,red<br>fillpattern gifs/nl.gif<br>drag xy<br>circle -3,2,100,green<br>fillpattern gifs/cn.gif<br>drag xy<br>circle 3,2,100,green</code>
18552 bpr 1726
  @ fillpattern is also active for <a href="#userdraw">userdraw object,color</a>...<br>the userdraw family a has also ''clickfill type`` (e.g. an object gets filled between boundaries, when clicked) commands like:<br>'userdraw dotfill,color'<br>'userdraw hatchfill,color' etc
18569 bpr 1727
  @%fillpattern_1%size 400,400%xrange -5,5%yrange -5,5%opacity 165,150%fillpattern grid%circle -6,3,160,blue%fillpattern dot%circle -3,-3,160,red%fillpattern hatch%circle 0,3,160,green%fillpattern diamond%circle 3,-3,160,cyan%zoom red
18552 bpr 1728
  @%fillpattern_2%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%fillcolor green%fillpattern hatch%#fillpattern dot,diamond,grid,imageurl%userdraw circle,red
1729
  */
1730
          temp = get_string(infile,1);
1731
          use_filled = 0;
1732
          js_function[DRAW_FILL_PATTERN] = 1;
1733
          if( strstr(temp,"grid") != 0 ){ use_filled = 2;}
1734
          else{
1735
            if( strstr(temp,"hatch") != 0 ){ use_filled = 3;}
1736
            else{
1737
              if( strstr(temp,"diamond") != 0 ){ use_filled = 4;}
1738
              else{
1739
                if( strstr(temp,"dot") != 0 ){ use_filled = 5;}
1740
                else{
1741
                  if( strstr(temp,"/") != 0 ){ /* get_image_from_url() needs to be called after function definition...*/
1742
                    use_filled = 6;js_function[JS_LOAD_IMAGE] = 1;
18557 bpr 1743
                    tmp_buffer=my_newmem(MAX_BUFFER);
1744
                    check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "get_image_from_url(\"%s\");",temp));
18552 bpr 1745
                    add_to_buffer(tmp_buffer);
1746
                  }
1747
                }
1748
              }
1749
            }
1750
          }
1751
          if( use_filled == 0 ){canvas_error("fillpattern unknown or typo...choose grid,hatch,diamond of dot...");}
1752
          break;
1753
        case FILLTOBORDER:
1754
  /*
1755
  @ filltoborder x,y,bordercolor,color
1756
  @ fill the region of point (x:y) with color 'color'
18615 bpr 1757
  @ any other color than bordercolor will not act as border to the bucket fill
1758
  @ the filling is done in the connex component whih contains (x,y) of the set of points which are in a color different of bordercolor
18552 bpr 1759
  @ use this command after all boundary objects are declared.
18615 bpr 1760
  @ it can be useful to increase strokeopacity or linewidth
18552 bpr 1761
  @ use command <a href="#canvastype">canvastype </a> to fill another canvas (default should be fine: DRAG_CANVAS = 5)
1762
  @ note: filltoborder is a very (client) cpu intensive operation!<br>filling is done pixel by pixel e.g. image size of 400x400 uses 160000 pixels: each pixel contains 4 data (R,G,B,Opacity) = 640000 data.<br>on every data a few operations / comparisons are done...<br>So have pity on your students CPU..
1763
  @ maybe used together with command <a href="#userdraw">userdraw clickfill,color</a>
18615 bpr 1764
  @%filltoborder%size 400,400%xrange -10,10%yrange -10,10%canvastype 100%linewidth 2%precision 1000%jsplot blue,5*sin(x)%opacity 200,50%filltoborder 6,6,blue,green%filltoborder 6,-6,blue,red
18552 bpr 1765
  */
1766
          for(i=0 ;i < 4 ; i++){
1767
            switch(i){
1768
              case 0:double_data[0] = get_real(infile,0);break;
1769
              case 1:double_data[1] = get_real(infile,0);break;
1770
              case 2:bgcolor = get_color(infile,0);break;
1771
              case 3:fill_color = get_color(infile,1);
18569 bpr 1772
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1773
            js_function[DRAW_FILLTOBORDER] = 1;
1774
            add_js_filltoborder(canvas_type);
1775
          }
1776
          decimals = find_number_of_digits(precision);
18552 bpr 1777
         /* we need to set a timeout: the canvas is not yet draw in memory? when floodfill is called directly... */
18569 bpr 1778
          tmp_buffer=my_newmem(MAX_BUFFER);
18629 bpr 1779
          check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "setTimeout(function(){filltoborder(%.*f,%.*f,[%s,%d],[%s,%d],%d,false,null)},1000);\n",decimals,double_data[0],decimals,double_data[1],bgcolor,(int) (fill_opacity/0.0039215),fill_color,(int) (fill_opacity/0.0039215),FILL_CANVAS+fill_cnt));
18569 bpr 1780
          add_to_buffer(tmp_buffer);
1781
          fill_cnt++;
1782
          reset();
1783
          break;
18552 bpr 1784
              default:break;
1785
            }
1786
          }
1787
          break;
1788
        case FLOODFILL:
1789
  /*
1790
  @ floodfill x,y,color
1791
  @ alternative: fill
1792
  @ fill the region of point (x:y) with color 'color'
1793
  @ any other color or size of picture (borders of picture) will act as border to the bucket fill
1794
  @ use this command after all boundary objects are declared.
1795
  @ Use command <code>userdraw clickfill,color</code> for user click driven flood fill.
1796
  @ use command <a href="#canvastype">canvastype </a> to fill another canvas (default should be fine: DRAG_CANVAS = 5)
1797
  @ note: floodfill is a very (client) cpu intensive operation!<br>filling is done pixel by pixel e.g. image size of 400x400 uses 160000 pixels: each pixel contains 4 data (R,G,B,Opacity) = 640000 data.<br>on every data a few operations / comparisons are done...<br>So have pity on your students CPU..
1798
  @%floodfill%size 400,400%xrange -10,10%yrange -10,10%canvastype 100%linewidth 2%precision 1000%jsplot blue,5*sin(x)%opacity 200,50%floodfill 6,6,blue%floodfill 6,-6,red
1799
  */
1800
          for(i=0 ;i < 4 ; i++){
1801
            switch(i){
1802
              case 0:double_data[0] = get_real(infile,0);break;
1803
              case 1:double_data[1] = get_real(infile,0);break;
1804
              case 2:fill_color = get_color(infile,1);
1805
                if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1806
                  js_function[DRAW_FILLTOBORDER] = 1;
1807
                  add_js_filltoborder(canvas_type);
1808
                }
1809
                decimals = find_number_of_digits(precision);
1810
         /* we need to set a timeout: the canvas is not yet draw in memory? when floodfill is called directly... */
18557 bpr 1811
                tmp_buffer=my_newmem(MAX_BUFFER);
18609 bpr 1812
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "setTimeout(function(){filltoborder(%.*f,%.*f,false,[%s,%d],%d,false,null);},1000);\n",decimals,double_data[0],decimals,double_data[1],fill_color,(int) (fill_opacity/0.0039215),FILL_CANVAS+fill_cnt));
18552 bpr 1813
                add_to_buffer(tmp_buffer);
1814
                fill_cnt++;
1815
                break;
1816
            default:break;
1817
            }
1818
          }
1819
          reset();
1820
          break;
1821
        case FONTCOLOR:
1822
  /*
18556 bpr 1823
  @ fontcolor color
1824
  @ color: hexcolor or colorname
1825
  @ default: black
1826
  @ use command <a href="#fontfamily">fontfamily</a> to deviate from default font type
1827
  @%fontcolor%size 400,400%xrange -10,10%yrange -10,10%fontcolor red%#note: use command fontfamily to change size and shape%axis%axisnumbering%grid 2,2,grey,2,2,4,grey
18552 bpr 1828
  */
1829
          font_color = get_color(infile,1);
1830
          break;
1831
        case FONTFAMILY:
1832
  /*
18556 bpr 1833
  @ fontfamily font_description
1834
  @ set the font family; for browsers that support it
1835
  @ font_description: Arial, Courier, Helvetica etc
1836
  @ in case commands <code>string color,x,y,the string</code>, <code>stringup color,x,y,rotation,the string</code>, ''fontfamily`` can be something like:<code>fontfamily italic 34pt Arial</code>. Use correct syntax: ''font style``, ''font size pt``, ''fontfamily``
1837
  @%fontfamily%size 400,400%xrange -10,10%yrange -10,10  %fontfamily Bold 10pt Arial%string blue,-9,9,10 pt Arial%fontfamily Italic 20pt Arial%string blue,0,9,20 pt Arial%fontfamily Bold 10pt Helvetica%string blue,-9,5,10 pt Helvetica%fontfamily Italic 20pt Helvetica%string blue,0,5,20 pt Helvetica %fontfamily Bold 10pt Courier%string blue,-9,0,10 pt Courier%fontfamily Italic 20pt Courier%string blue,0,0,20 pt Courier%fontfamily Bold 10pt Fixed%string blue,-9,-5,10 pt Fixed%fontfamily Italic 20pt Fixed%string blue,0,-5,20 pt Fixed %fontfamily Bold 10pt Times%string blue,-9,-9,10 pt Times%fontfamily Italic 20pt Times%string blue,0,-9,20 pt Times
12110 schaersvoo 1838
 
18552 bpr 1839
  */
1840
          font_family = get_string(infile,1);
1841
          break;
1842
        case FONTSIZE:
1843
  /*
18556 bpr 1844
  @ fontsize font_size
1845
  @ default value 12
1846
  @ note: for some macros (like ''grid | legend | xaxistext | xlabel`` etc) sometimes command <a href="#fontfamily">fontfamily</a> can be used for some specific font-setting<br>this is however not always very straight forward... so just try and see what happens
18552 bpr 1847
  */
1848
          font_size = (int) (get_real(infile,1));
1849
          break;
1850
        case FUNCTION_LABEL:
1851
  /*
18556 bpr 1852
  @ functionlabel label_1:label_2:label_3...
1853
  @ alternative: functionlabels
1854
  @ default value ''f(x)=:g(x)=:h(x)=:i(x)=:j(x)=:k(x)=:m(x)=:n(x)=``
1855
  @ no mathml allowed (just ascii string)
1856
  @ use command <a href='#fontsize'>fontsize int</a> to adjust the size
1857
  @ use command <a href='#strokecolor'>strokecolor colorname</a> to adjust the labels (individually, if needed)
1858
  @ if needed, use before every command <a href='#userinput'>userinput function | inputfield | textarea</a>
1859
  @ no limit in amount of inputfields for userbased function plotting
1860
  @%function_label%size 400,400%xrange -5,5%yrange -5,5%precision 0%axis%axisnumbering%opacity 100,190%grid 1,1,grey,2,2,5,black%linewidth 3%linewidth 1%precision 1000%functionlabels F(x)=:H(x)=:Yield(x)=%strokecolor green%userinput function%strokecolor red%userinput function%strokecolor blue%userinput function
18552 bpr 1861
  */
1862
          temp = get_string_argument(infile,1);
1863
          function_label = list2js_array(temp,":");
1864
          break;
1865
        case GRID:/* xmajor,ymajor,gridcolor [,xminor,yminor,tick length (px), axis/tickscolor]*/
1866
  /*
18556 bpr 1867
  @ grid step_x,step_y,gridcolor
1868
  @ if keywords <a href="#axis">axis</a> or <a href="#axisnumbering">axisnumbering</a> are set, use: <code>grid step_x,step_y,major_color,minor_x,minor_y,tics height in px,axis_color</code> minor x step = step_x / minor_x
1869
  @ in that case, use command <a href="#fontcolor">fontcolor</a>, <a href="#fontsize">fontsize</a> and / or <a href="#fontfamily">fontfamily</a> to adjust font; defaults: black,12,Arial
1870
  @ if xmin > 0 and/or ymin > 0 and zooming / panning is not active: be aware that the x/y-axis numbering and x/y major/minor tic marks will not be visual as they are placed under the x-axis and left to the y-axis (in Quadrant II and IV)
1871
  @ can <b>not</b> be set <a href="#onclick">onclick</a> or <a href="#drag">drag xy</a>
1872
  @ use commands <a href="#xlabel">xlabel some_string</a> and/or <a href="#ylabel">ylabel some_string</a> to label axis; use command ''fontsize`` to adjust size: the font family is non-configurable 'italic your_fontsize px Arial' !
1873
  @ see commands <a href="#xaxis">xaxis or xaxistext</a>, <a href="#yaxis">yaxis or yaxistext</a> to set tailormade values on axis (the used font is set by command <a href="#fontfamily">fontfamily</a>; default '12px Arial')
1874
  @ see command <a href="#legend">legend</a> to set a legend for the graph; use command <a href="#fontsize">fontsize</a> to adjust size (the font family is non-configurable 'bold your_fontsize px Arial')
1875
  @%grid%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%zoom red
1876
  @%grid_axis%size 400,400%xrange -10,10%yrange -10,10%axis%grid 1,1,grey,2,2,6,black%zoom red
1877
  @%grid_axis_axisnumbering%size 400,400%xrange -10,10%yrange -10,10%fontfamily Italic 14px Courier%axis%axisnumbering%precision 0%grid 1,1,grey,2,2,6,black%zoom red
18552 bpr 1878
  */
1879
          if( js_function[DRAW_YLOGSCALE] == 1 ){canvas_error("only one grid type is allowed...");}
1880
          js_function[DRAW_GRID] = 1;
1881
          for(i=0;i<4;i++){
1882
            switch(i){
1883
              case 0:double_data[0] = get_real(infile,0);break;/* xmajor */
1884
              case 1:double_data[1] = get_real(infile,0);break;/* ymajor */
1885
              case 2:
1886
              if( use_axis == TRUE ){
1887
                stroke_color = get_color(infile,0);
1888
                done = FALSE;
1889
                int_data[0] = (int) (get_real(infile,0));/* xminor */
1890
                int_data[1] = (int) (get_real(infile,0));/* yminor */
1891
                int_data[2] = (int) (get_real(infile,0));/* tic_length */
1892
                fill_color = get_color(infile,1); /* used as axis_color*/
1893
              }
1894
              else {
1895
              int_data[0] = 1;
1896
              int_data[1] = 1;
1897
              stroke_color = get_color(infile,1);
1898
              fill_color = stroke_color;
1899
              }
1900
              if( double_data[0] <= 0 ||  double_data[1] <= 0 ||  int_data[0] <= 0 ||  int_data[1] <= 0 ){canvas_error("major or minor ticks must be positive !");}
1901
              /* set snap_x snap_y values in pixels */
1902
              fprintf(js_include_file,"snap_x = %f;snap_y = %f;",double_data[0] / int_data[0],double_data[1] / int_data[1]);
1903
              fprintf(js_include_file,"\n/* add grid */function redraw_grid(){draw_grid%d(%d,%d,%.2f,%.*f,%.*f,%d,%d,%d,%d,\"%s\",\"%s\",%d,\"%s\",%d,%d,%d,%d,%d,\"%s\",%.2f);return;};",canvas_root_id,GRID_CANVAS,precision,stroke_opacity,decimals,double_data[0],decimals,double_data[1],int_data[0],int_data[1],int_data[2],line_width,stroke_color,fill_color,font_size,font_family,use_axis,use_axis_numbering,use_dashed,dashtype[0],dashtype[1],font_color,fill_opacity);
18557 bpr 1904
              tmp_buffer=my_newmem(MAX_BUFFER);
1905
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "redraw_grid();\n"));
18552 bpr 1906
              add_to_buffer(tmp_buffer);
1907
              break;
1908
            }
1909
          }
1910
          reset();
1911
          break;
1912
        case GRIDFILL:
1913
  /*
1914
  @ gridfill x0,y0,dx,dy,color
1915
  @ x0,y0 in xrange / yrange
1916
  @ distances dx,dy in pixels
1917
  @ there is also a command <a href="#userdraw">userdraw gridfill,color</a>
1918
  @%gridfill%size 400,400%xrange -10,10%yrange -10,10%canvastype 100%linewidth 2%precision 1000%jsplot blue,5*sin(x)%opacity 200,50%gridfill 6,6,10,10,blue%gridfill 6,-6,6,6,red
11806 schaersvoo 1919
 
18552 bpr 1920
  */
1921
          js_function[DRAW_GRIDFILL] = 1;
1922
          decimals = find_number_of_digits(precision);
1923
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1924
            js_function[DRAW_FILLTOBORDER] = 1;
1925
            add_js_filltoborder(canvas_type);
1926
          }
1927
          for(i=0;i<5;i++){
1928
            switch(i){
1929
              case 0: double_data[0] = get_real(infile,0); break; /* x  */
1930
              case 1: double_data[1] = get_real(infile,0); break; /* y  */
1931
              case 2: int_data[0] = (int) (get_real(infile,0)); break; /* dx pixel */
1932
              case 3: int_data[1] = (int) (get_real(infile,0)); break; /* dy pixel*/
1933
              case 4: stroke_color = get_color(infile,1);
18557 bpr 1934
 
1935
              tmp_buffer=my_newmem(MAX_BUFFER);
1936
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_gridfill(%d,%.*f,%.*f,%d,%d,%d,\"%s\",%.2f,%d,%d);\n",STATIC_CANVAS+fill_cnt,decimals,double_data[0],decimals,double_data[1],int_data[0],int_data[1],line_width,stroke_color,stroke_opacity,xsize,ysize));
18552 bpr 1937
              add_to_buffer(tmp_buffer);
1938
              fill_cnt++;
1939
              reset();
1940
              break;
1941
              default:break;
1942
            }
1943
          }
1944
          break;
1945
        case GROUP:
1946
  /*
18556 bpr 1947
  @ group
1948
  @ keyword
1949
  @ work in 'progress'
1950
  @ all objects(*) after the command and until <a href="#kill">kill group</a> or <a href="#killslider">killslider</a> may be moved together with mouse moverments<br> (*) for now all real canvas objects and latex / xml ; but no images (work in progress)
1951
  @ may be combined with slider driven movements or drag & drop
1952
  @%group%%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 100%linewidth 4%rotationcenter 0,0%slider -2*pi,2*pi,300,40,angle active,rotate%snaptogrid%ftriangle 0,-4,-2,-2,4,--5,blue%fillcolor red%fcircle -4.4,4.4,40,blue%kill slider%slider -20,20,300,40,x active,x-slide%ftriangle -2,0,0,4,2,0,green%fcircle 4.4,4.5,40,red%kill slider%slider -20,20,300,40,y active,y-slide%fcircle 4,-4,40,green%linewidth 4%fcircle -4,-4,40,orange%kill slider%group%fcircle -4.4,4.5,10,blue%fcircle -5.4,4.5,10,blue%fcircle -6.4,4.5,10,blue%fcircle -4.4,8,16,green%fcircle -5.4,8,16,green%fcircle -6.4,8,16,green%mouse red,22%zoom red
18552 bpr 1953
  */
1954
          use_slider++;
1955
          add_slider(2);
1956
          no_reset = TRUE;
1957
          int c = 0;
1958
          for(i=last_slider;i<=use_slider;i++){ int_data[c] = i; c++; }
1959
          my_sliders = data2js_array(int_data,use_slider - last_slider+1);
1960
          if( precision == 0 ){precision = 100;}
1961
          onclick = 5;
1962
          use_dragstuff = 2;
1963
          drag_type = 0;
1964
          js_function[INTERACTIVE] = 1;
1965
          fprintf(js_include_file,"var slider%d;dragdrop_precision = %d;use_dragdrop_reply = true;",use_slider,precision);
18557 bpr 1966
          tmp_buffer=my_newmem(MAX_BUFFER);
1967
          check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "slider%d = new move_group(%d);\n",use_slider,use_slider));
18552 bpr 1968
          add_to_buffer(tmp_buffer);
1969
          break;
1970
        case HALFLINE:
1971
  /*
1972
  @ demiline x1,y1,x2,y2,color
1973
  @ alternative: halfline
1974
  @ draws a halfline starting in (x1:y1) and through (x2:y2) in color 'color' (colorname or hex)
1975
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1976
  @%halfline%size 400,400%xrange -10,10%yrange -10,10%halfline -5,5,0,0,red%halfline -5,-5,0,0,blue
1977
  */
1978
          for(i=0; i<13;i++){double_data[i]=0;}
1979
          for(i=0;i<5;i++){
1980
            switch(i){
1981
              case 0: double_data[0]= get_real(infile,0);break; /* x-values */
1982
              case 1: double_data[1]= get_real(infile,0);break; /* y-values */
1983
              case 2: double_data[10]= get_real(infile,0);break; /* x-values */
1984
              case 3: double_data[11]= get_real(infile,0);break; /* y-values */
1985
              case 4: stroke_color=get_color(infile,1);/* name or hex color */
1986
                if(double_data[0] == double_data[10]){ /* vertical halfline */
1987
                  if(double_data[1] < double_data[11]){
1988
                    double_data[3] = ymax + 1000;
1989
                  }
1990
                  else {
1991
                    double_data[3] = ymin - 1000;
1992
                  }
1993
                  double_data[2] = double_data[0];
1994
                } else { /* horizontal halfline*/
1995
                  if( double_data[1] == double_data[11] ){
1996
                    if( double_data[0] < double_data[10] ){
1997
                      double_data[2] = xmax + 1000; /* halfline to the right */
1998
                    }
1999
                    else {
2000
                      double_data[2] = xmin - 1000; /* halfline to the left */
2001
                    }
2002
                    double_data[3] = double_data[1];
2003
                  }
2004
                else {
2005
          /* any other halfline */
2006
          /* slope */
2007
                  double_data[12] = (double_data[11] - double_data[1])/(double_data[10] - double_data[0]);
2008
                /* const */
2009
                  double_data[13] = double_data[1] - double_data[12]*double_data[0];
2010
                  if( double_data[0] < double_data[10] ){
2011
                    double_data[2] = double_data[2] + 1000;
2012
                  }
2013
                  else {
2014
                    double_data[2] = double_data[2] - 1000;
2015
                  }
2016
                  double_data[3] = double_data[12]*double_data[2] + double_data[13];
2017
                }
2018
              }
2019
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2020
              if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
2021
              if(use_affine == TRUE ){ transform(4,2);}
18557 bpr 2022
              tmp_buffer=my_newmem(MAX_BUFFER);
2023
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,18,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[1],decimals,double_data[3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 2024
              add_to_buffer(tmp_buffer);
2025
              if(onclick != 0){object_cnt++;}
2026
        /* object_cnt++; */
2027
              reset();
2028
              break;
2029
            }
2030
          }
2031
          dragstuff[18] = 1;
2032
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2033
          break;
2034
        case HALFLINES:
2035
  /*
2036
  @ demilines color,x1,y1,x2,y2,....
2037
  @ alternative: halflines
2038
  @ draws halflines starting in (x1:y1) and through (x2:y2) in color 'color' (colorname or hex) etc
2039
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> indiviually
2040
  @%halflines%size 400,400%xrange -10,10%yrange -10,10%halflines red,-5,5,0,0,-5,-5,0,0
2041
  */
2042
          stroke_color=get_color(infile,0);
2043
          fill_color = stroke_color;
2044
          i=0;
2045
          while( ! done ){     /* get next item until EOL*/
2046
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
2047
            if(i%2 == 0 ){
2048
              double_data[i] = get_real(infile,0); /* x */
2049
            } else {
2050
              double_data[i] = get_real(infile,1); /* y */
2051
            }
2052
            i++;
2053
          }
2054
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2055
          decimals = find_number_of_digits(precision);
2056
          for(c = 0 ; c < i-1 ; c = c+4){
2057
            if( double_data[c] == double_data[c+2] ){ /* vertical line*/
2058
              if(double_data[c+1] < double_data[c+3]){ /* upright halfline */
2059
                double_data[c+3] = ymax + 1000;
2060
              }
2061
              else {
2062
                double_data[c+3] = ymin - 1000;/* descending halfline */
2063
              }
2064
            }
2065
            else {
2066
              if( double_data[c+1] == double_data[c+3] ){ /* horizontal line */
2067
                if(double_data[c] < double_data[c+2] ){ /* halfline to the right */
2068
                  double_data[c+2] = xmax+100;
2069
                }
2070
                else {
2071
                  double_data[c+2] = xmin-1000; /* halfline to the right */
2072
                }
2073
              }
2074
              else {
2075
      /* m */
2076
                double m = (double_data[c+3] - double_data[c+1]) /(double_data[c+2] - double_data[c]);
2077
      /* q */
2078
                double q = double_data[c+1] - ((double_data[c+3] - double_data[c+1]) /(double_data[c+2] - double_data[c]))*double_data[c];
2079
                if(double_data[c] < double_data[c+2]){ /* to the right */
2080
                  double_data[c+2] = xmax+1000; /* 1000 is needed for dragging...otherwise it is just segment */
2081
                  double_data[c+3] = (m)*(double_data[c+2])+(q);
2082
                  }
2083
                  else { /* to the left */
2084
                    double_data[c+2] = xmin - 1000;
2085
                    double_data[c+3] = (m)*(double_data[c+2])+(q);
2086
                  }
2087
                }
2088
              }
2089
              if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
2090
              if(use_affine == TRUE ){ transform(i-1,2);}
18557 bpr 2091
              tmp_buffer=my_newmem(MAX_BUFFER);
2092
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,18,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+1],decimals,double_data[c+3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 2093
              add_to_buffer(tmp_buffer);
2094
              if(onclick != 0){object_cnt++;}/* object_cnt++; */
2095
            }
2096
          reset();
2097
          dragstuff[18] = 1;
2098
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2099
          break;
2100
        case HATCHFILL:
2101
  /*
2102
  @ hatchfill x0,y0,dx,dy,color
2103
  @ x0,y0 in xrange / yrange
2104
  @ distances dx,dy in pixels
2105
  @ there is also a command <a href="#userdraw">userdraw hatchfill,color</a>
2106
  @%hatchfill%size 400,400%xrange -10,10%yrange -10,10%canvastype 100%linewidth 2%precision 1000%jsplot blue,5*sin(x)%opacity 200,50%hatchfill 6,6,10,10,blue%hatchfill 6,-6,6,6,red
2107
  */
2108
          js_function[DRAW_HATCHFILL] = 1;
2109
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
2110
            js_function[DRAW_FILLTOBORDER] = 1;
2111
            add_js_filltoborder(canvas_type);
2112
          }
2113
          decimals = find_number_of_digits(precision);
2114
          for(i=0;i<5;i++){
2115
            switch(i){
2116
              case 0: double_data[0] = get_real(infile,0); break; /* x */
2117
              case 1: double_data[1] = get_real(infile,0); break; /* y  */
2118
              case 2: int_data[0] = (int) (get_real(infile,0)); break; /* dx pixel */
2119
              case 3: int_data[1] = (int) (get_real(infile,0)); break; /* dy pixel*/
2120
              case 4: stroke_color = get_color(infile,1);
2121
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
2122
                if(use_affine == TRUE ){ transform(2,2);}
2123
                /* draw_hatchfill(ctx,x0,y0,dx,dy,linewidth,color,opacity,xsize,ysize) */
18557 bpr 2124
                tmp_buffer=my_newmem(MAX_BUFFER);
2125
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_hatchfill(%d,%.*f,%.*f,%d,%d,%d,\"%s\",%.2f,%d,%d);\n",STATIC_CANVAS+fill_cnt,decimals,double_data[0],decimals,double_data[1],int_data[0],int_data[1],line_width,stroke_color,stroke_opacity,xsize,ysize));
18552 bpr 2126
                add_to_buffer(tmp_buffer);
2127
                fill_cnt++;
2128
                reset();
2129
                break;
2130
              default:break;
2131
            }
2132
          }
2133
          break;
2134
        case HLINE:
2135
  /*
2136
  @ hline x,y,color
2137
  @ alternative: horizontalline
2138
  @ draw a horizontal line through point (x:y) in color 'color'
2139
  @ or use command <a href='#curve'>curve color,formula</a> to draw the line (uses more points to draw the line; is however better draggable)
2140
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
2141
  @%hline%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%hline 0,0,red%dhline 0,5,blue
2142
  */
2143
          for(i=0;i<3;i++) {
2144
            switch(i){
2145
              case 0: double_data[0] = get_real(infile,0);break; /* x-values */
2146
              case 1: double_data[1] = get_real(infile,0);break; /* y-values */
2147
              case 2: stroke_color = get_color(infile,1);/* name or hex color */
2148
                double_data[3] = double_data[1];
2149
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
2150
                if(use_affine == TRUE ){ transform(2,2);}
2151
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2152
                decimals = find_number_of_digits(precision);
18557 bpr 2153
                tmp_buffer=my_newmem(MAX_BUFFER);
2154
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,100*xmin,decimals,100*xmax,decimals,double_data[1],decimals,double_data[3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 2155
                add_to_buffer(tmp_buffer);
2156
                if(onclick != 0){object_cnt++;}/* object_cnt++; */
2157
                dragstuff[4] = 1;
2158
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2159
                reset();
2160
                break;
2161
            }
2162
          }
2163
          break;
2164
        case HLINES:
2165
  /*
2166
  @ hlines color,x1,y1,x2,y2,...
2167
  @ alternative: horizontallines
2168
  @ draw horizontal lines through points (x1:y1)...(xn:yn) in color 'color'
2169
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
2170
  @%hlines%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%hlines red,0,0,0,5,0,-5
2171
  */
2172
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
2173
          fill_color = stroke_color;
2174
          i=0;
2175
          while( ! done ){     /* get next item until EOL*/
2176
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
2177
            if(i%2 == 0 ){
2178
                double_data[i] = get_real(infile,0); /* x */
2179
            }
2180
            else {
2181
              double_data[i] = get_real(infile,1); /* y */
2182
            }
2183
            i++;
2184
          }
2185
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
2186
          if(use_affine == TRUE ){ transform(i-1,2);}
2187
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
11806 schaersvoo 2188
 
18552 bpr 2189
          decimals = find_number_of_digits(precision);
2190
          for(c = 0 ; c < i-1 ; c = c+2){
18557 bpr 2191
            tmp_buffer=my_newmem(MAX_BUFFER);
18607 bpr 2192
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,100*xmin,decimals,100*xmax,decimals,double_data[c+1],decimals,double_data[c+1],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 2193
            add_to_buffer(tmp_buffer);
2194
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
2195
          }
2196
          reset();
2197
          dragstuff[4] = 1;
2198
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2199
          break;
2200
        case HTTP:
2201
  /*
18556 bpr 2202
  @ http x1,y1,x2,y2,http://some_adress.com
2203
  @ an active html-page will be displayed in an "iframe" rectangle left top (x1:y1), right bottom (x2:y2)
2204
  @ do not use interactivity (or mouse) if the mouse needs to be active in the iframe
2205
  @ can <b>not</b> be ''set onclick`` or ''drag xy``
2206
  @%http%size 400,400%xrange -10,10%yrange -10,10%http 0,10,10,0,http://wims.unice.fr%opacity 200,50%drag xy%fcircle 0,0,100,green
18552 bpr 2207
  */
2208
          js_function[DRAW_HTTP] = 1;
2209
          for(i=0;i<5;i++){
2210
            switch(i){
2211
              case 0: int_data[0]=x2px(get_real(infile,0));break; /* x in x/y-range coord system -> pixel width */
2212
              case 1: int_data[1]=y2px(get_real(infile,0));break; /* y in x/y-range coord system  -> pixel height */
2213
              case 2: int_data[2]=x2px(get_real(infile,0)) - int_data[0];break; /* width in x/y-range coord system -> pixel width */
2214
              case 3: int_data[3]=y2px(get_real(infile,0)) - int_data[1];break; /* height in x/y-range coord system  -> pixel height */
2215
              case 4: decimals = find_number_of_digits(precision);
2216
                temp = get_string(infile,1);
2217
                if(strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'");}
18557 bpr 2218
                tmp_buffer = my_newmem(string_length+2);
2219
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_http(%d,%d,%d,%d,%d,\"%s\");\n",canvas_root_id,int_data[0],int_data[1],int_data[2],int_data[3],temp));
18552 bpr 2220
                add_to_buffer(tmp_buffer);
2221
               break;
2222
            }
2223
          }
2224
          reset();
2225
          break;
2226
        case HTML:
2227
  /*
18556 bpr 2228
  @ html x1,y1,html_string
2229
  @ all tags are allowed, html code using inputfields could be read using your own javascript code. Do not use ids like 'canvas_input0' etc.
2230
  @ can be set <a href='#onclick'>onclick</a>  and <a href='#drag'>drag&amp;drop</a>
2231
  @ command <a href='#affine'>affine</a> will produce CSS3 matrix transformations
2232
  @ command <a href='#rotate'>rotate</a> will rotate the object
2233
  @ use keyword <a href='#centered'>centered</a> to center the html object on (x1:y1)
2234
  @ note: using drag&amp;drop for all external P,SPAN,DIV,IMG,SVG-images onto a canvasdraw element, use ''onclick=javascript:place_image_on_canvas(this.id)``
2235
  @ note: sub &amp; sup are supported in command family <a href='#string'>string</a>, e.g. real internal canvas objects !
2236
  @%html-text%size 500,500%xrange -10,10%yrange -10,10%drag xy%centered%fillcolor lightblue%html 2,2,<h1 style='color:red'>DRAG ME</h1> %opacity 200,50%drag xy%fcircle 0,0,100,green
2237
  @%html-image-slider%size 500,500%xrange -10,10%yrange -10,10%fontsize 42%rotationcenter 0,0%centered%html 0,0,<img src="http://85.148.206.56/gifs/can1.gif">%slider 0,pi,400,40,angle active degree, %centered%html 0,0,<img src="http://85.148.206.56/gifs/can2.gif">
18552 bpr 2238
  */
2239
          js_function[DRAW_XML] = 1;
2240
          for(i=0;i<5;i++){
2241
            switch(i){
2242
              case 0: double_data[0] = get_real(infile,0);break;
2243
              case 1: double_data[1] = get_real(infile,0);break;
2244
              case 4: decimals = find_number_of_digits(precision);
2245
                if(use_affine == TRUE ){ transform(2,2);}/* needs double_data[] */
2246
                if( use_offset != 0 || drag_type != -1 ){int_data[2] = 1;}else{int_data[2] = 0;} /* only centered or not-centered */
2247
                int_data[0] = x2px(double_data[0]);/* needs px */
2248
                int_data[1] = y2px(double_data[1]);
2249
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2250
                if( use_slider != -1 && drag_type != -1){ onclick = 5; }
2251
                temp = get_string(infile,1);
2252
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","\\\""); }
2253
                if( strstr(temp,"<img ")!= 0){URL="image";}else{URL="html";}
18557 bpr 2254
                tmp_buffer=my_newmem(MAX_BUFFER);
2255
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "var draw_xml%d = {id:%d,type:'%s',x:[%d],y:[%d],mathml:\"%s\",drag_type:%d,onclick:%d,object_cnt:%d,stroke_color:\"%s\",stroke_opacity:%.2f,fill_color:\"%s\",fill_opacity:%.2f,use_center:%d,use_snap:%d,angle:%f,fontfamily:\"%s\",transform:%s,use_affine:%d,offset:[0,0],use_slider:%s,rotation_center:%s,once:true};slidergroup[%d] = null;draw_xml(draw_xml%d);\n",drawxml_cnt,drawxml_cnt,URL,int_data[0],int_data[1],temp,drag_type,onclick,object_cnt,stroke_color,stroke_opacity,fill_color,fill_opacity,int_data[2],use_snap,angle,font_family,doubledata2js_array(affine_matrix,6,decimals),use_affine,my_sliders,rotation_center,object_cnt,drawxml_cnt));
18552 bpr 2256
                add_to_buffer(tmp_buffer);
2257
                if(onclick != 0 ){object_cnt++;}
2258
                drawxml_cnt++;/* keeps track on imported img,div,p,span,mathml,svg */
2259
                break;
2260
              default:break;
2261
            }
2262
          }
2263
          reset();
2264
          break;
2265
        case IMAGEFILL:
2266
  /*
2267
  @ imagefill x,y,scaling to xsize &times; ysize?,image_url
2268
  @ The next suitable <b>filled object</b> will be filled with "image_url" tiled
2269
  @ scaling to xsize &times; ysize ? ... 1 = yes 0 = no
2270
  @ After pattern filling, the fill-color should be reset !
2271
  @ wims getins / image from class directory: imagefill 80,80,my_image.gif
2272
  @ normal url: imagefill 80,80,0,&#36;module_dir/gifs/my_image.gif
2273
  @ normal url: imagefill 80,80,1,http://adres/a/b/c/my_image.jpg
2274
  @ if dx,dy is larger than the image, the whole image will be background to the next object.
2275
  @%imagefill_tile%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%circles blue,0,0,5,3,2,5%imagefill 1.5,1.5,0,gifs/en.gif%imagefill -5,5,0,gifs/logo/wimsedu.png
2276
  @%imagefill_scale%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%circles blue,0,0,5,3,2,5%imagefill 1.5,1.5,1,gifs/en.gif%imagefill -5,5,1,gifs/logo/wimsedu.png
2277
  */
2278
          js_function[DRAW_IMAGEFILL] = 1;
2279
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
2280
            js_function[DRAW_FILLTOBORDER] = 1;
2281
            add_js_filltoborder(canvas_type);
2282
          }
2283
          for(i=0 ;i < 4 ; i++){
2284
            switch(i){
2285
              case 0:int_data[0] = (int) (get_real(infile,0));break;
2286
              case 1:int_data[1] = (int) (get_real(infile,0));break;
2287
              case 2:int_data[2] = (int) (get_real(infile,0));break; /* 0 | 1 */
2288
              case 3: URL = get_string_argument(infile,1);
18557 bpr 2289
                tmp_buffer=my_newmem(MAX_BUFFER);
2290
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_imagefill(%d,%d,%d,\"%s\",%d,%d,%d,%d);\n",STATIC_CANVAS+fill_cnt,int_data[0],int_data[1],URL,xsize,ysize,use_userdraw,int_data[2]));
18552 bpr 2291
                add_to_buffer(tmp_buffer);
2292
                fill_cnt++;
2293
              break;
2294
            }
2295
          }
2296
          reset();
2297
          break;
2298
        case IMAGEPALETTE:
2299
  /*
18556 bpr 2300
  @ imagepalette image1,image2,image3,...
2301
  @ if used before and together with command <a href='#multidraw'>multidraw images,..,..., etc</a> the image will be presented in a small table in the ''control panel``.
2302
  @%imagepalette%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%copy 0,0,-1,-1,-1,-1,gifs/images/skull_and_crossbones50.png%fontcolor green%fontfamily Bold 42pt Arial%imagepalette gifs/ca.gif,gifs/en.gif,gifs/nl.gif,gifs/fr.gif,gifs/cn.gif,gifs/de.gif,gifs/kh.gif,gifs/it.gif%multiuserinput 0,0,1%css color:blue;%multisnaptogrid 1,1,1%multilinewidth 0,4,0%# attention: use unicode text input without the slash %# \u222D ---> u222D at least will sometimes work%# otherwise cut&past unicode symbols into inputfield...%multilabel TEXT,REACTION ARROW,FLAGS,STOP DRAWING%multidraw text,arrow,images
18552 bpr 2303
   */
2304
          temp = get_string(infile,1);
2305
          temp = str_replace(temp,",","\",\"");
2306
          if( use_tooltip == 1 ){canvas_error("command 'imagepalette' is incompatible with command 'intooltip tip_text',as they use the same div-element ");}
2307
          fprintf(js_include_file,"\nvar current_id;var imagepalette = [\" %s \"];\n",temp);
2308
          break;
2309
        case INPUT:
2310
  /*
18556 bpr 2311
  @ input x,y,size,editable,value
2312
  @ to set inputfield "readonly", use editable = 0
2313
  @ if no preset 'value' is needed...use a 'space' as last item argument
2314
  @ only active inputfields (editable = 1) will be read with read_canvas();
2315
  @ if ''&#36;status=done`` (e.g. in answer.phtml) the inputfield will be cleared and set readonly<br>override this by keyword <a href="#status">status</a>
2316
  @ may be further controlled by <a href="#css">css</a>
2317
  @ if mathml inputfields are present and / or some userdraw is performed, these data will <b>not</b> be send as well (javascript:read_canvas();)
2318
  @ use keyword <a href='#xoffset'>xoffset | centered</a> if the inputfield should be centered on (x:y)<br> default is the left top corner is (x:y)
2319
  @ if the student must place an inputfield(s) somewhere on the canvas, use command <a href="#userdraw">userdraw input,color</a> or make use of a command like <a href="#userdraw">userdraw text,color</a>
2320
  @%input%size 400,400%xrange -10,10%yrange -10,10%linewidth 6%point 1,2,red%input 1,2,5,1, ?%point -5,5,red%input -5,5,5,1, ?%point 6,-5,red%input 6,-5,5,1, ?%point -5,-8,red%input -5,-8,5,1, ?
18552 bpr 2321
  */
2322
          js_function[DRAW_INPUTS] = 1;
2323
          for(i = 0 ; i<5;i++){
2324
            switch(i){
2325
              case 0: int_data[0]=x2px(get_real(infile,0));break;/* x in px */
2326
              case 1: int_data[1]=y2px(get_real(infile,0));break;/* y in px */
2327
              case 2: int_data[2]=abs( (int)(get_real(infile,0)));break; /* size */
2328
              case 3: if( get_real(infile,1) >0){int_data[3] = 1;}else{int_data[3] = 0;};break; /* readonly */
2329
              case 4: temp = get_string(infile,3);
18557 bpr 2330
                tmp_buffer=my_newmem(MAX_BUFFER);
2331
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_static_inputs(%d,%d,%d,%d,%d,%d,\"%s\",\"%s\",%d);\n",canvas_root_id,input_cnt,int_data[0],int_data[1],int_data[2],int_data[3],css_class,temp,use_offset));
18552 bpr 2332
                add_to_buffer(tmp_buffer);
2333
                input_cnt++;break;
2334
              default: break;
2335
            }
2336
          }
2337
          if(reply_format == 0 ){reply_format = 15;}
2338
          reset();
2339
          break;
2340
        case INTOOLTIP:
18556 bpr 2341
  /*
2342
  @ intooltip link_text
2343
  @ link_text is a single line (span-element)
2344
  @ link_text may also be an image URL ''http://some_server/images/my_image.png`` or ''&#36;module_dir/gifs/my_image.jpg``
2345
  @ link_text may contain HTML markup
2346
  @ the canvas will be displayed in a tooltip on ''link_text``
2347
  @ the canvas is default transparent: use command <a href="#bgcolor">bgcolor color</a> to adjust background-color, the link text will also be shown with this 'bgcolor'.
2348
  @ many ''userinput stuff`` will use the tooltip_placeholder_div element...only one is defined in the wims-page<br>and are therefore these commands are mutually exclusive.<br>keep this in mind...
2349
  @%intooltip%size 400,400%xrange -10,10%yrange -10,10%fontfamily Bold 42pt Courier%string black,0,0,Hello World%intooltip <span style="background-color:black;color:white;font-style:bold;font-size:48pt;">CLICK <br>HERE</span>
2350
  */
18552 bpr 2351
          if(use_input_xy != FALSE ){canvas_error("intooltip can not be combined with userinput_xy or other commands using the tooltip-div...see documentation");}
2352
          if( use_tooltip == 1 ){ canvas_error("command 'intooltip' cannot be combined with command 'popup'...");}
2353
          tooltip_text = get_string(infile,1);
2354
          if(strstr(tooltip_text,"\"") != 0 ){ tooltip_text = str_replace(tooltip_text,"\"","'"); }
2355
          use_tooltip = 1;
2356
          break;
2357
        case JSCURVE:
2358
  /*
18556 bpr 2359
  @ jscurve color,formula1(x),formula2(x),formula3(x),...
2360
  @ alternative: jsplot
2361
  @ your function will be plotted by the javascript engine of the client browser
2362
  @ if <a href='trange'>trange</a> is defined, the two functions will be plotted parametric<br><b>note</b>: use <i>x</i> as variable...and not <i>t</i>. Use keyword <a href='#animate'>animate</a> to animate a point on the curve
2363
  @ use only basic math in your curve: <code>sqrt,^,asin,acos,atan,log,pi,abs,sin,cos,tan,e</code>
2364
  @ use parenthesis and rawmath: use 2*x instead of 2x ; use 2^(sin(x))...etc etc (use error console to debug any errors...)
2365
  @ <b>attention</b>: last ''precision`` command in the canvasdraw script determines the calculation precision of the javascript curve plot !
2366
  @ no validity check is done by wims.
2367
  @ zooming & panning are implemented:<br>use command ''zoom color`` for mouse driven zooming<br>or use keyword 'setlimits' for inputfields setting xmin/xmax, ymin/ymax
2368
  @ zooming & panning is better than for curves produced by command <a href="#curve">curve color,formula</a> because for avery change in x/y-range the curve is recalculated in javascript
2369
  @ zooming & panning in case of userbased functionplot: reclick the OK button to re-plot curve onto the resized grid
2370
  @ use keyword <a href='animate'>animate</a> for animating a point on the curve
2371
  @ use command ''trace_jscurve formula(x)`` for tracing
2372
  @ use command ''jsmath formula(x)`` for calculating and displaying indiviual points on the curve
2373
  @ can <b>not</b> be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> (yet)
2374
  @ commands plotjump / plotstep are not active for ''jscurve``
2375
  @ every command jscurve will produce a new canvas (canvastype 111,112,113...) for this one curve.
18572 bpr 2376
  @ plotting multiple js-curves on the same canvas (for example if you want to use 'userdraw clickfill,color' on <a href="#canvastype">canvastype</a> number 111, use:<br> <code>jscurve red,fun1(x),fun2(x)...fun_n(x)</code>, you must specify individual multistrokecolors &amp; multistrokeopacity &amp; multilinewidth for these multiple js-curves to use different colors. Otherwise all curves will be the same color... Use commands like: <a href="#multistrokecolors">multistrokecolors</a>, <a href="#multilinewidth">multilinewidth</a>, <a href="#multidash">multidash</a>, <a href="#multistrokeopacity">multistroke</a>, <b>color</b> given for the command <code>jscurve color,formulas(x)</code> will not be used in that case... but the color argument must still be given in any case (otherwise syntax error...)
18556 bpr 2377
  @%jscurve%size 400,400%xrange -10,10%yrange -10,10%multistrokecolors red,green,blue,orange%multilinewidth 1,2,3%multistrokeopacity 0.5,0.8,1.0%jscurve red,sin(x),1/sin(x),sin(x^2)
18552 bpr 2378
  */
2379
          jsplot_cnt++;/* -1 --> 0 */
2380
          stroke_color = get_color(infile,0);
2381
          js_function[JS_MATH] = 1;
2382
          js_function[JS_PLOT] = 1;
2383
          if( tmin != 0 && tmax !=0){use_parametric = TRUE;}
2384
          temp = get_string(infile,1);
2385
          temp = str_replace(temp,",","\",\"");
18557 bpr 2386
          tmp_buffer=my_newmem(MAX_BUFFER);
2387
          check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "var js_plot%d = function(){jsplot(%d,[\"%s\"],[%d],[\"%s\"],[%.2f],[%d],%d,%d,[%f,%f],%d,%d,%d,0);};js_plot%d();",jsplot_cnt,JSPLOT_CANVAS+jsplot_cnt,temp,line_width,stroke_color,stroke_opacity,use_dashed,dashtype[0],dashtype[1],tmin,tmax,plot_steps,use_parametric,use_animate,jsplot_cnt));
18552 bpr 2388
          add_to_buffer(tmp_buffer);
2389
          fprintf(js_include_file,"if(typeof(all_jsplots) !== 'number'){var all_jsplots;};all_jsplots = %d;",jsplot_cnt);
11806 schaersvoo 2390
 
18552 bpr 2391
       /* we need to create multiple canvasses, so we may zoom and pan ?? */
2392
          break;
2393
        case JSMATH:
2394
  /*
18556 bpr 2395
  @ jsmath some_math_function
2396
  @ will calculate an y-value from a userinput x-value and draws a crosshair on these coordinates.
2397
  @ default labels ''x`` and ''y``; the commands ''xlabel some_x_axis_name`` and ''ylabel some_y_axis_name`` will set the label for the input fields
2398
  @ use command 'css some_css' for styling the display fields. Use command 'fontsize int' to size the labels ''x`` and ''y``
2399
  @ the client browser will convert your math function to javascript math.<br>use parenthesis and rawmath: use 2*x instead of 2x etc etc<br>no check is done on the validity of your function and/or syntax<br>use error console to debug any errors...
2400
  @ be aware that the formula's of the plotted function(s) can be found in the page javascript source
2401
  @%jsmath%size 400,400%xrange -10,10%yrange -10,10%jsplot blue,sin(x^2)%jsmath sin(x^2)
18552 bpr 2402
  */
2403
          js_function[DRAW_CROSSHAIRS] = 1;
2404
          js_function[JS_MATH] = 1;
2405
          add_calc_y(get_string(infile,1),font_size,css_class);
2406
          break;
2407
        case KILL:
2408
  /*
2409
  @ kill arguments
2410
  @ arguments may be: affine linear translation rotation slider offset  reset
2411
  @ for documentation see: killaffine,killlinear,killtranslation...
2412
  @ multiple arguments are allowed (although not checked for validity...)
2413
  */
2414
          temp = get_string(infile,1);
2415
          if(strstr(temp,"affine") != 0 ){use_affine = FALSE;affine_matrix[0] = 1.0;affine_matrix[1] = 0.0;affine_matrix[2] = 0.0;affine_matrix[3] = 1.0;affine_matrix[4] = 0.0;affine_matrix[5] = 0.0;}
2416
          if(strstr(temp,"linear") != 0 ){affine_matrix[0] = 1.0;affine_matrix[1] = 0.0;affine_matrix[2] = 0.0;affine_matrix[3] = 1.0;}
2417
          if(strstr(temp,"translation") != 0 || strstr(temp,"translate") != 0 ){affine_matrix[4] = 0.0;affine_matrix[5] = 0.0;}
2418
          if(strstr(temp,"rotation") != 0 || strstr(temp,"rotate") != 0 ){use_rotate = FALSE;angle = 0.0;rotation_center="null";}
2419
          if(strstr(temp,"slider") != 0 ){slider_type = "0";my_sliders = "[-1]";last_slider = use_slider+1;}
2420
          if(strstr(temp,"group") != 0 ){onclick = 0;drag_type = -1;slider_type = "0";my_sliders = "[-1]";last_slider = use_slider+1;use_slider = -1;reset();}
2421
          if(strstr(temp,"reset") != 0 ){if(no_reset == FALSE){no_reset = TRUE;}else{no_reset = FALSE;reset();}}
2422
          if(strstr(temp,"offset") != 0 ){use_offset = 0;}
2423
          break;
2424
        case KILLAFFINE:
2425
  /*
2426
  @ killaffine
2427
  @ keyword: resets the transformation matrix to 1,0,0,1,0,0
2428
  @ note: any active linear transformation will also be reset: tx=0, ty=0
2429
  */
2430
          use_affine = FALSE;
2431
          affine_matrix[0] = 1.0;
2432
          affine_matrix[1] = 0.0;
2433
          affine_matrix[2] = 0.0;
2434
          affine_matrix[3] = 1.0;
2435
          affine_matrix[4] = 0.0;
2436
          affine_matrix[5] = 0.0;
2437
          break;
2438
        case KILLLINEAR:
2439
  /*
2440
  @ killlinear
2441
  @ keyword: resets the transformation matrix to 1,0,0,1,tx,ty
2442
  @ note:any active transformation or rotation will not be killed (tx,ty remain active)
2443
  */
2444
          affine_matrix[0] = 1.0;
2445
          affine_matrix[1] = 0.0;
2446
          affine_matrix[2] = 0.0;
2447
          affine_matrix[3] = 1.0;
2448
          break;
2449
        case KILLROTATE:
2450
  /*
18556 bpr 2451
  @ killrotate
2452
  @ will set the rotation angle to 0.
18572 bpr 2453
  @ will also reset the command <a href="#rotationcenter">rotationcenter</a> to the first (x;y) of the next rotatable/slidable object(s) <br>eg a following rotate command will have the first object point as rotation center
18556 bpr 2454
  @ if not set, the rotation center will remain unchanged
2455
  @ note:any active transformation or linear will not be killed (e.g an active transformation matrix remains active)
2456
  @%killrotate%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%rotationcenter 0,0%# slider is active for all following objects until 'killslider'%slider -10,10,300,40,angle degree,Rotate%drag xy%# after dragging the object must be clicked to re-activate the slider%linewidth 4%arrow 0,0,6,0,9,blue%%# reset rotation center to the first (x,y) of the next object/arrow...%killrotate%drag xy%# after dragging the object must be clicked to re-activate the slider%arrow 0,0,6,1,9,red
18552 bpr 2457
  */
2458
          use_rotate = FALSE;
2459
          angle = 0.0;
2460
          rotation_center="null";
2461
          break;
2462
        case KILLSLIDER:
2463
  /*
18556 bpr 2464
  @ killslider
2465
  @ keyword (no arguments required)
2466
  @ ends grouping of object under a previously defined slider
18552 bpr 2467
  */
2468
          slider_type = "0";
2469
          my_sliders = "[-1]";
2470
          last_slider = use_slider+1;
2471
          break;
2472
        case KILLTRANSLATION:
2473
  /*
18556 bpr 2474
  @ killtranslation
2475
  @ alternative: killtranslate
2476
  @ note: a active linear or affine transformation will not be 100% reset...only tx=0,ty=0
2477
  @ resets the translation matrix a,b,c,d,tx,ty to a,b,c,d,0,0
18552 bpr 2478
  */
2479
          affine_matrix[4] = 0.0;
2480
          affine_matrix[5] = 0.0;
2481
          break;
2482
        case LATEX:
2483
  /*
18556 bpr 2484
  @ latex x,y,tex string
2485
  @ alternative: math
18572 bpr 2486
  @ note: <b>for a single greek letter</b> ,please be smart and use a command like <a href='#string'>string</a> along with <b>unicode</b> !! <br>possibly together with command <a href="#xyoffset">xoffset, yoffset or xyoffset</a><br> See <a target='new' href='https://en.wikipedia.org/wiki/Mathematical_operators_and_symbols_in_Unicode'>https://en.wikipedia.org/wiki/Mathematical_operators_and_symbols_in_Unicode</a><br> See <a target='new' href='https://en.wikipedia.org/wiki/Greek_script_in_Unicode'>https://en.wikipedia.org/wiki/Greek_script_in_Unicode</a>
18556 bpr 2487
  @ you may also use command <a href="#mathml">mathml</a> for xml strings generated with wims commmand ''mathmlmath`` (will not work on KaTeX enabled WIMS)
2488
  @ transformation commands <a href='#affine'>affine</a>, <a href='#translation'>translation</a> and <a href='#rotate'>rotate</a> are supported.(onclick and drag will work)
2489
  @ can be set onclick: <code>javascript:read_dragdrop();</code> will return click numbers of mathml-objects<br>if 4 clickable object are drawn, the reply could be 1,0,1,0 ... meaning clicked on the first and third object
2490
  @ can be set draggable:<code>javascript:read_dragdrop();</code> will return all coordinates in the same order as the canvas script: unmoved object will have their original coordinates...
2491
  @ can be moved/rotated with command <a href='#slider'>slider</a>
2492
  @ snaptogrid is supported
18627 bpr 2493
  @ when clicked, the color of the 'div background' of the 'mathobject' will be determined by the <a href="#fillcolor">fillcolor</a> and <a href="#opacity">opacity</a> settings
18556 bpr 2494
  @ userdraw may be combined with 'latex' ; the js-function 'read_canvas()' will contain the coordinates of the drawing.
2495
  @ userdraw may be combined; the read_canvas() will contain the drawing.
2496
  @ draggable or onclick 'external images' from command <a href='#copyresized'>copy or copyresized</a> and all objects from commands <a href='#html'>html</a> or <a href='#obabel'>obabel</a> can be combined with drag and/or onclick mathml
2497
  @ other drag objects (circles/rects etc) are supported, but read_dragdrop() will probably be difficult to interpret...
2498
  @ if inputfields are incorporated in mathml (with id's: id='mathml0',id='mathml1',...id='mathml_n')<br>the user_input values will be read by <code>javascript:read_mathml();</code>. <b>attention</b>: if after this mathml-input object other user-interactions are included, these will read mathml too using "read_canvas();"
2499
  @ If other inputfields (command input / command textarea) or userdraw are performed, the function read_canvas() will not read mathml. Use some generic function to read it....
2500
  @ use keyword <a href='#centered'>centered</a> to center the katex div object on (x1:y1) <br>this may not work as expected for MathJaX [TO BE TESTED]
2501
  @ note: if you want to include external TeX via drag&amp;drop onto a canvasdraw element, use \\mmlid{integer} in the tex-command:''!insmath \\mmlid{1}\\frac{1}{\pi}``<br> (if your wims_mathml does not support it...use <a href="http://85.148.206.56/wims/download/Mathml.tar.gz">this version...</a>)
2502
  @ note: the same is true for all external P,SPAN,DIV,IMG,SVG-images via drag&amp;drop onto a canvasdraw element, use ''onclick=javascript:place_image_on_canvas(this.id)``
2503
  @%latex_drag%size 400,400%xrange -10,10%yrange -10,10%grid 2,2,grey%strokecolor red%drag xy%centered%latex -6,5,\\frac{1}{2}+ \\frac{\\pi}{2}%strokecolor blue%drag xy%centered%latex -3,5,\\frac{1}{3}+ \\frac{\\pi}{3}%strokecolor green%drag xy%centered%latex 0,5,\\frac{1}{4}+ \\frac{\\pi}{4}%strokecolor orange%drag xy%fontfamily 26px Times%centered%latex 3,5,\\frac{1}{5}+ \\frac{\\pi}{6}
2504
  @%latex%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 3%vline 0,0,green%hline 0,0,green%fontfamily 16px Arial%fillcolor orange%strokecolor blue%linewidth 2%slider 0,4*pi,400,40,angle degree active, %centered%latex 0,0,\\frac{12345}{23456} \\times \\frac{12345}{23456}%translate 4,4%centered%rotate 180%drag xy%html 0,0,<table><tr><th>HTML TABLE</th></tr><tr><th><a href="https://wimsedu.info/">WIMS EDU </a> </th></tr><tr><td><img src="gifs/en.gif"></tr><tr><td><img src="gifs/nl.gif"></tr><tr><td><img src="gifs/fr.gif"></tr><tr><td><img src="gifs/cn.gif"></tr><tr><td><img src="gifs/it.gif"></tr></table>%userdraw arrow2,red
18552 bpr 2505
  */
2506
          js_function[DRAW_XML] = 1;
2507
          for(i=0;i<3;i++){
2508
            switch(i){
2509
              case 0: double_data[0]=get_real(infile,0);break; /* x in x/y-range coord system -> pixel width */
2510
              case 1: double_data[1]=get_real(infile,0);break; /* y in x/y-range coord system  -> pixel height */
2511
              case 2: decimals = find_number_of_digits(precision);
2512
                temp = get_string(infile,1);
2513
                if(use_affine == TRUE ){ transform(2,2);}/* slider will use css-rotate transformation */
2514
                if( use_offset != 0 || drag_type != -1 ){int_data[2] = 1;}else{int_data[2] = 0;} /* only centered or not-centered */
2515
                int_data[0] = x2px(double_data[0]);
2516
                int_data[1] = y2px(double_data[1]);
2517
                if( use_slider != -1 && onclick == 0 ){ onclick = 5;}
2518
                if( use_slider != -1 && drag_type != -1){ onclick = 5; }
15757 schaersvoo 2519
#ifdef KATEX_INSTALLED
18552 bpr 2520
                if( strstr(temp,"\\") != 0 ){ temp = str_replace(temp,"\\","\\\\"); }
2521
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'"); }
18557 bpr 2522
                tmp_buffer=my_newmem(MAX_BUFFER);
2523
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "var draw_xml%d = {id:%d,type:'katex',x:[%d],y:[%d],mathml:\"%s\",drag_type:%d,onclick:%d,object_cnt:%d,stroke_color:\"%s\",stroke_opacity:%.2f,fill_color:\"%s\",fill_opacity:%.2f,use_center:%d,use_snap:%d,angle:%f,fontfamily:\"%s\",transform:%s,use_affine:%d,offset:[0,0],use_slider:%s,rotation_center:%s,once:true};draw_xml(draw_xml%d);\n",drawxml_cnt,drawxml_cnt,int_data[0],int_data[1],temp,drag_type,onclick,object_cnt,stroke_color,stroke_opacity,fill_color,fill_opacity,int_data[2],use_snap,angle,font_family,doubledata2js_array(affine_matrix,6,decimals),use_affine,my_sliders,rotation_center,drawxml_cnt));
15757 schaersvoo 2524
#else
18552 bpr 2525
                temp = getMML(temp);/* generate MathML for Firefox or MathJaX */
2526
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'"); }
18557 bpr 2527
                tmp_buffer=my_newmem(MAX_BUFFER);
2528
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "var draw_xml%d = {id:%d,type:'mathml',x:[%d],y:[%d],mathml:\"%s\",drag_type:%d,onclick:%d,object_cnt:%d,stroke_color:\"%s\",stroke_opacity:%.2f,fill_color:\"%s\",fill_opacity:%.2f,use_center:%d,use_snap:%d,angle:%f,fontfamily:\"%s\",transform:%s,use_affine:%d,offset:[0,0],use_slider:%s,rotation_center:%s,once:true};draw_xml(draw_xml%d);\n",drawxml_cnt,drawxml_cnt,int_data[0],int_data[1],temp,drag_type,onclick,object_cnt,stroke_color,stroke_opacity,fill_color,fill_opacity,int_data[2],use_snap,angle,font_family,doubledata2js_array(affine_matrix,6,decimals),use_affine,my_sliders,rotation_center,drawxml_cnt));
15757 schaersvoo 2529
#endif
18552 bpr 2530
                add_to_buffer(tmp_buffer);
2531
                if(onclick != 0 ){object_cnt++;}
2532
                drawxml_cnt++;/* keeps track on imported img,div,p,span,mathml,svg */
2533
                break;
2534
              default:break;
2535
              }
2536
          }
2537
          reset();
2538
          break;
2539
        case LATTICE:
2540
  /*
18556 bpr 2541
  @ lattice x0,y0,xv1,yv1,xv2,yv2,n1,n2,color
2542
  @ can <b>not</b> be set ''onclick`` or ''drag xy``
2543
  @%lattice%size 400,400%xrange -10,10%yrange -10,10%fillcolor red%linewidth 2%lattice -10,-10,0,1,1,1,10,10,red%fillcolor blue%lattice 10,-10,0,1,-1,1,10,10,blue
18552 bpr 2544
  */
2545
          js_function[DRAW_LATTICE] = 1;
2546
          for( i = 0; i<9; i++){
2547
            switch(i){
2548
              case 0: int_data[0] = x2px(get_real(infile,0));break; /* x0-values  -> x-pixels*/
2549
              case 1: int_data[1] = y2px(get_real(infile,0));break; /* y0-values  -> y-pixels*/
2550
              case 2: int_data[2] = (int) (get_real(infile,0));break; /* x1-values  -> x-pixels*/
2551
              case 3: int_data[3] = (int) -1*(get_real(infile,0));break; /* y1-values  -> y-pixels*/
2552
              case 4: int_data[4] = (int) (get_real(infile,0));break; /* x2-values  -> x-pixels*/
2553
              case 5: int_data[5] = (int) -1*(get_real(infile,0));break; /* y2-values  -> y-pixels*/
2554
              case 6: int_data[6] = (int) (get_real(infile,0));break; /* n1-values */
2555
              case 7: int_data[7] = (int) (get_real(infile,0));break; /* n2-values */
2556
              case 8: stroke_color=get_color(infile,1);
2557
                decimals = find_number_of_digits(precision);
18557 bpr 2558
                tmp_buffer=my_newmem(MAX_BUFFER);
2559
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_lattice(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,\"%s\",%.2f,\"%s\",%.2f,%d,%.2f,%d); ",STATIC_CANVAS,line_width,int_data[0],int_data[1],int_data[2],int_data[3],int_data[4],int_data[5],int_data[6],int_data[7],fill_color,fill_opacity,stroke_color,stroke_opacity,use_rotate,angle,use_filled));
18552 bpr 2560
                add_to_buffer(tmp_buffer);break;
2561
              default:break;
2562
            }
2563
          }
2564
          reset();
2565
          break;
2566
        case LINEAR:
2567
  /*
18556 bpr 2568
  @ linear a,b,c,d
2569
  @ defines a transformation matrix for subsequent objects
2570
  @ use keyword <a href='#killlinear'>killlinear</a> to end the transformation...the next objects will be drawn in the original x/y-range
2571
  @ a: Scales the drawings horizontally
2572
  @ b: Skews the drawings horizontally
2573
  @ c: Skews the drawings vertically
2574
  @ d: Scales the drawings vertically
2575
  @ the data precision may be set by preceding command ''precision int``
2576
  @ note: any active translation (tx,ty) is not changed
2577
  @%linear%size 400,400%xrange -10,10%yrange -10,10%opacity 255,255%fcircle 5,5,40,blue%linear 0.2,0,0,0.2%fcircle 5,5,40,green
18552 bpr 2578
  */
2579
          for(i = 0 ; i<4;i++){
2580
            switch(i){
2581
              case 0: affine_matrix[0] = get_real(infile,0);break;
2582
              case 1: affine_matrix[1] = get_real(infile,0);break;
2583
              case 2: affine_matrix[2] = get_real(infile,0);break;
2584
              case 3: affine_matrix[3] = get_real(infile,1);
2585
                affine_matrix[4] = 0;affine_matrix[5] = 0;
2586
                use_affine = TRUE;
2587
                break;
2588
              default: break;
2589
            }
2590
          }
2591
          reset();
2592
         break;
2593
        case LINE:
2594
  /*
2595
  @ line x1,y1,x2,y2,color
2596
  @ draw a line through points (x1:y1)--(x2:y2) in color ''color``
2597
  @ or use command ''curve color,formula`` to draw the line (uses more points to draw the line; is however better draggable)
2598
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
2599
  @%line%size 400,400%xrange -10,10%yrange -10,10%line 0,1,2,-1,green
2600
  */
2601
          for(i=0;i<5;i++){
2602
            switch(i){
2603
              case 0: double_data[10]= get_real(infile,0);break; /* x-values */
2604
              case 1: double_data[11]= get_real(infile,0);break; /* y-values */
2605
              case 2: double_data[12]= get_real(infile,0);break; /* x-values */
2606
              case 3: double_data[13]= get_real(infile,0);break; /* y-values */
2607
              case 4: stroke_color=get_color(infile,1);/* name or hex color */
2608
                if( double_data[10] == double_data[12] ){ /* vertical line*/
2609
                  double_data[1] = xmin;
2610
                  double_data[3] = ymax;
2611
                  double_data[0] = double_data[10];
2612
                  double_data[2] = double_data[10];
2613
                }
2614
                else{
2615
                  if( double_data[11] == double_data[13] ){ /* horizontal line */
2616
                    double_data[1] = double_data[11];
2617
                    double_data[3] = double_data[11];
2618
                    double_data[0] = ymin;
2619
                    double_data[2] = xmax;
2620
                }
2621
                else {
2622
      /* m */
2623
                  double_data[5] = (double_data[13] - double_data[11]) /(double_data[12] - double_data[10]);
2624
      /* q */
2625
                  double_data[6] = double_data[11] - ((double_data[13] - double_data[11]) /(double_data[12] - double_data[10]))*double_data[10];
2626
      /*xmin,m*xmin+q,xmax,m*xmax+q*/
2627
                  double_data[1] = (double_data[5])*(xmin)+(double_data[6]);
2628
                  double_data[3] = (double_data[5])*(xmax)+(double_data[6]);
2629
                  double_data[0] = xmin;
2630
                  double_data[2] = xmax;
2631
                }
2632
              }
2633
              if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
2634
              if(use_affine == TRUE ){ transform(4,2);}
2635
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2636
              decimals = find_number_of_digits(precision);
18557 bpr 2637
              tmp_buffer=my_newmem(MAX_BUFFER);
2638
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[1],decimals,double_data[3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 2639
              add_to_buffer(tmp_buffer);
2640
              if(onclick != 0){object_cnt++;}
2641
        /* object_cnt++;*/
2642
              reset();
2643
              break;
2644
            }
2645
          }
2646
          dragstuff[4] = 1;
2647
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2648
          break;
2649
        case LINES:
2650
  /*
2651
  @ lines color,x1,y1,x2,y2...x_n-1,y_n-1,x_n,y_n
2652
  @ draw multiple lines through points (x1:y1)--(x2:y2) ...(x_n-1:y_n-1)--(x_n:y_n) in color 'color'
2653
  @ or use multiple commands ''curve color,formula`` or ''jscurve color,formule`` to draw the line <br>(uses more points to draw the line; is however better draggable)
2654
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
2655
  @%lines%size 400,400%xrange -10,10%yrange -10,10%lines green,0,1,1,3,0,0,1,3,0,0,-2,1
2656
  */
2657
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
2658
          fill_color = stroke_color;
2659
          i=0;
2660
          while( ! done ){     /* get next item until EOL*/
2661
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
2662
            if(i%2 == 0 ){
2663
              double_data[i] = get_real(infile,0); /* x */
2664
            }
2665
            else {
2666
              double_data[i] = get_real(infile,1); /* y */
2667
            }
2668
            i++;
2669
          }
2670
          decimals = find_number_of_digits(precision);
2671
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2672
          for(c = 0 ; c < i-1 ; c = c+4){
2673
            if(double_data[c] == double_data[c+2] ){ /* vertical line*/
2674
              double_data[c+1] = xmin;
2675
              double_data[c+3] = ymax;
2676
              double_data[c+2] = double_data[c];
2677
            }
2678
            else {
2679
              if( double_data[c+1] == double_data[c+3] ){ /* horizontal line */
2680
                double_data[c+3] = double_data[c+1];
2681
                double_data[c] = ymin;
2682
                double_data[c+2] = xmax;
2683
              }
2684
              else {
2685
      /* m */
2686
                double m = (double_data[c+3] - double_data[c+1]) /(double_data[c+2] - double_data[c]);
2687
      /* q */
2688
                double q = double_data[c+1] - ((double_data[c+3] - double_data[c+1]) /(double_data[c+2] - double_data[c]))*double_data[c];
2689
      /*xmin,m*xmin+q,xmax,m*xmax+q*/
2690
                double_data[c+1] = (m)*(xmin)+(q);
2691
                double_data[c+3] = (m)*(xmax)+(q);
2692
                double_data[c] = xmin;
2693
                double_data[c+2] = xmax;
2694
              }
2695
            }
2696
            if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
2697
            if(use_affine == TRUE ){ transform(i-1,2);}
18557 bpr 2698
            tmp_buffer=my_newmem(MAX_BUFFER);
2699
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+1],decimals,double_data[c+3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 2700
            add_to_buffer(tmp_buffer);
2701
            if(onclick != 0){object_cnt++;}
2702
    /* object_cnt++; */
2703
          }
2704
          dragstuff[4] = 1;
2705
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2706
          reset();
2707
          break;
2708
        case LINEWIDTH:
2709
  /*
2710
  @ linewidth int
2711
  @ default 1
2712
  @%linewidth%size 400,400%xrange -10,10%yrange -10,10%linewidth 1%line -5,-5,-5,5,red%linewidth 2%line -4,-5,-4,5,green%linewidth 3%line -3,-5,-3,5,blue%linewidth 4%line -2,-5,-2,5,orange%linewidth 1%line -1,-5,-1,5,brown%linewidth 5%line 1,-5,1,5,cyan%linewidth 6%line 3,-5,3,5,purple%linewidth 7%line 5,-5,5,5,black
2713
  */
2714
          line_width = (int) (get_real(infile,1));
2715
          break;
2716
        case LEVELCURVE:
2717
  /*
2718
  @ levelcurve color,expression in x/y,l1,l2,...
2719
  @ draws very primitive level curves for expression, with levels l1,l2,l3,...,l_n
2720
  @ the quality is <b>not to be compared</b> with the Flydraw levelcurve. <br>(choose flydraw if you want quality...)
2721
  @ every individual level curve may be set 'onclick / drag xy' <br>e.g. every single level curve (l1,l2,l3...l_n) has a unique identifier
2722
  @ note: the arrays for holding the javascript data are limited in size
2723
  @ note: reduce image size if javascript data arrays get overloaded<br>(command 'plotsteps int' will not control the data size of the plot...)
2724
  @%levelcurve%size 400,400%xrange -10,10%yrange -10,10%levelcurve red,x*y,1,2,3,4
2725
  */
2726
          fill_color = get_color(infile,0);
2727
          char *fun1 = get_string_argument(infile,0);
2728
          if( strlen(fun1) == 0 ){canvas_error("function is NOT OK !");}
2729
          i = 0;
2730
          done = FALSE;
2731
          while( !done ){
2732
            double_data[i] = get_real(infile,1);
2733
            i++;
2734
          }
2735
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2736
          for(c = 0 ; c < i; c++){
18557 bpr 2737
            tmp_buffer=my_newmem(MAX_BUFFER);
2738
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,16,%s,[%d],[%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,eval_levelcurve(xsize,ysize,fun1,xmin,xmax,ymin,ymax,plot_steps,precision,double_data[c]),line_width,line_width,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 2739
            add_to_buffer(tmp_buffer);
2740
            if(onclick != 0){object_cnt++;}
2741
           /* object_cnt++; */
2742
          }
2743
          dragstuff[16] = 1;
2744
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2745
          reset();
2746
          break;
2747
        case LEGEND:
2748
  /*
2749
  @ legend string1:string2:string3....string_n
2750
  @ will be used to create a legend for a graph
2751
  @ also see command <a href='#piechart'>piechart</a>
2752
  @ will use the same colors per default as used in the graphs; use command <a href='#legendcolors'>legendcolors</a> to override the default
2753
  @ use command <a href="#fontsize">fontsize</a> to adjust. (command ''fontfamily`` is not active for command ''legend``)
2754
  @%legend%size 400,400%xrange -10,10%yrange -10,10%bgcolor white%fontsize 16%legend legend 1:legend 2:legend 3:legend 4:this is legend 5:legend 6:another legend abc%legendcolors red:green:blue%grid 1,1,white%# note: command "grid" is mandatory%# just set grid invisible if not wanted
2755
  */
2756
          temp = get_string(infile,1);
2757
          if( strstr( temp,":") != 0 ){ temp = str_replace(temp,":","\",\""); }
2758
          legend_cnt++; /* attention: starts with -1: it will be used in piechart etc */
2759
          fprintf(js_include_file,"var legend%d = [\"%s\"];",legend_cnt,temp);
2760
          break;
2761
        case LEGENDCOLORS:
2762
  /*
2763
  @ legendcolors color1:color2:color3:...:color_n
2764
  @ will be used to color a legend: use this command after the legend command ! e.g. <code>legend test1:test2:test3<br>legendcolors blue:red:orange</code>.
2765
  @ make sure the number of colors match the number of legend items
18627 bpr 2766
  @ command ''legend`` in case of ''piechart`` and ''barchart`` will use these colors per default (no need to specify ''legendcolors``)
18552 bpr 2767
  @%legendcolors%size 400,400%xrange -10,10%yrange -10,10%fontsize 18%legend legend 1:legend 2:legend 3%legendcolors red:green:blue%grid 1,1,grey
2768
  */
2769
          if(legend_cnt == -1){canvas_error("use command \"legend\" before command \"legendcolors\" ! ");}
2770
          temp = get_string(infile,1);
2771
          if( strstr( temp,":") != 0 ){ temp = str_replace(temp,":","\",\""); }
2772
          fprintf(js_include_file,"var legendcolors%d = [\"%s\"];",legend_cnt,temp);
2773
          break;
2774
        case LINEGRAPH: /* scheme: var linegraph_0 = [ 'stroke_color','line_width','use_dashed', 'dashtype0','dashtype1','x1','y1',...,'x_n','y_n'];*/
2775
  /*
2776
  @ linegraph x1:y1:x2:y2...x_n:y_n
2777
  @ will plot your data in a graph
2778
  @ may <b>only</b> to be used together with command <a href='#grid'>grid</a>
2779
  @ can be used together with freestyle x-axis/y-axis texts: see commands <a href='#xaxis'>xaxis</a>,<a href='#xaxisup'>xaxisup</a> and <a href='#yaxis'>yaxis</a>
2780
  @ use command <a href='#legend'>legend</a> to provide an optional legend in right-top-corner
2781
  @ also see command <a href='#piechart'>piechart</a>
2782
  @ multiple linegraphs may be used in a single plot
2783
  @ note: your arguments are not checked by canvasdraw: use your javascript console in case of trouble...
2784
  @ <ul><li>use command <a href='#strokecolor'>strokecolor</a> before a command ''linegraph`` to set the color of this graph</li><li>use command <a href='#linewidth'>linewidth</a> before command ''linegraph`` to set linewidth of this graph</li><li>use keyword <a href='#dashed'>dashed</a> before command ''linegraph`` to set dashing of the graph</li><li>if dashing is set, use command <a href='#dashtype'>dashtype</a> before command ''linegraph`` to set the type of dashing of the (individual) graph</li></ul>
2785
  @%linegraph%size 400,400%xrange -10,10%yrange -10,10%strokecolor red%linegraph -10:1:-5:-1:3:3:10:-5%strokecolor blue%linegraph -10:-1:-5:1:3:-3:10:5%dashed%strokecolor green%linegraph -10:2:-5:-2:3:4:10:2%grid 1,1,grey
2786
  */
2787
          temp = get_string(infile,1);
2788
          if( strstr( temp,":") != 0 ){ temp = str_replace(temp,":","\",\""); }
2789
          fprintf(js_include_file,"var linegraph_%d = [\"%s\",\"%d\",\"%d\",\"%d\",\"%d\",\"%s\"];",linegraph_cnt,stroke_color,line_width,use_dashed,dashtype[0],dashtype[1],temp);
2790
          linegraph_cnt++;
2791
          reset();
2792
          break;
2793
        case MATHML:
2794
  /*
2795
  @ mathml x1,y1,mathml_string
2796
  @ this command is special for GECKO browsers, and it makes use of Native Mathml
2797
  @ For general use with all browsers, use command <a href='#latex'>latex</a>
2798
  @ can be set <a href='onclick'>onclick</a>  and <a href='drag'>drag&amp;drop</a> <br>Note: dragging is fairly primitive dragging of the div-element, and is not done using the <em>dragstuff library</em>
2799
  @ command <a href='#affine'>affine</a> will produce CSS3 matrix transformations
2800
  @ command <a href='#rotate'>rotate</a> will rotate the object
2801
  @ the mathml object is centered at (x1:y1)
2802
  @ the ''mathml_string`` can be produced using WIMS commands like ''texmath`` followed by ''mathmlmath``... or write correct TeX and use only ''mathmlmath``
2803
  @ mathml will be displayed in a rectangle left top (x1:y1)
2804
  @ can be set onclick <code>javascript:read_dragdrop();</code> will return click numbers of mathml-objects; if 4 clickable object are drawn, the reply could be 1,0,1,0 ... meaning clicked on the first and third object
2805
  @ can be set draggable: <code>javascript:read_dragdrop()</code> will return all coordinates in same order as the canvas script: unmoved objects will have their original coordinates...
2806
  @ snaptogrid is supported...snaptopoints will work, but use with care... due to the primitive dragging. Technically: the dragstuff library is not used... the mathml is embedded in a new div element and not in the html5-canvas.
2807
  @ when clicked, the mathml object will be drawn in red color; the div background color will be determined by the <a href="#fillcolor">fillcolor</a> and <a href="#opacity">opacity</a> settings.
2808
  @ userdraw may be combined with 'mathml' ; the read_canvas() will contain the drawing.
2809
  @ draggable or onclick 'external images' from command <a href='#copyresized'>copy or copyresized</a> can be combined with drag and/or onclick mathml
2810
  @ other drag objects (circles/rects etc) are supported, but read_dragdrop() will probably be difficult to interpret...
2811
  @ if inputfields are incorporated in mathml (with id's: id='mathml0',id='mathml1',...id='mathml_n')<br>the user_input values will be read by javascript:read_mathml();<br><b>attention</b>: if after this mathml-input object other user-interactions are included, these will read mathml too using "read_canvas();"
2812
  @ If other inputfields (command input / command textarea) or userdraw is performed, the function read_canvas() will not read mathml. Use some generic function to read it....
2813
  @ use keyword <a href='#centered'>centered</a> to center the mathml/xml object on (x1:y1)
2814
  @%mathml_onclick%size 400,400%xrange -10,10%yrange -10,10%onclick%strokecolor red%mathml -5,5,<span style="font-size:1em;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mstyle id="wims_mathml366290"><mrow><mo stretchy="true">[</mo><mtable rowspacing="0.5ex" columnalign=" left " columnlines=" none " rowlines=" none " ><mtr><mtd><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mstyle displaystyle="true"><mfrac><mn>1</mn><mn>2</mn></mfrac></mstyle><mo>&sdot;</mo><msup><mi>x</mi> <mn>2</mn></msup></mtd></mtr> <mtr><mtd><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><msqrt><mstyle displaystyle="true"><mfrac><mn>1</mn><mrow><msup><mi>x</mi> <mn>2</mn></msup></mrow></mfrac></mstyle></msqrt></mtd></mtr></mtable><mo stretchy="true">]</mo></mrow></mstyle></math></span>%onclick%strokecolor blue%mathml 5,5,<span style="font-size:1em;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mstyle id="wims_mathml580175" ><mrow><mo stretchy="true">[</mo><mtable rowspacing="0.5ex" columnalign=" left " columnlines=" none " rowlines="none"><mtr><mtd><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mstyle displaystyle="true"><mfrac><mn>1</mn><mrow><mi>sin</mi><mrow><mo stretchy="true">(</mo><msup><mi>x</mi> <mn>2</mn></msup><mo stretchy="true">)</mo></mrow></mrow></mfrac></mstyle></mtd></mtr> <mtr><mtd><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><msqrt><mrow><mi>sin</mi><mrow><mo stretchy="true">(</mo><msup><mi>x</mi> <mn>2</mn></msup><mo stretchy="true">)</mo></mrow></mrow></msqrt></mtd></mtr></mtable><mo stretchy="true">]</mo></mrow></mstyle></math></span>
2815
  @%mathml_drag%size 400,400%xrange -10,10%yrange -10,10%drag xy%strokecolor red%mathml -5,5,<span style="font-size:1em;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mstyle id="wims_mathml366290"><mrow><mo stretchy="true">[</mo><mtable rowspacing="0.5ex" columnalign=" left " columnlines=" none " rowlines=" none "><mtr><mtd><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mstyle displaystyle="true"><mfrac><mn>1</mn><mn>2</mn></mfrac></mstyle><mo>&sdot;</mo><msup><mi>x</mi> <mn>2</mn></msup></mtd></mtr> <mtr><mtd><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><msqrt><mstyle displaystyle="true"><mfrac><mn>1</mn><mrow><msup><mi>x</mi> <mn>2</mn></msup></mrow></mfrac></mstyle></msqrt></mtd></mtr></mtable><mo stretchy="true">]</mo></mrow></mstyle></math></span>%drag xy%strokecolor blue%mathml 5,5,<span style="font-size:1em;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mstyle id="wims_mathml580175" ><mrow><mo stretchy="true">[</mo><mtable rowspacing="0.5ex" columnalign=" left " columnlines=" none " rowlines=" none "><mtr><mtd><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mstyle displaystyle="true"><mfrac><mn>1</mn><mrow><mi>sin</mi><mrow><mo stretchy="true">(</mo><msup><mi>x</mi> <mn>2</mn></msup><mo stretchy="true">)</mo></mrow></mrow></mfrac></mstyle></mtd></mtr> <mtr><mtd><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><msqrt><mrow><mi>sin</mi><mrow><mo stretchy="true">(</mo><msup><mi>x</mi> <mn>2</mn></msup><mo stretchy="true">)</mo></mrow></mrow></msqrt></mtd></mtr></mtable><mo stretchy="true">]</mo></mrow></mstyle></math></span>%#click left top corner...then drag...
2816
  */
2817
          js_function[DRAW_XML] = 1;
2818
          for(i=0;i<3;i++){
2819
            switch(i){
2820
              case 0: double_data[0]=get_real(infile,0);break; /* x in x/y-range coord system -> pixel width */
2821
              case 1: double_data[1]=get_real(infile,0);break; /* y in x/y-range coord system  -> pixel height */
2822
              case 2: decimals = find_number_of_digits(precision);
2823
                if(use_affine == TRUE ){ transform(2,2);}/* needs double_data[] */
2824
                if( use_offset != 0 || drag_type != -1 ){int_data[2] = 1;}else{int_data[2] = 0;} /* only centered or not-centered */
2825
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2826
                int_data[0] = x2px(double_data[0]);/* needs px */
2827
                int_data[1] = y2px(double_data[1]);
2828
                if( use_slider != -1 && onclick == 0 ){ onclick = 3;}/* no drag&onclick but slideable */
2829
                if( use_slider != -1 && drag_type != -1){ onclick = 5; }
2830
                temp = get_string(infile,1);
2831
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'"); }
18557 bpr 2832
                tmp_buffer=my_newmem(MAX_BUFFER);
2833
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "var draw_xml%d = {id:%d,type:'mathml',x:[%d],y:[%d],mathml:\"%s\",drag_type:%d,onclick:%d,object_cnt:%d,stroke_color:\"%s\",stroke_opacity:%.2f,fill_color:\"%s\",fill_opacity:%.2f,use_center:%d,use_snap:%d,angle:%f,fontfamily:\"%s\",transform:%s,use_affine:%d,offset:[0,0],use_slider:%d,rotation_center:%s,once:true};draw_xml(draw_xml%d);slidergroup[%d] = null;\n",drawxml_cnt,drawxml_cnt,int_data[0],int_data[1],temp,drag_type,onclick,object_cnt,stroke_color,stroke_opacity,fill_color,fill_opacity,int_data[2],use_snap,angle,font_family,doubledata2js_array(affine_matrix,6,decimals),use_affine,use_slider,rotation_center,drawxml_cnt,object_cnt));
18552 bpr 2834
                add_to_buffer(tmp_buffer);
2835
                if(onclick != 0 ){object_cnt++;}
2836
                drawxml_cnt++;/* keeps track on imported img,div,p,span,mathml,svg */
2837
          /*
2838
            in case inputs are present, trigger adding the read_mathml()
2839
            if no other reply_format is defined
2840
            note: all other reply types will include a reading of elements with id='mathml'+p)
2841
          */
2842
                if(strstr(temp,"mathml0") != NULL){ if(reply_format == 0 ){reply_format = 16;}} /* no other reply type is defined */
2843
                break;
2844
              default:break;
2845
            }
2846
          }
2847
          reset();
2848
          break;
2849
        case MOUSE:
2850
  /*
18556 bpr 2851
  @ mouse color,fontsize
2852
  @ will display the cursor (x:y) coordinates in ''color`` and ''fontsize`` using default fontfamily Arial
2853
  @ note: use command ''mouse`` at the end of your script code (the same is true for command ''zoom``)
2854
  @%mouse%size 400,400%xrange -10,10%yrange -10,10%mouse red,22
18552 bpr 2855
  */
2856
          stroke_color = get_color(infile,0);
2857
          font_size = (int) (get_real(infile,1));
2858
          tmp_buffer = my_newmem(26);
2859
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2860
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,2);
2861
          js_function[INTERACTIVE] = 1;
2862
          break;
2863
        case MOUSE_DEGREE:
2864
  /*
18556 bpr 2865
  @ mouse_degree color,fontsize
2866
  @ will display the angle in degrees between x-axis, (0:0) and the cursor (x:y) in 'color' and 'font size'<br> using a fontfamily Arial
2867
  @ The angle is positive in QI and QIII and the angle value is negative in QII and QIV
2868
  @ note: use command 'mouse' at the end of your script code (the same is true for command 'zoom')
2869
  @%mouse_degree%size 400,400%xrange -10,10%yrange -10,10%userdraw arc,blue%precision 100000%mouse_degree red,22
18552 bpr 2870
  */
2871
          stroke_color = get_color(infile,0);
2872
          font_size = (int) (get_real(infile,1));
2873
          tmp_buffer = my_newmem(26);
2874
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2875
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,3);
2876
          js_function[JS_FIND_ANGLE] = 1;
2877
          js_function[INTERACTIVE] = 1;
2878
          break;
2879
        case MOUSE_DISPLAY:
2880
  /*
18556 bpr 2881
  @ display TYPE,color,fontsize
2882
  @ TYPE may be x | y | xy | degree | radian | radius
2883
  @ will display the mouse cursor coordinates as x-only,y-only,(x:y), the radius of a circle (this only in case 'userdraw circle(s),color') or the angle in degrees or radians for commands <code>userdraw arc,color</code> or protractor, ruler (if set dynamic).
2884
  @ use commands ''xunit`` and / or ''yunit`` to add the units to the mouse values. The ''degree | radian`` will always have the appropriate symbol).
2885
  @ just like commands ''mouse``, ''mousex``, ''mousey``, ''mouse_degree``... only other name
2886
  @%display_x%size 400,400%xrange -10,10%yrange -10,10%xunit \\u212B%display x,red,22
2887
  @%display_y%size 400,400%xrange -10,10%yrange -10,10%yunit seconds%display y,red,22
2888
  @%display_xy%size 400,400%xrange -10,10%yrange -10,10%xunit centimetre%yunit seconds%display xy,red,22%userdraw segments,blue
2889
  @%display_deg%size 400,400%xrange -10,10%yrange -10,10%display degree,red,22%fillcolor orange%opacity 200,50%userdraw arc,blue
2890
  @%display_rad%size 400,400%xrange -10,10%yrange -10,10%display radian,red,22%fillcolor orange%opacity 200,50%userdraw arc,blue
2891
  @%display_radius%size 400,400%xrange -10,10%yrange -10,10%xunit cm%xunit \\u212b%display radius,red,22%userdraw circle,blue
18552 bpr 2892
  */
2893
          temp = get_string_argument(infile,0);
2894
          if( strstr(temp,"xy") != NULL ){
2895
            int_data[0] = 2;
2896
          } else {
2897
            if( strstr(temp,"y") != NULL ){
2898
              int_data[0] = 1;
2899
            }else{
2900
              if( strstr(temp,"x") != NULL ){
2901
                int_data[0] = 0;
2902
              }else{
2903
                if(strstr(temp,"degree") != NULL){
2904
                int_data[0] = 3;
2905
                js_function[JS_FIND_ANGLE] = 1;
2906
                }else{
2907
                  if(strstr(temp,"radian") != NULL){
2908
                    int_data[0] = 4;
2909
                    js_function[JS_FIND_ANGLE] = 1;
2910
                  }else{
2911
                    if(strstr(temp,"radius") != NULL){
2912
                      int_data[0] = 5;
2913
                    }else{
2914
                      int_data[0] = 2;
2915
                    }
2916
                  }
2917
                }
2918
              }
2919
            }
2920
          }
2921
          stroke_color = get_color(infile,0);
2922
          font_size = (int) (get_real(infile,1));
2923
          tmp_buffer = my_newmem(26);
2924
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2925
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,int_data[0]);
2926
          js_function[INTERACTIVE] = 1;
2927
          break;
2928
        case MOUSE_PRECISION:
2929
  /*
18556 bpr 2930
  @ precision int
2931
  @ 1 = no decimals ; 10 = 1 decimal ; 100 = 2 decimals etc
2932
  @ may be used / changed before every object
2933
  @ In case of user interaction (like ''userdraw`` or ''multidraw``), this value will be used to determine the amount of decimals in the reply / answer
2934
  @%precision%size 400,400%xrange -10,10%yrange -10,10%precision 1%userdraw segment,red
18552 bpr 2935
  */
2936
          precision = (int) (get_real(infile,1));
2937
          if(precision < 1 ){precision = 1;};
2938
          break;
2939
        case MOUSEX:
2940
  /*
18556 bpr 2941
  @ mousex color,fontsize
2942
  @ will display the cursor x-coordinate in ''color`` and ''font size`` using the fontfamily Arial.
2943
  @ note: use command ''mouse`` at the end of your script code (the same is true for command ''zoom``).
18552 bpr 2944
  */
2945
          stroke_color = get_color(infile,0);
2946
          font_size = (int) (get_real(infile,1));
2947
          tmp_buffer = my_newmem(26);
2948
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2949
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,0);
2950
          js_function[INTERACTIVE] = 1;
2951
          break;
2952
        case MOUSEY:
2953
  /*
18556 bpr 2954
  @ mousey color,fontsize
2955
  @ will display the cursor y-coordinate in ''color`` and ''font size`` using default fontfamily Arial.
2956
  @ note: use command ''mouse`` at the end of your script code (the same is true for command ''zoom``).
8386 schaersvoo 2957
 
18552 bpr 2958
  */
2959
          stroke_color = get_color(infile,0);
2960
          font_size = (int) (get_real(infile,1));
2961
          tmp_buffer = my_newmem(26);
2962
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2963
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,1);
2964
          js_function[INTERACTIVE] = 1;
2965
          break;
2966
        case MULTIDASH:
2967
  /*
18556 bpr 2968
  @ multidash 0,1,1
2969
  @ meaning draw objects no. 2 (circle) and 3 (segments), in the list of command like <code>multifill points,circle,segments</code>, are dashed
2970
  @ use before command <a href='#multidraw'>multidraw</a>
2971
  @ if not set all objects will be set ''not dashed``... unless a generic keyword ''dashed`` was given before command ''multidraw``
2972
  @ the dash-type is not -yet- adjustable <br>(e.g. command <code>dashtype line_px,space_px</code> will give no control over multidraw objects)
2973
  @ wims will <b>not</b> check if the number of 0 or 1's matches the amount of draw primitives...
2974
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 2975
  */
2976
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
2977
          temp = get_string(infile,1);
2978
          temp = str_replace(temp,",","\",\"");
2979
          fprintf(js_include_file,"var multidash = [\"%s\"];",temp);
2980
          reset();/* if command 'dashed' was given...reset to not-dashed */
2981
          break;
2982
        case MULTIDRAW:
2983
  /*
18556 bpr 2984
  @ multidraw obj_type_1,obj_type_2...obj_type_11
2985
  @ for simple single object user drawings you could also use command <a href="#userdraw">userdraw</a>
18572 bpr 2986
  @ implemented obj_types:<ul><li>point | points</li><li>circle | circles</li><li>line | lines</li><li>segment | segments</li><li>arrow | arrows (use command 'arrowhead int' for size (default value 8 pixels))</li><li>curvedarrow | curvedarrows</li><li>rect | rects</li><li>closedpoly<br><b>only one</b> closedpolygon may be drawn.The number of ''corner points`` is not preset (e.g. not limited, freestyle), the polygon is closed when clicking on the first point again..(+/- 10px)</li><li>triangle | triangles</li><li>parallelogram | parallelograms</li><li>poly[3-9] | polys[3-9] draw 3...9 point polygone(s): polys3 is of course triangles</li><li>images</li><li>crosshair | crosshairs</li><li>function <br>for more function user input fields, use it multiple times<br>for 4 inputfields use : multidraw function,function,function,function</li></ul>
18556 bpr 2987
  @ additionally objects may be user labelled, using obj_type ''text``...<br>in this case allways a text input field and if <a href='#multiuserinput'> multiuserinput=1 </a> also (x:y) inputfields will be added to the page.<br>use commands ''fontfamily`` and ''fontcolor`` to adjust (command ''multistrokeopacity`` may be set to adjust text opacity)<br>note: text is always centered on the mouse-click or user-input coordinates !<br>note: no keyboard listeners are used
2988
  @ it makes no sense using something like ''multidraw point,points`` ... <br>something like "multidraw polys4,polys7" will only result in drawing a ''4 point polygone`` and not a ''7 point polygone``: this is a design flaw and not a feature...
2989
  @ note: mouselisteners are only active if "&#36;status != done " (eg only drawing in an active/non-finished exercise) <br> to overrule use command/keyword "status" (no arguments required)
2990
  @ buttons for changing the obj_type (and in case of ''multiuserinput``, some inputfields and buttons) <br>will be present in the reserved div ''tooltip_div`` and can be styled using command 'css some_css'
2991
  @ the button label will be default the ''object primitive name`` (like ''point``, ''circles``).<br>If you want a different label (e.g. an other language), use command ''multilabel``<br>for example in dutch: <br><code>multilabel cirkel,lijnstuk,punten,STOP<br>multidraw circle,segment,points</code><br>(see command <a href='#multilabel'>multilabel</a> for more details)
2992
  @ a right mouse button click will remove the last drawn object of the selected drawing type. All other type of objects are not removed
2993
  @ multidraw is incompatible with command ''tooltip`` (the reserved div_area is used for the multidraw control buttons)
2994
  @ all ''multidraw`` drawings will scale on zooming.<br>this in contrast to the command <a href="#userdraw">userdraw</a>.
2995
  @ wims will <b>not</b> check the amount or validity of your command arguments ! <br>( use javascript console to debug any typo's )
18572 bpr 2996
  @ a local function <code>read_canvas%d</code> will read all userbased drawings.<br>The output is always a 16 lines string with fixed sequence.<br>line 1 = points_x+";"+points_y+"\\n"<br>line 2 = circles_x+";"+circles_y+";"+multi_radius+"\\n"<br>line 3 = segments_x+";"+segments_y+"\\n"<br>line 4 = arrows_x+";"+arrows_y+"\\n"<br>line 5 = lines_x+";"+lines_y+"\\n"<br>line 6 = triangles_x+";"+triangles_y+"\\n"<br>line 7 = polys[3-9]_x+";"+polys[3-9]_y+"\\n"<br>line 8 = rects_x +";"+rects_y+"\\n"<br>line 9 = closedpoly_x+";"+closedpoly_y+"\\n"<br>line 10 = parallelogram_x+";"+parallelogram_y"\\n"<br>line 11 = text_x+";"+text_y+";"+text"\\n"<br>line 12 = image_x+";"+image_y+";"+image_id<br>line 13 = curvedarrows_x +";"+ curvedarrows_y +"\\n"<br>line 14 = curvedarrows2_x +";"+ curvedarrows2_y +"\\n"<br>line 15 = crosshairs_x +";"+ crosshairs_y +"\\n"<br>line 16 = userdraw_x +";"+userdraw_y + "\\n" note: this is for single ''userdraw object,color`` and ''replyformat 29``<br>line 17 = userdraw_x +";"+userdraw_y +";"+userdraw_radius + "\\n" note: this is for single ''userdraw object,color`` and ''replyformat 29``<br>The x/y-data are in x/y-coordinate system and display precision may be set by a previous command ''precision 0 | 10 | 100 | 1000...``<br>In case of circles the radius is -for the time being- rounded to pixels<br><b>use the wims "direct exec" tool to see the format of the reply</b>
18556 bpr 2997
  @ It is best to prepare / format the student reply in clientside javascript.<br>However in ''wims`` language you could use something like this<br>for example you are interested in the polys5 drawings of a pupil (the pupil may draw multiple poly5 objects...)<br>note: the reply for 2 poly5's is: x11,x12,x13,x14,x15,x21,x22,x23,x24,x25 ; y11,y12,y13,y14,y15,y21,y22,y23,y24,y25<br>rep = !line 7 of reply <br>rep = !translate ';' to '\\n' in &#36;rep <br>pts = 5 # 5 points for polygon <br>x_rep = !line 1 of &#36;rep <br>y_rep = !line 2 of &#36;rep <br>tot = !itemcnt &#36;x_rep <br>num_poly = &#36;[&#36;tot/&#36;pts] <br>idx = 0 <br>!for p=1 to &#36;num_poly <br>&nbsp;!for s=1 to &#36;pts <br>&nbsp;&nbsp;!increase idx <br>&nbsp;&nbsp;X = !item &#36;idx of &#36;x_rep <br>&nbsp;&nbsp;Y = !item &#36;idx of &#36;y_rep <br>&nbsp;&nbsp;# do some checking <br>&nbsp;!next s <br>!next p <br>
2998
  @ <b>attention</b>: for command argument ''closedpoly``, only one polygone can be drawn. The last point (e.g. the point clicked near the first point) of the array is removed.
2999
  @ technical: all 10 ''draw primitives`` + ''text`` will have their own -transparent- PNG bitmap canvas. <br>So for example there can be a points_canvas entirely separated from a line_canvas.<br>This to avoid the need for a complete redraw when something is drawn to the canvas...(eg only the object_type_canvas is redrawn), this in contrast too many very slow do-it-all HTML5 canvas javascript libraries.<br>The mouselisteners are attached to the canvas-div element.
3000
  @ a special object type is ''images``.<br>if used together with <a href='#imagepalette'>imagepalette</a> a image table will be integrated in the 'control section' of multidraw (set <code>multiuserinput 1</code> for ''images``) if not used with <a href='#imagepalette'>imagepalette</a>, provide the images or div's (&lt;img&gt; tag with bitmap or SVG or anything in a div element) somewhere on the html exercise page, with an onclick handler like:<br><code>&lt;img src='gifs/images/dog.svg' onclick='javascript:place_image_on_canvas(this.id);' id="ext_image_1" /&gt;<br>&lt;img src='gifs/fish.png' onclick='javascript:place_image_on_canvas(this.id);' id="another" /&gt;</code><br>etc ... when activating the multidraw ''image`` button, the images can be selected<br> (left mouse button/onclick) and placed on the canvas...left mouse click.<br>using div's will enable you -amongst other content- to add math typesetting from the exercise page onto the canvas.
18572 bpr 3001
  @ When you are not content with the default ''multidraw control panel``, you can create your own interface, using a few javascript functions to call the drawprimitives, delete things and ''stop drawing`` in case you also want to drag&drop stuff...</br>To activate this feature, use <a href='#multilabel'>multilabel NOCONTROLS</a><br>The object types are internally represented by the following numbers (making typos will render your exercise null and void)<br>point = 0<br>points =1<br>circle = 2<br>circles = 3<br>line = 4<br>lines = 5<br>segment = 6<br>segments = 7<br>arrow = 8<br>arrows = 9<br>triangle = 10<br>triangles = 11<br>closedspoly = 12<br>text = 13<br>rect = 14<br>rects = 15<br>poly[3-9] = 16<br>polys[3-9] = 17<br>parallelogram = 18<br>parallelograms = 19<br>images  = 20<br>curvedarrow = 21<br>curvedarrows = 22<br>curvedarrow2 = 23<br>curvedarrows2 = 24<br>crosshair = 25<br>crosshairs = 26 <br>controls for example:<br><code>&lt;input type='button' onclick='javascript:userdraw_primitive=null' value='STOP DRAWING' /&gt;<br>&lt;input type='button' onclick='javascript:userdraw_primitive=24;multidraw_object_cnt = 0;' value='start drawing curvedarrows2' /&gt; <br>&lt;input type='button' onclick='javascript:var fun=eval("clear_draw_area"+canvas_scripts[0]);fun(24,0);' value='REMOVE LAST CURVEDARROW ' /&gt; </code><br> If using multiple canvas scripts in a single page, loop through the canvas_scripts[n] <br>note: if using NOCONTROLS and just a single draw primitive (for example, just: 'multidraw circles'), the object may be drawn directly. (analogue to 'userdraw circles,color')<br>And since a right mouse button click will always remove the last drawn object of the current object type, there is no need for a special "remove button"
18556 bpr 3002
  @%multidraw_function%size 400,400%xrange -10,10%yrange -10,10%fontfamily Italic 22px Helvetica%axis%axisnumbering%precision 0%grid 2,2,grey,1,1,5,black%multicolors red,green,blue%fontcolor orange%multilinewidth 1,2,3%multidraw text,function,function,function,line
3003
  @%multidraw%size 400,400%xrange -10,10%yrange -10,10%multidash 1,0%multilinewidth 1,2%multistrokecolors red,blue%multisnaptogrid 1,1%multilabel LINES,CIRCLES,STOP DRAWING%multidraw lines,circles
3004
  @%multidraw_images%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%drag xy%# use special function to read the drag coordinates%copy 0,0,-1,-1,-1,-1,gifs/images/skull_and_crossbones50.png%fontcolor green%fontfamily Bold 42pt Arial%imagepalette gifs/ca.gif,gifs/en.gif,gifs/nl.gif,gifs/fr.gif,gifs/cn.gif,gifs/de.gif,gifs/kh.gif,gifs/it.gif%multiuserinput 0,0,1%css color:blue;%multisnaptogrid 1,1,1%multilinewidth 0,4,0%# attention: use unicode text input without the slash %# \u222D ---> u222D at least will sometimes work%# otherwise cut&past unicode symbols into inputfield...%multilabel TEXT,REACTION ARROW,FLAGS,STOP DRAWING%multidraw text,arrow,images
3005
  @%multidraw_demo%size 800,800%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%css color:blue;%fontfamily Italic 42pt Arial%precision 1%opacity 200,50%snaptogrid%linewidth 3%filled%multistrokecolors red,green,blue,orange,yellow,purple,black,cyan,red,green,blue,orange,green,purple,black,cyan%multifillcolors red,green,blue,orange,yellow,purple,black,cyan,red,green,blue,orange,brown,purple%imagepalette gifs/ca.gif,gifs/en.gif,gifs/nl.gif,gifs/fr.gif,gifs/cn.gif,gifs/de.gif,gifs/kh.gif,gifs/it.gif%multidraw closedpoly,segments,rect,parallelogram,triangles,poly5,points,lines,arrows,circles,text,curvedarrows,curvedarrows2,images
3006
  @%multidraw_NOCONTROLS%size 400,400%xrange -10,10%yrange -10,10%grid 2,2,grey%linewidth 3%strokecolor green%fillcolor blue%filled%opacity 255,60%multilabel NOCONTROLS%multidraw circles%# RIGHT MOUSE CLICK REMOVES LAST OBJECT
18552 bpr 3007
  */
3008
          js_function[INTERACTIVE] = 1;
3009
          if(js_function[JS_ZOOM] == 1){use_zoom = 1;} /* use noisy zoom_code, when command zoom is given before command 'multidraw' */
3010
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3011
          if( use_userdraw == 1 ){canvas_error("Only one userdraw primitive may be used in command 'userdraw' use command 'multidraw' for this...");}
3012
          use_userdraw = 2;
3013
          temp = get_string(infile,1);
3014
          fprintf(js_include_file,"\
3015
            var MMP = %d;\
3016
            if( typeof(multisnaptogrid) == 'undefined' && multisnaptogrid == null){var multisnaptogrid = new Array(MMP);for(var i=0;i<MMP;i++){multisnaptogrid[i] = %d;};};\
3017
            if( typeof(multistrokecolors) === 'undefined' && multistrokecolors == null){ var multistrokecolors = new Array(MMP);for(var i=0;i<MMP;i++){multistrokecolors[i] = '%s';};};\
3018
            if( typeof(multifillcolors) === 'undefined' && multifillcolors == null ){var multifillcolors = new Array(MMP);for(var i=0;i<MMP;i++){multifillcolors[i] = '%s';};};\
3019
            if( typeof(multistrokeopacity) === 'undefined' && multistrokeopacity == null){var multistrokeopacity = new Array(MMP);for(var i=0;i<MMP;i++){multistrokeopacity[i] = %.2f;};};\
3020
            if( typeof(multifillopacity) === 'undefined' &&  multifillopacity == null){var multifillopacity = new Array(MMP);for(var i=0;i<MMP;i++){multifillopacity[i] = %.2f;};};\
3021
            if( typeof(multilinewidth) === 'undefined' && multilinewidth == null){var multilinewidth = new Array(MMP);for(var i=0;i<MMP;i++){multilinewidth[i] = %d;};};\
3022
            if( typeof(multifill) === 'undefined' && multifill == null){var multifill = new Array(MMP);for(var i=0;i<MMP;i++){multifill[i] = %d;};};\
3023
            if( typeof(multidash) === 'undefined' && multidash == null){var multidash = new Array(MMP);for(var i=0;i<MMP;i++){multidash[i] = %d;};};\
3024
            if( typeof(multilabel) === 'undefined' && multilabel == null){var multilabel = [\"%s\",\"stop drawing\"];};\
3025
            if( typeof(multiuserinput) === 'undefined' && multiuserinput == null){var multiuserinput = new Array(MMP);for(var i=0;i<MMP;i++){multiuserinput[i] = '0';};};\
3026
            var arrow_head = %d;var multifont_color = '%s';var multifont_family = '%s';var forbidden_zone = [xsize+2,ysize+2];",
3027
            MAX_MULTI_PRIMITIVES,
3028
            use_snap,
3029
            stroke_color,
3030
            fill_color,
3031
            stroke_opacity,
3032
            fill_opacity,
3033
            line_width,
3034
            use_filled,
3035
            use_dashed,
3036
            str_replace(temp,",","\",\""),
3037
            arrow_head,font_color,font_family);
3038
          add_js_multidraw(temp,css_class,use_offset,int_data[MAX_MULTI_PRIMITIVES+1],crosshair_size,use_zoom);
3039
            /* no_controls == int_data[MAX_MULTI_PRIMITIVES+1] */
3040
          reply_precision = precision;
3041
          if(strstr(temp,"text") != NULL){
3042
            js_function[JS_SAFE_EVAL] = 1;
3043
            js_function[DRAW_SUBSUP] = 1;
3044
          }
3045
          if(strstr(temp,"function") != NULL){
3046
            int pp, funs = count_substring(temp, "function");
3047
            js_function[JS_SAFE_EVAL] = 1;
3048
            js_function[JS_RAWMATH] = 1;
3049
            js_function[DRAW_JSFUNCTION] = 1;
3050
            js_function[JS_MATH] = 1;
3051
            js_function[JS_PLOT] = 1;
3052
            for(pp = 0 ; pp< funs ;pp++){
3053
              add_input_jsfunction(css_class,function_label,input_cnt,stroke_color,stroke_opacity,line_width,use_dashed,dashtype[0],dashtype[1],font_size);
3054
              input_cnt++;
3055
              jsplot_cnt++;
3056
            }
3057
            fprintf(js_include_file,"if(typeof(all_jsplots) !== 'number'){var all_jsplots;};all_jsplots = %d;function redraw_userdraw(){redraw_jsplot();return;};",jsplot_cnt);
3058
          }
3059
      /* the canvasses range from 1000 ... 1008 */
3060
          if( reply_format == 0){reply_format = 29;}
3061
          reset();/* if command 'filled' / 'dashed' was given...reset all */
3062
          break;
3063
        case MULTILABEL:
3064
  /*
18556 bpr 3065
  @ multilabel button_label_1,button_label_2,...,button_label_8,'stop drawing text'
3066
  @ use before command <a href='#multidraw'>multidraw</a>
3067
  @ if not set all labels (e.g. the value of input type 'button') will be set by the english names for the draw_primitives (like 'point','circle'...)
3068
  @ the ''stop drawing`` button text <b>must</b> be the last item on the ''multilabel`` -list <br>for example:<br><code>multilabel punten,lijnen,Stop met Tekenen<br>multidraw points,lines</code>
3069
  @ all buttons can be ''styled`` by using command <code>css</code><br><b>note:</b>If you want to add some CSS style to the buttons...<br>the id's of the ''draw buttons`` are their english command argument<br>(e.g. id="canvasdraw_points" for the draw points button).<br>the id of the ''stop drawing`` button is "canvasdraw_stop_drawing".<br>the id of the "OK" button is ''canvasdraw_ok_button``
3070
  @ wims will not check the amount or validity of your input
3071
  @ always use the same sequence as is used for ''multidraw``
3072
  @ if you don't want the controls, and want to write your own interface, set <code>multilabel NOCONTROLS</code>
18552 bpr 3073
  */
3074
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3075
          temp = get_string(infile,1);
3076
          if( strcasestr(temp,"NOCONTROLS") ){
3077
            int_data[MAX_MULTI_PRIMITIVES+1] = 1; /*int_data[25] = 1 --> 'no_controls = 1' in canvasmacro.c */
3078
            fprintf(js_include_file,"var multilabel = null;");
3079
          }
3080
          else {
3081
            int_data[MAX_MULTI_PRIMITIVES+1] = 0; /* so DO use control buttons etc */
3082
            temp = str_replace(temp,",","\",\"");
3083
            fprintf(js_include_file,"var multilabel = [\"%s\"];",temp);
3084
          }
3085
          break;
3086
        case MULTILINEWIDTH:
3087
  /*
18556 bpr 3088
  @ multilinewidth linewidth_1,linewidth_2,...,linewidth_8
3089
  @ use before command <a href='#multidraw'>multidraw</a>
3090
  @ if not set all line widths will be set by a previous command ''linewidth int``
3091
  @ use these up to 7 different line widths for the draw primitives used by command <code>multidraw obj_type_1,obj_type_2...obj_type_7</code>
3092
  @ wims will <b>not</b> check if the number of 0 or 1's matches the amount of draw primitives...
3093
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3094
  */
3095
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3096
          temp = get_string(infile,1);
3097
          temp = str_replace(temp,",","\",\"");
3098
          fprintf(js_include_file,"var multilinewidth = [\"%s\"];",temp);
3099
          break;
3100
        case MULTIFILL:
3101
  /*
18556 bpr 3102
  @ multifill 0,0,1,0,1,0,0
3103
  @ meaning draw objects no. 3 and 5, in the list of command ''multifill``, are filled (if the object is fillable...and not a line,segment,arrow or point...)
3104
  @ using a fillpattern: multifill 0,1,2,5,3,4<br>meaning: first object is not filled...second object is solid color filled...2=grid | 3=hatch | 4=diamond | 5=dot
3105
  @ use before command <a href='#multidraw'>multidraw</a>
3106
  @ if not set all objects -except point|points- will be set ''not filled``... unless a command <code>filled</code> was given before command <code>multifill</code>
3107
  @ only suitable for draw_primitives like ''circle | circles``, ''triangle | triangles``, ''rect | rects``, ''poly[3-9] | polys[3-9]`` and ''polygon``
3108
  @ wims will <b>not</b> check if the number of 0 or 1's matches the amount of draw primitives...
3109
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3110
  */
3111
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3112
          i=0;
3113
          while( ! done ){     /* get next item until EOL*/
3114
            if(i > MAX_MULTI_PRIMITIVES){canvas_error("too many multidraw primitives...read the documentation...");}
3115
            int_data[i] = (int)(get_real(infile,1)); /* 0,1,2,3,4,5 */
3116
            if(int_data[i] < 0 || int_data[i] > 5 ){canvas_error("the only possible multifill arguments are: 0,1,2,3,4,5 ");}
3117
            if(int_data[i] > 1 ){use_filled = 2;js_function[DRAW_FILL_PATTERN] = 1;}/* switch to trigger pattern filling */
3118
            i++;
3119
          }
3120
          fprintf(js_include_file,"var multifill = %s ;",data2js_array(int_data,i-1));
3121
          break;
3122
        case MULTIFILLCOLORS:
3123
  /*
18556 bpr 3124
  @ multifillcolors color_name_1,color_name_2,...,color_name_8
3125
  @ use before command <a href='#multidraw'>multidraw</a>
3126
  @ if not set all fillcolors (for circle | triangle | poly[3-9] | closedpoly ) will be ''stroke_color``, ''fill_opacity``
3127
  @ use these up to 6 colors for the draw primitives used by command <code>multidraw obj_type_1,obj_type_2...obj_type_n</code>
18627 bpr 3128
  @ wims will <b>not</b> check if the number of colors matches the amount of draw primitives...
18556 bpr 3129
  @ always use the same sequence as is used for ''multidraw``
18627 bpr 3130
  @ can also be used with command <a href='#userdraw'>userdraw clickfill,color</a> when more than one fillcolor is wanted.<br>in that case use for example <a href='#replyformat'>replyformat 10</a> ... reply=x1:y1:color1,x2:y2:color2...<br>the colors will restart at the first color, when there are more fill-clicks than multi-fill-colors<br>if more control over the used colors is wanted, see command <a href='#colorpalette'>colorpalette color1,color2...</a>
18552 bpr 3131
  */
3132
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3133
          fprintf(js_include_file,"var multifillcolors = [");
3134
          while( ! done ){
3135
            temp = get_color(infile,1);
3136
            fprintf(js_include_file,"\"%s\",",temp);
3137
          }
3138
          fprintf(js_include_file,"\"0,0,0\"];");/* add black to avoid trouble with dangling comma... */
3139
          break;
3140
        case MULTIFILLOPACITY:
3141
  /*
18556 bpr 3142
  @ multifillopacity fill_opacity_1,fill_opacity_2,...,fill_opacity_8
3143
  @ float values 0 - 1 or integer values 0 - 255
3144
  @ use before command <a href='#multidraw'>multidraw</a>
3145
  @ if not set all fill opacity_ will be set by previous command <code>opacity int,int</code> and keyword ''filled``
3146
  @ use these up to 7 different stroke opacities for the draw primitives used by command <code>multidraw obj_type_1,obj_type_2...obj_type_y</code>
3147
  @ wims will not check the amount or validity of your input
3148
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3149
  */
3150
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3151
          temp = get_string(infile,1);
3152
          temp = str_replace(temp,",","\",\"");
3153
          fprintf(js_include_file,"var multifillopacity = [\"%s\"];",temp);
3154
          break;
3155
        case MULTISNAPTOGRID:
3156
  /*
18556 bpr 3157
  @ multisnaptogrid 0,1,1
3158
  @ alternative: multisnap
3159
  @ meaning draw objects no. 2 (circle) and 3 (segments), in the list of command like <code>multifill points,circle,segments</code>, will snap to the xy-grid (default 1 in x/y-coordinate system: see command <a href='#snaptogrid'>snaptogrid</a>)
3160
  @ freehand drawing...specify precision for reply: all objects snap to grid <code>multisnaptogrid 1,1,1,...</code>
3161
  @ only the xy-values snap_to_grid: all objects snap to grid <code>multisnaptogrid 1,1,1,...</code>
3162
  @ only the x-values snap_to_grid: all objects snap to x-grid <code>multisnaptogrid 2,2,2,...</code>
3163
  @ only the y-values snap_to_grid: all objects snap to y-grid <code>multisnaptogrid 3,3,3,...</code>
3164
  @ if <a href='#snaptopoints'>snaptopoints</a> is defined: all objects snap to points <code>multisnaptogrid 4,4,4,...</code> <br><b>make sure to define the points to snap on...</b> use command <a href='#snaptopoints'>snaptopoints</a>
3165
  @ <code>multisnaptogrid 0,1,2,3,4<br>multidraw text,arrow,line,circle,image</code><br>''text`` is free hand, ''arrow`` is snap to grid, ''line`` is snap to x-grid, ''circle`` is snap to y-grid, ''image`` is snap to points defined by command <a href='#snaptopoints'>snaptopoints</a>
3166
  @ use before command <a href='#multidraw'>multidraw</a>
3167
  @ attention: if not set all objects will be set ''no snap``... unless a generic command ''snaptogrid`` was given before command ''multidraw``
3168
  @ commands <a href='#xsnaptogrid'>xsnaptogrid</a>, <a href='#ysnaptogrid'>ysnaptogrid</a>, <a href='#snaptofunction'>snaptofunction</a> are <b>not</b> supported amd only functional for command <a href='#userdraw'>userdraw</a>
3169
  @ always use the same sequence as is used for ''multidraw``
3170
  @ wims will <b>not</b> check if the number of 0 or 1's matches the amount of draw primitives...
18552 bpr 3171
  */
3172
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3173
          temp = get_string(infile,1);
3174
          fprintf(js_include_file,"var multisnaptogrid = [%s];",temp);
3175
          reset();/* if command 'dashed' was given...reset to not-dashed */
3176
          break;
3177
        case MULTISTROKECOLORS:
3178
  /*
18556 bpr 3179
  @ multistrokecolors color_name_1,color_name_2,...,color_name_8
3180
  @ use before command <a href='#multidraw'>multidraw</a>
3181
  @ if not set all colors will be ''stroke_color``, ''stroke_opacity``
3182
  @ use these up to 6 colors for the draw primitives used by command <code>multidraw obj_type_1,obj_type_2...obj_type_7</code>
18627 bpr 3183
  @ wims will <b>not</b> check if the number of colors matches the amount of draw primitives...
18556 bpr 3184
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3185
  */
3186
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3187
          fprintf(js_include_file,"var multistrokecolors = [");
3188
          while( ! done ){
3189
            temp = get_color(infile,1);
3190
            fprintf(js_include_file,"\"%s\",",temp);
3191
          }
3192
          fprintf(js_include_file,"\"0,0,0\"];");/* add black to avoid trouble with dangling comma... */
3193
          break;
3194
        case MULTISTROKEOPACITY:
3195
  /*
18556 bpr 3196
  @ multistrokeopacity stroke_opacity_1,stroke_opacity_2,...,stroke_opacity_7
3197
  @ float values 0 - 1 or integer values 0 - 255
3198
  @ use before command <a href='#multidraw'>multidraw</a>
3199
  @ if not set all stroke opacity_ will be set by previous command <code>opacity int,int</code>
3200
  @ use these up to 7 different stroke opacities for the draw primitives used by command <code>multidraw obj_type_1,obj_type_2...obj_type_7</code>
3201
  @ wims will not check the amount or validity of your input
3202
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3203
  */
3204
          if( use_tooltip == 1){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3205
          temp = get_string(infile,1);
3206
          temp = str_replace(temp,",","\",\"");
3207
          fprintf(js_include_file,"var multistrokeopacity = [\"%s\"];",temp);
3208
          break;
3209
        case MULTIUSERINPUT:
3210
  /*
3211
  @ multiuserinput 0,1,1,0
3212
  @ alternative: multiinput
18572 bpr 3213
  @ meaning, when the command ''multidraw`` is used <code>multidraw circles,points,lines,triangles</code><br>objects ''points`` and ''lines`` may additionally be ''drawn`` by direct input (inputfields)<br>all other objects must be drawn with a mouse
18552 bpr 3214
  @ in case of circle | circles a third inputfield for Radius (R) is added. The radius must be in the x/y coordinate system (x-range) and <b>not</b> in pixels...students don't think in pixels.<br>note: R-values will not snap-to-grid
3215
  @ in case of line(s) | segment(s) | arrow(s) the user should write <b>x1:y1</b> in the first inputfield and <b>x2:y2</b> in the second.<br>These ''hints`` are pre-filled into the input field.<br>Other coordinate delimiters are '';`` and '',`` e.g. <b>x1;y1</b> or <b>x1,y1</b>.<br>An error message (alert box) will popup when things are not correctly...
3216
  @ in case of a triangle | poly3, three inputfields are provided.
3217
  @ in case of ''text`` and ''multiuserinput=1, 3`` inputfields will be shown: ''x,y,text``
3218
  @ in case of ''text`` and ''multiuserinput=0, 1`` inputfield will be shown: text ... a mouse click will place the text on the canvas.
3219
  @ may be styled using command <a href="#css">css</a>
3220
  @ an additional button ''stop drawing`` may be used to combine userbased drawings with ''drag&and;drop`` or ''onclick`` elements
3221
  @ when exercise if finished (status=done) the buttons will not be shown.<br>To override this default behaviour use command / keyword ''status``
3222
  @ use before command <a href='#multidraw'>multidraw</a>
3223
  @ always use the same sequence as is used for ''multidraw``
3224
  */
3225
      /* simple rawmath and input check */
3226
          js_function[JS_SAFE_EVAL] = 1;
3227
          temp = get_string(infile,1);
3228
          temp = str_replace(temp,",","\",\"");
3229
          fprintf(js_include_file,"var multiuserinput = [\"%s\"];",temp);
3230
          break;
3231
        case NORESET:
3232
  /*
3233
  @ noreset
3234
  @ alternative: killreset
3235
  @ keyword
3236
  @ may come in handy if canvas script code is generated using loops
3237
  @ if used the following properties will remain to be valid<br><ul><li>filled</li><li>dash settings</li><li>onclick or drag settings</li><li>centering or offset</li></ul>
3238
  @ if used again, these properies will be reset to the default values and normal behaviour is continued (e.g. the above properties will be reset after 'use' on a canvas object)
3239
  @ etc etc
3240
  @ commands <a href='#slider'>slider</a>, <a href='#linear'>linear</a>, <a href='#rotate'>rotate</a>, <a href='#translate'>translate</a>, <a href='#affine'>affine</a> are always active until the 'kill' commands are given: <br><a href='#killlinear'>killlinear</a>, <a href='#killrotate'>killrotate</a>, <a href='#killtranslate'>killtranslate</a> and <a href='#killaffine'>killaffine</a>
3241
  @ commands like 'opacity', 'linewidth', 'fontsize', 'fontfamily' are only changed when redefined again
3242
  @%noreset%size 400,400%xrange -10,10%yrange -10,10%noreset%drag xy%linewidth 4%filled%rect -4,4,-2,2,blue%triangle -3,-3,0,0,1,-5,green%circle 0,0,50,orange%noreset%rect 2,4,4,2,blue
3243
  @%noreset_oefgraduation%size 800,100%xrange 0,11%yrange -1,1%hline 0,0,black%parallel 0,0,0,0.5,1,0,11,blue%noreset%onclick%centered%text black,1,0.6,large,20%text black,2,0.6,large,30%text black,3,0.6,large,40%text black,4,0.6,large,50%text black,5,0.6,large,60%text black,6,0.6,large,70%text black,7,0.6,large,80%text black,8,0.6,large,90%text black,9,0.6,large,100%text black,10,0.6,large,110
3244
  */
3245
          if(no_reset == FALSE){no_reset = TRUE;}else{no_reset = FALSE;reset();}
3246
          break;
3247
        case NOXAXIS:
3248
  /*
3249
  @ noxaxis
3250
  @ keyword
3251
  @ if set, the automatic x-axis numbering will be ignored
3252
  @ use command <a href="#axis">axis</a> to have a visual x/y-axis lines (see command <a href="#grid">grid</a>)
3253
  @ to be used before command grid (see <a href="#grid">command grid</a>)
3254
  */
3255
          fprintf(js_include_file,"x_strings = {};x_strings_up = [];\n");
3256
          use_axis_numbering = -1;
3257
          break;
3258
        case NOYAXIS:
3259
  /*
3260
  @ noyaxis
3261
  @ keyword
3262
  @ if set, the automatic y-axis numbering will be ignored
3263
  @ use command <a href="#axis">axis</a> to have a visual x/y-axis lines (see command <a href="#grid">grid</a>)
3264
  @ to be used before command grid (see <a href="#grid">command grid</a>)
3265
  */
3266
          fprintf(js_include_file,"y_strings = {};\n");
3267
          break;
3268
        case NUMBERLINE:
3269
  /*
3270
  @ numberline x0,x1,xmajor,xminor,y0,y1
3271
  @ numberline is using xrange/yrange system for all dimensions
3272
  @ multiple numberlines are allowed ; combinations with command <a href='#grid'>grid</a> is allowed; multiple commands <a href='#xaxis'>xaxis numbering</a> are allowed
3273
  @ x0 is start x-value in xrange
3274
  @ x1 is end x-value in xrange
3275
  @ xmajor is step for major division
3276
  @ xminor is divisor of xmajor; using small (30% of major tick) tick marks: this behaviour is ''hardcoded``
3277
  @ is xminor is an even divisor, an extra tickmark (60% of major tick) is added to the numberline: this behaviour is ''hardcoded``
3278
  @ y0 is bottom of numberline; y1 endpoint of major tics
3279
  @ use command <a href="#linewidth">linewidth</a> to control appearance
3280
  @ use <a href="#strokecolor">strokecolor</a> and <a href="#opacity">opacity</a> to controle measure line
3281
  @ for all ticks linewidth and color / opacity are identical.
3282
  @ if command <a href="#xaxis">xaxis</a> or <a href="#xaxisup">xaxisup</a> is not defined, the labeling will be on major ticks: x0...x1
3283
  @ use <a href="#fontfamily">fontfamily</a> and <a href="#fontcolor">fontcolor</a> to control fonts settings
3284
  @ may be used together with <a href="#userdraw">userdraw</a>, <a href="#multidraw">multidraw</a> and <a href="#drag">user drag</a> command family for the extra object drawn onto the numberline
3285
  @ <a href="#snaptogrid">snaptogrid, snaptopoints etc</a> and <a href="#zoom">zooming and panning</a> is supported
3286
  @ onclick and dragging of the numberline are not -yet- supported
3287
  @ note: in case of multiple numberlines, make sure the numberline without special x-axis numbering (e.g. ranging from xmin to xmax) comes first !
3288
  @%numberline%size 400,400%xrange -10,10%yrange -10,10%precision 1%strokecolor black%numberline -8,8,1,6,-4,-3.5%strokecolor red%xaxis -4:AA:-2:BB:2:CC:4:DD%numberline -8,8,1,2,4,4.5%strokecolor green%xaxisup -4:AAA:-2:BBB:2:CCC:4:DDD%numberline -8,8,1,3,2,2.5%strokecolor blue%xaxis -4:AAAA:-2:BBBB:2:CCCC:4:DDDD%numberline -8,8,1,4,0,0.5%strokecolor brown%xaxis -4:AAAAA:-2:BBBBB:2:CCCCC:4:DDDDD%numberline -8,8,1,5,-2,-1.5%zoom red
3289
  */
3290
          js_function[DRAW_NUMBERLINE] = 1;
3291
          for(i=0;i<6;i++){
3292
            switch(i){
3293
              case 0: double_data[0] = get_real(infile,0);break;/* xmin */
3294
              case 1: double_data[1] = get_real(infile,0);break;/* xmax */
3295
              case 2: double_data[2] = get_real(infile,0);break;/* xmajor */
3296
              case 3: double_data[3] = get_real(infile,0);break;/* xminor */
3297
              case 4: double_data[4] = get_real(infile,0);break;/* ymin */
3298
              case 5: double_data[5] = get_real(infile,1);/* ymax */
3299
            /*
3300
            var draw_numberline%d = function(canvas_type,xmin,xmax,xmajor,xminor,ymin,ymax,linewidth,strokecolor,strokeopacity,fontfamily,fontcolor);
3301
            */
3302
                fprintf(js_include_file,"snap_x = %f;snap_y = %f;",double_data[2] / double_data[3],double_data[5] - double_data[4] );
18557 bpr 3303
                tmp_buffer=my_newmem(MAX_BUFFER);
3304
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "\ndraw_numberline(%d,%d,%f,%f,%f,%f,%f,%f,%d,\"%s\",%f,\"%s\",\"%s\",%d);  ",NUMBERLINE_CANVAS+numberline_cnt,use_axis_numbering,double_data[0],double_data[1],double_data[2],double_data[3],double_data[4],double_data[5],line_width,stroke_color,stroke_opacity,font_family,font_color,precision));
18552 bpr 3305
                add_to_buffer(tmp_buffer);
3306
                numberline_cnt++;
3307
                break;
3308
              default:break;
3309
            }
3310
          }
3311
          reset();
3312
          break;
3313
        case OBABEL:
3314
  /*
3315
  @ obabel x,y,type input,molecule smiles-code or file location, extra arguments,extra arguments,...
3316
  @ will call the ''obabel`` program, if installed.
3317
  @ output will be an svg file
3318
  @ see documentation of obabel for special keys
3319
  @ command <a href='#affine'>affine</a> will produce CSS3 matrix transformations
3320
  @ command <a href='#rotate'>rotate</a> will rotate the object
3321
  @ can be set onclick: <code>javascript:read_dragdrop();</code> will return click numbers of mathml-objects<br>if 4 clickable object are drawn, the reply could be 1,0,1,0 ... meaning clicked on the first and third object
3322
  @ can be set draggable: <code>javascript:read_dragdrop();</code> will return all coordinates in the same order as the canvas script: unmoved object will have their original coordinates...
3323
  @ snaptogrid is supported...snaptopoints will work, but use with care...due to the primitive dragging<br>technically: the dragstuff library is not used...the mathml is embedded in a new div element and not in the html5-canvas
3324
  @ external files may be loaded if they are present on the server or in the modules <br>for example:<br> obabel 0,0,mol,&#36;module_dir/caffeine.mol,-P100,-xb none
3325
  @%obabel_smi%size 400,400%xrange -10,10%yrange -10,10%fillcolor green%drag xy%centered%obabel 0,0,smi,-:c1cFccc1cc,-xb none,-xB blue,-xi,-xt,-xa,-xX,-xP180,-h
3326
  */
3327
          js_function[DRAW_XML] = 1;
3328
          for(i=0;i<4;i++){
3329
            switch(i){
3330
              case 0: double_data[0]=get_real(infile,0);break; /* x in x/y-range coord system -> pixel width */
3331
              case 1: double_data[1]=get_real(infile,0);break; /* y in x/y-range coord system  -> pixel height */
3332
              case 2: URL = get_string_argument(infile,0);break;
3333
              case 3:
3334
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3335
                temp = getSVGMOL(URL,get_string(infile,1));
3336
                decimals = find_number_of_digits(precision);
3337
                if(use_affine == TRUE ){ transform(2,2);}
3338
                if( use_offset != 0 || drag_type != -1 ){int_data[2] = 1;}else{int_data[2] = 0;} /* only centered or not-centered */
3339
                int_data[0] = x2px(double_data[0]);
3340
                int_data[1] = y2px(double_data[1]);
3341
                if( use_slider != -1 && onclick == 0 ){ onclick = 3;}/* no drag&onclick but slideable */
3342
                if( use_slider != -1 && drag_type > 0 ){ onclick = 5;}/* slider+drag*/
3343
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'"); }
18557 bpr 3344
                tmp_buffer=my_newmem(MAX_BUFFER);
3345
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "var draw_xml%d = {id:%d,type:'svg',x:[%d],y:[%d],mathml:\"%s\",drag_type:%d,onclick:%d,object_cnt:%d,stroke_color:\"%s\",stroke_opacity:%.2f,fill_color:\"%s\",fill_opacity:%.2f,use_center:%d,use_snap:%d,angle:%f,fontfamily:\"%s\",transform:%s,use_affine:%d,offset:[0,0],use_slider:%s,rotation_center:%s,once:true};slidergroup[%d] = null;draw_xml(draw_xml%d);\n",drawxml_cnt,drawxml_cnt,int_data[0],int_data[1],temp,drag_type,onclick,object_cnt,stroke_color,stroke_opacity,fill_color,fill_opacity,int_data[2],use_snap,angle,font_family,doubledata2js_array(affine_matrix,6,decimals),use_affine,my_sliders,rotation_center,object_cnt,drawxml_cnt));
18552 bpr 3346
                add_to_buffer(tmp_buffer);
3347
                if(onclick != 0 ){object_cnt++;}
3348
                drawxml_cnt++;/* keeps track on imported img,div,p,span,mathml,svg */
3349
                break;
3350
              default:break;
3351
            }
3352
          }
3353
          reset();
3354
          break;
3355
        case OPACITY:
3356
  /*
3357
  @ opacity [0-255],[0-255]
3358
  @ opacity [0.0 - 1.0],[0.0 - 1.0]
3359
  @ alternative: transparent
3360
  @ first item is stroke opacity, second is fill opacity
3361
  @%opacity%size 400,400%xrange -10,10%yrange -10,10%opacity 255,0%fcircle -10,0,100,blue%opacity 250,50%fcircle -5,0,100,blue%opacity 200,100%fcircle 0,0,100,blue%opacity 150,150%fcircle 5,0,100,blue%opacity 100,200%fcircle 10,0,100,blue
3362
  */
3363
          for(i = 0 ; i<2;i++){
3364
            switch(i){
3365
              case 0: double_data[0]= get_real(infile,0);break;
3366
              case 1: double_data[1]= get_real(infile,1);break;
3367
              default: break;
3368
            }
3369
           }
3370
          if( double_data[0] > 255 ||  double_data[1] > 255  || double_data[0] < 0 || double_data[1] < 0 ){ canvas_error("opacity [0 - 255], [0 - 255] ");}/* typo or non-RGB ? */
18608 bpr 3371
          if( double_data[0] > 1 ){ stroke_opacity = (double) (0.0039215*double_data[0]); }else{ stroke_opacity = double_data[0];} /* 0.0 - 1.0 */
3372
          if( double_data[1] > 1 ){ fill_opacity = (double) (0.0039215*double_data[1]); }else{ fill_opacity = double_data[1];} /* 0.0 - 1.0 */
18552 bpr 3373
          break;
18608 bpr 3374
        case STROKEOPACITY:
3375
  /*
3376
  @ strokeopacity [0-255]
3377
  @ strokeopacity [0.0 - 1.0]
3378
  @%strokeopacity%size 400,400%xrange -10,10%yrange -10,10%fillopacity 120%strokeopacity 255%circle -10,0,100,blue%strokeopacity 100%circle -5,0,100,blue%strokeopacity 50%circle 0,0,100,blue
3379
  */
3380
          double_data[0]= get_real(infile,1);
3381
          if( double_data[0] > 255 || double_data[0] < 0 ){ canvas_error("opacity [0 - 255] ");}/* typo or non-RGB ? */
3382
          if( double_data[0] > 1 ){ stroke_opacity = (double) (0.0039215*double_data[0]); }else{ stroke_opacity = double_data[0];} /* 0.0 - 1.0 */
3383
          break;
3384
        case FILLOPACITY:
3385
  /*
3386
  @ fillopacity [0-255]
3387
  @ fillopacity [0.0 - 1.0]
3388
  @%fillopacity%size 400,400%xrange -10,10%yrange -10,10%strokeopacity 100%%fillopacity 0%fcircle -10,0,100,blue%fillopacity 50%fcircle -5,0,100,blue%fillopacity 100%fcircle 0,0,100,blue%fillopacity 150%fcircle 5,0,100,blue%fillopacity 200%fcircle 10,0,100,blue
3389
  */
3390
          double_data[0]= get_real(infile,1);
3391
          if( double_data[0] > 255 || double_data[0] < 0 ){ canvas_error("fillopacity [0 - 255] ");}/* typo or non-RGB ? */
3392
          if( double_data[0] > 1 ){ fill_opacity = (double) (0.0039215*double_data[0]); }else{ fill_opacity = double_data[0];} /* 0.0 - 1.0 */
3393
          break;
18552 bpr 3394
        case ONCLICK:
3395
  /*
18556 bpr 3396
  @ onclick
3397
  @ keyword (no arguments required)
3398
  @ if the next object is clicked, its ''object onclick_or_drag sequence number`` in fly script is returned by <code>javascript:read_canvas();</code>
3399
  @ onclick seqeuence numbering starts at ''0``, e.g. if there are 6 objects set onclick, the first onclick object will have id-number ''0``, the last id-number ''5``
3400
  @ line based objects will show an increase in line width<br>font based objects will show the text in ''bold`` when clicked.
3401
  @ the click zone (accuracy) is determined by 2&times; the line width of the object
3402
  @ onclick and <a href="#drag">drag x|y|xy</a> may be combined in a single flyscript (although a single object can <b>not</b> be onclick and draggable at the same time...)
3403
  @ note: not all objects may be set onclick
3404
  @%onclick%size 400,400%xrange -10,10%yrange -10,10%opacity 255,60%linewidth 3%onclick%fcircles blue,-3,3,1,1,2,2,3,1,1%onclick%ftriangles red,-4,-4,-4,0,-3,-2,0,0,4,0,2,-4%onclick%frects green,-4,4,-2,2,1,-1,3,-4
18552 bpr 3405
  */
3406
          fprintf(js_include_file,"use_dragdrop_reply = true;");
3407
          onclick = 1;
3408
          use_dragstuff=2;
3409
          js_function[INTERACTIVE] = 1;
3410
          break;
3411
        case PARALLEL:
3412
  /*
18556 bpr 3413
  @ parallel x1,y1,x2,y2,dx,dy,n,[colorname or #hexcolor]
3414
  @ affine transformations should be identical to flydraw
3415
  @ in case of <a href='#rotate'>rotation</a>  or <a href='#affine'>affine transformation </a>, command parallel will produce <em>n</em> individual segments, and these may be set ''onclick`` or ''drag xy`` individually.
3416
  @ in case of <em>no rotation or transformations</em> the lines can not be set ''onclick`` or ''drag xy``.
3417
  @ note: a large number of parallel lines (large <em>n</em>) may result in a canvasdraw error (...simplify your script...it produces too many lines...)
3418
  @%parallel_click%size 400,400%xrange -10,10%yrange -10,10%parallel -5,5,-4,-5,0.25,0,40,red%rotate 45%onclick%parallel -5,5,-4,-5,0.25,0,40,blue
3419
  @%parallel%size 400,400%xrange -10,10%yrange -10,10%parallel -5,5,-4,-5,0.25,0,40,red
18552 bpr 3420
  */
3421
          decimals = find_number_of_digits(precision);
3422
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3423
          if( use_rotate == TRUE || use_affine == TRUE ){
3424
            for( i = 0;i < 8; i++ ){
3425
              switch(i){
3426
                case 0: double_data[0] = get_real(infile,0);break; /* x1-values */
3427
                case 1: double_data[1] = get_real(infile,0);break; /* y1-values */
3428
                case 2: double_data[2] = get_real(infile,0);break; /* x2-values */
3429
                case 3: double_data[3] = get_real(infile,0);break; /* y2-values */
3430
                case 4: double_data[4] = get_real(infile,0);break; /* xv  */
3431
                case 5: double_data[5] = get_real(infile,0);break; /* yv  */
3432
                case 6: int_data[0] = (int) (get_real(infile,0));break; /* n  */
3433
                case 7: stroke_color=get_color(infile,1);break;/* name or hex color */
3434
                default: break;
3435
              }
3436
            }
3437
            double_data[6] = double_data[0]; /* x1 */
3438
            double_data[7] = double_data[1]; /* y1 */
3439
            double_data[8] = double_data[2]; /* x2 */
3440
            double_data[9] = double_data[3]; /* y2 */
3441
            for(i = 0 ; i < int_data[0] ; i++){
3442
              double_data[0] = double_data[6] + i*double_data[4];
3443
              double_data[1] = double_data[7] + i*double_data[5];
3444
              double_data[2] = double_data[8] + i*double_data[4];
3445
              double_data[3] = double_data[9] + i*double_data[5];
3446
              if(use_rotate == TRUE ){ rotate(4,angle,rotationcenter,2);}
3447
              if(use_affine == TRUE ){ transform(4,2);}
18557 bpr 3448
              tmp_buffer=my_newmem(MAX_BUFFER);
3449
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[1],decimals,double_data[3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3450
              add_to_buffer(tmp_buffer);
3451
              if(onclick != 0){object_cnt++;}
3452
            }
3453
            dragstuff[4] = 1;
3454
          }
3455
          else  /* use the old parallel version: calculations in javascript */
3456
          {
3457
            for( i = 0;i < 8; i++ ){
3458
              switch(i){
3459
                case 0: double_data[0] = get_real(infile,0);break; /* x1-values */
3460
                case 1: double_data[1] = get_real(infile,0);break; /* y1-values */
3461
                case 2: double_data[2] = get_real(infile,0);break; /* x2-values */
3462
                case 3: double_data[3] = get_real(infile,0);break; /* y2-values */
3463
                case 4: double_data[4] = xmin + get_real(infile,0);break; /* xv  */
3464
                case 5: double_data[5] = ymax + get_real(infile,0);break; /* yv  */
3465
                case 6: int_data[0] = (int) (get_real(infile,0));break; /* n  */
3466
                case 7: stroke_color=get_color(infile,1);/* name or hex color */
18557 bpr 3467
                  tmp_buffer=my_newmem(MAX_BUFFER);
3468
                  check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,11,[%.*f,%.*f,%.*f],[%.*f,%.*f,%.*f],[%d,%d,%d],[%d,%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[4],decimals,double_data[1],decimals,double_data[3],decimals,double_data[5],int_data[0],int_data[0],int_data[0],int_data[0],int_data[0],int_data[0],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3469
                  add_to_buffer(tmp_buffer);
3470
                  if(onclick != 0){object_cnt++;}
3471
                  break;
3472
                default: break;
3473
              }
3474
              dragstuff[11] = 1;
3475
            }
3476
          }
3477
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3478
          reset();
3479
          break;
3480
        case PLOTSTEPS:
3481
      /*
18556 bpr 3482
  @ plotsteps a_number
3483
  @ default 150
3484
  @ only used for commands <a href="#curve">curve / plot</a> and <a href="#levelcurve">levelcurve</a>
3485
  @ use with care !
18552 bpr 3486
      */
3487
          plot_steps = (int) (get_real(infile,1));
3488
          break;
3489
        case POINT:
3490
  /*
3491
  @ point x,y,color
3492
  @ draw a single point at (x;y) in color 'color'
3493
  @ use command <code>linewidth int</code> to adjust size
3494
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
3495
  @ will not resize on zooming (command <code>circle x,y,r,color</code> will resize on zooming)
3496
  @ attention: in case of command <a href="#rotate">rotate angle</a> a point has rotation center (0:0) in x/y-range
3497
  @%point%size 400,400%xrange -10,10%yrange -10,10%opacity 255,255%linewidth 1%onclick%point 0,0,red%linewidth 2%onclick%point 1,1,blue%linewidth 3%onclick%point 3,3,green%linewidth 4%point 4,4,orange
3498
  */
3499
          for(i=0;i<3;i++){
3500
            switch(i){
3501
              case 0: double_data[0] = get_real(infile,0);break; /* x */
3502
              case 1: double_data[1] = get_real(infile,0);break; /* y */
3503
              case 2: stroke_color = get_color(infile,1);/* name or hex color */
3504
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
3505
                if(use_affine == TRUE ){ transform(2,2);}
3506
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3507
                decimals = find_number_of_digits(precision);
18557 bpr 3508
                tmp_buffer=my_newmem(MAX_BUFFER);
3509
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,2,[%.*f],[%.*f],[%.2f],[%d],%.2f,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[1],1.5*line_width,line_width,1.5*line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,1,0,0,0,use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3510
                add_to_buffer(tmp_buffer);
3511
                /* object_cnt++; */
3512
                if(onclick != 0){object_cnt++;}
3513
                break;
3514
              default: break;
3515
            }
3516
          }
3517
          dragstuff[2] = 1;
3518
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3519
          reset();
3520
          break;
3521
        case POINTS:
3522
  /*
3523
  @ points color,x1,y1,x2,y2,...,x_n,y_n
3524
  @ draw multiple points at given coordinates in color 'color'
3525
  @ use command <code>linewidth int</code> to adjust size
3526
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
3527
  @ attention: in case of command <a href="#rotate">rotate angle</a> the points have rotation center (0:0) in x/y-range
3528
  @%points_1%size 400,400%xrange -10,10%yrange -10,10%opacity 255,255%snaptogrid%linewidth 1%drag xy%points red,0,0,1,1,2,2,3,3%drag x%points blue,0,1,1,2,2,3,3,4
3529
  @%points_2%size 400,400%xrange -10,10%yrange -10,10%opacity 255,255%linewidth 1%onclick%points red,0,0,1,1,2,2,3,3%onclick%points blue,0,1,1,2,2,3,3,4
3530
  */
3531
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
3532
          fill_color = stroke_color;
3533
          i=0;
3534
          while( ! done ){     /* get next item until EOL*/
3535
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3536
            if(i%2 == 0 ){
3537
              double_data[i] = get_real(infile,0); /* x */
3538
            }
3539
            else {
3540
              double_data[i] = get_real(infile,1); /* y */
3541
            }
3542
            i++;
3543
          }
3544
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3545
          if(use_affine == TRUE ){ transform(i-1,2);}
3546
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3547
          decimals = find_number_of_digits(precision);
3548
          for(c = 0 ; c < i-1 ; c = c+2){
18557 bpr 3549
            tmp_buffer=my_newmem(MAX_BUFFER);
3550
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,2,[%.*f],[%.*f],[%.2f],[%d],%.2f,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+1],1.5*line_width,line_width,1.5*line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,1,0,0,0,use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3551
            add_to_buffer(tmp_buffer);
3552
            /* object_cnt++; */
3553
            if(onclick != 0){object_cnt++;}
3554
          }
3555
          dragstuff[2] = 1;
3556
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3557
          reset();
3558
          break;
3559
        case POLY:
3560
  /*
3561
  @ poly color,x1,y1,x2,y2...x_n,y_n
3562
  @ polygon color,x1,y1,x2,y2...x_n,y_n
3563
  @ draw closed polygon
3564
  @ use command ''fpoly`` to fill it or use keyword <a href='#filled'>filled</a>
3565
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
3566
  @%polygon_1%size 400,400%xrange -10,10%yrange -10,10%opacity 255,25%fillcolor orange%filled%linewidth 2%drag xy%snaptogrid%poly blue,0,0,1,3,3,1,2,4,-1,3
3567
  @%polygon_2%size 400,400%xrange -10,10%yrange -10,10%opacity 255,25%fillcolor orange%filled%linewidth 1%onclick%poly green,0,0,1,3,3,1,2,4,-1,3
3568
  */
3569
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
3570
          i=0;
3571
          c=0;
3572
          while( ! done ){     /* get next item until EOL*/
3573
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3574
            for( c = 0 ; c < 2; c++){
3575
              if(c == 0 ){
3576
                double_data[i] = get_real(infile,0);
3577
                i++;
3578
              }
3579
              else {
3580
                double_data[i] = get_real(infile,1);
3581
                i++;
3582
              }
3583
            }
3584
          }
3585
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3586
          if(use_affine == TRUE ){ transform(i-1,2);}
3587
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
8386 schaersvoo 3588
 
18552 bpr 3589
      /* draw path:  closed & optional filled */
3590
          decimals = find_number_of_digits(precision);
18557 bpr 3591
          tmp_buffer=my_newmem(MAX_BUFFER);
3592
          check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,5,%s,[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,double_xy2js_array(double_data,i,decimals),line_width,stroke_color,stroke_opacity,stroke_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3593
          add_to_buffer(tmp_buffer);
3594
          if(onclick != 0){object_cnt++;}
3595
          reset();
3596
          dragstuff[5] = 1;
3597
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3598
          break;
3599
        case POLYLINE:
3600
  /*
3601
  @ polyline color,x1,y1,x2,y2...x_n,y_n
3602
  @ brokenline color,x1,y1,x2,y2...x_n,y_n
3603
  @ path color,x1,y1,x2,y2...x_n,y_n
3604
  @ remark: there is <b>no</b> command polylines | brokenlines | paths ... just use multiple commands <code>polyline, x1,y1,x2,y2...x_n,y_n</code>
3605
  @ remark: there are commands <code>userdraw path(s),color</code> and <code>userdraw polyline,color</code>... these are two entirely different things ! the path(s) userdraw commands may be used for freehand drawing(s)<br>the polyline userdraw command is analogue to this polyline|brokenline command
3606
  @ the command interconnects the points in the given order with a line (canvasdraw will not close the drawing: use command <a href="#poly">polygon</a> for this)
3607
  @ use command <a href='#segments'>segments</a> for a series of segments. These may be clicked/dragged individually
3608
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
3609
  @%polyline_1%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag xy%snaptogrid%polyline blue,0,0,1,3,3,1,2,4,-1,3
3610
  @%polyline_2%size 400,400%xrange -10,10%yrange -10,10%linewidth 1%onclick%polyline green,0,0,1,3,3,1,2,4,-1,3
3611
  */
11806 schaersvoo 3612
 
18552 bpr 3613
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
3614
          i=0;
3615
          c=0;
3616
          while( ! done ){     /* get next item until EOL*/
3617
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3618
            for( c = 0 ; c < 2; c++){
3619
              if(c == 0 ){
3620
                double_data[i] = get_real(infile,0);
3621
                i++;
3622
              }
3623
              else {
3624
                double_data[i] = get_real(infile,1);
3625
                i++;
3626
              }
3627
            }
3628
          }
11806 schaersvoo 3629
 
18552 bpr 3630
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3631
          if(use_affine == TRUE ){ transform(i-1,2);}
3632
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
11806 schaersvoo 3633
 
18552 bpr 3634
      /* draw path: not closed & not filled */
3635
          decimals = find_number_of_digits(precision);
18557 bpr 3636
          tmp_buffer=my_newmem(MAX_BUFFER);
3637
          check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,%s,[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,double_xy2js_array(double_data,i,decimals),line_width,stroke_color,stroke_opacity,stroke_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3638
          add_to_buffer(tmp_buffer);
3639
          if(onclick != 0){object_cnt++;}
3640
          /* object_cnt++;*/
3641
          reset();
3642
          dragstuff[4] = 1;
3643
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3644
          break;
3645
        case POPUP:
3646
      /*
18556 bpr 3647
  @ popup
3648
  @ keyword (no arguments)
3649
  @ if fly-script starts with keyword ''popup``, the canvas image will be exclusively in a popup window (xsize px &times; ysize px)
3650
  @ if keyword ''popup`` is used after command <code>size xsize,ysize</code> the canvas will also be displayed in a popup window with size ''xsize &times; ysize``
3651
  @ the popup window will be embedded into the page as a normal image, when ''status=done``; override with keyword <a href="#status">nostatus</a>
3652
  @ to access the read_canvas and read_dragdrop functions in a popup window, use:<br> <code> function read_all(){<br> if( typeof popup !== 'undefined' ){<br> var fun1 = popup['read_dragdrop'+canvas_scripts[0]];<br>var fun2 = popup['read_canvas'+canvas_scripts[0]];<br> popup.close();<br> return "dragdrop="+fun1()+"\\ncanvas="+fun2();<br> };</code>
3653
  @ to set a canvasdraw produced <a href="#clock">clock</a> or multiple clocks...use something like: <code>popup.set_clock(clock_id,type,diff);</code> as js-function for a button (or something else) in your document page.<br>where in <b>clock_id</b> starts with 0 for the first clock<br><b>type</b> is 1 for Hours,2 for Minutes and 3 for Seconds<br><b>diff</b> is the increment (positive or negative) per click
3654
  @%popup%popup%size 400,400%xrange -2*pi,2*pi%yrange -5,5%precision 0%axis%axisnumbering%opacity 100,190%grid 1,1,grey,2,2,5,black%linewidth 4%fillcolor blue%trange -pi,pi%animate%linewidth 1%precision 1000%jsplot red,4*cos(2*x),2*sin(3*x-pi/6)%strokecolor green%functionlabel H(x)=%userinput function
18552 bpr 3655
      */
3656
          use_tooltip = 2;
3657
          break;
3658
        case PROTRACTOR:
3659
  /*
18556 bpr 3660
  @ protractor x,y,x_width,type,mode,use_a_scale
3661
  @ x,y are the initial location
3662
  @ x_width: give the width in x-coordinate system (e.g. not in pixels !)
3663
  @ type = 1: a triangle range 0 - 180<br>type = 2: a circle shape 0 - 360
3664
  @ mode: use -1 to set the protractor interactive (mouse movement of protractor)<br>use mode = '0&deg; - 360&deg;' to set the protractor with a static angle of some value
3665
  @ if the value of the user_rotation angle is to be shown...use command <a href='#display'>display degree,color,fontsize</a><a href='#display'>display radian,color,fontsize</a>
3666
  @ use_scale = 1: the protractor will have some scale values printed; use_scale=0 to disable
3667
  @ the rotating direction of the mouse around the protractor determines the clockwise/ counter clockwise rotation of the protractor...
3668
  @ commands ''stroke_color | fill_color | linewidth | opacity | font_family`` will determine the looks of the protractor.
3669
  @ default replyformat: reply[0] = x;reply[1] = y;reply[2] = angle_in_radians<br>use command ''precision`` to set the reply precision.
3670
  @ if combined with a ruler, use replyformat = 32
3671
  @ command <code>snap_to_grid</code> may be used to assist the pupil at placing the protractor
3672
  @ when using command ''zoom``, pay <b>attention</b> to the size and symmetry of your canvas<br>...to avoid a partial image, locate the start position near the center of the visual canvas<br>technical: the actual ''protractor`` is just a static generated image in a new canvas-memory<br>This image is only generated once, and a copy of its bitmap is translated & rotated onto the visible canvas.<br>That is the reason for the ''high-speed dragging and rotating``.<br>I've limited its size to xsize &times; ysize e.g. the same size as the visual canvas...
3673
  @ only one protractor allowed (for the time being)
3674
  @ usage: first left click on the protractor will activate dragging;<br>a second left click will activate rotating (just move mouse around)<br>a third click will freeze this position and the x/y-coordinate and angle in radians will be stored in reply(3)<br>a next click will restart this sequence...
3675
  @%protractor%size 400,400%xrange -5,10%yrange -5,10%hline 0,0,black%vline 0,0,black%fillcolor orange%opacity 255,40%protractor 2,-2,6,0,-1,1,1%mouse red,22
18552 bpr 3676
  */
3677
          for( i = 0;i < 6; i++ ){
3678
            switch(i){
3679
              case 0: double_data[0] = get_real(infile,0);break; /* x-center */
3680
              case 1: double_data[1] = get_real(infile,0);break; /* y-center */
3681
              case 2: double_data[2] = get_real(infile,0);break; /* x-width */
3682
              case 3: int_data[0] = (int)(get_real(infile,0));break; /* type: 1==triangle 2 == circle */
3683
              case 4: int_data[1] = (int)(get_real(infile,0));break; /* passive mode == 0; active mode == -1 */
3684
              case 5: int_data[2] = (int)(get_real(infile,1)); /* use scale */
3685
                decimals = find_number_of_digits(precision);
3686
                if( int_data[1] < 0 ){ js_function[JS_FIND_ANGLE] = 1;}
18557 bpr 3687
                add_js_protractor(int_data[0],double_data[0], double_data[1], double_data[2],font_family,stroke_color,stroke_opacity,fill_color,fill_opacity,line_width,int_data[2],int_data[1],use_snap);
3688
                tmp_buffer=my_newmem(MAX_BUFFER);
3689
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, ";protractor%d(); ",canvas_root_id));
18552 bpr 3690
                add_to_buffer(tmp_buffer);
3691
                reply_precision = precision;
3692
        /* no reply from protractor if non-interactive */
3693
                if( reply_format == 0 && int_data[1] == -1 ){reply_format = 30;}
3694
                js_function[INTERACTIVE] = 1;
3695
                break;
3696
              default: break;
3697
            }
3698
          }
3699
          break;
3700
        case PIXELS:
3701
  /*
3702
  @ pixels color,x1,y1,x2,y2,x3,y3...
3703
  @ draw rectangular "points" with diameter 1 pixel
3704
  @ pixels can <b>not</b> be dragged or clicked
3705
  @ "pixelsize = 1" may be changed by command <code>pixelsize int</code>
3706
  @%pixels%size 400,400%opacity 255,255%pixelsize 5%pixels red,1,1,2,2,3,3,4,4,5,5,10,10,20,20,30,30,40,40,50,50,60,60,70,70,80,80,90,90,100,100,120,120,140,140,160,160,180,180,200,200,240,240,280,280,320,320,360,360,400,400%#NOTE pixelsize=5...otherwise you will not see them clearly...
3707
  */
3708
          js_function[DRAW_PIXELS] = 1;
3709
          stroke_color=get_color(infile,0);
3710
          i=0;
3711
          c=0;
3712
          while( ! done ){     /* get next item until EOL*/
3713
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3714
            for( c = 0 ; c < 2; c++){
3715
              if(c == 0 ){
3716
                double_data[i] = get_real(infile,0);
3717
                i++;
3718
              }
3719
              else {
3720
                double_data[i] = get_real(infile,1);
3721
              }
3722
            }
3723
        }
3724
        if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3725
        if(use_affine == TRUE ){ transform(i-1,2);}
3726
        decimals = find_number_of_digits(precision);
3727
        /*  *double_xy2js_array(double xy[],int len,int decimals) */
18557 bpr 3728
        tmp_buffer=my_newmem(MAX_BUFFER);
3729
        check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_setpixel(%s,\"%s\",%.2f,%d);\n",double_xy2js_array(double_data,i,decimals),stroke_color,stroke_opacity,pixelsize));
18552 bpr 3730
        add_to_buffer(tmp_buffer);
3731
        reset();
3732
        break;
3733
        case PIXELSIZE:
3734
  /*
3735
  @ pixelsize int
3736
  @ in case you want to deviate from default pixelsize = 1(...)
3737
  @ pixelsize 100 is of course a filled rectangle 100px &times; 100px
3738
  */
3739
          pixelsize = (int) get_real(infile,1);
3740
          break;
15111 schaersvoo 3741
 
18552 bpr 3742
        case PIECHART:
3743
  /*
3744
  @ piechart xc,yc,radius,'data+colorlist'
3745
  @ (xc: yc) center of circle diagram in xrange/yrange
3746
  @ radius in pixels
18627 bpr 3747
  @ data+color list: a colon separated list of raw data and corresponding colors<br>canvasdraw will not check validity of colornames...<br>in case of trouble look into javascript debugging of your browser
18552 bpr 3748
  @ example data+colorlist: 32:red:65:green:23:black:43:orange:43:yellow:14:white
3749
  @ the number of colors must match the number of data.
3750
  @ if defined <a href='#fillpattern'>fillpattern some_pattern</a> then the pie pieces will be filled with the respective color and a fill pattern...<br>the pattern is cycled from the 4 pattern primitives: grid,hatch,diamond,dot,grid,hatch,diamond,dot,...
18627 bpr 3751
  @ use command <a href='#opacity'>opacity</a> to adjust fill_opacity of colors
3752
  @ use command <a href='#legend'>legend</a> to automatically create a legend using the same colors as pie segments; unicode allowed in legend; expect javascript trouble if the amount of ''pie-slices``, ''pie-colors``, ''pie-legend-titles`` do not match, a javascript console is your best friend...<br>use command ''fontfamily`` to set the font of the legend.
18552 bpr 3753
  @ use command <a href='centered'>centered</a> to place <a href='#legend'>legend</a> text inside the piechart. The text is using the same color as the pie segment: use (fill) opacity to enhance visibility.
3754
  @%piechart_1%size 300,200%xrange -10,10%yrange -10,10%legend cars:motorcycles:bicycles:trikes%opacity 255,120%piechart -5,0,75,22:red:8:blue:63:green:7:purple%
3755
  @%piechart_2%size 200,200%xrange -10,10%yrange -10,10%fontfamily 16px Arial%centered%legend cars:motorcycles:bicycles:trikes%opacity 255,60%piechart 0,0,100,22:red:8:blue:63:green:7:purple
3756
  */
3757
          js_function[DRAW_PIECHART] = 1;
3758
          for(i=0;i<5;i++){
3759
            switch(i){
3760
              case 0: int_data[0] = x2px(get_real(infile,0)); break; /* x */
3761
              case 1: int_data[1] = y2px(get_real(infile,0)); break; /* y  */
3762
              case 2: int_data[2] = (int)(get_real(infile,1));break;/* radius*/
3763
              case 3: temp = get_string(infile,1);
3764
                if( strstr( temp, ":" ) != 0 ){ temp = str_replace(temp,":","\",\"");}
18557 bpr 3765
                tmp_buffer=my_newmem(MAX_BUFFER);
3766
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_piechart(%d,%d,%d,%d,[\"%s\"],%.2f,%d,\"%s\",%d,%d);\n",PIECHART,int_data[0],int_data[1],int_data[2],temp,fill_opacity,legend_cnt,font_family,use_filled,use_offset));
18552 bpr 3767
                add_to_buffer(tmp_buffer);
3768
                break;
3769
              default:break;
3770
            }
3771
          }
3772
          reset();
3773
          break;
3774
        case RANGE:
3775
  /*
3776
  @ range xmin,xmax,ymin,ymax
3777
  @ if not given: 0,xsize,0,ysize (eg in pixels)
3778
  */
3779
          for(i = 0 ; i<4; i++){
3780
            switch(i){
3781
              case 0: xmin = get_real(infile,0);break;
3782
              case 1: xmax = get_real(infile,1);break;
3783
              case 2: ymin = get_real(infile,0);break;
3784
              case 3: ymax = get_real(infile,1);break;
3785
              default: break;
3786
            }
3787
          }
3788
          if(xmin >= xmax){canvas_error(" xrange is not OK: xmin &lt; xmax !");}
3789
          if(ymin >= ymax){canvas_error(" yrange is not OK: ymin &lt; ymax !");}
3790
          fprintf(js_include_file,"var xmin = %f;var xmax = %f;var ymin = %f;var ymax = %f;",xmin,xmax,ymin,ymax);
3791
          found_size_command = found_size_command+2;
3792
          break;
3793
        case RAYS:
3794
  /*
18556 bpr 3795
  @ rays color,xc,yc,x1,y1,x2,y2,x3,y3...x_n,y_n
3796
  @ draw rays in color 'color' and center (xc:yc)
3797
  @ may be set draggable or onclick (every individual ray)
3798
  @%rays_onclick%size 400,400%xrange -10,10%yrange -10,10%onclick%rays blue,0,0,3,9,-3,5,-4,0,4,-9,7,9,-8,1,-1,-9
3799
  @%rays_drag_xy%size 400,400%xrange -10,10%yrange -10,10%drag xy%rays blue,0,0,3,9,-3,5,-4,0,4,-9,7,9,-8,1,-1,-9
18552 bpr 3800
  */
3801
          stroke_color=get_color(infile,0);
3802
          fill_color = stroke_color;
3803
          double_data[0] = get_real(infile,0);/* xc */
3804
          double_data[1] = get_real(infile,0);/* yc */
3805
          i=2;
3806
          while( ! done ){     /* get next item until EOL*/
3807
            if(i > MAX_INT - 1){canvas_error("in command rays too many points / rays in argument: repeat command multiple times to fit");}
3808
            if(i%2 == 0 ){
3809
              double_data[i] = get_real(infile,0); /* x */
3810
            }
3811
            else {
3812
              double_data[i] = get_real(infile,1); /* y */
3813
            }
3814
            fprintf(js_include_file,"/* double_data[%d] = %f */\n",i,double_data[i]);
3815
            i++;
3816
          }
3817
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3818
          if(use_affine == TRUE ){ transform(i-1,2);}
3819
          if( i%2 != 0 ){canvas_error("in command rays: unpaired x or y value");}
3820
          decimals = find_number_of_digits(precision);
3821
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3822
          for(c=2; c<i;c = c+2){
18557 bpr 3823
            tmp_buffer=my_newmem(MAX_BUFFER);
3824
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[c],decimals,double_data[1],decimals,double_data[c+1],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3825
            add_to_buffer(tmp_buffer);
3826
    /* object_cnt++; */
3827
            if(onclick != 0){object_cnt++;}
3828
          }
3829
          reset();
3830
          dragstuff[4] = 1;
3831
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3832
          break;
3833
        case RECT:
3834
  /*
3835
  @ rect x1,y1,x2,y2,color
3836
  @ use command <code>frect x1,y1,x2,y2,color</code> for a filled rectangle
3837
  @ use command/keyword <a href='#filled'>filled</a> before command <code>rect x1,y1,x2,y2,color</code>
3838
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
18572 bpr 3839
  @ note: internally a rect is defined with 4 points. So when performing some affine transformation, other than translation, it will result in some morphing of the rectangle !<br>this is a deviation of flydraw's rect&amp;affine
18552 bpr 3840
  @%rect%size 400,400%xrange -10,10%yrange -10,10%rect 0,0,4,-4,green%rect 0,5,4,1,red
3841
  */
3842
          for(i=0;i<5;i++){
3843
            switch(i){
3844
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
3845
              case 1:double_data[1] = get_real(infile,0);break; /* y-values */
3846
              case 2:double_data[4] = get_real(infile,0);break; /* x-values */
3847
              case 3:double_data[5] = get_real(infile,0);break; /* y-values */
3848
              case 4:stroke_color = get_color(infile,1);/* name or hex color */
3849
                decimals = find_number_of_digits(precision);
3850
                double_data[2] = double_data[4];
3851
                double_data[3] = double_data[1];
3852
                double_data[6] = double_data[0];
3853
                double_data[7] = double_data[5];
3854
          /* using closed PATH (type=5) instead of ctx.rect (type=1)!!!
3855
              0,1   2,3
3856
          6,7      4,5
3857
          x = [0,2,4,6]
3858
          y = [1,3,5,7]
3859
          */
18623 bpr 3860
                if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 3861
                if(use_rotate == TRUE ){rotate(8,angle,rotationcenter,2);}
3862
                if(use_affine == TRUE ){ transform(8,2);}
3863
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 3864
                tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 3865
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,5,[%.*f,%.*f,%.*f,%.*f],[%.*f,%.*f,%.*f,%.*f],[%d],[%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[4],decimals,double_data[6],decimals,double_data[1],decimals,double_data[3],decimals,double_data[5],decimals,double_data[7],line_width,line_width,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3866
                add_to_buffer(tmp_buffer);
3867
                if(onclick != 0){object_cnt++;}
18555 bpr 3868
                /* object_cnt++; */
18552 bpr 3869
                reset();
3870
                break;
3871
              }
3872
            }
3873
          dragstuff[5] = 1;
3874
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3875
          break;
3876
        case RECTS:
3877
  /*
3878
  @ rects color,x1,y1,x2,y2,.....
3879
  @ use command <code>frect color,x1,y1,x2,y2,.....</code> for a filled rectangle
3880
  @ use command/keyword <a href='#filled'>filled</a> before command <code>rects color,x1,y1,x2,y2,....</code>
18623 bpr 3881
  @ use command <code>fillcolor color</code> before ''frects`` to set the fill color.
18552 bpr 3882
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
3883
  @%rects%size 400,400%xrange -10,10%yrange -10,10%rects red,0,0,4,-4,0,5,4,1
3884
  */
3885
      /* using closed PATH (type=5) in stead of ctx.rect (type=1)!!!
3886
      0,1   2,3 .....8,9  10,11.....
3887
  6,7      4,5 .....14,15  12,13.....
3888
  x = [0,2,4,6,8,10,12,14...]
3889
  y = [1,3,5,7,9,11,13,15...]
3890
      */
3891
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
18623 bpr 3892
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 3893
          i=0;
3894
          while( ! done ){     /* get next item until EOL*/
3895
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3896
            if(i%2 == 0 ){
3897
              double_data[i] = get_real(infile,0); /* x */
3898
            }
3899
            else {
3900
              double_data[i] = get_real(infile,1); /* y */
3901
            }
3902
            i++;
3903
          }
3904
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3905
          if(use_affine == TRUE ){ transform(i-1,2);}
3906
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
11806 schaersvoo 3907
 
18552 bpr 3908
          decimals = find_number_of_digits(precision);
3909
          for(c = 0 ; c < i-1 ; c = c+4){
18557 bpr 3910
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 3911
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,5,[%.*f,%.*f,%.*f,%.*f],[%.*f,%.*f,%.*f,%.*f],[%d],[%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+2],decimals,double_data[c],decimals,double_data[c+1],decimals,double_data[c+1],decimals,double_data[c+3],decimals,double_data[c+3],line_width,line_width,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3912
            add_to_buffer(tmp_buffer);
3913
            if(onclick != 0){object_cnt++;}
3914
    /* object_cnt++; */
3915
          }
3916
          dragstuff[5] = 1;
3917
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3918
          if(use_rotate == TRUE ){
3919
            rotate(i-1,angle,rotationcenter,2);
3920
          }
3921
          reset();
3922
          break;
3923
        case REPLYFORMAT:
3924
  /*
3925
  @ replyformat number
3926
  @ use number=-1 to deactivate the js-functions read_canvas() and read_dragdrop()
3927
  @ default values should be fine !
3928
  @ use command <code>precision [0,1,10,100,1000,10000...]</code> before command ''replyformat`` to set the desired number of decimals in the student reply / drawing
3929
  @ the last value for ''precision int`` will be used to calculate the reply coordinates, if needed (read_canvas();)
3930
  @ choose<ul><li>replyformat 1: <code>x1,x2,x3,x4....x_n<br>y1,y2,y3,y4....y_n</code> x/y in pixels</li><li>replyformat 2: <code> x1,x2,x3,x4....x_n<br> y1,y2,y3,y4....y_n</code> x/y in xrange / yrange coordinate system</li><li>replyformat 3: <code> x1,x2,x3,x4....x_n<br> y1,y2,y3,y4....y_n<br> r1,r2,r3,r4....r_n</code> x/y in pixels, r in pixels</li><li>replyformat 4: <code> x1,x2,x3,x4....x_n<br> y1,y2,y3,y4....y_n<br> r1,r2,r3,r4....r_n</code> x/y in xrange / yrange coordinate system, r in pixels</li><li>replyformat 5: <code> Ax1,Ax2,Ax3,Ax4....Ax_n<br> Ay1,Ay2,Ay3,Ay4....Ay_n<br> Bx1,Bx2,Bx3,Bx4....Bx_n<br> By1,By2,By3,By4....By_n<br> Cx1,Cx2,Cx3,Cx4....Cx_n<br>  Cy1,Cy2,Cy3,Cy4....Cy_n<br>  ....<br>  Zx1,Zx2,Zx3,Zx4....Zx_n<br> Zy1,Zy2,Zy3,Zy4....Zy_n</code> x/y in pixels</li><li>replyformat 6: <code> Ax1,Ax2,Ax3,Ax4....Ax_n<br> Ay1,Ay2,Ay3,Ay4....Ay_n<br> Bx1,Bx2,Bx3,Bx4....Bx_n<br> By1,By2,By3,By4....By_n<br> Cx1,Cx2,Cx3,Cx4....Cx_n<br> Cy1,Cy2,Cy3,Cy4....Cy_n<br> ....<br> Zx1,Zx2,Zx3,Zx4....Zx_n<br> Zy1,Zy2,Zy3,Zy4....Zy_n</code> x/y in xrange / yrange coordinate system</li><li>replyformat 7: <code> x1:y1,x2:y2,x3:y3,x4:y4...x_n:y_n</code> x/y in pixels</li><li>replyformat 8: <code> x1:y1,x2:y2,x3:y3,x4:y4...x_n:y_n</code> x/y in xrange / yrange coordinate system</li><li>replyformat 9: <code> x1:y1:r1,x2:y2:r2,x3:y3:r3,x4:y4:r3...x_n:y_n:r_n</code> x/y in pixels</li><li>replyformat 10: <code> x1:y1:r1,x2:y2:r2,x3:y3:r3,x4:y4:r3...x_n:y_n:r_n</code> x/y in xrange / yrange coordinate system</li><li>replyformat 11: <code> Ax1,Ay1,Ax2,Ay2<br>Bx1,By1,Bx2,By2<br> Cx1,Cy1,Cx2,Cy2<br> Dx1,Dy1,Dx2,Dy2<br> ......<br> Zx1,Zy1,Zx2,Zy2</code> x/y in xrange / yrange coordinate system</li><li>replyformat 12: <code> Ax1,Ay1,Ax2,Ay2<br> Bx1,By1,Bx2,By2<br>Cx1,Cy1,Cx2,Cy2<br> Dx1,Dy1,Dx2,Dy2<br> ......<br> Zx1,Zy1,Zx2,Zy2</code> x/y in pixels</li><li>replyformat 13: <code> Ax1:Ay1:Ax2:Ay2,Bx1:By1:Bx2:By2,Cx1:Cy1:Cx2:Cy2,Dx1:Dy1:Dx2:Dy2, ... ,Zx1:Zy1:Zx2:Zy2</code> x/y in xrange / yrange coordinate system</li><li>replyformat 14: <code> Ax1:Ay1:Ax2:Ay2,Bx1:By1:Bx2:By2....Zx1:Zy1:Zx2:Zy2</code> x/y in pixels</li><li>replyformat 15: reply from inputfields,textareas <code>reply1,reply2,reply3,...,reply_n</code></li><li>replyformat 16: mathml input fields</li><li>replyformat 17: read ''userdraw text,color`` only <code>x1,y1,text1 \\n x2,y2,text2...\\n...x_n,y_n,text_n </code> x/y-values are in xrange/yrange</li><li>replyformat 18: read_canvas() will read all interactive clocks in <code>H1:M1:S1,H2:M2:S2...Hn:Mn:Sn</code></li><li>replyformat 19: read_canvas() will return the object number of marked / clicked object (clock), analogue to (shape library) onclick command</li><li>replyformat 20: read_canvas() will reply "object_number:x:y" of external images: object_number of the first draggable external image in the fly-script starts with 0, e.g. expect something like 0:-5:4,1:6:2,2:-2:-5, the first image position is (-5:4), the second image position is (6:2) and the third image position is (-2:-5)   <li>replyformat 21: <code> (x1:y1) (x2:y2) ... (x_n:y_n)</code> verbatim coordinate return</li><li>replyformat 22: returns an array .... <code>reply[0]=x1 reply[1]=y1 reply[2]=x2 reply[3]=y2 ... reply[n-1]=x_n reply[n]=y_n</code> x/y in xrange / yrange coordinate system</li><li>replyformat 23: can only be used for drawtype ''polyline``. A typical click sequence in drawtype polyline is x1,y1,x2,y2,x2,y2,x3,y3,x3,y3.....,x(n-1),y(n-1),x(n-1),y(n-1),xn,yn --replyformat 23 gives <code>x1,y1,x2,y2,x3,y3,.....x(n-1),y(n-1),xn,yn</code>; multiple occurences will be filtered out. The reply will be in x-y-range (xreply \\n yreply)</li><li>replyformat 24: read all inputfield values: even those set ''readonly``</li><li>replyformat 25: <code> angle1,angle2;...;angle_n</code> will return the radius (one or many) of the user drawn circle segment in degrees</li><li>replyformat 26: <code> rad1,rad2,...rad_n</code> will return the radius (one or many) of the user drawn circle segment in radians</li><li>replyformat 27: return (only) userdraw inputfields <code>x1,y1,text1<br> x2,y2,text2...<br>...x_n,y_n,textn</code></li><li>replyformat 28: <code> x1,y1,r1,x2,y2,r2...x_n,y_n,r_n</code> x / y / r in xrange / yrange coordinate system: may be used to reinput into command <code>circles color,x1,y1,r1,x2,y2,r2...x_n,y_n,r_n</code> will not return anything else (e.g. no inputfields, text etc)</li><li>replyformat 34: a special for OEF and dragging external images -included via commands <a href='#copy'>copy</a> or <a href='#copyresized'>copyresized</a> there will be an extra function <code>read_canvas_images()</code> for reading the coordinates of the images.<br>for now this is a unique function, e.g. there is no ''canvas id`` linked to it. (TO DO !!! 18/5/2019)</li></ul>
3931
  @ special replyformat = 100 ; will access to the raw javascript object data...use: read_dragdrop([property,property,...])<br>for example  properies like 'clicked','text', 'angle' , 'x'
3932
  */
3933
          reply_format = (int) get_real(infile,1);
3934
          reply_precision = precision;
3935
          break;
3936
        case ROUNDRECT:
3937
  /*
3938
  @ roundrect x1,y1,x2,y2,radius in px,color
3939
  @ use command <code>froundrect x1,y1,x2,y2,radius,color</code> for a filled rectangle
3940
  @ use command/keyword <a href='#filled'>filled</a> before command <code>roundrect x1,y1,x2,y2,radius,color</code>
3941
  @ fillcolor will be identical to ''color``
3942
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
3943
  @%roundrect%size 400,400%xrange -10,10%yrange -10,10%roundrect 0,0,4,-4,20,green%roundrect 0,5,4,1,10,red
3944
  */
3945
          for(i=0;i<6;i++){
3946
            switch(i){
3947
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
3948
              case 1:double_data[1] = get_real(infile,0);break; /* y-values */
3949
              case 2:double_data[2] = get_real(infile,0);break; /* x-values */
3950
              case 3:double_data[3] = get_real(infile,0);break; /* y-values */
3951
              case 4:int_data[0] = (int) (get_real(infile,0));break; /* radius value in pixels */
3952
              case 5:stroke_color = get_color(infile,1);/* name or hex color */
3953
                if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
3954
                if(use_affine == TRUE ){ transform(2,4);}
3955
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3956
      /* ensure no inverted roundrect is produced... */
3957
                if( double_data[0] > double_data[2] ){double_data[4] = double_data[0];double_data[0] = double_data[2];double_data[2] = double_data[4];}
3958
                if( double_data[3] > double_data[1] ){double_data[4] = double_data[1];double_data[1] = double_data[3];double_data[3] = double_data[4];}
3959
                decimals = find_number_of_digits(precision);
18557 bpr 3960
                tmp_buffer=my_newmem(MAX_BUFFER);
3961
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,6,[%.*f,%.*f],[%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[1],decimals,double_data[3],int_data[0],int_data[0],int_data[0],int_data[0],line_width,stroke_color,stroke_opacity,stroke_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 3962
                add_to_buffer(tmp_buffer);
3963
                if(onclick != 0){object_cnt++;}
3964
      /* object_cnt++;*/
3965
                reset();
3966
                break;
3967
            }
3968
          }
3969
          dragstuff[6] = 1;
3970
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3971
          break;
3972
        case ROUNDRECTS:
3973
  /*
3974
  @ roundrects color,radius in px,x1,y1,x2,y2,x3,y3,x4,y4,....
3975
  @ for filled roundrects use command/keyword <a href='#filled'>filled</a> before command
3976
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
3977
  @%roundrects%size 400,400%xrange -10,10%yrange -10,10%roundrects blue,5,0,0,4,-4,5,4,1,2
3978
  */
11806 schaersvoo 3979
 
18552 bpr 3980
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
3981
          int_data[0] = (int) (get_real(infile,0)); /* radius value in pixels */
18623 bpr 3982
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 3983
          i=0;
3984
          while( ! done ){     /* get next item until EOL*/
3985
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3986
            if(i%2 == 0 ){
3987
              double_data[i] = get_real(infile,0); /* x */
3988
            }
3989
            else {
3990
              double_data[i] = get_real(infile,1); /* y */
3991
            }
3992
            i++;
3993
          }
3994
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3995
          if(use_affine == TRUE ){ transform(i-1,2);}
3996
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3997
          decimals = find_number_of_digits(precision);
3998
          for(c = 0 ; c < i-1 ; c = c+4){
3999
    /* ensure no inverted roundrect is produced... */
4000
            if( double_data[c] > double_data[c+2] ){double_data[c+4] = double_data[c];double_data[c] = double_data[c+2];double_data[c+2] = double_data[c+4];}
4001
            if( double_data[c+3] > double_data[c+1] ){double_data[c+4] = double_data[c+1];double_data[c+1] = double_data[c+3];double_data[c+3] = double_data[c+4];}
18557 bpr 4002
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 4003
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,6,[%.*f,%.*f],[%.*f,%.*f],[%d,%d],[%d,%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+1],decimals,double_data[c+3],int_data[0],int_data[0],int_data[0],int_data[0],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 4004
            add_to_buffer(tmp_buffer);
4005
            if(onclick != 0){object_cnt++;}
4006
    /* object_cnt++; */
4007
          }
4008
          dragstuff[6] = 1;
4009
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4010
          reset();
4011
          break;
4012
        case RULER:
4013
  /*
4014
  @ ruler x,y,x-width,y-height,mode
4015
  @ x,y are the initial location
4016
  @ x-width, y-height are the ruler dimensions width &amp; height in xy-coordinate system
4017
  @ the ruler scale is by definition the x-scale, set by command ''xrange``. For example: a ruler x-width of 6 will have a scale ranging from 0 to 6
4018
  @ mode: use -1 to set the ruler interactive (eg mouse movement of ruler; drag &amp; rotate)<br>use mode = '0&deg; - 360&deg;' to set the ruler with a static angle of some value
4019
  @ if combined with a protractor, use replyformat = 32
4020
  @ only one ruler allowed (for the time being)
4021
  @ when using command ''zoom``, pay <b>attention</b> to the size and symmetry of your canvas to avoid a partial image, locate the start position near the center of the visual canvas; technical: the actual ''ruler`` is just a static generated image in a new canvas-memory. This image is only generated once, and a copy of its bitmap is translated & rotated onto the visible canvas. That is the reason for the ''high-speed dragging and rotating``. I have limited its size to xsize &times; ysize e.g. the same size as the visual canvas...
4022
  @ usage: first left click on the ruler will activate dragging; a second left click will activate rotating (just move mouse around), a third click will freeze this position and the x/y-coordinate and angle in radians will be stored in reply(3), a next click will restart this sequence...
4023
  @%ruler_interactive%size 800,400%xrange -10,10%yrange -10,10%strokecolor blue%opacity 200,50%filled%fillcolor lightgrey%ruler -9,0,10,2,-1%display degree,blue,22
4024
  @%ruler_set_degree_45%size 800,400%xrange -10,10%yrange -10,10%strokecolor blue%opacity 200,50%filled%fillcolor lightgrey%ruler 0,0,10,2,45
4025
  @%ruler_set_degree_125%size 800,400%xrange -10,10%yrange -10,10%strokecolor blue%opacity 200,50%filled%fillcolor lightgrey%ruler 0,0,10,2,125
4026
  */
4027
          for( i = 0;i < 5; i++ ){
4028
            switch(i){
4029
              case 0: double_data[0] = get_real(infile,0);break; /* x-center */
4030
              case 1: double_data[1] = get_real(infile,0);break; /* y-center */
4031
              case 2: double_data[2] = get_real(infile,0);break; /* x-width */
4032
              case 3: double_data[3] = get_real(infile,0);break; /* y-width */
4033
              case 4: int_data[0] = (int)(get_real(infile,1)); /* passive mode */
4034
                decimals = find_number_of_digits(precision);
4035
                if( int_data[0] < 0 ){
4036
                  js_function[JS_FIND_ANGLE] = 1;
4037
                }
18557 bpr 4038
                add_js_ruler(double_data[0],double_data[1],double_data[2],double_data[3], font_family,stroke_color,stroke_opacity,fill_color,fill_opacity,line_width,int_data[0],use_snap);
4039
                tmp_buffer=my_newmem(MAX_BUFFER);
4040
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, ";ruler%d(); ",canvas_root_id));
18552 bpr 4041
                add_to_buffer(tmp_buffer);
4042
                reply_precision = precision;
4043
                /* no reply from ruler if non-interactive */
4044
                if( reply_format == 0 && int_data[0] == -1 ){reply_format = 31;}
4045
                break;
4046
              default: break;
4047
            }
4048
          }
4049
          break;
4050
        case RESET:
4051
  /*
4052
  @ reset
4053
  @ keyword
4054
  @ disables the effects of the <a href="noreset">noreset</a> command
4055
  @ so the next objects will not be <a href="#filled">filled</a> and <a href="#dashed">dashed</a>
4056
  */
4057
          no_reset = FALSE; reset();
4058
          break;
4059
        case RESETOFFSET:
4060
  /*
18556 bpr 4061
  @ resetoffset
4062
  @ keyword ; use to restore text placement on the canvas to the real (x;y) coordinates of the left bottom corner of the text
4063
  @ may be active for commands <a href="#text">text</a> and <a href="#string">string</a> (e.g. objects in the drag/drop/onclick-librariy
18552 bpr 4064
  */
4065
          use_offset = 0;
4066
          break;
4067
        case ROTATE:
4068
  /*
18556 bpr 4069
  @ rotate rotation_angle
4070
  @ angle in degrees
4071
  @ (only) the next object will be rotated is given angle
4072
  @ positive values rotate counter clockwise
4073
  @ attention: all objects will be rotated around their first point...<br><code>rotate 45<br>triangle 1,1,5,1,3,4,red</code><br>will rotate 45 degrees around point (1:1)
4074
  @ if another rotation center is needed, use command <a href="#rotationcenter">rotationcenter xc,yc</a>.<br>to reset this rotationcenter, use keyword <a href="#killrotate">killrotate</a>
4075
  @ attention: rotate will mess up the interactivity of the rotated object <br>e.g. if combined with command <a href="#drag">drag xy</a> or keyword <a href="#onclick">onclick</a>: the mouse recognises the original -unrotated- coordinates of the object
4076
  @%rotate_1%size 400,400%xrange -10,10%yrange -10,10%fpoly yellow,0,0,4,3,2,5%rotate 45%fpoly violet,0,0,4,3,2,5%killrotate%rotate 90%fpoly violet,0,0,4,3,2,5%
18552 bpr 4077
  */
4078
          use_rotate = TRUE;
4079
          angle = -1*(get_real(infile,1));/* -1: to be compatible with Flydraw... */
4080
          break;
4081
        case ROTATION_CENTER:
4082
  /*
4083
  @ rotationcenter x_center,y_center
4084
  @ define an rotation center in your x/y-coordinate system
4085
  @ wims will not check the validity of your input; use javascript console to debug any erors
4086
  @ if not defined a rotation will be around the first point of an object
4087
  @ to be used before command <a href="#rotate">rotate</a>
18572 bpr 4088
  @ use <a href="#killrotate">killrotate</a> to reset to 'null' <br>(eg. the rotationcenter of the next object(s) will be the first (x;y) coordinate of the object(s))
18552 bpr 4089
  @ all other commands will use this rotation center, unless a <a href="#killrotation">killrotation</a> is given
4090
  @%rotationcenter%size 400,400%xrange -5,10%yrange -5,10%circles green,3,3,4.25%rotationcenter 3,3%opacity 255,80%fpoly yellow,0,0,4,3,2,5%rotate 45%fpoly violet,0,0,4,3,2,5%rotate 90%fpoly lightblue,0,0,4,3,2,5%rotate 135%fpoly blue,0,0,4,3,2,5%rotate 180%fpoly orange,0,0,4,3,2,5%rotate 225%fpoly green,0,0,4,3,2,5%rotate 270%fpoly cyan,0,0,4,3,2,5%rotate 315%fpoly purple,0,0,4,3,2,5%linewidth 3%point 3,3,red%mouse red,22
4091
  @%rotationcenter_slider%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%fillcolor black%strokecolor yellow%rotationcenter 0,0%fontsize 28%slider 0,2*pi,400,30,angle degrees active, rotate...%plot red,5*sin(x)%filled%linewidth 1%opacity 150,50%fillcolor orange%angle 0,0,pi,0,0,blue
4092
  */
4093
          for( i = 0;i < 2; i++ ){
4094
            switch(i){
4095
              case 0: rotationcenter[0] = get_real(infile,0);break; /* x-center */
4096
              case 1: rotationcenter[1] = get_real(infile,1);break; /* y-center */
4097
            }
4098
            string_length = 1 + snprintf(NULL,0,"[%f,%f ]",rotationcenter[0],rotationcenter[1]);
18557 bpr 4099
 
18552 bpr 4100
            rotation_center = my_newmem(string_length);
4101
            snprintf(rotation_center,string_length,"[%f,%f]",rotationcenter[0],rotationcenter[1]);
4102
          }
4103
          break;
4104
        case SIZE:
4105
      /*
18556 bpr 4106
  @ size width,height
4107
  @ set canvas size in pixels
4108
  @ mandatory first command (can only be preceded by keyword <a href="#popup">popup</a>)
4109
  @ if xrange and/or yrange is not given the range will be set to pixels:<br>xrange 0,xsize yrange 0,ysize<br>note: lower left corner is origin (0:0) !!! this in contrast to flydraw
18552 bpr 4110
      */
4111
          found_size_command = 1;
4112
          /* using fabs: however "xsize == int": so "xsize = abs( (int) get_real(infile,0))" would be the idea... */
4113
          xsize = (int)(fabs(round(get_real(infile,0)))); /* just to be sure that sizes > 0 */
4114
          ysize = (int)(fabs(round(get_real(infile,1))));
4115
          /* sometimes we want xrange / yrange to be in pixels...without telling x/y-range */
4116
          xmin = 0;xmax = xsize;
4117
          ymin = 0;ymax = ysize;
11806 schaersvoo 4118
 
4119
/*
4120
 The sequence in which stuff is finally printed is important !!
4121
*/
18552 bpr 4122
          fprintf(stdout,"\n\
4123
          <script>\n\
4124
          /*<![CDATA[*/\n\
4125
          if( typeof(wims_status) === 'undefined' ){ var wims_status = \"$status\";};\
4126
          if( typeof(use_dragdrop_reply) === 'undefined' ){ var use_dragdrop_reply = false;};\
4127
          if( typeof(canvas_scripts) === 'undefined' ){ var canvas_scripts = new Array();};\
4128
          canvas_scripts.push(\"%d\");\n/*]]>*/\n</script>\n\
4129
          ",canvas_root_id);
11806 schaersvoo 4130
 
18552 bpr 4131
          /* style=\"display:block;position:relative;margin-left:auto;margin-right:auto;margin-bottom:4px;\" */
4132
          if( use_tooltip != 2){
4133
            fprintf(stdout,"<!-- canvasdraw div -->\n\
4134
            <div tabindex=\"0\" id=\"canvas_div%d\" style=\"max-width:%dpx;width:%dpx;height:%dpx\" class=\"canvas_wrapper\" oncontextmenu=\"return false;\">\
4135
             <canvas class=\"canvas_placeholder\" width=\"%d\" height=\"%d\"></canvas>\
4136
            </div>\n\
4137
            <!-- tooltip and input placeholder -->\n\
4138
            <div id=\"tooltip_placeholder_div%d\" style=\"text-align:center\">\
4139
             <span id=\"tooltip_placeholder%d\" class=\"tooltip_placeholder\"></span></div>\
4140
            <!-- include actual object code via include file -->\n\
4141
            <script id=\"canvas_script%d\" src=\"%s\" defer></script>\n",canvas_root_id,xsize,xsize,ysize,xsize,ysize,canvas_root_id,canvas_root_id,canvas_root_id,getfile_cmd);
4142
          } else {
11806 schaersvoo 4143
/*
14066 bpr 4144
set canvas_div invisible and do not include placeholder in main html page:
15111 schaersvoo 4145
the js-include will also be in a popup window...to be shown when wims &#36;status = done
11806 schaersvoo 4146
*/
18552 bpr 4147
            fprintf(stdout,"<!-- canvasdraw div invisible -->\n\
4148
            <div tabindex=\"0\" id=\"canvas_div%d\" class=\"canvas_wrapper\" style=\"display:none;max-width:%dpx;width:%dpx;height:%dpx;\">\
4149
             <canvas class=\"canvas_placeholder\" width=\"%d\" height=\"%d\"></canvas>\
4150
            </div>\n\
4151
            <div id=\"tooltip_placeholder_div%d\" style=\"display:none;position:relative;margin-left:auto;margin-right:auto;margin-bottom:4px;\">\
4152
             <span id=\"tooltip_placeholder%d\" class=\"tooltip_placeholder\"></span></div>\
4153
            <!-- include actual object code via include file -->\n\
4154
            <script id=\"canvas_script%d\" src=\"%s\"></script>\n",canvas_root_id,xsize,xsize,ysize,xsize,ysize,canvas_root_id,canvas_root_id,canvas_root_id,getfile_cmd);
4155
          }
11806 schaersvoo 4156
 
14071 bpr 4157
/* these must be global...it is all really very poor javascript:( */
15734 schaersvoo 4158
fprintf(js_include_file,"\n/* begin generated javascript include for canvasdraw version %s */\n\
11806 schaersvoo 4159
\"use strict\";\n\
15111 schaersvoo 4160
/* these variables and functions must be global */\
11806 schaersvoo 4161
var read_dragdrop%d;\
14038 schaersvoo 4162
var read_canvas_images;\
11806 schaersvoo 4163
var read_canvas%d;\
4164
var set_clock;\
4165
var clear_draw_area%d;\
4166
var update_draw_area%d;\
14038 schaersvoo 4167
var place_image_on_canvas;\
11806 schaersvoo 4168
var draw_boxplot;\
4169
var redraw_all%d;\
15111 schaersvoo 4170
var userdraw_primitive;\
4171
var wims_canvas_function%d = function(){\n/* common used stuff */\
4172
var userdraw_x = [];var userdraw_y = [];var userdraw_radius = [];\
11806 schaersvoo 4173
var xsize = %d;\
4174
var ysize = %d;\
4175
var precision = 100;\
4176
var canvas_div = document.getElementById(\"canvas_div%d\");\
4177
var create_canvas%d = function(canvas_type,size_x,size_y){var cnv;if(document.getElementById(\"wims_canvas%d\"+canvas_type)){ cnv = document.getElementById(\"wims_canvas%d\"+canvas_type);}else{try{ cnv = document.createElement(\"canvas\"); }catch(e){alert(\"Your browser does not support HTML5 CANVAS:GET FIREFOX !\");return;};canvas_div.appendChild(cnv);};cnv.width = size_x;cnv.height = size_y;cnv.style.top = 0;cnv.style.left = 0;cnv.style.position = \"absolute\";cnv.id = \"wims_canvas%d\"+canvas_type;return cnv;};\
4178
function findPosX(i){ var obj = i;var curleft = 0;if(obj.offsetParent){while(1){curleft += obj.offsetLeft;if(!obj.offsetParent){break;};obj = obj.offsetParent;};}else{if(obj.x){curleft += obj.x;};};return curleft;};function findPosY(i){var obj = i;var curtop = 0;if(obj.offsetParent){while(1){curtop += obj.offsetTop;if(!obj.offsetParent){break;};obj = obj.offsetParent;};}else{if(obj.y){curtop += obj.y;};};return curtop;};\
18638 bpr 4179
function x2px(x){if(use_xlogscale == 0 ){let res=parseFloat((x-xmin)/(xmax - xmin)*xsize);return (res==xsize)?xsize-1:res;}else{let x_max = Math.log(xmax)/Math.log(xlogbase);let x_min = Math.log(xmin)/Math.log(xlogbase);let x_in = Math.log(x)/Math.log(xlogbase);let res=(x_in-x_min)/(x_max - x_min)*xsize; return (res==xsize)?xsize-1:res;};};\
18606 bpr 4180
function px2x(px){if(use_xlogscale == 0 ){return px*(xmax - xmin)/xsize + xmin;}else{let x_max = Math.log(xmax)/Math.log(xlogbase);let x_min = Math.log(xmin)/Math.log(xlogbase);let x_out = x_min +px*(x_max - x_min)/xsize;return Math.pow(xlogbase,x_out);};};\
4181
function px2y(py){if(use_ylogscale == 0 ){return ymax - py*(ymax - ymin)/ysize;}else{let y_max = Math.log(ymax)/Math.log(ylogbase);let y_min = Math.log(ymin)/Math.log(ylogbase);let y_out = y_max +py*(y_min - y_max)/ysize;return Math.pow(ylogbase,y_out);};};\
18638 bpr 4182
function y2px(y){if(use_ylogscale == 0){let res= parseFloat((ymax-y)/(ymax - ymin)*ysize);return (res==ysize)?ysize-1:res;}else{var y_max = Math.log(ymax)/Math.log(ylogbase);var y_min = Math.log(ymin)/Math.log(ylogbase);var y_in = Math.log(y)/Math.log(ylogbase);return (y_max - y_in)*ysize/(y_max - y_min);};};\
11806 schaersvoo 4183
function scale_x_radius(rx){return rx*xsize/(xmax - xmin);};\
4184
function scale_y_radius(ry){return ry*ysize/(ymax - ymin);};\
4185
function distance(x1,y1,x2,y2){return Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );};\
4186
function distance_to_line (r,q,x,y){var c = (y) - (-1/r)*(x);var xs = r*(c - q)/(r*r+1);var ys = (r)*(xs)+(q);return parseInt(Math.sqrt( (xs-x)*(xs-x) + (ys-y)*(ys-y) ));};\
4187
function move(obj,dx,dy){for(var p = 0 ; p < obj.x.length; p++){obj.x[p] = obj.x[p] + dx;obj.y[p] = obj.y[p] + dy;};return obj;};\
15111 schaersvoo 4188
var snap_x = 1;var snap_y = 1;\
11806 schaersvoo 4189
function snap_to_x(x){return x2px(snap_x*(Math.round((px2x(x))/snap_x)));};\
11890 schaersvoo 4190
function snap_to_y(y){return y2px(snap_y*(Math.round((px2y(y))/snap_y)));};\
15111 schaersvoo 4191
function multisnap_check(x,y,snap){switch(snap){case 1:return [snap_to_x(x),snap_to_y(y)];break;case 2:return [snap_to_x(x),y];break;case 3:return [x,snap_to_y(y)];break;case 4:return snap_to_points(x,y);break;case 5: return snap_to_fun(x,y);break;default: return [x,y];break;};};\
11806 schaersvoo 4192
var xlogbase = 10;\
4193
var ylogbase = 10;\
4194
var use_xlogscale = 0;\
4195
var use_ylogscale = 0;\
11891 schaersvoo 4196
var x_strings = {};var x_strings_up = [];\
11806 schaersvoo 4197
var y_strings = null;\
4198
var use_jsmath = 0;\
4199
var xstart = 0;\
4200
var ystart = 0;\
4201
var unit_x=\" \";\
4202
var unit_y=\" \";\
15111 schaersvoo 4203
var dragdrop_reply = [];\
15734 schaersvoo 4204
var external_canvas = create_canvas%d(%d,xsize,ysize);",VERSION,canvas_root_id,canvas_root_id,canvas_root_id,canvas_root_id,canvas_root_id,canvas_root_id,xsize,ysize,canvas_root_id,canvas_root_id,canvas_root_id,canvas_root_id,canvas_root_id,canvas_root_id,EXTERNAL_IMAGE_CANVAS);
15111 schaersvoo 4205
/* var xstart,ystart are normally 0 : in case of sgraph they have the 'jump' in the graph */
18552 bpr 4206
          break;
4207
        case SEGMENT:
4208
  /*
4209
  @ segment x1,y1,x2,y2,color
4210
  @ alternative: seg
4211
  @ draw a line segment between points (x1:y1)--(x2:y2) in color ''color``
4212
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
4213
  @%segment_onclick%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%segment 1,1,-9,3,green
4214
  @%segment_drag_y%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag y%segment 1,1,-9,3,green
4215
  */
4216
          for(i=0;i<5;i++) {
4217
            switch(i){
4218
              case 0: double_data[0]= get_real(infile,0);break; /* x1-values */
4219
              case 1: double_data[1]= get_real(infile,0);break; /* y1-values */
4220
              case 2: double_data[2]= get_real(infile,0);break; /* x2-values */
4221
              case 3: double_data[3]= get_real(infile,0);break; /* y2-values */
4222
              case 4: stroke_color=get_color(infile,1);/* name or hex color */
4223
                if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
4224
                if(use_affine == TRUE ){ transform(4,2);}
4225
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
4226
                decimals = find_number_of_digits(precision);
18557 bpr 4227
                tmp_buffer=my_newmem(MAX_BUFFER);
4228
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,double_data[1],decimals,double_data[3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 4229
                add_to_buffer(tmp_buffer);
4230
                if(onclick != 0){object_cnt++;}
4231
                /* object_cnt++; */
4232
                reset();
4233
                break;
4234
              default: break;
4235
            }
4236
          }
4237
          dragstuff[4] = 1;
4238
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4239
          break;
4240
        case SEGMENTS:
4241
  /*
4242
  @ segments color,x1,y1,x2,y2,...,x_n,y_n
4243
  @ alternative: segs
4244
  @ draw multiple segments between points (x1:y1)--(x2:y2).....and... (x_n-1:y_n-1)--(x_n:y_n) in color ''color``
4245
  @ use command ''linewidth int`` to adjust size
4246
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
4247
  @%segments_onclick%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%segments green,1,1,3,3,0,0,-3,3,1,1,4,-1,-5,5,-3,-1
4248
  @%segments_drag_y%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag y%segments green,1,1,3,3,0,0,-3,3,1,1,4,-1,-5,5,-3,-1
4249
  */
4250
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
4251
          fill_color = stroke_color;
4252
          i=0;
4253
          while( ! done ){     /* get next item until EOL*/
4254
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
4255
            if(i%2 == 0 ){
4256
              double_data[i] = get_real(infile,0); /* x */
4257
            }
4258
            else {
4259
              double_data[i] = get_real(infile,1); /* y */
4260
            }
4261
            i++;
4262
          }
4263
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
4264
          if(use_affine == TRUE ){ transform(i-1,2);}
4265
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
4266
          decimals = find_number_of_digits(precision);
4267
          for(c = 0 ; c < i-1 ; c = c+4){
18557 bpr 4268
            tmp_buffer=my_newmem(MAX_BUFFER);
4269
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+1],decimals,double_data[c+3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 4270
            add_to_buffer(tmp_buffer);
4271
            if(onclick != 0){object_cnt++;}
4272
    /* object_cnt++;*/
4273
          }
4274
          reset();
4275
          dragstuff[4] = 1;
4276
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4277
          break;
4278
        case SETLIMITS:
4279
  /*
18556 bpr 4280
  @ setlimits
4281
  @ keyword: if set, it will produce 4 inputfields for ''xmin,xmax,ymin,ymax`` and an ''ok`` button
4282
  @ may be used for inputfield based zooming / panning
4283
  @ may be styled using command <a href="#css">css</a>
4284
  @ use commands <a href="#xlabel">xlabel / ylabel</a> to change text from xmin to ''xlabel`` etc
4285
  @ note: the input value will not be checked on validity
4286
  @%setlimits%size 400,400%xrange -10,10%yrange -10,10%precision 1%xlabel T%ylabel H%axis%axisnumbering%grid 2,2,grey,2,2,5,grey%precision 100%multistrokecolors red,green,blue,orange%multilinewidth 1,1,2,2%multistrokeopacity 0.6,0.7,0.8,0.9%jsplot red,1/x,-1,x,1/(x-3),1/(x+3)%setlimits
18552 bpr 4287
  */
4288
          js_function[JS_SAFE_EVAL] = 1;
4289
          js_function[JSPLOT_AND_ZOOM] = 1;
4290
          add_setlimits(font_size,css_class);
4291
          done = TRUE;
4292
          break;
4293
        case SETPIXEL:
4294
  /*
4295
  @ setpixel x,y,color
4296
  @ A rectangular "point" with diameter 1 pixel centered at (x:y) in xrange / yrange
4297
  @ pixels can <b>not</b> be dragged or clicked
4298
  @ "pixelsize = 1" may be changed by command <code>pixelsize int</code>
4299
  @%setpixel%size 400,400%xrange -10,10%yrange -10,10%setpixel 1,1,red%pixelsize 2%setpixel 2,2,green%pixelsize 3%setpixel 3,3,blue%
4300
  */
4301
          js_function[DRAW_PIXELS] = 1;
4302
          for(i=0;i<3;i++){
4303
            switch(i){
4304
              case 0: double_data[0] = get_real(infile,0); break; /* x */
4305
              case 1: double_data[1] = get_real(infile,0); break; /* y */
4306
              case 2: stroke_color = get_color(infile,1);
18557 bpr 4307
                tmp_buffer=my_newmem(MAX_BUFFER);
4308
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_setpixel([%f],[%f],\"%s\",%.2f,%d);\n",double_data[0],double_data[1],stroke_color,stroke_opacity,pixelsize));
18552 bpr 4309
                add_to_buffer(tmp_buffer);
4310
                break;
4311
              default:break;
4312
            }
4313
          }
4314
          reset();
4315
          break;
4316
        case SLIDER:
4317
  /*
4318
  @ slider start_value,end_value,width px,height px,type,label
4319
  @ type may be: ''x,y,angle``
4320
  @ if a slider value display is desired, use for argument ''type``: ''x display``, ''y display``, ''angle radian``, ''angle degree``
4321
  @ is the slider is used for animation, add keyword ''anim`` or ''animate`` to ''type``; for now only one animated slider may be used...
18572 bpr 4322
  @ default behaviour is: click on an object to use its slider(s)<br>to use sliders without clicking on an object, use for ''type`` keyword ''active``<br>eg: <code>slider -2*pi,2*pi,300,30,angle degree active,Rotate</code>
18552 bpr 4323
  @ if a unit (or something like that...) for x/y-value display is needed, use commands ''xunit`` and / or ''yunit``
4324
  @ if the translation should be performed using a function, use for type: ''x function``, ''y function``<br>use commands ''sliderfunction_x`` and/or ''sliderfunction_y`` before the slider command to define the functions. Example:<code>sliderfunction_x x^2<br>sliderfunction_y y^2<br>slider -5,5,100,100,xy function,Some_Text<br>...some stuff to slide<br>killslider<br>sliderfunction_x x^2-2<br>slider -15,15,100,10,x function,Some_Other_Text<br>...more stuff to slide<br>killslider... etc</code>
4325
  @ use command ''slider`` before draggable/clickable objects.
4326
  @ drag and drop may be combined with rotation slider<br>for example an arrow rotated by a slider may be placed anywhere (drag&drop)<br><code>size 300,300<br>xrange -5,5<br>yrange -5,5<br>grid 1,1,grey<br>linewidth 3<br>drag xy<br>fillcolor orange<br>strokecolor blue<br>slider 0,2*pi,250,30,angle degrees,Rotate arrow<br>arrow 2,2,5,5,8,red</code><br>note: except a combination 'drag' and 'slider' for command 'latex, katex, mathml, html, obabel'
4327
  @ no slider for a math function, these can be traced using command ''trace_jscurve some_function_in_x``
4328
  @ a slider will affect all draggable objects after the ''slider`` command...<br>and can be used to group translate / rotate several objects...<br>until a next ''slider`` or keyword ''killslider``
4329
  @ amount of sliders is not limited.
4330
  @ a slider can not be set ''snaptogrid`` or other ''snapto*`` : you may always use 'drag xy' in combination with the slider objects
4331
  @ <code>javascript:read_dragdrop();</code> will return an array with ''object_number:slider_value``
4332
  @ every draggable object may have its own slider (no limit in amount of sliders)
4333
  @ label: some slider text. <br>Note: on <a target='new' href='https://katex.org'>KaTeX</a> enabled wims, TeX produced by wims command ''mathmlmath``, is allowed.
4334
  @ use fillcolor for slider controlkey
4335
  @ use strokecolor for slider bar
4336
  @ use fontfamily / fontcolor to set used fonts
4337
  @ use opacity (only fill opacity will be used) to set transparency
4338
  @ the slider canvas will be added to the ''tooltip div``: so incompatible with command tooltip ; setlimits etc
4339
  @%slider_x_y_angle%%size 300,300%xrange -5,5%yrange -5,5%grid 1,1,grey%linewidth 3%fillcolor orange%strokecolor blue%slider 0,2*pi,300,30,angle active degrees,Rotate arrow%arrow 0,0,4.5,0,8,red%killslider%opacity 200,100%slider -2,2,300,30,x active,move blue rectangle%frect -4,4,1,-1,blue%killslider%linewidth 2%slider -2,2,300,30,y,move green rectangle%frect -4,4,1,-1,green
4340
  @%slider_click%%size 300,300%xrange -6,6%yrange -6,6%grid 1,1,grey%linewidth 2%slider 0,2*pi,300,28,angle degree, name%fillcolor lightgreen%#CLICK ON THE OBJECTS TO ACTIVATE%opacity 255,30%ftriangle 2,2,-2,2,0,0,red%ftriangle -2,2,-2,-2,0,0,blue%ftriangle -2,-2,2,-2,0,0,green%ftriangle 2,-2,2,2,0,0,orange%rotationcenter 0,0%frect -2,2,2,-2,black
4341
  @%slider_active%%size 300,300%xrange -6,6%yrange -6,6%grid 1,1,grey%linewidth 1%slider 0,2*pi,300,28,angle degree active, name%fillcolor lightgreen%opacity 255,30%ftriangle 2,2,-2,2,0,0,red%ftriangle -2,2,-2,-2,0,0,blue%ftriangle -2,-2,2,-2,0,0,green%ftriangle 2,-2,2,2,0,0,orange%rotationcenter 0,0%frect -2,2,2,-2,black
4342
  @%slider_animate%%size 300,300%xrange -6,6%yrange -6,6%grid 1,1,grey%linewidth 1%slider 0,2*pi,300,28,angle anim active, name%fillcolor lightgreen%opacity 255,30%ftriangle 2,2,-2,2,0,0,red%ftriangle -2,2,-2,-2,0,0,blue%ftriangle -2,-2,2,-2,0,0,green%ftriangle 2,-2,2,2,0,0,orange%rotationcenter 0,0%frect -2,2,2,-2,black
4343
  @%slider_html_image%%size 400,400%xrange -6,6%yrange -6,6%bgcolor white%grid 1,1,grey%linewidth 1%slider 0,2*pi,300,28,angle active degree,%centered%html 0,0,<img src="gifs/domains/sciences/flasks.svg" width="100px" height="100px">
4344
  */
4345
          js_function[INTERACTIVE] = 1;
4346
          int_data[2] = 0; /* --> show_display = 0; */
4347
          for(i=0; i<6 ; i++){
4348
            switch(i){
4349
              case 0: double_data[0] = get_real(infile,0);break; /* start value */
4350
              case 1: double_data[1] = get_real(infile,0);break; /* end value */
4351
              case 2: int_data[0] = (int)(get_real(infile,0));break; /* width */
4352
              case 3: int_data[1] = (int)(get_real(infile,0));break; /* height */
4353
              case 4: temp = get_string_argument(infile,0); /* type: x,y,angle */
4354
                if( strstr(temp,"displ")!=0 ||  strstr(temp,"deg")!=0 || strstr(temp,"rad")!=0 ){int_data[5] = 1; }else{int_data[5] = 0;}
4355
                if(strstr(temp,"anim")!= 0){int_data[3] = 1;}else{int_data[3] = 0;}
4356
                if(strstr(temp,"active")!= 0){onclick = 4;}else{onclick=0;}
4357
                if(strstr(temp,"angle")!= 0){slider_type="R";if( strstr(temp,"rad")!= 0){int_data[2] = 3;}if( strstr(temp,"deg")!= 0){int_data[2] = 4;}}
4358
                else
4359
                  if(strstr(temp,"xy") != 0){slider_type = "XY";if( strstr(temp,"disp")!= 0){int_data[2] = 5;}}
4360
                    else
4361
                      if(strstr(temp,"x") != 0){slider_type = "X";if( strstr(temp,"disp")!= 0){int_data[2] = 1;}}
4362
                      else
4363
                        if(strstr(temp,"y") != 0){slider_type = "Y";if( strstr(temp,"disp")!= 0){int_data[2] = 2;}}
4364
                          else
4365
                            canvas_error("slider can be of type: x,y,angle,fun_x:fun_y");
4366
                  break;
4367
                case 5: temp = get_string_argument(infile,1); if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\""," ");}
4368
        /* slider label : in case of latex/mathmlmath we need to remove the extra " */
4369
              break;
4370
            }
4371
          }
4372
          if(use_slider == -1 ){ /* add once */
4373
            add_slider(int_data[3]);
4374
            if(int_data[5] == 1 ){add_slider_display(precision,font_size,font_color,stroke_opacity);}
4375
          }
4376
          use_slider++;
4377
          if(int_data[3] == 0){\
18557 bpr 4378
 
4379
            tmp_buffer=my_newmem(MAX_BUFFER);
18570 bpr 4380
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"slider%d = new slider(\"%s\",\"%s\",%d,%d,%d,%d,\"%s\",\"%s\",[%f,%f],%f,%f,'%s',%d);\n",use_slider,slider_type,temp,use_slider,int_data[0],int_data[1],line_width,fill_color,stroke_color,fill_opacity,stroke_opacity,double_data[0],double_data[1],font_family,int_data[2]));
18552 bpr 4381
          }else{
18557 bpr 4382
 
18552 bpr 4383
            add_slider(int_data[3]);/* use only once !! */
18557 bpr 4384
            tmp_buffer=my_newmem(MAX_BUFFER);
18570 bpr 4385
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"slider%d = new animslider(\"%s\",\"%s\",%d,%d,%d,%d,\"%s\",\"%s\",[%f,%f],%f,%f,'%s',%d);\n",use_slider,slider_type,temp,use_slider,int_data[0],int_data[1],line_width,fill_color,stroke_color,fill_opacity,stroke_opacity,double_data[0],double_data[1],font_family,int_data[2]));
18552 bpr 4386
          }
4387
          add_to_buffer(tmp_buffer);
4388
          fprintf(js_include_file,"var slider%d;",use_slider);
4389
          use_dragstuff = 2;
4390
//      dragstuff[22] = 1; /* dragstuff switch no 22 is a slider...*/
4391
          if(onclick != 4 ){ js_function[INTERACTIVE] = 1; }/* no need to click on object to use slider... */
4392
      //js_function[JS_ROTATE_MOUSE] = 1;
4393
          c = 0;
4394
          for(i=last_slider;i<=use_slider;i++){
4395
            int_data[c] = i; c++;
4396
          }
4397
          my_sliders = data2js_array(int_data,use_slider - last_slider+1);
4398
          break;
4399
        case SGRAPH:
4400
  /*
18556 bpr 4401
  @ sgraph xstart,ystart,xmajor,ymajor,xminor,yminor,majorgrid_color,minorgrid_color
4402
  @ primitive implementation of a ''broken scale`` graph...
4403
  @ not very versatile: only usable in combination with userdraw <br>eg no other objects will obey this "coordinate system"<br>if you want to place an object into this coordinate system, be aware that 10% or 20% of xsize and/or ysize is ''lost``.<br>Use these "formulas" to recalculate the virtual coordinates:<br>factor=0.8 in case xstart != xmin (or ystart != ymin)<br>factor=0.9 in case xstart = xmin (or ystart = ymin)<br>px_x_point = ((factor*xsize)/(xmax - xstart))*(x_point - xmax)+xsize<br>x_recalculated = px*(xmax - xmin)/xsize + $xmin<br>px_y_point = -1*factor*y_point*ysize/(ymax - ystart) + ymax*factor*ysize/(ymax - ystart)<br>y_recalculated = ymax - py*(ymax - ymin)/ysize<br>
4404
  @%sgraph%size 400,400%xrange 0,10000%yrange 0,100%sgraph 9000,50,100,10,4,4,grey,blue%userinput_xy%linewidth 2%userdraw segments,red%precision 0%mouse blue,22
18552 bpr 4405
  */
4406
            js_function[DRAW_SGRAPH] = 1;
4407
            for(i = 0 ; i < 8 ;i++){
4408
              switch(i){
4409
                case 0:double_data[0] = get_real(infile,0);break;
4410
                case 1:double_data[1] = get_real(infile,0);break;
4411
                case 2:double_data[2] = get_real(infile,0);break;
4412
                case 3:double_data[3] = get_real(infile,0);break;
4413
                case 4:int_data[0] = (int)(get_real(infile,0));break;
4414
                case 5:int_data[1] = (int)(get_real(infile,0));break;
4415
                case 6:stroke_color = get_color(infile,0);break;
4416
                case 7:font_color = get_color(infile,1);
18557 bpr 4417
                tmp_buffer=my_newmem(MAX_BUFFER);
4418
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "xstart = %f;\n ystart = %f;\ndraw_sgraph(%d,%d,%f,%f,%d,%d,\"%s\",\"%s\",\"%s\",%f,%d);\n", double_data[0],double_data[1],GRID_CANVAS,precision,double_data[2],double_data[3],int_data[0],int_data[1],stroke_color,font_color,font_family,stroke_opacity,font_size));
18552 bpr 4419
                add_to_buffer(tmp_buffer);
4420
                break;
4421
                default:break;
4422
              }
4423
            }
4424
      /* sgraph(canvas_type,precision,xmajor,ymajor,xminor,yminor,majorcolor,minorcolor,fontfamily,opacity)*/
4425
          break;
4426
        case SNAPTOFUNCTION:
4427
  /*
4428
  @ snaptofunction some_function_in_x,some_funtion_in_y
4429
  @ alternative: snaptofun
4430
  @ the next object will snap to the calculated values
4431
  @ note: snaptofun is probably not really useful feature...
4432
  @ if you want only modification of y-values,just use: <code>snaptofunction x,5*sin(1/y)</code>
4433
  @ if you want only modification of x-values,just use: <code>snaptofunction 5*sin(1/x),y</code>
4434
  @ for now only one instance of ''snaptofunction`` is allowed
4435
  @ use rawmath on your functions: no validity checking is done by wims !
4436
  @ note: switching x and y coordinates? <code>snaptofunction y,x</code>
4437
  @%snaptofunction_1%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 100%snaptofunction x,5*sin(x)%linewidth 3%crosshairsize 6%userdraw crosshairs,red%linewidth 2%curve blue,5*sin(x)%xunit = x-value%display x,blue,22
4438
  @%snaptofunction_2%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 100%snaptofunction y^2-9,y%#snaptofunction y^2-9,abs(y)%linewidth 3%crosshairsize 6%userdraw crosshairs,red%linewidth 2%curve blue,sqrt(x+9)%curve blue,-1*sqrt(x+9)%yunit = y-value%display y,blue,22
4439
  */
4440
          temp = get_string_argument(infile,0);
4441
          use_snap = 2;
4442
          use_snap = 5;
4443
          js_function[JS_MATH] = 1;
4444
          fprintf(js_include_file,"var snap_fun = {x:to_js_math('%s'),y:to_js_math('%s')};function snap_to_fun(px,py){ var x = px2x(px); var y = px2y(py); return [ x2px(eval(snap_fun.x)) , y2px(eval(snap_fun.y)) ];};",temp,get_string(infile,1));
4445
          break;
4446
        case SNAPTOPOINTS:
4447
  /*
4448
  @ snaptopoints x1,y1,x2,y2,x3,y3....
4449
  @ a userdraw object will snap to these points.
18572 bpr 4450
  @ the array size (e.g. the number of points) of command ''snaptopoints`` is limited by constant MAX_INT (canvasdraw.h)<br>this command may be repeated multiple times (no limit) to add points
18552 bpr 4451
  @ a draggable object (use command ''drag x|y|xy``) will snap to the closed of these points when dragged (mouseup)
4452
  @ other options: use keyword ''snaptogrid``, ''xsnaptogrid`` or ''ysnaptogrid``
18616 bpr 4453
  @%snaptopoints_1%size 400,400%xrange -5,5%yrange -5,5%snaptopoints -1,-3,-1,-2,-1,0,-1,1,-1,2,-1,3,1,-3,1,-2,1,-1,1,0,1,1,1,2,1,3%linewidth 2%points red,-1,-3,-1,-2,-1,0,-1,1,-1,2,-1,3,1,-3,1,-2,1,-1,1,0,1,1,1,2,1,3%userdraw arrows,red
4454
  @%snaptopoints_2%size 400,400%xrange -5,5%yrange -5,5%snaptopoints -1,-3,-1,-2,-1,0,-1,1,-1,2,-1,3,1,-3,1,-2,1,-1,1,0,1,1,1,2,1,3%linewidth 3%%points blue,-1,-3,-1,-2,-1,0,-1,1,-1,2,-1,3,1,-3,1,-2,1,-1,1,0,1,1,1,2,1,3%drag xy%ftriangle -4,0,-2,3,0,0,red
18552 bpr 4455
  */
4456
          i = 0;
4457
          while( ! done ){     /* get next item until EOL*/
4458
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
4459
            if(i%2 == 0 ){
4460
              double_data[i] = get_real(infile,0); /* x */
4461
            }
4462
            else {
4463
              double_data[i] = get_real(infile,1); /* y */
4464
            }
4465
            i++;
4466
          }
4467
          decimals = find_number_of_digits(precision);
4468
      /* NEED AN EXTRA COUNTER VARIABLE FOR MORE THAN 2 CALLS */
4469
          fprintf(js_include_file,"if( temp_push_array === 'undefined' ){var temp_push_array;};if( points_to_snap_on === 'undefined' ){var points_to_snap_on;};var temp_push_array = [%s];\n",double_xy2js_array(double_data,i,decimals));
4470
          if( snap_to_points_cnt == 0 ){
4471
            fprintf(js_include_file,"points_to_snap_on = temp_push_array;function find_min_diff(x,y,X,Y){var diff = 100000000;var chk;var idx = 0;var p = 0;while(X[p] != null){chk = distance(x,y,X[p],Y[p]);if( chk  < diff ){ diff = chk; idx = p;};p++;};return idx;};function snap_to_points(x,y){x = px2x(x); y = px2y(y);var xpoints = points_to_snap_on[0];var ypoints = points_to_snap_on[1];var idx = find_min_diff(x,y,xpoints,ypoints);x = xpoints[idx];y = ypoints[idx];return [x2px(x),y2px(y)];};");
4472
          }else{
4473
            fprintf(js_include_file,"points_to_snap_on[0].push.apply(points_to_snap_on[0],temp_push_array[0]);points_to_snap_on[1].push.apply(points_to_snap_on[1],temp_push_array[1]);");
4474
          }
4475
          snap_to_points_cnt = 1; /* do not repeat including the js-functions...just once*/
4476
          use_snap = 4;
4477
          break;
4478
        case SNAPTOGRID:
4479
  /*
18556 bpr 4480
  @ snaptogrid
4481
  @ keyword (no arguments required)
4482
  @ a draggable object (use command ''drag x|y|xy``) will snap to the given grid when dragged (mouseup)
4483
  @ in case of userdraw the drawn points will snap to xmajor / ymajor grid
4484
  @ if no grid is defined, points will snap to every integer xrange/yrange value. (eg snap_x=1,snap_y=1)
4485
  @ if you do not want a visible grid, but you only want a ''snaptogrid`` with some value...define this grid with opacity 0.
4486
  @ if xminor / yminor is defined,(use keyword ''axis`` to activate the minor steps) the drawing will snap to xminor and yminor<br>use only even dividers in x/y-minor...for example <code>snaptogrid<br>axis<br>grid 2,1,grey,4,4,7,red</code> will snap on x=0, x=0.5, x=1, x=1.5 .... will snap on y=0, y=0.25 y=0.5 y=0.75 ...
4487
  @%snaptogrid_1%size 400,400%xrange -5,5%yrange -5,5%axis%axisnumbering%precision 1%grid 1,1,grey,2,2,6,grey%linewidth 2%snaptogrid%userdraw crosshairs,blue%mouse red,22
4488
  @%snaptogrid_2%size 400,400%xrange -5,5%yrange -5,5%axis%axisnumbering%precision 1%grid 1,1,grey,4,1,6,grey%linewidth 1%snaptogrid%userdraw crosshairs,blue%mouse red,22
18552 bpr 4489
  */
4490
          use_snap = 1;
4491
          break;
4492
        case SQUARE:
4493
  /*
4494
  @ square x,y,side (px),color
4495
  @ draw a square with left top corner (x:y) with side ''side`` in color 'color'
4496
  @ use command <code>fsquare x,y,side,color</code> for a filled square
4497
  @ use command/keyword <a href='#filled'>filled</a> before command <code>square x,y,side,color</code>
4498
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
4499
  @%square%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%filled%fillcolor blue%square 0,0,120,green
4500
  */
4501
          for(i=0;i<4;i++){
4502
            switch(i){
4503
            case 0:double_data[0] = get_real(infile,0);break; /* x1-values */
4504
            case 1:double_data[1] = get_real(infile,0);break; /* y1-values */
4505
            case 2:double_data[2] = get_real(infile,0);break; /* width in px */
4506
            case 3:stroke_color = get_color(infile,1);/* name or hex color */
4507
              decimals = find_number_of_digits(precision);
4508
              double_data[3] = double_data[0] + (xmax - xmin)*double_data[2]/xsize;
4509
              double_data[4] = double_data[1] + -1*(ymax - ymin)*double_data[2]/ysize;
4510
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4511
              tmp_buffer=my_newmem(MAX_BUFFER);
4512
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,1,[%.*f,%.*f,%.*f,%.*f],[%.*f,%.*f,%.*f,%.*f],[%d],[%d],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[3],decimals,double_data[3],decimals,double_data[0],decimals,double_data[1],decimals,double_data[1],decimals,double_data[4],decimals,double_data[4],line_width,line_width,line_width,stroke_color,stroke_opacity,stroke_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 4513
              add_to_buffer(tmp_buffer);
4514
              if(onclick != 0){object_cnt++;}/* object_cnt++; */
4515
              reset();break;
4516
            default: break;
4517
            }
4518
          }
4519
          dragstuff[1] = 1;
4520
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4521
          break;
4522
        case STATUS:
4523
  /*
4524
  @ status
4525
  @ keyword
4526
  @ alernative: nostatus
4527
  @ used to override the effects of ''status=done`` in wims (answer.phtml)
4528
  @ affects ''readonly`` in inputfields / textareas in canvasimage and all userdraw based commands
4529
  @ e.g.: if keyword ''status`` is set, the pupil will be able to modify the canvas when the ''wims &#36;status variable`` is set to ''done``
4530
  */
11806 schaersvoo 4531
 
18552 bpr 4532
          fprintf(js_include_file,"\nwims_status=\"waiting\";\n");
4533
          break;
4534
        case STRING:
4535
  /*
18556 bpr 4536
  @ string color,x,y,the text string
4537
  @ may be set ''onclick`` or ''drag xy``
4538
  @ note: when set ''onclick``, use an extra command ''fontsize`` (default: fontsize=12) to adjust the size of the clicked text-string<br>note: a clicked text string will be hardcoded : fontsize+10 in the font family courier
18572 bpr 4539
  @ unicode supported: <code>string red,0,0,\\u2232</code><br> See <a target='new' href='https://en.wikipedia.org/wiki/Mathematical_operators_and_symbols_in_Unicode'>https://en.wikipedia.org/wiki/Mathematical_operators_and_symbols_in_Unicode</a><br> See <a  target='new' href='https://en.wikipedia.org/wiki/Greek_script_in_Unicode'>https://en.wikipedia.org/wiki/Greek_script_in_Unicode</a>
18556 bpr 4540
  @ use a command like <code>fontfamily italic 24px Arial</code> to set fonts on browser that support font change
4541
  @ super / sub script is supported, using '<b>_</b>' and '<b>^</b>' <br>The font family for the sub/sup string will be Helvetica e.g. your font family settings will be ignored <br>to force end the subscript/supscript, use an extra space...see example:
4542
  @%string_sup_sub%size 400,400%xrange -6,6%yrange -6,6%fontfamily 22px Arial%# you can use a single space for separation in formula...%# use double space to create new word%string blue,-5,3,H_3O^+ + OH^-  \\u2192 2H_2O%# you can use a single space for separation in formula...%string red,-5,-3,H_3 O^+ + OH^\\u2212  \\u2192 2H_2 O%
4543
  @%string%size 400,400%xrange -10,10%yrange -10,10%fontfamily 14px Arial%crosshair -3,-3,red%crosshair 3,3,blue%string red,-3,-3,Hello World%fontfamily Italic 18px Arial%string red,3,3,Hello World%fontfamily 22pt STIX%string black,-10,8,\\u03B1 \\u03B2 \\u03B3 \\u03B4 \\u03B5 \\u03B6 \\u03B7 \\u03B8 \\u03B9 \\u03BA \\u03BB \\u03BC \\u03BD \\u03BE \\u03BF
18552 bpr 4544
  */
4545
          if( use_rotate == TRUE  ){js_function[JS_ROTATE_MOUSE] = 1; }
4546
          dragstuff[14] = 1;
4547
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4548
          for(i=0;i<5;i++){
4549
            switch(i){
4550
              case 0: stroke_color = get_color(infile,0);break;/* name or hex color */
4551
              case 1: double_data[0] = get_real(infile,0);break; /* x in xrange*/
4552
              case 2: double_data[1] = get_real(infile,0);break; /* y in yrange*/
4553
              case 3: decimals = find_number_of_digits(precision);
4554
                if(use_affine == TRUE ){ transform(2,2);}
4555
        /* rotate is done by HTML5/CANVAS context rotation */
4556
                temp = get_string_argument(infile,1);
4557
                if(strstr(temp,"_") != NULL || strstr(temp,"^") != NULL){js_function[DRAW_SUBSUP] = 1;}
4558
                decimals = find_number_of_digits(precision);
4559
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4560
                tmp_buffer=my_newmem(MAX_BUFFER);
4561
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,14,[%.*f],[%.*f],[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[1],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,0,0,0,use_rotate,angle,temp,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 4562
                add_to_buffer(tmp_buffer);
4563
                if(onclick != 0){object_cnt++;}
4564
      //onclick = 0;
4565
      //use_offset = 0;
4566
                reset();
4567
                break;
4568
              default:break;
4569
            }
4570
          }
4571
          break;
4572
        case STRINGUP:
4573
  /*
18556 bpr 4574
  @ stringup color,x,y,rotation_degrees,the text string
4575
  @ may be set ''onclick`` or ''drag xy``
4576
  @ note: when set ''onclick``, use an extra command ''fontsize`` (default: fontsize=12) to adjust the size of the clicked text-string<br>note: a clicked text string will be hardcoded : fontsize+10 in the font family courier
4577
  @ unicode supported: <code>stringup red,0,0,45,\\u2232</code>
4578
  @ use a command like <code>fontfamily bold 34px Courier</code> to set fonts on browser that support font change
4579
  @ you could use keyword <a href='#yoffset'>yoffset</a> to -sometimes- do a small correction of text placement under/above a point (e.g. text &amp; point have thesame coordinates)
18572 bpr 4580
  @ note: no need to ''killrotate`` after ''stringup``<br><code>onclick<br>rotate 45<br>string red,0,0,AAAAAA<br>killrotate<br>string red,4,4,BBBBBB</code><br>is identical with:<br><code>onclick<br>stringup red,0,0,45,AAAAAA<br>string red,4,4,BBBBBB</code>
18556 bpr 4581
  @ super / sub script is supported, using '<b>_</b>' and '<b>^</b>' <br>to end the subscript/supscript, use an extra space...see example:
4582
  @%stringup_sub_sup%size 400,400%xrange -6,6%yrange -6,6%fontfamily 22px Arial%# use single space for separation in formula...%# use double space to create new word%stringup red,-5,0,45,H_3 O^+ + OH^\\u2212  \\u2192 2H_2 O%
4583
  @%stringup%size 400,400%xrange -10,10%yrange -10,10%fontsize 24%fontfamily 14px Arial%crosshair -3,0,red%crosshair 3,0,blue%onclick%stringup red,-3,0,-90,Hello World%drag xy%stringup red,-3,0,-45,Hello World%stringup red,-3,0,45,Hello World%stringup red,-3,0,90,Hello World%stringup blue,3,0,-90,Hello World%stringup blue,3,0,-45,Hello World%stringup blue,3,0,45,Hello World%stringup blue,3,0,90,Hello World
11806 schaersvoo 4584
 
18552 bpr 4585
  */
4586
      /* html5 canvas rotation is only used for text objects  */
4587
          use_rotate = TRUE ;
4588
          dragstuff[14] = 1;
4589
          js_function[JS_ROTATE_MOUSE] = 1;
4590
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
10953 bpr 4591
 
18552 bpr 4592
          for(i=0;i<6;i++){
4593
            switch(i){
4594
              case 0: stroke_color = get_color(infile,0);break;/* name or hex color */
4595
              case 1: double_data[0] = get_real(infile,0);break; /* x */
4596
              case 2: double_data[1] = get_real(infile,0);break; /* y */
4597
              case 3: angle = get_real(infile,0);break;/* rotation */
4598
              case 4: decimals = find_number_of_digits(precision);
4599
                temp = get_string_argument(infile,1);
4600
                if(strstr(temp,"_") != NULL || strstr(temp,"^") != NULL){js_function[DRAW_SUBSUP] = 1;}
4601
                decimals = find_number_of_digits(precision);
4602
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4603
                tmp_buffer=my_newmem(MAX_BUFFER);
4604
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,14,[%.*f],[%.*f],[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[1],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,0,0,0,use_rotate,angle,temp,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 4605
                add_to_buffer(tmp_buffer);
4606
                if(onclick != 0){object_cnt++;}
4607
                //onclick = 0;
4608
                //use_offset = 0;
4609
                reset();
4610
                break;
4611
              default:break;
4612
            }
4613
          }
4614
          use_rotate = FALSE;
4615
          break;
4616
        case STYLE:
4617
  /*
18556 bpr 4618
  @ highlight color,opacity,linewidth
4619
  @ NOT IMPLEMENTED
4620
  @ use command ''onclick``: when the object receives a userclick it will increase its linewidth
18552 bpr 4621
  */
4622
         break;
4623
        case STROKECOLOR:
4624
  /*
4625
  @ strokecolor colorname or #hex
4626
  @ to be used for commands that do not supply a color argument (like command ''linegraph``)
4627
  */
4628
          stroke_color = get_color(infile,1);
4629
          break;
4630
        case FLY_TEXT:
4631
  /*
4632
  @ text fontcolor,x,y,font,text_string
4633
  @ font may be described by keywords: giant,huge,normal,small,tiny
4634
  @ use command ''fontsize`` to increase base fontsize for these keywords
4635
  @ may be set ''onclick`` or ''drag xy``
4636
  @ backwards compatible with flydraw
4637
  @ unicode supported: text red,0,0,huge,\\u2232
4638
  @ special: use '_' and '^' to imitate html sup/sub, like H_3O^+ + OH^\\u22i2  \\u2192 2H_2 O
4639
  @ much better to use command <a href='#string'>string</a> combined with <a href='#fontfamily'>fontfamily</a> for a more fine grained control over html5 canvas text element
4640
  @ super / sub script is supported, using '<b>_</b>' and '<b>^</b>' <br>to end the subscript/supscript, use an extra space...see <a href='#string'>string </a> command
4641
  @ Avoid mixing old flydraw commands ''text``, ''textup`` with new canvasdraw commands ''string``, ''stringup``. If the fontfamily was set completely like <code>fontfamily italic 24px Arial</code>. In that case reset ''fontfamily`` to something lke ''fontfamily Arial`` before the old flydraw commands.
4642
  @%text%size 400,400%xrange -10,10%yrange -10,10%fontsize 14%onclick%drag xy%text green,-4,-4,small,Hello World%drag xy%text red,-4,-2,large,Hello World%drag xy%text blue,-4,0,huge,Hello World%drag xy%text green,-4,3,giant,Hello World%drag xy
4643
  */
4644
        for(i = 0; i < 5 ;i++){
4645
          switch(i){
4646
            case 0: stroke_color = get_color(infile,0);break;/* font_color == stroke_color name or hex color */
4647
            case 1: double_data[0] = get_real(infile,0);break; /* x */
4648
            case 2: double_data[1] = get_real(infile,0);break; /* y */
4649
            case 3: fly_font = get_string_argument(infile,0);
4650
              if(strcmp(fly_font,"giant") == 0){
4651
                fly_font_size = (int)(font_size + 24);
4652
              }
4653
              else {
4654
                if(strcmp(fly_font,"huge") == 0){
4655
                  fly_font_size = (int)(font_size + 14);
4656
                }
4657
                else {
4658
                  if(strcmp(fly_font,"large") == 0){
4659
                    fly_font_size = (int)(font_size + 6);
4660
                  }
4661
                  else {
4662
                    if(strcmp(fly_font,"small") == 0){
4663
                      fly_font_size = (int)(font_size - 4);
4664
                      if(fly_font_size<0){fly_font_size = 8;}
4665
                    }
4666
                  }
4667
                }
4668
              }
4669
              break;
4670
            case 4:
4671
              temp = get_string_argument(infile,1);
4672
              if(strstr(temp,"_") != NULL || strstr(temp,"^") != NULL){js_function[DRAW_SUBSUP] = 1;}
4673
              decimals = find_number_of_digits(precision);
4674
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
4675
              if(use_affine == TRUE ){ transform(2,2);}
18557 bpr 4676
              tmp_buffer=my_newmem(MAX_BUFFER);
4677
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,14,[%.*f],[%.*f],[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%f,\"%s\",%d,%s,%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[1],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,0,0,0,use_rotate,angle,temp,fly_font_size,"null",my_sliders,rotation_center,use_offset));
18552 bpr 4678
              add_to_buffer(tmp_buffer);
4679
              if(onclick != 0){object_cnt++;}
4680
              reset();
4681
              break;
4682
            default:break;
4683
            }
4684
          }
4685
          dragstuff[14] = 1;
4686
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4687
          break;
4688
        case TEXTAREA:
4689
  /*
18556 bpr 4690
  @ textarea x,y,cols,rows,readonly,value
4691
  @ may be further controlled by <a href="#css">css</a>
4692
  @ if ''&#36;status=done`` (e.g. in answer.phtml) the inputfield will be cleared and set readonly. Override this by keyword <a href="#status">status</a>.
4693
  @ if mathml inputfields are present and / or some userdraw is performed, these data will <b>not</b> be send as well (<code>javascript:read_canvas();</code>)
4694
  @ keyword ''xoffset | centered`` is not active for command ''textarea``
4695
  @%textarea%size 400,400%xrange -10,10%yrange -10,10%css color:red;background-color:lightblue;font-size:14px;text-align:center%textarea -3,-2,6,3,1,?%css color:blue;background-color:yellow;font-size:14px;text-align:center%textarea 0,-2,8,2,1,?
18552 bpr 4696
  */
4697
          js_function[DRAW_TEXTAREAS] = 1;
4698
          for(i = 0 ; i<6;i++){
4699
            switch(i){
4700
              case 0: int_data[0]=x2px(get_real(infile,0));break; /* x in px */
4701
              case 1: int_data[1]=y2px(get_real(infile,0));break; /* y in px */
4702
              case 2: int_data[2]=abs( (int)(get_real(infile,0)));break;/* cols */
4703
              case 3: int_data[3]=abs( (int)(get_real(infile,0)));break;/* rows */
4704
              case 4: if( get_real(infile,1) >0){int_data[4] = 1;}else{int_data[3] = 0;};break; /* readonly */
4705
              case 5: temp = get_string_argument(infile,1);
18557 bpr 4706
                tmp_buffer=my_newmem(MAX_BUFFER);
4707
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_textareas(%d,%d,%d,%d,%d,%d,%d,\"%s\",\"%s\");\n",canvas_root_id,input_cnt,int_data[0],int_data[1],int_data[2],int_data[3],int_data[4],css_class,temp));
18552 bpr 4708
                add_to_buffer(tmp_buffer);
4709
                input_cnt++;break;
4710
              default: break;
4711
            }
4712
          }
4713
          if(reply_format == 0 ){reply_format = 15;}
4714
          reset();
4715
          break;
4716
        case TEXTFILL:
4717
  /*
4718
  @ textfill x0,y0,color,some_text
4719
  @ x0,y0 in xrange / yrange
4720
  @ color will be used for the font color
4721
  @ use command <a href="#fontfamily">fontfamily</a> to set font type and size
4722
  @ there is also a command <a href="#userdraw">userdraw textfill,color,some_text</a>
4723
  @%textfill%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%fontfamily 24pt Arial%circles red,0,0,3,3,3,6%textfill 4,4,blue,HELLO WORLD
4724
  */
11806 schaersvoo 4725
 
18552 bpr 4726
          js_function[DRAW_TEXTFILL] = 1;
4727
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
4728
            js_function[DRAW_FILLTOBORDER] = 1;
4729
            add_js_filltoborder(canvas_type);
4730
          }
4731
          decimals = find_number_of_digits(precision);
4732
          for(i=0;i<4;i++){
4733
            switch(i){
4734
              case 0: double_data[0] = get_real(infile,0); break; /* x in px */
4735
              case 1: double_data[1] = get_real(infile,0); break; /* y in py */
4736
              case 2: font_color = get_color(infile,0); break;
4737
              case 3: temp = get_string(infile,1);
18557 bpr 4738
                tmp_buffer=my_newmem(MAX_BUFFER);
4739
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_textfill(%d,%*.f,%*.f,'%s','%s',%d,%d,'%s',false); ",FILL_CANVAS+fill_cnt,decimals,double_data[0],decimals,double_data[1],font_color,font_family,xsize,ysize,temp));
18552 bpr 4740
                add_to_buffer(tmp_buffer);
4741
                fill_cnt++;
4742
                break;
4743
              default:break;
4744
            }
4745
          }
4746
          reset();
4747
          break;
4748
        case FLY_TEXTUP:
4749
  /*
18556 bpr 4750
  @ textup fontcolor,x,y,font,text_string
4751
  @ can <b>not</b> be set ''onclick`` or ''drag xy`` (because of translaton matrix...mouse incompatible)
4752
  @ font may be described by keywords: giant,huge,normal,small,tiny
4753
  @ use command ''fontsize`` to increase base fontsize for the keywords
4754
  @ backwards compatible with flydraw
4755
  @ unicode supported: textup red,0,0,huge,\\u2232
4756
  @ use command ''stringup`` and ''fontfamily`` for a more fine grained control over html5 canvas text element
4757
  @ Avoid mixing old flydraw commands ''text``, ''textup`` with new canvasdraw commands ''string``; ''stringup``. If the fontfamily was set completely like <code>fontfamily italic 24px Arial</code>. In that case reset ''fontfamily`` to something like ''fontfamily Arial`` before the old flydraw commands.
18552 bpr 4758
  */
4759
          js_function[DRAW_TEXTS] = 1;
4760
          for(i = 0; i<5 ;i++){
4761
            switch(i){
4762
              case 0: font_color = get_color(infile,0);break;/* name or hex color */
4763
              case 1: int_data[0] = x2px(get_real(infile,0));break; /* x */
4764
              case 2: int_data[1] = y2px(get_real(infile,0));break; /* y */
4765
              case 3: fly_font = get_string_argument(infile,0);
4766
                if(strcmp(fly_font,"giant") == 0){
4767
                  fly_font_size = (int)(font_size + 24);
4768
                }
4769
                else {
4770
                  if(strcmp(fly_font,"huge") == 0){
4771
                    fly_font_size = (int)(font_size + 14);
4772
                  }
4773
                  else {
4774
                    if(strcmp(fly_font,"large") == 0){
4775
                      fly_font_size = (int)(font_size + 6);
4776
                    }
4777
                    else {
4778
                      if(strcmp(fly_font,"small") == 0){
4779
                        fly_font_size = (int)(font_size - 4);
4780
                        if(fly_font_size<0){fly_font_size = 8;}
4781
                      }
4782
                    }
4783
                  }
4784
                }
4785
                break;
4786
              case 4:
4787
                decimals = find_number_of_digits(precision);
4788
                temp = get_string_argument(infile,1);
4789
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4790
                tmp_buffer=my_newmem(MAX_BUFFER);
4791
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_text(%d,%d,%d,%d,\"%s\",\"%s\",%.2f,90,\"%s\",%d,%.2f,%d);\n",STATIC_CANVAS,int_data[0],int_data[1],fly_font_size,"null",font_color,stroke_opacity,temp,use_rotate,angle,use_offset));
18552 bpr 4792
                add_to_buffer(tmp_buffer);
4793
                reset();
4794
        //use_offset = 0;
4795
                break;
4796
              default:break;
4797
            }
4798
          }
4799
          break;
4800
        case TRACE_JSCURVE:
4801
  /*
18556 bpr 4802
  @ trace_jscurve some_math_function
4803
  @ will use a crosshair to trace the jsmath curve
4804
  @ two inputfields will display the current x/y-values (numerical evaluation by javascript)
4805
  @ default labels ''x`` and ''y``; use commands ''xlabel some_x_axis_name`` and ''ylabel some_y_axis_name`` to customize the labels for the input fields
4806
  @ use commands fontsize and css to format the fonts for labels and inputfields.
4807
  @ use commands ''linewidth, strokecolor, crosshairsize`` to adjust the corsshair.
4808
  @ the client browser will convert your math function to javascript math.<br>use parenthesis and rawmath: use 2*x instead of 2x etc etc no check is done on the validity of your function and/or syntax (use error console to debug any errors...)
4809
  @ be aware that the formulas of the plotted function(s) can be found in the page javascript source
4810
  @%trace_jscurve%size 400,400%xrange -10,10%yrange -10,10%precision 0%axis%axisnumbering%grid 2,2,grey,2,2,5,gray%recision 100%css color:blue;%linewidth 4%crosshairsize 8%trace_jscurve 5*sin(0.1*x^2)%linewidth 1%jsplot red,5*sin(0.1*x^2)%#only one curve can be traced
18552 bpr 4811
  */
4812
          js_function[INTERACTIVE] = 1;
4813
          js_function[DRAW_CROSSHAIRS] = 1;
4814
          js_function[DRAW_LINES] = 1;
4815
          js_function[JS_MATH] = 1;
4816
          add_trace_js_mouse(TRACE_CANVAS,stroke_color,get_string(infile,1),font_size,stroke_opacity,line_width,crosshair_size,css_class);
4817
          break;
4818
        case TRANGE:
4819
  /*
4820
  @ trange tmin,tmax
4821
  @ alternative: ranget
4822
  @ default -2,2
4823
  */
4824
          use_parametric = TRUE;
4825
          for(i = 0 ; i<2; i++){
4826
            switch(i){
4827
              case 0: tmin = get_real(infile,0);break;
4828
              case 1: tmax = get_real(infile,1);break;
4829
              default: break;
4830
            }
4831
          }
4832
          if(tmin >= tmax ){canvas_error(" trange is not OK: tmin &lt; tmax!\n");}
4833
          break;
4834
        case TRANSLATION:
4835
  /*
18556 bpr 4836
  @ translation tx,ty
4837
  @ alternative: translate
4838
  @ will translate the next objects tx in xrange and ty in yrange
4839
  @ use command ''killtranstation`` to end the command
18569 bpr 4840
  @%translation%size 400,400%xrange -10,10%yrange -10,10%linewidth 1%fillpattern grid%triangle -6,6,8,6,5,1,blue%translation 2,2%ftriangle -6,6,8,6,5,1,red
18552 bpr 4841
  */
4842
          for(i = 0 ; i<2;i++){
4843
            switch(i){
4844
              case 0: affine_matrix[4] = get_real(infile,0);break;
4845
              case 1: affine_matrix[5] = get_real(infile,1);
4846
                use_affine = TRUE;
4847
      /* the other values affine_matrix[0..3] remain untouched*/
4848
                break;
4849
              default: break;
4850
            }
4851
          }
4852
          break;
4853
        case TRIANGLE:
4854
  /*
18556 bpr 4855
  @ triangle x1,y1,x2,y2,x3,y3,color
4856
  @ use ftriangle or keyword <a href='#filled'>filled</a> for a solid triangle
4857
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
4858
  @%triangle%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%opacity 250,150%drag xy%triangle 0,0,-4,4,6,8,red%drag xy%ftriangle 0,0,-4,-4,6,-8,red%fillpattern grid%drag xy%ftriangle -6,6,8,6,5,1,blue
18552 bpr 4859
  */
4860
          for(i=0;i<7;i++){
4861
            switch(i){
4862
              case 0: double_data[0] = get_real(infile,0);break; /* x */
4863
              case 1: double_data[1] = get_real(infile,0);break; /* y */
4864
              case 2: double_data[2] = get_real(infile,0);break; /* x */
4865
              case 3: double_data[3] = get_real(infile,0);break; /* y */
4866
              case 4: double_data[4] = get_real(infile,0);break; /* x */
4867
              case 5: double_data[5] = get_real(infile,0);break; /* y */
4868
              case 6: stroke_color = get_color(infile,1);/* name or hex color */
4869
                decimals = find_number_of_digits(precision);
18623 bpr 4870
                if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 4871
                if( use_rotate == TRUE ){ rotate(6,angle,rotationcenter,2);}
4872
                if( use_affine == TRUE ){ transform(6,2);}
4873
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4874
                tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 4875
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,5,%s,[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,double_xy2js_array(double_data,6,decimals),line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 4876
                add_to_buffer(tmp_buffer);
4877
                if(onclick != 0){object_cnt++;}
4878
          /* object_cnt++;*/
4879
                reset();
4880
                break;
4881
              default: break;
4882
            }
4883
          }
4884
          dragstuff[5] = 1;
4885
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4886
          break;
4887
        case TRIANGLES:
4888
  /*
18556 bpr 4889
  @ triangles color,x1,y1,x2,y2,x3,y3,...
4890
  @ use ftriangles or keyword <a href='#filled'>filled</a> for solid triangles
4891
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
4892
  @%triangles%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%onclick%triangles red,0,0,-4,4,6,8,0,0,-4,-4,6,-8,-6,6,8,6,5,1%# the same as 3 calls to command triangle
18552 bpr 4893
  */
4894
          stroke_color = get_color(infile,0);/* name or hex color */
18623 bpr 4895
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 4896
          i = 0;
4897
          decimals = find_number_of_digits(precision);
4898
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
4899
          while( ! done ){
4900
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
4901
            double_data[0] = get_real(infile,0); /* x1 */
4902
            double_data[1] = get_real(infile,0); /* y1 */
4903
            double_data[2] = get_real(infile,0); /* x2 */
4904
            double_data[3] = get_real(infile,0); /* y2 */
4905
            double_data[4] = get_real(infile,0); /* x3 */
4906
            double_data[5] = get_real(infile,1); /* y3 */
18557 bpr 4907
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 4908
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,5,%s,[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,double_xy2js_array(double_data,6,decimals),line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 4909
            add_to_buffer(tmp_buffer);
4910
            if(onclick != 0){object_cnt++;}
4911
            i = i + 6;
4912
          }
4913
          reset();
4914
          dragstuff[5] = 1;
4915
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4916
          break;
4917
        case USERBOXPLOT:
4918
  /*
18556 bpr 4919
  @ userboxplot
4920
  @ keyword, no arguments
4921
  @ use before command <a href="#boxplot">boxplot x_or_y,box-height_or_box-width,x_or_y-position</a>
4922
  @ if set, the student will have to calculate "min,Q1,median,Q3,max" and feed these data into the ''draw_boxplot`` function
4923
  @ for example: put the canvas-script into a html element with id='boxplot' and set style='display:none'<br>define a variable called ''student_boxplot`` and fill it with the 5 student-data (from inputfields or something)<br><code>var student_boxplot = new Array(5)<br>function show_boxplot(){<br>student_boxplot[0] = min;<br>student_boxplot[1] = Q1;<br>student_boxplot[2] = median;<br>student_boxplot[3] = Q3;<br>student_boxplot[4] = max;<br>document.getElementById('boxplot').style.display = "block";<br>draw_boxplot(12345,1,2.00,5.00,[0,0,0,0,0],4,"0,0,255",0.78,"255,165,0",0.60,1,0,1,1);<br>};</code><br>In the canvas-script the function draw_boxplot has the following arguments:<br>draw_boxplot=function(canvas_type,xy,hw,cxy,data,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype0,dashtype1)
18552 bpr 4924
  */
4925
          js_function[DRAW_BOXPLOT] = 1;
4926
          fprintf(js_include_file,"var boxplot_source = 3;\n");
4927
          js_function[DRAW_JSBOXPLOT] = 2;
4928
          break;
4929
        case USERBOXPLOTDATA:
4930
  /*
18556 bpr 4931
  @ userboxplotdata
4932
  @ keyword, no arguments
4933
  @ use before command <a href="#boxplot">boxplot x_or_y,box-height_or_box-width,x_or_y-position</a>
4934
  @ if set, the student will have to generate some statistical data. These data should be put in a named array ''student_boxplot_data``
4935
  @ ''min,Q1,median,Q3,max`` are calculated by a js-function and the 'draw_boxplot' function will draw a boxplot.
4936
  @ see command <a href="#userboxplot">userboxplot</a> for calling 'draw_boxplot()'
18552 bpr 4937
  */
4938
          js_function[DRAW_BOXPLOT] = 1;
4939
          fprintf(js_include_file,"var boxplot_source = 2;\n");
4940
          js_function[DRAW_JSBOXPLOT] = 1;
4941
          break;
4942
        case USERDRAW:
4943
  /*
4944
  @ userdraw object_type,color
4945
  @ only a single object_type is allowed.
4946
  @ right mouse click will remove last drawn object.
4947
  @ for multiple different 'userdraw' objects in an exercise, use command <a href="#multidraw">multidraw</a>
18572 bpr 4948
  @ implemented object_type: <ul><li>point</li><li>points</li><li>crosshair</li><li>crosshairs</li><li>line</li><li>lines</li><li>vline</li><li>vlines</li><li>hline</li><li>hlines</li><li>demiline</li><li>demilines</li><li>segment</li><li>segments</li><li>polyline | brokenline</li><li>circle</li><li>circles</li><li>arrow</li><li>arrow2 (double arrow)</li><li>arrows</li><li>arrows2 (double arrows)</li><li>curvedarrow</li><li>curvedarrows</li><li>curvedarrow2</li><li>curvedarrows2</li><li>triangle</li><li>polygon</li><li>poly[3-9] (e.g poly3 ... poly7...poly9</li><li>rect</li><li>roundrect</li><li>rects</li><li>roundrects</li><li>freehandline | path</li><li>freehandlines | paths</li><li>clickfill: fill the clicked area with color<br>multiple areas may be selected <br>multiple colors may be provided using commands <a href='#colorpalette'>colorpalette color1,color2,color3,...</a> use <a href='#replyformat'>replyformat 10</a> for checking the user click color ... reply=x1:y1:color1,x2:y2:color2...<br>attention: this will <b>not</b> work for pattern filling, because the pattern image is only generated once and after creation can not be changed !<br>the opacity of this image on a separate canvas is set to 0.01 and not 0 (!!)...in the ''fill algorithm`` the opacity of the matching pixels is set to 1</li><li>dotfill: fill the clicked area with a dot pattern; use command linewidth to change dot size</li><li>diamondfill: fill the clicked area with a diamond pattern</li><li>hatchfill: fill the clicked area with a hatch pattern</li><li>gridfill: fill the clicked area with a grid pattern</li><li>textfill: fill the clicked area with a repeating string<br>userdraw textfill,blue,some_text<br>use command <a href="#fontfamily">fontfamily</a> to adjust text style and size</li><li>''clickfill | pattern filling`` in general:<br>the clicks may be set <a href="#snaptogrid">snaptogrid</a><br>can be used together with command <a href="#floodfill">floodfill or fill</a><br><b>always</b> use together with command <a href="#clearbutton">clearbutton some_text</a> for removal of all click_colored areas<br>the function read_canvas() will return the click coordinates in the sequence of the user clicks<br>use command <a href="#canvastype">canvastype</a> to fill another canvas (default should be fine: DRAG_CANVAS = 5)</li><li>text <br>an inputfield is provided, unicode allowed. The text is drawn a the mouse click, or if used with command ''userinput inputfield`` also at the given x/y-coordonates</li><li>arc</li><li>arcs</li><li>image<br>only a single "image" of every supported type(*) may be added to canvas window from the surrounding html page.<br>the image should have an 'id' and an onclick handler.<br>(*) supported types are ''svg``,''bitmap``,''p-element``,''div-element`` and ''mathml/tex-code`` with ''\\mmlid{int}``.</li><li>images</li><li>input<br>place a single inputfield on ''canvas`` <br>use commands 'css' for css styling: use command ''linewidth`` for adjusting the input field size (default 1)</li><li>inputs<br>place multiple inputfield: placing inputfields on top of each other is not possible</li><li>function : identical to <a href="#userinput">userinput function</a></li></ul>
18552 bpr 4949
  @ note: mouselisteners are only active if ''&#36;status != done`` (eg only drawing in an active/non-finished exercise) <br> to overrule use command/keyword ''status`` (no arguments required)
4950
  @ note: object_type text: Any string or multiple strings may be placed anywhere on the canvas.<br>Use command ''fontfamily`` to set font
4951
  @ note: object_type polygone: Will be finished (the object is closed) when clicked on the first point of the polygone again.
4952
  @ note: all objects will be removed -after a javascript confirm box- when clicked on an object point with middle or right mouse button (e.g. event.button != 1: all buttons but left)
18572 bpr 4953
  @ use a prefix <a href='#filled'>filled</a> or ''f`` to set fillable objects filled. (fcircles,filledcircles etc)<br> in case of ''fillpattern`` do not use the ''f`` prefix !
18552 bpr 4954
  @ for non solid filling, use command <a href="#fillpattern">fillpattern grid,hatch,diamond,dot</a>
4955
  @ use <a href='#opacity'>opacity int,int</a> and <a href='#fillcolor'>fillcolor color</a> to trigger coloured filling of fillable objects
4956
  @ use command ''dashed`` and/or ''dashtype int,int`` to trigger dashing
4957
  @ use command ''replyformat int`` to control / adjust output formatting of javascript function read_canvas(); (the defaults should be fine...)
4958
  @ may be combined with onclick or drag xy of other components of flyscript objects (although not very useful...)
4959
  @ may be combined with keyword <a href='#userinput_xy'>userinput_xy</a>
4960
  @ may be combined width the <a href='#snaptogrid'>snaptogrid snaptopoints </a> etc, to simplify the checking of the student reply
4961
  @ the cursor may be appropriately styled using command <a href='cursor'>cursor</a>
4962
  @ note: when zooming / panning after a drawing, the drawing will NOT be zoomed / panned...this is a "design" flaw and not a feature <br>To avoid trouble do not use zooming / panning together width userdraw.!<br>use command <a href="#multidraw">multidraw</a> is this is a problem for you...
4963
  @ note: the default replyformat for ''userdraw input(s),color`` used format x1;y1;text1 \n x2;y2;test2 \n x_n;y_n;text_n (e.g. it is not a comma separated array...use ''direct exec`` to test)
4964
  @ note: a special case is ''userdraw image,boguscolor``. Images (bitmap or svg or div) present in the exercise page and the img/svg/div-tag with an unique 'id' and <code>onclick='javascript:place_image_on_canvas(this.id)'</code> can be placed onto the canvas.<br>The ''id`` and (x;y) coordinates will be returned using read_canvas();<br> native MathML, MathJax or KaTeX typesetting may be included in div's.(experiments; wims_modules svn version only!)
4965
  @ note: command <br><code>userdraw function,color</code> is identical to acombination of <code>strokecolor color</code> and <code>userinput function</code><br>
18572 bpr 4966
  @ note: commands :<br><code>multicolors red,green,blue<br>multilabel f(x)=:g(x)=:h(x)=<br>userdraw functions3,color</code><br>is identical to commands :<br><code>functionlabel f(x)=:p(x)=:w(x)=<br>strokecolor red<br>userinput function <br>strokecolor green<br>userinput function <br>strokecolor blue<br>userinput function</code>
18552 bpr 4967
  @%userdraw_canvastype_a%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%grid 2,2,grey%replyformat 10%colorpalette orange,yellow,red,green,lightgreen,blue,lightblue,cyan%canvastype 4%userdraw clickfill,blue%clearbutton REMOVE LAST RECTANGLE
4968
  @%userdraw_canvastype_b%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%canvastype 4%snaptogrid%replyformat 10%userdraw dotfill,blue%clearbutton REMOVE LAST RECTANGLE
4969
  @%userdraw_rect%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%userdraw rect,green
4970
  @%userdraw_rects%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%userdraw rects,green
4971
  @%userdraw_frect%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%userdraw frect,green
18635 bpr 4972
  @%userdraw_frects%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%filled%opacity 200,50%userdraw rects,green
4973
  @%userdraw_roundrect%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%filled%opacity 200,50%userdraw roundrect,green
4974
  @%userdraw_roundrects%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%filled%opacity 200,50%userdraw roundrects,green
4975
  @%userdraw_froundrect%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%filled%opacity 200,50%userdraw roundrect,green
4976
  @%userdraw_froundrects%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%filled%opacity 200,50%userdraw roundrects,green
18552 bpr 4977
  @%userdraw_line%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw line,green
4978
  @%userdraw_lines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw lines,green
4979
  @%userdraw_vline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw vline,green
4980
  @%userdraw_vlines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw vlines,green
4981
  @%userdraw_hline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw hline,green
4982
  @%userdraw_hlines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw hlines,green
4983
  @%userdraw_demiline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw demiline,green
4984
  @%userdraw_demilines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw demilines,green
4985
  @%userdraw_arc%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%userdraw arc,green
4986
  @%userdraw_arcs%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%userdraw arcs,green
4987
  @%userdraw_point%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw point,green
4988
  @%userdraw_points%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw points,green
4989
  @%userdraw_arrow%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw arrow,green
4990
  @%userdraw_arrows%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw arrows,green
4991
  @%userdraw_arrow2%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw arrow2,green
4992
  @%userdraw_arrows2%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw arrows2,green
4993
  @%userdraw_curvedarrow%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 1%linewidth 3%userdraw curvedarrow,red%clearbutton REMOVE ALL ARROWS
4994
  @%userdraw_curvedarrows%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 1%linewidth 3%userdraw curvedarrows,red%clearbutton REMOVE ALL ARROWS
4995
  @%userdraw_curvedarrow2%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 1%linewidth 3%userdraw curvedarrow2,red%clearbutton REMOVE ALL ARROWS
4996
  @%userdraw_curvedarrows2%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%precision 1%linewidth 3%userdraw curvedarrows2,red%clearbutton REMOVE ALL ARROWS
4997
  @%userdraw_crosshair%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw crosshair,green
4998
  @%userdraw_crosshairs%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw crosshairs,green
18635 bpr 4999
  @%userdraw_circle%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%filled%opacity 200,50%userdraw circle,green
5000
  @%userdraw_circles%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%filled%opacity 200,50%userdraw circles,green
18552 bpr 5001
  @%userdraw_segment%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw segment,green
5002
  @%userdraw_segments%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw segments,green
5003
  @%userdraw_line%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw line,green
5004
  @%userdraw_lines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw lines,green
18635 bpr 5005
  @%userdraw_triangle%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%filled%opacity 200,50%userdraw triangle,green
5006
  @%userdraw_poly5%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw poly5,green
18552 bpr 5007
  @%userdraw_filled_poly5%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%filled%userdraw poly5,green
5008
  @%userdraw_poly7%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%userdraw poly7,green
5009
  @%userdraw_filled_poly7%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%filled%userdraw poly7,green
18635 bpr 5010
  @%userdraw_polyline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw polyline,green
18552 bpr 5011
  @%userdraw_freehandline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw freehandline,green
5012
  @%userdraw_filled_freehandline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%fillcolor orange%opacity 200,50%filled%userdraw freehandline,green
5013
  @%userdraw_freehandlines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw freehandlines,green
5014
  @%userdraw_input%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%userdraw input,green
5015
  @%userdraw_inputs%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%userdraw inputs,green
5016
  @%userdraw_text%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%fontfamily 42px Courier%userdraw text,green
5017
  @%userdraw_function%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 1%grid 2,2,grey,2,2,5,grey%multicolors orange,red,green,blue,cyan%precision 1000%userdraw functions3,red%jscurve blue,x^2,-x^2,5*cos(x)%precision 1%mouse red,22
5018
  @%userdraw_clickfill_colorpalette%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%circles blue,0,0,4,1,1,6,3,3,3,-3,-3,5%opacity 255,120%colorpalette red,green,yellow,blue%userdraw clickfill,green
5019
  @%userdraw_clickfill_1%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%circles blue,0,0,4,1,1,6,3,3,3,-3,-3,5%opacity 255,120%userdraw clickfill,green
18609 bpr 5020
  @%userdraw_clickfill_2%size 400,400%xrange -10,10%yrange -10,10%circles blue,0,0,2,1,1,5,5,5,4,-5,5,6,5,-5,6%userdraw hatchfill,red%#userdraw dotfill,red%#userdraw diamondfill,red%#userdraw gridfill,red
18552 bpr 5021
  @%userdraw_clickfill_2%size 400,400%xrange -10,10%yrange -10,10%bgcolor white%# to get nice click coordinates take invisible ''grid`` and use ''snaptogrid`` %grid 1,1,white%snaptogrid%circles blue,0,0,2,1,1,5,5,5,4,-5,5,6,5,-5,6%userdraw gridfill,red
5022
  */
5023
          if( use_userdraw != 0 ){ /* only one object type may be drawn*/
5024
            canvas_error("Only one userdraw primitive may be used in command 'userdraw' use command 'multidraw' for this...");
5025
          }
5026
          js_function[INTERACTIVE] = 1;
5027
          draw_type = get_string_argument(infile,0);
5028
          if( strcmp(draw_type,"textfill") == 0){
5029
            fprintf(js_include_file,"var userdraw_text_string = \"%s\";", get_string(infile,1));
5030
          }
5031
          else {
5032
            if( strcmp(draw_type,"imagefill") == 0){
5033
              fprintf(js_include_file,"var userdraw_image_url = \"%s\";", get_string(infile,1));
5034
            }
5035
            else {
5036
              stroke_color = get_color(infile,1);
5037
            }
5038
          }
5039
          if( strcmp(draw_type,"clickfill") == 0){use_filled = 1;fill_color = stroke_color;}
5040
          reply_precision = precision;
5041
          use_userdraw = 1;
5042
          fprintf(js_include_file,"\n\
15111 schaersvoo 5043
/* begin userdraw */\
5044
userdraw_x = new Array();userdraw_y = new Array();userdraw_radius = new Array();\
5045
var forbidden_zone=[xsize+1,ysize+1];var xy_cnt = 0;\
5046
var canvas_userdraw = create_canvas%d(%d,xsize,ysize);\
5047
var context_userdraw = canvas_userdraw.getContext(\"2d\");\
5048
var use_dashed = %d;\
5049
var use_snap = %d;if(use_dashed == 1){if( context_userdraw.setLineDash ){context_userdraw.setLineDash([%d,%d]);}else{if(context_userdraw.mozDash){context_userdraw.mozDash = [%d,%d];};};};\
5050
context_userdraw.lineWidth = %d;var use_filled = %d;\
5051
context_userdraw.strokeStyle =  \"rgba(%s,%.2f)\";\
5052
context_userdraw.font = \"%s\";\
15128 schaersvoo 5053
var user_is_dragging = false;\
15111 schaersvoo 5054
if(wims_status != \"done\"){\
5055
canvas_div.addEventListener(\"mousedown\" ,user_draw,false);\
5056
canvas_div.addEventListener(\"mousemove\" ,user_drag,false);\
5057
canvas_div.addEventListener(\"touchstart\",function(e){ e.preventDefault();user_draw(e.changedTouches[0]);},false);\
5058
canvas_div.addEventListener(\"touchmove\" ,function(e){ e.preventDefault();user_drag(e.changedTouches[0]);},false);\
15128 schaersvoo 5059
canvas_div.addEventListener(\"touchend\" ,function(e){ e.preventDefault();user_drawstop(e.changedTouches[0]);},false);\
15111 schaersvoo 5060
};",canvas_root_id,DRAW_CANVAS,use_dashed,use_snap,dashtype[0],dashtype[1],dashtype[0],dashtype[1],line_width,use_filled,stroke_color,stroke_opacity,font_family);
5061
 
18552 bpr 5062
          if( use_filled == 0 ){
5063
            fprintf(js_include_file,"context_userdraw.fillStyle = \"rgba(255,255,255.0)\";");
5064
          }
5065
          else {
5066
            if( use_filled == 1 ){
5067
              fprintf(js_include_file,"context_userdraw.fillStyle = \"rgba(%s,%.2f)\";",fill_color,fill_opacity);
5068
            }
5069
            else {
5070
              js_function[DRAW_FILL_PATTERN] = 1;
5071
              fprintf(js_include_file,"context_userdraw.fillStyle = create_Pattern(0,0,%d,[%s]);\n",use_filled,fill_color);
5072
            }
5073
          }
5074
          add_js_userdraw(draw_type,stroke_color,stroke_opacity,crosshair_size,arrow_head,use_offset,css_class,use_snap,canvas_type,use_filled,fill_color,fill_opacity,line_width,font_family);
5075
          reset();
5076
          break;
5077
        case USERINPUT:
5078
  /*
18556 bpr 5079
  @ userinput function inputfield
5080
  @ alternative: userinput_function
5081
  @ alternative: userinput_xy
5082
  @ ''inputfield`` is only usable in combination with some ''userdraw draw_type``
5083
  @ note: the input fields are not cleared after the object is drawn...be aware of multiple idential drawings (many clicks on the ''ok`` button)
5084
  @ ''userinput function`` may be used any time (e.g. without userdraw)
5085
  @ multiple ''userinput function`` commands may be used.
5086
  @ use command <code>functionlabel some_string</code> to define the inputfield text: default value "f(x)="
5087
  @ use command <code>strokecolor some_color</code> to adjust the plot / functionlabel color
5088
  @ use command <code>css some_css</code> to adjust the inputfields
5089
  @ use command <code>fontsize int</code> to adjust the label fonts. (default 12px)
5090
  @ the user input for the function will be corrected by a simple ''rawmath`` implementation...<br>an error message will be shown if javascript can not interpret the user input
5091
  @%userinput_function%size 400,400%xrange -10,10%yrange -10,10%functionlabel your function g(x)=%axis%axisnumbering%xlabel x-axis%ylabel y-axis%grid 2,2,grey,3,3,5,grey%css color:blue;text-align:center%userinput function%# note: number of function inputs not limited
5092
  @%userinput_points%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%# adding 2 inputfields for x and y%userinput inputfield%userdraw points,blue
5093
  @%userinput_arrows%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%#adding 4 inputfields for (x1;y1)---(x2;y2)%userinput inputfieldd%userdraw arrows,blue
5094
  @%userinput_combined%size 400,400%xrange -10,10%yrange -10,10%functionlabel your function g(x)=%axis%axisnumbering%xlabel x-axis%ylabel y-axis%precision 0%grid 2,2,grey,3,3,5,grey%css color:blue;text-align:center%precision 1000%strokecolor red%opacity 255,255%userinput function%# note: number of function inputs not limited%userdraw line,blue
18552 bpr 5095
  */
5096
          temp = get_string_argument(infile,1);
5097
          if(strstr(temp,"function") != 0  || strstr(temp,"curve") != 0  || strstr(temp,"plot") != 0 ){
5098
            if( js_function[DRAW_JSFUNCTION] != 1 ){
5099
              js_function[JS_RAWMATH] = 1;
5100
              js_function[DRAW_JSFUNCTION] = 1;
5101
              if(reply_format == 0){reply_format = 24;}/* read canvas_input values */
5102
              add_input_jsfunction(css_class,function_label,input_cnt,stroke_color,stroke_opacity,line_width,use_dashed,dashtype[0],dashtype[1],font_size);
5103
              input_cnt++;
5104
            }
5105
            else {
5106
        /* no need to add DRAW_JSFUNCTION, just call it with the parameters */
5107
            fprintf(js_include_file,"add_input_jsfunction(%d,\"%s\",%s,%d,\"%s\",\"%.2f\",%d,%d,%d,%d);\n",input_cnt,css_class,function_label,line_width,stroke_color,stroke_opacity,use_dashed,dashtype[0],dashtype[1],font_size);
5108
            input_cnt++;
5109
            }
5110
            js_function[JS_MATH] = 1;
5111
            js_function[JS_PLOT] = 1;
5112
          }
5113
          else {
5114
            if(strstr(temp,"inputfield") != 0 ){
5115
              js_function[JS_SAFE_EVAL] = 1;
5116
              js_function[ADD_USER_INPUTS] = 1;
5117
            }
5118
            else {
5119
              canvas_error("userinput argument may be \"function\" or \"inputfield\"");
5120
            }
5121
          }
5122
          break;
5123
        case USERINPUT_XY:
5124
  /*
5125
  @ userinput_xy
5126
  @ keyword (no arguments required)
5127
  @ to be used in combination with command "userdraw object_type,color"
5128
  @ if set two (or three) input fields are added to the document<br>(one for x-values, one for y-values and in case of drawing circle one for radius-values)
5129
  @ the student may use this as correction for (x:y) on a drawing (or to draw without mouse, using just the coordinates)
5130
  @ math input is allowed (e.g something like: 1+3,2*6,1/3,sqrt(3), sin(pi/4),10^-2,log(2)...)<br>eval function is ''protected`` against code injection.
5131
  @ can <b>not</b> be combined with command ''intooltip tiptext`` <br>note: the ''tooltip div element`` is used for placing inputfields
5132
  @ user drawings will not zoom on zooming (or pan on panning)
5133
  @ use command ''css some_css`` to adjust the inputarea.
5134
  @ use command ''fontsize int`` to adjust the text labels (if needed)
5135
  @%userinput_xy%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%precision 0%grid 2,2,grey,3,3,6,black%# provides inputfields for (x1:y1)---(x2:y2)%userinput_xy%linewidth 2%precision 1000%userdraw lines,blue
5136
  */
5137
      /* add simple eval check to avoid code injection with unprotected eval(string) */
5138
          js_function[JS_SAFE_EVAL] = 1;
5139
          js_function[ADD_USER_INPUTS] = 1;
5140
          break;
5141
        case USERINPUT_FUNCTION:
5142
  /*
5143
  @ userinput_function
5144
  @ alternative: userinput
5145
  @ keyword (no arguments required)
5146
  @ if set, a inputfield will be added to the page
5147
  @ repeat keyword for more function input fields
5148
  @ the userinput value will be plotted in the canvas
5149
  @ this value may be read with <code>read_canvas()</code>. <br>for do it yourself js-scripters: If this is the first inputfield in the script, its id is canvas_input0
5150
  @ use before this command ''userinput_function``,<br>commands like ''css some_css``, ''xlabel some_description``, ''opacity int,int``, ''linewidth int``, ''dashed`` and ''dashtype int,int`` to modify
5151
  @ fontsize can be set using command ''fontsize int``
5152
  @ incompatible with command ''intooltip link_text_or_image``: it uses the tooltip div for adding the inputfield
5153
  @%userinput_function%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%xlabel x-axis%ylabel y-axis%precision 0%grid 2,2,grey,2,2,5,grey%precision 1000%linewidth 2%# first inputfield%css color:blue;text-align:center;font-family:Italic;%strokecolor blue%functionlabel g(x)=:p(x)=:k(x)=%userinput function%# second inputfield%css color:green;text-align:center;font-family:Italic;%strokecolor green%userinput function%# third inputfield%css color:purple;text-align:center;font-family:Italic;%strokecolor purple%userinput function%# no limit in number of function inputfields
5154
  */
5155
          if( js_function[DRAW_JSFUNCTION] != 1 ){
5156
            js_function[DRAW_JSFUNCTION] = 1;
5157
            js_function[JS_RAWMATH] = 1;
5158
            if(reply_format == 0){reply_format = 24;}/* read canvas_input values */
5159
            add_input_jsfunction(css_class,function_label,input_cnt,stroke_color,stroke_opacity,line_width,use_dashed,dashtype[0],dashtype[1],font_size);
5160
            input_cnt++;
5161
          }
5162
          else {
5163
        /* no need to add DRAW_JSFUNCTION, just call it with the parameters */
5164
          fprintf(js_include_file,"add_input_jsfunction(%d,\"%s\",%s,%d,\"%s\",\"%.2f\",%d,%d,%d,%d);\n",input_cnt,css_class,function_label,line_width,stroke_color,stroke_opacity,use_dashed,dashtype[0],dashtype[1],font_size);
5165
          input_cnt++;
5166
          }
5167
          js_function[JS_MATH] = 1;
5168
          js_function[JS_PLOT] = 1;
5169
          break;
5170
        case VLINE:
5171
  /*
5172
  @ vline x,y,color
5173
  @ alternative: verticalline
5174
  @ draw a vertical line through point (x:y) in color 'color'
5175
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
5176
  @%vline%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%vline 0,0,red%onclick%vline 1,0,orange%onclick%vline 2,0,blue%onclick%vline 3,0,green
5177
  */
5178
          for(i=0;i<3;i++) {
5179
            switch(i){
5180
              case 0: double_data[0] = get_real(infile,0);break; /* x-values */
5181
              case 1: double_data[1] = get_real(infile,0);break; /* y-values */
5182
              case 2: stroke_color=get_color(infile,1);/* name or hex color */
5183
                double_data[2] = double_data[0];
5184
                decimals = find_number_of_digits(precision);
5185
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 5186
                    tmp_buffer=my_newmem(MAX_BUFFER);
5187
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[2],decimals,100*ymin,decimals,100*ymax,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 5188
                add_to_buffer(tmp_buffer);
5189
                if(onclick != 0){object_cnt++;}
5190
      /* object_cnt++; */
5191
                reset();
5192
               break;
5193
            }
5194
          }
5195
          dragstuff[4] = 1;
5196
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5197
          break;
5198
        case VLINES:
5199
  /*
5200
  @ vlines color,x1,y1,x2,y2....
5201
  @ alternative: verticallines
5202
  @ draw vertical lines through points (x1:y1),(x2:y2)... in color 'color'
5203
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
5204
  @%vlines%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%vlines red,1,0,2,0,3,0,4,0
5205
  */
5206
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5207
          fill_color = stroke_color;
5208
          i=0;
5209
          while( ! done ){     /* get next item until EOL*/
5210
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5211
            if(i%2 == 0 ){
5212
              double_data[i] = get_real(infile,0); /* x */
5213
            }
5214
            else {
5215
              double_data[i] = get_real(infile,1); /* y */
5216
            }
5217
            i++;
5218
          }
5219
          decimals = find_number_of_digits(precision);
5220
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5221
          for(c = 0 ; c < i-1 ; c = c+2){
18557 bpr 5222
            tmp_buffer=my_newmem(MAX_BUFFER);
18607 bpr 5223
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[0],[0],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c],decimals,100*ymin,decimals,100*ymax,line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 5224
            add_to_buffer(tmp_buffer);
5225
            if(onclick != 0){object_cnt++;}
5226
            /* object_cnt++; */
5227
          }
5228
          reset();
5229
          dragstuff[4] = 1;
5230
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5231
          break;
5232
        case VIDEO:
5233
  /*
5234
  @ video x,y,w,h,videofile location
5235
  @ x,y: left top corner of audio element (in xrange / yrange)
5236
  @ w,y: width and height in pixels
5237
  @ video format may be in *.mp4 (todo: other formats)
5238
  @%video%size 400,400%xrange -10,10%yrange -10,10%opacity 200,100%frect -9,9,6,-6,green%video -5,5,200,200,http://techslides.com/demos/sample-videos/small.mp4
5239
  */
5240
          js_function[DRAW_VIDEO] = 1;
5241
          for(i=0;i<5;i++){
5242
            switch(i){
5243
              case 0: int_data[0] = x2px(get_real(infile,0)); break; /* x in x/y-range coord system -> pixel */
5244
              case 1: int_data[1] = y2px(get_real(infile,0)); break; /* y in x/y-range coord system -> pixel */
5245
              case 2: int_data[2] = (int) (get_real(infile,0)); break; /* pixel width */
5246
              case 3: int_data[3] = (int) (get_real(infile,0)); break; /* height pixel height */
5247
              case 4: temp = get_string(infile,1);
18557 bpr 5248
                tmp_buffer=my_newmem(MAX_BUFFER);
5249
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_video(%d,%d,%d,%d,%d,\"%s\");\n",canvas_root_id,int_data[0],int_data[1],int_data[2],int_data[3],temp));
18552 bpr 5250
                add_to_buffer(tmp_buffer);
5251
                break;
5252
              default:break;
5253
            }
5254
          }
5255
          reset();
5256
          break;
5257
        case X_AXIS_STRINGS:
5258
  /*
18556 bpr 5259
  @ xaxis num1:string1:num2:string2:num3:string3:num4:string4:....num_n:string_n
5260
  @ alternative: xaxistext
5261
  @ usable for commands <a href="#numberline">numberline</a> and <a href="#grid">grid</a> or combinations thereof
5262
  @ use these x-axis num1...num_n values instead of default xmin...xmax
5263
  @ in case of command ''grid``. there is no need to use keyword <a href="#axisnumbering">axisnumbering</a>
5264
  @ use command <a href="#axis">axis</a> to have visual x/y-axis lines (see command <a href="#grid">grid</a>
5265
  @ use command ''fontcolor``, ''fontfamily`` to adjust font <br>defaults: black,12,Arial<br>note: command ''fontsize`` is not active for this command.(''fontsize`` can be used for the <a href="#legend">legend</a> in a <a href="#grid">grid</a>)
5266
  @ a javascript error message will flag non-matching value:name pairs
5267
  @ if the ''x-axis words`` are too big and will overlap, a simple alternating offset will be applied
5268
  @ to be used before command grid (see <a href="#grid">command grid</a>)
5269
  @ ''xmajor`` steps should be synchronised with numbers eg. ''1`` in the next example <code>grid 1,100,grey,1,4,6,grey</code>
5270
  @%xaxistext%size 800,200%xrange -1,13%yrange -5,10%axis%xaxistext 1:january:2:february:3:march:4:april:5:may:6:june:7:july:8:august:9:september:10:october:11:november:12:december%grid 1,4,grey,1,2,10,red
18552 bpr 5271
  */
5272
          use_axis_numbering++;
5273
          temp = get_string(infile,1);
5274
          if( strstr(temp,":") != 0 ){ temp = str_replace(temp,":","\",\"");}
5275
          if( strstr(temp,"pi") != 0 ){ temp = str_replace(temp,"pi","(3.1415927)");}/* we need to replace pi for javascript y-value*/
5276
          fprintf(js_include_file,"x_strings[%d] = [\"%s\"];x_strings_up[%d] = null;",use_axis_numbering,temp,use_axis_numbering);
5277
          break;
5278
        case X_AXIS_STRINGS_UP:
5279
  /*
18556 bpr 5280
  @ xaxisup num1:string1:num2:string2:num3:string3:num4:string4:....num_n:string_n
5281
  @ alternative: xaxistextup
5282
  @ the text will be rotated 90&deg; up
5283
  @ no need to use keyword <a href="#axisnumbering">axisnumbering</a>
5284
  @ use command <a href="#axis">axis</a> to have visual x/y-axis lines (see command <a href="#grid">grid</a>
5285
  @ use these x-axis num1...num_n values instead of default xmin...xmax
5286
  @ use command ''fontcolor``, <a href="#fontfamily">fontfamily</a> to adjust font <br>defaults: black,12,Arial<br>note: command ''fontsize`` is not active for this command.(''fontsize`` can be used for the <a href="#legend">legend</a> in a <a href="#grid">grid</a>)
5287
  @ a javascript error message will flag non-matching value:name pairs
5288
  @ if the ''x-axis words`` are too big, they will overlap the graph<br> (in this case the text will start from ysize upwards)
5289
  @ to be used before command grid (see <a href="#grid">command grid</a>)
5290
  @''xmajor`` steps should be synchronised with numbers eg. "1" in the next example <code>grid 1,100,grey,1,4,6,grey</code>
5291
  @%xaxistextup%size 800,300%xrange -1,13%yrange -10,10%fontfamily Italic 18pt Courier%axis%xaxistextup 1:january:2:february:3:march:4:april:5:may:6:june:7:july:8:august:9:september:10:october:11:november:12:december%grid 1,4,grey,1,2,10,red
18552 bpr 5292
  */
5293
          use_axis_numbering++;
5294
          temp = get_string(infile,1);
5295
          if( strstr(temp,":") != 0 ){ temp = str_replace(temp,":","\",\"");}
5296
          if( strstr(temp,"pi") != 0 ){ temp = str_replace(temp,"pi","(3.1415927)");}/* we need to replace pi for javascript y-value*/
5297
          fprintf(js_include_file,"x_strings_up[%d] = 1;x_strings[%d] = [\"%s\"];",use_axis_numbering,use_axis_numbering,temp);
5298
          break;
5299
        case XERRORBARS:
5300
  /*
5301
  @ xerrorbars color,E1,E2,x1,y1,x2,y2,...,x_n,y_n
5302
  @ draw multiple points with x-errorbars E1 (error value left from point) and E2 (error value right from point) at given coordinates in color 'color'
5303
  @ the errors E1 and E2 values are in xrange.
5304
  @ use command ''linewidth int`` to adust size
5305
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
5306
  @%xerrorbars%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag xy%xerrorbars red,0.8,1.3,0,0,1,1,2,3,3,2,4,5,5,2,6,1,-1,-2,-2,0,-3,2,-4,4,-5,-1
8386 schaersvoo 5307
 
18552 bpr 5308
  */
5309
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5310
          fill_color = stroke_color;
5311
          i=0;
5312
          while( ! done ){     /* get next item until EOL*/
5313
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5314
            if(i%2 == 0 ){
5315
                double_data[i] = get_real(infile,0); /* x */
5316
            }
5317
            else {
5318
              double_data[i] = get_real(infile,1); /* y */
5319
            }
5320
            i++;
5321
          }
5322
          decimals = find_number_of_digits(precision);
5323
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5324
          for(c = 2 ; c < i-1 ; c = c+2){
18557 bpr 5325
            tmp_buffer=my_newmem(MAX_BUFFER);
5326
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,20,[%.*f],[%.*f],[%.2f],[%.2f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+1],double_data[0],double_data[1],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,1,0,0,0,use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18552 bpr 5327
            add_to_buffer(tmp_buffer);
5328
            /* object_cnt++; */
5329
            if(onclick != 0){object_cnt++;}
5330
          }
5331
          reset();
5332
          dragstuff[20] = 1;
5333
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5334
          break;
5335
        case NEWRANGE:
5336
  /*
5337
  @ newrange xmin,xmax,ymin,ymax
5338
  @ objects defined after command will make use of this new range
5339
  @ https://wimsedu.info/?topic=dessiner-des-portions-de-fonctions-sur-un-meme-graphe
5340
  */
5341
          for(i = 0 ; i<4; i++){
5342
            switch(i){
5343
              case 0: xmin = get_real(infile,0);break;
5344
              case 1: xmax = get_real(infile,0);break;
5345
              case 2: ymin = get_real(infile,0);break;
5346
              case 3: ymax = get_real(infile,1);break;
5347
              default: break;
5348
            }
5349
          }
18557 bpr 5350
          tmp_buffer=my_newmem(MAX_BUFFER);
5351
          check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "\n\nxmin = %f;xmax = %f;ymin = %f;ymax = %f;\n\n",xmin,xmax,ymin,ymax));
18552 bpr 5352
          add_to_buffer(tmp_buffer);
5353
          break;
5354
        case XRANGE:
5355
  /*
5356
  @ xrange xmin,xmax
5357
  @ alternative: rangex
5358
  @ if not given: 0,xsize (eg in pixels)
5359
  */
18556 bpr 5360
          for(i = 0 ; i<2; i++){
5361
            switch(i){
5362
              case 0: xmin = get_real(infile,0);break;
5363
              case 1: xmax = get_real(infile,1);break;
5364
              default: break;
5365
            }
5366
          }
5367
          if(xmin >= xmax){canvas_error(" xrange is not OK: xmin &lt; xmax !");}
5368
          fprintf(js_include_file,"var xmin = %f;var xmax = %f;",xmin,xmax);
5369
          found_size_command++;
5370
          break;
18552 bpr 5371
        case XSNAPTOGRID:
5372
  /*
18556 bpr 5373
  @ xsnaptogrid
5374
  @ keyword (no arguments required)
5375
  @ a draggable object (use command ''drag x|y|xy``) will snap to the given x-grid values when dragged (mouseup)
5376
  @ in case of userdraw the drawn points will snap to xmajor grid
5377
  @ if no grid is defined, points will snap to every integer xrange value. (eg snap_x=1)
5378
  @ if you do not want a visible grid, but you only want a ''snaptogrid`` with some value...define this grid with opacity 0.
5379
  @ if xminor is defined (use keyword ''axis`` to activate xminor), the drawing will snap to xminor <br>use only even dividers in x-minor...for example<br><code>xsnaptogrid<br>axis<br>grid 2,1,grey,4,4,7,red</code><br> will snap on x=0, x=0.5, x=1, x=1.5 ....<br> will snap on y=0, y=0.25 y=0.5 y=0.75 ...<br>
5380
  @%xsnaptogrid_1%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%xsnaptogrid%userdraw segments,red%precision 1%display x,red,12
5381
  @%xsnaptogrid_2%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 3%drag x%points red,0,0,0,0,0,0,0,0,0,0
5382
*/
5383
          use_snap = 2;
5384
          break;
18552 bpr 5385
        case XOFFSET:
5386
  /*
18556 bpr 5387
  @ xoffset
5388
  @ keyword ; to place the text centered above the text coordinates(x:y) ...
5389
  @ may be used for points or other things requiring centered labels
5390
  @ use <a href="#fontfamily">fontfamily</a> for setting the font
5391
  @ may be active for commands <a href="#text">text</a> and <a href="#string">string</a> (e.g. objects in the drag/drop/onclick-library)
18552 bpr 5392
  @%xoffset%size 400,400%xrange -10,10%yrange -10,10%fontfamily 12pt Arial%string blue,-9,-9,no offset%point -9,-9,red%centered%string blue,-6,-6,centered%point -6,-6,red%xoffset%string blue,-3,-3,xoffset%point -3,-3,red%yoffset%string blue,0,0,yoffset%point 0,0,red%xyoffset%string blue,3,3,xyoffset%point 3,3,red%resetoffset%string blue,6,6,resetoffset%point 6,6,red
5393
  */
18556 bpr 5394
          use_offset = 2;
5395
          break;
18552 bpr 5396
        case XYOFFSET:
5397
  /*
18556 bpr 5398
  @ xyoffset
5399
  @ keyword ; to place the text (x:y) to (x+dx:y+dy)... dx/dy are dependent on fontsize/fontfamily
5400
  @ may be used for points or other things requiring labels
5401
  @ use <a href="#fontfamily">fontfamily</a> for setting the font
5402
  @ only active for commands <a href="#text">text</a> and <a href="#string">string</a> (e.g. objects in the drag/drop/onclick-librariy
5403
  @ in case of inputfields the inputfield will be centered x and y on its coordinates.<br>for example:<br>inputs 1,1,10,? <br>point 1,1,red <br> the point will be completely invisible<br>note: keyword ''xyoffset`` will also provide centering if used with <a href='#userdraw'>input(s),color</a>
5404
  @%xyoffset%size 400,400%xrange -10,10%yrange -10,10%fontfamily 12pt Arial%string blue,-9,-9,no offset%point -9,-9,red%centered%string blue,-6,-6,centered%point -6,-6,red%xoffset%string blue,-3,-3,xoffset%point -3,-3,red%yoffset%string blue,0,0,yoffset%point 0,0,red%xyoffset%string blue,3,3,xyoffset%point 3,3,red%resetoffset%string blue,6,6,resetoffset%point 6,6,red
18552 bpr 5405
  */
18556 bpr 5406
          use_offset = 3;
5407
          break;
18552 bpr 5408
        case XUNIT:
5409
  /*
18556 bpr 5410
  @ xunit some_unit_for_x-values
5411
  @ unicode allowed (no html code)
5412
  @ use together with command <a href="#display">display or mouse</a>
5413
  @ will display the cursor x-coordinate in ''unit``
5414
  @%xunit%size 400,400%xrange -10,10%yrange -10,10%xunit cm \\u00B2%grid 2,2,grey%linewidth 2%userdraw segments,blue%display x,blue,18
18552 bpr 5415
  */
18556 bpr 5416
          fprintf(js_include_file,"unit_x = \"%s\";",get_string(infile,1));
5417
          break;
18552 bpr 5418
        case XLABEL:
5419
  /*
5420
  @ xlabel some_string
5421
  @ will be used to create a label for the x-axis (label is in quadrant I)
5422
  @ can only be used together with command ''grid``<br>not depending on keywords ''axis`` and ''axisnumbering``
5423
  @ font setting: italic Courier, fontsize will be slightly larger (fontsize + 4)<br>use command ''fontsize`` to adjust.<br>(command ''fontfamily`` is not active for this command)
5424
  @ use <a href="#ylabel">ylabel</a>
5425
  @%xlabel%size 400,400%xrange -10,10%yrange -10,10%axis%axisnumbering%xlabel cm\\u00B2 %ylabel v\\u00B2 %precision 1%grid 2,2,grey,2,2,5,grey
5426
  */
18556 bpr 5427
          temp = get_string(infile,1);
5428
          fprintf(js_include_file,"var xaxislabel = \"%s\";",temp);
5429
          break;
18552 bpr 5430
        case XLOGBASE:
5431
  /*
5432
  @ xlogbase number
5433
  @ sets the logbase number for the x-axis
5434
  @ default value 10
5435
  @ use together with commands xlogscale / xylogscale
5436
  */
18556 bpr 5437
          fprintf(js_include_file,"xlogbase=%d;",(int)(get_real(infile,1)));
5438
          break;
18552 bpr 5439
        case XLOGSCALE:
5440
  /*
18556 bpr 5441
  @ xlogscale ymajor,yminor,majorcolor,minorcolor
5442
  @ the x/y-range are set using commands <code>xrange xmin,xmax</code> and <code>yrange ymin,ymax</code>
5443
  @ ymajor is the major step on the y-axis; yminor is the divisor for the y-step
5444
  @ the linewidth is set using command ''linewidth int``
5445
  @ the opacity of major / minor grid lines is set by command <a href='#opacity'>opacity</a>
5446
  @ default logbase number = 10 ... when needed, set the logbase number with command ''xlogbase number``
18627 bpr 5447
  @ the x/y- axis numbering is triggered by keyword ''axisnumbering``<ul><li>use command ''precision`` before ''xlogscale`` command to set the precision (decimals) of the axis numbering</li><li>use commands ''xlabel some_text`` and/or ''ylabel some_text`` for text on axis: use command ''fontsize int`` to set the fontsize (default 12px)</li><li>use command ''fontfamily fnt_family_string`` to set the fonts for axis-numbering</li><li>use command ''fontcolor`` to set the color</li></ul>
18556 bpr 5448
  @ note: the complete canvas will be used for the ''log paper``
5449
  @ note: userdrawings are done in the log paper, e.g. javascript:read_canvas() will return the real values
5450
  @ note: command ''mouse color,fontsize`` will show the real values in the logpaper.<br>\
5451
  @ note: when using something like ''xrange 0.0001,0.01``...combined with commands <a href='#mouse'>mouse</a> and/or <a href='#userdraw'>userdraw</a>...<br> make sure the <a href='#precision'>precision</a> is set accordingly
5452
  @ note: in case of userdraw, the use of keyword <a href='#userinput_xy'>userinput_xy</a> may be handy !
5453
  @ <b>attention</b>: keyword ''snaptogrid`` may not lead to the desired result...
5454
  @ <b>attention</b>: do not use command ''zoom``
5455
  @%xlogscale%size 400,400%xrange 10,50000%yrange -5,5%xlabel x-axis%ylabel y-axis%xlogscale 10,1,black,grey%display x,red,22
18552 bpr 5456
  */
18556 bpr 5457
          use_axis_numbering++;if(use_axis_numbering > 1){use_axis_numbering = 1;}
5458
          if( js_function[DRAW_GRID] == 1 ){canvas_error("only one type of grid is allowed...");}
5459
          js_function[DRAW_XLOGSCALE] = 1;
5460
          for(i=0;i<4;i++){
5461
            switch(i){
5462
              case 0: double_data[0] = get_real(infile,0);break; /* xmajor */
5463
              case 1: int_data[0] = (int) (get_real(infile,0));break; /* xminor */
5464
              case 2: stroke_color = get_color(infile,0); break;
5465
              case 3: fill_color = get_color(infile,1);
18557 bpr 5466
                tmp_buffer=my_newmem(MAX_BUFFER);
5467
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_grid%d(%d,%d,\"%s\",\"%s\",%.2f,%.2f,%d,\"%s\",\"%s\",%d,%f,%d,%d); ",canvas_root_id,GRID_CANVAS,line_width,stroke_color,fill_color,stroke_opacity,fill_opacity,font_size,font_family,font_color,use_axis_numbering,double_data[0],int_data[0],precision));
18556 bpr 5468
                fprintf(js_include_file,"use_xlogscale=1;snap_y = %f;snap_x = xlogbase;",double_data[0]/int_data[0]);
5469
                add_to_buffer(tmp_buffer);
5470
                break;
5471
              default:break;
5472
            }
5473
          }
5474
          break;
18552 bpr 5475
        case XYLOGSCALE:
5476
  /*
18556 bpr 5477
  @ xylogscale majorcolor,minorcolor
5478
  @ the x/y-range are set using commands ''xrange xmin,xmax`` and ''yrange ymin,ymax``
5479
  @ the linewidth is set using command ''linewidth int``
5480
  @ the opacity of major / minor grid lines is set by command ''opacity [0-255],[0-255]``
5481
  @ default logbase number = 10 ... when needed, set the logbase number with command ''xlogbase number`` and/or ''ylogbase number``
18627 bpr 5482
  @ the x/y- axis numbering is triggered by keyword ''axisnumbering``<ul><li>use commands ''xlabel some_text`` and/or ''ylabel some_text`` for text on axis: use command ''fontsize int`` to set the fontsize (default 12px)</li><li>use command ''fontfamily fnt_family_string`` to set the fonts for axis-numbering</li><li>use command ''fontcolor`` to set the color</li></ul>
18556 bpr 5483
  @ note: the complete canvas will be used for the ''log paper``
5484
  @ note: userdrawings are done in the log paper, e.g. javascript:read_canvas() will return the real values
5485
  @ note: command ''mouse color,fontsize`` will show the real values in the logpaper.<br>\
5486
  @ note: when using something like ''yrange 0.0001,0.01``...combined with commands ''mouse color,fontsize`` and/or ''userdraw type,color``...<br> make sure the precision is set accordingly (eg command ''precision 10000``)
5487
  @ note: in case of userdraw, the use of keyword ''userinput_xy`` may be handy !
5488
  @ <b>attention</b>: keyword ''snaptogrid`` may not lead to the desired result...
5489
  @ <b>attention</b>: do not use command ''zoom``
5490
  @%xylogscale%size 400,400%xrange 10,50000%yrange 10,50000%xlabel x-axis%ylabel y-axis%xylogscale black,grey%display xy,red,22
18552 bpr 5491
  */
18556 bpr 5492
          use_axis_numbering++;if(use_axis_numbering > 1){use_axis_numbering = 1;}
5493
          if( js_function[DRAW_GRID] == 1 ){canvas_error("only one type of grid is allowed...");}
5494
          js_function[DRAW_XYLOGSCALE] = 1;
5495
          for(i=0;i<2;i++){
5496
            switch(i){
5497
              case 0: stroke_color = get_color(infile,0); break;
5498
              case 1: fill_color = get_color(infile,1);
18557 bpr 5499
                tmp_buffer=my_newmem(MAX_BUFFER);
5500
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_grid%d(%d,%d,\"%s\",\"%s\",%.2f,%.2f,%d,\"%s\",\"%s\",%d,%d); ",canvas_root_id,GRID_CANVAS,line_width,stroke_color,fill_color,stroke_opacity,fill_opacity,font_size,font_family,font_color,use_axis_numbering,precision));
18556 bpr 5501
                fprintf(js_include_file,"use_xlogscale=1;use_ylogscale=1;snap_x = xlogbase;snap_y = ylogbase;");
5502
                add_to_buffer(tmp_buffer);
5503
                break;
5504
              default:break;
5505
            }
5506
          }
5507
          break;
18552 bpr 5508
        case Y_AXIS_STRINGS:
5509
  /*
18556 bpr 5510
  @ yaxis num1:string1:num2:string2:num3:string3:num4:string4:....num_n:string_n
5511
  @ alternative: yaxistext
5512
  @ use command ''fontcolor``, ''fontfamily`` to adjust font <br>defaults: black,12,Arial<br> note: command ''fontsize`` is not active for this command.(''fontsize`` can be used for the <a href="#legend">legend</a> in a <a href="#grid">grid</a>)
5513
  @ no need to use keyword <a href="#axisnumbering">axisnumbering</a>
5514
  @ use command <a href="#axis">axis</a> to have visual x/y-axis lines (see command <a href="#grid">grid</a>
5515
  @ use these y-axis num1...num_n values instead of default ymin...ymax
5516
  @ a javascript error message will flag non-matching value:name pairs
5517
  @ to be used before command grid (see <a href="#grid">command grid</a>)
5518
  @%yaxistext%size 400,400%yrange 0,13%xrange -100,500%axis%yaxis 1:january:2:february:3:march:5:may:6:june:7:july:8:august:9:september:10:october:11:november:12:december%#'ymajor' steps should be synchronised with numbers eg. "1" in this example%grid 100,1,grey,4,1,6,grey
18552 bpr 5519
  */
18556 bpr 5520
          temp = get_string(infile,1);
5521
          if( strstr(temp,":") != 0 ){ temp = str_replace(temp,":","\",\"");}
5522
          if( strstr(temp,"pi") != 0 ){ temp = str_replace(temp,"pi","(3.1415927)");}/* we need to replace pi for javascript y-value*/
5523
          fprintf(js_include_file,"y_strings = [\"%s\"];\n ",temp);
5524
          use_axis_numbering++;
5525
          break;
18552 bpr 5526
        case YERRORBARS:
5527
  /*
5528
  @ yerrorbars color,E1,E2,x1,y1,x2,y2,...,x_n,y_n
5529
  @ draw multiple points with y-errorbars E1 (error value under point) and E2 (error value above point) at given coordinates in color 'color'
5530
  @ the errors E1 and E2 values are in yrange.
5531
  @ use command ''linewidth int`` to adust size
5532
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
5533
  @%yerrorbars%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%yerrorbars red,0.8,1.3,0,0,1,1,2,3,3,2,4,5,5,2,6,1,-1,-2,-2,0,-3,2,-4,4,-5,-1
5534
  */
5535
      stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5536
      fill_color = stroke_color;
5537
      i=0;
5538
      while( ! done ){     /* get next item until EOL*/
18556 bpr 5539
        if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5540
        if(i%2 == 0 ){
5541
            double_data[i] = get_real(infile,0); /* x */
5542
        }
5543
        else
5544
        {
5545
            double_data[i] = get_real(infile,1); /* y */
5546
        }
5547
        i++;
18552 bpr 5548
      }
5549
      if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5550
      for(c = 2 ; c < i-1 ; c = c+2){
18557 bpr 5551
        tmp_buffer=my_newmem(MAX_BUFFER);
5552
        check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "dragstuff.addShape(new Shape(%d,%d,%d,%d,19,[%.*f],[%.*f],[%.2f],[%.2f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+1],double_data[0],double_data[1],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,1,0,0,0,use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18556 bpr 5553
        add_to_buffer(tmp_buffer);
18552 bpr 5554
    /* object_cnt++; */
18556 bpr 5555
        if(onclick != 0){object_cnt++;}
18552 bpr 5556
      }
5557
      decimals = find_number_of_digits(precision);
5558
      reset();
5559
      dragstuff[19] = 1;
5560
      if(use_dragstuff == 0 ){ use_dragstuff = 1;}
5561
      break;
5562
        case YOFFSET:
5563
  /*
18556 bpr 5564
  @ yoffset
5565
  @ keyword; to place the text centered above the text coordinates(x:y) ...
5566
  @ may be used for points or other things requiring centered labels
5567
  @ use <a href="#fontfamily">fontfamily</a> for setting the font
5568
  @ may be active for commands <a href="#text">text</a> and <a href="#string">string</a> (e.g. objects in the drag/drop/onclick-library)
5569
  @%yoffset%size 400,400%xrange -10,10%yrange -10,10%fontfamily 12pt Arial%string blue,-9,-9,no offset%point -9,-9,red%centered%string blue,-6,-6,centered%point -6,-6,red%xoffset%string blue,-3,-3,xoffset%point -3,-3,red%yoffset%string blue,0,0,yoffset%point 0,0,red%xyoffset%string blue,3,3,xyoffset%point 3,3,red%resetoffset%string blue,6,6,resetoffset%point 6,6,red
18552 bpr 5570
  */
18556 bpr 5571
          use_offset = 1;
5572
          break;
18552 bpr 5573
        case YRANGE:
5574
  /*
5575
  @ yrange ymin,ymax
5576
  @ alternative: rangey
5577
  @ if not given 0,ysize (eg in pixels)
5578
  */
18556 bpr 5579
          for(i = 0 ; i<2; i++){
5580
            switch(i){
5581
              case 0: ymin = get_real(infile,0);break;
5582
              case 1: ymax = get_real(infile,1);break;
5583
              default: break;
5584
            }
5585
          }
5586
          if(ymin >= ymax){canvas_error(" yrange is not OK: ymin &lt; ymax !<br>");}
5587
          fprintf(js_include_file,"var ymin = %f;var ymax = %f;",ymin,ymax);
5588
          found_size_command++;
5589
          break;
18552 bpr 5590
        case YSNAPTOGRID:
5591
  /*
18556 bpr 5592
  @ ysnaptogrid
5593
  @ keyword (no arguments required)
5594
  @ a draggable object (use command ''drag x|y|xy``) will snap to the given y-grid values when dragged (mouseup)
5595
  @ in case of userdraw the drawn points will snap to ymajor grid
5596
  @ if no grid is defined, points will snap to every integer yrange value. (eg snap_y=1)
5597
  @ if you do not want a visible grid, but you only want a ''snaptogrid`` with some value...define this grid with opacity 0.
5598
  @ if yminor is defined (use keyword ''axis`` to activate yminor), the drawing will snap to yminor <br>use only even dividers in y-minor...for example<br><code>ysnaptogrid<br>axis<br>grid 2,1,grey,4,4,7,red</code><br> will snap on x=0, x=0.5, x=1, x=1.5 ....<br> will snap on y=0, y=0.25 y=0.5 y=0.75 ...<br>
5599
  @%ysnaptogrid_1%size 400,400%xrange -10,10%yrange -10,10%ysnaptogrid%grid 1,1,grey%linewidth 2%userdraw crosshairs,blue%css font-size:8px;color:blue%clearbutton delete all crosshairs
5600
  @%ysnaptogrid_2%size 400,400%xrange -10,10%yrange -10,10%ysnaptogrid%grid 1,1,grey%linewidth 3%drag y%points red,0,0,0,0,0,0,0,0,0,0
18552 bpr 5601
  */
18556 bpr 5602
          use_snap = 3;
5603
          break;
18552 bpr 5604
        case YLABEL:
5605
  /*
5606
  @ ylabel some_string
5607
  @ will be used to create a (vertical) label for the y-axis (label is in quadrant I)
5608
  @ can only be used together with command <a href="#grid">grid</a><br>not depending on keywords ''axis`` and ''axisnumbering``
5609
  @ font setting: italic Courier, fontsize will be slightly larger (fontsize + 4)<br>use command ''fontsize`` to adjust (command ''fontsize`` is not active for this command)
5610
  @ use <a href="#xlabel">xlabel</a>
5611
  @%ylabel%size 400,400%xrange -10,10%yrange -10,10%fontsize 8%axis%axisnumbering%precision 1%xlabel x-axis%ylabel y-axis%grid 1,1,grey,2,2,2,red
5612
  */
18556 bpr 5613
          temp = get_string(infile,1);
5614
          fprintf(js_include_file,"var yaxislabel = \"%s\";",temp);
5615
          break;
18552 bpr 5616
        case YLOGBASE:
5617
  /*
5618
  @ ylogbase number
5619
  @ sets the logbase number for the y-axis
5620
  @ default value 10
5621
  @ use together with commands ylogscale / xylogscale
5622
  */
5623
          fprintf(js_include_file,"ylogbase=%d;",(int)(get_real(infile,1)));
5624
          break;
5625
        case YLOGSCALE:
5626
  /*
18556 bpr 5627
  @ ylogscale xmajor,xminor,majorcolor,minorcolor
5628
  @ the x/y-range are set using commands ''xrange xmin,xmax`` and ''yrange ymin,ymax``
5629
  @ xmajor is the major step on the x-axis; xminor is the divisor for the x-step
5630
  @ the linewidth is set using command ''linewidth int``
5631
  @ the opacity of major / minor grid lines is set by command ''opacity [0-255],[0-255]``
5632
  @ default logbase number = 10 ... when needed, set the logbase number with command ''ylogbase number``
5633
  @ the x/y- axis numbering is triggered by keyword ''axisnumbering``<ul><li>use command ''precision`` before ''ylogscale`` command to set the precision (decimals) of the axis numbering</li><li>use commands ''xlabel some_text`` and/or ''ylabel some_text`` for text on axis: use command ''fontsize int`` to set the fontsize (default 12px)</li><li>use command ''fontfamily fnt_family_string`` to set the fonts for axis-numbering</li><li>use command ''fontcolor`` to set the color</li></ul>
5634
  @ note: the complete canvas will be used for the ''log paper``
5635
  @ note: userdrawings are done in the log paper, e.g. javascript:read_canvas() will return the real values
5636
  @ note: command ''mouse color,fontsize`` will show the real values in the logpaper.<br>\
5637
  @ note: when using something like ''yrange 0.0001,0.01``...combined with commands ''mouse color,fontsize`` and/or ''userdraw type,color``...<br> make sure the precision is set accordingly (eg command ''precision 10000``)
5638
  @ note: in case of userdraw, the use of keyword ''userinput_xy`` may be handy !
5639
  @ <b>attention</b>: do not use command ''zoom``
5640
  @ <b>attention</b>: keyword ''snaptogrid`` may not lead to the desired result...
18552 bpr 5641
  */
18555 bpr 5642
        use_axis_numbering++;if(use_axis_numbering > 1){use_axis_numbering = 1;}
5643
        if( js_function[DRAW_GRID] == 1 ){canvas_error("only one type of grid is allowed...");}
5644
        js_function[DRAW_YLOGSCALE] = 1;
5645
        for(i=0;i<4;i++){
5646
          switch(i){
5647
            case 0: double_data[0] = get_real(infile,0);break; /* xmajor */
5648
            case 1: int_data[0] = (int) (get_real(infile,0));break; /* xminor */
5649
            case 2: stroke_color = get_color(infile,0); break;
5650
            case 3: fill_color = get_color(infile,1);
18557 bpr 5651
              tmp_buffer=my_newmem(MAX_BUFFER);
5652
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "draw_grid%d(%d,%d,\"%s\",\"%s\",%.2f,%.2f,%d,\"%s\",\"%s\",%d,%f,%d,%d); ",canvas_root_id,GRID_CANVAS,line_width,stroke_color,fill_color,stroke_opacity,fill_opacity,font_size,font_family,font_color,use_axis_numbering,double_data[0],int_data[0],precision));
18555 bpr 5653
              fprintf(js_include_file,"use_ylogscale=1;snap_x = %f;snap_y = ylogbase;",double_data[0]/int_data[0]);
5654
              add_to_buffer(tmp_buffer);
5655
               break;
5656
            default:break;
5657
            }
5658
          }
5659
          break;
18552 bpr 5660
        case YUNIT:
5661
  /*
18556 bpr 5662
  @ yunit some_unit_for_y-values
5663
  @ unicode allowed (no html code)
5664
  @ use together with command mousey
5665
  @ will display the cursor y-coordinate in ''unit``
18552 bpr 5666
  */
5667
          fprintf(js_include_file,"unit_y = \"%s\";",get_string(infile,1));
5668
          break;
18555 bpr 5669
        case HYPSEGMENTS:
18556 bpr 5670
  /*
5671
  @ hypsegments color,x1,y1,x2,y2,...,x_n,y_n
5672
  @ draw multiple hyperbolic segments in the Poincaré disk between points (x1:y1)--(x2:y2).....and... (x_n-1:y_n-1)--(x_n:y_n) in color ''color``
5673
  @ use command ''linewidth int`` to adjust size
5674
  may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
5675
  @%hypsegments%size 400,400%xrange -1,1%yrange -1,1%circles black,0,0,1%linewidth 2%hypsegments green,0.1,-0.3,0.6,0.7,0.3,0,-0.8,0.6,0.6,0.5,-0.5,0.6
5676
  segments_onclick%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%segments green,1,1,3,3,0,0,-3,3,1,1,4,-1,-5,5,-3,-1
5677
  segments_drag_y%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag y%segments green,1,1,3,3,0,0,-3,3,1,1,4,-1,-5,5,-3,-1
5678
  */
18555 bpr 5679
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5680
          fill_color = stroke_color;
5681
          i=0;
5682
          while( ! done ){     /* get next item until EOL*/
5683
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5684
              if(i%2 == 0 ){
5685
                double_data[i] = get_real(infile,0); /* x */
5686
              }
5687
            else {
5688
              double_data[i] = get_real(infile,1); /* y */
5689
            }
5690
            i++;
5691
          }
5692
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
5693
          if(use_affine == TRUE ){ transform(i-1,2);}
5694
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5695
          decimals = find_number_of_digits(precision);
5696
          for(c = 0 ; c < i-1 ; c = c+4){
18569 bpr 5697
            tmp_buffer=my_newmem(MAX_BUFFER);
18555 bpr 5698
            if (hypgeodaux(double_data+c,res,0)){
5699
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,12,[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,res[0],decimals,res[0],decimals,res[1],decimals,res[1],decimals,res[2],decimals,res[3],decimals,res[4],decimals,res[5],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
5700
            }
5701
            else {
5702
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+1],decimals,double_data[c+3],line_width,stroke_color,stroke_opacity,stroke_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
5703
            }
5704
            add_to_buffer(tmp_buffer);
5705
            if(onclick != 0){object_cnt++;}
5706
          }
5707
          reset();
5708
          dragstuff[4] = 1;dragstuff[12] = 1;
5709
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5710
          break;
5711
        case HYPLINES:
5712
        /*
5713
  @ hyplines color,x1,y1,x2,y2...x_n-1,y_n-1,x_n,y_n
5714
  @ draw multiple hyperbolic lines in the Poincaré disk through points (x1:y1)--(x2:y2) ...(x_n-1:y_n-1)--(x_n:y_n) in color 'color'
5715
  may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
5716
  @%hyplines%size 400,400%xrange -1,1%yrange -1,1%circles black,0,0,1%hyplines green,0,0.1,0.1,0.3,0.2,0.3,0.1,0.3,0,0.5,-0.5,0.4
5717
  */
5718
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5719
          fill_color = stroke_color;
5720
          i=0;
5721
          while( ! done ){     /* get next item until EOL*/
5722
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
18562 bpr 5723
            if(i%2 == 0 ){
5724
              double_data[i] = get_real(infile,0); /* x */
5725
            }
18555 bpr 5726
            else {
5727
              double_data[i] = get_real(infile,1); /* y */
5728
            }
5729
            i++;
5730
          }
5731
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
5732
          if(use_affine == TRUE ){ transform(i-1,2);}
5733
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18623 bpr 5734
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18555 bpr 5735
          decimals = find_number_of_digits(precision);
5736
          for(c = 0 ; c < i-1 ; c = c+4){
18569 bpr 5737
            tmp_buffer=my_newmem(MAX_BUFFER);
18555 bpr 5738
            if (hypgeodaux(double_data+c,res,1)){
5739
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,12,[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,res[0],decimals,res[0],decimals,res[1],decimals,res[1],decimals,res[2],decimals,res[3],decimals,res[4],decimals,res[5],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));}
5740
            else {
18623 bpr 5741
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,res[0],decimals,res[2],decimals,res[1],decimals,res[3],line_width,stroke_color,stroke_opacity,fill_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18555 bpr 5742
            }
5743
            add_to_buffer(tmp_buffer);
5744
            if(onclick != 0){object_cnt++;}
5745
          }
5746
          reset();
5747
          dragstuff[4] = 1;dragstuff[12] = 1;
5748
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5749
          break;
5750
        case HYPPOLY:
18615 bpr 5751
/*  @ hyppolygon color,x1,y1,x2,y2...x_n-1,y_n-1,x_n,y_n
5752
    @ draw hyperbolicpolygon in the Poincaré disk through points (x1:y1)--(x2:y2) ...(x_n-1:y_n-1)--(x_n:y_n) -- (x1:y1)  in color 'color'
5753
    may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
5754
    @ option fhyppolygon only for convex polygon for the moment
5755
    @%hyppolygon%size 400,400%xrange -1,1%yrange -1,1%circles black,0,0,1%hyppolygon green,0,0,0.5,0.3,0.8,-0.1,0.4,-0.5
5756
*/
5757
          stroke_color=get_color(infile,0);
18555 bpr 5758
          fill_color = stroke_color;
5759
          i=0;
5760
          while( ! done ){     /* get next item until EOL*/
5761
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5762
            if(i%2 == 0 ){
5763
              double_data[i] = get_real(infile,0); /* x */
5764
            }
5765
            else {
5766
              double_data[i] = get_real(infile,1); /* y */
5767
            }
5768
            i++;
5769
          }
5770
          /* il faut rajouter le premier point à la fin*/
5771
          double_data[i]=double_data[0]; double_data[i+1]=double_data[1];
5772
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
5773
          if(use_affine == TRUE ){ transform(i-1,2);}
5774
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5775
          decimals = find_number_of_digits(precision);
5776
          for(c = 0 ; c < i-1 ; c = c+2){
18615 bpr 5777
            tmp_buffer=my_newmem(MAX_BUFFER);
18555 bpr 5778
            if (hypgeodaux(double_data+c,res,0)){
18615 bpr 5779
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,12,[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,res[0],decimals,res[0],decimals,res[1],decimals,res[1],decimals,res[2],decimals,res[3],decimals,res[4],decimals,res[5],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18555 bpr 5780
            }
5781
            else {
18623 bpr 5782
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+2],decimals,double_data[c+1],decimals,double_data[c+3],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18555 bpr 5783
            }
5784
            add_to_buffer(tmp_buffer);
5785
            if(onclick != 0){object_cnt++;}
18615 bpr 5786
          }
5787
          if(use_filled){
5788
            hypgeodaux(double_data+2,res,0);
5789
            res[4]=double_data[0]; res[5]=double_data[1];
5790
            hypgeodaux(res+4,res,0);
5791
            add_js_filltoborder(canvas_type);
5792
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"setTimeout(function(){filltoborder (%.*f,%.*f,[%s,%d],[%s,%d],%d,false,null);},1000);\n",decimals,res[6],decimals,res[7],fill_color,(int) (fill_opacity/0.0039215),fill_color,(int) (fill_opacity/0.0039215),FILL_CANVAS+fill_cnt));
5793
            add_to_buffer(tmp_buffer);
5794
                fill_cnt++;
18606 bpr 5795
                }
18569 bpr 5796
          dragstuff[4] = 1; dragstuff[12] = 1;
18555 bpr 5797
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5798
          reset();
5799
          break;
5800
        case HYPRAYS:
5801
  /*
18556 bpr 5802
  @ hyprays color,xc,yc,x1,y1,x2,y2,x3,y3...x_n,y_n
5803
  @ draw hyperbolic rays in the Poincaré disk in color 'color' and center (xc:yc)
18555 bpr 5804
   may be set draggable or onclick (every individual ray)
18556 bpr 5805
  @%hyprays%size 400,400%xrange -1,1%yrange -1,1%circles black,0,0,1%onclick%hyprays blue,0.5,0.5,0.3,0.9,-0.3,0.5,-0.4,0,0.4,-0.9,-0.8,0.1,-0.1,-0.9
18555 bpr 5806
   hyprays_onclick%size 400,400%xrange -1,1%yrange -1,1%circles black,0,0,1%onclick%hyprays blue,0.5,0.5,0.3,0.9,-0.3,0.5,-0.4,0,0.4,-0.9,-0.8,0.1,-0.1,-0.9
5807
   hyprays_drag_xy%size 400,400%xrange -1,1%yrange -1,1%circles black,0,0,1%drag xy%hyprays blue,0,0,0.3,0.9,-0.3,0.5,-0.4,0,0.4,-0.9,-0.8,0.1,-0.1,-0.9
5808
  */
5809
          stroke_color=get_color(infile,0);
18623 bpr 5810
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18555 bpr 5811
          double_data[0] = get_real(infile,0);/* xc */
5812
          double_data[1] = get_real(infile,0);/* yc */
5813
          i=2;
18562 bpr 5814
          while( ! done ){ /* get next item until EOL*/
18555 bpr 5815
            if(i > MAX_INT - 1){canvas_error("in command rays too many points / rays in argument: repeat command multiple times to fit");}
5816
            if(i%2 == 0 ){
5817
              double_data[i] = get_real(infile,0); /* x */
5818
            }
5819
            else {
5820
              double_data[i] = get_real(infile,1); /* y */
5821
            }
5822
            fprintf(js_include_file,"/* double_data[%d] = %f */\n",i,double_data[i]);
5823
            i++;
5824
          }
5825
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
5826
          if(use_affine == TRUE ){ transform(i-1,2);}
5827
          if( i%2 != 0 ){canvas_error("in command rays: unpaired x or y value");}
5828
          decimals = find_number_of_digits(precision);
5829
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5830
          for(c=2; c<i;c = c+2){
18557 bpr 5831
            tmp_buffer=my_newmem(MAX_BUFFER);
18555 bpr 5832
            double_data[2]=double_data[c];double_data[3]=double_data[c+1];
5833
            if (hypgeodaux(double_data,res,0)){
5834
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,12,[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],[%.*f,%.*f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,res[0],decimals,res[0],decimals,res[1],decimals,res[1],decimals,res[2],decimals,res[3],decimals,res[4],decimals,res[5],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
5835
            }
5836
            else {
18623 bpr 5837
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,4,[%.*f,%.*f],[%.*f,%.*f],[30,30],[30,30],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[0],decimals,double_data[c],decimals,double_data[1],decimals,double_data[c+1],line_width,stroke_color,stroke_opacity,fill_color,stroke_opacity,0,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18555 bpr 5838
            }
5839
            add_to_buffer(tmp_buffer);
5840
            /* object_cnt++; */
5841
            if(onclick != 0){object_cnt++;}
5842
          }
5843
          reset();
5844
          dragstuff[4] = 1; dragstuff[12] = 1;
5845
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5846
          break;
5847
        case HYPCIRCLES:
5848
        /*
5849
  @ hypcircles color,xc1,yc1,r1,xc2,yc2,r2...xc_n,yc_n,r_n
5850
  @ draw hyperbolic circles in Poincaré disk
5851
  @ <b>attention</b> r = radius in x-range (!)
5852
  @ use keyword <code>filled</code> or command <code>fhypcircles</code> to produce solid circles
5853
  @ use command <code>fillcolor color</code> to set the fillcolor
5854
  @%hypcircles%size 400,400%xrange -1,1%yrange -1,1%filled%fillcolor lightblue%opacity 255,50%hypcircles blue,0,0,1,0.4,0.4,3,0.2,0.6,6
5855
  hypcircles_drag%size 400,400%xrange -1,1%yrange -1,1%filled%fillcolor lightblue%opacity 255,50%drag xy%hypcircles blue,0,0,2,0.2,0.2,3,0.2,0.2,5%zoom red
5856
  hypcircles_onclick%size 400,400%xrange -1,1%yrange -1,1%filled%fillcolor lightblue%opacity 255,50%onclick%hypcircles blue,0,0,2,0.2,0.2,3,0.2,0.2,5%zoom red
5857
  hypcircles_drag_slider%size 400,400%xrange -1,1%yrange -1,1%linewidth 2%drag xy%# Click circles(s) to activate%opacity 200,50%fillcolor orange%rotationcenter 2,3%slider 0,2*pi,300,30,angle degrees,Rotate%slider -5,5*pi,300,30,x display,move in x-direction%slider -10,10*pi,300,30,y display,move in y-direction%hypcircles blue,0,0,2,0.2,0.2,3,0.2,0.2,5
5858
  */
5859
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
18623 bpr 5860
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18555 bpr 5861
          i=1;
18562 bpr 5862
          while( ! done ){ /* get next item until EOL*/
18555 bpr 5863
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5864
              switch (i%3){
5865
                case 1:double_data[i-1] = get_real(infile,0);break; /* x */
5866
                case 2:double_data[i-1] = get_real(infile,0);break; /* y */
5867
                case 0:double_data[i-1] = get_real(infile,1);break; /* r */
5868
              }
5869
            i++;
5870
          }
5871
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,3);}
5872
          if(use_affine == TRUE ){ transform(i-1,3);}
5873
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5874
          decimals = find_number_of_digits(precision);
5875
          for(c = 0 ; c < i-1 ; c = c+3){
18556 bpr 5876
            double Z2=double_data[c]*double_data[c]+double_data[c+1]*double_data[c+1];//[Z]^2
18555 bpr 5877
            double R=tanh(double_data[c+2]/2);double R2=R*R;
5878
            double den=1-R2*Z2; double XY=(1-R2)/den;
5879
            double_data[c]=XY*double_data[c];
5880
            double_data[c+1]=XY*double_data[c+1];
5881
            double_data[c+2]=(1-Z2)/den*R;
18557 bpr 5882
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 5883
            check_string_length(snprintf(tmp_buffer,MAX_BUFFER,"dragstuff.addShape(new Shape(%d,%d,%d,%d,13,[%.*f],[%.*f],[%.3f],[%.3f],%d,\"%s\",%.2f,\"%s\",%.2f,%d,%d,%d,%d,%d,%.1f,\"%s\",%d,\"%s\",%s,%s,%d));\n",drag_type,object_cnt,onclick,use_snap,decimals,double_data[c],decimals,double_data[c+1],double_data[c+2],double_data[c+2],line_width,stroke_color,stroke_opacity,fill_color,fill_opacity,use_filled,use_dashed,dashtype[0],dashtype[1],use_rotate,angle,flytext,font_size,font_family,my_sliders,rotation_center,use_offset));
18555 bpr 5884
            add_to_buffer(tmp_buffer);
5885
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
5886
          }
5887
          reset();
5888
          dragstuff[13] = 1;
5889
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5890
          break;
18552 bpr 5891
        case ZOOM:
5892
  /*
18556 bpr 5893
  @ zoom button_color
5894
  @ introduce a very small ''controlpanel`` at the lower right corner (font size of the panel is fixed to: 22px Arial)
5895
  @ giving six 15&times;15px ''active`` rectangle areas<br>(''&times;,&darr;,&uarr;,&larr;,&rarr;,&minus;,+``) for zooming and/or panning of the image
5896
  @ a mouse wheel is active for in/out zooming. Drag panning is not supported (this will conflict with many ''userdraw`` or ''multidraw`` primitives)
5897
  @ the ''controlpanel`` is not active for a ''userdraw`` mousedown (but it can interfere with some ''userdraw`` types)
5898
  @ the ''&times;`` symbol will reset to your original xmax/xmin ymax/ymin values.
5899
  @ choose an appropriate color, so the small ''&times;,&darr;,&uarr;,&larr;,&rarr;,&minus;,+`` are clearly visible
5900
  @ command ''opacity`` may be used to set stroke_opacity of buttons
5901
  @ note: on zooming, text will not increase / decrease the font size (todo??)
5902
  @ note: adding ''zooming`` will increase the size of the javascript include with approx. 11 kb
18552 bpr 5903
  */
18556 bpr 5904
         js_function[INTERACTIVE] = 1;
18552 bpr 5905
          js_function[JS_ZOOM] = 1;
5906
          if( use_userdraw == 1 ){
5907
            js_function[USERDRAW_AND_ZOOM] = 1;
5908
            fprintf(js_include_file,"forbidden_zone = [%d,%d];",xsize-115,ysize - 20);
5909
          }
5910
          if(jsplot_cnt != -1){ js_function[JSPLOT_AND_ZOOM] = 1;}
5911
          stroke_color = get_color(infile,1);
5912
          /* we use BG_CANVAS (0) */
5913
          add_js_zoom_buttons(stroke_color,stroke_opacity);
5914
          done = TRUE;
5915
          break;
11806 schaersvoo 5916
 
5917
/* ready */
18552 bpr 5918
        default:sync_input(infile);
5919
        break;
5920
      }
7614 schaersvoo 5921
    }
5922
  /* we are done parsing script file */
18556 bpr 5923
    if(use_dragstuff != 0){
18562 bpr 5924
  /* add the 20kb drag code: nearly always used ... use_dragstuff==1: no-mouse ! */
18556 bpr 5925
      add_drag_code(DRAG_CANVAS,use_dragstuff,dragstuff,reply_format);
5926
      if(js_function[JS_ZOOM] == 1){
15111 schaersvoo 5927
        js_function[DRAG_AND_ZOOM] = 1;
18556 bpr 5928
      }
15111 schaersvoo 5929
  }
15116 bpr 5930
 
14066 bpr 5931
  /* check if xrange / yrange was set explicit ... or use xmin=0 xmax=xsize ymin=0 ymax=ysize: Quadrant I */
18556 bpr 5932
    if( found_size_command == 1 ){
5933
      fprintf(js_include_file,"var xmin = 0;var xmax = %d;var ymin = 0;var ymax = %d",xsize,ysize);
7983 schaersvoo 5934
    }
18556 bpr 5935
    else
5936
    {
5937
      if( found_size_command != 3 ){
5938
        canvas_error("Please specify size first and then both xrange and yrange ...");
5939
      }
5940
    }
8257 schaersvoo 5941
 
18562 bpr 5942
  /* if needed, add generic draw functions (grid / xml etc) to buffer: these are no draggable/clickable shapes / objects ! */
18556 bpr 5943
    add_javascript_function();
7614 schaersvoo 5944
   /* add read_canvas() etc functions if needed */
18556 bpr 5945
    if( reply_format > 0 ){ add_read_canvas(reply_format,reply_precision);}
7797 schaersvoo 5946
  /* no zoom, just add buffer */
18556 bpr 5947
    fprintf(js_include_file,"\n/* add buffer */\n%s};\n/* end wims_canvas_function */\nwims_canvas_function%d();\n",buffer,canvas_root_id);
7614 schaersvoo 5948
/* done writing the javascript include file */
18556 bpr 5949
    fclose(js_include_file);
5950
    }
7614 schaersvoo 5951
 
5952
/* if using a tooltip, this should always be printed to the *.phtml file, so stdout */
18556 bpr 5953
    if( use_tooltip > 0 ){
5954
      if( use_tooltip == 1 ){
5955
        add_js_tooltip(tooltip_text,bgcolor);
5956
      }
5957
      else
5958
      {
5959
      if( use_tooltip == 2 ){
5960
        add_js_popup(getfile_cmd);
5961
      }
5962
    }
9329 schaersvoo 5963
  }
18556 bpr 5964
  exit(EXIT_SUCCESS);
7614 schaersvoo 5965
}
5966
/* end main() */
5967
 
5968
/******************************************************************************
5969
**
5970
**  sync_input
5971
**
5972
**  synchronises input line - reads to end of line, leaving file pointer
5973
**  at first character of next line.
5974
**
5975
**  Used by:
5976
**  main program - error handling.
5977
**
5978
******************************************************************************/
5979
void sync_input(FILE *infile)
5980
{
18552 bpr 5981
  int c = 0;
7614 schaersvoo 5982
 
18552 bpr 5983
  if( c == '\n' || c == ';' ) return;
5984
  while( ( (c=getc(infile)) != EOF ) && (c != '\n') && (c != '\r') && (c != ';')) ;
5985
  if( c == EOF ) finished = 1;
5986
  if( c == '\n' || c == '\r' || c == ';') line_number++;
5987
  return;
7614 schaersvoo 5988
}
5989
 
5990
/******************************************************************************/
15111 schaersvoo 5991
void transform(int num,int incr){
5992
/*.
5993
only "double_data[]" is used for transformations !!
5994
*/
5995
 int i;int ii;double x,y;
5996
 for(i=0;i<num;i = i+incr){
5997
  ii = i+1;
5998
  x = double_data[i]*affine_matrix[0] + double_data[ii]*affine_matrix[1]+affine_matrix[4];
5999
  y = double_data[i]*affine_matrix[2] + double_data[ii]*affine_matrix[3]+affine_matrix[5];
15601 schaersvoo 6000
 /*
17351 bpr 6001
  printf("(%f:%f) &rarr; (%f:%f)<br>",double_data[i],double_data[ii],x,y);
15601 schaersvoo 6002
 */
15111 schaersvoo 6003
  double_data[i] = x;
6004
  double_data[ii] = y;
6005
 }
6006
}
6007
 
6008
void rotate(int num,double angle,double center[],int incr){
6009
 int i;int ii;double rad = angle * 0.0174532925199;
6010
 double c = cos(rad);
6011
 double s = sin(rad);
6012
 double x,y;
6013
 for(i=0;i<num;i = i+incr){
6014
  ii = i+1;
6015
  x = c*(double_data[i]-center[0]) + s*(double_data[ii] - center[1] ) + center[0];
6016
  y = c*(double_data[ii]-center[1]) - s*(double_data[i] - center[0] ) + center[1];
6017
  double_data[i] = x;
6018
  double_data[ii] = y;
17351 bpr 6019
 // printf("(x:y) - (%f:%f)<br>",x,y);
15111 schaersvoo 6020
 }
6021
}
6022
/* not used: see transform()
6023
void translate(int num){
6024
 int i;int ii;
6025
 double x,y;
6026
 for(i=0;i<num;i = i+2){
6027
  ii = i+1;
6028
  x = double_data[i] + affine_matrix[4];
6029
  y = double_data[ii] + affine_matrix[5];
6030
  double_data[i] = x;
6031
  double_data[ii] = y;
6032
 }
6033
}
6034
*/
7614 schaersvoo 6035
char *str_replace(const char *str, const char *old, const char *new){
18562 bpr 6036
  if(strlen(str) > MAX_BUFFER){canvas_error("string argument too big");}
6037
  char *ret, *r;
6038
  const char *p, *q;
6039
  size_t oldlen = strlen(old);
6040
  size_t count = 0;
6041
  size_t retlen = 0;
6042
  size_t newlen = strlen(new);
6043
  if (oldlen != newlen){
6044
    for (count = 0, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen){
18552 bpr 6045
      count++;
6046
      retlen = p - str + strlen(p) + count * (newlen - oldlen);
18562 bpr 6047
    }
18552 bpr 6048
  }
18562 bpr 6049
  else {
6050
    retlen = strlen(str);
6051
  }
6052
  if ((ret = malloc(retlen + 1)) == NULL){
6053
    ret = NULL;
6054
    canvas_error("string argument is NULL");
6055
  }
6056
  else
6057
  {
6058
    for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
18552 bpr 6059
      size_t l = q - p;
6060
      memcpy(r, p, l);
6061
      r += l;
6062
      memcpy(r, new, newlen);
6063
      r += newlen;
18562 bpr 6064
    }
6065
    strcpy(r, p);
18552 bpr 6066
  }
18562 bpr 6067
  return ret;
7614 schaersvoo 6068
}
6069
 
6070
/******************************************************************************/
7848 bpr 6071
 
7614 schaersvoo 6072
char *get_color(FILE *infile , int last){
18562 bpr 6073
  int c,i = 0,is_hex = 0;
6074
  char temp[MAX_COLOR_STRING], *string;
6075
  const char *not_allowed = "0123456789";
6076
  while(( (c=getc(infile)) != EOF ) && ( c != '\n') && ( c != ',' ) && ( c != ';' )  && ( c != '\t' ) ){
6077
    if( i > MAX_COLOR_STRING ){ canvas_error("colour string is too big ... ? ");}
6078
    if( c == '#' ){
18552 bpr 6079
      is_hex = 1;
18562 bpr 6080
    }
6081
    if( c != ' '){
18552 bpr 6082
      if( is_hex == 0 ){if(strchr(not_allowed,c) != 0){canvas_error("found something like a number...but is should have been a colour or #hex color number...<br>Do not use R,G,B !!! ");}}
6083
      temp[i]=tolower(c);
6084
      i++;
18562 bpr 6085
    }
18552 bpr 6086
  }
18562 bpr 6087
  if( ( c == '\n' || c == EOF || c == ';' || c == '\t' ) && last == 0){canvas_error("expecting more arguments in command");}
6088
  if( c == '\n' || c == ';'  || c == '\t' ){ done = TRUE; line_number++; }
6089
  if( c == EOF ){finished = 1;}
6090
  if( finished == 1 && last != 1 ){ canvas_error("expected more arguments");}
6091
  temp[i]='\0';
6092
  if( strlen(temp) == 0 ){ canvas_error("expected a colorname or hexnumber, but found nothing !!");}
6093
  if( is_hex == 1 ){
6094
    char red[3], green[3], blue[3];
6095
    red[0]   = toupper(temp[1]); red[1]   = toupper(temp[2]); red[2]   = '\0';
6096
    green[0] = toupper(temp[3]); green[1] = toupper(temp[4]); green[2] = '\0';
6097
    blue[0]  = toupper(temp[5]); blue[1]  = toupper(temp[6]); blue[2]  = '\0';
6098
    int r = (int) strtol(red,   NULL, 16);
6099
    int g = (int) strtol(green, NULL, 16);
6100
    int b = (int) strtol(blue,  NULL, 16);
6101
    int L0 = 1+snprintf(NULL,0,"%d,%d,%d",r,g,b);
6102
    string = my_newmem(L0);
6103
    snprintf(string,L0,"%d,%d,%d",r,g,b);
6104
    return string;
6105
  }
6106
  else
6107
  {
6108
    string = (char *)my_newmem(sizeof(temp));
6109
    snprintf(string,sizeof(temp),"%s",temp);
6110
    for( i = 0; i < NUMBER_OF_COLORNAMES ; i++ ){
18552 bpr 6111
      if( strcmp( colors[i].name , string ) == 0 ){
18562 bpr 6112
        return colors[i].rgb;
18552 bpr 6113
      }
18562 bpr 6114
    }
6115
    canvas_error("I was expecting a color name or hexnumber...but found nothing.");
18552 bpr 6116
  }
18562 bpr 6117
  return "0,0,255";
7614 schaersvoo 6118
}
6119
 
14066 bpr 6120
char *get_string(FILE *infile,int last){ /* last = 0: more arguments ; last=1 final argument */
18562 bpr 6121
  int c,i=0;
6122
  char  temp[MAX_BUFFER], *string;
6123
  while(( (c=getc(infile)) != EOF ) && ( c != '\n') && ( c != '\t') ){
6124
    temp[i]=c;
6125
    i++;
6126
    if(i > MAX_BUFFER){ canvas_error("string size too big...repeat command to fit string");break;}
6127
  }
6128
  if( ( c == '\n' ||  c == '\t'  || c == EOF ) && last == 0){
6129
    canvas_error("expecting more arguments in command");}
6130
  if( c == '\n' ||  c == '\t') { done = TRUE; line_number++; }
6131
  if( c == EOF ) {finished = 1;}
6132
  temp[i]='\0';
6133
  if( strlen(temp) == 0 && last != 3 ){
6134
    canvas_error("expected a word or string, but found nothing!");}
6135
  string=(char *)my_newmem(strlen(temp));
6136
  snprintf(string,sizeof(temp),"%s",temp);
6137
  return string;
7614 schaersvoo 6138
}
6139
 
14066 bpr 6140
char *get_string_argument(FILE *infile,int last){  /* last = 0: more arguments ; last=1 final argument */
18562 bpr 6141
  int c,i=0;
6142
  char temp[MAX_BUFFER], *string;
6143
  while(( (c=getc(infile)) != EOF ) && ( c != '\n') && ( c != '\t') && ( c != ',')){
6144
    temp[i]=c;
6145
    i++;
6146
    if(i > MAX_BUFFER){ canvas_error("string size too big...will cut it off");break;}
6147
  }
6148
  if( ( c == '\n' || c == EOF) && last == 0){canvas_error("expecting more arguments in command");}
6149
  if( c == '\n' || c == '\t' ) { line_number++; }
6150
  if( c == EOF ) {finished = 1;}
6151
  if( finished == 1 && last == 0 ){ canvas_error("expected more arguments");}
6152
  temp[i]='\0';
10953 bpr 6153
/*
18562 bpr 6154
  17.10.2014 removed (question Perrin)
6155
  may cause some unwanted effects...
6156
  if( strlen(temp) == 0 ){ canvas_error("expected a word or string (without comma), but found nothing !!");}
8322 schaersvoo 6157
*/
18562 bpr 6158
  string=(char *)my_newmem(sizeof(temp));
6159
  snprintf(string,sizeof(temp),"%s",temp);
6160
  done = TRUE;
6161
  return string;
7614 schaersvoo 6162
}
6163
 
14066 bpr 6164
double get_real(FILE *infile, int last){ /* accept anything that looks like an number ?  last = 0: more arguments ; last=1 final argument */
18562 bpr 6165
  int c,i=0,found_calc = 0;
6166
  double y;
6167
  char tmp[MAX_INT];
6168
  /*
6169
   these things are 'allowed functions': *,^,+,-,/,(,),e,arc,cos,tan,pi,log,ln,sqrt,abs
6170
   but there should be a better way to avoid segfaults !
6171
  */
6172
  const char *allowed = "earcostanpilogqb*+-/^()";/* assuming these are allowed stuff in a 'number'*/
6173
  const char *not_allowed = "#dfhjkmuvwxyz{}[]%&~!$";/* avoid segmentation faults in a "atof()" and "wims eval" */
6174
  while(( (c=getc(infile)) != EOF ) && ( c != ',') && (c != '\n') && (c != '\t') && ( c != ';')){
6175
    if( c != ' ' ){
8224 bpr 6176
      if( i == 0 &&  c == '+' ){
18562 bpr 6177
        continue;
8224 bpr 6178
      }
7614 schaersvoo 6179
      else
6180
      {
18562 bpr 6181
        c = tolower(c);
6182
        if( strchr(not_allowed,c) != 0 ){canvas_error("found a character not associated with a number...");}
6183
        if( strchr(allowed,c) != 0 ){found_calc = 1;}/* hand the string over to wims eval() */
6184
        tmp[i] = c;
6185
        i++;
7614 schaersvoo 6186
      }
6187
    }
18562 bpr 6188
    if( i > MAX_INT - 1){canvas_error("number too large");}
6189
  }
6190
  if( ( c == '\n' || c == EOF || c == ';' || c == '\t' ) && last == 0){canvas_error("expecting more arguments in command");}
6191
  if( c == '\n' || c == ';' || c == '\t' ){ done = TRUE; line_number++; }
6192
  if( c == EOF ){done = TRUE ; finished = 1;}
6193
  tmp[i]='\0';
6194
  if( strlen(tmp) == 0 ){canvas_error("expected a number, but found nothing !!");}
6195
  if( found_calc == 1 ){ /* use wims eval to calculate 2*pi/3 */
6196
    void *f = eval_create(tmp);
6197
    assert(f);if( f == NULL ){canvas_error("I'm having trouble parsing your \"expression\" ") ;}
6198
    y = eval_x(f, 1);
6199
    /* if function is bogus; y = 1: so no core dumps */
6200
    eval_destroy(f);
6201
  }
6202
  else
6203
  {
6204
   y = atof(tmp);
6205
  }
6206
  return y;
7614 schaersvoo 6207
}
6208
void canvas_error(char *msg){
18562 bpr 6209
  fprintf(stdout,"\n</script><hr><span style=\"color:red\">FATAL syntax error: line %d: %s</span><hr>",line_number,msg);
6210
  finished = 1;
6211
  exit(EXIT_SUCCESS);
7614 schaersvoo 6212
}
6213
/* convert x/y coordinates to pixel */
6214
int x2px(double x){
18606 bpr 6215
  int res=(x-xmin)/(xmax-xmin)*xsize;
6216
  return (res==xsize)?xsize-1:res;
7614 schaersvoo 6217
}
6218
int y2px(double y){
18606 bpr 6219
  int res=(ymax-y)/(ymax-ymin)*ysize;
6220
  return (res==ysize)?ysize-1:res;
7614 schaersvoo 6221
}
6222
double px2x(int x){
18562 bpr 6223
  return (x*(xmax - xmin)/xsize + xmin);
7614 schaersvoo 6224
}
6225
double px2y(int y){
18562 bpr 6226
  return (y*(ymax - ymin)/ysize + ymin);
7614 schaersvoo 6227
}
6228
void add_to_buffer(char *tmp){
17351 bpr 6229
//fprintf(stdout,"tmp = %s<br>buffer = %s<br>",tmp,buffer);
18562 bpr 6230
  if( tmp == NULL || tmp == 0 ){ canvas_error("nothing to add_to_buffer()...");}
6231
  /*  do we have enough space left in buffer[MAX_BUFFER] ? */
6232
  int space_left = (int) (sizeof(buffer) - strlen(buffer));
6233
  if( space_left > strlen(tmp)){
6234
    strncat(buffer,tmp,space_left - 1);/* add safely "tmp" to the string buffer */
6235
  }
6236
  else
6237
  {
6238
    canvas_error("your memory buffer is too big<br>simplify your script...it produces too many lines ");
6239
  }
6240
  tmp = NULL;free(tmp);
6241
  return;
7614 schaersvoo 6242
}
6243
void reset(){
18562 bpr 6244
  if(no_reset == FALSE){ /* 8/5/2020 */
6245
    use_filled = FALSE;
6246
    use_dashed = FALSE;
6247
    if(onclick != 4 ){onclick = 0;} /* slider param 'active'... onclick=4 */
6248
    drag_type = -1;
6249
    use_offset = 0;
18623 bpr 6250
    fillcolor = FALSE;
18562 bpr 6251
  }
7614 schaersvoo 6252
}
15111 schaersvoo 6253
char *getMML(char *tex){
18562 bpr 6254
  int my_pipe[2];pid_t pid;
6255
  if(pipe(my_pipe)){canvas_error("mathml(): pipe() failure.\n");}
15111 schaersvoo 6256
  pid = fork();
6257
  if (pid == (pid_t) 0){
18562 bpr 6258
    char *argv[]={"wims_mathml","--use-zoom","0","--tex-size 100%","--max-mml-size","1024","--tex-string",tex,NULL};
6259
    close(my_pipe[0]);dup2(my_pipe[1], 1);dup2(my_pipe[1], 2);close(my_pipe[1]);
6260
    execv("../bin/wims_mathml",argv);canvas_error("could not execute wims_mathml\n");
15111 schaersvoo 6261
  }
6262
  else
15116 bpr 6263
  {
18562 bpr 6264
    if (pid < (pid_t) 0){
6265
      close(my_pipe[0]);close(my_pipe[1]);canvas_error("mathml(): fork() failure.\n");
6266
    }
6267
    int status;FILE *stream;close(my_pipe[1]);stream = fdopen (my_pipe[0], "r");
6268
    char buffer[MAX_BUFFER+1];memset(buffer,'\0',MAX_BUFFER);
6269
    fgets(buffer, MAX_BUFFER, stream);
6270
    int L0 = 1 + snprintf(NULL,0,"%s", buffer);
6271
    tex = my_newmem(L0);memset(tex,'\0',L0);
6272
    snprintf(tex,L0,"%s",buffer);
6273
    fclose (stream);close(my_pipe[0]);waitpid(pid, &status, 0);
15111 schaersvoo 6274
  }
18562 bpr 6275
  return tex;
15111 schaersvoo 6276
}
7614 schaersvoo 6277
 
15111 schaersvoo 6278
char *getSVGMOL(char *inputtype,char *keys){
6279
  int idx;
6280
  char *forbidden[] = {"-O","-H","-z","-L","-o","-m"};
6281
  char *argv[1+strlen(keys)];
6282
  argv[0] = "obabel"; argv[1] = "-i"; argv[2] = inputtype;
6283
  idx = 3;int i;
6284
  char *ptr = strtok(keys,",");
6285
  while(ptr != NULL ){
6286
    for(i = 0 ; i < 6; i++ ){if( strncmp(ptr,forbidden[i],2) == 0 ){return "NOT ALLOWED ARGUMENT";}}
6287
    argv[idx] = ptr; idx++;
17351 bpr 6288
    if(idx > 18){canvas_error("too many arguments for obabel....see docs<br>");}
15111 schaersvoo 6289
    ptr = strtok(NULL,",");
6290
  }
6291
  /* last arguments; no 'javascript', only 'svg to STDOUT' and 'NULL' */
6292
  argv[idx] = "-xj";argv[idx+1] = "-o"; argv[idx+2] = "svg";argv[idx+3] = NULL;
6293
  int link[2];
6294
  pid_t pid;
6295
  char buffer[MAX_BUFFER+1];
6296
  memset(buffer,'\0',MAX_BUFFER);
6297
  if (pipe(link)==-1){canvas_error("pipe");}
6298
  if ((pid = fork()) == -1){canvas_error("fork");}
15116 bpr 6299
 
15111 schaersvoo 6300
  char *svgmol = "error";
6301
  int string_length = 0;
15116 bpr 6302
 
15111 schaersvoo 6303
  if(pid == 0) {
6304
    dup2 (link[1], STDOUT_FILENO);
6305
    dup2(link[0],  STDERR_FILENO);/* remove annoying messages '1 molecule converted' */
6306
    close(link[0]);
6307
    close(link[1]);
6308
    execvp("obabel",argv);
6309
  } else {
6310
    close(link[1]);
18109 schaersvoo 6311
    read(link[0],buffer, sizeof(buffer));
15111 schaersvoo 6312
    close(link[0]);
6313
    /* need to remover newline from svg-string on freebsd */
6314
    char *pch = strstr(buffer, "\n");
6315
    while(pch != NULL){
18555 bpr 6316
      strncpy(pch, " ", 1);
6317
      pch = strstr(buffer, "\n");
15111 schaersvoo 6318
    }
6319
    string_length = 1 + snprintf(NULL,0,"%s",buffer);
6320
    svgmol= my_newmem(string_length);
6321
    snprintf(svgmol,string_length,"%s",buffer);
6322
    wait(NULL);
6323
  }
18562 bpr 6324
  return svgmol;
15111 schaersvoo 6325
}
6326
/* GNU libmatheval library for evaluating mathematical functions. */
15601 schaersvoo 6327
char *eval(int xsize,int ysize,char *fun,double xmin,double xmax,double ymin,double ymax,int plotsteps,int precision,double rotationcenter[]){
18555 bpr 6328
  void *f;
6329
  double x;
6330
  double y;
6331
  double xorg;
6332
  int xv;
6333
  int i = 0;
6334
  int xstep =(int)(xsize/plotsteps);
6335
  if( xstep == 0 ){xstep = 1;}
6336
  double a = (xmax - xmin)/xsize;
6337
  f = eval_create(fun);
6338
  assert (f);
6339
  if( f == NULL ){canvas_error("I'm having trouble parsing your \"expression\" ") ;}
6340
  /* we supply the true x/y values...draw_curve() will convert these (x:y) to pixels : used for pan/scale */
6341
  double xydata[MAX_BUFFER+1];/* hmmm */
6342
  int lim_ymin =(int)( ymin - 4*fabs(ymin));/* 19-4-2015 replacing "abs" by "fabs"*/
6343
  int lim_ymax =(int)( ymax + 4*fabs(ymax));/* 19-4-2015 replacing "abs" by "fabs"*/
6344
  double c = 1.0;double s = 1.0;
6345
  if( use_rotate == TRUE ){s = sin(angle*0.0174533);c = cos(angle*0.0174533);}
6346
  for ( xv = 0 ;xv < xsize ; xv = xv+xstep ){
18562 bpr 6347
    x = (double) (xv*a + xmin);
6348
    xorg = x;
6349
    if( i < MAX_BUFFER - 2){
18552 bpr 6350
      y = eval_x(f, x);
6351
      if(y < lim_ymax && y > lim_ymin ){
18562 bpr 6352
        if( use_affine == TRUE ){
6353
          x = x*affine_matrix[0] + y*affine_matrix[1]+affine_matrix[4];
6354
          y = xorg*affine_matrix[2] + y*affine_matrix[3]+affine_matrix[5];
6355
        }
6356
        if( use_rotate == TRUE){
6357
          x = (c * (x - rotationcenter[0])) + (s * (y - rotationcenter[1])) + rotationcenter[0];
6358
          y = (c * (y - rotationcenter[1])) - (s * (xorg - rotationcenter[0])) + rotationcenter[1];
6359
        }
6360
        xydata[i++] = x;
18552 bpr 6361
        xydata[i++] = y;
6362
      }
18562 bpr 6363
    }
6364
    else
6365
    {
18552 bpr 6366
      canvas_error("\nYour curve plotting produces too many data \n Use less plotsteps or some other means to reduce the amount of data... ");
18562 bpr 6367
    }
18552 bpr 6368
  }
18562 bpr 6369
  eval_destroy(f);
6370
  return double_xy2js_array(xydata,i,find_number_of_digits(precision));
15111 schaersvoo 6371
}
6372
/* plot a very primitive (!) levelcurve : not to be compared with "flydraw levelcurve" */
6373
char *eval_levelcurve(int xsize,int ysize,char *fun,double xmin,double xmax,double ymin,double ymax,int plotsteps,int precision,double level){
18562 bpr 6374
  void *f = eval_create(fun);
6375
  assert (f);
6376
  if( f == NULL ){canvas_error("I'm having trouble parsing your \"expression\" ") ;}
6377
  double a = (double)((xmax - xmin)/plotsteps);
6378
  double b = (double)((ymax - ymin)/plotsteps);
6379
  double x;double y;double diff;
6380
  double xydata[MAX_BUFFER+1];
6381
  int i = 0;
6382
  ymin = ymin - 1;
6383
  xmin = xmin - 1;
6384
  ymax = ymax + 1;
6385
  xmax = xmax + 1;
6386
  for( x = xmin ;x < xmax ; x = x + a ){
6387
    for ( y = ymin ;y < ymax ; y = y + b ){
18552 bpr 6388
      if( i < MAX_BUFFER - 2){
18562 bpr 6389
        diff = level - eval_x_y(f, x,y);
6390
        if(diff < 0.1 && diff > -0.1){
6391
          xydata[i++] = x;
6392
          xydata[i++] = y;
6393
        }
18552 bpr 6394
      }
6395
      else
6396
      {
18562 bpr 6397
        canvas_error("\nYour curve plotting produces too many data \n Use less plotsteps, decrease image size...\nor some other means to reduce the amount of data... ");
18552 bpr 6398
      }
18562 bpr 6399
    }
18552 bpr 6400
  }
18562 bpr 6401
  eval_destroy(f);
6402
  return double_xy2js_array(xydata,i,find_number_of_digits(precision));
15111 schaersvoo 6403
}
7614 schaersvoo 6404
 
15111 schaersvoo 6405
/* plot parametric function */
18562 bpr 6406
char *eval_parametric(int xsize,int ysize,char *fun1,char* fun2,double xmin,
6407
  double xmax,double ymin,double ymax,
6408
  double tmin,double tmax,int plotsteps,int precision,double rotationcenter[]){
6409
  void *fx;
6410
  void *fy;
6411
  double t;
6412
  int i = 0;
6413
  double tstep = (tmax-tmin)/plotsteps;
6414
  if( tstep == 0 ){canvas_error("zero step for t variable : reduce plotsteps or inrease trange");}
6415
  fx = eval_create(fun1);
6416
  fy = eval_create(fun2);
6417
  assert(fx);
6418
  assert(fy);
6419
  if( fx == NULL || fy == NULL ){canvas_error("I'm having trouble parsing your \"expression\" ") ;}
15111 schaersvoo 6420
    /* we supply the true x/y values...draw_curve() will convert these (x:y) to pixels : used for pan/scale */
18562 bpr 6421
 double xydata[MAX_BUFFER+1];/* hmmm */
6422
 double x; /* real x-values */
6423
 double y; /* real y-values */
6424
 double xorg;
6425
 /*
6426
 29/12/2020
6427
 disabled to try and synchronise curve+affine behaviour in complex scripts produced by "elec, tool circuit" (BPR)
15623 schaersvoo 6428
    int lim_ymin =(int)( ymin - 4*fabs(ymin));
6429
    int lim_ymax =(int)( ymax + 4*fabs(ymax));
6430
    */
18562 bpr 6431
  double c = 1.0;double s = 1.0;
6432
  if( use_rotate == TRUE ){s = sin(angle*0.0174533);c = cos(angle*0.0174533);}
6433
  for( t = tmin ;t <= tmax ; t = t + tstep ){
6434
    if( i < MAX_BUFFER - 2 ){
18552 bpr 6435
      y = eval_t(fy, t);
6436
  /*    if(y > lim_ymin && y < lim_ymax){*/
18562 bpr 6437
      x = eval_t(fx, t);
6438
      if( x == x){ /* no NaN */
6439
        xorg = x;
6440
        if( use_affine == TRUE ){
6441
          x = x*affine_matrix[0] + y*affine_matrix[1]+affine_matrix[4];
6442
          y = xorg*affine_matrix[2] + y*affine_matrix[3]+affine_matrix[5];
6443
        }
6444
        if( use_rotate == TRUE){
6445
          x = (c * (x - rotationcenter[0])) + (s * (y - rotationcenter[1])) + rotationcenter[0];
6446
          y = (c * (y - rotationcenter[1])) - (s * (xorg - rotationcenter[0])) + rotationcenter[1];
6447
        }
6448
        xydata[i++] = x;
6449
        xydata[i++] = y;
6450
      }
6451
  /*    } */
18552 bpr 6452
    }
18562 bpr 6453
    else
6454
    {
18552 bpr 6455
      canvas_error("\nYour curve plotting produces too many data \n Use less plotsteps or some other means to reduce the amount of data... ");
18562 bpr 6456
    }
18552 bpr 6457
  }
18562 bpr 6458
  eval_destroy(fx);
6459
  eval_destroy(fy);
6460
  return double_xy2js_array(xydata,i,find_number_of_digits(precision));
15111 schaersvoo 6461
}
7614 schaersvoo 6462
 
15111 schaersvoo 6463
char *double_xy2js_array(double xy[],int len,int decimals){
6464
 /*
6465
    1,2,3,4,5,6,7,8 --> [1,3,5,7],[2,4,6,8]
6466
    int xy[] is already checked for errors or overflow in "get_real()"
6467
    just to be sure we double check the size of "temp"
7614 schaersvoo 6468
*/
18562 bpr 6469
  char temp[2*MAX_BUFFER], *string;
6470
  char *tmp = my_newmem(16);/* <= 9999999999999999  */
6471
  memset(temp,'\0',2*MAX_BUFFER);/* clear memory */
6472
  int i;int space_left;
6473
  temp[0] = '[';/* start js-array */
6474
  for(i = 0; i < len;i = i + 2){ /*  x_points[] */
6475
    if(i == len - 2){sprintf(tmp, "%.*f",decimals, xy[i]);}
6476
    else {sprintf(tmp, "%.*f,",decimals,xy[i]);}
6477
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6478
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6479
    else{
6480
      canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce your image size or plotsteps ");}
15111 schaersvoo 6481
    }
6482
    strncat(temp,"],[",4); /* close js x_values array and start new */
6483
    for(i = 1; i < len;i = i + 2){ /* y_points */
18557 bpr 6484
      if(i == len - 1){ sprintf(tmp, "%.*f",decimals,xy[i]);}else{sprintf(tmp, "%.*f,",decimals,xy[i]);}
6485
      space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6486
      if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}else{canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce your image size or plotsteps");}
15111 schaersvoo 6487
    }
6488
    strncat(temp,"]",2);
6489
    string=(char *)my_newmem(sizeof(temp));
6490
    snprintf(string,sizeof(temp),"%s",temp);
6491
    return string;
6492
}
7614 schaersvoo 6493
 
15111 schaersvoo 6494
char *list2js_array(char *list, char *s){/* abc:defg:hjiuy:qwer --> ["abc","defg","hjiuy","qwer"] */
6495
#define MAX_ARG 128
18562 bpr 6496
  if( strlen(list)> MAX_ARG - 1){canvas_error("argument is too large (&gt; 128)");}
6497
  char tmp[MAX_ARG];
6498
  size_t p = 0;
6499
  tmp[0] = '[';
6500
  tmp[1] = '\"';
6501
  size_t t = 2;
6502
  while(list[p] != '\0'){
6503
    if( list[p] == s[0] ){
6504
      tmp[t++]='\"';tmp[t++]=',';tmp[t++]='\"';
6505
    }
6506
    else
6507
    {
6508
      tmp[t++] = list[p];
6509
    }
6510
    p++;
15111 schaersvoo 6511
  }
18562 bpr 6512
  tmp[t++]='\"';tmp[t++]=']';tmp[t++]= '\0';
6513
  char *js_array = (char *)my_newmem(sizeof(tmp));
6514
  snprintf(js_array,sizeof(tmp),"%s",tmp);
6515
  return js_array;
15111 schaersvoo 6516
}
7963 schaersvoo 6517
 
15111 schaersvoo 6518
char *xy2js_array(int xy[],int len){
6519
 /*
6520
    1,2,3,4,5,6,7,8 --> [1,3,5,7],[2,4,6,8]
6521
    int xy[] is already checked for errors or overflow in "get_real()"
6522
    just to be sure we double check the size of "temp"
7614 schaersvoo 6523
*/
18562 bpr 6524
  char temp[MAX_BUFFER], *string;
6525
  char *tmp = my_newmem(16);/* <= 9999999999999999  */
6526
  memset(temp,'\0',MAX_BUFFER);/* clear memory */
6527
  int i;int space_left;
6528
  temp[0] = '[';/* start js-array */
6529
  for(i = 0; i < len;i = i + 2){ /*  x_points[] */
6530
    if(i == len - 2){sprintf(tmp, "%d", xy[i]);}else{sprintf(tmp, "%d,", xy[i]);}
6531
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6532
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6533
    else {
6534
    canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce image size or plotsteps ");}
6535
  }
6536
  strncat(temp,"],[",4); /* close js x_values array and start new */
6537
  for(i = 1; i < len;i = i + 2){ /* y_points */
6538
    if(i == len - 1){ sprintf(tmp, "%d", xy[i]);}else{sprintf(tmp, "%d,", xy[i]);}
6539
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6540
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6541
    else{canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data\nreduce image size or plotsteps \n");}
6542
  }
6543
  strncat(temp,"]",2);
6544
  string=(char *)my_newmem(sizeof(temp));
6545
  snprintf(string,sizeof(temp),"%s",temp);
6546
  return string;
7614 schaersvoo 6547
}
6548
 
15111 schaersvoo 6549
char *data2js_array(int data[],int len){
6550
 /*
6551
    1,2,3,4,5,6,7,8 --> [1,2,3,4,5,6,7,8]
6552
    int data[] is already checked for errors or overflow in "get_real()"
6553
    just to be sure we double check the size of "temp"
7614 schaersvoo 6554
*/
18562 bpr 6555
  char temp[MAX_BUFFER], *string;
6556
  char *tmp = my_newmem(16);/* <= 9999999999999999  */
6557
  memset(temp,'\0',MAX_BUFFER);/* clear memory */
6558
  int i;int space_left;
6559
  temp[0] = '[';/* start js-array */
6560
  for(i = 0; i < len; i++){
6561
    if(i == len - 1){sprintf(tmp, "%d", data[i]);}else{sprintf(tmp, "%d,", data[i]);}
6562
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6563
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6564
    else{
6565
    canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce image size or plotsteps ");
15111 schaersvoo 6566
    }
18562 bpr 6567
  }
6568
  strncat(temp,"]",2);
6569
  string=(char *)my_newmem(sizeof(temp));
6570
  snprintf(string,sizeof(temp),"%s",temp);
6571
  return string;
15111 schaersvoo 6572
}
7614 schaersvoo 6573
 
15111 schaersvoo 6574
char *doubledata2js_array(double data[],int len, int decimals){
6575
 /*
15116 bpr 6576
    1.4355,2.345353,3.3455 --> [1.44,2.35,3.35]
15111 schaersvoo 6577
    double data[] is already checked for errors or overflow in "get_real()"
6578
    just to be sure we double check the size of "temp"
8448 schaersvoo 6579
*/
18562 bpr 6580
  char temp[MAX_BUFFER], *string;
6581
  char *tmp = my_newmem(16);/* <= 9999999999999999  */
6582
  memset(temp,'\0',MAX_BUFFER);/* clear memory */
6583
  int i;int space_left;
6584
  temp[0] = '[';/* start js-array */
6585
  for(i = 0; i < len; i++){
6586
    if(i == len - 1){sprintf(tmp, "%.*f",decimals,data[i]);}
6587
    else{sprintf(tmp, "%.*f,",decimals,data[i]);}
6588
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6589
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6590
    else{
6591
      canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce image size or plotsteps ");}
6592
  }
6593
  strncat(temp,"]",2);
6594
  string=(char *)my_newmem(sizeof(temp));
6595
  snprintf(string,sizeof(temp),"%s",temp);
6596
  return string;
15111 schaersvoo 6597
}
13829 bpr 6598
 
15111 schaersvoo 6599
void *my_newmem(size_t size){
18562 bpr 6600
  void  *p;
6601
  if((p = malloc(size +1)) == NULL){canvas_error("canvasdraw: ran out of memory\n");}
6602
  return p;
15111 schaersvoo 6603
}
8224 bpr 6604
 
15111 schaersvoo 6605
int find_number_of_digits(int i){
18562 bpr 6606
  if(i < 0 ){ i = -1*i;}
6607
  int digits = 0;
6608
  while ( i > 0){
6609
    digits++;
6610
    i = i/10;
6611
  }
6612
  return digits;
15111 schaersvoo 6613
}
7645 schaersvoo 6614
 
16828 schaersvoo 6615
int count_substring(char* string, char* substring) {
18164 schaersvoo 6616
  int i, j, l1, l2;
16828 schaersvoo 6617
  int count = 0;
6618
  l1 = strlen(string);
6619
  l2 = strlen(substring);
6620
  for(i = 0; i < l1 - l2 + 1; i++) {
6621
    if(strstr(string + i, substring) == string + i) {
6622
      count++;
6623
      i = i + l2 -1;
6624
    }
6625
  }
6626
  return count;
6627
}
11830 schaersvoo 6628
 
7614 schaersvoo 6629
void check_string_length(int L){
18555 bpr 6630
  if( L > MAX_BUFFER-1){
6631
    canvas_error("problem with your arguments to command...");
6632
  }
6633
  return;
7614 schaersvoo 6634
}
18555 bpr 6635
/* useful in hyp commands: determine if the hypsegment is an arc or a line */
18615 bpr 6636
/* give a point on the arc */
18555 bpr 6637
int hypgeodaux(double *q, double* ress, int full){
6638
  double alpha,beta,gamma,r,cx,cy,a1,a2,a3,tmp,
6639
    nx = -q[0]*q[2]*q[2]+(q[0]*q[0]+q[1]*q[1]+1)*q[2]-q[0]*q[3]*q[3]-q[0],
6640
    ny = -q[1]*q[2]*q[2]-q[1]*q[3]*q[3]+(q[0]*q[0]+q[1]*q[1]+1)*q[3]-q[1],
6641
    dy = -2*q[1]*q[2]+2*q[0]*q[3];
6642
  if (dy*dy*1e4 <= nx*nx+ny*ny){
6643
    if(full){
6644
      if (q[1]*q[1]+q[0]*q[0] > q[2]*q[2]+q[3]*q[3])
6645
        gamma = atan2(q[1],q[0]);
6646
      else
6647
        gamma = atan2(q[3],q[2]);
6648
      ress[0]=cos(gamma); ress[1]=sin(gamma); ress[2]=-cos(gamma); ress[3]=-sin(gamma);
6649
    }
6650
    else
6651
      {int i;for(i=0;i<4;++i) ress[i]=q[i];}
18615 bpr 6652
    ress[6]=(q[0]+q[2])/2;
6653
    ress[7]=(q[1]+q[3])/2;
18555 bpr 6654
    return 0;}
6655
  cx = ny/dy; cy=-nx/dy;
6656
  r = sqrt(cx*cx+cy*cy-1);
6657
  if(full)
6658
    {alpha=atan(1/r); beta = atan2(cy,cx);a1=M_PI+beta-alpha;a2=M_PI+beta+alpha;}
6659
  else
6660
    {a1 = atan2(q[1]-cy, q[0]-cx);a2 = atan2(q[3]-cy, q[2]-cx);}
6661
  if (fabs(a2-a1)>M_PI){if(a1<a2) a1+=2*M_PI; else a2+=2*M_PI;};
6662
  a3 = (a1+a2)/2;
6663
  if(a1>a2) {tmp=a1; a1=a2; a2=tmp;}
6664
  ress[0]=cx;
6665
  ress[1]=cy;
6666
  ress[2]=2*r;
6667
  ress[3]=2*r;
6668
  ress[4]=360+180/M_PI*a1;
6669
  ress[5]=360+180/M_PI*a2;
6670
  ress[6]=cx+r*cos(a3);
6671
  ress[7]=cy+r*sin(a3);
6672
  return 1;
6673
}
7614 schaersvoo 6674
 
6675
int get_token(FILE *infile){
18589 bpr 6676
  int left,milieu,delta,right,c,i=0;
18562 bpr 6677
  char temp[MAX_INT], *input_type;
18589 bpr 6678
  enum{rien,usefilled,usedashed};
6679
  static struct commande {char *nom; int res; int special;} table[]=
6680
  {
6681
{"#",COMMENT,0},
6682
{"affine",AFFINE,0},
6683
{"allowdups",ALLOW_DUPLICATES,0},
6684
{"angle",ANGLE,0},
6685
{"animate",ANIMATE,0},
6686
{"arc",ARC,0},
6687
{"arcarrow",ARCARROW,0},
6688
{"arrow",ARROW,0},
6689
{"arrow2",ARROW2,0},
6690
{"arrowarc",ARCARROW,0},
6691
{"arrowhead",ARROWHEAD,0},
6692
{"arrows",ARROWS,0},
6693
{"arrows2",ARROWS2,0},
6694
{"audio",AUDIO,0},
6695
{"audioobject",AUDIOOBJECT,0},
6696
{"axis",AXIS,0},
6697
{"axisnumbering",AXIS_NUMBERING,0},
6698
{"axisnumbers",AXIS_NUMBERING,0},
6699
{"backgroundimage",BGIMAGE,0},
6700
{"barchart",BARCHART,0},
6701
{"bezier",BEZIER,0},
6702
{"bgcolor",BGCOLOR,0},
6703
{"bgimage",BGIMAGE,0},
6704
{"blink",BLINK,0},
6705
{"boxplot",BOXPLOT,0},
6706
{"boxplotdata",BOXPLOTDATA,0},
6707
{"brokenline",POLYLINE,0},
6708
{"canvastype",CANVASTYPE,0},
6709
{"centered",CENTERED,0},
6710
{"centerstring",CENTERSTRING,0},
6711
{"chemtex",CHEMTEX,0},
6712
{"circle",CIRCLE,0},
6713
{"circles",CIRCLES,0},
6714
{"clearbutton",CLEARBUTTON,0},
6715
{"clicktile",CLICKTILE,0},
6716
{"clicktile_colors",CLICKTILE_COLORS,0},
6717
{"clock",CLOCK,0},
6718
{"colorpalette",COLORPALETTE,0},
6719
{"colors",MULTISTROKECOLORS,0},
6720
{"copy",COPY,0},
6721
{"copyresized",COPYRESIZED,0},
6722
{"crosshair",CROSSHAIR,0},
6723
{"crosshairs",CROSSHAIRS,0},
6724
{"crosshairsize",CROSSHAIRSIZE,0},
6725
{"css",CSS,0},
6726
{"cursor",CURSOR,0},
6727
{"curve",CURVE,0},
6728
{"curvedarrow",CURVEDARROW,0},
6729
{"curvedarrow2",CURVEDARROW2,0},
6730
{"curvedarrows",CURVEDARROWS,0},
6731
{"curvedarrows2",CURVEDARROWS2,0},
6732
{"darrow",ARROW,usedashed},
6733
{"darrow2",ARROW2,usedashed},
6734
{"dashed",DASHED,0},
6735
{"dashtype",DASHTYPE,0},
6736
{"dcurve",CURVE,usedashed},
6737
{"delete",CLEARBUTTON,0},
6738
{"demiline",HALFLINE,0},
6739
{"demilines",HALFLINES,0},
6740
{"dhline",HLINE,usedashed},
6741
{"diafill",DIAMONDFILL,0},
6742
{"diamondfill",DIAMONDFILL,0},
6743
{"disk",CIRCLE,usefilled},
6744
{"disks",CIRCLES,usefilled},
6745
{"display",MOUSE_DISPLAY,0},
6746
{"dline",LINE,usedashed},
6747
{"dotfill",DOTFILL,0},
6748
{"dplot",CURVE,usedashed},
6749
{"dpolyline",POLYLINE,usedashed},
6750
{"drag",DRAG,0},
6751
{"dsegment",SEGMENT,usedashed},
6752
{"dsegments",SEGMENTS,usedashed},
6753
{"duplicates",ALLOW_DUPLICATES,0},
6754
{"dvline",VLINE,usedashed},
6755
{"ellipse",ELLIPSE,0},
6756
{"ellipses",ELLIPSES,0},
6757
{"end",END,0},
6758
{"erase",CLEARBUTTON,0},
6759
{"farc",ARC,usefilled},
6760
{"fcircle",CIRCLE,usefilled},
6761
{"fcircles",CIRCLES,usefilled},
6762
{"fellipse",ELLIPSE,usefilled},
6763
{"fhypcircles",HYPCIRCLES,usefilled},
18615 bpr 6764
{"fhyppolygon",HYPPOLY,usefilled},
18589 bpr 6765
{"fill",FLOODFILL,0},
6766
{"fillall",FILLALL,0},
6767
{"fillcolor",FILLCOLOR,0},
6768
{"fillcolors",MULTIFILLCOLORS,0},
6769
{"filled",FILLED,0},
6770
{"filledarc",ARC,usefilled},
6771
{"filledpoly",POLY,usefilled},
6772
{"filledpolygon",POLY,usefilled},
18608 bpr 6773
{"fillopacity",FILLOPACITY,0},
18589 bpr 6774
{"fillpattern",FILLPATTERN,0},
6775
{"filltoborder",FILLTOBORDER,0},
6776
{"floodfill",FLOODFILL,0},
6777
{"fontcolor",FONTCOLOR,0},
6778
{"fontfamily",FONTFAMILY,0},
6779
{"fontsize",FONTSIZE,0},
6780
{"fpoly",POLY,usefilled},
6781
{"fpolygon",POLY,usefilled},
6782
{"frect",RECT,usefilled},
6783
{"frectangle",RECT,usefilled},
6784
{"frects",RECTS,usefilled},
6785
{"froundrect",ROUNDRECT,usefilled},
6786
{"froundrects",ROUNDRECTS,usefilled},
6787
{"fsquare",SQUARE,usefilled},
6788
{"fsquares",RECTS,usefilled},
6789
{"ftriangle",TRIANGLE,usefilled},
6790
{"ftriangles",TRIANGLES,usefilled},
6791
{"functionlabel",FUNCTION_LABEL,0},
6792
{"functionlabels",FUNCTION_LABEL,0},
6793
{"grid",GRID,0},
6794
{"gridfill",GRIDFILL,0},
6795
{"group",GROUP,0},
6796
{"halfline",HALFLINE,0},
6797
{"halflines",HALFLINES,0},
6798
{"hatchfill",HATCHFILL,0},
6799
{"highlight",STYLE,0},
6800
{"hline",HLINE,0},
6801
{"hlines",HLINES,0},
6802
{"horizontalline",HLINE,0},
6803
{"horizontallines",HLINES,0},
6804
{"html",HTML,0},
6805
{"http",HTTP,0},
6806
{"hypcircles",HYPCIRCLES,0},
6807
{"hyplines",HYPLINES,0},
6808
{"hyppolygon",HYPPOLY,0},
6809
{"hyprays",HYPRAYS,0},
6810
{"hypsegments",HYPSEGMENTS,0},
6811
{"imagefill",IMAGEFILL,0},
6812
{"imagepalette",IMAGEPALETTE,0},
6813
{"input",INPUT,0},
6814
{"intooltip",INTOOLTIP,0},
6815
{"jscurve",JSCURVE,0},
6816
{"jsmath",JSMATH,0},
6817
{"jsplot",JSCURVE,0},
6818
{"katex",LATEX,0},
6819
{"kill",KILL,0},
6820
{"killaffine",KILLAFFINE,0},
6821
{"killgroup",KILLSLIDER,0},
6822
{"killinear",KILLLINEAR,0},
6823
{"killlinear",KILLLINEAR,0},
6824
{"killreset",NORESET,0},
6825
{"killrotate",KILLROTATE,0},
6826
{"killslider",KILLSLIDER,0},
6827
{"killtranslate",KILLTRANSLATION,0},
6828
{"killtranslation",KILLTRANSLATION,0},
6829
{"latex",LATEX,0},
6830
{"lattice",LATTICE,0},
6831
{"legend",LEGEND,0},
6832
{"legendcolors",LEGENDCOLORS,0},
6833
{"levelcurve",LEVELCURVE,0},
6834
{"line",LINE,0},
6835
{"linear",LINEAR,0},
6836
{"linegraph",LINEGRAPH,0},
6837
{"lines",LINES,0},
6838
{"linewidth",LINEWIDTH,0},
6839
{"linewidths",MULTILINEWIDTH,0},
6840
{"math",LATEX,0},
6841
{"mathml",MATHML,0},
6842
{"mouse",MOUSE,0},
6843
{"mousedegree",MOUSE_DEGREE,0},
6844
{"mouseprecision",MOUSE_PRECISION,0},
6845
{"mousex",MOUSEX,0},
6846
{"mousey",MOUSEY,0},
6847
{"multicolors",MULTISTROKECOLORS,0},
6848
{"multidash",MULTIDASH,0},
6849
{"multidraw",MULTIDRAW,0},
6850
{"multifill",MULTIFILL,0},
6851
{"multifillcolors",MULTIFILLCOLORS,0},
6852
{"multifillopacity",MULTIFILLOPACITY,0},
6853
{"multiinput",MULTIUSERINPUT,0},
6854
{"multilabel",MULTILABEL,0},
6855
{"multilinewidth",MULTILINEWIDTH,0},
6856
{"multisnap",MULTISNAPTOGRID,0},
6857
{"multisnaptogrid",MULTISNAPTOGRID,0},
6858
{"multistrokecolors",MULTISTROKECOLORS,0},
6859
{"multistrokeopacity",MULTISTROKEOPACITY,0},
6860
{"multiuserinput",MULTIUSERINPUT,0},
6861
{"newrange",NEWRANGE,0},
6862
{"noreset",NORESET,0},
6863
{"nostatus",STATUS,0},
6864
{"noxaxis",NOXAXIS,0},
6865
{"noyaxis",NOYAXIS,0},
6866
{"numberline",NUMBERLINE,0},
6867
{"obabel",OBABEL,0},
6868
{"onclick",ONCLICK,0},
6869
{"opacity",OPACITY,0},
6870
{"parallel",PARALLEL,0},
6871
{"path",POLYLINE,0},
6872
{"patternfill",PATTERNFILL,0},
6873
{"piechart",PIECHART,0},
6874
{"pixels",PIXELS,0},
6875
{"pixelsize",PIXELSIZE,0},
6876
{"plot",CURVE,0},
6877
{"plotstep",PLOTSTEPS,0},
6878
{"plotsteps",PLOTSTEPS,0},
6879
{"point",POINT,0},
6880
{"pointer",CURSOR,0},
6881
{"points",POINTS,0},
6882
{"poly",POLY,0},
6883
{"polygon",POLY,0},
6884
{"polyline",POLYLINE,0},
6885
{"popup",POPUP,0},
6886
{"precision",MOUSE_PRECISION,0},
6887
{"protractor",PROTRACTOR,0},
6888
{"range",RANGE,0},
6889
{"ranget",TRANGE,0},
6890
{"rangex",XRANGE,0},
6891
{"rangey",YRANGE,0},
6892
{"rays",RAYS,0},
6893
{"rect",RECT,0},
6894
{"rectangle",RECT,0},
6895
{"rects",RECTS,0},
6896
{"replyformat",REPLYFORMAT,0},
6897
{"reset",RESET,0},
6898
{"resetoffset",RESETOFFSET,0},
6899
{"rotate",ROTATE,0},
6900
{"rotationcenter",ROTATION_CENTER,0},
6901
{"roundrect",ROUNDRECT,0},
6902
{"roundrectangle",ROUNDRECT,0},
6903
{"roundrects",ROUNDRECTS,0},
6904
{"ruler",RULER,0},
6905
{"seg",SEGMENT,0},
6906
{"segment",SEGMENT,0},
6907
{"segments",SEGMENTS,0},
6908
{"segs",SEGMENTS,0},
6909
{"setlimits",SETLIMITS,0},
6910
{"setpixel",SETPIXEL,0},
6911
{"settile",FILLPATTERN,0},
6912
{"sgraph",SGRAPH,0},
6913
{"size",SIZE,0},
6914
{"slider",SLIDER,0},
6915
{"snaptofun",SNAPTOFUNCTION,0},
6916
{"snaptofunction",SNAPTOFUNCTION,0},
6917
{"snaptogrid",SNAPTOGRID,0},
6918
{"snaptopoints",SNAPTOPOINTS,0},
6919
{"square",SQUARE,0},
6920
{"status",STATUS,0},
6921
{"string",STRING,0},
6922
{"stringup",STRINGUP,0},
6923
{"strokecolor",STROKECOLOR,0},
6924
{"strokecolors",MULTISTROKECOLORS,0},
18608 bpr 6925
{"strokeopacity",STROKEOPACITY,0},
18589 bpr 6926
{"style",STYLE,0},
6927
{"text",FLY_TEXT,0},
6928
{"textarea",TEXTAREA,0},
6929
{"textfill",TEXTFILL,0},
6930
{"textup",FLY_TEXTUP,0},
6931
{"title",CENTERSTRING,0},
6932
{"trace_jscurve",TRACE_JSCURVE,0},
6933
{"trange",TRANGE,0},
6934
{"translate",TRANSLATION,0},
6935
{"translation",TRANSLATION,0},
6936
{"transparent",OPACITY,0},
6937
{"triangle",TRIANGLE,0},
6938
{"triangles",TRIANGLES,0},
6939
{"tsteps",PLOTSTEPS,0},
6940
{"userboxplot",USERBOXPLOT,0},
6941
{"userboxplotdata",USERBOXPLOT,0},
6942
{"userdraw",USERDRAW,0},
6943
{"userinput",USERINPUT,0},
6944
{"userinput_function",USERINPUT_FUNCTION,0},
6945
{"userinput_xy",USERINPUT_XY,0},
6946
{"vector",ARROW,0},
6947
{"vectors",ARROWS,0},
6948
{"verticalline",VLINE,0},
6949
{"verticallines",VLINES,0},
6950
{"video",VIDEO,0},
6951
{"vline",VLINE,0},
6952
{"vlines",VLINES,0},
6953
{"xaxis",X_AXIS_STRINGS,0},
6954
{"xaxistext",X_AXIS_STRINGS,0},
6955
{"xaxistextup",X_AXIS_STRINGS_UP,0},
6956
{"xaxisup",X_AXIS_STRINGS_UP,0},
6957
{"xerrorbars",XERRORBARS,0},
6958
{"xlabel",XLABEL,0},
6959
{"xlogbase",XLOGBASE,0},
6960
{"xlogscale",XLOGSCALE,0},
6961
{"xoffset",XOFFSET,0},
6962
{"xrange",XRANGE,0},
6963
{"xsnaptogrid",XSNAPTOGRID,0},
6964
{"xunit",XUNIT,0},
6965
{"xylogscale",XYLOGSCALE,0},
6966
{"xyoffset",XYOFFSET,0},
6967
{"yaxis",Y_AXIS_STRINGS,0},
6968
{"yaxistext",Y_AXIS_STRINGS,0},
6969
{"yerrorbars",YERRORBARS,0},
6970
{"ylabel",YLABEL,0},
6971
{"ylogbase",YLOGBASE,0},
6972
{"ylogscale",YLOGSCALE,0},
6973
{"yoffset",YOFFSET,0},
6974
{"yrange",YRANGE,0},
6975
{"ysnaptogrid",YSNAPTOGRID,0},
6976
{"yunit",YUNIT,0},
6977
{"zoom",ZOOM,0}
6978
  };
7614 schaersvoo 6979
 
18552 bpr 6980
  while(((c = getc(infile)) != EOF)&&(c!='\n')&&(c!=',')&&(c!='=')&&(c!='\r')&&(c!='\t')){
6981
   if( i == 0 && (c == ' ') ){ continue; /* white spaces or tabs allowed before first command identifier */
6982
   }else{
6983
    if( c == ' ' ){
6984
      break;
6985
    }else{
6986
     temp[i] = c;
6987
     if(i > MAX_INT - 2){canvas_error("command string too long !");}
6988
     i++;
6989
    }
6990
   }
6991
   if(temp[0] == '#'){ break; }
6992
  }
6993
  if (c == '\n' || c == '\r' || c == '\t' ){  line_number++; }
6994
  if (c == EOF) {finished=1;return 0;}
7614 schaersvoo 6995
 
18552 bpr 6996
  temp[i]='\0';
6997
  if(strstr(temp,"dash") !=0 && strlen(temp) > 4 && strstr(temp,"dashtype") == 0 ){
6998
  /* 4/2024 adapt to Flydraw's dashing syntax for all objects with prefix "dash" */
6999
      use_dashed = TRUE;int idx=0;int p;
7000
      for( p = 4; p < strlen(temp); p++){temp[idx] = temp[p];idx++;}
7001
      input_type = (char*)my_newmem(idx); snprintf(input_type,idx+1,"%s",temp);
7002
  }else{
7003
      input_type=(char*)my_newmem(strlen(temp));
7004
      snprintf(input_type,sizeof(temp),"%s",temp);
7005
  }
18572 bpr 7006
/*  fprintf(stdout,"input_type = %s no_reset = %d <br>",input_type,no_reset);*/
18589 bpr 7007
 
7008
  left=0; right=sizeof(table)/sizeof(struct commande);
7009
  while (left<right){
7010
    milieu = (left+right)/2;
7011
    delta = strcmp(input_type, table[milieu].nom);
7012
    if (delta == 0){
7013
             free(input_type);
7014
             if (table[milieu].special==usefilled) use_filled=TRUE;
7015
             if (table[milieu].special==usedashed) use_dashed=TRUE;
7016
             return table[milieu].res;
7017
          }
7018
    if (delta<0) right=milieu; else left=milieu+1;
18552 bpr 7019
  }
7020
  free(input_type);
18562 bpr 7021
  ungetc(c,infile);
7022
  return 0;
7614 schaersvoo 7023
}