Subversion Repositories wimsdev

Rev

Rev 18641 | 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
  */
18641 bpr 340
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 341
          for(i=0;i<7;i++){
342
            switch(i){
343
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
344
              case 1:double_data[1] = get_real(infile,0);
345
              if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
346
              if(use_affine == TRUE ){ transform(4,2);}
347
              break; /* y-values */
348
              case 2:double_data[2] = get_real(infile,0);break; /* width x-range no pixels ! */
349
              case 3:double_data[3] = get_real(infile,0);
350
              break; /* height y-range no pixels ! */
351
              case 4:double_data[4] = get_real(infile,0) - angle ;break; /* start angle in degrees */
352
              case 5:double_data[5] = get_real(infile,0) - angle;break; /* end angle in degrees */
353
              case 6:stroke_color = get_color(infile,1);/* name or hex color */
354
        /* in Shape library:
355
      x[0] = x[1] = xc = double_data[0]
356
      y[0] = y[1] = yc = double_data[1]
357
      w[0] = width = double_data[2]
358
      w[1] = height = double_data[3]
359
      h[0] = start_angle = double_data[4]
360
      h[1] = end_angle = double_data[5]
361
        */
18555 bpr 362
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
363
                decimals = find_number_of_digits(precision);
18557 bpr 364
 
365
                tmp_buffer=my_newmem(MAX_BUFFER);
366
                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 367
                add_to_buffer(tmp_buffer);reset();
368
                dragstuff[12] = 1;
369
                if(onclick != 0){object_cnt++;}
370
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
18552 bpr 371
              break;
372
            }
373
          }
374
          break;
375
        case ARCARROW:
376
  /*
18556 bpr 377
  @ arrowarc xc,yc,x-width,y-height,start_angle,end_angle,color,type
378
  @ alternative: arcarrow
379
  @ uses same syntax as <a href='#arc'>arc</a>
380
  @ for arrow hat: type = 1 : right<br>type = 2 : left<br>type = 3 : left&amp;right
381
  @ if the default arrow hat/head is not satisfactory , the size of the arrow may be set with command <a href='#arrowhead'>arrowhead</a>
382
  @ no other arrow types are implemented...yet
383
  @ may be set draggable or onclick
384
  @ 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)
385
  @%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 386
  */
387
          for(i=0;i<8;i++){
388
            switch(i){
389
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
390
              case 1:double_data[1] = get_real(infile,0);
391
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
392
                if(use_affine == TRUE ){ transform(4,2);}
393
                break; /* y-values */
394
              case 2:double_data[2] = get_real(infile,0);break; /* width x-range no pixels ! */
395
              case 3:double_data[3] = get_real(infile,0);
396
                break; /* height y-range no pixels ! */
397
              case 4:double_data[4] = get_real(infile,0) - angle ;break; /* start angle in degrees */
398
              case 5:double_data[5] = get_real(infile,0) - angle;break; /* end angle in degrees */
399
              case 6:stroke_color = get_color(infile,0);/* name or hex color */
400
                break;
401
              case 7:int_data[0] = (int) get_real(infile,1);
402
                switch(int_data[0]){
403
                  case 1: int_data[1] = 24;break; /* right */
404
                  case 2: int_data[1] = 25;break; /* left */
405
                  case 3: int_data[1] = 26;break; /* left&right */
406
                  default:int_data[1] = 24;break;
407
                }
408
              if(int_data[0] == 1 ){int_data[1] = 24;}
409
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
410
              decimals = find_number_of_digits(precision);
18557 bpr 411
 
412
              tmp_buffer=my_newmem(MAX_BUFFER);
413
              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 414
              add_to_buffer(tmp_buffer);
415
              dragstuff[int_data[1]] = 1;
416
              if(onclick != 0){object_cnt++;}
417
              if(use_dragstuff == 0 ){ use_dragstuff = 1; }
418
              js_function[JS_ARROWHEAD] = 1;
419
              reset();
420
            }
421
          }
422
          break;
423
        case ARROW:
424
  /*
425
  @ arrow x1,y1,x2,y2,h,color
426
  @ alternative: vector
427
  @ draw a single headed arrow / vector from (x1:y1) to (x2:y2)<br>with arrowhead size h in px and in color ''color``
428
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
429
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
430
  @%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
431
  @%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
432
  */
433
          for(i=0;i<6;i++){
434
            switch(i){
435
              case 0: double_data[0] = get_real(infile,0);break; /* x */
436
              case 1: double_data[1] = get_real(infile,0);break; /* y */
437
              case 2: double_data[2] = get_real(infile,0);break; /* x */
438
              case 3: double_data[3] = get_real(infile,0);break; /* y */
439
              case 4: arrow_head = (int) get_real(infile,0);break;/* h */
440
              case 5: stroke_color = get_color(infile,1);/* name or hex color */
441
                if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
442
                if(use_affine == TRUE ){ transform(4,2);}
443
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
444
                decimals = find_number_of_digits(precision);
18557 bpr 445
                tmp_buffer=my_newmem(MAX_BUFFER);
446
                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 447
                if(onclick != 0){object_cnt++;}
448
          /* object_cnt++;*/
449
                add_to_buffer(tmp_buffer);reset();
450
                dragstuff[8] = 1;
451
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
452
              break;
453
            }
454
          }
455
          break;
456
        case ARROWS:
457
  /*
458
  @ arrows color,head (px),x1,y1,x2,y2...x_n,y_n
459
  @ alternative: vectors
460
  @ draw single headed arrows / vectors from (x1:y1) to (x2:y2) ... (x3:y3) to (x4:y4) etc ... in color 'color'
461
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
462
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
463
  @%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%
464
  @%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%
465
  @%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%
466
  */
467
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
468
          fill_color = stroke_color;
469
          arrow_head = (int) get_real(infile,0);/* h */
470
          i=0;
471
          while( ! done ){     /* get next item until EOL*/
472
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
473
            if(i%2 == 0 ){
474
              double_data[i] = get_real(infile,0); /* x */
475
            } else {
476
              double_data[i] = get_real(infile,1); /* y */
477
            }
478
          i++;
479
          }
480
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
481
          if( use_affine == TRUE ){ transform(i-1,2);}
482
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
483
          decimals = find_number_of_digits(precision);
484
          for(c = 0 ; c < i-1 ; c = c+4){
18557 bpr 485
            tmp_buffer=my_newmem(MAX_BUFFER);
486
            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 487
            add_to_buffer(tmp_buffer);
488
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
489
          }
490
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
491
          dragstuff[8] = 1;
492
          reset();
493
          break;
494
        case ARROW2:
495
  /*
496
  @ arrow2 x1,y1,x2,y2,h,color
497
  @ draw a double headed arrow/vector from (x1:y1) to (x2:y2)<br>with arrowhead size h in px and in color ''color``
498
  @ use command <code>arrowhead int</code> to adjust the arrow head size
499
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
500
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
501
  @%arrow2%size 400,400%xrange -10,10%yrange -10,10%drag xy%arrow2 0,0,4,3,8,blue%
502
  */
503
          for(i=0;i<6;i++){
504
            switch(i){
505
              case 0: double_data[0] = get_real(infile,0);break; /* x */
506
              case 1: double_data[1] = get_real(infile,0);break; /* y */
507
              case 2: double_data[2] = get_real(infile,0);break; /* x */
508
              case 3: double_data[3] = get_real(infile,0);break; /* y */
509
              case 4: arrow_head = (int) get_real(infile,0);break;/* h */
510
              case 5: stroke_color = get_color(infile,1);/* name or hex color */
511
                if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
512
                if( use_affine == 1 ){ transform(4,2);}
513
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
514
                decimals = find_number_of_digits(precision);
18557 bpr 515
                tmp_buffer=my_newmem(MAX_BUFFER);
516
                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 517
                add_to_buffer(tmp_buffer);
518
                if(onclick != 0){object_cnt++;}/* object_cnt++;*/
519
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
520
                dragstuff[10] = 1;
521
                reset();
522
                break;
523
            }
524
          }
525
          break;
526
        case ARROWS2:
527
  /*
528
  @ arrows2 color,head (px),x1,y1,x2,y2...x_n,y_n
529
  @ draw double headed arrows / vectors from (x1:y1) to (x2:y2) ... (x3:y3) to (x4:y4) etc ... in color ''color``
530
  @ use command <code>linewidth int</code> to adjust thickness of the arrows
531
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
532
  @%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%
533
  */
534
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
535
          fill_color = stroke_color;
536
          arrow_head = (int) get_real(infile,0);/* h */
537
          i=0;
538
          while( ! done ){     /* get next item until EOL*/
539
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
540
            if(i%2 == 0 ){
541
              double_data[i] = get_real(infile,0); /* x */
542
            } else {
543
              double_data[i] = get_real(infile,1); /* y */
544
            }
545
            i++;
546
          }
547
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
548
          if( use_affine == 1 ){ transform(i-1,2);}
549
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
8386 schaersvoo 550
 
18552 bpr 551
          decimals = find_number_of_digits(precision);
552
          for(c = 0 ; c < i-1 ; c = c+4){
18557 bpr 553
            tmp_buffer=my_newmem(MAX_BUFFER);
554
            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 555
            add_to_buffer(tmp_buffer);
556
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
557
          }
558
          dragstuff[10] = 1;
559
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
560
          reset();
561
          break;
562
        case ARROWHEAD:
563
  /*
564
  @ arrowhead int
565
  @ default 8 (pixels)
566
  */
567
          arrow_head = (int) (get_real(infile,1));
568
          break;
569
        case AUDIO:
570
  /*
571
  @ audio x,y,w,h,loop,visible,audiofile location
572
  @ x,y: left top corner of audio element (in xrange / yrange)
573
  @ w,y: width and height in pixels
574
  @ loop: 0 or 1 ( 1 = loop audio fragment)
575
  @ visible: 0 or 1 (1 = show controls)
576
  @ audio format may be in *.mp3 or *.ogg
577
  @ If you are using *.mp3: be aware that FireFox will not (never) play this ! (Pattented format)
578
  @ if you are using *.ogg: be aware that Microsoft based systems not support it natively
579
  @ To avoid problems supply both types (mp3 and ogg) of audiofiles.<br>the program will use both as source tag
580
  */
581
          js_function[DRAW_AUDIO] = 1;
582
          for(i=0;i<7;i++){
583
            switch(i){
584
              case 0: int_data[0] = x2px(get_real(infile,0)); break; /* x in x/y-range coord system -> pixel */
585
              case 1: int_data[1] = y2px(get_real(infile,0)); break; /* y in x/y-range coord system  -> pixel */
586
              case 2: int_data[2] = (int) (get_real(infile,0)); break; /* pixel width */
587
              case 3: int_data[3] = (int) (get_real(infile,0)); break; /* height pixel height */
588
              case 4: int_data[4] = (int) (get_real(infile,0)); if(int_data[4] != TRUE){int_data[4] = FALSE;} break; /* loop boolean */
589
              case 5: int_data[5] = (int) (get_real(infile,0)); if(int_data[5] != TRUE){int_data[5] = FALSE;} break; /* visible boolean */
590
              case 6:
591
                temp = get_string(infile,1);
592
                if( strstr(temp,".mp3") != 0 ){ temp = str_replace(temp,".mp3","");}
593
                if( strstr(temp,".ogg") != 0 ){ temp = str_replace(temp,".ogg","");}
18557 bpr 594
                tmp_buffer=my_newmem(MAX_BUFFER);
595
              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 596
                add_to_buffer(tmp_buffer);
597
                break;
598
              default:break;
599
            }
600
          }
601
          reset();
602
          break;
603
        case AXIS_NUMBERING:
604
  /*
18556 bpr 605
  @ axisnumbering
606
  @ keyword (no arguments required)
607
  @ 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>
608
  @ to be used before command grid (see <a href="#grid">command grid</a>)
18552 bpr 609
  */
610
          use_axis_numbering++;
611
          break;
612
        case AXIS:
613
  /*
18556 bpr 614
  @ axis
615
  @ keyword (no arguments required)
616
  @ to be used before command grid (see <a href="#grid">command grid</a>)
8386 schaersvoo 617
 
18552 bpr 618
  */
619
          use_axis = TRUE;
620
          break;
621
        case BARCHART:
622
  /*
623
  @ barchart x_1:y_1:color_1:x_2:y_2:color_2:...x_n:y_n:color_n
624
  @ may <b>only</b> to be used together with command <a href='#grid'>grid</a>
625
  @ 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>
626
  @ use command <a href='#legend'>legend</a> to provide an optional legend in right-top-corner
627
  @ multiple barchart command may be used in a single script
628
  @ also see command <a href='#piechart'>piechart</a>
629
  @ note: your arguments are not checked by canvasdraw: use your javascript console in case of trouble...
630
  @%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
631
  */
632
          temp = get_string(infile,1);
633
          if( strstr( temp,":" ) != 0 ){ temp = str_replace(temp,":","\",\""); }
634
          fprintf(js_include_file,"var barchart_%d = [\"%s\"];",barchart_cnt,temp);
635
          barchart_cnt++;
636
          reset();
637
          break;
638
        case BEZIER:
639
  /*
640
  @ bezier color,x_start,y_start,x_first,y_first,x_second,y_second,x_end,y_end
641
  @ draw a bezier curve between points, starting from (x_start:y_start)
642
  @ can <b>not</b> be dragged or set onclick
643
  */
644
          js_function[DRAW_BEZIER] = 1;
645
          decimals = find_number_of_digits(precision);
646
          for(i = 0 ; i < 9; i++){
647
            switch(i){
648
              case 0: stroke_color = get_color(infile,0);break;
649
              case 1: double_data[0] = get_real(infile,0);break;/* start x */
650
              case 2: double_data[1] = get_real(infile,0);break;/* start y */
651
              case 3: double_data[2] = get_real(infile,0);break;/*The x-coordinate of the first Bézier control point */
652
              case 4: double_data[3] = get_real(infile,0);break;/*The y-coordinate of the first Bézier control point */
653
              case 5: double_data[4] = get_real(infile,0);break;/*The x-coordinate of the second Bézier control point */
654
              case 6: double_data[5] = get_real(infile,0);break;/*The y-coordinate of the second Bézier control point */
655
              case 7: double_data[6] = get_real(infile,0);break;/*The x-coordinate of the Bézier end point */
656
              case 8: double_data[7] = get_real(infile,1);/*The y-coordinate of the Bézier end point */
657
                if(use_rotate == TRUE ){rotate(8,angle,rotationcenter,2);}
658
                if(use_affine == TRUE ){ transform(2,5);}
18557 bpr 659
                tmp_buffer=my_newmem(MAX_BUFFER);
660
                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 661
                add_to_buffer(tmp_buffer);
662
                break;
663
              default: break;
664
            }
665
          }
666
          reset();
667
          break;
668
        case BGCOLOR:
669
  /*
18556 bpr 670
  @ bgcolor colorname or #hex
671
  @ use this color as background of the "div" containing the canvas(es)
672
  @%bgcolor%size 400,400%xrange -10,10%yrange -10,10%bgcolor lightblue
18552 bpr 673
  */
674
  /* [255,255,255]*/
675
          bgcolor = get_string(infile,1);
676
          if(strstr(bgcolor,"#") == NULL){ /* convert colorname -> #ff00ff */
677
            int found = 0;
678
            for( i = 0; i < NUMBER_OF_COLORNAMES ; i++ ){
679
              if( strcmp( colors[i].name , bgcolor ) == 0 ){
680
                bgcolor = colors[i].hex;
681
                found = 1;
682
              break;
683
              }
684
            }
685
            if(found == 0){canvas_error("your bgcolor is not in my rgb.txt data list: use hexcolor...something like #a0ffc4");}
686
          }
687
          fprintf(js_include_file,"/* set background color of canvas div */\ncanvas_div.style.backgroundColor = \"%s\";canvas_div.style.opacity = %f;\n",bgcolor,fill_opacity);
688
          break;
689
        case BGIMAGE:
690
  /*
18556 bpr 691
  @ bgimage image_location
692
  @ use an image as background; technical: we use the background of ''canvas_div``
693
  @ the background image will be resized to match "width = xsize" and "height = ysize"
694
  @%bgimage%size 400,400%xrange -10,10%yrange -10,10%bgimage https://wims.unice.fr/wims/gifs/en.gif
18552 bpr 695
  */
696
          URL = get_string(infile,1);
697
          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);
698
          break;
699
        case BLINK:
700
  /*
18556 bpr 701
  @ blink time(seconds)
702
  @ NOT IMPLEMETED -YET
18552 bpr 703
  */
704
          break;
705
        case BOXPLOT:
706
  /*
707
  @ boxplot x_or_y,box-height_or_box-width,position,min,Q1,median,Q3,max
708
  @ 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
709
  @ 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
710
  @ 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
711
  @ use command <a href='#fillpattern'>fillpattern some_pattern</a> to use a (diamond for Q1, hatch for Q3) pattern.
18627 bpr 712
  @ use command <a href='#opacity'>opacity</a> to adjust fill_opacity of stroke and fill colors
18552 bpr 713
  @ 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.
714
  @ there is no limit to the number of boxplots used.
715
  @ can <b>not</b> be set draggable and <a href='#onclick'>onclick</a> is not ready yet
716
  @ 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)
717
  @ use keyword <a href="#userboxplotdata">userboxplotdata</a> before command boxplot, if a pupil must generate the data by some means.
718
  @ use command <a href="#boxplotdata">boxplotdata</a> when the boxplot should be drawn from wims-generated raw statistical date
719
  @%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
720
  @%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
721
  @%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
722
  */
723
          js_function[DRAW_BOXPLOT] = 1;
724
          for(i=0;i<8;i++){
725
            switch(i){
726
              case 0: temp = get_string_argument(infile,0);
727
                if( strstr(temp,"x") != 0){int_data[0] = 1;}else{int_data[0] = 0;} break; /* x or y */
728
              case 1: double_data[0] = get_real(infile,0);break;/* height | width  */
729
              case 2:
730
                if( js_function[DRAW_JSBOXPLOT] == 0 ){
731
                  double_data[1] = get_real(infile,0);
732
                  fprintf(js_include_file,"var boxplot_source = 0;\n");/* we use given min,Q1,median,Q3,max */
733
                }
734
                else {
735
                  double_data[1] = get_real(infile,1);
736
                  double_data[2] = 1;
737
                  double_data[3] = 1;
738
                  double_data[4] = 1;
739
                  double_data[5] = 1;
740
                  double_data[6] = 1;
741
                  double_data[7] = 1;
742
                  i=8;
743
                }
744
                break;/* center value x or y */
745
              case 3: double_data[2] = get_real(infile,0); break;/* min */
746
              case 4: double_data[3] = get_real(infile,0); break;/* Q1 */
747
              case 5: double_data[4] = get_real(infile,0); break;/* median */
748
              case 6: double_data[5] = get_real(infile,0); break;/* Q3 */
749
              case 7: double_data[6] = get_real(infile,1); break;/* max */
750
              default:break;
751
            }
752
          }
753
          decimals = find_number_of_digits(precision);
754
          /*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 755
          tmp_buffer=my_newmem(MAX_BUFFER);
756
          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 757
          add_to_buffer(tmp_buffer);
758
          boxplot_cnt++;
759
          reset();
760
          break;
761
        case BOXPLOTDATA:
762
  /*
763
  @ boxplotdata some_data
764
  @ 'some_data' are a list of numbers separated by a comma "," (items)
765
  @ only be used before command <code>boxplot</code>: the command <a href="#boxplot">boxplot</a> will provide the boxplot drawing of the data.
766
  @ 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
767
  @ note: wims will not check your data input | format. use js-error console to debug any problems.
768
  @ 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.
769
  @ 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>
770
  @%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
771
  */
772
          js_function[DRAW_JSBOXPLOT] = 1;
773
          js_function[DRAW_BOXPLOT] = 1;
774
          fprintf(js_include_file,"var boxplot_source = 1;var jsboxplot_data = [%s];\n",get_string(infile,1));
775
          break;
776
        case CANVASTYPE:
777
          canvas_type = (int) (get_real(infile,1));
778
  /*
779
  @ canvastype TYPE
780
  @ for now only useful before commands filltoborder / floodfill / clickfill etc operations<br>Only the images of this TYPE will be scanned and filled
781
  @ default value of TYPE is DRAG_CANVAS e.g. 5 (all clickable / draggable object are in this canvas)
782
  @ use another TYPE, if you know what you are doing...
18627 bpr 783
  @ 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 784
  */
785
          break;
786
        case CENTERED:
787
          use_offset = 4;
788
   /*
18556 bpr 789
  @ centered
790
  @ keyword ; to place the text centered (in width and height) on the text coordinates(x:y)
791
  @ may be used for text exactly centered on its (x;y)
792
  @ use <a href="#fontfamily">fontfamily</a> for setting the font
793
  @ 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``)
794
  @%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 795
  */
18556 bpr 796
          break;
18552 bpr 797
        case CENTERSTRING:
798
  /*
18556 bpr 799
  @ centerstring color,y-value,the text string
800
  @ title color,y-value,the text string
801
  @ draw a string centered on the canvas at y = y-value
802
  @ can not be set ''onclick`` or ''drag xy`` (...)
803
  @ unicode supported: <code>centerstring red,5,\\u2232</code>
804
  @ use a command like <code>fontfamily italic 24pt Arial</code> to set fonts on browser that support font change
805
  @%centerstring%size 400,400%xrange -10,10%yrange -10,10%bgcolor lightblue%fontfamily italic 22pt Courier%centerstring blue,7,the center
18552 bpr 806
  */
807
          js_function[DRAW_CENTERSTRING] = 1;
808
          for(i=0;i<3;i++){
809
            switch(i){
810
              case 0: stroke_color = get_color(infile,0);break;/* name or hex color */
811
              case 1: double_data[0] = get_real(infile,0);break; /* y in xrange*/
812
              case 2: temp = get_string_argument(infile,1);
813
                /* draw_text = function(canvas_type,y,font_family,stroke_color,stroke_opacity,text) */
814
                decimals = find_number_of_digits(precision);
18557 bpr 815
                tmp_buffer=my_newmem(MAX_BUFFER);
816
                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 817
                add_to_buffer(tmp_buffer);
818
                break;
819
              default:break;
820
            }
821
          }
822
          break;
823
        case CHEMTEX:
824
  /*
825
  chemtex
826
  keyword...needs to be the first command in the script (even before the ''size`` command)
827
  only for KaTeX enabled typesetting !
828
  will include 80kB large js-library for chemisty typesetting
829
  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>
830
  using MathJaX : <code>latex x,y,\\ce{ chemistry tex code} like : \\ce{ Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2- }</code>
831
  see https://mhchem.github.io/MathJax-mhchem/
832
  %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-}
833
  */
834
          found_size_command = 1;
835
          fprintf(stdout,"\n<script src=\"scripts/js/KaTeX/mhchem.js\" defer></script>\n");
836
          break;
8386 schaersvoo 837
 
18552 bpr 838
        case CIRCLE:
839
  /*
840
  @ circle xc,yc,width (2*r in pixels),color
841
  @ use command <code>fcircle xc,yc,d,color</code>
842
  @ alternative: disk
843
  @ use command <code>fillcolor color</code> to set the fillcolor
844
  @ may be set <a href='#drag'>draggable</a> / <a href='#onclick'>onclick</a>
845
  @ will shrink / expand on zoom out / zoom in
846
  @%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
847
  */
848
          for(i=0;i<4;i++){
849
            switch(i){
850
              case 0: double_data[0] = get_real(infile,0);break; /* x */
851
              case 1: double_data[1] = get_real(infile,0);break; /* y */
852
              case 2: double_data[2] = px2x((get_real(infile,0))/2) - px2x(0);break; /* for zoom in/out: radius in 'dx' xrange*/
853
              case 3: stroke_color = get_color(infile,1);/* name or hex color */
18623 bpr 854
                if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 855
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
856
                if(use_affine == TRUE ){ transform(2,2);}
857
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
858
                decimals = find_number_of_digits(precision);
18557 bpr 859
                tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 860
                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 861
                add_to_buffer(tmp_buffer);
862
                if(onclick != 0){object_cnt++;}/* object_cnt++;*/
863
                dragstuff[13] = 1;
864
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
865
                reset();
866
                break;
867
              default : break;
868
            }
869
          }
870
          break;
871
        case CIRCLES:
872
  /*
873
  @ circles color,xc1,yc1,r1,xc2,yc2,r2...xc_n,yc_n,r_n
874
  @ <b>attention</b> r = radius in x-range (!)
875
  @ use keyword <code>filled</code> or command <code>fcircles</code> to produce solid circles
876
  @ alternative: disks
877
  @ use command <code>fillcolor color</code> to set the fillcolor
878
  @ may be set <a href='#drag'>draggable</a> / <a href='#onclick'>onclick</a> (individually)
879
  @ will shrink / expand on zoom out / zoom in
880
  @%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
881
  @%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
882
  @%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
883
  */
884
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
18623 bpr 885
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 886
          i=1;
887
          while( ! done ){     /* get next item until EOL*/
888
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
889
            switch (i%3){
890
              case 1:double_data[i-1] = get_real(infile,0);break; /* x */
891
              case 2:double_data[i-1] = get_real(infile,0);break; /* y */
892
              case 0:double_data[i-1] = get_real(infile,1);break; /* r */
893
            }
894
            i++;
895
          }
896
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,3);}
897
          if(use_affine == TRUE ){ transform(i-1,3);}
898
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
8386 schaersvoo 899
 
18552 bpr 900
          decimals = find_number_of_digits(precision);
901
          for(c = 0 ; c < i-1 ; c = c+3){
18557 bpr 902
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 903
            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 904
            add_to_buffer(tmp_buffer);
905
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
906
          }
907
          reset();
908
          dragstuff[13] = 1;
909
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
910
          break;
911
        case CLEARBUTTON:
912
  /*
18556 bpr 913
  @ clearbutton value
914
  @ alternative: delete
915
  @ alternative: erase
916
  @ adds a button to clear the <a href="#userdraw">userdraw</a> canvas with text ''value``
18572 bpr 917
  @ <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 918
  @ 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
919
  @ uses the tooltip placeholder div element: may not be used with command <code>intooltip</code>
920
  @ use command <a href="#css">css</a> to style the button...
921
  @ 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>
922
  @%clearbutton%size 400,400%xrange -10,10%yrange -10,10%filled%fillcolor lightblue%opacity 255,50%userdraw circles,red%clearbutton Remove All
18552 bpr 923
  */
924
          if(reply_format == 29){/* eg multidraw is selected */
925
  // canvas_error("command clearbutton incompatible with multidraw...only suitable for userdraw");
926
          }
927
          add_clear_button(css_class,get_string(infile,1));
928
          break;
929
        case CLOCK:
930
  /*
931
  @ clock x,y,r(px),H,M,S,type hourglass,interactive [ ,H_color,M_color,S_color,background_color,foreground_color ]
932
  @ use command <code>opacity stroke-opacity,fill-opacity</code> to adjust foreground (stroke) and background (fill) transparency
933
  @ type hourglass:<br>type = 0: only segments<br>type = 1: only numbers<br>type = 2: numbers and segments
18627 bpr 934
  @ 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 935
  @ if you don't want a seconds hand (or minutes...), just make it invisible by using the background color of the hourglass...
936
  @ 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>
937
  @ canvasdraw will not check validity of colornames...the javascript console is your best friend
938
  @ no combinations with other reply_types allowed, for now
939
  @ 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 940
  @ 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 941
  @ note: clocks will not zoom or pan, when using command <a href='#zoom'>zoom</a>
942
  @%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
943
  @%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
944
  @%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
945
  @%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
946
  @%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
947
  @%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
948
  @%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
949
  */
950
          js_function[DRAW_CLOCK] = 1;
951
          js_function[INTERACTIVE] = 1;
8386 schaersvoo 952
 
18552 bpr 953
  /*    var clock = function(xc,yc,radius,H,M,S,h_color,m_color,s_color,bg_color,fg_color) */
954
          for(i=0;i<9;i++){
955
            switch(i){
956
              case 0: int_data[0] = x2px(get_real(infile,0)); break; /* xc */
957
              case 1: int_data[1] = y2px(get_real(infile,0)); break; /* yc */
958
              case 2: int_data[2] = get_real(infile,0);break;/* radius in px */
959
              case 3: int_data[3] = get_real(infile,0);break;/* hours */
960
              case 4: int_data[4] = get_real(infile,0);break;/* minutes */
961
              case 5: int_data[5] = get_real(infile,0);break;/* seconds */
962
              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 */
963
              case 7: int_data[7] = (int)(get_real(infile,1));/* interactive 0,1,2*/
964
                switch(int_data[7]){
965
                  case 0:break;
966
                  case 1:
967
                    if(clock_cnt == 0){
968
                      if( reply_format == 0 ){
969
                        reply_format = 18; /* user sets clock */
18557 bpr 970
                  /*
971
                     tmp_buffer=my_newmem(MAX_BUFFER);
972
                     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 973
                     add_to_buffer(tmp_buffer);
974
                 */
975
                        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");
976
                      }
977
                      else {
978
                        canvas_error("interactive clock may not be used together with other reply_types...");
979
                      }
980
                    }
981
                    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);
982
                    break;
983
                  case 3:
984
                    if(clock_cnt == 0){
985
                      if( reply_format == 0 ){
986
                        reply_format = 18; /* user sets clock */
987
                        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");
988
                       }
989
                      else {
990
                        canvas_error("interactive clock may not be used together with other reply_types...");
991
                      }
992
                    }
993
          /*
994
          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);
995
         */
996
                  break;
997
                  case 2:
998
                    if( reply_format == 0 ){
999
                      reply_format = 19; /* "onclick */
1000
                      js_function[INTERACTIVE] = 1;
1001
                      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");
1002
                    }
1003
                    else {
1004
                      if( reply_format != 19){
1005
                        canvas_error("clickable clock(s) may not be used together with other reply_types...");
1006
                      }
1007
                    }
1008
                    break;
1009
                  default: canvas_error("interactive must be set 0,1 or 2");break;
1010
                }
1011
                break;
1012
              case 8:
1013
                if(clock_cnt == 0 ){ /* set opacity's just once .... it should be a argument to clock(), for now it's OK */
1014
                  fprintf(js_include_file,"var clock_bg_opacity = %.2f;var clock_fg_opacity = %.2f;",fill_opacity,stroke_opacity);
1015
                }
1016
                temp = get_string(infile,3);/* optional colors, like: ,,red,,blue*/
1017
                if( strstr( temp,",") != 0 ){ temp = str_replace(temp,",","\",\""); }
1018
                else{
1019
                /* h_color,m_color,s_color,bg_color,fg_color */
1020
                  temp = ",black\",\"black\",\"black\",\"white\",\"black";}
18557 bpr 1021
                tmp_buffer=my_newmem(MAX_BUFFER);
1022
                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 1023
                add_to_buffer(tmp_buffer);
1024
                fprintf(js_include_file,"var clocks%d;",clock_cnt);
1025
                clock_cnt++;
1026
                break;
1027
              default:break;
1028
            }
1029
          }
1030
          break;
1031
        case COLORPALETTE:
1032
  /*
18556 bpr 1033
  @ colorpalette color_name_1,color_name_2,...,color_name_8
1034
  @ opacity will be the same for all colors and is set by command <a href="#opacity">opacity [0-255],[0-255]</a>
1035
  @ 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
18642 schaersvoo 1036
  @ make sure to include the ''remove button`` by using command <a href='#clearbutton'>clearbutton some_text</a><br/>please note: right mouse click will alse remove last added item...
1037
  @%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,100%colorpalette red,green,yellow,blue%userdraw clickfill,green%clearbutton REMOVE
18552 bpr 1038
  */
1039
          if( use_tooltip == 1 ){canvas_error("command 'colorpalette' is incompatible with command 'intooltip tip_text'");}
1040
          fprintf(js_include_file,"var multifillcolors = [];var palettecolors = [");
1041
          while( ! done ){
1042
            temp = get_color(infile,1);
18642 schaersvoo 1043
            fprintf(js_include_file,"\"%s,%d\",",temp,(int) (255*fill_opacity));
18552 bpr 1044
          }
1045
          fprintf(js_include_file,"];");/* add black to avoid trouble with dangling comma... */
1046
          add_color_palette(css_class);
1047
          break;
15111 schaersvoo 1048
 
18552 bpr 1049
        case COMMENT:
1050
          sync_input(infile);
1051
          break;
11806 schaersvoo 1052
 
18552 bpr 1053
        case COPY:
1054
  /*
1055
  @ copy x,y,x1,y1,x2,y2,[filename URL]
1056
  @ The image may be "bitmap" or "SVG"
1057
  @ Insert the region from (x1,y1) to (x2,y2) (in pixels) of [filename] to (x,y) in x/y-range
1058
  @ If x1=y1=x2=y2=-1, the whole [filename URL] is copied.
1059
  @ [filename] is the URL of the image
1060
  @ <em>TODO:move special image functions to generic 'dragstuff' library</em>
1061
  @ URL is normal URL of network reachable image file location
1062
  @ 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>.
1063
  @ 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
1064
  @ ''onclick`` for external images may be mixed with canvas generated stuff (like lines,curves, embeded XML etc)
1065
  @ you may draw / userdraw / drag other stuff on top of an "imported" image
1066
  @ 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>
1067
  @ use keyword <a href='#centered'>centered</a> before command ''copy`` to place image center at given coordinates.
1068
  @%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
1069
  @%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
1070
  @%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
1071
  */
1072
          for(i = 0 ; i<7;i++){
1073
            switch(i){
1074
              case 0: double_data[0]=get_real(infile,0);break; /* x left top corner in x/y range  */
1075
              case 1: double_data[1]=get_real(infile,0);break; /* y left top corner in x/y range */
1076
              case 2: int_data[2]=(int)(get_real(infile,0));break;/* x1 in px of external image */
1077
              case 3: int_data[3]=(int)(get_real(infile,0));break;/* y1 in px of external image */
1078
              case 4: int_data[4]=(int)(get_real(infile,0));break;/* x2 --> width  */
1079
              case 5: int_data[5]=(int)(get_real(infile,0)) ;break;/* y2 --> height */
1080
              case 6: URL = get_string(infile,1);
1081
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
1082
                if(use_affine == TRUE ){transform(2,2);}
1083
                int_data[0] = x2px(double_data[0]);
1084
                int_data[1] = y2px(double_data[1]);
1085
                int_data[6] = int_data[4] - int_data[2];/* swidth & width (if not scaling )*/
1086
                int_data[7] = int_data[5] - int_data[3];/* sheight & height (if not scaling )*/
1087
                if( onclick == 0 ){ /* no mouse needed static image copy  */
1088
                  if(js_function[DRAW_EXTERNAL_IMAGE] == 0){/* create canvas just once */
1089
                    fprintf(js_include_file,"var image_copy_canvas = create_canvas%d(%d,xsize,ysize);",canvas_root_id,STATIC_IMAGE_CANVAS);
1090
                    js_function[DRAW_EXTERNAL_IMAGE] = 1;
1091
                  }
18557 bpr 1092
                  tmp_buffer=my_newmem(MAX_BUFFER);
1093
                  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 1094
                }
1095
                else /* onclick or drag & drop external copy images */
1096
                {
1097
                  js_function[DRAG_EXTERNAL_IMAGE] = 1;
18557 bpr 1098
                  tmp_buffer=my_newmem(MAX_BUFFER);
1099
                  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 1100
                }
1101
                add_to_buffer(tmp_buffer);
1102
                object_cnt++;
1103
                break;
1104
              default: break;
1105
            }
1106
          }
1107
          reset();
1108
          break;
11806 schaersvoo 1109
/*
1110
HTML5 specs:
1111
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
18552 bpr 1112
img   Specifies the image, canvas, or video element to use
1113
sx   The x coordinate where to start clipping: x1 = int_data[0]
1114
sy   The y coordinate where to start clipping: x2 = int_data[1]
1115
swidth   The width of the clipped image: int_data[2] - int_data[0]
14066 bpr 1116
sheight The height of the clipped image: int_data[3] - int_data[1]
18552 bpr 1117
x   The x coordinate where to place the image on the canvas: dx1 = int_data[4]
1118
y   The y coordinate where to place the image on the canvas: dy1 = int_data[5]
1119
width   The width of the image to use (stretch or reduce the image): dx2 - dx1 = int_data[6]
1120
height   The height of the image to use (stretch or reduce the image): dy2 - dy1 = int_data[7]
11806 schaersvoo 1121
*/
18552 bpr 1122
        case COPYRESIZED:
1123
  /*
1124
  @ copyresized x1,y2,x2,y2,dx1,dy1,dx2,dy2,image_file_url
1125
  @ The image may be any "bitmap" or "SVG"
1126
  @ 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
1127
  @ (dx1:dy1) must be left top corner; (dx2:dy2) must be right bottom corner of inserted image
1128
  @ If x1=y1=x2=y2=-1, the whole [filename / URL ] is copied and resized.
1129
  @ 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 !!)
1130
  @ 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>
1131
  @ 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
1132
  @ ''onclick`` for external images may be mixed with canvas generated stuff (like lines,curves etc)
1133
  @ you may draw / userdraw / drag stuff on top of an "imported" image
1134
  @ 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``
1135
  @ use keyword <a href='#centered'>centered</a> before command 'copyresized' to place image center at given coordinates.
1136
  @ <em>TODO:move special image functions to generic 'dragstuff' library</em>
1137
  */
1138
          for(i = 0 ; i<9;i++){
1139
           switch(i){
1140
            case 0: int_data[0] = (int)(get_real(infile,0));break; /* x1 */
1141
            case 1: int_data[1] = (int)(get_real(infile,0));break; /* y1 */
1142
            case 2: int_data[2] = (int)(get_real(infile,0));break;/* x2 */
1143
            case 3: int_data[3] = (int)(get_real(infile,0));break;/* y2 */
1144
            case 4: int_data[4] = x2px(get_real(infile,0));break;/* dx1 */
1145
            case 5: int_data[5] = y2px(get_real(infile,0));break;/* dy1 */
1146
            case 6: int_data[6] = x2px(get_real(infile,0));break;/* dx2 */
1147
            case 7: int_data[7] = y2px(get_real(infile,0));break;/* dy2 */
1148
            case 8: URL = get_string(infile,1);
1149
              if( int_data[1] == -1 ){ int_data[10] = 1; }else{int_data[10] = 0; }/* resized / not resized */
1150
          /* flag error when wrong diagonal:  copyresized -1,-1,-1,-1,0,0,7,7,testfig.gif */
1151
              if( int_data[7] < int_data[5] || int_data[6] < int_data[4]){
1152
                canvas_error("in copyresized,  use:<br>left top corner (dx1:dy1) and right bottom corner (dx2:dy2) ! ");
1153
              }
1154
              int_data[2] = abs(int_data[2] - int_data[0]);/* swidth */
1155
              int_data[3] = abs(int_data[3] - int_data[1]);/* sheight */
1156
              int_data[6] = abs(int_data[6] - int_data[4]);/* width */
1157
              int_data[7] = abs(int_data[7] - int_data[5]);/* height */
1158
              if( onclick == 0 ){ /* no mouse needed static image copy  */
1159
                if(js_function[DRAW_EXTERNAL_IMAGE] == 0){
1160
                  fprintf(js_include_file,"var image_copy_canvas = create_canvas%d(%d,xsize,ysize);",canvas_root_id,STATIC_IMAGE_CANVAS);
1161
                  js_function[DRAW_EXTERNAL_IMAGE] = 1;
1162
                }
18557 bpr 1163
                tmp_buffer=my_newmem(MAX_BUFFER);
1164
                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 1165
              }
1166
              else /* onclick or drag & drop external copy images */
1167
              {
1168
                js_function[DRAG_EXTERNAL_IMAGE] = 1;
18557 bpr 1169
                tmp_buffer=my_newmem(MAX_BUFFER);
1170
                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 1171
                object_cnt++;
1172
              }
1173
              add_to_buffer(tmp_buffer);
1174
              break;
1175
            default: break;
1176
            }
1177
          }
1178
          reset();
1179
          break;
8386 schaersvoo 1180
 
18552 bpr 1181
        case CROSSHAIR:
1182
  /*
1183
  @ crosshair x,y,color
1184
  @ draw a single crosshair point at (x;y) in color ''color``
1185
  @ use command <code>crosshairsize int</code> and / or <code>linewidth int</code> to adjust
1186
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1187
  @%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
1188
  */
1189
          for(i=0;i<3;i++){
1190
            switch(i){
1191
              case 0: double_data[0] = get_real(infile,0);break; /* x */
1192
              case 1: double_data[1] = get_real(infile,0);break; /* y */
1193
              case 2: stroke_color = get_color(infile,1);/* name or hex color */
1194
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
1195
                if(use_affine == TRUE ){ transform(2,2);}
1196
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1197
                decimals = find_number_of_digits(precision);
18557 bpr 1198
                tmp_buffer=my_newmem(MAX_BUFFER);
1199
                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 1200
                add_to_buffer(tmp_buffer);
1201
                if(onclick != 0){object_cnt++;}
1202
          /* object_cnt++ */
1203
                reset();
1204
                dragstuff[7] = 1;
1205
                break;
1206
              default:break;
1207
            }
1208
          }
1209
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1210
          break;
11806 schaersvoo 1211
 
18552 bpr 1212
        case CROSSHAIRS:
1213
  /*
1214
  @ crosshairs color,x1,y1,x2,y2,...,x_n,y_n
1215
  @ draw multiple crosshair points at given coordinates in color ''color``
1216
  @ use command <code>crosshairsize int</code> and / or <code>linewidth int</code> to adjust
1217
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
1218
  @%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
1219
  @%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 1220
*/
18552 bpr 1221
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
1222
          fill_color = stroke_color;
1223
          i=0;
1224
          while( ! done ){     /* get next item until EOL*/
1225
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1226
            if(i%2 == 0 ){
1227
              double_data[i] = get_real(infile,0); /* x */
1228
            }
1229
            else {
1230
              double_data[i] = get_real(infile,1); /* y */
1231
            }
1232
            i++;
1233
          }
1234
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
1235
          if(use_affine == TRUE ){ transform(i-1,2);}
1236
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1237
          decimals = find_number_of_digits(precision);
1238
          for(c=0 ; c < i-1 ; c = c+2){
18557 bpr 1239
            tmp_buffer=my_newmem(MAX_BUFFER);
1240
            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 1241
            add_to_buffer(tmp_buffer);
1242
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
1243
          }
1244
          dragstuff[7] = 1;
1245
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1246
          reset();
1247
          break;
1248
        case CROSSHAIRSIZE:
1249
  /*
1250
  @ crosshairsize int
1251
  @ default 8 (px)
1252
  */
1253
          crosshair_size = (int) (get_real(infile,1));
1254
          break;
1255
        case CSS:
1256
  /*
1257
  @ css css_class
1258
  @ may be used before any ''style-able`` html object (like inputfields or buttons) or some html objects that are generated by some canvasdraw commands
1259
  @ in case of <a href="#multidraw">multidraw</a> this command must be a table css class, for example "wimstable"
1260
  @%css%size 400,400%xrange -10,10%yrange -10,10%css wims_button_help%input 0,0,10,1,Hello
1261
  */
1262
          css_class = get_string(infile,1);
1263
          break;
1264
        case CURSOR:
1265
  /*
1266
  @ cursor some CSS cursor_style
1267
  @ alternative: pointer
1268
  @ style can be any valid CSS property value
1269
  @ 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
1270
  @ note: wims will not check the validity of your cursor declaration
1271
  @%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
1272
  */
1273
          fprintf(js_include_file,"canvas_div%d.style.cursor = \"%s\";",canvas_root_id,get_string(infile,1));
1274
         break;
1275
        case CURVE:
1276
  /*
18556 bpr 1277
  @ curve color,formula(x)
1278
  @ alternative: plot
18572 bpr 1279
  @ 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 1280
  @ use command <a href="#precision">precision</a> to increase the number of digits of the plotted points
1281
  @ use command <a href="#plotsteps">plotsteps</a> to increase / decrease the amount of plotted points (default 150)
1282
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1283
  @ 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 1284
  @%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 1285
  */
1286
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
11806 schaersvoo 1287
 
18552 bpr 1288
          if( use_parametric == TRUE ){ /* parametric color,fun1(t),fun2(t)*/
1289
            use_parametric = FALSE;
1290
            stroke_color = get_color(infile,0);
1291
            char *fun1 = get_string_argument(infile,0);
1292
            char *fun2 = get_string_argument(infile,1);
1293
            if( strlen(fun1) == 0 || strlen(fun2) == 0 ){canvas_error("parametric functions are NOT OK !");}
18557 bpr 1294
            tmp_buffer=my_newmem(MAX_BUFFER);
18634 schaersvoo 1295
            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 1296
            add_to_buffer(tmp_buffer);
1297
          }
1298
          else{
1299
            stroke_color = get_color(infile,0);
1300
            char *fun1 = get_string_argument(infile,1);
1301
            if( strlen(fun1) == 0 ){canvas_error("function is NOT OK !");}
18557 bpr 1302
            tmp_buffer=my_newmem(MAX_BUFFER);
18634 schaersvoo 1303
            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 1304
            add_to_buffer(tmp_buffer);
1305
          }
1306
          if(onclick != 0){object_cnt++;}/* object_cnt++; */
1307
          dragstuff[9] = 1;
1308
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1309
          reset();
1310
          break;
1311
        case CURVEDARROW:
14038 schaersvoo 1312
    /*
18556 bpr 1313
  @ curvedarrow x1,y1,xc,yc,x2,y2,color
1314
  @ 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)
1315
  @ use command <a href='#arrowhead'>arrowhead</a> to set the size of the arrow head.
1316
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
1317
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1318
  @%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
1319
  @%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 1320
 
14029 schaersvoo 1321
h[0] = arrowhead
14066 bpr 1322
h[1] = type: 1 = single 2=double arrow
15111 schaersvoo 1323
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 1324
    */
18552 bpr 1325
          for(i=0;i<7;i++){
1326
            switch(i){
1327
              case 0: double_data[0] = get_real(infile,0);break; /* x1 */
1328
              case 1: double_data[1] = get_real(infile,0);break; /* y1 */
1329
              case 2: double_data[2] = get_real(infile,0);break; /* xc */
1330
              case 3: double_data[3] = get_real(infile,0);break; /* yc */
1331
              case 4: double_data[4] = get_real(infile,0);break; /* y3 */
1332
              case 5: double_data[5] = get_real(infile,0);break; /* y3 */
1333
              case 6: stroke_color = get_color(infile,1);/* name or hex color */
1334
                if(use_rotate == TRUE ){rotate(6,angle,rotationcenter,2);}
1335
                if(use_affine == TRUE ){ transform(6,2);}
1336
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1337
                decimals = find_number_of_digits(precision);
18557 bpr 1338
                tmp_buffer=my_newmem(MAX_BUFFER);
1339
                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 1340
                add_to_buffer(tmp_buffer);
1341
                if(onclick != 0){object_cnt++;}/* object_cnt++;*/
1342
                reset();
1343
                break;
1344
            }
1345
          }
1346
          dragstuff[21] = 1;
1347
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1348
          break;
1349
        case CURVEDARROW2:
14038 schaersvoo 1350
    /*
18556 bpr 1351
  @ curvedarrow2 x1,y1,xc,yc,x2,y2,color
1352
  @ 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)
1353
  @ use command <a href='#arrowhead'>arrowhead</a> to set the size of the arrow head.
1354
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
1355
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1356
  @%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 1357
  @%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 1358
 
1359
h[0] = arrowhead
14066 bpr 1360
h[1] = type: 1 = single 2=double arrow
15111 schaersvoo 1361
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 1362
    */
18552 bpr 1363
          for(i=0;i<7;i++){
1364
            switch(i){
1365
              case 0: double_data[0] = get_real(infile,0);break; /* x1 */
1366
              case 1: double_data[1] = get_real(infile,0);break; /* y1 */
1367
              case 2: double_data[2] = get_real(infile,0);break; /* xc */
1368
              case 3: double_data[3] = get_real(infile,0);break; /* yc */
1369
              case 4: double_data[4] = get_real(infile,0);break; /* y3 */
1370
              case 5: double_data[5] = get_real(infile,0);break; /* y3 */
1371
              case 6: stroke_color = get_color(infile,1);/* name or hex color */
1372
              if(use_rotate == TRUE ){rotate(6,angle,rotationcenter,2);}
1373
              if(use_affine == TRUE ){ transform(6,2);}
1374
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1375
              decimals = find_number_of_digits(precision);
18557 bpr 1376
              tmp_buffer=my_newmem(MAX_BUFFER);
1377
              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 1378
              add_to_buffer(tmp_buffer);
1379
              if(onclick != 0){object_cnt++;}/* object_cnt++;*/
1380
              dragstuff[21] = 1;
1381
              if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1382
              reset();
1383
              break;
1384
            }
1385
          }
1386
          break;
1387
        case CURVEDARROWS:
14038 schaersvoo 1388
    /*
18556 bpr 1389
  @ curvedarrows color,x1,y1,xc,yc,x2,y2,...,x_(n-1),y_(n-1),xc,yc,x_n,y_n
1390
  @ 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)
1391
  @ use command <a href='#arrowhead'>arrowhead</a> to set the size of the arrow head.
1392
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
1393
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1394
  @%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
1395
  @%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 1396
 
14030 schaersvoo 1397
h[0] = arrowhead
14066 bpr 1398
h[1] = type: 1 = single 2=double arrow
15111 schaersvoo 1399
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 1400
    */
18552 bpr 1401
          stroke_color = get_color(infile,0);/* name or hex color */
1402
          i = 0;
1403
          decimals = find_number_of_digits(precision);
1404
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1405
          while( ! done ){
1406
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1407
            double_data[0] = get_real(infile,0); /* x1 */
1408
            double_data[1] = get_real(infile,0); /* y1 */
1409
            double_data[2] = get_real(infile,0); /* xc */
1410
            double_data[3] = get_real(infile,0); /* yc */
1411
            double_data[4] = get_real(infile,0); /* x3 */
1412
            double_data[5] = get_real(infile,1); /* y3 */
18557 bpr 1413
            tmp_buffer=my_newmem(MAX_BUFFER);
1414
            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 1415
            add_to_buffer(tmp_buffer);
1416
            if(onclick != 0){object_cnt++;}
1417
            i = i + 6;
1418
          }
1419
          if(use_rotate == TRUE ){rotate(i-6,angle,rotationcenter,2);}
1420
          if(use_affine == TRUE ){ transform(i-6,2);}
1421
          dragstuff[21] = 1;
1422
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1423
          reset();
1424
          break;
1425
        case CURVEDARROWS2:
14038 schaersvoo 1426
    /*
18556 bpr 1427
  @ curvedarrows2 color,x1,y1,xc,yc,x2,y2,...x_(n-1),y_(n-1),xc,yc,x_n,y_n
1428
  @ 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)
1429
  @ use command <a href='#arrowhead'>arrowhead</a> to set the size of the arrow head.
1430
  @ use command <code>linewidth int</code> to adjust thickness of the arrow
1431
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1432
  @%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
1433
  @%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 1434
 
1435
h[0] = arrowhead
14066 bpr 1436
h[1] = type: 1 = single 2=double arrow
15111 schaersvoo 1437
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 1438
    */
18552 bpr 1439
          stroke_color = get_color(infile,0);/* name or hex color */
1440
          i = 0;
1441
          decimals = find_number_of_digits(precision);
1442
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1443
          while( ! done ){
1444
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1445
            double_data[0] = get_real(infile,0); /* x1 */
1446
            double_data[1] = get_real(infile,0); /* y1 */
1447
            double_data[2] = get_real(infile,0); /* xc */
1448
            double_data[3] = get_real(infile,0); /* yc */
1449
            double_data[4] = get_real(infile,0); /* x3 */
1450
            double_data[5] = get_real(infile,1); /* y3 */
18557 bpr 1451
            tmp_buffer=my_newmem(MAX_BUFFER);
1452
            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 1453
            add_to_buffer(tmp_buffer);
1454
            if(onclick != 0){object_cnt++;}
1455
            i = i + 6;
1456
          }
1457
          if(use_rotate == TRUE ){rotate(i-6,angle,rotationcenter,2);}
1458
          if(use_affine == TRUE ){ transform(i-6,2);}
1459
          dragstuff[21] = 1;
1460
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1461
          reset();
1462
          break;
1463
        case DASHED:
1464
  /*
1465
  @ dashed
1466
  @ keyword (no arguments required)
1467
  @ next object will be drawn with a dashed line
1468
  @ change dashing scheme by using command <a href="#dashtype">dashtype</a>
1469
  @%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
1470
  */
1471
          use_dashed = TRUE;
1472
          break;
1473
        case DASHTYPE:
1474
  /*
1475
  @ dashtype line_width_px,space_width_px
1476
  @ every indiviual object may have its own dashtype, if needed...
1477
  @ When keyword <a href='#dashed'>dashed</a> is set, the objects will be drawn with this dashtype
1478
  @ default value <code>dashtype 2,2</code> e.g. 2px line and 2px space
1479
  @ HTML5 canvas specification supports more arguments (dashing schemes) ... but not all modern browsers are yet capable
1480
  @%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
1481
  */
1482
          for(i=0;i<2;i++){
1483
            switch(i){
1484
              case 0 : dashtype[0] = (int) line_width*( get_real(infile,0)) ; break;
1485
              case 1 : dashtype[1] = (int) line_width*( get_real(infile,1)) ; break;
1486
            }
1487
          }
1488
          break;
1489
        case DIAMONDFILL:
1490
  /*
1491
  @ diamondfill x0,y0,dx,dy,color
1492
  @ x0,y0 in xrange / yrange
1493
  @ distances dx,dy in pixels
1494
  @ there is also a command <a href="#userdraw">userdraw diamondfill,color</a>
1495
  @%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
1496
  */
1497
          js_function[DRAW_DIAMONDFILL] = 1;
1498
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1499
            js_function[DRAW_FILLTOBORDER] = 1;
1500
            add_js_filltoborder(canvas_type);
1501
          }
1502
          decimals = find_number_of_digits(precision);
1503
          for(i=0;i<5;i++){
1504
            switch(i){
1505
              case 0: double_data[0] = get_real(infile,0); break; /* x */
1506
              case 1: double_data[1] = get_real(infile,0); break; /* y  */
1507
              case 2: int_data[0] = (int) (get_real(infile,0)); break; /* dx pixel */
1508
              case 3: int_data[1] = (int) (get_real(infile,0)); break; /* dy pixel*/
1509
              case 4: stroke_color = get_color(infile,1);
1510
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
1511
                if(use_affine == TRUE ){ transform(2,2);}
18573 bpr 1512
              /* draw_diamondfill(ctx,x0,y0,dx,dy,linewidth,color,opacity,xsize,ysize) */
18557 bpr 1513
                tmp_buffer=my_newmem(MAX_BUFFER);
1514
                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 1515
                add_to_buffer(tmp_buffer);
1516
                fill_cnt++;
1517
                reset();
1518
                break;
1519
              default:break;
1520
            }
1521
          }
1522
          break;
1523
        case DOTFILL:
1524
  /*
1525
  @ dotfill x0,y0,dx,dy,color
1526
  @ x0,y0 in xrange / yrange
1527
  @ distances dx,dy in pixels
1528
  @ radius of dots is linewidth
1529
  @ there is also a command <a href="#userdraw">userdraw dotfill,color</a>
1530
  @%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
1531
  */
1532
          js_function[DRAW_DOTFILL] = 1;
1533
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1534
            js_function[DRAW_FILLTOBORDER] = 1;
1535
            add_js_filltoborder(canvas_type);
1536
          }
1537
          decimals = find_number_of_digits(precision);
1538
          for(i=0;i<5;i++){
1539
            switch(i){
1540
              case 0: double_data[0] = get_real(infile,0); break; /* x in px */
1541
              case 1: double_data[1] = get_real(infile,0); break; /* y in py */
1542
              case 2: int_data[0] = (int) (get_real(infile,0)); break; /* dx pixel */
1543
              case 3: int_data[1] = (int) (get_real(infile,0)); break; /* dy pixel*/
1544
              case 4: stroke_color = get_color(infile,1);
1545
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
1546
                if(use_affine == TRUE ){ transform(2,2);}
1547
        /* draw_dotfill(ctx,x0,y0,dx,dy,radius,color,opacity,xsize,ysize) */
18557 bpr 1548
                tmp_buffer=my_newmem(MAX_BUFFER);
1549
                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 1550
                add_to_buffer(tmp_buffer);
1551
                fill_cnt++;
1552
                reset();
1553
                break;
1554
              default:break;
1555
            }
1556
          }
1557
          break;
1558
        case DRAG:
1559
  /*
18556 bpr 1560
  @ drag [x][y][xy]
1561
  @ the next object will be draggable in x / y / xy direction
1562
  @ the displacement can be read by <code>javascript:read_dragdrop();</code>
1563
  @ 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' !
1564
  @ <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 )
1565
  @ ''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)
1566
  @ <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
1567
  @ 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)
1568
  @ 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
1569
  @ 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.
1570
  @%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
1571
  @%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
1572
  @%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 1573
  */
1574
          temp = get_string(infile,1);
1575
          if(strstr(temp,"xy") != NULL ){
1576
            drag_type = 0;
1577
          } else {
1578
            if(strstr(temp,"x") != NULL ){
1579
              drag_type = 1;
1580
            }
1581
            else { drag_type = 2;}
1582
          }
1583
      /* assuming all drag&drop coordinates the same precision: so set only once */
1584
          if( print_drag_params_only_once == FALSE ){
1585
            fprintf(js_include_file,"dragdrop_precision = %d;use_dragdrop_reply = true;",precision);
1586
            print_drag_params_only_once = TRUE;
1587
          }
1588
          onclick = 2;
1589
      /* if(use_userdraw == TRUE ){canvas_error("\"drag & drop\" may not be combined with \"userdraw\" or \"pan and zoom\" \n");} */
1590
          use_dragstuff = 2;
1591
          js_function[INTERACTIVE] = 1;
1592
          break;
1593
        case ELLIPSE:
1594
  /*
1595
  @ ellipse xc,yc,width_x,height_y,color
1596
  @ ellipses with center xc/yc and width/height in x/y-range etc (this differs from flydraw syntax!)
1597
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1598
  @ will shrink / expand on zoom out / zoom in
1599
  @%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
1600
  */
1601
          for(i=0;i<5;i++){
1602
            switch(i){
1603
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
1604
              case 1:double_data[1] = get_real(infile,0);break; /* y-values */
1605
              case 2:double_data[2] = get_real(infile,0);break; /* rx -> px */
1606
              case 3:double_data[3] = get_real(infile,0);break; /* ry -> px */
1607
              case 4:stroke_color = get_color(infile,1);/* name or hex color */
1608
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,4);}
1609
                if(use_affine == TRUE ){ transform(2,4);}
1610
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1611
                decimals = find_number_of_digits(precision);
18557 bpr 1612
                tmp_buffer=my_newmem(MAX_BUFFER);
1613
                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 1614
                add_to_buffer(tmp_buffer);
1615
                if(onclick != 0){object_cnt++;}/* object_cnt++; */
1616
                dragstuff[3] = 1;
1617
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1618
                reset();
1619
              break;
1620
            }
1621
          }
1622
          break;
1623
        case ELLIPSES:
1624
  /*
1625
  @ ellipses color,xc1,yc1,width_x1,height_y1,xc2,yc2,width_x2,height_y2,xc3,yc3,width_x3,height_y3,...
1626
  @ ellipses with center and height in x/y-range etc (this differs from flydraw syntax!)
1627
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1628
  @ will shrink / expand on zoom out / zoom in
1629
  @%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
1630
  */
8224 bpr 1631
 
18552 bpr 1632
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
1633
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
18623 bpr 1634
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 1635
          i=1;
1636
          while( ! done ){     /* get next item until EOL*/
1637
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1638
            switch (i%4){
1639
              case 1:double_data[i-1] = get_real(infile,0);break; /* x */
1640
              case 2:double_data[i-1] = get_real(infile,0);break; /* y */
1641
              case 3:double_data[i-1] = get_real(infile,0);break; /* rx */
1642
              case 0:double_data[i-1] = get_real(infile,1);break; /* ry */
1643
              default: break;
1644
            }
1645
            i++;
1646
          }
1647
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,4);}
1648
          if(use_affine == TRUE ){ transform(i-1,4);}
1649
          decimals = find_number_of_digits(precision);
1650
          for(c = 0 ; c < i-1 ; c = c+4){
18623 bpr 1651
            check_string_length(string_length);
1652
            tmp_buffer=my_newmem(MAX_BUFFER);
1653
            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 1654
            add_to_buffer(tmp_buffer);
1655
            if(onclick != 0){object_cnt++;} /* object_cnt++; */
1656
          }
1657
          reset();
1658
          dragstuff[3] = 1;
1659
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
1660
          break;
1661
        case FILLALL:
1662
  /*
1663
  @ fillall color,x1,y1,x2,y2...x_n,y_n
18615 bpr 1664
  @ fill all the region containing points (x1:y1),(x2:y2)...(x_n:y_n) with color 'color'
1665
  @ any color (object) in the <a href="#canvastype">canvastype</a> will act as border to the bucket fill
18552 bpr 1666
  @ use this command after all boundary objects are declared.
1667
  @ Use command 'userdraw clickfill,color' for user click driven flood fill.
1668
  @ use command <a href="#canvastype">canvastype </a> to fill another canvas (default should be fine: DRAG_CANVAS = 5)
1669
  @ 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..
1670
  @%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
1671
  */
1672
          decimals = find_number_of_digits(precision);
1673
          fill_color=get_color(infile,0); /* how nice: now the color comes first...*/
1674
          i=0;
1675
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1676
            js_function[DRAW_FILLTOBORDER] = 1;
1677
            add_js_filltoborder(canvas_type);
1678
          }
1679
          while( ! done ){     /* get next item until EOL*/
1680
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
1681
            if(i%2 == 0 ){
1682
              double_data[i] = get_real(infile,0); /* x */
1683
            }
1684
            else {
1685
              double_data[i] = get_real(infile,1); /* y */
18557 bpr 1686
              tmp_buffer=my_newmem(MAX_BUFFER);
18609 bpr 1687
              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 1688
              add_to_buffer(tmp_buffer);
1689
              fill_cnt++;
1690
            }
1691
            i++;
1692
          }
1693
          break;
1694
        case FILLED:
1695
  /*
1696
  @ filled
1697
  @ keyword (no arguments required)
1698
  @ the next ''fillable`` object (only the next !) will be filled
1699
  @ use command <a href="#fillcolor">fillcolor color</a> to set fillcolor
1700
  @ use <a href="#fillpattern">fillpattern</a> for non-solid color filling.
1701
  @ use command <code>opacity 0-255,0-255</code> to set stroke and fill-opacity
1702
  @ 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 !
1703
  */
1704
          use_filled = 1;
1705
          break;
1706
        case FILLCOLOR:
1707
  /*
1708
  @ fillcolor colorname or #hex
1709
  @ set the color: mainly used for command 'userdraw obj,stroke_color'
18635 bpr 1710
  @ 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 1711
  @ see <a href="#fillpattern">fillpattern</a> for non-solid color filling.
1712
  */
18623 bpr 1713
          fillcolor = get_color(infile,1);
18635 bpr 1714
          fill_color = fillcolor;
18552 bpr 1715
          break;
1716
        case FILLPATTERN:
1717
  /*
1718
  @ fillpattern grid | hatch | diamond | dot | image_url
1719
  @ alternative: settile image_url
1720
  @ use a pattern as fillstyle
1721
  @ suitable for all fillable object including the <a href="#userdraw">userdraw objects' family</a>
18627 bpr 1722
  @ note: do not use the ''f`` for a fillable object : this is used exclusively for solid color filling.
18569 bpr 1723
  @ 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 1724
  @ the pattern dimensions are hardcoded (linewidth, radius,dx,dy are fixed)
1725
  @ the pattern color is set by command <a href='#fillcolor'>fillcolor</a> and <a href='#opacity'>opacity</a>
1726
  @ see <a href="#fillcolor">fillcolor</a> for solid color filling.
18569 bpr 1727
  @ 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 1728
  @ 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 1729
  @%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 1730
  @%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
1731
  */
1732
          temp = get_string(infile,1);
1733
          use_filled = 0;
1734
          js_function[DRAW_FILL_PATTERN] = 1;
1735
          if( strstr(temp,"grid") != 0 ){ use_filled = 2;}
1736
          else{
1737
            if( strstr(temp,"hatch") != 0 ){ use_filled = 3;}
1738
            else{
1739
              if( strstr(temp,"diamond") != 0 ){ use_filled = 4;}
1740
              else{
1741
                if( strstr(temp,"dot") != 0 ){ use_filled = 5;}
1742
                else{
1743
                  if( strstr(temp,"/") != 0 ){ /* get_image_from_url() needs to be called after function definition...*/
1744
                    use_filled = 6;js_function[JS_LOAD_IMAGE] = 1;
18557 bpr 1745
                    tmp_buffer=my_newmem(MAX_BUFFER);
1746
                    check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "get_image_from_url(\"%s\");",temp));
18552 bpr 1747
                    add_to_buffer(tmp_buffer);
1748
                  }
1749
                }
1750
              }
1751
            }
1752
          }
1753
          if( use_filled == 0 ){canvas_error("fillpattern unknown or typo...choose grid,hatch,diamond of dot...");}
1754
          break;
1755
        case FILLTOBORDER:
1756
  /*
1757
  @ filltoborder x,y,bordercolor,color
1758
  @ fill the region of point (x:y) with color 'color'
18615 bpr 1759
  @ any other color than bordercolor will not act as border to the bucket fill
1760
  @ 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 1761
  @ use this command after all boundary objects are declared.
18615 bpr 1762
  @ it can be useful to increase strokeopacity or linewidth
18552 bpr 1763
  @ use command <a href="#canvastype">canvastype </a> to fill another canvas (default should be fine: DRAG_CANVAS = 5)
1764
  @ 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..
1765
  @ maybe used together with command <a href="#userdraw">userdraw clickfill,color</a>
18615 bpr 1766
  @%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 1767
  */
1768
          for(i=0 ;i < 4 ; i++){
1769
            switch(i){
1770
              case 0:double_data[0] = get_real(infile,0);break;
1771
              case 1:double_data[1] = get_real(infile,0);break;
1772
              case 2:bgcolor = get_color(infile,0);break;
1773
              case 3:fill_color = get_color(infile,1);
18569 bpr 1774
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1775
            js_function[DRAW_FILLTOBORDER] = 1;
1776
            add_js_filltoborder(canvas_type);
1777
          }
1778
          decimals = find_number_of_digits(precision);
18552 bpr 1779
         /* we need to set a timeout: the canvas is not yet draw in memory? when floodfill is called directly... */
18569 bpr 1780
          tmp_buffer=my_newmem(MAX_BUFFER);
18629 bpr 1781
          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 1782
          add_to_buffer(tmp_buffer);
1783
          fill_cnt++;
1784
          reset();
1785
          break;
18552 bpr 1786
              default:break;
1787
            }
1788
          }
1789
          break;
1790
        case FLOODFILL:
1791
  /*
1792
  @ floodfill x,y,color
1793
  @ alternative: fill
1794
  @ fill the region of point (x:y) with color 'color'
1795
  @ any other color or size of picture (borders of picture) will act as border to the bucket fill
1796
  @ use this command after all boundary objects are declared.
1797
  @ Use command <code>userdraw clickfill,color</code> for user click driven flood fill.
1798
  @ use command <a href="#canvastype">canvastype </a> to fill another canvas (default should be fine: DRAG_CANVAS = 5)
1799
  @ 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..
1800
  @%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
1801
  */
1802
          for(i=0 ;i < 4 ; i++){
1803
            switch(i){
1804
              case 0:double_data[0] = get_real(infile,0);break;
1805
              case 1:double_data[1] = get_real(infile,0);break;
1806
              case 2:fill_color = get_color(infile,1);
1807
                if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1808
                  js_function[DRAW_FILLTOBORDER] = 1;
1809
                  add_js_filltoborder(canvas_type);
1810
                }
1811
                decimals = find_number_of_digits(precision);
1812
         /* we need to set a timeout: the canvas is not yet draw in memory? when floodfill is called directly... */
18557 bpr 1813
                tmp_buffer=my_newmem(MAX_BUFFER);
18609 bpr 1814
                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 1815
                add_to_buffer(tmp_buffer);
1816
                fill_cnt++;
1817
                break;
1818
            default:break;
1819
            }
1820
          }
1821
          reset();
1822
          break;
1823
        case FONTCOLOR:
1824
  /*
18556 bpr 1825
  @ fontcolor color
1826
  @ color: hexcolor or colorname
1827
  @ default: black
1828
  @ use command <a href="#fontfamily">fontfamily</a> to deviate from default font type
1829
  @%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 1830
  */
1831
          font_color = get_color(infile,1);
1832
          break;
1833
        case FONTFAMILY:
1834
  /*
18556 bpr 1835
  @ fontfamily font_description
1836
  @ set the font family; for browsers that support it
1837
  @ font_description: Arial, Courier, Helvetica etc
1838
  @ 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``
1839
  @%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 1840
 
18552 bpr 1841
  */
1842
          font_family = get_string(infile,1);
1843
          break;
1844
        case FONTSIZE:
1845
  /*
18556 bpr 1846
  @ fontsize font_size
1847
  @ default value 12
1848
  @ 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 1849
  */
1850
          font_size = (int) (get_real(infile,1));
1851
          break;
1852
        case FUNCTION_LABEL:
1853
  /*
18556 bpr 1854
  @ functionlabel label_1:label_2:label_3...
1855
  @ alternative: functionlabels
1856
  @ default value ''f(x)=:g(x)=:h(x)=:i(x)=:j(x)=:k(x)=:m(x)=:n(x)=``
1857
  @ no mathml allowed (just ascii string)
1858
  @ use command <a href='#fontsize'>fontsize int</a> to adjust the size
1859
  @ use command <a href='#strokecolor'>strokecolor colorname</a> to adjust the labels (individually, if needed)
1860
  @ if needed, use before every command <a href='#userinput'>userinput function | inputfield | textarea</a>
1861
  @ no limit in amount of inputfields for userbased function plotting
1862
  @%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 1863
  */
1864
          temp = get_string_argument(infile,1);
1865
          function_label = list2js_array(temp,":");
1866
          break;
1867
        case GRID:/* xmajor,ymajor,gridcolor [,xminor,yminor,tick length (px), axis/tickscolor]*/
1868
  /*
18556 bpr 1869
  @ grid step_x,step_y,gridcolor
1870
  @ 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
1871
  @ 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
1872
  @ 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)
1873
  @ can <b>not</b> be set <a href="#onclick">onclick</a> or <a href="#drag">drag xy</a>
1874
  @ 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' !
1875
  @ 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')
1876
  @ 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')
1877
  @%grid%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%zoom red
1878
  @%grid_axis%size 400,400%xrange -10,10%yrange -10,10%axis%grid 1,1,grey,2,2,6,black%zoom red
1879
  @%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 1880
  */
1881
          if( js_function[DRAW_YLOGSCALE] == 1 ){canvas_error("only one grid type is allowed...");}
1882
          js_function[DRAW_GRID] = 1;
1883
          for(i=0;i<4;i++){
1884
            switch(i){
1885
              case 0:double_data[0] = get_real(infile,0);break;/* xmajor */
1886
              case 1:double_data[1] = get_real(infile,0);break;/* ymajor */
1887
              case 2:
1888
              if( use_axis == TRUE ){
1889
                stroke_color = get_color(infile,0);
1890
                done = FALSE;
1891
                int_data[0] = (int) (get_real(infile,0));/* xminor */
1892
                int_data[1] = (int) (get_real(infile,0));/* yminor */
1893
                int_data[2] = (int) (get_real(infile,0));/* tic_length */
1894
                fill_color = get_color(infile,1); /* used as axis_color*/
1895
              }
1896
              else {
1897
              int_data[0] = 1;
1898
              int_data[1] = 1;
1899
              stroke_color = get_color(infile,1);
1900
              fill_color = stroke_color;
1901
              }
1902
              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 !");}
1903
              /* set snap_x snap_y values in pixels */
1904
              fprintf(js_include_file,"snap_x = %f;snap_y = %f;",double_data[0] / int_data[0],double_data[1] / int_data[1]);
1905
              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 1906
              tmp_buffer=my_newmem(MAX_BUFFER);
1907
              check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "redraw_grid();\n"));
18552 bpr 1908
              add_to_buffer(tmp_buffer);
1909
              break;
1910
            }
1911
          }
1912
          reset();
1913
          break;
1914
        case GRIDFILL:
1915
  /*
1916
  @ gridfill x0,y0,dx,dy,color
1917
  @ x0,y0 in xrange / yrange
1918
  @ distances dx,dy in pixels
1919
  @ there is also a command <a href="#userdraw">userdraw gridfill,color</a>
1920
  @%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 1921
 
18552 bpr 1922
  */
1923
          js_function[DRAW_GRIDFILL] = 1;
1924
          decimals = find_number_of_digits(precision);
1925
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
1926
            js_function[DRAW_FILLTOBORDER] = 1;
1927
            add_js_filltoborder(canvas_type);
1928
          }
1929
          for(i=0;i<5;i++){
1930
            switch(i){
1931
              case 0: double_data[0] = get_real(infile,0); break; /* x  */
1932
              case 1: double_data[1] = get_real(infile,0); break; /* y  */
1933
              case 2: int_data[0] = (int) (get_real(infile,0)); break; /* dx pixel */
1934
              case 3: int_data[1] = (int) (get_real(infile,0)); break; /* dy pixel*/
1935
              case 4: stroke_color = get_color(infile,1);
18557 bpr 1936
 
1937
              tmp_buffer=my_newmem(MAX_BUFFER);
1938
              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 1939
              add_to_buffer(tmp_buffer);
1940
              fill_cnt++;
1941
              reset();
1942
              break;
1943
              default:break;
1944
            }
1945
          }
1946
          break;
1947
        case GROUP:
1948
  /*
18556 bpr 1949
  @ group
1950
  @ keyword
1951
  @ work in 'progress'
1952
  @ 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)
1953
  @ may be combined with slider driven movements or drag & drop
1954
  @%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 1955
  */
1956
          use_slider++;
1957
          add_slider(2);
1958
          no_reset = TRUE;
1959
          int c = 0;
1960
          for(i=last_slider;i<=use_slider;i++){ int_data[c] = i; c++; }
1961
          my_sliders = data2js_array(int_data,use_slider - last_slider+1);
1962
          if( precision == 0 ){precision = 100;}
1963
          onclick = 5;
1964
          use_dragstuff = 2;
1965
          drag_type = 0;
1966
          js_function[INTERACTIVE] = 1;
1967
          fprintf(js_include_file,"var slider%d;dragdrop_precision = %d;use_dragdrop_reply = true;",use_slider,precision);
18557 bpr 1968
          tmp_buffer=my_newmem(MAX_BUFFER);
1969
          check_string_length(snprintf(tmp_buffer,MAX_BUFFER, "slider%d = new move_group(%d);\n",use_slider,use_slider));
18552 bpr 1970
          add_to_buffer(tmp_buffer);
1971
          break;
1972
        case HALFLINE:
1973
  /*
1974
  @ demiline x1,y1,x2,y2,color
1975
  @ alternative: halfline
1976
  @ draws a halfline starting in (x1:y1) and through (x2:y2) in color 'color' (colorname or hex)
1977
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
1978
  @%halfline%size 400,400%xrange -10,10%yrange -10,10%halfline -5,5,0,0,red%halfline -5,-5,0,0,blue
1979
  */
1980
          for(i=0; i<13;i++){double_data[i]=0;}
1981
          for(i=0;i<5;i++){
1982
            switch(i){
1983
              case 0: double_data[0]= get_real(infile,0);break; /* x-values */
1984
              case 1: double_data[1]= get_real(infile,0);break; /* y-values */
1985
              case 2: double_data[10]= get_real(infile,0);break; /* x-values */
1986
              case 3: double_data[11]= get_real(infile,0);break; /* y-values */
1987
              case 4: stroke_color=get_color(infile,1);/* name or hex color */
1988
                if(double_data[0] == double_data[10]){ /* vertical halfline */
1989
                  if(double_data[1] < double_data[11]){
1990
                    double_data[3] = ymax + 1000;
1991
                  }
1992
                  else {
1993
                    double_data[3] = ymin - 1000;
1994
                  }
1995
                  double_data[2] = double_data[0];
1996
                } else { /* horizontal halfline*/
1997
                  if( double_data[1] == double_data[11] ){
1998
                    if( double_data[0] < double_data[10] ){
1999
                      double_data[2] = xmax + 1000; /* halfline to the right */
2000
                    }
2001
                    else {
2002
                      double_data[2] = xmin - 1000; /* halfline to the left */
2003
                    }
2004
                    double_data[3] = double_data[1];
2005
                  }
2006
                else {
2007
          /* any other halfline */
2008
          /* slope */
2009
                  double_data[12] = (double_data[11] - double_data[1])/(double_data[10] - double_data[0]);
2010
                /* const */
2011
                  double_data[13] = double_data[1] - double_data[12]*double_data[0];
2012
                  if( double_data[0] < double_data[10] ){
2013
                    double_data[2] = double_data[2] + 1000;
2014
                  }
2015
                  else {
2016
                    double_data[2] = double_data[2] - 1000;
2017
                  }
2018
                  double_data[3] = double_data[12]*double_data[2] + double_data[13];
2019
                }
2020
              }
2021
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2022
              if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
2023
              if(use_affine == TRUE ){ transform(4,2);}
18557 bpr 2024
              tmp_buffer=my_newmem(MAX_BUFFER);
2025
              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 2026
              add_to_buffer(tmp_buffer);
2027
              if(onclick != 0){object_cnt++;}
2028
        /* object_cnt++; */
2029
              reset();
2030
              break;
2031
            }
2032
          }
2033
          dragstuff[18] = 1;
2034
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2035
          break;
2036
        case HALFLINES:
2037
  /*
2038
  @ demilines color,x1,y1,x2,y2,....
2039
  @ alternative: halflines
2040
  @ draws halflines starting in (x1:y1) and through (x2:y2) in color 'color' (colorname or hex) etc
2041
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> indiviually
2042
  @%halflines%size 400,400%xrange -10,10%yrange -10,10%halflines red,-5,5,0,0,-5,-5,0,0
2043
  */
2044
          stroke_color=get_color(infile,0);
2045
          fill_color = stroke_color;
2046
          i=0;
2047
          while( ! done ){     /* get next item until EOL*/
2048
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
2049
            if(i%2 == 0 ){
2050
              double_data[i] = get_real(infile,0); /* x */
2051
            } else {
2052
              double_data[i] = get_real(infile,1); /* y */
2053
            }
2054
            i++;
2055
          }
2056
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2057
          decimals = find_number_of_digits(precision);
2058
          for(c = 0 ; c < i-1 ; c = c+4){
2059
            if( double_data[c] == double_data[c+2] ){ /* vertical line*/
2060
              if(double_data[c+1] < double_data[c+3]){ /* upright halfline */
2061
                double_data[c+3] = ymax + 1000;
2062
              }
2063
              else {
2064
                double_data[c+3] = ymin - 1000;/* descending halfline */
2065
              }
2066
            }
2067
            else {
2068
              if( double_data[c+1] == double_data[c+3] ){ /* horizontal line */
2069
                if(double_data[c] < double_data[c+2] ){ /* halfline to the right */
2070
                  double_data[c+2] = xmax+100;
2071
                }
2072
                else {
2073
                  double_data[c+2] = xmin-1000; /* halfline to the right */
2074
                }
2075
              }
2076
              else {
2077
      /* m */
2078
                double m = (double_data[c+3] - double_data[c+1]) /(double_data[c+2] - double_data[c]);
2079
      /* q */
2080
                double q = double_data[c+1] - ((double_data[c+3] - double_data[c+1]) /(double_data[c+2] - double_data[c]))*double_data[c];
2081
                if(double_data[c] < double_data[c+2]){ /* to the right */
2082
                  double_data[c+2] = xmax+1000; /* 1000 is needed for dragging...otherwise it is just segment */
2083
                  double_data[c+3] = (m)*(double_data[c+2])+(q);
2084
                  }
2085
                  else { /* to the left */
2086
                    double_data[c+2] = xmin - 1000;
2087
                    double_data[c+3] = (m)*(double_data[c+2])+(q);
2088
                  }
2089
                }
2090
              }
2091
              if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
2092
              if(use_affine == TRUE ){ transform(i-1,2);}
18557 bpr 2093
              tmp_buffer=my_newmem(MAX_BUFFER);
2094
              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 2095
              add_to_buffer(tmp_buffer);
2096
              if(onclick != 0){object_cnt++;}/* object_cnt++; */
2097
            }
2098
          reset();
2099
          dragstuff[18] = 1;
2100
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2101
          break;
2102
        case HATCHFILL:
2103
  /*
2104
  @ hatchfill x0,y0,dx,dy,color
2105
  @ x0,y0 in xrange / yrange
2106
  @ distances dx,dy in pixels
2107
  @ there is also a command <a href="#userdraw">userdraw hatchfill,color</a>
2108
  @%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
2109
  */
2110
          js_function[DRAW_HATCHFILL] = 1;
2111
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
2112
            js_function[DRAW_FILLTOBORDER] = 1;
2113
            add_js_filltoborder(canvas_type);
2114
          }
2115
          decimals = find_number_of_digits(precision);
2116
          for(i=0;i<5;i++){
2117
            switch(i){
2118
              case 0: double_data[0] = get_real(infile,0); break; /* x */
2119
              case 1: double_data[1] = get_real(infile,0); break; /* y  */
2120
              case 2: int_data[0] = (int) (get_real(infile,0)); break; /* dx pixel */
2121
              case 3: int_data[1] = (int) (get_real(infile,0)); break; /* dy pixel*/
2122
              case 4: stroke_color = get_color(infile,1);
2123
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
2124
                if(use_affine == TRUE ){ transform(2,2);}
2125
                /* draw_hatchfill(ctx,x0,y0,dx,dy,linewidth,color,opacity,xsize,ysize) */
18557 bpr 2126
                tmp_buffer=my_newmem(MAX_BUFFER);
2127
                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 2128
                add_to_buffer(tmp_buffer);
2129
                fill_cnt++;
2130
                reset();
2131
                break;
2132
              default:break;
2133
            }
2134
          }
2135
          break;
2136
        case HLINE:
2137
  /*
2138
  @ hline x,y,color
2139
  @ alternative: horizontalline
2140
  @ draw a horizontal line through point (x:y) in color 'color'
2141
  @ 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)
2142
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
2143
  @%hline%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%hline 0,0,red%dhline 0,5,blue
2144
  */
2145
          for(i=0;i<3;i++) {
2146
            switch(i){
2147
              case 0: double_data[0] = get_real(infile,0);break; /* x-values */
2148
              case 1: double_data[1] = get_real(infile,0);break; /* y-values */
2149
              case 2: stroke_color = get_color(infile,1);/* name or hex color */
2150
                double_data[3] = double_data[1];
2151
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
2152
                if(use_affine == TRUE ){ transform(2,2);}
2153
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2154
                decimals = find_number_of_digits(precision);
18557 bpr 2155
                tmp_buffer=my_newmem(MAX_BUFFER);
2156
                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 2157
                add_to_buffer(tmp_buffer);
2158
                if(onclick != 0){object_cnt++;}/* object_cnt++; */
2159
                dragstuff[4] = 1;
2160
                if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2161
                reset();
2162
                break;
2163
            }
2164
          }
2165
          break;
2166
        case HLINES:
2167
  /*
2168
  @ hlines color,x1,y1,x2,y2,...
2169
  @ alternative: horizontallines
2170
  @ draw horizontal lines through points (x1:y1)...(xn:yn) in color 'color'
2171
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
2172
  @%hlines%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%hlines red,0,0,0,5,0,-5
2173
  */
2174
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
2175
          fill_color = stroke_color;
2176
          i=0;
2177
          while( ! done ){     /* get next item until EOL*/
2178
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
2179
            if(i%2 == 0 ){
2180
                double_data[i] = get_real(infile,0); /* x */
2181
            }
2182
            else {
2183
              double_data[i] = get_real(infile,1); /* y */
2184
            }
2185
            i++;
2186
          }
2187
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
2188
          if(use_affine == TRUE ){ transform(i-1,2);}
2189
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
11806 schaersvoo 2190
 
18552 bpr 2191
          decimals = find_number_of_digits(precision);
2192
          for(c = 0 ; c < i-1 ; c = c+2){
18557 bpr 2193
            tmp_buffer=my_newmem(MAX_BUFFER);
18607 bpr 2194
            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 2195
            add_to_buffer(tmp_buffer);
2196
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
2197
          }
2198
          reset();
2199
          dragstuff[4] = 1;
2200
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2201
          break;
2202
        case HTTP:
2203
  /*
18556 bpr 2204
  @ http x1,y1,x2,y2,http://some_adress.com
2205
  @ an active html-page will be displayed in an "iframe" rectangle left top (x1:y1), right bottom (x2:y2)
2206
  @ do not use interactivity (or mouse) if the mouse needs to be active in the iframe
2207
  @ can <b>not</b> be ''set onclick`` or ''drag xy``
2208
  @%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 2209
  */
2210
          js_function[DRAW_HTTP] = 1;
2211
          for(i=0;i<5;i++){
2212
            switch(i){
2213
              case 0: int_data[0]=x2px(get_real(infile,0));break; /* x in x/y-range coord system -> pixel width */
2214
              case 1: int_data[1]=y2px(get_real(infile,0));break; /* y in x/y-range coord system  -> pixel height */
2215
              case 2: int_data[2]=x2px(get_real(infile,0)) - int_data[0];break; /* width in x/y-range coord system -> pixel width */
2216
              case 3: int_data[3]=y2px(get_real(infile,0)) - int_data[1];break; /* height in x/y-range coord system  -> pixel height */
2217
              case 4: decimals = find_number_of_digits(precision);
2218
                temp = get_string(infile,1);
2219
                if(strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'");}
18557 bpr 2220
                tmp_buffer = my_newmem(string_length+2);
2221
                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 2222
                add_to_buffer(tmp_buffer);
2223
               break;
2224
            }
2225
          }
2226
          reset();
2227
          break;
2228
        case HTML:
2229
  /*
18556 bpr 2230
  @ html x1,y1,html_string
2231
  @ all tags are allowed, html code using inputfields could be read using your own javascript code. Do not use ids like 'canvas_input0' etc.
2232
  @ can be set <a href='#onclick'>onclick</a>  and <a href='#drag'>drag&amp;drop</a>
2233
  @ command <a href='#affine'>affine</a> will produce CSS3 matrix transformations
2234
  @ command <a href='#rotate'>rotate</a> will rotate the object
2235
  @ use keyword <a href='#centered'>centered</a> to center the html object on (x1:y1)
2236
  @ 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)``
2237
  @ note: sub &amp; sup are supported in command family <a href='#string'>string</a>, e.g. real internal canvas objects !
2238
  @%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
2239
  @%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 2240
  */
2241
          js_function[DRAW_XML] = 1;
2242
          for(i=0;i<5;i++){
2243
            switch(i){
2244
              case 0: double_data[0] = get_real(infile,0);break;
2245
              case 1: double_data[1] = get_real(infile,0);break;
2246
              case 4: decimals = find_number_of_digits(precision);
2247
                if(use_affine == TRUE ){ transform(2,2);}/* needs double_data[] */
2248
                if( use_offset != 0 || drag_type != -1 ){int_data[2] = 1;}else{int_data[2] = 0;} /* only centered or not-centered */
2249
                int_data[0] = x2px(double_data[0]);/* needs px */
2250
                int_data[1] = y2px(double_data[1]);
2251
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2252
                if( use_slider != -1 && drag_type != -1){ onclick = 5; }
2253
                temp = get_string(infile,1);
2254
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","\\\""); }
2255
                if( strstr(temp,"<img ")!= 0){URL="image";}else{URL="html";}
18557 bpr 2256
                tmp_buffer=my_newmem(MAX_BUFFER);
2257
                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 2258
                add_to_buffer(tmp_buffer);
2259
                if(onclick != 0 ){object_cnt++;}
2260
                drawxml_cnt++;/* keeps track on imported img,div,p,span,mathml,svg */
2261
                break;
2262
              default:break;
2263
            }
2264
          }
2265
          reset();
2266
          break;
2267
        case IMAGEFILL:
2268
  /*
2269
  @ imagefill x,y,scaling to xsize &times; ysize?,image_url
2270
  @ The next suitable <b>filled object</b> will be filled with "image_url" tiled
2271
  @ scaling to xsize &times; ysize ? ... 1 = yes 0 = no
2272
  @ After pattern filling, the fill-color should be reset !
2273
  @ wims getins / image from class directory: imagefill 80,80,my_image.gif
2274
  @ normal url: imagefill 80,80,0,&#36;module_dir/gifs/my_image.gif
2275
  @ normal url: imagefill 80,80,1,http://adres/a/b/c/my_image.jpg
2276
  @ if dx,dy is larger than the image, the whole image will be background to the next object.
2277
  @%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
2278
  @%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
2279
  */
2280
          js_function[DRAW_IMAGEFILL] = 1;
2281
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
2282
            js_function[DRAW_FILLTOBORDER] = 1;
2283
            add_js_filltoborder(canvas_type);
2284
          }
2285
          for(i=0 ;i < 4 ; i++){
2286
            switch(i){
2287
              case 0:int_data[0] = (int) (get_real(infile,0));break;
2288
              case 1:int_data[1] = (int) (get_real(infile,0));break;
2289
              case 2:int_data[2] = (int) (get_real(infile,0));break; /* 0 | 1 */
2290
              case 3: URL = get_string_argument(infile,1);
18557 bpr 2291
                tmp_buffer=my_newmem(MAX_BUFFER);
2292
                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 2293
                add_to_buffer(tmp_buffer);
2294
                fill_cnt++;
2295
              break;
2296
            }
2297
          }
2298
          reset();
2299
          break;
2300
        case IMAGEPALETTE:
2301
  /*
18556 bpr 2302
  @ imagepalette image1,image2,image3,...
2303
  @ 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``.
2304
  @%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 2305
   */
2306
          temp = get_string(infile,1);
2307
          temp = str_replace(temp,",","\",\"");
2308
          if( use_tooltip == 1 ){canvas_error("command 'imagepalette' is incompatible with command 'intooltip tip_text',as they use the same div-element ");}
2309
          fprintf(js_include_file,"\nvar current_id;var imagepalette = [\" %s \"];\n",temp);
2310
          break;
2311
        case INPUT:
2312
  /*
18556 bpr 2313
  @ input x,y,size,editable,value
2314
  @ to set inputfield "readonly", use editable = 0
2315
  @ if no preset 'value' is needed...use a 'space' as last item argument
2316
  @ only active inputfields (editable = 1) will be read with read_canvas();
2317
  @ 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>
2318
  @ may be further controlled by <a href="#css">css</a>
2319
  @ if mathml inputfields are present and / or some userdraw is performed, these data will <b>not</b> be send as well (javascript:read_canvas();)
2320
  @ 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)
2321
  @ 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>
2322
  @%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 2323
  */
2324
          js_function[DRAW_INPUTS] = 1;
2325
          for(i = 0 ; i<5;i++){
2326
            switch(i){
2327
              case 0: int_data[0]=x2px(get_real(infile,0));break;/* x in px */
2328
              case 1: int_data[1]=y2px(get_real(infile,0));break;/* y in px */
2329
              case 2: int_data[2]=abs( (int)(get_real(infile,0)));break; /* size */
2330
              case 3: if( get_real(infile,1) >0){int_data[3] = 1;}else{int_data[3] = 0;};break; /* readonly */
2331
              case 4: temp = get_string(infile,3);
18557 bpr 2332
                tmp_buffer=my_newmem(MAX_BUFFER);
2333
                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 2334
                add_to_buffer(tmp_buffer);
2335
                input_cnt++;break;
2336
              default: break;
2337
            }
2338
          }
2339
          if(reply_format == 0 ){reply_format = 15;}
2340
          reset();
2341
          break;
2342
        case INTOOLTIP:
18556 bpr 2343
  /*
2344
  @ intooltip link_text
2345
  @ link_text is a single line (span-element)
2346
  @ link_text may also be an image URL ''http://some_server/images/my_image.png`` or ''&#36;module_dir/gifs/my_image.jpg``
2347
  @ link_text may contain HTML markup
2348
  @ the canvas will be displayed in a tooltip on ''link_text``
2349
  @ 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'.
2350
  @ 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...
2351
  @%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>
2352
  */
18552 bpr 2353
          if(use_input_xy != FALSE ){canvas_error("intooltip can not be combined with userinput_xy or other commands using the tooltip-div...see documentation");}
2354
          if( use_tooltip == 1 ){ canvas_error("command 'intooltip' cannot be combined with command 'popup'...");}
2355
          tooltip_text = get_string(infile,1);
2356
          if(strstr(tooltip_text,"\"") != 0 ){ tooltip_text = str_replace(tooltip_text,"\"","'"); }
2357
          use_tooltip = 1;
2358
          break;
2359
        case JSCURVE:
2360
  /*
18556 bpr 2361
  @ jscurve color,formula1(x),formula2(x),formula3(x),...
2362
  @ alternative: jsplot
2363
  @ your function will be plotted by the javascript engine of the client browser
2364
  @ 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
2365
  @ use only basic math in your curve: <code>sqrt,^,asin,acos,atan,log,pi,abs,sin,cos,tan,e</code>
2366
  @ use parenthesis and rawmath: use 2*x instead of 2x ; use 2^(sin(x))...etc etc (use error console to debug any errors...)
2367
  @ <b>attention</b>: last ''precision`` command in the canvasdraw script determines the calculation precision of the javascript curve plot !
2368
  @ no validity check is done by wims.
2369
  @ 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
2370
  @ 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
2371
  @ zooming & panning in case of userbased functionplot: reclick the OK button to re-plot curve onto the resized grid
2372
  @ use keyword <a href='animate'>animate</a> for animating a point on the curve
2373
  @ use command ''trace_jscurve formula(x)`` for tracing
2374
  @ use command ''jsmath formula(x)`` for calculating and displaying indiviual points on the curve
2375
  @ can <b>not</b> be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> (yet)
2376
  @ commands plotjump / plotstep are not active for ''jscurve``
2377
  @ every command jscurve will produce a new canvas (canvastype 111,112,113...) for this one curve.
18572 bpr 2378
  @ 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 2379
  @%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 2380
  */
2381
          jsplot_cnt++;/* -1 --> 0 */
2382
          stroke_color = get_color(infile,0);
2383
          js_function[JS_MATH] = 1;
2384
          js_function[JS_PLOT] = 1;
2385
          if( tmin != 0 && tmax !=0){use_parametric = TRUE;}
2386
          temp = get_string(infile,1);
2387
          temp = str_replace(temp,",","\",\"");
18557 bpr 2388
          tmp_buffer=my_newmem(MAX_BUFFER);
2389
          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 2390
          add_to_buffer(tmp_buffer);
2391
          fprintf(js_include_file,"if(typeof(all_jsplots) !== 'number'){var all_jsplots;};all_jsplots = %d;",jsplot_cnt);
11806 schaersvoo 2392
 
18552 bpr 2393
       /* we need to create multiple canvasses, so we may zoom and pan ?? */
2394
          break;
2395
        case JSMATH:
2396
  /*
18556 bpr 2397
  @ jsmath some_math_function
2398
  @ will calculate an y-value from a userinput x-value and draws a crosshair on these coordinates.
2399
  @ 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
2400
  @ use command 'css some_css' for styling the display fields. Use command 'fontsize int' to size the labels ''x`` and ''y``
2401
  @ 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...
2402
  @ be aware that the formula's of the plotted function(s) can be found in the page javascript source
2403
  @%jsmath%size 400,400%xrange -10,10%yrange -10,10%jsplot blue,sin(x^2)%jsmath sin(x^2)
18552 bpr 2404
  */
2405
          js_function[DRAW_CROSSHAIRS] = 1;
2406
          js_function[JS_MATH] = 1;
2407
          add_calc_y(get_string(infile,1),font_size,css_class);
2408
          break;
2409
        case KILL:
2410
  /*
2411
  @ kill arguments
2412
  @ arguments may be: affine linear translation rotation slider offset  reset
2413
  @ for documentation see: killaffine,killlinear,killtranslation...
2414
  @ multiple arguments are allowed (although not checked for validity...)
2415
  */
2416
          temp = get_string(infile,1);
2417
          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;}
2418
          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;}
2419
          if(strstr(temp,"translation") != 0 || strstr(temp,"translate") != 0 ){affine_matrix[4] = 0.0;affine_matrix[5] = 0.0;}
2420
          if(strstr(temp,"rotation") != 0 || strstr(temp,"rotate") != 0 ){use_rotate = FALSE;angle = 0.0;rotation_center="null";}
2421
          if(strstr(temp,"slider") != 0 ){slider_type = "0";my_sliders = "[-1]";last_slider = use_slider+1;}
2422
          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();}
2423
          if(strstr(temp,"reset") != 0 ){if(no_reset == FALSE){no_reset = TRUE;}else{no_reset = FALSE;reset();}}
2424
          if(strstr(temp,"offset") != 0 ){use_offset = 0;}
2425
          break;
2426
        case KILLAFFINE:
2427
  /*
2428
  @ killaffine
2429
  @ keyword: resets the transformation matrix to 1,0,0,1,0,0
2430
  @ note: any active linear transformation will also be reset: tx=0, ty=0
2431
  */
2432
          use_affine = FALSE;
2433
          affine_matrix[0] = 1.0;
2434
          affine_matrix[1] = 0.0;
2435
          affine_matrix[2] = 0.0;
2436
          affine_matrix[3] = 1.0;
2437
          affine_matrix[4] = 0.0;
2438
          affine_matrix[5] = 0.0;
2439
          break;
2440
        case KILLLINEAR:
2441
  /*
2442
  @ killlinear
2443
  @ keyword: resets the transformation matrix to 1,0,0,1,tx,ty
2444
  @ note:any active transformation or rotation will not be killed (tx,ty remain active)
2445
  */
2446
          affine_matrix[0] = 1.0;
2447
          affine_matrix[1] = 0.0;
2448
          affine_matrix[2] = 0.0;
2449
          affine_matrix[3] = 1.0;
2450
          break;
2451
        case KILLROTATE:
2452
  /*
18556 bpr 2453
  @ killrotate
2454
  @ will set the rotation angle to 0.
18572 bpr 2455
  @ 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 2456
  @ if not set, the rotation center will remain unchanged
2457
  @ note:any active transformation or linear will not be killed (e.g an active transformation matrix remains active)
2458
  @%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 2459
  */
2460
          use_rotate = FALSE;
2461
          angle = 0.0;
2462
          rotation_center="null";
2463
          break;
2464
        case KILLSLIDER:
2465
  /*
18556 bpr 2466
  @ killslider
2467
  @ keyword (no arguments required)
2468
  @ ends grouping of object under a previously defined slider
18552 bpr 2469
  */
2470
          slider_type = "0";
2471
          my_sliders = "[-1]";
2472
          last_slider = use_slider+1;
2473
          break;
2474
        case KILLTRANSLATION:
2475
  /*
18556 bpr 2476
  @ killtranslation
2477
  @ alternative: killtranslate
2478
  @ note: a active linear or affine transformation will not be 100% reset...only tx=0,ty=0
2479
  @ resets the translation matrix a,b,c,d,tx,ty to a,b,c,d,0,0
18552 bpr 2480
  */
2481
          affine_matrix[4] = 0.0;
2482
          affine_matrix[5] = 0.0;
2483
          break;
2484
        case LATEX:
2485
  /*
18556 bpr 2486
  @ latex x,y,tex string
2487
  @ alternative: math
18572 bpr 2488
  @ 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 2489
  @ 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)
2490
  @ 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)
2491
  @ 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
2492
  @ 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...
2493
  @ can be moved/rotated with command <a href='#slider'>slider</a>
2494
  @ snaptogrid is supported
18627 bpr 2495
  @ 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 2496
  @ userdraw may be combined with 'latex' ; the js-function 'read_canvas()' will contain the coordinates of the drawing.
2497
  @ userdraw may be combined; the read_canvas() will contain the drawing.
2498
  @ 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
2499
  @ other drag objects (circles/rects etc) are supported, but read_dragdrop() will probably be difficult to interpret...
2500
  @ 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();"
2501
  @ 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....
2502
  @ 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]
2503
  @ 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>)
2504
  @ 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)``
2505
  @%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}
2506
  @%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 2507
  */
2508
          js_function[DRAW_XML] = 1;
2509
          for(i=0;i<3;i++){
2510
            switch(i){
2511
              case 0: double_data[0]=get_real(infile,0);break; /* x in x/y-range coord system -> pixel width */
2512
              case 1: double_data[1]=get_real(infile,0);break; /* y in x/y-range coord system  -> pixel height */
2513
              case 2: decimals = find_number_of_digits(precision);
2514
                temp = get_string(infile,1);
2515
                if(use_affine == TRUE ){ transform(2,2);}/* slider will use css-rotate transformation */
2516
                if( use_offset != 0 || drag_type != -1 ){int_data[2] = 1;}else{int_data[2] = 0;} /* only centered or not-centered */
2517
                int_data[0] = x2px(double_data[0]);
2518
                int_data[1] = y2px(double_data[1]);
2519
                if( use_slider != -1 && onclick == 0 ){ onclick = 5;}
2520
                if( use_slider != -1 && drag_type != -1){ onclick = 5; }
15757 schaersvoo 2521
#ifdef KATEX_INSTALLED
18552 bpr 2522
                if( strstr(temp,"\\") != 0 ){ temp = str_replace(temp,"\\","\\\\"); }
2523
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'"); }
18557 bpr 2524
                tmp_buffer=my_newmem(MAX_BUFFER);
2525
                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 2526
#else
18552 bpr 2527
                temp = getMML(temp);/* generate MathML for Firefox or MathJaX */
2528
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'"); }
18557 bpr 2529
                tmp_buffer=my_newmem(MAX_BUFFER);
2530
                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 2531
#endif
18552 bpr 2532
                add_to_buffer(tmp_buffer);
2533
                if(onclick != 0 ){object_cnt++;}
2534
                drawxml_cnt++;/* keeps track on imported img,div,p,span,mathml,svg */
2535
                break;
2536
              default:break;
2537
              }
2538
          }
2539
          reset();
2540
          break;
2541
        case LATTICE:
2542
  /*
18556 bpr 2543
  @ lattice x0,y0,xv1,yv1,xv2,yv2,n1,n2,color
2544
  @ can <b>not</b> be set ''onclick`` or ''drag xy``
2545
  @%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 2546
  */
2547
          js_function[DRAW_LATTICE] = 1;
2548
          for( i = 0; i<9; i++){
2549
            switch(i){
2550
              case 0: int_data[0] = x2px(get_real(infile,0));break; /* x0-values  -> x-pixels*/
2551
              case 1: int_data[1] = y2px(get_real(infile,0));break; /* y0-values  -> y-pixels*/
2552
              case 2: int_data[2] = (int) (get_real(infile,0));break; /* x1-values  -> x-pixels*/
2553
              case 3: int_data[3] = (int) -1*(get_real(infile,0));break; /* y1-values  -> y-pixels*/
2554
              case 4: int_data[4] = (int) (get_real(infile,0));break; /* x2-values  -> x-pixels*/
2555
              case 5: int_data[5] = (int) -1*(get_real(infile,0));break; /* y2-values  -> y-pixels*/
2556
              case 6: int_data[6] = (int) (get_real(infile,0));break; /* n1-values */
2557
              case 7: int_data[7] = (int) (get_real(infile,0));break; /* n2-values */
2558
              case 8: stroke_color=get_color(infile,1);
2559
                decimals = find_number_of_digits(precision);
18557 bpr 2560
                tmp_buffer=my_newmem(MAX_BUFFER);
2561
                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 2562
                add_to_buffer(tmp_buffer);break;
2563
              default:break;
2564
            }
2565
          }
2566
          reset();
2567
          break;
2568
        case LINEAR:
2569
  /*
18556 bpr 2570
  @ linear a,b,c,d
2571
  @ defines a transformation matrix for subsequent objects
2572
  @ use keyword <a href='#killlinear'>killlinear</a> to end the transformation...the next objects will be drawn in the original x/y-range
2573
  @ a: Scales the drawings horizontally
2574
  @ b: Skews the drawings horizontally
2575
  @ c: Skews the drawings vertically
2576
  @ d: Scales the drawings vertically
2577
  @ the data precision may be set by preceding command ''precision int``
2578
  @ note: any active translation (tx,ty) is not changed
2579
  @%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 2580
  */
2581
          for(i = 0 ; i<4;i++){
2582
            switch(i){
2583
              case 0: affine_matrix[0] = get_real(infile,0);break;
2584
              case 1: affine_matrix[1] = get_real(infile,0);break;
2585
              case 2: affine_matrix[2] = get_real(infile,0);break;
2586
              case 3: affine_matrix[3] = get_real(infile,1);
2587
                affine_matrix[4] = 0;affine_matrix[5] = 0;
2588
                use_affine = TRUE;
2589
                break;
2590
              default: break;
2591
            }
2592
          }
2593
          reset();
2594
         break;
2595
        case LINE:
2596
  /*
2597
  @ line x1,y1,x2,y2,color
2598
  @ draw a line through points (x1:y1)--(x2:y2) in color ''color``
2599
  @ or use command ''curve color,formula`` to draw the line (uses more points to draw the line; is however better draggable)
2600
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
2601
  @%line%size 400,400%xrange -10,10%yrange -10,10%line 0,1,2,-1,green
2602
  */
2603
          for(i=0;i<5;i++){
2604
            switch(i){
2605
              case 0: double_data[10]= get_real(infile,0);break; /* x-values */
2606
              case 1: double_data[11]= get_real(infile,0);break; /* y-values */
2607
              case 2: double_data[12]= get_real(infile,0);break; /* x-values */
2608
              case 3: double_data[13]= get_real(infile,0);break; /* y-values */
2609
              case 4: stroke_color=get_color(infile,1);/* name or hex color */
2610
                if( double_data[10] == double_data[12] ){ /* vertical line*/
2611
                  double_data[1] = xmin;
2612
                  double_data[3] = ymax;
2613
                  double_data[0] = double_data[10];
2614
                  double_data[2] = double_data[10];
2615
                }
2616
                else{
2617
                  if( double_data[11] == double_data[13] ){ /* horizontal line */
2618
                    double_data[1] = double_data[11];
2619
                    double_data[3] = double_data[11];
2620
                    double_data[0] = ymin;
2621
                    double_data[2] = xmax;
2622
                }
2623
                else {
2624
      /* m */
2625
                  double_data[5] = (double_data[13] - double_data[11]) /(double_data[12] - double_data[10]);
2626
      /* q */
2627
                  double_data[6] = double_data[11] - ((double_data[13] - double_data[11]) /(double_data[12] - double_data[10]))*double_data[10];
2628
      /*xmin,m*xmin+q,xmax,m*xmax+q*/
2629
                  double_data[1] = (double_data[5])*(xmin)+(double_data[6]);
2630
                  double_data[3] = (double_data[5])*(xmax)+(double_data[6]);
2631
                  double_data[0] = xmin;
2632
                  double_data[2] = xmax;
2633
                }
2634
              }
2635
              if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
2636
              if(use_affine == TRUE ){ transform(4,2);}
2637
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2638
              decimals = find_number_of_digits(precision);
18557 bpr 2639
              tmp_buffer=my_newmem(MAX_BUFFER);
2640
              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 2641
              add_to_buffer(tmp_buffer);
2642
              if(onclick != 0){object_cnt++;}
2643
        /* object_cnt++;*/
2644
              reset();
2645
              break;
2646
            }
2647
          }
2648
          dragstuff[4] = 1;
2649
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2650
          break;
2651
        case LINES:
2652
  /*
2653
  @ lines color,x1,y1,x2,y2...x_n-1,y_n-1,x_n,y_n
2654
  @ draw multiple lines through points (x1:y1)--(x2:y2) ...(x_n-1:y_n-1)--(x_n:y_n) in color 'color'
2655
  @ 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)
2656
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
2657
  @%lines%size 400,400%xrange -10,10%yrange -10,10%lines green,0,1,1,3,0,0,1,3,0,0,-2,1
2658
  */
2659
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
2660
          fill_color = stroke_color;
2661
          i=0;
2662
          while( ! done ){     /* get next item until EOL*/
2663
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
2664
            if(i%2 == 0 ){
2665
              double_data[i] = get_real(infile,0); /* x */
2666
            }
2667
            else {
2668
              double_data[i] = get_real(infile,1); /* y */
2669
            }
2670
            i++;
2671
          }
2672
          decimals = find_number_of_digits(precision);
2673
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2674
          for(c = 0 ; c < i-1 ; c = c+4){
2675
            if(double_data[c] == double_data[c+2] ){ /* vertical line*/
2676
              double_data[c+1] = xmin;
2677
              double_data[c+3] = ymax;
2678
              double_data[c+2] = double_data[c];
2679
            }
2680
            else {
2681
              if( double_data[c+1] == double_data[c+3] ){ /* horizontal line */
2682
                double_data[c+3] = double_data[c+1];
2683
                double_data[c] = ymin;
2684
                double_data[c+2] = xmax;
2685
              }
2686
              else {
2687
      /* m */
2688
                double m = (double_data[c+3] - double_data[c+1]) /(double_data[c+2] - double_data[c]);
2689
      /* q */
2690
                double q = double_data[c+1] - ((double_data[c+3] - double_data[c+1]) /(double_data[c+2] - double_data[c]))*double_data[c];
2691
      /*xmin,m*xmin+q,xmax,m*xmax+q*/
2692
                double_data[c+1] = (m)*(xmin)+(q);
2693
                double_data[c+3] = (m)*(xmax)+(q);
2694
                double_data[c] = xmin;
2695
                double_data[c+2] = xmax;
2696
              }
2697
            }
2698
            if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
2699
            if(use_affine == TRUE ){ transform(i-1,2);}
18557 bpr 2700
            tmp_buffer=my_newmem(MAX_BUFFER);
2701
            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 2702
            add_to_buffer(tmp_buffer);
2703
            if(onclick != 0){object_cnt++;}
2704
    /* object_cnt++; */
2705
          }
2706
          dragstuff[4] = 1;
2707
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2708
          reset();
2709
          break;
2710
        case LINEWIDTH:
2711
  /*
2712
  @ linewidth int
2713
  @ default 1
2714
  @%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
2715
  */
2716
          line_width = (int) (get_real(infile,1));
2717
          break;
2718
        case LEVELCURVE:
2719
  /*
2720
  @ levelcurve color,expression in x/y,l1,l2,...
2721
  @ draws very primitive level curves for expression, with levels l1,l2,l3,...,l_n
2722
  @ the quality is <b>not to be compared</b> with the Flydraw levelcurve. <br>(choose flydraw if you want quality...)
2723
  @ 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
2724
  @ note: the arrays for holding the javascript data are limited in size
2725
  @ note: reduce image size if javascript data arrays get overloaded<br>(command 'plotsteps int' will not control the data size of the plot...)
2726
  @%levelcurve%size 400,400%xrange -10,10%yrange -10,10%levelcurve red,x*y,1,2,3,4
2727
  */
2728
          fill_color = get_color(infile,0);
2729
          char *fun1 = get_string_argument(infile,0);
2730
          if( strlen(fun1) == 0 ){canvas_error("function is NOT OK !");}
2731
          i = 0;
2732
          done = FALSE;
2733
          while( !done ){
2734
            double_data[i] = get_real(infile,1);
2735
            i++;
2736
          }
2737
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2738
          for(c = 0 ; c < i; c++){
18557 bpr 2739
            tmp_buffer=my_newmem(MAX_BUFFER);
2740
            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 2741
            add_to_buffer(tmp_buffer);
2742
            if(onclick != 0){object_cnt++;}
2743
           /* object_cnt++; */
2744
          }
2745
          dragstuff[16] = 1;
2746
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
2747
          reset();
2748
          break;
2749
        case LEGEND:
2750
  /*
2751
  @ legend string1:string2:string3....string_n
2752
  @ will be used to create a legend for a graph
2753
  @ also see command <a href='#piechart'>piechart</a>
2754
  @ will use the same colors per default as used in the graphs; use command <a href='#legendcolors'>legendcolors</a> to override the default
2755
  @ use command <a href="#fontsize">fontsize</a> to adjust. (command ''fontfamily`` is not active for command ''legend``)
2756
  @%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
2757
  */
2758
          temp = get_string(infile,1);
2759
          if( strstr( temp,":") != 0 ){ temp = str_replace(temp,":","\",\""); }
2760
          legend_cnt++; /* attention: starts with -1: it will be used in piechart etc */
2761
          fprintf(js_include_file,"var legend%d = [\"%s\"];",legend_cnt,temp);
2762
          break;
2763
        case LEGENDCOLORS:
2764
  /*
2765
  @ legendcolors color1:color2:color3:...:color_n
2766
  @ 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>.
2767
  @ make sure the number of colors match the number of legend items
18627 bpr 2768
  @ command ''legend`` in case of ''piechart`` and ''barchart`` will use these colors per default (no need to specify ''legendcolors``)
18552 bpr 2769
  @%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
2770
  */
2771
          if(legend_cnt == -1){canvas_error("use command \"legend\" before command \"legendcolors\" ! ");}
2772
          temp = get_string(infile,1);
2773
          if( strstr( temp,":") != 0 ){ temp = str_replace(temp,":","\",\""); }
2774
          fprintf(js_include_file,"var legendcolors%d = [\"%s\"];",legend_cnt,temp);
2775
          break;
2776
        case LINEGRAPH: /* scheme: var linegraph_0 = [ 'stroke_color','line_width','use_dashed', 'dashtype0','dashtype1','x1','y1',...,'x_n','y_n'];*/
2777
  /*
2778
  @ linegraph x1:y1:x2:y2...x_n:y_n
2779
  @ will plot your data in a graph
2780
  @ may <b>only</b> to be used together with command <a href='#grid'>grid</a>
2781
  @ 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>
2782
  @ use command <a href='#legend'>legend</a> to provide an optional legend in right-top-corner
2783
  @ also see command <a href='#piechart'>piechart</a>
2784
  @ multiple linegraphs may be used in a single plot
2785
  @ note: your arguments are not checked by canvasdraw: use your javascript console in case of trouble...
2786
  @ <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>
2787
  @%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
2788
  */
2789
          temp = get_string(infile,1);
2790
          if( strstr( temp,":") != 0 ){ temp = str_replace(temp,":","\",\""); }
2791
          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);
2792
          linegraph_cnt++;
2793
          reset();
2794
          break;
2795
        case MATHML:
2796
  /*
2797
  @ mathml x1,y1,mathml_string
2798
  @ this command is special for GECKO browsers, and it makes use of Native Mathml
2799
  @ For general use with all browsers, use command <a href='#latex'>latex</a>
2800
  @ 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>
2801
  @ command <a href='#affine'>affine</a> will produce CSS3 matrix transformations
2802
  @ command <a href='#rotate'>rotate</a> will rotate the object
2803
  @ the mathml object is centered at (x1:y1)
2804
  @ the ''mathml_string`` can be produced using WIMS commands like ''texmath`` followed by ''mathmlmath``... or write correct TeX and use only ''mathmlmath``
2805
  @ mathml will be displayed in a rectangle left top (x1:y1)
2806
  @ 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
2807
  @ 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...
2808
  @ 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.
2809
  @ 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.
2810
  @ userdraw may be combined with 'mathml' ; the read_canvas() will contain the drawing.
2811
  @ draggable or onclick 'external images' from command <a href='#copyresized'>copy or copyresized</a> can be combined with drag and/or onclick mathml
2812
  @ other drag objects (circles/rects etc) are supported, but read_dragdrop() will probably be difficult to interpret...
2813
  @ 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();"
2814
  @ 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....
2815
  @ use keyword <a href='#centered'>centered</a> to center the mathml/xml object on (x1:y1)
2816
  @%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>
2817
  @%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...
2818
  */
2819
          js_function[DRAW_XML] = 1;
2820
          for(i=0;i<3;i++){
2821
            switch(i){
2822
              case 0: double_data[0]=get_real(infile,0);break; /* x in x/y-range coord system -> pixel width */
2823
              case 1: double_data[1]=get_real(infile,0);break; /* y in x/y-range coord system  -> pixel height */
2824
              case 2: decimals = find_number_of_digits(precision);
2825
                if(use_affine == TRUE ){ transform(2,2);}/* needs double_data[] */
2826
                if( use_offset != 0 || drag_type != -1 ){int_data[2] = 1;}else{int_data[2] = 0;} /* only centered or not-centered */
2827
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
2828
                int_data[0] = x2px(double_data[0]);/* needs px */
2829
                int_data[1] = y2px(double_data[1]);
2830
                if( use_slider != -1 && onclick == 0 ){ onclick = 3;}/* no drag&onclick but slideable */
2831
                if( use_slider != -1 && drag_type != -1){ onclick = 5; }
2832
                temp = get_string(infile,1);
2833
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'"); }
18557 bpr 2834
                tmp_buffer=my_newmem(MAX_BUFFER);
2835
                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 2836
                add_to_buffer(tmp_buffer);
2837
                if(onclick != 0 ){object_cnt++;}
2838
                drawxml_cnt++;/* keeps track on imported img,div,p,span,mathml,svg */
2839
          /*
2840
            in case inputs are present, trigger adding the read_mathml()
2841
            if no other reply_format is defined
2842
            note: all other reply types will include a reading of elements with id='mathml'+p)
2843
          */
2844
                if(strstr(temp,"mathml0") != NULL){ if(reply_format == 0 ){reply_format = 16;}} /* no other reply type is defined */
2845
                break;
2846
              default:break;
2847
            }
2848
          }
2849
          reset();
2850
          break;
2851
        case MOUSE:
2852
  /*
18556 bpr 2853
  @ mouse color,fontsize
2854
  @ will display the cursor (x:y) coordinates in ''color`` and ''fontsize`` using default fontfamily Arial
2855
  @ note: use command ''mouse`` at the end of your script code (the same is true for command ''zoom``)
2856
  @%mouse%size 400,400%xrange -10,10%yrange -10,10%mouse red,22
18552 bpr 2857
  */
2858
          stroke_color = get_color(infile,0);
2859
          font_size = (int) (get_real(infile,1));
2860
          tmp_buffer = my_newmem(26);
2861
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2862
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,2);
2863
          js_function[INTERACTIVE] = 1;
2864
          break;
2865
        case MOUSE_DEGREE:
2866
  /*
18556 bpr 2867
  @ mouse_degree color,fontsize
2868
  @ 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
2869
  @ The angle is positive in QI and QIII and the angle value is negative in QII and QIV
2870
  @ note: use command 'mouse' at the end of your script code (the same is true for command 'zoom')
2871
  @%mouse_degree%size 400,400%xrange -10,10%yrange -10,10%userdraw arc,blue%precision 100000%mouse_degree red,22
18552 bpr 2872
  */
2873
          stroke_color = get_color(infile,0);
2874
          font_size = (int) (get_real(infile,1));
2875
          tmp_buffer = my_newmem(26);
2876
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2877
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,3);
2878
          js_function[JS_FIND_ANGLE] = 1;
2879
          js_function[INTERACTIVE] = 1;
2880
          break;
2881
        case MOUSE_DISPLAY:
2882
  /*
18556 bpr 2883
  @ display TYPE,color,fontsize
2884
  @ TYPE may be x | y | xy | degree | radian | radius
2885
  @ 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).
2886
  @ use commands ''xunit`` and / or ''yunit`` to add the units to the mouse values. The ''degree | radian`` will always have the appropriate symbol).
2887
  @ just like commands ''mouse``, ''mousex``, ''mousey``, ''mouse_degree``... only other name
2888
  @%display_x%size 400,400%xrange -10,10%yrange -10,10%xunit \\u212B%display x,red,22
2889
  @%display_y%size 400,400%xrange -10,10%yrange -10,10%yunit seconds%display y,red,22
2890
  @%display_xy%size 400,400%xrange -10,10%yrange -10,10%xunit centimetre%yunit seconds%display xy,red,22%userdraw segments,blue
2891
  @%display_deg%size 400,400%xrange -10,10%yrange -10,10%display degree,red,22%fillcolor orange%opacity 200,50%userdraw arc,blue
2892
  @%display_rad%size 400,400%xrange -10,10%yrange -10,10%display radian,red,22%fillcolor orange%opacity 200,50%userdraw arc,blue
2893
  @%display_radius%size 400,400%xrange -10,10%yrange -10,10%xunit cm%xunit \\u212b%display radius,red,22%userdraw circle,blue
18552 bpr 2894
  */
2895
          temp = get_string_argument(infile,0);
2896
          if( strstr(temp,"xy") != NULL ){
2897
            int_data[0] = 2;
2898
          } else {
2899
            if( strstr(temp,"y") != NULL ){
2900
              int_data[0] = 1;
2901
            }else{
2902
              if( strstr(temp,"x") != NULL ){
2903
                int_data[0] = 0;
2904
              }else{
2905
                if(strstr(temp,"degree") != NULL){
2906
                int_data[0] = 3;
2907
                js_function[JS_FIND_ANGLE] = 1;
2908
                }else{
2909
                  if(strstr(temp,"radian") != NULL){
2910
                    int_data[0] = 4;
2911
                    js_function[JS_FIND_ANGLE] = 1;
2912
                  }else{
2913
                    if(strstr(temp,"radius") != NULL){
2914
                      int_data[0] = 5;
2915
                    }else{
2916
                      int_data[0] = 2;
2917
                    }
2918
                  }
2919
                }
2920
              }
2921
            }
2922
          }
2923
          stroke_color = get_color(infile,0);
2924
          font_size = (int) (get_real(infile,1));
2925
          tmp_buffer = my_newmem(26);
2926
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2927
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,int_data[0]);
2928
          js_function[INTERACTIVE] = 1;
2929
          break;
2930
        case MOUSE_PRECISION:
2931
  /*
18556 bpr 2932
  @ precision int
2933
  @ 1 = no decimals ; 10 = 1 decimal ; 100 = 2 decimals etc
2934
  @ may be used / changed before every object
2935
  @ In case of user interaction (like ''userdraw`` or ''multidraw``), this value will be used to determine the amount of decimals in the reply / answer
2936
  @%precision%size 400,400%xrange -10,10%yrange -10,10%precision 1%userdraw segment,red
18552 bpr 2937
  */
2938
          precision = (int) (get_real(infile,1));
2939
          if(precision < 1 ){precision = 1;};
2940
          break;
2941
        case MOUSEX:
2942
  /*
18556 bpr 2943
  @ mousex color,fontsize
2944
  @ will display the cursor x-coordinate in ''color`` and ''font size`` using the fontfamily Arial.
2945
  @ note: use command ''mouse`` at the end of your script code (the same is true for command ''zoom``).
18552 bpr 2946
  */
2947
          stroke_color = get_color(infile,0);
2948
          font_size = (int) (get_real(infile,1));
2949
          tmp_buffer = my_newmem(26);
2950
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2951
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,0);
2952
          js_function[INTERACTIVE] = 1;
2953
          break;
2954
        case MOUSEY:
2955
  /*
18556 bpr 2956
  @ mousey color,fontsize
2957
  @ will display the cursor y-coordinate in ''color`` and ''font size`` using default fontfamily Arial.
2958
  @ note: use command ''mouse`` at the end of your script code (the same is true for command ''zoom``).
8386 schaersvoo 2959
 
18552 bpr 2960
  */
2961
          stroke_color = get_color(infile,0);
2962
          font_size = (int) (get_real(infile,1));
2963
          tmp_buffer = my_newmem(26);
2964
          snprintf(tmp_buffer,26,"use_mouse_coordinates();\n");add_to_buffer(tmp_buffer);
2965
          add_js_mouse(MOUSE_CANVAS,precision,stroke_color,font_size,stroke_opacity,1);
2966
          js_function[INTERACTIVE] = 1;
2967
          break;
2968
        case MULTIDASH:
2969
  /*
18556 bpr 2970
  @ multidash 0,1,1
2971
  @ meaning draw objects no. 2 (circle) and 3 (segments), in the list of command like <code>multifill points,circle,segments</code>, are dashed
2972
  @ use before command <a href='#multidraw'>multidraw</a>
2973
  @ if not set all objects will be set ''not dashed``... unless a generic keyword ''dashed`` was given before command ''multidraw``
2974
  @ 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)
2975
  @ wims will <b>not</b> check if the number of 0 or 1's matches the amount of draw primitives...
2976
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 2977
  */
2978
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
2979
          temp = get_string(infile,1);
2980
          temp = str_replace(temp,",","\",\"");
2981
          fprintf(js_include_file,"var multidash = [\"%s\"];",temp);
2982
          reset();/* if command 'dashed' was given...reset to not-dashed */
2983
          break;
2984
        case MULTIDRAW:
2985
  /*
18556 bpr 2986
  @ multidraw obj_type_1,obj_type_2...obj_type_11
2987
  @ for simple single object user drawings you could also use command <a href="#userdraw">userdraw</a>
18572 bpr 2988
  @ 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 2989
  @ 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
2990
  @ 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...
2991
  @ 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)
2992
  @ 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'
2993
  @ 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)
2994
  @ a right mouse button click will remove the last drawn object of the selected drawing type. All other type of objects are not removed
2995
  @ multidraw is incompatible with command ''tooltip`` (the reserved div_area is used for the multidraw control buttons)
2996
  @ all ''multidraw`` drawings will scale on zooming.<br>this in contrast to the command <a href="#userdraw">userdraw</a>.
2997
  @ 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 2998
  @ 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 2999
  @ 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>
3000
  @ <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.
3001
  @ 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.
3002
  @ 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 3003
  @ 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 3004
  @%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
3005
  @%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
3006
  @%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
3007
  @%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
3008
  @%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 3009
  */
3010
          js_function[INTERACTIVE] = 1;
3011
          if(js_function[JS_ZOOM] == 1){use_zoom = 1;} /* use noisy zoom_code, when command zoom is given before command 'multidraw' */
3012
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3013
          if( use_userdraw == 1 ){canvas_error("Only one userdraw primitive may be used in command 'userdraw' use command 'multidraw' for this...");}
3014
          use_userdraw = 2;
3015
          temp = get_string(infile,1);
3016
          fprintf(js_include_file,"\
3017
            var MMP = %d;\
3018
            if( typeof(multisnaptogrid) == 'undefined' && multisnaptogrid == null){var multisnaptogrid = new Array(MMP);for(var i=0;i<MMP;i++){multisnaptogrid[i] = %d;};};\
3019
            if( typeof(multistrokecolors) === 'undefined' && multistrokecolors == null){ var multistrokecolors = new Array(MMP);for(var i=0;i<MMP;i++){multistrokecolors[i] = '%s';};};\
3020
            if( typeof(multifillcolors) === 'undefined' && multifillcolors == null ){var multifillcolors = new Array(MMP);for(var i=0;i<MMP;i++){multifillcolors[i] = '%s';};};\
3021
            if( typeof(multistrokeopacity) === 'undefined' && multistrokeopacity == null){var multistrokeopacity = new Array(MMP);for(var i=0;i<MMP;i++){multistrokeopacity[i] = %.2f;};};\
3022
            if( typeof(multifillopacity) === 'undefined' &&  multifillopacity == null){var multifillopacity = new Array(MMP);for(var i=0;i<MMP;i++){multifillopacity[i] = %.2f;};};\
3023
            if( typeof(multilinewidth) === 'undefined' && multilinewidth == null){var multilinewidth = new Array(MMP);for(var i=0;i<MMP;i++){multilinewidth[i] = %d;};};\
3024
            if( typeof(multifill) === 'undefined' && multifill == null){var multifill = new Array(MMP);for(var i=0;i<MMP;i++){multifill[i] = %d;};};\
3025
            if( typeof(multidash) === 'undefined' && multidash == null){var multidash = new Array(MMP);for(var i=0;i<MMP;i++){multidash[i] = %d;};};\
3026
            if( typeof(multilabel) === 'undefined' && multilabel == null){var multilabel = [\"%s\",\"stop drawing\"];};\
3027
            if( typeof(multiuserinput) === 'undefined' && multiuserinput == null){var multiuserinput = new Array(MMP);for(var i=0;i<MMP;i++){multiuserinput[i] = '0';};};\
3028
            var arrow_head = %d;var multifont_color = '%s';var multifont_family = '%s';var forbidden_zone = [xsize+2,ysize+2];",
3029
            MAX_MULTI_PRIMITIVES,
3030
            use_snap,
3031
            stroke_color,
3032
            fill_color,
3033
            stroke_opacity,
3034
            fill_opacity,
3035
            line_width,
3036
            use_filled,
3037
            use_dashed,
3038
            str_replace(temp,",","\",\""),
3039
            arrow_head,font_color,font_family);
3040
          add_js_multidraw(temp,css_class,use_offset,int_data[MAX_MULTI_PRIMITIVES+1],crosshair_size,use_zoom);
3041
            /* no_controls == int_data[MAX_MULTI_PRIMITIVES+1] */
3042
          reply_precision = precision;
3043
          if(strstr(temp,"text") != NULL){
3044
            js_function[JS_SAFE_EVAL] = 1;
3045
            js_function[DRAW_SUBSUP] = 1;
3046
          }
3047
          if(strstr(temp,"function") != NULL){
3048
            int pp, funs = count_substring(temp, "function");
3049
            js_function[JS_SAFE_EVAL] = 1;
3050
            js_function[JS_RAWMATH] = 1;
3051
            js_function[DRAW_JSFUNCTION] = 1;
3052
            js_function[JS_MATH] = 1;
3053
            js_function[JS_PLOT] = 1;
3054
            for(pp = 0 ; pp< funs ;pp++){
3055
              add_input_jsfunction(css_class,function_label,input_cnt,stroke_color,stroke_opacity,line_width,use_dashed,dashtype[0],dashtype[1],font_size);
3056
              input_cnt++;
3057
              jsplot_cnt++;
3058
            }
3059
            fprintf(js_include_file,"if(typeof(all_jsplots) !== 'number'){var all_jsplots;};all_jsplots = %d;function redraw_userdraw(){redraw_jsplot();return;};",jsplot_cnt);
3060
          }
3061
      /* the canvasses range from 1000 ... 1008 */
3062
          if( reply_format == 0){reply_format = 29;}
3063
          reset();/* if command 'filled' / 'dashed' was given...reset all */
3064
          break;
3065
        case MULTILABEL:
3066
  /*
18556 bpr 3067
  @ multilabel button_label_1,button_label_2,...,button_label_8,'stop drawing text'
3068
  @ use before command <a href='#multidraw'>multidraw</a>
3069
  @ 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'...)
3070
  @ 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>
3071
  @ 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``
3072
  @ wims will not check the amount or validity of your input
3073
  @ always use the same sequence as is used for ''multidraw``
3074
  @ if you don't want the controls, and want to write your own interface, set <code>multilabel NOCONTROLS</code>
18552 bpr 3075
  */
3076
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3077
          temp = get_string(infile,1);
3078
          if( strcasestr(temp,"NOCONTROLS") ){
3079
            int_data[MAX_MULTI_PRIMITIVES+1] = 1; /*int_data[25] = 1 --> 'no_controls = 1' in canvasmacro.c */
3080
            fprintf(js_include_file,"var multilabel = null;");
3081
          }
3082
          else {
3083
            int_data[MAX_MULTI_PRIMITIVES+1] = 0; /* so DO use control buttons etc */
3084
            temp = str_replace(temp,",","\",\"");
3085
            fprintf(js_include_file,"var multilabel = [\"%s\"];",temp);
3086
          }
3087
          break;
3088
        case MULTILINEWIDTH:
3089
  /*
18556 bpr 3090
  @ multilinewidth linewidth_1,linewidth_2,...,linewidth_8
3091
  @ use before command <a href='#multidraw'>multidraw</a>
3092
  @ if not set all line widths will be set by a previous command ''linewidth int``
3093
  @ 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>
3094
  @ wims will <b>not</b> check if the number of 0 or 1's matches the amount of draw primitives...
3095
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3096
  */
3097
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3098
          temp = get_string(infile,1);
3099
          temp = str_replace(temp,",","\",\"");
3100
          fprintf(js_include_file,"var multilinewidth = [\"%s\"];",temp);
3101
          break;
3102
        case MULTIFILL:
3103
  /*
18556 bpr 3104
  @ multifill 0,0,1,0,1,0,0
3105
  @ 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...)
3106
  @ 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
3107
  @ use before command <a href='#multidraw'>multidraw</a>
3108
  @ 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>
3109
  @ only suitable for draw_primitives like ''circle | circles``, ''triangle | triangles``, ''rect | rects``, ''poly[3-9] | polys[3-9]`` and ''polygon``
3110
  @ wims will <b>not</b> check if the number of 0 or 1's matches the amount of draw primitives...
3111
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3112
  */
3113
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3114
          i=0;
3115
          while( ! done ){     /* get next item until EOL*/
3116
            if(i > MAX_MULTI_PRIMITIVES){canvas_error("too many multidraw primitives...read the documentation...");}
3117
            int_data[i] = (int)(get_real(infile,1)); /* 0,1,2,3,4,5 */
3118
            if(int_data[i] < 0 || int_data[i] > 5 ){canvas_error("the only possible multifill arguments are: 0,1,2,3,4,5 ");}
3119
            if(int_data[i] > 1 ){use_filled = 2;js_function[DRAW_FILL_PATTERN] = 1;}/* switch to trigger pattern filling */
3120
            i++;
3121
          }
3122
          fprintf(js_include_file,"var multifill = %s ;",data2js_array(int_data,i-1));
3123
          break;
3124
        case MULTIFILLCOLORS:
3125
  /*
18556 bpr 3126
  @ multifillcolors color_name_1,color_name_2,...,color_name_8
3127
  @ use before command <a href='#multidraw'>multidraw</a>
3128
  @ if not set all fillcolors (for circle | triangle | poly[3-9] | closedpoly ) will be ''stroke_color``, ''fill_opacity``
3129
  @ 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 3130
  @ wims will <b>not</b> check if the number of colors matches the amount of draw primitives...
18556 bpr 3131
  @ always use the same sequence as is used for ''multidraw``
18627 bpr 3132
  @ 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 3133
  */
3134
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3135
          fprintf(js_include_file,"var multifillcolors = [");
3136
          while( ! done ){
3137
            temp = get_color(infile,1);
3138
            fprintf(js_include_file,"\"%s\",",temp);
3139
          }
3140
          fprintf(js_include_file,"\"0,0,0\"];");/* add black to avoid trouble with dangling comma... */
3141
          break;
3142
        case MULTIFILLOPACITY:
3143
  /*
18556 bpr 3144
  @ multifillopacity fill_opacity_1,fill_opacity_2,...,fill_opacity_8
3145
  @ float values 0 - 1 or integer values 0 - 255
3146
  @ use before command <a href='#multidraw'>multidraw</a>
3147
  @ if not set all fill opacity_ will be set by previous command <code>opacity int,int</code> and keyword ''filled``
3148
  @ 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>
3149
  @ wims will not check the amount or validity of your input
3150
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3151
  */
3152
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3153
          temp = get_string(infile,1);
3154
          temp = str_replace(temp,",","\",\"");
3155
          fprintf(js_include_file,"var multifillopacity = [\"%s\"];",temp);
3156
          break;
3157
        case MULTISNAPTOGRID:
3158
  /*
18556 bpr 3159
  @ multisnaptogrid 0,1,1
3160
  @ alternative: multisnap
3161
  @ 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>)
3162
  @ freehand drawing...specify precision for reply: all objects snap to grid <code>multisnaptogrid 1,1,1,...</code>
3163
  @ only the xy-values snap_to_grid: all objects snap to grid <code>multisnaptogrid 1,1,1,...</code>
3164
  @ only the x-values snap_to_grid: all objects snap to x-grid <code>multisnaptogrid 2,2,2,...</code>
3165
  @ only the y-values snap_to_grid: all objects snap to y-grid <code>multisnaptogrid 3,3,3,...</code>
3166
  @ 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>
3167
  @ <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>
3168
  @ use before command <a href='#multidraw'>multidraw</a>
3169
  @ attention: if not set all objects will be set ''no snap``... unless a generic command ''snaptogrid`` was given before command ''multidraw``
3170
  @ 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>
3171
  @ always use the same sequence as is used for ''multidraw``
3172
  @ wims will <b>not</b> check if the number of 0 or 1's matches the amount of draw primitives...
18552 bpr 3173
  */
3174
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3175
          temp = get_string(infile,1);
3176
          fprintf(js_include_file,"var multisnaptogrid = [%s];",temp);
3177
          reset();/* if command 'dashed' was given...reset to not-dashed */
3178
          break;
3179
        case MULTISTROKECOLORS:
3180
  /*
18556 bpr 3181
  @ multistrokecolors color_name_1,color_name_2,...,color_name_8
3182
  @ use before command <a href='#multidraw'>multidraw</a>
3183
  @ if not set all colors will be ''stroke_color``, ''stroke_opacity``
3184
  @ 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 3185
  @ wims will <b>not</b> check if the number of colors matches the amount of draw primitives...
18556 bpr 3186
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3187
  */
3188
          if( use_tooltip == 1 ){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3189
          fprintf(js_include_file,"var multistrokecolors = [");
3190
          while( ! done ){
3191
            temp = get_color(infile,1);
3192
            fprintf(js_include_file,"\"%s\",",temp);
3193
          }
3194
          fprintf(js_include_file,"\"0,0,0\"];");/* add black to avoid trouble with dangling comma... */
3195
          break;
3196
        case MULTISTROKEOPACITY:
3197
  /*
18556 bpr 3198
  @ multistrokeopacity stroke_opacity_1,stroke_opacity_2,...,stroke_opacity_7
3199
  @ float values 0 - 1 or integer values 0 - 255
3200
  @ use before command <a href='#multidraw'>multidraw</a>
3201
  @ if not set all stroke opacity_ will be set by previous command <code>opacity int,int</code>
3202
  @ 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>
3203
  @ wims will not check the amount or validity of your input
3204
  @ always use the same sequence as is used for ''multidraw``
18552 bpr 3205
  */
3206
          if( use_tooltip == 1){canvas_error("command 'multidraw' is incompatible with command 'intooltip tip_text'");}
3207
          temp = get_string(infile,1);
3208
          temp = str_replace(temp,",","\",\"");
3209
          fprintf(js_include_file,"var multistrokeopacity = [\"%s\"];",temp);
3210
          break;
3211
        case MULTIUSERINPUT:
3212
  /*
3213
  @ multiuserinput 0,1,1,0
3214
  @ alternative: multiinput
18572 bpr 3215
  @ 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 3216
  @ 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
3217
  @ 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...
3218
  @ in case of a triangle | poly3, three inputfields are provided.
3219
  @ in case of ''text`` and ''multiuserinput=1, 3`` inputfields will be shown: ''x,y,text``
3220
  @ in case of ''text`` and ''multiuserinput=0, 1`` inputfield will be shown: text ... a mouse click will place the text on the canvas.
3221
  @ may be styled using command <a href="#css">css</a>
3222
  @ an additional button ''stop drawing`` may be used to combine userbased drawings with ''drag&and;drop`` or ''onclick`` elements
3223
  @ when exercise if finished (status=done) the buttons will not be shown.<br>To override this default behaviour use command / keyword ''status``
3224
  @ use before command <a href='#multidraw'>multidraw</a>
3225
  @ always use the same sequence as is used for ''multidraw``
3226
  */
3227
      /* simple rawmath and input check */
3228
          js_function[JS_SAFE_EVAL] = 1;
3229
          temp = get_string(infile,1);
3230
          temp = str_replace(temp,",","\",\"");
3231
          fprintf(js_include_file,"var multiuserinput = [\"%s\"];",temp);
3232
          break;
3233
        case NORESET:
3234
  /*
3235
  @ noreset
3236
  @ alternative: killreset
3237
  @ keyword
3238
  @ may come in handy if canvas script code is generated using loops
3239
  @ 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>
3240
  @ 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)
3241
  @ etc etc
3242
  @ 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>
3243
  @ commands like 'opacity', 'linewidth', 'fontsize', 'fontfamily' are only changed when redefined again
3244
  @%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
3245
  @%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
3246
  */
3247
          if(no_reset == FALSE){no_reset = TRUE;}else{no_reset = FALSE;reset();}
3248
          break;
3249
        case NOXAXIS:
3250
  /*
3251
  @ noxaxis
3252
  @ keyword
3253
  @ if set, the automatic x-axis numbering will be ignored
3254
  @ use command <a href="#axis">axis</a> to have a visual x/y-axis lines (see command <a href="#grid">grid</a>)
3255
  @ to be used before command grid (see <a href="#grid">command grid</a>)
3256
  */
3257
          fprintf(js_include_file,"x_strings = {};x_strings_up = [];\n");
3258
          use_axis_numbering = -1;
3259
          break;
3260
        case NOYAXIS:
3261
  /*
3262
  @ noyaxis
3263
  @ keyword
3264
  @ if set, the automatic y-axis numbering will be ignored
3265
  @ use command <a href="#axis">axis</a> to have a visual x/y-axis lines (see command <a href="#grid">grid</a>)
3266
  @ to be used before command grid (see <a href="#grid">command grid</a>)
3267
  */
3268
          fprintf(js_include_file,"y_strings = {};\n");
3269
          break;
3270
        case NUMBERLINE:
3271
  /*
3272
  @ numberline x0,x1,xmajor,xminor,y0,y1
3273
  @ numberline is using xrange/yrange system for all dimensions
3274
  @ multiple numberlines are allowed ; combinations with command <a href='#grid'>grid</a> is allowed; multiple commands <a href='#xaxis'>xaxis numbering</a> are allowed
3275
  @ x0 is start x-value in xrange
3276
  @ x1 is end x-value in xrange
3277
  @ xmajor is step for major division
3278
  @ xminor is divisor of xmajor; using small (30% of major tick) tick marks: this behaviour is ''hardcoded``
3279
  @ is xminor is an even divisor, an extra tickmark (60% of major tick) is added to the numberline: this behaviour is ''hardcoded``
3280
  @ y0 is bottom of numberline; y1 endpoint of major tics
3281
  @ use command <a href="#linewidth">linewidth</a> to control appearance
3282
  @ use <a href="#strokecolor">strokecolor</a> and <a href="#opacity">opacity</a> to controle measure line
3283
  @ for all ticks linewidth and color / opacity are identical.
3284
  @ 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
3285
  @ use <a href="#fontfamily">fontfamily</a> and <a href="#fontcolor">fontcolor</a> to control fonts settings
3286
  @ 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
3287
  @ <a href="#snaptogrid">snaptogrid, snaptopoints etc</a> and <a href="#zoom">zooming and panning</a> is supported
3288
  @ onclick and dragging of the numberline are not -yet- supported
3289
  @ note: in case of multiple numberlines, make sure the numberline without special x-axis numbering (e.g. ranging from xmin to xmax) comes first !
3290
  @%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
3291
  */
3292
          js_function[DRAW_NUMBERLINE] = 1;
3293
          for(i=0;i<6;i++){
3294
            switch(i){
3295
              case 0: double_data[0] = get_real(infile,0);break;/* xmin */
3296
              case 1: double_data[1] = get_real(infile,0);break;/* xmax */
3297
              case 2: double_data[2] = get_real(infile,0);break;/* xmajor */
3298
              case 3: double_data[3] = get_real(infile,0);break;/* xminor */
3299
              case 4: double_data[4] = get_real(infile,0);break;/* ymin */
3300
              case 5: double_data[5] = get_real(infile,1);/* ymax */
3301
            /*
3302
            var draw_numberline%d = function(canvas_type,xmin,xmax,xmajor,xminor,ymin,ymax,linewidth,strokecolor,strokeopacity,fontfamily,fontcolor);
3303
            */
3304
                fprintf(js_include_file,"snap_x = %f;snap_y = %f;",double_data[2] / double_data[3],double_data[5] - double_data[4] );
18557 bpr 3305
                tmp_buffer=my_newmem(MAX_BUFFER);
3306
                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 3307
                add_to_buffer(tmp_buffer);
3308
                numberline_cnt++;
3309
                break;
3310
              default:break;
3311
            }
3312
          }
3313
          reset();
3314
          break;
3315
        case OBABEL:
3316
  /*
3317
  @ obabel x,y,type input,molecule smiles-code or file location, extra arguments,extra arguments,...
3318
  @ will call the ''obabel`` program, if installed.
3319
  @ output will be an svg file
3320
  @ see documentation of obabel for special keys
3321
  @ command <a href='#affine'>affine</a> will produce CSS3 matrix transformations
3322
  @ command <a href='#rotate'>rotate</a> will rotate the object
3323
  @ 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
3324
  @ 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...
3325
  @ 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
3326
  @ 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
3327
  @%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
3328
  */
3329
          js_function[DRAW_XML] = 1;
3330
          for(i=0;i<4;i++){
3331
            switch(i){
3332
              case 0: double_data[0]=get_real(infile,0);break; /* x in x/y-range coord system -> pixel width */
3333
              case 1: double_data[1]=get_real(infile,0);break; /* y in x/y-range coord system  -> pixel height */
3334
              case 2: URL = get_string_argument(infile,0);break;
3335
              case 3:
3336
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3337
                temp = getSVGMOL(URL,get_string(infile,1));
3338
                decimals = find_number_of_digits(precision);
3339
                if(use_affine == TRUE ){ transform(2,2);}
3340
                if( use_offset != 0 || drag_type != -1 ){int_data[2] = 1;}else{int_data[2] = 0;} /* only centered or not-centered */
3341
                int_data[0] = x2px(double_data[0]);
3342
                int_data[1] = y2px(double_data[1]);
3343
                if( use_slider != -1 && onclick == 0 ){ onclick = 3;}/* no drag&onclick but slideable */
3344
                if( use_slider != -1 && drag_type > 0 ){ onclick = 5;}/* slider+drag*/
3345
                if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\"","'"); }
18557 bpr 3346
                tmp_buffer=my_newmem(MAX_BUFFER);
3347
                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 3348
                add_to_buffer(tmp_buffer);
3349
                if(onclick != 0 ){object_cnt++;}
3350
                drawxml_cnt++;/* keeps track on imported img,div,p,span,mathml,svg */
3351
                break;
3352
              default:break;
3353
            }
3354
          }
3355
          reset();
3356
          break;
3357
        case OPACITY:
3358
  /*
3359
  @ opacity [0-255],[0-255]
3360
  @ opacity [0.0 - 1.0],[0.0 - 1.0]
3361
  @ alternative: transparent
3362
  @ first item is stroke opacity, second is fill opacity
3363
  @%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
3364
  */
3365
          for(i = 0 ; i<2;i++){
3366
            switch(i){
3367
              case 0: double_data[0]= get_real(infile,0);break;
3368
              case 1: double_data[1]= get_real(infile,1);break;
3369
              default: break;
3370
            }
3371
           }
3372
          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 3373
          if( double_data[0] > 1 ){ stroke_opacity = (double) (0.0039215*double_data[0]); }else{ stroke_opacity = double_data[0];} /* 0.0 - 1.0 */
3374
          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 3375
          break;
18608 bpr 3376
        case STROKEOPACITY:
3377
  /*
3378
  @ strokeopacity [0-255]
3379
  @ strokeopacity [0.0 - 1.0]
3380
  @%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
3381
  */
3382
          double_data[0]= get_real(infile,1);
3383
          if( double_data[0] > 255 || double_data[0] < 0 ){ canvas_error("opacity [0 - 255] ");}/* typo or non-RGB ? */
3384
          if( double_data[0] > 1 ){ stroke_opacity = (double) (0.0039215*double_data[0]); }else{ stroke_opacity = double_data[0];} /* 0.0 - 1.0 */
3385
          break;
3386
        case FILLOPACITY:
3387
  /*
3388
  @ fillopacity [0-255]
3389
  @ fillopacity [0.0 - 1.0]
3390
  @%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
3391
  */
3392
          double_data[0]= get_real(infile,1);
3393
          if( double_data[0] > 255 || double_data[0] < 0 ){ canvas_error("fillopacity [0 - 255] ");}/* typo or non-RGB ? */
3394
          if( double_data[0] > 1 ){ fill_opacity = (double) (0.0039215*double_data[0]); }else{ fill_opacity = double_data[0];} /* 0.0 - 1.0 */
3395
          break;
18552 bpr 3396
        case ONCLICK:
3397
  /*
18556 bpr 3398
  @ onclick
3399
  @ keyword (no arguments required)
3400
  @ if the next object is clicked, its ''object onclick_or_drag sequence number`` in fly script is returned by <code>javascript:read_canvas();</code>
3401
  @ 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``
3402
  @ line based objects will show an increase in line width<br>font based objects will show the text in ''bold`` when clicked.
3403
  @ the click zone (accuracy) is determined by 2&times; the line width of the object
3404
  @ 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...)
3405
  @ note: not all objects may be set onclick
3406
  @%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 3407
  */
3408
          fprintf(js_include_file,"use_dragdrop_reply = true;");
3409
          onclick = 1;
3410
          use_dragstuff=2;
3411
          js_function[INTERACTIVE] = 1;
3412
          break;
3413
        case PARALLEL:
3414
  /*
18556 bpr 3415
  @ parallel x1,y1,x2,y2,dx,dy,n,[colorname or #hexcolor]
3416
  @ affine transformations should be identical to flydraw
3417
  @ 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.
3418
  @ in case of <em>no rotation or transformations</em> the lines can not be set ''onclick`` or ''drag xy``.
3419
  @ 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...)
3420
  @%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
3421
  @%parallel%size 400,400%xrange -10,10%yrange -10,10%parallel -5,5,-4,-5,0.25,0,40,red
18552 bpr 3422
  */
3423
          decimals = find_number_of_digits(precision);
3424
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3425
          if( use_rotate == TRUE || use_affine == TRUE ){
3426
            for( i = 0;i < 8; i++ ){
3427
              switch(i){
3428
                case 0: double_data[0] = get_real(infile,0);break; /* x1-values */
3429
                case 1: double_data[1] = get_real(infile,0);break; /* y1-values */
3430
                case 2: double_data[2] = get_real(infile,0);break; /* x2-values */
3431
                case 3: double_data[3] = get_real(infile,0);break; /* y2-values */
3432
                case 4: double_data[4] = get_real(infile,0);break; /* xv  */
3433
                case 5: double_data[5] = get_real(infile,0);break; /* yv  */
3434
                case 6: int_data[0] = (int) (get_real(infile,0));break; /* n  */
3435
                case 7: stroke_color=get_color(infile,1);break;/* name or hex color */
3436
                default: break;
3437
              }
3438
            }
3439
            double_data[6] = double_data[0]; /* x1 */
3440
            double_data[7] = double_data[1]; /* y1 */
3441
            double_data[8] = double_data[2]; /* x2 */
3442
            double_data[9] = double_data[3]; /* y2 */
3443
            for(i = 0 ; i < int_data[0] ; i++){
3444
              double_data[0] = double_data[6] + i*double_data[4];
3445
              double_data[1] = double_data[7] + i*double_data[5];
3446
              double_data[2] = double_data[8] + i*double_data[4];
3447
              double_data[3] = double_data[9] + i*double_data[5];
3448
              if(use_rotate == TRUE ){ rotate(4,angle,rotationcenter,2);}
3449
              if(use_affine == TRUE ){ transform(4,2);}
18557 bpr 3450
              tmp_buffer=my_newmem(MAX_BUFFER);
3451
              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 3452
              add_to_buffer(tmp_buffer);
3453
              if(onclick != 0){object_cnt++;}
3454
            }
3455
            dragstuff[4] = 1;
3456
          }
3457
          else  /* use the old parallel version: calculations in javascript */
3458
          {
3459
            for( i = 0;i < 8; i++ ){
3460
              switch(i){
3461
                case 0: double_data[0] = get_real(infile,0);break; /* x1-values */
3462
                case 1: double_data[1] = get_real(infile,0);break; /* y1-values */
3463
                case 2: double_data[2] = get_real(infile,0);break; /* x2-values */
3464
                case 3: double_data[3] = get_real(infile,0);break; /* y2-values */
3465
                case 4: double_data[4] = xmin + get_real(infile,0);break; /* xv  */
3466
                case 5: double_data[5] = ymax + get_real(infile,0);break; /* yv  */
3467
                case 6: int_data[0] = (int) (get_real(infile,0));break; /* n  */
3468
                case 7: stroke_color=get_color(infile,1);/* name or hex color */
18557 bpr 3469
                  tmp_buffer=my_newmem(MAX_BUFFER);
3470
                  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 3471
                  add_to_buffer(tmp_buffer);
3472
                  if(onclick != 0){object_cnt++;}
3473
                  break;
3474
                default: break;
3475
              }
3476
              dragstuff[11] = 1;
3477
            }
3478
          }
3479
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3480
          reset();
3481
          break;
3482
        case PLOTSTEPS:
3483
      /*
18556 bpr 3484
  @ plotsteps a_number
3485
  @ default 150
3486
  @ only used for commands <a href="#curve">curve / plot</a> and <a href="#levelcurve">levelcurve</a>
3487
  @ use with care !
18552 bpr 3488
      */
3489
          plot_steps = (int) (get_real(infile,1));
3490
          break;
3491
        case POINT:
3492
  /*
3493
  @ point x,y,color
3494
  @ draw a single point at (x;y) in color 'color'
3495
  @ use command <code>linewidth int</code> to adjust size
3496
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
3497
  @ will not resize on zooming (command <code>circle x,y,r,color</code> will resize on zooming)
3498
  @ attention: in case of command <a href="#rotate">rotate angle</a> a point has rotation center (0:0) in x/y-range
3499
  @%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
3500
  */
3501
          for(i=0;i<3;i++){
3502
            switch(i){
3503
              case 0: double_data[0] = get_real(infile,0);break; /* x */
3504
              case 1: double_data[1] = get_real(infile,0);break; /* y */
3505
              case 2: stroke_color = get_color(infile,1);/* name or hex color */
3506
                if(use_rotate == TRUE ){rotate(2,angle,rotationcenter,2);}
3507
                if(use_affine == TRUE ){ transform(2,2);}
3508
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3509
                decimals = find_number_of_digits(precision);
18557 bpr 3510
                tmp_buffer=my_newmem(MAX_BUFFER);
3511
                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 3512
                add_to_buffer(tmp_buffer);
3513
                /* object_cnt++; */
3514
                if(onclick != 0){object_cnt++;}
3515
                break;
3516
              default: break;
3517
            }
3518
          }
3519
          dragstuff[2] = 1;
3520
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3521
          reset();
3522
          break;
3523
        case POINTS:
3524
  /*
3525
  @ points color,x1,y1,x2,y2,...,x_n,y_n
3526
  @ draw multiple points at given coordinates in color 'color'
3527
  @ use command <code>linewidth int</code> to adjust size
3528
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
3529
  @ attention: in case of command <a href="#rotate">rotate angle</a> the points have rotation center (0:0) in x/y-range
3530
  @%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
3531
  @%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
3532
  */
3533
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
3534
          fill_color = stroke_color;
3535
          i=0;
3536
          while( ! done ){     /* get next item until EOL*/
3537
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3538
            if(i%2 == 0 ){
3539
              double_data[i] = get_real(infile,0); /* x */
3540
            }
3541
            else {
3542
              double_data[i] = get_real(infile,1); /* y */
3543
            }
3544
            i++;
3545
          }
3546
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3547
          if(use_affine == TRUE ){ transform(i-1,2);}
3548
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3549
          decimals = find_number_of_digits(precision);
3550
          for(c = 0 ; c < i-1 ; c = c+2){
18557 bpr 3551
            tmp_buffer=my_newmem(MAX_BUFFER);
3552
            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 3553
            add_to_buffer(tmp_buffer);
3554
            /* object_cnt++; */
3555
            if(onclick != 0){object_cnt++;}
3556
          }
3557
          dragstuff[2] = 1;
3558
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3559
          reset();
3560
          break;
3561
        case POLY:
3562
  /*
3563
  @ poly color,x1,y1,x2,y2...x_n,y_n
3564
  @ polygon color,x1,y1,x2,y2...x_n,y_n
3565
  @ draw closed polygon
3566
  @ use command ''fpoly`` to fill it or use keyword <a href='#filled'>filled</a>
3567
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
3568
  @%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
3569
  @%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
3570
  */
3571
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
3572
          i=0;
3573
          c=0;
3574
          while( ! done ){     /* get next item until EOL*/
3575
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3576
            for( c = 0 ; c < 2; c++){
3577
              if(c == 0 ){
3578
                double_data[i] = get_real(infile,0);
3579
                i++;
3580
              }
3581
              else {
3582
                double_data[i] = get_real(infile,1);
3583
                i++;
3584
              }
3585
            }
3586
          }
3587
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3588
          if(use_affine == TRUE ){ transform(i-1,2);}
3589
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
8386 schaersvoo 3590
 
18552 bpr 3591
      /* draw path:  closed & optional filled */
3592
          decimals = find_number_of_digits(precision);
18557 bpr 3593
          tmp_buffer=my_newmem(MAX_BUFFER);
3594
          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 3595
          add_to_buffer(tmp_buffer);
3596
          if(onclick != 0){object_cnt++;}
3597
          reset();
3598
          dragstuff[5] = 1;
3599
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3600
          break;
3601
        case POLYLINE:
3602
  /*
3603
  @ polyline color,x1,y1,x2,y2...x_n,y_n
3604
  @ brokenline color,x1,y1,x2,y2...x_n,y_n
3605
  @ path color,x1,y1,x2,y2...x_n,y_n
3606
  @ 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>
3607
  @ 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
3608
  @ 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)
3609
  @ use command <a href='#segments'>segments</a> for a series of segments. These may be clicked/dragged individually
3610
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
3611
  @%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
3612
  @%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
3613
  */
11806 schaersvoo 3614
 
18552 bpr 3615
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
3616
          i=0;
3617
          c=0;
3618
          while( ! done ){     /* get next item until EOL*/
3619
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3620
            for( c = 0 ; c < 2; c++){
3621
              if(c == 0 ){
3622
                double_data[i] = get_real(infile,0);
3623
                i++;
3624
              }
3625
              else {
3626
                double_data[i] = get_real(infile,1);
3627
                i++;
3628
              }
3629
            }
3630
          }
11806 schaersvoo 3631
 
18552 bpr 3632
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3633
          if(use_affine == TRUE ){ transform(i-1,2);}
3634
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
11806 schaersvoo 3635
 
18552 bpr 3636
      /* draw path: not closed & not filled */
3637
          decimals = find_number_of_digits(precision);
18557 bpr 3638
          tmp_buffer=my_newmem(MAX_BUFFER);
3639
          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 3640
          add_to_buffer(tmp_buffer);
3641
          if(onclick != 0){object_cnt++;}
3642
          /* object_cnt++;*/
3643
          reset();
3644
          dragstuff[4] = 1;
3645
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3646
          break;
3647
        case POPUP:
3648
      /*
18556 bpr 3649
  @ popup
3650
  @ keyword (no arguments)
3651
  @ if fly-script starts with keyword ''popup``, the canvas image will be exclusively in a popup window (xsize px &times; ysize px)
3652
  @ 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``
3653
  @ the popup window will be embedded into the page as a normal image, when ''status=done``; override with keyword <a href="#status">nostatus</a>
3654
  @ 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>
3655
  @ 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
3656
  @%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 3657
      */
3658
          use_tooltip = 2;
3659
          break;
3660
        case PROTRACTOR:
3661
  /*
18556 bpr 3662
  @ protractor x,y,x_width,type,mode,use_a_scale
3663
  @ x,y are the initial location
3664
  @ x_width: give the width in x-coordinate system (e.g. not in pixels !)
3665
  @ type = 1: a triangle range 0 - 180<br>type = 2: a circle shape 0 - 360
3666
  @ 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
3667
  @ 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>
3668
  @ use_scale = 1: the protractor will have some scale values printed; use_scale=0 to disable
3669
  @ the rotating direction of the mouse around the protractor determines the clockwise/ counter clockwise rotation of the protractor...
3670
  @ commands ''stroke_color | fill_color | linewidth | opacity | font_family`` will determine the looks of the protractor.
3671
  @ default replyformat: reply[0] = x;reply[1] = y;reply[2] = angle_in_radians<br>use command ''precision`` to set the reply precision.
3672
  @ if combined with a ruler, use replyformat = 32
3673
  @ command <code>snap_to_grid</code> may be used to assist the pupil at placing the protractor
3674
  @ 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...
3675
  @ only one protractor allowed (for the time being)
3676
  @ 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...
3677
  @%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 3678
  */
3679
          for( i = 0;i < 6; i++ ){
3680
            switch(i){
3681
              case 0: double_data[0] = get_real(infile,0);break; /* x-center */
3682
              case 1: double_data[1] = get_real(infile,0);break; /* y-center */
3683
              case 2: double_data[2] = get_real(infile,0);break; /* x-width */
3684
              case 3: int_data[0] = (int)(get_real(infile,0));break; /* type: 1==triangle 2 == circle */
3685
              case 4: int_data[1] = (int)(get_real(infile,0));break; /* passive mode == 0; active mode == -1 */
3686
              case 5: int_data[2] = (int)(get_real(infile,1)); /* use scale */
3687
                decimals = find_number_of_digits(precision);
3688
                if( int_data[1] < 0 ){ js_function[JS_FIND_ANGLE] = 1;}
18557 bpr 3689
                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);
3690
                tmp_buffer=my_newmem(MAX_BUFFER);
3691
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, ";protractor%d(); ",canvas_root_id));
18552 bpr 3692
                add_to_buffer(tmp_buffer);
3693
                reply_precision = precision;
3694
        /* no reply from protractor if non-interactive */
3695
                if( reply_format == 0 && int_data[1] == -1 ){reply_format = 30;}
3696
                js_function[INTERACTIVE] = 1;
3697
                break;
3698
              default: break;
3699
            }
3700
          }
3701
          break;
3702
        case PIXELS:
3703
  /*
3704
  @ pixels color,x1,y1,x2,y2,x3,y3...
3705
  @ draw rectangular "points" with diameter 1 pixel
3706
  @ pixels can <b>not</b> be dragged or clicked
3707
  @ "pixelsize = 1" may be changed by command <code>pixelsize int</code>
3708
  @%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...
3709
  */
3710
          js_function[DRAW_PIXELS] = 1;
3711
          stroke_color=get_color(infile,0);
3712
          i=0;
3713
          c=0;
3714
          while( ! done ){     /* get next item until EOL*/
3715
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3716
            for( c = 0 ; c < 2; c++){
3717
              if(c == 0 ){
3718
                double_data[i] = get_real(infile,0);
3719
                i++;
3720
              }
3721
              else {
3722
                double_data[i] = get_real(infile,1);
3723
              }
3724
            }
3725
        }
3726
        if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3727
        if(use_affine == TRUE ){ transform(i-1,2);}
3728
        decimals = find_number_of_digits(precision);
3729
        /*  *double_xy2js_array(double xy[],int len,int decimals) */
18557 bpr 3730
        tmp_buffer=my_newmem(MAX_BUFFER);
3731
        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 3732
        add_to_buffer(tmp_buffer);
3733
        reset();
3734
        break;
3735
        case PIXELSIZE:
3736
  /*
3737
  @ pixelsize int
3738
  @ in case you want to deviate from default pixelsize = 1(...)
3739
  @ pixelsize 100 is of course a filled rectangle 100px &times; 100px
3740
  */
3741
          pixelsize = (int) get_real(infile,1);
3742
          break;
15111 schaersvoo 3743
 
18552 bpr 3744
        case PIECHART:
3745
  /*
3746
  @ piechart xc,yc,radius,'data+colorlist'
3747
  @ (xc: yc) center of circle diagram in xrange/yrange
3748
  @ radius in pixels
18627 bpr 3749
  @ 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 3750
  @ example data+colorlist: 32:red:65:green:23:black:43:orange:43:yellow:14:white
3751
  @ the number of colors must match the number of data.
3752
  @ 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 3753
  @ use command <a href='#opacity'>opacity</a> to adjust fill_opacity of colors
3754
  @ 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 3755
  @ 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.
3756
  @%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%
3757
  @%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
3758
  */
3759
          js_function[DRAW_PIECHART] = 1;
3760
          for(i=0;i<5;i++){
3761
            switch(i){
3762
              case 0: int_data[0] = x2px(get_real(infile,0)); break; /* x */
3763
              case 1: int_data[1] = y2px(get_real(infile,0)); break; /* y  */
3764
              case 2: int_data[2] = (int)(get_real(infile,1));break;/* radius*/
3765
              case 3: temp = get_string(infile,1);
3766
                if( strstr( temp, ":" ) != 0 ){ temp = str_replace(temp,":","\",\"");}
18557 bpr 3767
                tmp_buffer=my_newmem(MAX_BUFFER);
3768
                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 3769
                add_to_buffer(tmp_buffer);
3770
                break;
3771
              default:break;
3772
            }
3773
          }
3774
          reset();
3775
          break;
3776
        case RANGE:
3777
  /*
3778
  @ range xmin,xmax,ymin,ymax
3779
  @ if not given: 0,xsize,0,ysize (eg in pixels)
3780
  */
3781
          for(i = 0 ; i<4; i++){
3782
            switch(i){
3783
              case 0: xmin = get_real(infile,0);break;
3784
              case 1: xmax = get_real(infile,1);break;
3785
              case 2: ymin = get_real(infile,0);break;
3786
              case 3: ymax = get_real(infile,1);break;
3787
              default: break;
3788
            }
3789
          }
3790
          if(xmin >= xmax){canvas_error(" xrange is not OK: xmin &lt; xmax !");}
3791
          if(ymin >= ymax){canvas_error(" yrange is not OK: ymin &lt; ymax !");}
3792
          fprintf(js_include_file,"var xmin = %f;var xmax = %f;var ymin = %f;var ymax = %f;",xmin,xmax,ymin,ymax);
3793
          found_size_command = found_size_command+2;
3794
          break;
3795
        case RAYS:
3796
  /*
18556 bpr 3797
  @ rays color,xc,yc,x1,y1,x2,y2,x3,y3...x_n,y_n
3798
  @ draw rays in color 'color' and center (xc:yc)
3799
  @ may be set draggable or onclick (every individual ray)
3800
  @%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
3801
  @%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 3802
  */
3803
          stroke_color=get_color(infile,0);
3804
          fill_color = stroke_color;
3805
          double_data[0] = get_real(infile,0);/* xc */
3806
          double_data[1] = get_real(infile,0);/* yc */
3807
          i=2;
3808
          while( ! done ){     /* get next item until EOL*/
3809
            if(i > MAX_INT - 1){canvas_error("in command rays too many points / rays in argument: repeat command multiple times to fit");}
3810
            if(i%2 == 0 ){
3811
              double_data[i] = get_real(infile,0); /* x */
3812
            }
3813
            else {
3814
              double_data[i] = get_real(infile,1); /* y */
3815
            }
3816
            fprintf(js_include_file,"/* double_data[%d] = %f */\n",i,double_data[i]);
3817
            i++;
3818
          }
3819
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3820
          if(use_affine == TRUE ){ transform(i-1,2);}
3821
          if( i%2 != 0 ){canvas_error("in command rays: unpaired x or y value");}
3822
          decimals = find_number_of_digits(precision);
3823
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3824
          for(c=2; c<i;c = c+2){
18557 bpr 3825
            tmp_buffer=my_newmem(MAX_BUFFER);
3826
            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 3827
            add_to_buffer(tmp_buffer);
3828
    /* object_cnt++; */
3829
            if(onclick != 0){object_cnt++;}
3830
          }
3831
          reset();
3832
          dragstuff[4] = 1;
3833
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3834
          break;
3835
        case RECT:
3836
  /*
3837
  @ rect x1,y1,x2,y2,color
3838
  @ use command <code>frect x1,y1,x2,y2,color</code> for a filled rectangle
3839
  @ use command/keyword <a href='#filled'>filled</a> before command <code>rect x1,y1,x2,y2,color</code>
3840
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
18572 bpr 3841
  @ 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 3842
  @%rect%size 400,400%xrange -10,10%yrange -10,10%rect 0,0,4,-4,green%rect 0,5,4,1,red
3843
  */
3844
          for(i=0;i<5;i++){
3845
            switch(i){
3846
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
3847
              case 1:double_data[1] = get_real(infile,0);break; /* y-values */
3848
              case 2:double_data[4] = get_real(infile,0);break; /* x-values */
3849
              case 3:double_data[5] = get_real(infile,0);break; /* y-values */
3850
              case 4:stroke_color = get_color(infile,1);/* name or hex color */
3851
                decimals = find_number_of_digits(precision);
3852
                double_data[2] = double_data[4];
3853
                double_data[3] = double_data[1];
3854
                double_data[6] = double_data[0];
3855
                double_data[7] = double_data[5];
3856
          /* using closed PATH (type=5) instead of ctx.rect (type=1)!!!
3857
              0,1   2,3
3858
          6,7      4,5
3859
          x = [0,2,4,6]
3860
          y = [1,3,5,7]
3861
          */
18623 bpr 3862
                if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 3863
                if(use_rotate == TRUE ){rotate(8,angle,rotationcenter,2);}
3864
                if(use_affine == TRUE ){ transform(8,2);}
3865
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 3866
                tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 3867
                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 3868
                add_to_buffer(tmp_buffer);
3869
                if(onclick != 0){object_cnt++;}
18555 bpr 3870
                /* object_cnt++; */
18552 bpr 3871
                reset();
3872
                break;
3873
              }
3874
            }
3875
          dragstuff[5] = 1;
3876
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3877
          break;
3878
        case RECTS:
3879
  /*
3880
  @ rects color,x1,y1,x2,y2,.....
3881
  @ use command <code>frect color,x1,y1,x2,y2,.....</code> for a filled rectangle
3882
  @ use command/keyword <a href='#filled'>filled</a> before command <code>rects color,x1,y1,x2,y2,....</code>
18623 bpr 3883
  @ use command <code>fillcolor color</code> before ''frects`` to set the fill color.
18552 bpr 3884
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
3885
  @%rects%size 400,400%xrange -10,10%yrange -10,10%rects red,0,0,4,-4,0,5,4,1
3886
  */
3887
      /* using closed PATH (type=5) in stead of ctx.rect (type=1)!!!
3888
      0,1   2,3 .....8,9  10,11.....
3889
  6,7      4,5 .....14,15  12,13.....
3890
  x = [0,2,4,6,8,10,12,14...]
3891
  y = [1,3,5,7,9,11,13,15...]
3892
      */
3893
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
18623 bpr 3894
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 3895
          i=0;
3896
          while( ! done ){     /* get next item until EOL*/
3897
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3898
            if(i%2 == 0 ){
3899
              double_data[i] = get_real(infile,0); /* x */
3900
            }
3901
            else {
3902
              double_data[i] = get_real(infile,1); /* y */
3903
            }
3904
            i++;
3905
          }
3906
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3907
          if(use_affine == TRUE ){ transform(i-1,2);}
3908
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
11806 schaersvoo 3909
 
18552 bpr 3910
          decimals = find_number_of_digits(precision);
3911
          for(c = 0 ; c < i-1 ; c = c+4){
18557 bpr 3912
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 3913
            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 3914
            add_to_buffer(tmp_buffer);
3915
            if(onclick != 0){object_cnt++;}
3916
    /* object_cnt++; */
3917
          }
3918
          dragstuff[5] = 1;
3919
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3920
          if(use_rotate == TRUE ){
3921
            rotate(i-1,angle,rotationcenter,2);
3922
          }
3923
          reset();
3924
          break;
3925
        case REPLYFORMAT:
3926
  /*
3927
  @ replyformat number
3928
  @ use number=-1 to deactivate the js-functions read_canvas() and read_dragdrop()
3929
  @ default values should be fine !
3930
  @ 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
3931
  @ the last value for ''precision int`` will be used to calculate the reply coordinates, if needed (read_canvas();)
3932
  @ 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>
3933
  @ 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'
3934
  */
3935
          reply_format = (int) get_real(infile,1);
3936
          reply_precision = precision;
3937
          break;
3938
        case ROUNDRECT:
3939
  /*
3940
  @ roundrect x1,y1,x2,y2,radius in px,color
3941
  @ use command <code>froundrect x1,y1,x2,y2,radius,color</code> for a filled rectangle
3942
  @ use command/keyword <a href='#filled'>filled</a> before command <code>roundrect x1,y1,x2,y2,radius,color</code>
3943
  @ fillcolor will be identical to ''color``
3944
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
3945
  @%roundrect%size 400,400%xrange -10,10%yrange -10,10%roundrect 0,0,4,-4,20,green%roundrect 0,5,4,1,10,red
3946
  */
3947
          for(i=0;i<6;i++){
3948
            switch(i){
3949
              case 0:double_data[0] = get_real(infile,0);break; /* x-values */
3950
              case 1:double_data[1] = get_real(infile,0);break; /* y-values */
3951
              case 2:double_data[2] = get_real(infile,0);break; /* x-values */
3952
              case 3:double_data[3] = get_real(infile,0);break; /* y-values */
3953
              case 4:int_data[0] = (int) (get_real(infile,0));break; /* radius value in pixels */
3954
              case 5:stroke_color = get_color(infile,1);/* name or hex color */
3955
                if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
3956
                if(use_affine == TRUE ){ transform(2,4);}
3957
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3958
      /* ensure no inverted roundrect is produced... */
3959
                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];}
3960
                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];}
3961
                decimals = find_number_of_digits(precision);
18557 bpr 3962
                tmp_buffer=my_newmem(MAX_BUFFER);
3963
                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 3964
                add_to_buffer(tmp_buffer);
3965
                if(onclick != 0){object_cnt++;}
3966
      /* object_cnt++;*/
3967
                reset();
3968
                break;
3969
            }
3970
          }
3971
          dragstuff[6] = 1;
3972
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
3973
          break;
3974
        case ROUNDRECTS:
3975
  /*
3976
  @ roundrects color,radius in px,x1,y1,x2,y2,x3,y3,x4,y4,....
3977
  @ for filled roundrects use command/keyword <a href='#filled'>filled</a> before command
3978
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
3979
  @%roundrects%size 400,400%xrange -10,10%yrange -10,10%roundrects blue,5,0,0,4,-4,5,4,1,2
3980
  */
11806 schaersvoo 3981
 
18552 bpr 3982
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
3983
          int_data[0] = (int) (get_real(infile,0)); /* radius value in pixels */
18623 bpr 3984
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 3985
          i=0;
3986
          while( ! done ){     /* get next item until EOL*/
3987
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
3988
            if(i%2 == 0 ){
3989
              double_data[i] = get_real(infile,0); /* x */
3990
            }
3991
            else {
3992
              double_data[i] = get_real(infile,1); /* y */
3993
            }
3994
            i++;
3995
          }
3996
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
3997
          if(use_affine == TRUE ){ transform(i-1,2);}
3998
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
3999
          decimals = find_number_of_digits(precision);
4000
          for(c = 0 ; c < i-1 ; c = c+4){
4001
    /* ensure no inverted roundrect is produced... */
4002
            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];}
4003
            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 4004
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 4005
            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 4006
            add_to_buffer(tmp_buffer);
4007
            if(onclick != 0){object_cnt++;}
4008
    /* object_cnt++; */
4009
          }
4010
          dragstuff[6] = 1;
4011
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4012
          reset();
4013
          break;
4014
        case RULER:
4015
  /*
4016
  @ ruler x,y,x-width,y-height,mode
4017
  @ x,y are the initial location
4018
  @ x-width, y-height are the ruler dimensions width &amp; height in xy-coordinate system
4019
  @ 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
4020
  @ 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
4021
  @ if combined with a protractor, use replyformat = 32
4022
  @ only one ruler allowed (for the time being)
4023
  @ 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...
4024
  @ 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...
4025
  @%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
4026
  @%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
4027
  @%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
4028
  */
4029
          for( i = 0;i < 5; i++ ){
4030
            switch(i){
4031
              case 0: double_data[0] = get_real(infile,0);break; /* x-center */
4032
              case 1: double_data[1] = get_real(infile,0);break; /* y-center */
4033
              case 2: double_data[2] = get_real(infile,0);break; /* x-width */
4034
              case 3: double_data[3] = get_real(infile,0);break; /* y-width */
4035
              case 4: int_data[0] = (int)(get_real(infile,1)); /* passive mode */
4036
                decimals = find_number_of_digits(precision);
4037
                if( int_data[0] < 0 ){
4038
                  js_function[JS_FIND_ANGLE] = 1;
4039
                }
18557 bpr 4040
                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);
4041
                tmp_buffer=my_newmem(MAX_BUFFER);
4042
                check_string_length(snprintf(tmp_buffer,MAX_BUFFER, ";ruler%d(); ",canvas_root_id));
18552 bpr 4043
                add_to_buffer(tmp_buffer);
4044
                reply_precision = precision;
4045
                /* no reply from ruler if non-interactive */
4046
                if( reply_format == 0 && int_data[0] == -1 ){reply_format = 31;}
4047
                break;
4048
              default: break;
4049
            }
4050
          }
4051
          break;
4052
        case RESET:
4053
  /*
4054
  @ reset
4055
  @ keyword
4056
  @ disables the effects of the <a href="noreset">noreset</a> command
4057
  @ so the next objects will not be <a href="#filled">filled</a> and <a href="#dashed">dashed</a>
4058
  */
4059
          no_reset = FALSE; reset();
4060
          break;
4061
        case RESETOFFSET:
4062
  /*
18556 bpr 4063
  @ resetoffset
4064
  @ keyword ; use to restore text placement on the canvas to the real (x;y) coordinates of the left bottom corner of the text
4065
  @ 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 4066
  */
4067
          use_offset = 0;
4068
          break;
4069
        case ROTATE:
4070
  /*
18556 bpr 4071
  @ rotate rotation_angle
4072
  @ angle in degrees
4073
  @ (only) the next object will be rotated is given angle
4074
  @ positive values rotate counter clockwise
4075
  @ 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)
4076
  @ 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>
4077
  @ 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
4078
  @%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 4079
  */
4080
          use_rotate = TRUE;
4081
          angle = -1*(get_real(infile,1));/* -1: to be compatible with Flydraw... */
4082
          break;
4083
        case ROTATION_CENTER:
4084
  /*
4085
  @ rotationcenter x_center,y_center
4086
  @ define an rotation center in your x/y-coordinate system
4087
  @ wims will not check the validity of your input; use javascript console to debug any erors
4088
  @ if not defined a rotation will be around the first point of an object
4089
  @ to be used before command <a href="#rotate">rotate</a>
18572 bpr 4090
  @ 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 4091
  @ all other commands will use this rotation center, unless a <a href="#killrotation">killrotation</a> is given
4092
  @%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
4093
  @%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
4094
  */
4095
          for( i = 0;i < 2; i++ ){
4096
            switch(i){
4097
              case 0: rotationcenter[0] = get_real(infile,0);break; /* x-center */
4098
              case 1: rotationcenter[1] = get_real(infile,1);break; /* y-center */
4099
            }
4100
            string_length = 1 + snprintf(NULL,0,"[%f,%f ]",rotationcenter[0],rotationcenter[1]);
18557 bpr 4101
 
18552 bpr 4102
            rotation_center = my_newmem(string_length);
4103
            snprintf(rotation_center,string_length,"[%f,%f]",rotationcenter[0],rotationcenter[1]);
4104
          }
4105
          break;
4106
        case SIZE:
4107
      /*
18556 bpr 4108
  @ size width,height
4109
  @ set canvas size in pixels
4110
  @ mandatory first command (can only be preceded by keyword <a href="#popup">popup</a>)
4111
  @ 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 4112
      */
4113
          found_size_command = 1;
4114
          /* using fabs: however "xsize == int": so "xsize = abs( (int) get_real(infile,0))" would be the idea... */
4115
          xsize = (int)(fabs(round(get_real(infile,0)))); /* just to be sure that sizes > 0 */
4116
          ysize = (int)(fabs(round(get_real(infile,1))));
4117
          /* sometimes we want xrange / yrange to be in pixels...without telling x/y-range */
4118
          xmin = 0;xmax = xsize;
4119
          ymin = 0;ymax = ysize;
11806 schaersvoo 4120
 
4121
/*
4122
 The sequence in which stuff is finally printed is important !!
4123
*/
18552 bpr 4124
          fprintf(stdout,"\n\
4125
          <script>\n\
4126
          /*<![CDATA[*/\n\
4127
          if( typeof(wims_status) === 'undefined' ){ var wims_status = \"$status\";};\
4128
          if( typeof(use_dragdrop_reply) === 'undefined' ){ var use_dragdrop_reply = false;};\
4129
          if( typeof(canvas_scripts) === 'undefined' ){ var canvas_scripts = new Array();};\
4130
          canvas_scripts.push(\"%d\");\n/*]]>*/\n</script>\n\
4131
          ",canvas_root_id);
11806 schaersvoo 4132
 
18552 bpr 4133
          /* style=\"display:block;position:relative;margin-left:auto;margin-right:auto;margin-bottom:4px;\" */
4134
          if( use_tooltip != 2){
4135
            fprintf(stdout,"<!-- canvasdraw div -->\n\
4136
            <div tabindex=\"0\" id=\"canvas_div%d\" style=\"max-width:%dpx;width:%dpx;height:%dpx\" class=\"canvas_wrapper\" oncontextmenu=\"return false;\">\
4137
             <canvas class=\"canvas_placeholder\" width=\"%d\" height=\"%d\"></canvas>\
4138
            </div>\n\
4139
            <!-- tooltip and input placeholder -->\n\
4140
            <div id=\"tooltip_placeholder_div%d\" style=\"text-align:center\">\
4141
             <span id=\"tooltip_placeholder%d\" class=\"tooltip_placeholder\"></span></div>\
4142
            <!-- include actual object code via include file -->\n\
4143
            <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);
4144
          } else {
11806 schaersvoo 4145
/*
14066 bpr 4146
set canvas_div invisible and do not include placeholder in main html page:
15111 schaersvoo 4147
the js-include will also be in a popup window...to be shown when wims &#36;status = done
11806 schaersvoo 4148
*/
18552 bpr 4149
            fprintf(stdout,"<!-- canvasdraw div invisible -->\n\
4150
            <div tabindex=\"0\" id=\"canvas_div%d\" class=\"canvas_wrapper\" style=\"display:none;max-width:%dpx;width:%dpx;height:%dpx;\">\
4151
             <canvas class=\"canvas_placeholder\" width=\"%d\" height=\"%d\"></canvas>\
4152
            </div>\n\
4153
            <div id=\"tooltip_placeholder_div%d\" style=\"display:none;position:relative;margin-left:auto;margin-right:auto;margin-bottom:4px;\">\
4154
             <span id=\"tooltip_placeholder%d\" class=\"tooltip_placeholder\"></span></div>\
4155
            <!-- include actual object code via include file -->\n\
4156
            <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);
4157
          }
11806 schaersvoo 4158
 
14071 bpr 4159
/* these must be global...it is all really very poor javascript:( */
15734 schaersvoo 4160
fprintf(js_include_file,"\n/* begin generated javascript include for canvasdraw version %s */\n\
11806 schaersvoo 4161
\"use strict\";\n\
15111 schaersvoo 4162
/* these variables and functions must be global */\
11806 schaersvoo 4163
var read_dragdrop%d;\
14038 schaersvoo 4164
var read_canvas_images;\
11806 schaersvoo 4165
var read_canvas%d;\
4166
var set_clock;\
4167
var clear_draw_area%d;\
4168
var update_draw_area%d;\
14038 schaersvoo 4169
var place_image_on_canvas;\
11806 schaersvoo 4170
var draw_boxplot;\
4171
var redraw_all%d;\
15111 schaersvoo 4172
var userdraw_primitive;\
4173
var wims_canvas_function%d = function(){\n/* common used stuff */\
4174
var userdraw_x = [];var userdraw_y = [];var userdraw_radius = [];\
11806 schaersvoo 4175
var xsize = %d;\
4176
var ysize = %d;\
4177
var precision = 100;\
4178
var canvas_div = document.getElementById(\"canvas_div%d\");\
4179
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;};\
4180
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 4181
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 4182
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);};};\
4183
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 4184
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 4185
function scale_x_radius(rx){return rx*xsize/(xmax - xmin);};\
4186
function scale_y_radius(ry){return ry*ysize/(ymax - ymin);};\
4187
function distance(x1,y1,x2,y2){return Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );};\
4188
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) ));};\
4189
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 4190
var snap_x = 1;var snap_y = 1;\
11806 schaersvoo 4191
function snap_to_x(x){return x2px(snap_x*(Math.round((px2x(x))/snap_x)));};\
11890 schaersvoo 4192
function snap_to_y(y){return y2px(snap_y*(Math.round((px2y(y))/snap_y)));};\
15111 schaersvoo 4193
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 4194
var xlogbase = 10;\
4195
var ylogbase = 10;\
4196
var use_xlogscale = 0;\
4197
var use_ylogscale = 0;\
11891 schaersvoo 4198
var x_strings = {};var x_strings_up = [];\
11806 schaersvoo 4199
var y_strings = null;\
4200
var use_jsmath = 0;\
4201
var xstart = 0;\
4202
var ystart = 0;\
4203
var unit_x=\" \";\
4204
var unit_y=\" \";\
15111 schaersvoo 4205
var dragdrop_reply = [];\
15734 schaersvoo 4206
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 4207
/* var xstart,ystart are normally 0 : in case of sgraph they have the 'jump' in the graph */
18552 bpr 4208
          break;
4209
        case SEGMENT:
4210
  /*
4211
  @ segment x1,y1,x2,y2,color
4212
  @ alternative: seg
4213
  @ draw a line segment between points (x1:y1)--(x2:y2) in color ''color``
4214
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
4215
  @%segment_onclick%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%segment 1,1,-9,3,green
4216
  @%segment_drag_y%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%drag y%segment 1,1,-9,3,green
4217
  */
4218
          for(i=0;i<5;i++) {
4219
            switch(i){
4220
              case 0: double_data[0]= get_real(infile,0);break; /* x1-values */
4221
              case 1: double_data[1]= get_real(infile,0);break; /* y1-values */
4222
              case 2: double_data[2]= get_real(infile,0);break; /* x2-values */
4223
              case 3: double_data[3]= get_real(infile,0);break; /* y2-values */
4224
              case 4: stroke_color=get_color(infile,1);/* name or hex color */
4225
                if(use_rotate == TRUE ){rotate(4,angle,rotationcenter,2);}
4226
                if(use_affine == TRUE ){ transform(4,2);}
4227
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
4228
                decimals = find_number_of_digits(precision);
18557 bpr 4229
                tmp_buffer=my_newmem(MAX_BUFFER);
4230
                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 4231
                add_to_buffer(tmp_buffer);
4232
                if(onclick != 0){object_cnt++;}
4233
                /* object_cnt++; */
4234
                reset();
4235
                break;
4236
              default: break;
4237
            }
4238
          }
4239
          dragstuff[4] = 1;
4240
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4241
          break;
4242
        case SEGMENTS:
4243
  /*
4244
  @ segments color,x1,y1,x2,y2,...,x_n,y_n
4245
  @ alternative: segs
4246
  @ draw multiple segments between points (x1:y1)--(x2:y2).....and... (x_n-1:y_n-1)--(x_n:y_n) in color ''color``
4247
  @ use command ''linewidth int`` to adjust size
4248
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
4249
  @%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
4250
  @%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
4251
  */
4252
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
4253
          fill_color = stroke_color;
4254
          i=0;
4255
          while( ! done ){     /* get next item until EOL*/
4256
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
4257
            if(i%2 == 0 ){
4258
              double_data[i] = get_real(infile,0); /* x */
4259
            }
4260
            else {
4261
              double_data[i] = get_real(infile,1); /* y */
4262
            }
4263
            i++;
4264
          }
4265
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
4266
          if(use_affine == TRUE ){ transform(i-1,2);}
4267
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
4268
          decimals = find_number_of_digits(precision);
4269
          for(c = 0 ; c < i-1 ; c = c+4){
18557 bpr 4270
            tmp_buffer=my_newmem(MAX_BUFFER);
4271
            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 4272
            add_to_buffer(tmp_buffer);
4273
            if(onclick != 0){object_cnt++;}
4274
    /* object_cnt++;*/
4275
          }
4276
          reset();
4277
          dragstuff[4] = 1;
4278
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4279
          break;
4280
        case SETLIMITS:
4281
  /*
18556 bpr 4282
  @ setlimits
4283
  @ keyword: if set, it will produce 4 inputfields for ''xmin,xmax,ymin,ymax`` and an ''ok`` button
4284
  @ may be used for inputfield based zooming / panning
4285
  @ may be styled using command <a href="#css">css</a>
4286
  @ use commands <a href="#xlabel">xlabel / ylabel</a> to change text from xmin to ''xlabel`` etc
4287
  @ note: the input value will not be checked on validity
4288
  @%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 4289
  */
4290
          js_function[JS_SAFE_EVAL] = 1;
4291
          js_function[JSPLOT_AND_ZOOM] = 1;
4292
          add_setlimits(font_size,css_class);
4293
          done = TRUE;
4294
          break;
4295
        case SETPIXEL:
4296
  /*
4297
  @ setpixel x,y,color
4298
  @ A rectangular "point" with diameter 1 pixel centered at (x:y) in xrange / yrange
4299
  @ pixels can <b>not</b> be dragged or clicked
4300
  @ "pixelsize = 1" may be changed by command <code>pixelsize int</code>
4301
  @%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%
4302
  */
4303
          js_function[DRAW_PIXELS] = 1;
4304
          for(i=0;i<3;i++){
4305
            switch(i){
4306
              case 0: double_data[0] = get_real(infile,0); break; /* x */
4307
              case 1: double_data[1] = get_real(infile,0); break; /* y */
4308
              case 2: stroke_color = get_color(infile,1);
18557 bpr 4309
                tmp_buffer=my_newmem(MAX_BUFFER);
4310
                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 4311
                add_to_buffer(tmp_buffer);
4312
                break;
4313
              default:break;
4314
            }
4315
          }
4316
          reset();
4317
          break;
4318
        case SLIDER:
4319
  /*
4320
  @ slider start_value,end_value,width px,height px,type,label
4321
  @ type may be: ''x,y,angle``
4322
  @ if a slider value display is desired, use for argument ''type``: ''x display``, ''y display``, ''angle radian``, ''angle degree``
4323
  @ 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 4324
  @ 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 4325
  @ if a unit (or something like that...) for x/y-value display is needed, use commands ''xunit`` and / or ''yunit``
4326
  @ 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>
4327
  @ use command ''slider`` before draggable/clickable objects.
4328
  @ 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'
4329
  @ no slider for a math function, these can be traced using command ''trace_jscurve some_function_in_x``
4330
  @ 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``
4331
  @ amount of sliders is not limited.
4332
  @ a slider can not be set ''snaptogrid`` or other ''snapto*`` : you may always use 'drag xy' in combination with the slider objects
4333
  @ <code>javascript:read_dragdrop();</code> will return an array with ''object_number:slider_value``
4334
  @ every draggable object may have its own slider (no limit in amount of sliders)
4335
  @ 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.
4336
  @ use fillcolor for slider controlkey
4337
  @ use strokecolor for slider bar
4338
  @ use fontfamily / fontcolor to set used fonts
4339
  @ use opacity (only fill opacity will be used) to set transparency
4340
  @ the slider canvas will be added to the ''tooltip div``: so incompatible with command tooltip ; setlimits etc
4341
  @%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
4342
  @%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
4343
  @%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
4344
  @%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
4345
  @%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">
4346
  */
4347
          js_function[INTERACTIVE] = 1;
4348
          int_data[2] = 0; /* --> show_display = 0; */
4349
          for(i=0; i<6 ; i++){
4350
            switch(i){
4351
              case 0: double_data[0] = get_real(infile,0);break; /* start value */
4352
              case 1: double_data[1] = get_real(infile,0);break; /* end value */
4353
              case 2: int_data[0] = (int)(get_real(infile,0));break; /* width */
4354
              case 3: int_data[1] = (int)(get_real(infile,0));break; /* height */
4355
              case 4: temp = get_string_argument(infile,0); /* type: x,y,angle */
4356
                if( strstr(temp,"displ")!=0 ||  strstr(temp,"deg")!=0 || strstr(temp,"rad")!=0 ){int_data[5] = 1; }else{int_data[5] = 0;}
4357
                if(strstr(temp,"anim")!= 0){int_data[3] = 1;}else{int_data[3] = 0;}
4358
                if(strstr(temp,"active")!= 0){onclick = 4;}else{onclick=0;}
4359
                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;}}
4360
                else
4361
                  if(strstr(temp,"xy") != 0){slider_type = "XY";if( strstr(temp,"disp")!= 0){int_data[2] = 5;}}
4362
                    else
4363
                      if(strstr(temp,"x") != 0){slider_type = "X";if( strstr(temp,"disp")!= 0){int_data[2] = 1;}}
4364
                      else
4365
                        if(strstr(temp,"y") != 0){slider_type = "Y";if( strstr(temp,"disp")!= 0){int_data[2] = 2;}}
4366
                          else
4367
                            canvas_error("slider can be of type: x,y,angle,fun_x:fun_y");
4368
                  break;
4369
                case 5: temp = get_string_argument(infile,1); if( strstr(temp,"\"") != 0 ){ temp = str_replace(temp,"\""," ");}
4370
        /* slider label : in case of latex/mathmlmath we need to remove the extra " */
4371
              break;
4372
            }
4373
          }
4374
          if(use_slider == -1 ){ /* add once */
4375
            add_slider(int_data[3]);
4376
            if(int_data[5] == 1 ){add_slider_display(precision,font_size,font_color,stroke_opacity);}
4377
          }
4378
          use_slider++;
4379
          if(int_data[3] == 0){\
18557 bpr 4380
 
4381
            tmp_buffer=my_newmem(MAX_BUFFER);
18570 bpr 4382
            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 4383
          }else{
18557 bpr 4384
 
18552 bpr 4385
            add_slider(int_data[3]);/* use only once !! */
18557 bpr 4386
            tmp_buffer=my_newmem(MAX_BUFFER);
18570 bpr 4387
            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 4388
          }
4389
          add_to_buffer(tmp_buffer);
4390
          fprintf(js_include_file,"var slider%d;",use_slider);
4391
          use_dragstuff = 2;
4392
//      dragstuff[22] = 1; /* dragstuff switch no 22 is a slider...*/
4393
          if(onclick != 4 ){ js_function[INTERACTIVE] = 1; }/* no need to click on object to use slider... */
4394
      //js_function[JS_ROTATE_MOUSE] = 1;
4395
          c = 0;
4396
          for(i=last_slider;i<=use_slider;i++){
4397
            int_data[c] = i; c++;
4398
          }
4399
          my_sliders = data2js_array(int_data,use_slider - last_slider+1);
4400
          break;
4401
        case SGRAPH:
4402
  /*
18556 bpr 4403
  @ sgraph xstart,ystart,xmajor,ymajor,xminor,yminor,majorgrid_color,minorgrid_color
4404
  @ primitive implementation of a ''broken scale`` graph...
4405
  @ 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>
4406
  @%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 4407
  */
4408
            js_function[DRAW_SGRAPH] = 1;
4409
            for(i = 0 ; i < 8 ;i++){
4410
              switch(i){
4411
                case 0:double_data[0] = get_real(infile,0);break;
4412
                case 1:double_data[1] = get_real(infile,0);break;
4413
                case 2:double_data[2] = get_real(infile,0);break;
4414
                case 3:double_data[3] = get_real(infile,0);break;
4415
                case 4:int_data[0] = (int)(get_real(infile,0));break;
4416
                case 5:int_data[1] = (int)(get_real(infile,0));break;
4417
                case 6:stroke_color = get_color(infile,0);break;
4418
                case 7:font_color = get_color(infile,1);
18557 bpr 4419
                tmp_buffer=my_newmem(MAX_BUFFER);
4420
                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 4421
                add_to_buffer(tmp_buffer);
4422
                break;
4423
                default:break;
4424
              }
4425
            }
4426
      /* sgraph(canvas_type,precision,xmajor,ymajor,xminor,yminor,majorcolor,minorcolor,fontfamily,opacity)*/
4427
          break;
4428
        case SNAPTOFUNCTION:
4429
  /*
4430
  @ snaptofunction some_function_in_x,some_funtion_in_y
4431
  @ alternative: snaptofun
4432
  @ the next object will snap to the calculated values
4433
  @ note: snaptofun is probably not really useful feature...
4434
  @ if you want only modification of y-values,just use: <code>snaptofunction x,5*sin(1/y)</code>
4435
  @ if you want only modification of x-values,just use: <code>snaptofunction 5*sin(1/x),y</code>
4436
  @ for now only one instance of ''snaptofunction`` is allowed
4437
  @ use rawmath on your functions: no validity checking is done by wims !
4438
  @ note: switching x and y coordinates? <code>snaptofunction y,x</code>
4439
  @%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
4440
  @%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
4441
  */
4442
          temp = get_string_argument(infile,0);
4443
          use_snap = 2;
4444
          use_snap = 5;
4445
          js_function[JS_MATH] = 1;
4446
          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));
4447
          break;
4448
        case SNAPTOPOINTS:
4449
  /*
4450
  @ snaptopoints x1,y1,x2,y2,x3,y3....
4451
  @ a userdraw object will snap to these points.
18572 bpr 4452
  @ 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 4453
  @ a draggable object (use command ''drag x|y|xy``) will snap to the closed of these points when dragged (mouseup)
4454
  @ other options: use keyword ''snaptogrid``, ''xsnaptogrid`` or ''ysnaptogrid``
18616 bpr 4455
  @%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
4456
  @%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 4457
  */
4458
          i = 0;
4459
          while( ! done ){     /* get next item until EOL*/
4460
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
4461
            if(i%2 == 0 ){
4462
              double_data[i] = get_real(infile,0); /* x */
4463
            }
4464
            else {
4465
              double_data[i] = get_real(infile,1); /* y */
4466
            }
4467
            i++;
4468
          }
4469
          decimals = find_number_of_digits(precision);
4470
      /* NEED AN EXTRA COUNTER VARIABLE FOR MORE THAN 2 CALLS */
4471
          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));
4472
          if( snap_to_points_cnt == 0 ){
4473
            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)];};");
4474
          }else{
4475
            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]);");
4476
          }
4477
          snap_to_points_cnt = 1; /* do not repeat including the js-functions...just once*/
4478
          use_snap = 4;
4479
          break;
4480
        case SNAPTOGRID:
4481
  /*
18556 bpr 4482
  @ snaptogrid
4483
  @ keyword (no arguments required)
4484
  @ a draggable object (use command ''drag x|y|xy``) will snap to the given grid when dragged (mouseup)
4485
  @ in case of userdraw the drawn points will snap to xmajor / ymajor grid
4486
  @ if no grid is defined, points will snap to every integer xrange/yrange value. (eg snap_x=1,snap_y=1)
4487
  @ if you do not want a visible grid, but you only want a ''snaptogrid`` with some value...define this grid with opacity 0.
4488
  @ 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 ...
4489
  @%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
4490
  @%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 4491
  */
4492
          use_snap = 1;
4493
          break;
4494
        case SQUARE:
4495
  /*
4496
  @ square x,y,side (px),color
4497
  @ draw a square with left top corner (x:y) with side ''side`` in color 'color'
4498
  @ use command <code>fsquare x,y,side,color</code> for a filled square
4499
  @ use command/keyword <a href='#filled'>filled</a> before command <code>square x,y,side,color</code>
4500
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
4501
  @%square%size 400,400%xrange -10,10%yrange -10,10%linewidth 3%filled%fillcolor blue%square 0,0,120,green
4502
  */
4503
          for(i=0;i<4;i++){
4504
            switch(i){
4505
            case 0:double_data[0] = get_real(infile,0);break; /* x1-values */
4506
            case 1:double_data[1] = get_real(infile,0);break; /* y1-values */
4507
            case 2:double_data[2] = get_real(infile,0);break; /* width in px */
4508
            case 3:stroke_color = get_color(infile,1);/* name or hex color */
4509
              decimals = find_number_of_digits(precision);
4510
              double_data[3] = double_data[0] + (xmax - xmin)*double_data[2]/xsize;
4511
              double_data[4] = double_data[1] + -1*(ymax - ymin)*double_data[2]/ysize;
4512
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4513
              tmp_buffer=my_newmem(MAX_BUFFER);
4514
              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 4515
              add_to_buffer(tmp_buffer);
4516
              if(onclick != 0){object_cnt++;}/* object_cnt++; */
4517
              reset();break;
4518
            default: break;
4519
            }
4520
          }
4521
          dragstuff[1] = 1;
4522
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4523
          break;
4524
        case STATUS:
4525
  /*
4526
  @ status
4527
  @ keyword
4528
  @ alernative: nostatus
4529
  @ used to override the effects of ''status=done`` in wims (answer.phtml)
4530
  @ affects ''readonly`` in inputfields / textareas in canvasimage and all userdraw based commands
4531
  @ 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``
4532
  */
11806 schaersvoo 4533
 
18552 bpr 4534
          fprintf(js_include_file,"\nwims_status=\"waiting\";\n");
4535
          break;
4536
        case STRING:
4537
  /*
18556 bpr 4538
  @ string color,x,y,the text string
4539
  @ may be set ''onclick`` or ''drag xy``
4540
  @ 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 4541
  @ 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 4542
  @ use a command like <code>fontfamily italic 24px Arial</code> to set fonts on browser that support font change
4543
  @ 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:
4544
  @%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%
4545
  @%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 4546
  */
4547
          if( use_rotate == TRUE  ){js_function[JS_ROTATE_MOUSE] = 1; }
4548
          dragstuff[14] = 1;
4549
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4550
          for(i=0;i<5;i++){
4551
            switch(i){
4552
              case 0: stroke_color = get_color(infile,0);break;/* name or hex color */
4553
              case 1: double_data[0] = get_real(infile,0);break; /* x in xrange*/
4554
              case 2: double_data[1] = get_real(infile,0);break; /* y in yrange*/
4555
              case 3: decimals = find_number_of_digits(precision);
4556
                if(use_affine == TRUE ){ transform(2,2);}
4557
        /* rotate is done by HTML5/CANVAS context rotation */
4558
                temp = get_string_argument(infile,1);
4559
                if(strstr(temp,"_") != NULL || strstr(temp,"^") != NULL){js_function[DRAW_SUBSUP] = 1;}
4560
                decimals = find_number_of_digits(precision);
4561
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4562
                tmp_buffer=my_newmem(MAX_BUFFER);
4563
                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 4564
                add_to_buffer(tmp_buffer);
4565
                if(onclick != 0){object_cnt++;}
4566
      //onclick = 0;
4567
      //use_offset = 0;
4568
                reset();
4569
                break;
4570
              default:break;
4571
            }
4572
          }
4573
          break;
4574
        case STRINGUP:
4575
  /*
18556 bpr 4576
  @ stringup color,x,y,rotation_degrees,the text string
4577
  @ may be set ''onclick`` or ''drag xy``
4578
  @ 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
4579
  @ unicode supported: <code>stringup red,0,0,45,\\u2232</code>
4580
  @ use a command like <code>fontfamily bold 34px Courier</code> to set fonts on browser that support font change
4581
  @ 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 4582
  @ 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 4583
  @ super / sub script is supported, using '<b>_</b>' and '<b>^</b>' <br>to end the subscript/supscript, use an extra space...see example:
4584
  @%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%
4585
  @%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 4586
 
18552 bpr 4587
  */
4588
      /* html5 canvas rotation is only used for text objects  */
4589
          use_rotate = TRUE ;
4590
          dragstuff[14] = 1;
4591
          js_function[JS_ROTATE_MOUSE] = 1;
4592
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
10953 bpr 4593
 
18552 bpr 4594
          for(i=0;i<6;i++){
4595
            switch(i){
4596
              case 0: stroke_color = get_color(infile,0);break;/* name or hex color */
4597
              case 1: double_data[0] = get_real(infile,0);break; /* x */
4598
              case 2: double_data[1] = get_real(infile,0);break; /* y */
4599
              case 3: angle = get_real(infile,0);break;/* rotation */
4600
              case 4: decimals = find_number_of_digits(precision);
4601
                temp = get_string_argument(infile,1);
4602
                if(strstr(temp,"_") != NULL || strstr(temp,"^") != NULL){js_function[DRAW_SUBSUP] = 1;}
4603
                decimals = find_number_of_digits(precision);
4604
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4605
                tmp_buffer=my_newmem(MAX_BUFFER);
4606
                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 4607
                add_to_buffer(tmp_buffer);
4608
                if(onclick != 0){object_cnt++;}
4609
                //onclick = 0;
4610
                //use_offset = 0;
4611
                reset();
4612
                break;
4613
              default:break;
4614
            }
4615
          }
4616
          use_rotate = FALSE;
4617
          break;
4618
        case STYLE:
4619
  /*
18556 bpr 4620
  @ highlight color,opacity,linewidth
4621
  @ NOT IMPLEMENTED
4622
  @ use command ''onclick``: when the object receives a userclick it will increase its linewidth
18552 bpr 4623
  */
4624
         break;
4625
        case STROKECOLOR:
4626
  /*
4627
  @ strokecolor colorname or #hex
4628
  @ to be used for commands that do not supply a color argument (like command ''linegraph``)
4629
  */
4630
          stroke_color = get_color(infile,1);
4631
          break;
4632
        case FLY_TEXT:
4633
  /*
4634
  @ text fontcolor,x,y,font,text_string
4635
  @ font may be described by keywords: giant,huge,normal,small,tiny
4636
  @ use command ''fontsize`` to increase base fontsize for these keywords
4637
  @ may be set ''onclick`` or ''drag xy``
4638
  @ backwards compatible with flydraw
4639
  @ unicode supported: text red,0,0,huge,\\u2232
4640
  @ special: use '_' and '^' to imitate html sup/sub, like H_3O^+ + OH^\\u22i2  \\u2192 2H_2 O
4641
  @ 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
4642
  @ 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
4643
  @ 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.
4644
  @%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
4645
  */
4646
        for(i = 0; i < 5 ;i++){
4647
          switch(i){
4648
            case 0: stroke_color = get_color(infile,0);break;/* font_color == stroke_color name or hex color */
4649
            case 1: double_data[0] = get_real(infile,0);break; /* x */
4650
            case 2: double_data[1] = get_real(infile,0);break; /* y */
4651
            case 3: fly_font = get_string_argument(infile,0);
4652
              if(strcmp(fly_font,"giant") == 0){
4653
                fly_font_size = (int)(font_size + 24);
4654
              }
4655
              else {
4656
                if(strcmp(fly_font,"huge") == 0){
4657
                  fly_font_size = (int)(font_size + 14);
4658
                }
4659
                else {
4660
                  if(strcmp(fly_font,"large") == 0){
4661
                    fly_font_size = (int)(font_size + 6);
4662
                  }
4663
                  else {
4664
                    if(strcmp(fly_font,"small") == 0){
4665
                      fly_font_size = (int)(font_size - 4);
4666
                      if(fly_font_size<0){fly_font_size = 8;}
4667
                    }
4668
                  }
4669
                }
4670
              }
4671
              break;
4672
            case 4:
4673
              temp = get_string_argument(infile,1);
4674
              if(strstr(temp,"_") != NULL || strstr(temp,"^") != NULL){js_function[DRAW_SUBSUP] = 1;}
4675
              decimals = find_number_of_digits(precision);
4676
              if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
4677
              if(use_affine == TRUE ){ transform(2,2);}
18557 bpr 4678
              tmp_buffer=my_newmem(MAX_BUFFER);
4679
              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 4680
              add_to_buffer(tmp_buffer);
4681
              if(onclick != 0){object_cnt++;}
4682
              reset();
4683
              break;
4684
            default:break;
4685
            }
4686
          }
4687
          dragstuff[14] = 1;
4688
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4689
          break;
4690
        case TEXTAREA:
4691
  /*
18556 bpr 4692
  @ textarea x,y,cols,rows,readonly,value
4693
  @ may be further controlled by <a href="#css">css</a>
4694
  @ 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>.
4695
  @ 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>)
4696
  @ keyword ''xoffset | centered`` is not active for command ''textarea``
4697
  @%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 4698
  */
4699
          js_function[DRAW_TEXTAREAS] = 1;
4700
          for(i = 0 ; i<6;i++){
4701
            switch(i){
4702
              case 0: int_data[0]=x2px(get_real(infile,0));break; /* x in px */
4703
              case 1: int_data[1]=y2px(get_real(infile,0));break; /* y in px */
4704
              case 2: int_data[2]=abs( (int)(get_real(infile,0)));break;/* cols */
4705
              case 3: int_data[3]=abs( (int)(get_real(infile,0)));break;/* rows */
4706
              case 4: if( get_real(infile,1) >0){int_data[4] = 1;}else{int_data[3] = 0;};break; /* readonly */
4707
              case 5: temp = get_string_argument(infile,1);
18557 bpr 4708
                tmp_buffer=my_newmem(MAX_BUFFER);
4709
                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 4710
                add_to_buffer(tmp_buffer);
4711
                input_cnt++;break;
4712
              default: break;
4713
            }
4714
          }
4715
          if(reply_format == 0 ){reply_format = 15;}
4716
          reset();
4717
          break;
4718
        case TEXTFILL:
4719
  /*
4720
  @ textfill x0,y0,color,some_text
4721
  @ x0,y0 in xrange / yrange
4722
  @ color will be used for the font color
4723
  @ use command <a href="#fontfamily">fontfamily</a> to set font type and size
4724
  @ there is also a command <a href="#userdraw">userdraw textfill,color,some_text</a>
4725
  @%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
4726
  */
11806 schaersvoo 4727
 
18552 bpr 4728
          js_function[DRAW_TEXTFILL] = 1;
4729
          if(js_function[DRAW_FILLTOBORDER] != 1 ){/* use only once */
4730
            js_function[DRAW_FILLTOBORDER] = 1;
4731
            add_js_filltoborder(canvas_type);
4732
          }
4733
          decimals = find_number_of_digits(precision);
4734
          for(i=0;i<4;i++){
4735
            switch(i){
4736
              case 0: double_data[0] = get_real(infile,0); break; /* x in px */
4737
              case 1: double_data[1] = get_real(infile,0); break; /* y in py */
4738
              case 2: font_color = get_color(infile,0); break;
4739
              case 3: temp = get_string(infile,1);
18557 bpr 4740
                tmp_buffer=my_newmem(MAX_BUFFER);
4741
                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 4742
                add_to_buffer(tmp_buffer);
4743
                fill_cnt++;
4744
                break;
4745
              default:break;
4746
            }
4747
          }
4748
          reset();
4749
          break;
4750
        case FLY_TEXTUP:
4751
  /*
18556 bpr 4752
  @ textup fontcolor,x,y,font,text_string
4753
  @ can <b>not</b> be set ''onclick`` or ''drag xy`` (because of translaton matrix...mouse incompatible)
4754
  @ font may be described by keywords: giant,huge,normal,small,tiny
4755
  @ use command ''fontsize`` to increase base fontsize for the keywords
4756
  @ backwards compatible with flydraw
4757
  @ unicode supported: textup red,0,0,huge,\\u2232
4758
  @ use command ''stringup`` and ''fontfamily`` for a more fine grained control over html5 canvas text element
4759
  @ 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 4760
  */
4761
          js_function[DRAW_TEXTS] = 1;
4762
          for(i = 0; i<5 ;i++){
4763
            switch(i){
4764
              case 0: font_color = get_color(infile,0);break;/* name or hex color */
4765
              case 1: int_data[0] = x2px(get_real(infile,0));break; /* x */
4766
              case 2: int_data[1] = y2px(get_real(infile,0));break; /* y */
4767
              case 3: fly_font = get_string_argument(infile,0);
4768
                if(strcmp(fly_font,"giant") == 0){
4769
                  fly_font_size = (int)(font_size + 24);
4770
                }
4771
                else {
4772
                  if(strcmp(fly_font,"huge") == 0){
4773
                    fly_font_size = (int)(font_size + 14);
4774
                  }
4775
                  else {
4776
                    if(strcmp(fly_font,"large") == 0){
4777
                      fly_font_size = (int)(font_size + 6);
4778
                    }
4779
                    else {
4780
                      if(strcmp(fly_font,"small") == 0){
4781
                        fly_font_size = (int)(font_size - 4);
4782
                        if(fly_font_size<0){fly_font_size = 8;}
4783
                      }
4784
                    }
4785
                  }
4786
                }
4787
                break;
4788
              case 4:
4789
                decimals = find_number_of_digits(precision);
4790
                temp = get_string_argument(infile,1);
4791
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4792
                tmp_buffer=my_newmem(MAX_BUFFER);
4793
                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 4794
                add_to_buffer(tmp_buffer);
4795
                reset();
4796
        //use_offset = 0;
4797
                break;
4798
              default:break;
4799
            }
4800
          }
4801
          break;
4802
        case TRACE_JSCURVE:
4803
  /*
18556 bpr 4804
  @ trace_jscurve some_math_function
4805
  @ will use a crosshair to trace the jsmath curve
4806
  @ two inputfields will display the current x/y-values (numerical evaluation by javascript)
4807
  @ 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
4808
  @ use commands fontsize and css to format the fonts for labels and inputfields.
4809
  @ use commands ''linewidth, strokecolor, crosshairsize`` to adjust the corsshair.
4810
  @ 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...)
4811
  @ be aware that the formulas of the plotted function(s) can be found in the page javascript source
4812
  @%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 4813
  */
4814
          js_function[INTERACTIVE] = 1;
4815
          js_function[DRAW_CROSSHAIRS] = 1;
4816
          js_function[DRAW_LINES] = 1;
4817
          js_function[JS_MATH] = 1;
4818
          add_trace_js_mouse(TRACE_CANVAS,stroke_color,get_string(infile,1),font_size,stroke_opacity,line_width,crosshair_size,css_class);
4819
          break;
4820
        case TRANGE:
4821
  /*
4822
  @ trange tmin,tmax
4823
  @ alternative: ranget
4824
  @ default -2,2
4825
  */
4826
          use_parametric = TRUE;
4827
          for(i = 0 ; i<2; i++){
4828
            switch(i){
4829
              case 0: tmin = get_real(infile,0);break;
4830
              case 1: tmax = get_real(infile,1);break;
4831
              default: break;
4832
            }
4833
          }
4834
          if(tmin >= tmax ){canvas_error(" trange is not OK: tmin &lt; tmax!\n");}
4835
          break;
4836
        case TRANSLATION:
4837
  /*
18556 bpr 4838
  @ translation tx,ty
4839
  @ alternative: translate
4840
  @ will translate the next objects tx in xrange and ty in yrange
4841
  @ use command ''killtranstation`` to end the command
18569 bpr 4842
  @%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 4843
  */
4844
          for(i = 0 ; i<2;i++){
4845
            switch(i){
4846
              case 0: affine_matrix[4] = get_real(infile,0);break;
4847
              case 1: affine_matrix[5] = get_real(infile,1);
4848
                use_affine = TRUE;
4849
      /* the other values affine_matrix[0..3] remain untouched*/
4850
                break;
4851
              default: break;
4852
            }
4853
          }
4854
          break;
4855
        case TRIANGLE:
4856
  /*
18556 bpr 4857
  @ triangle x1,y1,x2,y2,x3,y3,color
4858
  @ use ftriangle or keyword <a href='#filled'>filled</a> for a solid triangle
4859
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
4860
  @%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 4861
  */
4862
          for(i=0;i<7;i++){
4863
            switch(i){
4864
              case 0: double_data[0] = get_real(infile,0);break; /* x */
4865
              case 1: double_data[1] = get_real(infile,0);break; /* y */
4866
              case 2: double_data[2] = get_real(infile,0);break; /* x */
4867
              case 3: double_data[3] = get_real(infile,0);break; /* y */
4868
              case 4: double_data[4] = get_real(infile,0);break; /* x */
4869
              case 5: double_data[5] = get_real(infile,0);break; /* y */
4870
              case 6: stroke_color = get_color(infile,1);/* name or hex color */
4871
                decimals = find_number_of_digits(precision);
18623 bpr 4872
                if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 4873
                if( use_rotate == TRUE ){ rotate(6,angle,rotationcenter,2);}
4874
                if( use_affine == TRUE ){ transform(6,2);}
4875
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 4876
                tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 4877
                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 4878
                add_to_buffer(tmp_buffer);
4879
                if(onclick != 0){object_cnt++;}
4880
          /* object_cnt++;*/
4881
                reset();
4882
                break;
4883
              default: break;
4884
            }
4885
          }
4886
          dragstuff[5] = 1;
4887
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4888
          break;
4889
        case TRIANGLES:
4890
  /*
18556 bpr 4891
  @ triangles color,x1,y1,x2,y2,x3,y3,...
4892
  @ use ftriangles or keyword <a href='#filled'>filled</a> for solid triangles
4893
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
4894
  @%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 4895
  */
4896
          stroke_color = get_color(infile,0);/* name or hex color */
18623 bpr 4897
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18552 bpr 4898
          i = 0;
4899
          decimals = find_number_of_digits(precision);
4900
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
4901
          while( ! done ){
4902
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
4903
            double_data[0] = get_real(infile,0); /* x1 */
4904
            double_data[1] = get_real(infile,0); /* y1 */
4905
            double_data[2] = get_real(infile,0); /* x2 */
4906
            double_data[3] = get_real(infile,0); /* y2 */
4907
            double_data[4] = get_real(infile,0); /* x3 */
4908
            double_data[5] = get_real(infile,1); /* y3 */
18557 bpr 4909
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 4910
            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 4911
            add_to_buffer(tmp_buffer);
4912
            if(onclick != 0){object_cnt++;}
4913
            i = i + 6;
4914
          }
4915
          reset();
4916
          dragstuff[5] = 1;
4917
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
4918
          break;
4919
        case USERBOXPLOT:
4920
  /*
18556 bpr 4921
  @ userboxplot
4922
  @ keyword, no arguments
4923
  @ use before command <a href="#boxplot">boxplot x_or_y,box-height_or_box-width,x_or_y-position</a>
4924
  @ if set, the student will have to calculate "min,Q1,median,Q3,max" and feed these data into the ''draw_boxplot`` function
4925
  @ 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 4926
  */
4927
          js_function[DRAW_BOXPLOT] = 1;
4928
          fprintf(js_include_file,"var boxplot_source = 3;\n");
4929
          js_function[DRAW_JSBOXPLOT] = 2;
4930
          break;
4931
        case USERBOXPLOTDATA:
4932
  /*
18556 bpr 4933
  @ userboxplotdata
4934
  @ keyword, no arguments
4935
  @ use before command <a href="#boxplot">boxplot x_or_y,box-height_or_box-width,x_or_y-position</a>
4936
  @ if set, the student will have to generate some statistical data. These data should be put in a named array ''student_boxplot_data``
4937
  @ ''min,Q1,median,Q3,max`` are calculated by a js-function and the 'draw_boxplot' function will draw a boxplot.
4938
  @ see command <a href="#userboxplot">userboxplot</a> for calling 'draw_boxplot()'
18552 bpr 4939
  */
4940
          js_function[DRAW_BOXPLOT] = 1;
4941
          fprintf(js_include_file,"var boxplot_source = 2;\n");
4942
          js_function[DRAW_JSBOXPLOT] = 1;
4943
          break;
4944
        case USERDRAW:
4945
  /*
4946
  @ userdraw object_type,color
4947
  @ only a single object_type is allowed.
4948
  @ right mouse click will remove last drawn object.
4949
  @ for multiple different 'userdraw' objects in an exercise, use command <a href="#multidraw">multidraw</a>
18572 bpr 4950
  @ 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 4951
  @ 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)
4952
  @ note: object_type text: Any string or multiple strings may be placed anywhere on the canvas.<br>Use command ''fontfamily`` to set font
4953
  @ note: object_type polygone: Will be finished (the object is closed) when clicked on the first point of the polygone again.
4954
  @ 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 4955
  @ 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 4956
  @ for non solid filling, use command <a href="#fillpattern">fillpattern grid,hatch,diamond,dot</a>
4957
  @ use <a href='#opacity'>opacity int,int</a> and <a href='#fillcolor'>fillcolor color</a> to trigger coloured filling of fillable objects
4958
  @ use command ''dashed`` and/or ''dashtype int,int`` to trigger dashing
4959
  @ use command ''replyformat int`` to control / adjust output formatting of javascript function read_canvas(); (the defaults should be fine...)
4960
  @ may be combined with onclick or drag xy of other components of flyscript objects (although not very useful...)
4961
  @ may be combined with keyword <a href='#userinput_xy'>userinput_xy</a>
4962
  @ may be combined width the <a href='#snaptogrid'>snaptogrid snaptopoints </a> etc, to simplify the checking of the student reply
4963
  @ the cursor may be appropriately styled using command <a href='cursor'>cursor</a>
4964
  @ 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...
4965
  @ 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)
4966
  @ 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!)
4967
  @ 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 4968
  @ 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 4969
  @%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
4970
  @%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
4971
  @%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
4972
  @%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
4973
  @%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 4974
  @%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
4975
  @%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
4976
  @%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
4977
  @%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
4978
  @%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 4979
  @%userdraw_line%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw line,green
4980
  @%userdraw_lines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw lines,green
4981
  @%userdraw_vline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw vline,green
4982
  @%userdraw_vlines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw vlines,green
4983
  @%userdraw_hline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw hline,green
4984
  @%userdraw_hlines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw hlines,green
4985
  @%userdraw_demiline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw demiline,green
4986
  @%userdraw_demilines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw demilines,green
4987
  @%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
4988
  @%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
4989
  @%userdraw_point%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw point,green
4990
  @%userdraw_points%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw points,green
4991
  @%userdraw_arrow%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw arrow,green
4992
  @%userdraw_arrows%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw arrows,green
4993
  @%userdraw_arrow2%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw arrow2,green
4994
  @%userdraw_arrows2%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw arrows2,green
4995
  @%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
4996
  @%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
4997
  @%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
4998
  @%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
4999
  @%userdraw_crosshair%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw crosshair,green
5000
  @%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 5001
  @%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
5002
  @%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 5003
  @%userdraw_segment%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw segment,green
5004
  @%userdraw_segments%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw segments,green
5005
  @%userdraw_line%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw line,green
5006
  @%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 5007
  @%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
5008
  @%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 5009
  @%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
5010
  @%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
5011
  @%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 5012
  @%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 5013
  @%userdraw_freehandline%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw freehandline,green
5014
  @%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
5015
  @%userdraw_freehandlines%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%linewidth 2%opacity 200,50%userdraw freehandlines,green
5016
  @%userdraw_input%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%userdraw input,green
5017
  @%userdraw_inputs%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%userdraw inputs,green
5018
  @%userdraw_text%size 400,400%xrange -10,10%yrange -10,10%grid 1,1,grey%fontfamily 42px Courier%userdraw text,green
5019
  @%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
5020
  @%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
5021
  @%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 5022
  @%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 5023
  @%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
5024
  */
5025
          if( use_userdraw != 0 ){ /* only one object type may be drawn*/
5026
            canvas_error("Only one userdraw primitive may be used in command 'userdraw' use command 'multidraw' for this...");
5027
          }
5028
          js_function[INTERACTIVE] = 1;
5029
          draw_type = get_string_argument(infile,0);
5030
          if( strcmp(draw_type,"textfill") == 0){
5031
            fprintf(js_include_file,"var userdraw_text_string = \"%s\";", get_string(infile,1));
5032
          }
5033
          else {
5034
            if( strcmp(draw_type,"imagefill") == 0){
5035
              fprintf(js_include_file,"var userdraw_image_url = \"%s\";", get_string(infile,1));
5036
            }
5037
            else {
5038
              stroke_color = get_color(infile,1);
5039
            }
5040
          }
5041
          if( strcmp(draw_type,"clickfill") == 0){use_filled = 1;fill_color = stroke_color;}
5042
          reply_precision = precision;
5043
          use_userdraw = 1;
5044
          fprintf(js_include_file,"\n\
15111 schaersvoo 5045
/* begin userdraw */\
5046
userdraw_x = new Array();userdraw_y = new Array();userdraw_radius = new Array();\
5047
var forbidden_zone=[xsize+1,ysize+1];var xy_cnt = 0;\
5048
var canvas_userdraw = create_canvas%d(%d,xsize,ysize);\
5049
var context_userdraw = canvas_userdraw.getContext(\"2d\");\
5050
var use_dashed = %d;\
5051
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];};};};\
5052
context_userdraw.lineWidth = %d;var use_filled = %d;\
5053
context_userdraw.strokeStyle =  \"rgba(%s,%.2f)\";\
5054
context_userdraw.font = \"%s\";\
15128 schaersvoo 5055
var user_is_dragging = false;\
15111 schaersvoo 5056
if(wims_status != \"done\"){\
5057
canvas_div.addEventListener(\"mousedown\" ,user_draw,false);\
5058
canvas_div.addEventListener(\"mousemove\" ,user_drag,false);\
5059
canvas_div.addEventListener(\"touchstart\",function(e){ e.preventDefault();user_draw(e.changedTouches[0]);},false);\
5060
canvas_div.addEventListener(\"touchmove\" ,function(e){ e.preventDefault();user_drag(e.changedTouches[0]);},false);\
15128 schaersvoo 5061
canvas_div.addEventListener(\"touchend\" ,function(e){ e.preventDefault();user_drawstop(e.changedTouches[0]);},false);\
15111 schaersvoo 5062
};",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);
5063
 
18552 bpr 5064
          if( use_filled == 0 ){
5065
            fprintf(js_include_file,"context_userdraw.fillStyle = \"rgba(255,255,255.0)\";");
5066
          }
5067
          else {
5068
            if( use_filled == 1 ){
5069
              fprintf(js_include_file,"context_userdraw.fillStyle = \"rgba(%s,%.2f)\";",fill_color,fill_opacity);
5070
            }
5071
            else {
5072
              js_function[DRAW_FILL_PATTERN] = 1;
5073
              fprintf(js_include_file,"context_userdraw.fillStyle = create_Pattern(0,0,%d,[%s]);\n",use_filled,fill_color);
5074
            }
5075
          }
5076
          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);
5077
          reset();
5078
          break;
5079
        case USERINPUT:
5080
  /*
18556 bpr 5081
  @ userinput function inputfield
5082
  @ alternative: userinput_function
5083
  @ alternative: userinput_xy
5084
  @ ''inputfield`` is only usable in combination with some ''userdraw draw_type``
5085
  @ note: the input fields are not cleared after the object is drawn...be aware of multiple idential drawings (many clicks on the ''ok`` button)
5086
  @ ''userinput function`` may be used any time (e.g. without userdraw)
5087
  @ multiple ''userinput function`` commands may be used.
5088
  @ use command <code>functionlabel some_string</code> to define the inputfield text: default value "f(x)="
5089
  @ use command <code>strokecolor some_color</code> to adjust the plot / functionlabel color
5090
  @ use command <code>css some_css</code> to adjust the inputfields
5091
  @ use command <code>fontsize int</code> to adjust the label fonts. (default 12px)
5092
  @ 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
5093
  @%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
5094
  @%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
5095
  @%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
5096
  @%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 5097
  */
5098
          temp = get_string_argument(infile,1);
5099
          if(strstr(temp,"function") != 0  || strstr(temp,"curve") != 0  || strstr(temp,"plot") != 0 ){
5100
            if( js_function[DRAW_JSFUNCTION] != 1 ){
5101
              js_function[JS_RAWMATH] = 1;
5102
              js_function[DRAW_JSFUNCTION] = 1;
5103
              if(reply_format == 0){reply_format = 24;}/* read canvas_input values */
5104
              add_input_jsfunction(css_class,function_label,input_cnt,stroke_color,stroke_opacity,line_width,use_dashed,dashtype[0],dashtype[1],font_size);
5105
              input_cnt++;
5106
            }
5107
            else {
5108
        /* no need to add DRAW_JSFUNCTION, just call it with the parameters */
5109
            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);
5110
            input_cnt++;
5111
            }
5112
            js_function[JS_MATH] = 1;
5113
            js_function[JS_PLOT] = 1;
5114
          }
5115
          else {
5116
            if(strstr(temp,"inputfield") != 0 ){
5117
              js_function[JS_SAFE_EVAL] = 1;
5118
              js_function[ADD_USER_INPUTS] = 1;
5119
            }
5120
            else {
5121
              canvas_error("userinput argument may be \"function\" or \"inputfield\"");
5122
            }
5123
          }
5124
          break;
5125
        case USERINPUT_XY:
5126
  /*
5127
  @ userinput_xy
5128
  @ keyword (no arguments required)
5129
  @ to be used in combination with command "userdraw object_type,color"
5130
  @ 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)
5131
  @ the student may use this as correction for (x:y) on a drawing (or to draw without mouse, using just the coordinates)
5132
  @ 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.
5133
  @ can <b>not</b> be combined with command ''intooltip tiptext`` <br>note: the ''tooltip div element`` is used for placing inputfields
5134
  @ user drawings will not zoom on zooming (or pan on panning)
5135
  @ use command ''css some_css`` to adjust the inputarea.
5136
  @ use command ''fontsize int`` to adjust the text labels (if needed)
5137
  @%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
5138
  */
5139
      /* add simple eval check to avoid code injection with unprotected eval(string) */
5140
          js_function[JS_SAFE_EVAL] = 1;
5141
          js_function[ADD_USER_INPUTS] = 1;
5142
          break;
5143
        case USERINPUT_FUNCTION:
5144
  /*
5145
  @ userinput_function
5146
  @ alternative: userinput
5147
  @ keyword (no arguments required)
5148
  @ if set, a inputfield will be added to the page
5149
  @ repeat keyword for more function input fields
5150
  @ the userinput value will be plotted in the canvas
5151
  @ 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
5152
  @ 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
5153
  @ fontsize can be set using command ''fontsize int``
5154
  @ incompatible with command ''intooltip link_text_or_image``: it uses the tooltip div for adding the inputfield
5155
  @%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
5156
  */
5157
          if( js_function[DRAW_JSFUNCTION] != 1 ){
5158
            js_function[DRAW_JSFUNCTION] = 1;
5159
            js_function[JS_RAWMATH] = 1;
5160
            if(reply_format == 0){reply_format = 24;}/* read canvas_input values */
5161
            add_input_jsfunction(css_class,function_label,input_cnt,stroke_color,stroke_opacity,line_width,use_dashed,dashtype[0],dashtype[1],font_size);
5162
            input_cnt++;
5163
          }
5164
          else {
5165
        /* no need to add DRAW_JSFUNCTION, just call it with the parameters */
5166
          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);
5167
          input_cnt++;
5168
          }
5169
          js_function[JS_MATH] = 1;
5170
          js_function[JS_PLOT] = 1;
5171
          break;
5172
        case VLINE:
5173
  /*
5174
  @ vline x,y,color
5175
  @ alternative: verticalline
5176
  @ draw a vertical line through point (x:y) in color 'color'
5177
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
5178
  @%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
5179
  */
5180
          for(i=0;i<3;i++) {
5181
            switch(i){
5182
              case 0: double_data[0] = get_real(infile,0);break; /* x-values */
5183
              case 1: double_data[1] = get_real(infile,0);break; /* y-values */
5184
              case 2: stroke_color=get_color(infile,1);/* name or hex color */
5185
                double_data[2] = double_data[0];
5186
                decimals = find_number_of_digits(precision);
5187
                if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18557 bpr 5188
                    tmp_buffer=my_newmem(MAX_BUFFER);
5189
                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 5190
                add_to_buffer(tmp_buffer);
5191
                if(onclick != 0){object_cnt++;}
5192
      /* object_cnt++; */
5193
                reset();
5194
               break;
5195
            }
5196
          }
5197
          dragstuff[4] = 1;
5198
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5199
          break;
5200
        case VLINES:
5201
  /*
5202
  @ vlines color,x1,y1,x2,y2....
5203
  @ alternative: verticallines
5204
  @ draw vertical lines through points (x1:y1),(x2:y2)... in color 'color'
5205
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually
5206
  @%vlines%size 400,400%xrange -10,10%yrange -10,10%linewidth 2%onclick%vlines red,1,0,2,0,3,0,4,0
5207
  */
5208
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5209
          fill_color = stroke_color;
5210
          i=0;
5211
          while( ! done ){     /* get next item until EOL*/
5212
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5213
            if(i%2 == 0 ){
5214
              double_data[i] = get_real(infile,0); /* x */
5215
            }
5216
            else {
5217
              double_data[i] = get_real(infile,1); /* y */
5218
            }
5219
            i++;
5220
          }
5221
          decimals = find_number_of_digits(precision);
5222
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5223
          for(c = 0 ; c < i-1 ; c = c+2){
18557 bpr 5224
            tmp_buffer=my_newmem(MAX_BUFFER);
18607 bpr 5225
            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 5226
            add_to_buffer(tmp_buffer);
5227
            if(onclick != 0){object_cnt++;}
5228
            /* object_cnt++; */
5229
          }
5230
          reset();
5231
          dragstuff[4] = 1;
5232
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5233
          break;
5234
        case VIDEO:
5235
  /*
5236
  @ video x,y,w,h,videofile location
5237
  @ x,y: left top corner of audio element (in xrange / yrange)
5238
  @ w,y: width and height in pixels
5239
  @ video format may be in *.mp4 (todo: other formats)
5240
  @%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
5241
  */
5242
          js_function[DRAW_VIDEO] = 1;
5243
          for(i=0;i<5;i++){
5244
            switch(i){
5245
              case 0: int_data[0] = x2px(get_real(infile,0)); break; /* x in x/y-range coord system -> pixel */
5246
              case 1: int_data[1] = y2px(get_real(infile,0)); break; /* y in x/y-range coord system -> pixel */
5247
              case 2: int_data[2] = (int) (get_real(infile,0)); break; /* pixel width */
5248
              case 3: int_data[3] = (int) (get_real(infile,0)); break; /* height pixel height */
5249
              case 4: temp = get_string(infile,1);
18557 bpr 5250
                tmp_buffer=my_newmem(MAX_BUFFER);
5251
                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 5252
                add_to_buffer(tmp_buffer);
5253
                break;
5254
              default:break;
5255
            }
5256
          }
5257
          reset();
5258
          break;
5259
        case X_AXIS_STRINGS:
5260
  /*
18556 bpr 5261
  @ xaxis num1:string1:num2:string2:num3:string3:num4:string4:....num_n:string_n
5262
  @ alternative: xaxistext
5263
  @ usable for commands <a href="#numberline">numberline</a> and <a href="#grid">grid</a> or combinations thereof
5264
  @ use these x-axis num1...num_n values instead of default xmin...xmax
5265
  @ in case of command ''grid``. there is no need to use keyword <a href="#axisnumbering">axisnumbering</a>
5266
  @ use command <a href="#axis">axis</a> to have visual x/y-axis lines (see command <a href="#grid">grid</a>
5267
  @ 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>)
5268
  @ a javascript error message will flag non-matching value:name pairs
5269
  @ if the ''x-axis words`` are too big and will overlap, a simple alternating offset will be applied
5270
  @ to be used before command grid (see <a href="#grid">command grid</a>)
5271
  @ ''xmajor`` steps should be synchronised with numbers eg. ''1`` in the next example <code>grid 1,100,grey,1,4,6,grey</code>
5272
  @%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 5273
  */
5274
          use_axis_numbering++;
5275
          temp = get_string(infile,1);
5276
          if( strstr(temp,":") != 0 ){ temp = str_replace(temp,":","\",\"");}
5277
          if( strstr(temp,"pi") != 0 ){ temp = str_replace(temp,"pi","(3.1415927)");}/* we need to replace pi for javascript y-value*/
5278
          fprintf(js_include_file,"x_strings[%d] = [\"%s\"];x_strings_up[%d] = null;",use_axis_numbering,temp,use_axis_numbering);
5279
          break;
5280
        case X_AXIS_STRINGS_UP:
5281
  /*
18556 bpr 5282
  @ xaxisup num1:string1:num2:string2:num3:string3:num4:string4:....num_n:string_n
5283
  @ alternative: xaxistextup
5284
  @ the text will be rotated 90&deg; up
5285
  @ no need to use keyword <a href="#axisnumbering">axisnumbering</a>
5286
  @ use command <a href="#axis">axis</a> to have visual x/y-axis lines (see command <a href="#grid">grid</a>
5287
  @ use these x-axis num1...num_n values instead of default xmin...xmax
5288
  @ 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>)
5289
  @ a javascript error message will flag non-matching value:name pairs
5290
  @ if the ''x-axis words`` are too big, they will overlap the graph<br> (in this case the text will start from ysize upwards)
5291
  @ to be used before command grid (see <a href="#grid">command grid</a>)
5292
  @''xmajor`` steps should be synchronised with numbers eg. "1" in the next example <code>grid 1,100,grey,1,4,6,grey</code>
5293
  @%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 5294
  */
5295
          use_axis_numbering++;
5296
          temp = get_string(infile,1);
5297
          if( strstr(temp,":") != 0 ){ temp = str_replace(temp,":","\",\"");}
5298
          if( strstr(temp,"pi") != 0 ){ temp = str_replace(temp,"pi","(3.1415927)");}/* we need to replace pi for javascript y-value*/
5299
          fprintf(js_include_file,"x_strings_up[%d] = 1;x_strings[%d] = [\"%s\"];",use_axis_numbering,use_axis_numbering,temp);
5300
          break;
5301
        case XERRORBARS:
5302
  /*
5303
  @ xerrorbars color,E1,E2,x1,y1,x2,y2,...,x_n,y_n
5304
  @ 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'
5305
  @ the errors E1 and E2 values are in xrange.
5306
  @ use command ''linewidth int`` to adust size
5307
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
5308
  @%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 5309
 
18552 bpr 5310
  */
5311
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5312
          fill_color = stroke_color;
5313
          i=0;
5314
          while( ! done ){     /* get next item until EOL*/
5315
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5316
            if(i%2 == 0 ){
5317
                double_data[i] = get_real(infile,0); /* x */
5318
            }
5319
            else {
5320
              double_data[i] = get_real(infile,1); /* y */
5321
            }
5322
            i++;
5323
          }
5324
          decimals = find_number_of_digits(precision);
5325
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5326
          for(c = 2 ; c < i-1 ; c = c+2){
18557 bpr 5327
            tmp_buffer=my_newmem(MAX_BUFFER);
5328
            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 5329
            add_to_buffer(tmp_buffer);
5330
            /* object_cnt++; */
5331
            if(onclick != 0){object_cnt++;}
5332
          }
5333
          reset();
5334
          dragstuff[20] = 1;
5335
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5336
          break;
5337
        case NEWRANGE:
5338
  /*
5339
  @ newrange xmin,xmax,ymin,ymax
5340
  @ objects defined after command will make use of this new range
5341
  @ https://wimsedu.info/?topic=dessiner-des-portions-de-fonctions-sur-un-meme-graphe
5342
  */
5343
          for(i = 0 ; i<4; i++){
5344
            switch(i){
5345
              case 0: xmin = get_real(infile,0);break;
5346
              case 1: xmax = get_real(infile,0);break;
5347
              case 2: ymin = get_real(infile,0);break;
5348
              case 3: ymax = get_real(infile,1);break;
5349
              default: break;
5350
            }
5351
          }
18557 bpr 5352
          tmp_buffer=my_newmem(MAX_BUFFER);
5353
          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 5354
          add_to_buffer(tmp_buffer);
5355
          break;
5356
        case XRANGE:
5357
  /*
5358
  @ xrange xmin,xmax
5359
  @ alternative: rangex
5360
  @ if not given: 0,xsize (eg in pixels)
5361
  */
18556 bpr 5362
          for(i = 0 ; i<2; i++){
5363
            switch(i){
5364
              case 0: xmin = get_real(infile,0);break;
5365
              case 1: xmax = get_real(infile,1);break;
5366
              default: break;
5367
            }
5368
          }
5369
          if(xmin >= xmax){canvas_error(" xrange is not OK: xmin &lt; xmax !");}
5370
          fprintf(js_include_file,"var xmin = %f;var xmax = %f;",xmin,xmax);
5371
          found_size_command++;
5372
          break;
18552 bpr 5373
        case XSNAPTOGRID:
5374
  /*
18556 bpr 5375
  @ xsnaptogrid
5376
  @ keyword (no arguments required)
5377
  @ a draggable object (use command ''drag x|y|xy``) will snap to the given x-grid values when dragged (mouseup)
5378
  @ in case of userdraw the drawn points will snap to xmajor grid
5379
  @ if no grid is defined, points will snap to every integer xrange value. (eg snap_x=1)
5380
  @ if you do not want a visible grid, but you only want a ''snaptogrid`` with some value...define this grid with opacity 0.
5381
  @ 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>
5382
  @%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
5383
  @%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
5384
*/
5385
          use_snap = 2;
5386
          break;
18552 bpr 5387
        case XOFFSET:
5388
  /*
18556 bpr 5389
  @ xoffset
5390
  @ keyword ; to place the text centered above the text coordinates(x:y) ...
5391
  @ may be used for points or other things requiring centered labels
5392
  @ use <a href="#fontfamily">fontfamily</a> for setting the font
5393
  @ 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 5394
  @%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
5395
  */
18556 bpr 5396
          use_offset = 2;
5397
          break;
18552 bpr 5398
        case XYOFFSET:
5399
  /*
18556 bpr 5400
  @ xyoffset
5401
  @ keyword ; to place the text (x:y) to (x+dx:y+dy)... dx/dy are dependent on fontsize/fontfamily
5402
  @ may be used for points or other things requiring labels
5403
  @ use <a href="#fontfamily">fontfamily</a> for setting the font
5404
  @ only active for commands <a href="#text">text</a> and <a href="#string">string</a> (e.g. objects in the drag/drop/onclick-librariy
5405
  @ 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>
5406
  @%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 5407
  */
18556 bpr 5408
          use_offset = 3;
5409
          break;
18552 bpr 5410
        case XUNIT:
5411
  /*
18556 bpr 5412
  @ xunit some_unit_for_x-values
5413
  @ unicode allowed (no html code)
5414
  @ use together with command <a href="#display">display or mouse</a>
5415
  @ will display the cursor x-coordinate in ''unit``
5416
  @%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 5417
  */
18556 bpr 5418
          fprintf(js_include_file,"unit_x = \"%s\";",get_string(infile,1));
5419
          break;
18552 bpr 5420
        case XLABEL:
5421
  /*
5422
  @ xlabel some_string
5423
  @ will be used to create a label for the x-axis (label is in quadrant I)
5424
  @ can only be used together with command ''grid``<br>not depending on keywords ''axis`` and ''axisnumbering``
5425
  @ 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)
5426
  @ use <a href="#ylabel">ylabel</a>
5427
  @%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
5428
  */
18556 bpr 5429
          temp = get_string(infile,1);
5430
          fprintf(js_include_file,"var xaxislabel = \"%s\";",temp);
5431
          break;
18552 bpr 5432
        case XLOGBASE:
5433
  /*
5434
  @ xlogbase number
5435
  @ sets the logbase number for the x-axis
5436
  @ default value 10
5437
  @ use together with commands xlogscale / xylogscale
5438
  */
18556 bpr 5439
          fprintf(js_include_file,"xlogbase=%d;",(int)(get_real(infile,1)));
5440
          break;
18552 bpr 5441
        case XLOGSCALE:
5442
  /*
18556 bpr 5443
  @ xlogscale ymajor,yminor,majorcolor,minorcolor
5444
  @ the x/y-range are set using commands <code>xrange xmin,xmax</code> and <code>yrange ymin,ymax</code>
5445
  @ ymajor is the major step on the y-axis; yminor is the divisor for the y-step
5446
  @ the linewidth is set using command ''linewidth int``
5447
  @ the opacity of major / minor grid lines is set by command <a href='#opacity'>opacity</a>
5448
  @ default logbase number = 10 ... when needed, set the logbase number with command ''xlogbase number``
18627 bpr 5449
  @ 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 5450
  @ note: the complete canvas will be used for the ''log paper``
5451
  @ note: userdrawings are done in the log paper, e.g. javascript:read_canvas() will return the real values
5452
  @ note: command ''mouse color,fontsize`` will show the real values in the logpaper.<br>\
5453
  @ 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
5454
  @ note: in case of userdraw, the use of keyword <a href='#userinput_xy'>userinput_xy</a> may be handy !
5455
  @ <b>attention</b>: keyword ''snaptogrid`` may not lead to the desired result...
5456
  @ <b>attention</b>: do not use command ''zoom``
5457
  @%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 5458
  */
18556 bpr 5459
          use_axis_numbering++;if(use_axis_numbering > 1){use_axis_numbering = 1;}
5460
          if( js_function[DRAW_GRID] == 1 ){canvas_error("only one type of grid is allowed...");}
5461
          js_function[DRAW_XLOGSCALE] = 1;
5462
          for(i=0;i<4;i++){
5463
            switch(i){
5464
              case 0: double_data[0] = get_real(infile,0);break; /* xmajor */
5465
              case 1: int_data[0] = (int) (get_real(infile,0));break; /* xminor */
5466
              case 2: stroke_color = get_color(infile,0); break;
5467
              case 3: fill_color = get_color(infile,1);
18557 bpr 5468
                tmp_buffer=my_newmem(MAX_BUFFER);
5469
                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 5470
                fprintf(js_include_file,"use_xlogscale=1;snap_y = %f;snap_x = xlogbase;",double_data[0]/int_data[0]);
5471
                add_to_buffer(tmp_buffer);
5472
                break;
5473
              default:break;
5474
            }
5475
          }
5476
          break;
18552 bpr 5477
        case XYLOGSCALE:
5478
  /*
18556 bpr 5479
  @ xylogscale majorcolor,minorcolor
5480
  @ the x/y-range are set using commands ''xrange xmin,xmax`` and ''yrange ymin,ymax``
5481
  @ the linewidth is set using command ''linewidth int``
5482
  @ the opacity of major / minor grid lines is set by command ''opacity [0-255],[0-255]``
5483
  @ default logbase number = 10 ... when needed, set the logbase number with command ''xlogbase number`` and/or ''ylogbase number``
18627 bpr 5484
  @ 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 5485
  @ note: the complete canvas will be used for the ''log paper``
5486
  @ note: userdrawings are done in the log paper, e.g. javascript:read_canvas() will return the real values
5487
  @ note: command ''mouse color,fontsize`` will show the real values in the logpaper.<br>\
5488
  @ 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``)
5489
  @ note: in case of userdraw, the use of keyword ''userinput_xy`` may be handy !
5490
  @ <b>attention</b>: keyword ''snaptogrid`` may not lead to the desired result...
5491
  @ <b>attention</b>: do not use command ''zoom``
5492
  @%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 5493
  */
18556 bpr 5494
          use_axis_numbering++;if(use_axis_numbering > 1){use_axis_numbering = 1;}
5495
          if( js_function[DRAW_GRID] == 1 ){canvas_error("only one type of grid is allowed...");}
5496
          js_function[DRAW_XYLOGSCALE] = 1;
5497
          for(i=0;i<2;i++){
5498
            switch(i){
5499
              case 0: stroke_color = get_color(infile,0); break;
5500
              case 1: fill_color = get_color(infile,1);
18557 bpr 5501
                tmp_buffer=my_newmem(MAX_BUFFER);
5502
                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 5503
                fprintf(js_include_file,"use_xlogscale=1;use_ylogscale=1;snap_x = xlogbase;snap_y = ylogbase;");
5504
                add_to_buffer(tmp_buffer);
5505
                break;
5506
              default:break;
5507
            }
5508
          }
5509
          break;
18552 bpr 5510
        case Y_AXIS_STRINGS:
5511
  /*
18556 bpr 5512
  @ yaxis num1:string1:num2:string2:num3:string3:num4:string4:....num_n:string_n
5513
  @ alternative: yaxistext
5514
  @ 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>)
5515
  @ no need to use keyword <a href="#axisnumbering">axisnumbering</a>
5516
  @ use command <a href="#axis">axis</a> to have visual x/y-axis lines (see command <a href="#grid">grid</a>
5517
  @ use these y-axis num1...num_n values instead of default ymin...ymax
5518
  @ a javascript error message will flag non-matching value:name pairs
5519
  @ to be used before command grid (see <a href="#grid">command grid</a>)
5520
  @%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 5521
  */
18556 bpr 5522
          temp = get_string(infile,1);
5523
          if( strstr(temp,":") != 0 ){ temp = str_replace(temp,":","\",\"");}
5524
          if( strstr(temp,"pi") != 0 ){ temp = str_replace(temp,"pi","(3.1415927)");}/* we need to replace pi for javascript y-value*/
5525
          fprintf(js_include_file,"y_strings = [\"%s\"];\n ",temp);
5526
          use_axis_numbering++;
5527
          break;
18552 bpr 5528
        case YERRORBARS:
5529
  /*
5530
  @ yerrorbars color,E1,E2,x1,y1,x2,y2,...,x_n,y_n
5531
  @ draw multiple points with y-errorbars E1 (error value under point) and E2 (error value above point) at given coordinates in color 'color'
5532
  @ the errors E1 and E2 values are in yrange.
5533
  @ use command ''linewidth int`` to adust size
5534
  @ may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
5535
  @%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
5536
  */
5537
      stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5538
      fill_color = stroke_color;
5539
      i=0;
5540
      while( ! done ){     /* get next item until EOL*/
18556 bpr 5541
        if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5542
        if(i%2 == 0 ){
5543
            double_data[i] = get_real(infile,0); /* x */
5544
        }
5545
        else
5546
        {
5547
            double_data[i] = get_real(infile,1); /* y */
5548
        }
5549
        i++;
18552 bpr 5550
      }
5551
      if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5552
      for(c = 2 ; c < i-1 ; c = c+2){
18557 bpr 5553
        tmp_buffer=my_newmem(MAX_BUFFER);
5554
        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 5555
        add_to_buffer(tmp_buffer);
18552 bpr 5556
    /* object_cnt++; */
18556 bpr 5557
        if(onclick != 0){object_cnt++;}
18552 bpr 5558
      }
5559
      decimals = find_number_of_digits(precision);
5560
      reset();
5561
      dragstuff[19] = 1;
5562
      if(use_dragstuff == 0 ){ use_dragstuff = 1;}
5563
      break;
5564
        case YOFFSET:
5565
  /*
18556 bpr 5566
  @ yoffset
5567
  @ keyword; to place the text centered above the text coordinates(x:y) ...
5568
  @ may be used for points or other things requiring centered labels
5569
  @ use <a href="#fontfamily">fontfamily</a> for setting the font
5570
  @ 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)
5571
  @%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 5572
  */
18556 bpr 5573
          use_offset = 1;
5574
          break;
18552 bpr 5575
        case YRANGE:
5576
  /*
5577
  @ yrange ymin,ymax
5578
  @ alternative: rangey
5579
  @ if not given 0,ysize (eg in pixels)
5580
  */
18556 bpr 5581
          for(i = 0 ; i<2; i++){
5582
            switch(i){
5583
              case 0: ymin = get_real(infile,0);break;
5584
              case 1: ymax = get_real(infile,1);break;
5585
              default: break;
5586
            }
5587
          }
5588
          if(ymin >= ymax){canvas_error(" yrange is not OK: ymin &lt; ymax !<br>");}
5589
          fprintf(js_include_file,"var ymin = %f;var ymax = %f;",ymin,ymax);
5590
          found_size_command++;
5591
          break;
18552 bpr 5592
        case YSNAPTOGRID:
5593
  /*
18556 bpr 5594
  @ ysnaptogrid
5595
  @ keyword (no arguments required)
5596
  @ a draggable object (use command ''drag x|y|xy``) will snap to the given y-grid values when dragged (mouseup)
5597
  @ in case of userdraw the drawn points will snap to ymajor grid
5598
  @ if no grid is defined, points will snap to every integer yrange value. (eg snap_y=1)
5599
  @ if you do not want a visible grid, but you only want a ''snaptogrid`` with some value...define this grid with opacity 0.
5600
  @ 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>
5601
  @%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
5602
  @%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 5603
  */
18556 bpr 5604
          use_snap = 3;
5605
          break;
18552 bpr 5606
        case YLABEL:
5607
  /*
5608
  @ ylabel some_string
5609
  @ will be used to create a (vertical) label for the y-axis (label is in quadrant I)
5610
  @ can only be used together with command <a href="#grid">grid</a><br>not depending on keywords ''axis`` and ''axisnumbering``
5611
  @ 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)
5612
  @ use <a href="#xlabel">xlabel</a>
5613
  @%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
5614
  */
18556 bpr 5615
          temp = get_string(infile,1);
5616
          fprintf(js_include_file,"var yaxislabel = \"%s\";",temp);
5617
          break;
18552 bpr 5618
        case YLOGBASE:
5619
  /*
5620
  @ ylogbase number
5621
  @ sets the logbase number for the y-axis
5622
  @ default value 10
5623
  @ use together with commands ylogscale / xylogscale
5624
  */
5625
          fprintf(js_include_file,"ylogbase=%d;",(int)(get_real(infile,1)));
5626
          break;
5627
        case YLOGSCALE:
5628
  /*
18556 bpr 5629
  @ ylogscale xmajor,xminor,majorcolor,minorcolor
5630
  @ the x/y-range are set using commands ''xrange xmin,xmax`` and ''yrange ymin,ymax``
5631
  @ xmajor is the major step on the x-axis; xminor is the divisor for the x-step
5632
  @ the linewidth is set using command ''linewidth int``
5633
  @ the opacity of major / minor grid lines is set by command ''opacity [0-255],[0-255]``
5634
  @ default logbase number = 10 ... when needed, set the logbase number with command ''ylogbase number``
5635
  @ 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>
5636
  @ note: the complete canvas will be used for the ''log paper``
5637
  @ note: userdrawings are done in the log paper, e.g. javascript:read_canvas() will return the real values
5638
  @ note: command ''mouse color,fontsize`` will show the real values in the logpaper.<br>\
5639
  @ 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``)
5640
  @ note: in case of userdraw, the use of keyword ''userinput_xy`` may be handy !
5641
  @ <b>attention</b>: do not use command ''zoom``
5642
  @ <b>attention</b>: keyword ''snaptogrid`` may not lead to the desired result...
18552 bpr 5643
  */
18555 bpr 5644
        use_axis_numbering++;if(use_axis_numbering > 1){use_axis_numbering = 1;}
5645
        if( js_function[DRAW_GRID] == 1 ){canvas_error("only one type of grid is allowed...");}
5646
        js_function[DRAW_YLOGSCALE] = 1;
5647
        for(i=0;i<4;i++){
5648
          switch(i){
5649
            case 0: double_data[0] = get_real(infile,0);break; /* xmajor */
5650
            case 1: int_data[0] = (int) (get_real(infile,0));break; /* xminor */
5651
            case 2: stroke_color = get_color(infile,0); break;
5652
            case 3: fill_color = get_color(infile,1);
18557 bpr 5653
              tmp_buffer=my_newmem(MAX_BUFFER);
5654
              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 5655
              fprintf(js_include_file,"use_ylogscale=1;snap_x = %f;snap_y = ylogbase;",double_data[0]/int_data[0]);
5656
              add_to_buffer(tmp_buffer);
5657
               break;
5658
            default:break;
5659
            }
5660
          }
5661
          break;
18552 bpr 5662
        case YUNIT:
5663
  /*
18556 bpr 5664
  @ yunit some_unit_for_y-values
5665
  @ unicode allowed (no html code)
5666
  @ use together with command mousey
5667
  @ will display the cursor y-coordinate in ''unit``
18552 bpr 5668
  */
5669
          fprintf(js_include_file,"unit_y = \"%s\";",get_string(infile,1));
5670
          break;
18555 bpr 5671
        case HYPSEGMENTS:
18556 bpr 5672
  /*
5673
  @ hypsegments color,x1,y1,x2,y2,...,x_n,y_n
5674
  @ 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``
18639 schaersvoo 5675
  @ use command ''linewidth int`` to adjust size may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a> individually (!)
18556 bpr 5676
  @%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
18639 schaersvoo 5677
  */
18555 bpr 5678
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5679
          fill_color = stroke_color;
5680
          i=0;
5681
          while( ! done ){     /* get next item until EOL*/
5682
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5683
              if(i%2 == 0 ){
5684
                double_data[i] = get_real(infile,0); /* x */
5685
              }
5686
            else {
5687
              double_data[i] = get_real(infile,1); /* y */
5688
            }
5689
            i++;
5690
          }
5691
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
5692
          if(use_affine == TRUE ){ transform(i-1,2);}
5693
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5694
          decimals = find_number_of_digits(precision);
5695
          for(c = 0 ; c < i-1 ; c = c+4){
18569 bpr 5696
            tmp_buffer=my_newmem(MAX_BUFFER);
18555 bpr 5697
            if (hypgeodaux(double_data+c,res,0)){
5698
              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));
5699
            }
5700
            else {
5701
              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));
5702
            }
5703
            add_to_buffer(tmp_buffer);
5704
            if(onclick != 0){object_cnt++;}
5705
          }
5706
          reset();
5707
          dragstuff[4] = 1;dragstuff[12] = 1;
5708
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5709
          break;
5710
        case HYPLINES:
18639 schaersvoo 5711
  /*
18555 bpr 5712
  @ hyplines color,x1,y1,x2,y2...x_n-1,y_n-1,x_n,y_n
18639 schaersvoo 5713
  @ 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' may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
18555 bpr 5714
  @%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
5715
  */
5716
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
5717
          fill_color = stroke_color;
5718
          i=0;
5719
          while( ! done ){     /* get next item until EOL*/
5720
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
18562 bpr 5721
            if(i%2 == 0 ){
5722
              double_data[i] = get_real(infile,0); /* x */
5723
            }
18555 bpr 5724
            else {
5725
              double_data[i] = get_real(infile,1); /* y */
5726
            }
5727
            i++;
5728
          }
5729
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
5730
          if(use_affine == TRUE ){ transform(i-1,2);}
5731
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
18623 bpr 5732
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18555 bpr 5733
          decimals = find_number_of_digits(precision);
5734
          for(c = 0 ; c < i-1 ; c = c+4){
18569 bpr 5735
            tmp_buffer=my_newmem(MAX_BUFFER);
18555 bpr 5736
            if (hypgeodaux(double_data+c,res,1)){
5737
              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));}
5738
            else {
18623 bpr 5739
              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 5740
            }
5741
            add_to_buffer(tmp_buffer);
5742
            if(onclick != 0){object_cnt++;}
5743
          }
5744
          reset();
5745
          dragstuff[4] = 1;dragstuff[12] = 1;
5746
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5747
          break;
5748
        case HYPPOLY:
18639 schaersvoo 5749
    /*
5750
    @ hyppolygon color,x1,y1,x2,y2...x_n-1,y_n-1,x_n,y_n
5751
    @ 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' may be set <a href="#drag">draggable</a> / <a href="#onclick">onclick</a>
18615 bpr 5752
    @ option fhyppolygon only for convex polygon for the moment
5753
    @%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
18639 schaersvoo 5754
    */
18615 bpr 5755
          stroke_color=get_color(infile,0);
18555 bpr 5756
          fill_color = stroke_color;
5757
          i=0;
5758
          while( ! done ){     /* get next item until EOL*/
5759
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5760
            if(i%2 == 0 ){
5761
              double_data[i] = get_real(infile,0); /* x */
5762
            }
5763
            else {
5764
              double_data[i] = get_real(infile,1); /* y */
5765
            }
5766
            i++;
5767
          }
5768
          /* il faut rajouter le premier point à la fin*/
5769
          double_data[i]=double_data[0]; double_data[i+1]=double_data[1];
5770
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
5771
          if(use_affine == TRUE ){ transform(i-1,2);}
5772
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5773
          decimals = find_number_of_digits(precision);
5774
          for(c = 0 ; c < i-1 ; c = c+2){
18615 bpr 5775
            tmp_buffer=my_newmem(MAX_BUFFER);
18555 bpr 5776
            if (hypgeodaux(double_data+c,res,0)){
18615 bpr 5777
              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 5778
            }
5779
            else {
18623 bpr 5780
              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 5781
            }
5782
            add_to_buffer(tmp_buffer);
5783
            if(onclick != 0){object_cnt++;}
18615 bpr 5784
          }
5785
          if(use_filled){
5786
            hypgeodaux(double_data+2,res,0);
5787
            res[4]=double_data[0]; res[5]=double_data[1];
5788
            hypgeodaux(res+4,res,0);
5789
            add_js_filltoborder(canvas_type);
5790
            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));
5791
            add_to_buffer(tmp_buffer);
5792
                fill_cnt++;
18606 bpr 5793
                }
18569 bpr 5794
          dragstuff[4] = 1; dragstuff[12] = 1;
18555 bpr 5795
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5796
          reset();
5797
          break;
5798
        case HYPRAYS:
5799
  /*
18556 bpr 5800
  @ hyprays color,xc,yc,x1,y1,x2,y2,x3,y3...x_n,y_n
18639 schaersvoo 5801
  @ draw hyperbolic rays in the Poincaré disk in color 'color' and center (xc:yc) may be set draggable or onclick (every individual ray)
18556 bpr 5802
  @%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
18639 schaersvoo 5803
  */
5804
  /*
18555 bpr 5805
   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
5806
   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
5807
  */
5808
          stroke_color=get_color(infile,0);
18623 bpr 5809
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18555 bpr 5810
          double_data[0] = get_real(infile,0);/* xc */
5811
          double_data[1] = get_real(infile,0);/* yc */
5812
          i=2;
18562 bpr 5813
          while( ! done ){ /* get next item until EOL*/
18555 bpr 5814
            if(i > MAX_INT - 1){canvas_error("in command rays too many points / rays in argument: repeat command multiple times to fit");}
5815
            if(i%2 == 0 ){
5816
              double_data[i] = get_real(infile,0); /* x */
5817
            }
5818
            else {
5819
              double_data[i] = get_real(infile,1); /* y */
5820
            }
5821
            fprintf(js_include_file,"/* double_data[%d] = %f */\n",i,double_data[i]);
5822
            i++;
5823
          }
5824
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,2);}
5825
          if(use_affine == TRUE ){ transform(i-1,2);}
5826
          if( i%2 != 0 ){canvas_error("in command rays: unpaired x or y value");}
5827
          decimals = find_number_of_digits(precision);
5828
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5829
          for(c=2; c<i;c = c+2){
18557 bpr 5830
            tmp_buffer=my_newmem(MAX_BUFFER);
18555 bpr 5831
            double_data[2]=double_data[c];double_data[3]=double_data[c+1];
5832
            if (hypgeodaux(double_data,res,0)){
5833
              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));
5834
            }
5835
            else {
18623 bpr 5836
              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 5837
            }
5838
            add_to_buffer(tmp_buffer);
5839
            /* object_cnt++; */
5840
            if(onclick != 0){object_cnt++;}
5841
          }
5842
          reset();
5843
          dragstuff[4] = 1; dragstuff[12] = 1;
5844
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5845
          break;
5846
        case HYPCIRCLES:
5847
        /*
5848
  @ hypcircles color,xc1,yc1,r1,xc2,yc2,r2...xc_n,yc_n,r_n
5849
  @ draw hyperbolic circles in Poincaré disk
5850
  @ <b>attention</b> r = radius in x-range (!)
5851
  @ use keyword <code>filled</code> or command <code>fhypcircles</code> to produce solid circles
5852
  @ use command <code>fillcolor color</code> to set the fillcolor
5853
  @%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
18639 schaersvoo 5854
  */
5855
  /*
18555 bpr 5856
  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
5857
  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
5858
  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
5859
  */
5860
          stroke_color=get_color(infile,0); /* how nice: now the color comes first...*/
18623 bpr 5861
          if(fillcolor) {fill_color=fillcolor;} else {fill_color=stroke_color;}
18555 bpr 5862
          i=1;
18562 bpr 5863
          while( ! done ){ /* get next item until EOL*/
18555 bpr 5864
            if(i > MAX_INT - 1){canvas_error("too many points in argument: repeat command multiple times to fit");}
5865
              switch (i%3){
5866
                case 1:double_data[i-1] = get_real(infile,0);break; /* x */
5867
                case 2:double_data[i-1] = get_real(infile,0);break; /* y */
5868
                case 0:double_data[i-1] = get_real(infile,1);break; /* r */
5869
              }
5870
            i++;
5871
          }
5872
          if(use_rotate == TRUE ){rotate(i-1,angle,rotationcenter,3);}
5873
          if(use_affine == TRUE ){ transform(i-1,3);}
5874
          if( use_slider != -1 && onclick == 0){ onclick = 3; }/* no drag&onclick but slideable */
5875
          decimals = find_number_of_digits(precision);
5876
          for(c = 0 ; c < i-1 ; c = c+3){
18556 bpr 5877
            double Z2=double_data[c]*double_data[c]+double_data[c+1]*double_data[c+1];//[Z]^2
18555 bpr 5878
            double R=tanh(double_data[c+2]/2);double R2=R*R;
5879
            double den=1-R2*Z2; double XY=(1-R2)/den;
5880
            double_data[c]=XY*double_data[c];
5881
            double_data[c+1]=XY*double_data[c+1];
5882
            double_data[c+2]=(1-Z2)/den*R;
18557 bpr 5883
            tmp_buffer=my_newmem(MAX_BUFFER);
18623 bpr 5884
            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 5885
            add_to_buffer(tmp_buffer);
5886
            if(onclick != 0){object_cnt++;}/* object_cnt++; */
5887
          }
5888
          reset();
5889
          dragstuff[13] = 1;
5890
          if(use_dragstuff == 0 ){ use_dragstuff = 1; }
5891
          break;
18552 bpr 5892
        case ZOOM:
5893
  /*
18556 bpr 5894
  @ zoom button_color
5895
  @ introduce a very small ''controlpanel`` at the lower right corner (font size of the panel is fixed to: 22px Arial)
5896
  @ giving six 15&times;15px ''active`` rectangle areas<br>(''&times;,&darr;,&uarr;,&larr;,&rarr;,&minus;,+``) for zooming and/or panning of the image
5897
  @ a mouse wheel is active for in/out zooming. Drag panning is not supported (this will conflict with many ''userdraw`` or ''multidraw`` primitives)
5898
  @ the ''controlpanel`` is not active for a ''userdraw`` mousedown (but it can interfere with some ''userdraw`` types)
5899
  @ the ''&times;`` symbol will reset to your original xmax/xmin ymax/ymin values.
5900
  @ choose an appropriate color, so the small ''&times;,&darr;,&uarr;,&larr;,&rarr;,&minus;,+`` are clearly visible
5901
  @ command ''opacity`` may be used to set stroke_opacity of buttons
5902
  @ note: on zooming, text will not increase / decrease the font size (todo??)
5903
  @ note: adding ''zooming`` will increase the size of the javascript include with approx. 11 kb
18552 bpr 5904
  */
18556 bpr 5905
         js_function[INTERACTIVE] = 1;
18552 bpr 5906
          js_function[JS_ZOOM] = 1;
5907
          if( use_userdraw == 1 ){
5908
            js_function[USERDRAW_AND_ZOOM] = 1;
5909
            fprintf(js_include_file,"forbidden_zone = [%d,%d];",xsize-115,ysize - 20);
5910
          }
5911
          if(jsplot_cnt != -1){ js_function[JSPLOT_AND_ZOOM] = 1;}
5912
          stroke_color = get_color(infile,1);
5913
          /* we use BG_CANVAS (0) */
5914
          add_js_zoom_buttons(stroke_color,stroke_opacity);
5915
          done = TRUE;
5916
          break;
11806 schaersvoo 5917
 
5918
/* ready */
18552 bpr 5919
        default:sync_input(infile);
5920
        break;
5921
      }
7614 schaersvoo 5922
    }
5923
  /* we are done parsing script file */
18556 bpr 5924
    if(use_dragstuff != 0){
18562 bpr 5925
  /* add the 20kb drag code: nearly always used ... use_dragstuff==1: no-mouse ! */
18556 bpr 5926
      add_drag_code(DRAG_CANVAS,use_dragstuff,dragstuff,reply_format);
5927
      if(js_function[JS_ZOOM] == 1){
15111 schaersvoo 5928
        js_function[DRAG_AND_ZOOM] = 1;
18556 bpr 5929
      }
15111 schaersvoo 5930
  }
15116 bpr 5931
 
14066 bpr 5932
  /* check if xrange / yrange was set explicit ... or use xmin=0 xmax=xsize ymin=0 ymax=ysize: Quadrant I */
18556 bpr 5933
    if( found_size_command == 1 ){
5934
      fprintf(js_include_file,"var xmin = 0;var xmax = %d;var ymin = 0;var ymax = %d",xsize,ysize);
7983 schaersvoo 5935
    }
18556 bpr 5936
    else
5937
    {
5938
      if( found_size_command != 3 ){
5939
        canvas_error("Please specify size first and then both xrange and yrange ...");
5940
      }
5941
    }
8257 schaersvoo 5942
 
18562 bpr 5943
  /* if needed, add generic draw functions (grid / xml etc) to buffer: these are no draggable/clickable shapes / objects ! */
18556 bpr 5944
    add_javascript_function();
7614 schaersvoo 5945
   /* add read_canvas() etc functions if needed */
18556 bpr 5946
    if( reply_format > 0 ){ add_read_canvas(reply_format,reply_precision);}
7797 schaersvoo 5947
  /* no zoom, just add buffer */
18556 bpr 5948
    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 5949
/* done writing the javascript include file */
18556 bpr 5950
    fclose(js_include_file);
5951
    }
7614 schaersvoo 5952
 
5953
/* if using a tooltip, this should always be printed to the *.phtml file, so stdout */
18556 bpr 5954
    if( use_tooltip > 0 ){
5955
      if( use_tooltip == 1 ){
5956
        add_js_tooltip(tooltip_text,bgcolor);
5957
      }
5958
      else
5959
      {
5960
      if( use_tooltip == 2 ){
5961
        add_js_popup(getfile_cmd);
5962
      }
5963
    }
9329 schaersvoo 5964
  }
18556 bpr 5965
  exit(EXIT_SUCCESS);
7614 schaersvoo 5966
}
5967
/* end main() */
5968
 
5969
/******************************************************************************
5970
**
5971
**  sync_input
5972
**
5973
**  synchronises input line - reads to end of line, leaving file pointer
5974
**  at first character of next line.
5975
**
5976
**  Used by:
5977
**  main program - error handling.
5978
**
5979
******************************************************************************/
5980
void sync_input(FILE *infile)
5981
{
18552 bpr 5982
  int c = 0;
7614 schaersvoo 5983
 
18552 bpr 5984
  if( c == '\n' || c == ';' ) return;
5985
  while( ( (c=getc(infile)) != EOF ) && (c != '\n') && (c != '\r') && (c != ';')) ;
5986
  if( c == EOF ) finished = 1;
5987
  if( c == '\n' || c == '\r' || c == ';') line_number++;
5988
  return;
7614 schaersvoo 5989
}
5990
 
5991
/******************************************************************************/
15111 schaersvoo 5992
void transform(int num,int incr){
5993
/*.
5994
only "double_data[]" is used for transformations !!
5995
*/
5996
 int i;int ii;double x,y;
5997
 for(i=0;i<num;i = i+incr){
5998
  ii = i+1;
5999
  x = double_data[i]*affine_matrix[0] + double_data[ii]*affine_matrix[1]+affine_matrix[4];
6000
  y = double_data[i]*affine_matrix[2] + double_data[ii]*affine_matrix[3]+affine_matrix[5];
15601 schaersvoo 6001
 /*
17351 bpr 6002
  printf("(%f:%f) &rarr; (%f:%f)<br>",double_data[i],double_data[ii],x,y);
15601 schaersvoo 6003
 */
15111 schaersvoo 6004
  double_data[i] = x;
6005
  double_data[ii] = y;
6006
 }
6007
}
6008
 
6009
void rotate(int num,double angle,double center[],int incr){
6010
 int i;int ii;double rad = angle * 0.0174532925199;
6011
 double c = cos(rad);
6012
 double s = sin(rad);
6013
 double x,y;
6014
 for(i=0;i<num;i = i+incr){
6015
  ii = i+1;
6016
  x = c*(double_data[i]-center[0]) + s*(double_data[ii] - center[1] ) + center[0];
6017
  y = c*(double_data[ii]-center[1]) - s*(double_data[i] - center[0] ) + center[1];
6018
  double_data[i] = x;
6019
  double_data[ii] = y;
17351 bpr 6020
 // printf("(x:y) - (%f:%f)<br>",x,y);
15111 schaersvoo 6021
 }
6022
}
6023
/* not used: see transform()
6024
void translate(int num){
6025
 int i;int ii;
6026
 double x,y;
6027
 for(i=0;i<num;i = i+2){
6028
  ii = i+1;
6029
  x = double_data[i] + affine_matrix[4];
6030
  y = double_data[ii] + affine_matrix[5];
6031
  double_data[i] = x;
6032
  double_data[ii] = y;
6033
 }
6034
}
6035
*/
7614 schaersvoo 6036
char *str_replace(const char *str, const char *old, const char *new){
18562 bpr 6037
  if(strlen(str) > MAX_BUFFER){canvas_error("string argument too big");}
6038
  char *ret, *r;
6039
  const char *p, *q;
6040
  size_t oldlen = strlen(old);
6041
  size_t count = 0;
6042
  size_t retlen = 0;
6043
  size_t newlen = strlen(new);
6044
  if (oldlen != newlen){
6045
    for (count = 0, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen){
18552 bpr 6046
      count++;
6047
      retlen = p - str + strlen(p) + count * (newlen - oldlen);
18562 bpr 6048
    }
18552 bpr 6049
  }
18562 bpr 6050
  else {
6051
    retlen = strlen(str);
6052
  }
6053
  if ((ret = malloc(retlen + 1)) == NULL){
6054
    ret = NULL;
6055
    canvas_error("string argument is NULL");
6056
  }
6057
  else
6058
  {
6059
    for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
18552 bpr 6060
      size_t l = q - p;
6061
      memcpy(r, p, l);
6062
      r += l;
6063
      memcpy(r, new, newlen);
6064
      r += newlen;
18562 bpr 6065
    }
6066
    strcpy(r, p);
18552 bpr 6067
  }
18562 bpr 6068
  return ret;
7614 schaersvoo 6069
}
6070
 
6071
/******************************************************************************/
7848 bpr 6072
 
7614 schaersvoo 6073
char *get_color(FILE *infile , int last){
18562 bpr 6074
  int c,i = 0,is_hex = 0;
6075
  char temp[MAX_COLOR_STRING], *string;
6076
  const char *not_allowed = "0123456789";
6077
  while(( (c=getc(infile)) != EOF ) && ( c != '\n') && ( c != ',' ) && ( c != ';' )  && ( c != '\t' ) ){
6078
    if( i > MAX_COLOR_STRING ){ canvas_error("colour string is too big ... ? ");}
6079
    if( c == '#' ){
18552 bpr 6080
      is_hex = 1;
18562 bpr 6081
    }
6082
    if( c != ' '){
18552 bpr 6083
      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 !!! ");}}
6084
      temp[i]=tolower(c);
6085
      i++;
18562 bpr 6086
    }
18552 bpr 6087
  }
18562 bpr 6088
  if( ( c == '\n' || c == EOF || c == ';' || c == '\t' ) && last == 0){canvas_error("expecting more arguments in command");}
6089
  if( c == '\n' || c == ';'  || c == '\t' ){ done = TRUE; line_number++; }
6090
  if( c == EOF ){finished = 1;}
6091
  if( finished == 1 && last != 1 ){ canvas_error("expected more arguments");}
6092
  temp[i]='\0';
6093
  if( strlen(temp) == 0 ){ canvas_error("expected a colorname or hexnumber, but found nothing !!");}
6094
  if( is_hex == 1 ){
6095
    char red[3], green[3], blue[3];
6096
    red[0]   = toupper(temp[1]); red[1]   = toupper(temp[2]); red[2]   = '\0';
6097
    green[0] = toupper(temp[3]); green[1] = toupper(temp[4]); green[2] = '\0';
6098
    blue[0]  = toupper(temp[5]); blue[1]  = toupper(temp[6]); blue[2]  = '\0';
6099
    int r = (int) strtol(red,   NULL, 16);
6100
    int g = (int) strtol(green, NULL, 16);
6101
    int b = (int) strtol(blue,  NULL, 16);
6102
    int L0 = 1+snprintf(NULL,0,"%d,%d,%d",r,g,b);
6103
    string = my_newmem(L0);
6104
    snprintf(string,L0,"%d,%d,%d",r,g,b);
6105
    return string;
6106
  }
6107
  else
6108
  {
6109
    string = (char *)my_newmem(sizeof(temp));
6110
    snprintf(string,sizeof(temp),"%s",temp);
6111
    for( i = 0; i < NUMBER_OF_COLORNAMES ; i++ ){
18552 bpr 6112
      if( strcmp( colors[i].name , string ) == 0 ){
18562 bpr 6113
        return colors[i].rgb;
18552 bpr 6114
      }
18562 bpr 6115
    }
6116
    canvas_error("I was expecting a color name or hexnumber...but found nothing.");
18552 bpr 6117
  }
18562 bpr 6118
  return "0,0,255";
7614 schaersvoo 6119
}
6120
 
14066 bpr 6121
char *get_string(FILE *infile,int last){ /* last = 0: more arguments ; last=1 final argument */
18562 bpr 6122
  int c,i=0;
6123
  char  temp[MAX_BUFFER], *string;
6124
  while(( (c=getc(infile)) != EOF ) && ( c != '\n') && ( c != '\t') ){
6125
    temp[i]=c;
6126
    i++;
6127
    if(i > MAX_BUFFER){ canvas_error("string size too big...repeat command to fit string");break;}
6128
  }
6129
  if( ( c == '\n' ||  c == '\t'  || c == EOF ) && last == 0){
6130
    canvas_error("expecting more arguments in command");}
6131
  if( c == '\n' ||  c == '\t') { done = TRUE; line_number++; }
6132
  if( c == EOF ) {finished = 1;}
6133
  temp[i]='\0';
6134
  if( strlen(temp) == 0 && last != 3 ){
6135
    canvas_error("expected a word or string, but found nothing!");}
6136
  string=(char *)my_newmem(strlen(temp));
6137
  snprintf(string,sizeof(temp),"%s",temp);
6138
  return string;
7614 schaersvoo 6139
}
6140
 
14066 bpr 6141
char *get_string_argument(FILE *infile,int last){  /* last = 0: more arguments ; last=1 final argument */
18562 bpr 6142
  int c,i=0;
6143
  char temp[MAX_BUFFER], *string;
6144
  while(( (c=getc(infile)) != EOF ) && ( c != '\n') && ( c != '\t') && ( c != ',')){
6145
    temp[i]=c;
6146
    i++;
6147
    if(i > MAX_BUFFER){ canvas_error("string size too big...will cut it off");break;}
6148
  }
6149
  if( ( c == '\n' || c == EOF) && last == 0){canvas_error("expecting more arguments in command");}
6150
  if( c == '\n' || c == '\t' ) { line_number++; }
6151
  if( c == EOF ) {finished = 1;}
6152
  if( finished == 1 && last == 0 ){ canvas_error("expected more arguments");}
6153
  temp[i]='\0';
10953 bpr 6154
/*
18562 bpr 6155
  17.10.2014 removed (question Perrin)
6156
  may cause some unwanted effects...
6157
  if( strlen(temp) == 0 ){ canvas_error("expected a word or string (without comma), but found nothing !!");}
8322 schaersvoo 6158
*/
18562 bpr 6159
  string=(char *)my_newmem(sizeof(temp));
6160
  snprintf(string,sizeof(temp),"%s",temp);
6161
  done = TRUE;
6162
  return string;
7614 schaersvoo 6163
}
6164
 
14066 bpr 6165
double get_real(FILE *infile, int last){ /* accept anything that looks like an number ?  last = 0: more arguments ; last=1 final argument */
18562 bpr 6166
  int c,i=0,found_calc = 0;
6167
  double y;
6168
  char tmp[MAX_INT];
6169
  /*
6170
   these things are 'allowed functions': *,^,+,-,/,(,),e,arc,cos,tan,pi,log,ln,sqrt,abs
6171
   but there should be a better way to avoid segfaults !
6172
  */
6173
  const char *allowed = "earcostanpilogqb*+-/^()";/* assuming these are allowed stuff in a 'number'*/
6174
  const char *not_allowed = "#dfhjkmuvwxyz{}[]%&~!$";/* avoid segmentation faults in a "atof()" and "wims eval" */
6175
  while(( (c=getc(infile)) != EOF ) && ( c != ',') && (c != '\n') && (c != '\t') && ( c != ';')){
6176
    if( c != ' ' ){
8224 bpr 6177
      if( i == 0 &&  c == '+' ){
18562 bpr 6178
        continue;
8224 bpr 6179
      }
7614 schaersvoo 6180
      else
6181
      {
18562 bpr 6182
        c = tolower(c);
6183
        if( strchr(not_allowed,c) != 0 ){canvas_error("found a character not associated with a number...");}
6184
        if( strchr(allowed,c) != 0 ){found_calc = 1;}/* hand the string over to wims eval() */
6185
        tmp[i] = c;
6186
        i++;
7614 schaersvoo 6187
      }
6188
    }
18562 bpr 6189
    if( i > MAX_INT - 1){canvas_error("number too large");}
6190
  }
6191
  if( ( c == '\n' || c == EOF || c == ';' || c == '\t' ) && last == 0){canvas_error("expecting more arguments in command");}
6192
  if( c == '\n' || c == ';' || c == '\t' ){ done = TRUE; line_number++; }
6193
  if( c == EOF ){done = TRUE ; finished = 1;}
6194
  tmp[i]='\0';
6195
  if( strlen(tmp) == 0 ){canvas_error("expected a number, but found nothing !!");}
6196
  if( found_calc == 1 ){ /* use wims eval to calculate 2*pi/3 */
6197
    void *f = eval_create(tmp);
6198
    assert(f);if( f == NULL ){canvas_error("I'm having trouble parsing your \"expression\" ") ;}
6199
    y = eval_x(f, 1);
6200
    /* if function is bogus; y = 1: so no core dumps */
6201
    eval_destroy(f);
6202
  }
6203
  else
6204
  {
6205
   y = atof(tmp);
6206
  }
6207
  return y;
7614 schaersvoo 6208
}
6209
void canvas_error(char *msg){
18562 bpr 6210
  fprintf(stdout,"\n</script><hr><span style=\"color:red\">FATAL syntax error: line %d: %s</span><hr>",line_number,msg);
6211
  finished = 1;
6212
  exit(EXIT_SUCCESS);
7614 schaersvoo 6213
}
6214
/* convert x/y coordinates to pixel */
6215
int x2px(double x){
18606 bpr 6216
  int res=(x-xmin)/(xmax-xmin)*xsize;
6217
  return (res==xsize)?xsize-1:res;
7614 schaersvoo 6218
}
6219
int y2px(double y){
18606 bpr 6220
  int res=(ymax-y)/(ymax-ymin)*ysize;
6221
  return (res==ysize)?ysize-1:res;
7614 schaersvoo 6222
}
6223
double px2x(int x){
18562 bpr 6224
  return (x*(xmax - xmin)/xsize + xmin);
7614 schaersvoo 6225
}
6226
double px2y(int y){
18562 bpr 6227
  return (y*(ymax - ymin)/ysize + ymin);
7614 schaersvoo 6228
}
6229
void add_to_buffer(char *tmp){
17351 bpr 6230
//fprintf(stdout,"tmp = %s<br>buffer = %s<br>",tmp,buffer);
18562 bpr 6231
  if( tmp == NULL || tmp == 0 ){ canvas_error("nothing to add_to_buffer()...");}
6232
  /*  do we have enough space left in buffer[MAX_BUFFER] ? */
6233
  int space_left = (int) (sizeof(buffer) - strlen(buffer));
6234
  if( space_left > strlen(tmp)){
6235
    strncat(buffer,tmp,space_left - 1);/* add safely "tmp" to the string buffer */
6236
  }
6237
  else
6238
  {
6239
    canvas_error("your memory buffer is too big<br>simplify your script...it produces too many lines ");
6240
  }
6241
  tmp = NULL;free(tmp);
6242
  return;
7614 schaersvoo 6243
}
6244
void reset(){
18562 bpr 6245
  if(no_reset == FALSE){ /* 8/5/2020 */
6246
    use_filled = FALSE;
6247
    use_dashed = FALSE;
6248
    if(onclick != 4 ){onclick = 0;} /* slider param 'active'... onclick=4 */
6249
    drag_type = -1;
6250
    use_offset = 0;
18623 bpr 6251
    fillcolor = FALSE;
18562 bpr 6252
  }
7614 schaersvoo 6253
}
15111 schaersvoo 6254
char *getMML(char *tex){
18562 bpr 6255
  int my_pipe[2];pid_t pid;
6256
  if(pipe(my_pipe)){canvas_error("mathml(): pipe() failure.\n");}
15111 schaersvoo 6257
  pid = fork();
6258
  if (pid == (pid_t) 0){
18562 bpr 6259
    char *argv[]={"wims_mathml","--use-zoom","0","--tex-size 100%","--max-mml-size","1024","--tex-string",tex,NULL};
6260
    close(my_pipe[0]);dup2(my_pipe[1], 1);dup2(my_pipe[1], 2);close(my_pipe[1]);
6261
    execv("../bin/wims_mathml",argv);canvas_error("could not execute wims_mathml\n");
15111 schaersvoo 6262
  }
6263
  else
15116 bpr 6264
  {
18562 bpr 6265
    if (pid < (pid_t) 0){
6266
      close(my_pipe[0]);close(my_pipe[1]);canvas_error("mathml(): fork() failure.\n");
6267
    }
6268
    int status;FILE *stream;close(my_pipe[1]);stream = fdopen (my_pipe[0], "r");
6269
    char buffer[MAX_BUFFER+1];memset(buffer,'\0',MAX_BUFFER);
6270
    fgets(buffer, MAX_BUFFER, stream);
6271
    int L0 = 1 + snprintf(NULL,0,"%s", buffer);
6272
    tex = my_newmem(L0);memset(tex,'\0',L0);
6273
    snprintf(tex,L0,"%s",buffer);
6274
    fclose (stream);close(my_pipe[0]);waitpid(pid, &status, 0);
15111 schaersvoo 6275
  }
18562 bpr 6276
  return tex;
15111 schaersvoo 6277
}
7614 schaersvoo 6278
 
15111 schaersvoo 6279
char *getSVGMOL(char *inputtype,char *keys){
6280
  int idx;
6281
  char *forbidden[] = {"-O","-H","-z","-L","-o","-m"};
6282
  char *argv[1+strlen(keys)];
6283
  argv[0] = "obabel"; argv[1] = "-i"; argv[2] = inputtype;
6284
  idx = 3;int i;
6285
  char *ptr = strtok(keys,",");
6286
  while(ptr != NULL ){
6287
    for(i = 0 ; i < 6; i++ ){if( strncmp(ptr,forbidden[i],2) == 0 ){return "NOT ALLOWED ARGUMENT";}}
6288
    argv[idx] = ptr; idx++;
17351 bpr 6289
    if(idx > 18){canvas_error("too many arguments for obabel....see docs<br>");}
15111 schaersvoo 6290
    ptr = strtok(NULL,",");
6291
  }
6292
  /* last arguments; no 'javascript', only 'svg to STDOUT' and 'NULL' */
6293
  argv[idx] = "-xj";argv[idx+1] = "-o"; argv[idx+2] = "svg";argv[idx+3] = NULL;
6294
  int link[2];
6295
  pid_t pid;
6296
  char buffer[MAX_BUFFER+1];
6297
  memset(buffer,'\0',MAX_BUFFER);
6298
  if (pipe(link)==-1){canvas_error("pipe");}
6299
  if ((pid = fork()) == -1){canvas_error("fork");}
15116 bpr 6300
 
15111 schaersvoo 6301
  char *svgmol = "error";
6302
  int string_length = 0;
15116 bpr 6303
 
15111 schaersvoo 6304
  if(pid == 0) {
6305
    dup2 (link[1], STDOUT_FILENO);
6306
    dup2(link[0],  STDERR_FILENO);/* remove annoying messages '1 molecule converted' */
6307
    close(link[0]);
6308
    close(link[1]);
6309
    execvp("obabel",argv);
6310
  } else {
6311
    close(link[1]);
18109 schaersvoo 6312
    read(link[0],buffer, sizeof(buffer));
15111 schaersvoo 6313
    close(link[0]);
6314
    /* need to remover newline from svg-string on freebsd */
6315
    char *pch = strstr(buffer, "\n");
6316
    while(pch != NULL){
18555 bpr 6317
      strncpy(pch, " ", 1);
6318
      pch = strstr(buffer, "\n");
15111 schaersvoo 6319
    }
6320
    string_length = 1 + snprintf(NULL,0,"%s",buffer);
6321
    svgmol= my_newmem(string_length);
6322
    snprintf(svgmol,string_length,"%s",buffer);
6323
    wait(NULL);
6324
  }
18562 bpr 6325
  return svgmol;
15111 schaersvoo 6326
}
6327
/* GNU libmatheval library for evaluating mathematical functions. */
15601 schaersvoo 6328
char *eval(int xsize,int ysize,char *fun,double xmin,double xmax,double ymin,double ymax,int plotsteps,int precision,double rotationcenter[]){
18555 bpr 6329
  void *f;
6330
  double x;
6331
  double y;
6332
  double xorg;
6333
  int xv;
6334
  int i = 0;
6335
  int xstep =(int)(xsize/plotsteps);
6336
  if( xstep == 0 ){xstep = 1;}
6337
  double a = (xmax - xmin)/xsize;
6338
  f = eval_create(fun);
6339
  assert (f);
6340
  if( f == NULL ){canvas_error("I'm having trouble parsing your \"expression\" ") ;}
6341
  /* we supply the true x/y values...draw_curve() will convert these (x:y) to pixels : used for pan/scale */
6342
  double xydata[MAX_BUFFER+1];/* hmmm */
6343
  int lim_ymin =(int)( ymin - 4*fabs(ymin));/* 19-4-2015 replacing "abs" by "fabs"*/
6344
  int lim_ymax =(int)( ymax + 4*fabs(ymax));/* 19-4-2015 replacing "abs" by "fabs"*/
6345
  double c = 1.0;double s = 1.0;
6346
  if( use_rotate == TRUE ){s = sin(angle*0.0174533);c = cos(angle*0.0174533);}
6347
  for ( xv = 0 ;xv < xsize ; xv = xv+xstep ){
18562 bpr 6348
    x = (double) (xv*a + xmin);
6349
    xorg = x;
6350
    if( i < MAX_BUFFER - 2){
18552 bpr 6351
      y = eval_x(f, x);
6352
      if(y < lim_ymax && y > lim_ymin ){
18562 bpr 6353
        if( use_affine == TRUE ){
6354
          x = x*affine_matrix[0] + y*affine_matrix[1]+affine_matrix[4];
6355
          y = xorg*affine_matrix[2] + y*affine_matrix[3]+affine_matrix[5];
6356
        }
6357
        if( use_rotate == TRUE){
6358
          x = (c * (x - rotationcenter[0])) + (s * (y - rotationcenter[1])) + rotationcenter[0];
6359
          y = (c * (y - rotationcenter[1])) - (s * (xorg - rotationcenter[0])) + rotationcenter[1];
6360
        }
6361
        xydata[i++] = x;
18552 bpr 6362
        xydata[i++] = y;
6363
      }
18562 bpr 6364
    }
6365
    else
6366
    {
18552 bpr 6367
      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 6368
    }
18552 bpr 6369
  }
18562 bpr 6370
  eval_destroy(f);
6371
  return double_xy2js_array(xydata,i,find_number_of_digits(precision));
15111 schaersvoo 6372
}
6373
/* plot a very primitive (!) levelcurve : not to be compared with "flydraw levelcurve" */
6374
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 6375
  void *f = eval_create(fun);
6376
  assert (f);
6377
  if( f == NULL ){canvas_error("I'm having trouble parsing your \"expression\" ") ;}
6378
  double a = (double)((xmax - xmin)/plotsteps);
6379
  double b = (double)((ymax - ymin)/plotsteps);
6380
  double x;double y;double diff;
6381
  double xydata[MAX_BUFFER+1];
6382
  int i = 0;
6383
  ymin = ymin - 1;
6384
  xmin = xmin - 1;
6385
  ymax = ymax + 1;
6386
  xmax = xmax + 1;
6387
  for( x = xmin ;x < xmax ; x = x + a ){
6388
    for ( y = ymin ;y < ymax ; y = y + b ){
18552 bpr 6389
      if( i < MAX_BUFFER - 2){
18562 bpr 6390
        diff = level - eval_x_y(f, x,y);
6391
        if(diff < 0.1 && diff > -0.1){
6392
          xydata[i++] = x;
6393
          xydata[i++] = y;
6394
        }
18552 bpr 6395
      }
6396
      else
6397
      {
18562 bpr 6398
        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 6399
      }
18562 bpr 6400
    }
18552 bpr 6401
  }
18562 bpr 6402
  eval_destroy(f);
6403
  return double_xy2js_array(xydata,i,find_number_of_digits(precision));
15111 schaersvoo 6404
}
7614 schaersvoo 6405
 
15111 schaersvoo 6406
/* plot parametric function */
18562 bpr 6407
char *eval_parametric(int xsize,int ysize,char *fun1,char* fun2,double xmin,
6408
  double xmax,double ymin,double ymax,
6409
  double tmin,double tmax,int plotsteps,int precision,double rotationcenter[]){
6410
  void *fx;
6411
  void *fy;
6412
  double t;
6413
  int i = 0;
6414
  double tstep = (tmax-tmin)/plotsteps;
6415
  if( tstep == 0 ){canvas_error("zero step for t variable : reduce plotsteps or inrease trange");}
6416
  fx = eval_create(fun1);
6417
  fy = eval_create(fun2);
6418
  assert(fx);
6419
  assert(fy);
6420
  if( fx == NULL || fy == NULL ){canvas_error("I'm having trouble parsing your \"expression\" ") ;}
15111 schaersvoo 6421
    /* we supply the true x/y values...draw_curve() will convert these (x:y) to pixels : used for pan/scale */
18562 bpr 6422
 double xydata[MAX_BUFFER+1];/* hmmm */
6423
 double x; /* real x-values */
6424
 double y; /* real y-values */
6425
 double xorg;
6426
 /*
6427
 29/12/2020
6428
 disabled to try and synchronise curve+affine behaviour in complex scripts produced by "elec, tool circuit" (BPR)
15623 schaersvoo 6429
    int lim_ymin =(int)( ymin - 4*fabs(ymin));
6430
    int lim_ymax =(int)( ymax + 4*fabs(ymax));
6431
    */
18562 bpr 6432
  double c = 1.0;double s = 1.0;
6433
  if( use_rotate == TRUE ){s = sin(angle*0.0174533);c = cos(angle*0.0174533);}
6434
  for( t = tmin ;t <= tmax ; t = t + tstep ){
6435
    if( i < MAX_BUFFER - 2 ){
18552 bpr 6436
      y = eval_t(fy, t);
6437
  /*    if(y > lim_ymin && y < lim_ymax){*/
18562 bpr 6438
      x = eval_t(fx, t);
6439
      if( x == x){ /* no NaN */
6440
        xorg = x;
6441
        if( use_affine == TRUE ){
6442
          x = x*affine_matrix[0] + y*affine_matrix[1]+affine_matrix[4];
6443
          y = xorg*affine_matrix[2] + y*affine_matrix[3]+affine_matrix[5];
6444
        }
6445
        if( use_rotate == TRUE){
6446
          x = (c * (x - rotationcenter[0])) + (s * (y - rotationcenter[1])) + rotationcenter[0];
6447
          y = (c * (y - rotationcenter[1])) - (s * (xorg - rotationcenter[0])) + rotationcenter[1];
6448
        }
6449
        xydata[i++] = x;
6450
        xydata[i++] = y;
6451
      }
6452
  /*    } */
18552 bpr 6453
    }
18562 bpr 6454
    else
6455
    {
18552 bpr 6456
      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 6457
    }
18552 bpr 6458
  }
18562 bpr 6459
  eval_destroy(fx);
6460
  eval_destroy(fy);
6461
  return double_xy2js_array(xydata,i,find_number_of_digits(precision));
15111 schaersvoo 6462
}
7614 schaersvoo 6463
 
15111 schaersvoo 6464
char *double_xy2js_array(double xy[],int len,int decimals){
6465
 /*
6466
    1,2,3,4,5,6,7,8 --> [1,3,5,7],[2,4,6,8]
6467
    int xy[] is already checked for errors or overflow in "get_real()"
6468
    just to be sure we double check the size of "temp"
7614 schaersvoo 6469
*/
18562 bpr 6470
  char temp[2*MAX_BUFFER], *string;
6471
  char *tmp = my_newmem(16);/* <= 9999999999999999  */
6472
  memset(temp,'\0',2*MAX_BUFFER);/* clear memory */
6473
  int i;int space_left;
6474
  temp[0] = '[';/* start js-array */
6475
  for(i = 0; i < len;i = i + 2){ /*  x_points[] */
6476
    if(i == len - 2){sprintf(tmp, "%.*f",decimals, xy[i]);}
6477
    else {sprintf(tmp, "%.*f,",decimals,xy[i]);}
6478
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6479
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6480
    else{
6481
      canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce your image size or plotsteps ");}
15111 schaersvoo 6482
    }
6483
    strncat(temp,"],[",4); /* close js x_values array and start new */
6484
    for(i = 1; i < len;i = i + 2){ /* y_points */
18557 bpr 6485
      if(i == len - 1){ sprintf(tmp, "%.*f",decimals,xy[i]);}else{sprintf(tmp, "%.*f,",decimals,xy[i]);}
6486
      space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6487
      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 6488
    }
6489
    strncat(temp,"]",2);
6490
    string=(char *)my_newmem(sizeof(temp));
6491
    snprintf(string,sizeof(temp),"%s",temp);
6492
    return string;
6493
}
7614 schaersvoo 6494
 
15111 schaersvoo 6495
char *list2js_array(char *list, char *s){/* abc:defg:hjiuy:qwer --> ["abc","defg","hjiuy","qwer"] */
6496
#define MAX_ARG 128
18562 bpr 6497
  if( strlen(list)> MAX_ARG - 1){canvas_error("argument is too large (&gt; 128)");}
6498
  char tmp[MAX_ARG];
6499
  size_t p = 0;
6500
  tmp[0] = '[';
6501
  tmp[1] = '\"';
6502
  size_t t = 2;
6503
  while(list[p] != '\0'){
6504
    if( list[p] == s[0] ){
6505
      tmp[t++]='\"';tmp[t++]=',';tmp[t++]='\"';
6506
    }
6507
    else
6508
    {
6509
      tmp[t++] = list[p];
6510
    }
6511
    p++;
15111 schaersvoo 6512
  }
18562 bpr 6513
  tmp[t++]='\"';tmp[t++]=']';tmp[t++]= '\0';
6514
  char *js_array = (char *)my_newmem(sizeof(tmp));
6515
  snprintf(js_array,sizeof(tmp),"%s",tmp);
6516
  return js_array;
15111 schaersvoo 6517
}
7963 schaersvoo 6518
 
15111 schaersvoo 6519
char *xy2js_array(int xy[],int len){
6520
 /*
6521
    1,2,3,4,5,6,7,8 --> [1,3,5,7],[2,4,6,8]
6522
    int xy[] is already checked for errors or overflow in "get_real()"
6523
    just to be sure we double check the size of "temp"
7614 schaersvoo 6524
*/
18562 bpr 6525
  char temp[MAX_BUFFER], *string;
6526
  char *tmp = my_newmem(16);/* <= 9999999999999999  */
6527
  memset(temp,'\0',MAX_BUFFER);/* clear memory */
6528
  int i;int space_left;
6529
  temp[0] = '[';/* start js-array */
6530
  for(i = 0; i < len;i = i + 2){ /*  x_points[] */
6531
    if(i == len - 2){sprintf(tmp, "%d", xy[i]);}else{sprintf(tmp, "%d,", xy[i]);}
6532
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6533
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6534
    else {
6535
    canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce image size or plotsteps ");}
6536
  }
6537
  strncat(temp,"],[",4); /* close js x_values array and start new */
6538
  for(i = 1; i < len;i = i + 2){ /* y_points */
6539
    if(i == len - 1){ sprintf(tmp, "%d", xy[i]);}else{sprintf(tmp, "%d,", xy[i]);}
6540
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6541
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6542
    else{canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data\nreduce image size or plotsteps \n");}
6543
  }
6544
  strncat(temp,"]",2);
6545
  string=(char *)my_newmem(sizeof(temp));
6546
  snprintf(string,sizeof(temp),"%s",temp);
6547
  return string;
7614 schaersvoo 6548
}
6549
 
15111 schaersvoo 6550
char *data2js_array(int data[],int len){
6551
 /*
6552
    1,2,3,4,5,6,7,8 --> [1,2,3,4,5,6,7,8]
6553
    int data[] is already checked for errors or overflow in "get_real()"
6554
    just to be sure we double check the size of "temp"
7614 schaersvoo 6555
*/
18562 bpr 6556
  char temp[MAX_BUFFER], *string;
6557
  char *tmp = my_newmem(16);/* <= 9999999999999999  */
6558
  memset(temp,'\0',MAX_BUFFER);/* clear memory */
6559
  int i;int space_left;
6560
  temp[0] = '[';/* start js-array */
6561
  for(i = 0; i < len; i++){
6562
    if(i == len - 1){sprintf(tmp, "%d", data[i]);}else{sprintf(tmp, "%d,", data[i]);}
6563
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6564
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6565
    else{
6566
    canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce image size or plotsteps ");
15111 schaersvoo 6567
    }
18562 bpr 6568
  }
6569
  strncat(temp,"]",2);
6570
  string=(char *)my_newmem(sizeof(temp));
6571
  snprintf(string,sizeof(temp),"%s",temp);
6572
  return string;
15111 schaersvoo 6573
}
7614 schaersvoo 6574
 
15111 schaersvoo 6575
char *doubledata2js_array(double data[],int len, int decimals){
6576
 /*
15116 bpr 6577
    1.4355,2.345353,3.3455 --> [1.44,2.35,3.35]
15111 schaersvoo 6578
    double data[] is already checked for errors or overflow in "get_real()"
6579
    just to be sure we double check the size of "temp"
8448 schaersvoo 6580
*/
18562 bpr 6581
  char temp[MAX_BUFFER], *string;
6582
  char *tmp = my_newmem(16);/* <= 9999999999999999  */
6583
  memset(temp,'\0',MAX_BUFFER);/* clear memory */
6584
  int i;int space_left;
6585
  temp[0] = '[';/* start js-array */
6586
  for(i = 0; i < len; i++){
6587
    if(i == len - 1){sprintf(tmp, "%.*f",decimals,data[i]);}
6588
    else{sprintf(tmp, "%.*f,",decimals,data[i]);}
6589
    space_left = (int) (sizeof(temp) - strlen(temp) - strlen(tmp) - 1);
6590
    if( space_left > 0 ){ strncat(temp,tmp,space_left - 1);}
6591
    else{
6592
      canvas_error("can not parse integer to js-array:\nYour curve plotting produces too many data \nreduce image size or plotsteps ");}
6593
  }
6594
  strncat(temp,"]",2);
6595
  string=(char *)my_newmem(sizeof(temp));
6596
  snprintf(string,sizeof(temp),"%s",temp);
6597
  return string;
15111 schaersvoo 6598
}
13829 bpr 6599
 
15111 schaersvoo 6600
void *my_newmem(size_t size){
18562 bpr 6601
  void  *p;
6602
  if((p = malloc(size +1)) == NULL){canvas_error("canvasdraw: ran out of memory\n");}
6603
  return p;
15111 schaersvoo 6604
}
8224 bpr 6605
 
15111 schaersvoo 6606
int find_number_of_digits(int i){
18562 bpr 6607
  if(i < 0 ){ i = -1*i;}
6608
  int digits = 0;
6609
  while ( i > 0){
6610
    digits++;
6611
    i = i/10;
6612
  }
6613
  return digits;
15111 schaersvoo 6614
}
7645 schaersvoo 6615
 
16828 schaersvoo 6616
int count_substring(char* string, char* substring) {
18164 schaersvoo 6617
  int i, j, l1, l2;
16828 schaersvoo 6618
  int count = 0;
6619
  l1 = strlen(string);
6620
  l2 = strlen(substring);
6621
  for(i = 0; i < l1 - l2 + 1; i++) {
6622
    if(strstr(string + i, substring) == string + i) {
6623
      count++;
6624
      i = i + l2 -1;
6625
    }
6626
  }
6627
  return count;
6628
}
11830 schaersvoo 6629
 
7614 schaersvoo 6630
void check_string_length(int L){
18555 bpr 6631
  if( L > MAX_BUFFER-1){
6632
    canvas_error("problem with your arguments to command...");
6633
  }
6634
  return;
7614 schaersvoo 6635
}
18555 bpr 6636
/* useful in hyp commands: determine if the hypsegment is an arc or a line */
18615 bpr 6637
/* give a point on the arc */
18555 bpr 6638
int hypgeodaux(double *q, double* ress, int full){
6639
  double alpha,beta,gamma,r,cx,cy,a1,a2,a3,tmp,
6640
    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],
6641
    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],
6642
    dy = -2*q[1]*q[2]+2*q[0]*q[3];
6643
  if (dy*dy*1e4 <= nx*nx+ny*ny){
6644
    if(full){
6645
      if (q[1]*q[1]+q[0]*q[0] > q[2]*q[2]+q[3]*q[3])
6646
        gamma = atan2(q[1],q[0]);
6647
      else
6648
        gamma = atan2(q[3],q[2]);
6649
      ress[0]=cos(gamma); ress[1]=sin(gamma); ress[2]=-cos(gamma); ress[3]=-sin(gamma);
6650
    }
6651
    else
6652
      {int i;for(i=0;i<4;++i) ress[i]=q[i];}
18615 bpr 6653
    ress[6]=(q[0]+q[2])/2;
6654
    ress[7]=(q[1]+q[3])/2;
18555 bpr 6655
    return 0;}
6656
  cx = ny/dy; cy=-nx/dy;
6657
  r = sqrt(cx*cx+cy*cy-1);
6658
  if(full)
6659
    {alpha=atan(1/r); beta = atan2(cy,cx);a1=M_PI+beta-alpha;a2=M_PI+beta+alpha;}
6660
  else
6661
    {a1 = atan2(q[1]-cy, q[0]-cx);a2 = atan2(q[3]-cy, q[2]-cx);}
6662
  if (fabs(a2-a1)>M_PI){if(a1<a2) a1+=2*M_PI; else a2+=2*M_PI;};
6663
  a3 = (a1+a2)/2;
6664
  if(a1>a2) {tmp=a1; a1=a2; a2=tmp;}
6665
  ress[0]=cx;
6666
  ress[1]=cy;
6667
  ress[2]=2*r;
6668
  ress[3]=2*r;
6669
  ress[4]=360+180/M_PI*a1;
6670
  ress[5]=360+180/M_PI*a2;
6671
  ress[6]=cx+r*cos(a3);
6672
  ress[7]=cy+r*sin(a3);
6673
  return 1;
6674
}
7614 schaersvoo 6675
 
6676
int get_token(FILE *infile){
18589 bpr 6677
  int left,milieu,delta,right,c,i=0;
18562 bpr 6678
  char temp[MAX_INT], *input_type;
18589 bpr 6679
  enum{rien,usefilled,usedashed};
6680
  static struct commande {char *nom; int res; int special;} table[]=
6681
  {
6682
{"#",COMMENT,0},
6683
{"affine",AFFINE,0},
6684
{"allowdups",ALLOW_DUPLICATES,0},
6685
{"angle",ANGLE,0},
6686
{"animate",ANIMATE,0},
6687
{"arc",ARC,0},
6688
{"arcarrow",ARCARROW,0},
6689
{"arrow",ARROW,0},
6690
{"arrow2",ARROW2,0},
6691
{"arrowarc",ARCARROW,0},
6692
{"arrowhead",ARROWHEAD,0},
6693
{"arrows",ARROWS,0},
6694
{"arrows2",ARROWS2,0},
6695
{"audio",AUDIO,0},
6696
{"audioobject",AUDIOOBJECT,0},
6697
{"axis",AXIS,0},
6698
{"axisnumbering",AXIS_NUMBERING,0},
6699
{"axisnumbers",AXIS_NUMBERING,0},
6700
{"backgroundimage",BGIMAGE,0},
6701
{"barchart",BARCHART,0},
6702
{"bezier",BEZIER,0},
6703
{"bgcolor",BGCOLOR,0},
6704
{"bgimage",BGIMAGE,0},
6705
{"blink",BLINK,0},
6706
{"boxplot",BOXPLOT,0},
6707
{"boxplotdata",BOXPLOTDATA,0},
6708
{"brokenline",POLYLINE,0},
6709
{"canvastype",CANVASTYPE,0},
6710
{"centered",CENTERED,0},
6711
{"centerstring",CENTERSTRING,0},
6712
{"chemtex",CHEMTEX,0},
6713
{"circle",CIRCLE,0},
6714
{"circles",CIRCLES,0},
6715
{"clearbutton",CLEARBUTTON,0},
6716
{"clicktile",CLICKTILE,0},
6717
{"clicktile_colors",CLICKTILE_COLORS,0},
6718
{"clock",CLOCK,0},
6719
{"colorpalette",COLORPALETTE,0},
6720
{"colors",MULTISTROKECOLORS,0},
6721
{"copy",COPY,0},
6722
{"copyresized",COPYRESIZED,0},
6723
{"crosshair",CROSSHAIR,0},
6724
{"crosshairs",CROSSHAIRS,0},
6725
{"crosshairsize",CROSSHAIRSIZE,0},
6726
{"css",CSS,0},
6727
{"cursor",CURSOR,0},
6728
{"curve",CURVE,0},
6729
{"curvedarrow",CURVEDARROW,0},
6730
{"curvedarrow2",CURVEDARROW2,0},
6731
{"curvedarrows",CURVEDARROWS,0},
6732
{"curvedarrows2",CURVEDARROWS2,0},
6733
{"darrow",ARROW,usedashed},
6734
{"darrow2",ARROW2,usedashed},
6735
{"dashed",DASHED,0},
6736
{"dashtype",DASHTYPE,0},
6737
{"dcurve",CURVE,usedashed},
6738
{"delete",CLEARBUTTON,0},
6739
{"demiline",HALFLINE,0},
6740
{"demilines",HALFLINES,0},
6741
{"dhline",HLINE,usedashed},
6742
{"diafill",DIAMONDFILL,0},
6743
{"diamondfill",DIAMONDFILL,0},
6744
{"disk",CIRCLE,usefilled},
6745
{"disks",CIRCLES,usefilled},
6746
{"display",MOUSE_DISPLAY,0},
6747
{"dline",LINE,usedashed},
6748
{"dotfill",DOTFILL,0},
6749
{"dplot",CURVE,usedashed},
6750
{"dpolyline",POLYLINE,usedashed},
6751
{"drag",DRAG,0},
6752
{"dsegment",SEGMENT,usedashed},
6753
{"dsegments",SEGMENTS,usedashed},
6754
{"duplicates",ALLOW_DUPLICATES,0},
6755
{"dvline",VLINE,usedashed},
6756
{"ellipse",ELLIPSE,0},
6757
{"ellipses",ELLIPSES,0},
6758
{"end",END,0},
6759
{"erase",CLEARBUTTON,0},
6760
{"farc",ARC,usefilled},
6761
{"fcircle",CIRCLE,usefilled},
6762
{"fcircles",CIRCLES,usefilled},
6763
{"fellipse",ELLIPSE,usefilled},
6764
{"fhypcircles",HYPCIRCLES,usefilled},
18615 bpr 6765
{"fhyppolygon",HYPPOLY,usefilled},
18589 bpr 6766
{"fill",FLOODFILL,0},
6767
{"fillall",FILLALL,0},
6768
{"fillcolor",FILLCOLOR,0},
6769
{"fillcolors",MULTIFILLCOLORS,0},
6770
{"filled",FILLED,0},
6771
{"filledarc",ARC,usefilled},
6772
{"filledpoly",POLY,usefilled},
6773
{"filledpolygon",POLY,usefilled},
18608 bpr 6774
{"fillopacity",FILLOPACITY,0},
18589 bpr 6775
{"fillpattern",FILLPATTERN,0},
6776
{"filltoborder",FILLTOBORDER,0},
6777
{"floodfill",FLOODFILL,0},
6778
{"fontcolor",FONTCOLOR,0},
6779
{"fontfamily",FONTFAMILY,0},
6780
{"fontsize",FONTSIZE,0},
6781
{"fpoly",POLY,usefilled},
6782
{"fpolygon",POLY,usefilled},
6783
{"frect",RECT,usefilled},
6784
{"frectangle",RECT,usefilled},
6785
{"frects",RECTS,usefilled},
6786
{"froundrect",ROUNDRECT,usefilled},
6787
{"froundrects",ROUNDRECTS,usefilled},
6788
{"fsquare",SQUARE,usefilled},
6789
{"fsquares",RECTS,usefilled},
6790
{"ftriangle",TRIANGLE,usefilled},
6791
{"ftriangles",TRIANGLES,usefilled},
6792
{"functionlabel",FUNCTION_LABEL,0},
6793
{"functionlabels",FUNCTION_LABEL,0},
6794
{"grid",GRID,0},
6795
{"gridfill",GRIDFILL,0},
6796
{"group",GROUP,0},
6797
{"halfline",HALFLINE,0},
6798
{"halflines",HALFLINES,0},
6799
{"hatchfill",HATCHFILL,0},
6800
{"highlight",STYLE,0},
6801
{"hline",HLINE,0},
6802
{"hlines",HLINES,0},
6803
{"horizontalline",HLINE,0},
6804
{"horizontallines",HLINES,0},
6805
{"html",HTML,0},
6806
{"http",HTTP,0},
6807
{"hypcircles",HYPCIRCLES,0},
6808
{"hyplines",HYPLINES,0},
6809
{"hyppolygon",HYPPOLY,0},
6810
{"hyprays",HYPRAYS,0},
6811
{"hypsegments",HYPSEGMENTS,0},
6812
{"imagefill",IMAGEFILL,0},
6813
{"imagepalette",IMAGEPALETTE,0},
6814
{"input",INPUT,0},
6815
{"intooltip",INTOOLTIP,0},
6816
{"jscurve",JSCURVE,0},
6817
{"jsmath",JSMATH,0},
6818
{"jsplot",JSCURVE,0},
6819
{"katex",LATEX,0},
6820
{"kill",KILL,0},
6821
{"killaffine",KILLAFFINE,0},
6822
{"killgroup",KILLSLIDER,0},
6823
{"killinear",KILLLINEAR,0},
6824
{"killlinear",KILLLINEAR,0},
6825
{"killreset",NORESET,0},
6826
{"killrotate",KILLROTATE,0},
6827
{"killslider",KILLSLIDER,0},
6828
{"killtranslate",KILLTRANSLATION,0},
6829
{"killtranslation",KILLTRANSLATION,0},
6830
{"latex",LATEX,0},
6831
{"lattice",LATTICE,0},
6832
{"legend",LEGEND,0},
6833
{"legendcolors",LEGENDCOLORS,0},
6834
{"levelcurve",LEVELCURVE,0},
6835
{"line",LINE,0},
6836
{"linear",LINEAR,0},
6837
{"linegraph",LINEGRAPH,0},
6838
{"lines",LINES,0},
6839
{"linewidth",LINEWIDTH,0},
6840
{"linewidths",MULTILINEWIDTH,0},
6841
{"math",LATEX,0},
6842
{"mathml",MATHML,0},
6843
{"mouse",MOUSE,0},
6844
{"mousedegree",MOUSE_DEGREE,0},
6845
{"mouseprecision",MOUSE_PRECISION,0},
6846
{"mousex",MOUSEX,0},
6847
{"mousey",MOUSEY,0},
6848
{"multicolors",MULTISTROKECOLORS,0},
6849
{"multidash",MULTIDASH,0},
6850
{"multidraw",MULTIDRAW,0},
6851
{"multifill",MULTIFILL,0},
6852
{"multifillcolors",MULTIFILLCOLORS,0},
6853
{"multifillopacity",MULTIFILLOPACITY,0},
6854
{"multiinput",MULTIUSERINPUT,0},
6855
{"multilabel",MULTILABEL,0},
6856
{"multilinewidth",MULTILINEWIDTH,0},
6857
{"multisnap",MULTISNAPTOGRID,0},
6858
{"multisnaptogrid",MULTISNAPTOGRID,0},
6859
{"multistrokecolors",MULTISTROKECOLORS,0},
6860
{"multistrokeopacity",MULTISTROKEOPACITY,0},
6861
{"multiuserinput",MULTIUSERINPUT,0},
6862
{"newrange",NEWRANGE,0},
6863
{"noreset",NORESET,0},
6864
{"nostatus",STATUS,0},
6865
{"noxaxis",NOXAXIS,0},
6866
{"noyaxis",NOYAXIS,0},
6867
{"numberline",NUMBERLINE,0},
6868
{"obabel",OBABEL,0},
6869
{"onclick",ONCLICK,0},
6870
{"opacity",OPACITY,0},
6871
{"parallel",PARALLEL,0},
6872
{"path",POLYLINE,0},
6873
{"patternfill",PATTERNFILL,0},
6874
{"piechart",PIECHART,0},
6875
{"pixels",PIXELS,0},
6876
{"pixelsize",PIXELSIZE,0},
6877
{"plot",CURVE,0},
6878
{"plotstep",PLOTSTEPS,0},
6879
{"plotsteps",PLOTSTEPS,0},
6880
{"point",POINT,0},
6881
{"pointer",CURSOR,0},
6882
{"points",POINTS,0},
6883
{"poly",POLY,0},
6884
{"polygon",POLY,0},
6885
{"polyline",POLYLINE,0},
6886
{"popup",POPUP,0},
6887
{"precision",MOUSE_PRECISION,0},
6888
{"protractor",PROTRACTOR,0},
6889
{"range",RANGE,0},
6890
{"ranget",TRANGE,0},
6891
{"rangex",XRANGE,0},
6892
{"rangey",YRANGE,0},
6893
{"rays",RAYS,0},
6894
{"rect",RECT,0},
6895
{"rectangle",RECT,0},
6896
{"rects",RECTS,0},
6897
{"replyformat",REPLYFORMAT,0},
6898
{"reset",RESET,0},
6899
{"resetoffset",RESETOFFSET,0},
6900
{"rotate",ROTATE,0},
6901
{"rotationcenter",ROTATION_CENTER,0},
6902
{"roundrect",ROUNDRECT,0},
6903
{"roundrectangle",ROUNDRECT,0},
6904
{"roundrects",ROUNDRECTS,0},
6905
{"ruler",RULER,0},
6906
{"seg",SEGMENT,0},
6907
{"segment",SEGMENT,0},
6908
{"segments",SEGMENTS,0},
6909
{"segs",SEGMENTS,0},
6910
{"setlimits",SETLIMITS,0},
6911
{"setpixel",SETPIXEL,0},
6912
{"settile",FILLPATTERN,0},
6913
{"sgraph",SGRAPH,0},
6914
{"size",SIZE,0},
6915
{"slider",SLIDER,0},
6916
{"snaptofun",SNAPTOFUNCTION,0},
6917
{"snaptofunction",SNAPTOFUNCTION,0},
6918
{"snaptogrid",SNAPTOGRID,0},
6919
{"snaptopoints",SNAPTOPOINTS,0},
6920
{"square",SQUARE,0},
6921
{"status",STATUS,0},
6922
{"string",STRING,0},
6923
{"stringup",STRINGUP,0},
6924
{"strokecolor",STROKECOLOR,0},
6925
{"strokecolors",MULTISTROKECOLORS,0},
18608 bpr 6926
{"strokeopacity",STROKEOPACITY,0},
18589 bpr 6927
{"style",STYLE,0},
6928
{"text",FLY_TEXT,0},
6929
{"textarea",TEXTAREA,0},
6930
{"textfill",TEXTFILL,0},
6931
{"textup",FLY_TEXTUP,0},
6932
{"title",CENTERSTRING,0},
6933
{"trace_jscurve",TRACE_JSCURVE,0},
6934
{"trange",TRANGE,0},
6935
{"translate",TRANSLATION,0},
6936
{"translation",TRANSLATION,0},
6937
{"transparent",OPACITY,0},
6938
{"triangle",TRIANGLE,0},
6939
{"triangles",TRIANGLES,0},
6940
{"tsteps",PLOTSTEPS,0},
6941
{"userboxplot",USERBOXPLOT,0},
6942
{"userboxplotdata",USERBOXPLOT,0},
6943
{"userdraw",USERDRAW,0},
6944
{"userinput",USERINPUT,0},
6945
{"userinput_function",USERINPUT_FUNCTION,0},
6946
{"userinput_xy",USERINPUT_XY,0},
6947
{"vector",ARROW,0},
6948
{"vectors",ARROWS,0},
6949
{"verticalline",VLINE,0},
6950
{"verticallines",VLINES,0},
6951
{"video",VIDEO,0},
6952
{"vline",VLINE,0},
6953
{"vlines",VLINES,0},
6954
{"xaxis",X_AXIS_STRINGS,0},
6955
{"xaxistext",X_AXIS_STRINGS,0},
6956
{"xaxistextup",X_AXIS_STRINGS_UP,0},
6957
{"xaxisup",X_AXIS_STRINGS_UP,0},
6958
{"xerrorbars",XERRORBARS,0},
6959
{"xlabel",XLABEL,0},
6960
{"xlogbase",XLOGBASE,0},
6961
{"xlogscale",XLOGSCALE,0},
6962
{"xoffset",XOFFSET,0},
6963
{"xrange",XRANGE,0},
6964
{"xsnaptogrid",XSNAPTOGRID,0},
6965
{"xunit",XUNIT,0},
6966
{"xylogscale",XYLOGSCALE,0},
6967
{"xyoffset",XYOFFSET,0},
6968
{"yaxis",Y_AXIS_STRINGS,0},
6969
{"yaxistext",Y_AXIS_STRINGS,0},
6970
{"yerrorbars",YERRORBARS,0},
6971
{"ylabel",YLABEL,0},
6972
{"ylogbase",YLOGBASE,0},
6973
{"ylogscale",YLOGSCALE,0},
6974
{"yoffset",YOFFSET,0},
6975
{"yrange",YRANGE,0},
6976
{"ysnaptogrid",YSNAPTOGRID,0},
6977
{"yunit",YUNIT,0},
6978
{"zoom",ZOOM,0}
6979
  };
7614 schaersvoo 6980
 
18552 bpr 6981
  while(((c = getc(infile)) != EOF)&&(c!='\n')&&(c!=',')&&(c!='=')&&(c!='\r')&&(c!='\t')){
6982
   if( i == 0 && (c == ' ') ){ continue; /* white spaces or tabs allowed before first command identifier */
6983
   }else{
6984
    if( c == ' ' ){
6985
      break;
6986
    }else{
6987
     temp[i] = c;
6988
     if(i > MAX_INT - 2){canvas_error("command string too long !");}
6989
     i++;
6990
    }
6991
   }
6992
   if(temp[0] == '#'){ break; }
6993
  }
6994
  if (c == '\n' || c == '\r' || c == '\t' ){  line_number++; }
6995
  if (c == EOF) {finished=1;return 0;}
7614 schaersvoo 6996
 
18552 bpr 6997
  temp[i]='\0';
6998
  if(strstr(temp,"dash") !=0 && strlen(temp) > 4 && strstr(temp,"dashtype") == 0 ){
6999
  /* 4/2024 adapt to Flydraw's dashing syntax for all objects with prefix "dash" */
7000
      use_dashed = TRUE;int idx=0;int p;
7001
      for( p = 4; p < strlen(temp); p++){temp[idx] = temp[p];idx++;}
7002
      input_type = (char*)my_newmem(idx); snprintf(input_type,idx+1,"%s",temp);
7003
  }else{
7004
      input_type=(char*)my_newmem(strlen(temp));
7005
      snprintf(input_type,sizeof(temp),"%s",temp);
7006
  }
18572 bpr 7007
/*  fprintf(stdout,"input_type = %s no_reset = %d <br>",input_type,no_reset);*/
18589 bpr 7008
 
7009
  left=0; right=sizeof(table)/sizeof(struct commande);
7010
  while (left<right){
7011
    milieu = (left+right)/2;
7012
    delta = strcmp(input_type, table[milieu].nom);
7013
    if (delta == 0){
7014
             free(input_type);
7015
             if (table[milieu].special==usefilled) use_filled=TRUE;
7016
             if (table[milieu].special==usedashed) use_dashed=TRUE;
7017
             return table[milieu].res;
7018
          }
7019
    if (delta<0) right=milieu; else left=milieu+1;
18552 bpr 7020
  }
7021
  free(input_type);
18562 bpr 7022
  ungetc(c,infile);
7023
  return 0;
7614 schaersvoo 7024
}