-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsltxt2svg.js
790 lines (731 loc) · 28.2 KB
/
sltxt2svg.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
/**
sltxt2svg.js -- create an SVG image from Sensei's Library diagram format
Copyright (C) 2001-2004 by
Arno Hollosi <[email protected]>, Morten Pahle <[email protected]>
Javascript port Copyright (C) by
Stefano Franchi 2019 <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program (see bottom of file); if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
See demo function after the class definition on how to use it.
**/
/**
* The syntax for Sensei Library ASCII diagrams:
*
* The first line controls the behavior of the diagram.
*
* The basic syntax is:
* $$(B,W)(c)(size)(m Num)(title)
* | | | | +----> title of the diagram
* | | | +-----> starting move number (e.g m67 - no space!)
* | | +----> board size (for SGF and coordinates - default:19)
* | +-> enable and show coordinates in the diagram image
* +--> first move is either by black (B) or white (W)
* All parts are optional and can be omitted.
*
* The diagram itself may contain the following symbols
* (see https://senseis.xmp.net/?HowDiagramsWork for full details):
*
* . empty intersection (dot)
* , hoshi
* + empty corner intersection
* | empty vertical border
* - empty horizontal border (minus sign)
* _ empty space (underscore) (used to create room around the diagram)
* X plain black stone
* O plain white stone
* 1..9 Black's move 1, White's move 2
* 0 (zero) Black's or White's move 10
* - Black's or White's move 11-100
* B black stone with circle
* W white stone with circle
* # black stone with square
* @ white stone with square
* Y black stone with triangle (omitted [OTF])
* Q white stone with triangle (appears as WS [OTF])
* Z black stone with cross mark (X) (omitted [OTF])
* P white stone with cross mark (X) (omitted [OTF])
* C circle on empty intersection
* S square on empty intersection
* T triangle on empty intersection (omitted [OTF])
* M cross mark (X) on empty intersection (omitted [OTF])
* a..z letter on empty intersection
*
* The diagram may also contain links between any of the symbols
* and an internal or external URL in standard wiki format,
* i.e. [symbol|link]
*
**/
/**
* The GoDiagram class
* All you need to know are the following methods and variables:
*
* - create image with new GoDiagram(string) where string contains
* the diagram in Sensei Library's diagram format.
*
* - to parse the ASCII diagram and get the SVG image call diagram.createSVG()
* If parsing has failed, an SVG image with an error message will be returned.
* If parsing was successful, an SVG image of the diagram will be returned.
*
* - image size and width can be read from diagram.imageWidth and
* diagram.imageHeight
*
* - for the client side link map call diagram.getLinkmap()
*
* - for the (escaped) title call diagram.getTitle()
*
* - for the SGF file call diagram.createSGF()
*
* The basic unit of measure for the conversion from ASCII to SVG image
* in the original sl2png.php codebase is fontsize, which represents
* the height and width in pixels of a box containing a character of
* font size n, where n goes from 1 to 5.
*
* GoDiagramJS keeps the same mechanism but uses instead height and width
* (stored as attributes h and w of a fontisize dictionary variable)
* of a character cell, given in pixels to the class constructor method.
* The constructor defaults to 16x8, which would correspond
* to a font of size 2 for a browser's built-in latin2 font.
*
**/
class GoDiagram
{
constructor(input_diagram,fontSize={"h":16,"w":8})
/**
* Constructor of class GoDiagram
* input_diagram is the diagram in SL's diagram format
*
* fontSize are the height and width in pixels of a box for
* HTML latin2 standard fontsize 4.
**/
{
this.fontSize = fontSize;
this.inputDiagram = input_diagram;
this.diagram = null; //default value, overwritten if parsing succeeds
this.parseFailedMessage = '';
}
parseInput(){
/**
Parse input (this.inputDiagram) into internal representation.
Sets this.diagram to null if invalid diagram found
//values extracted from the title line
firstColor; // 'B' or 'W'
coordinates; // boolean
boardSize; // integer
title; // raw text of title
diagram; // raw copy of diagram contents (single string)
rows; // normalized copy of _diagram (array of lines)
linkmap; // array of imagemap links (bracketlinks)
image; // image object of PNG graphic
// image properties
fontsize; // dict (h,w), the base unit for dimensions,
//see note above.
radius; // based on fontsize, is the radius of the circle
// circumscribing the cell containing a stone,
// markup, or an empty intersection.
imageWidth;
imageHeight;
offset_x;
offset_y;
// information about rows, columns
startrow;
startcol;
endrow;
endcol;
// whether there is a border at the top, bottom, left, right (boolean)
topborder;
bottomborder;
leftborder;
rightborder;
**/
try {
var match;
this.content = this.inputDiagram.split("\n");
// Parse the parameters of the first line
match = this.content[0].trim().match(/^\$\$([WB])?(c)?(d+)?(.*)/);
this.firstColor = (match[1] == 'W') ? 'W' : 'B';
this.coordinates = !(match[2] == undefined);
this.boardSize = (match[3]== undefined) ? 19 : match[3]+0;
this.title = match[4].trim();
// fill diagram and linkmap variables
this.diagram = '';
this.linkmap = {}; // new Object because JS does not have distinct associative arrays
// Read all lines after first one
// Using " " as regex delimiter instead of / because
// we are looking for possible URLs
for (var line of this.content.slice(1,))
{
// Add NOT EMPTY line prefixed with $$ NOT containing bracketed links, discarding prefix
if ((match = line.trim().match(/^\$\$\s*([^[\s].*)/)))
{
this.diagram += (match[1] + "\n");
}
// Now looking for links and adding them to the map
if ((match = line.match(/^\$\$\s*\[(.*)\|(.*)\]/)))
{
var anchor = match[1].trim();
if (anchor.match(/^[a-z0-9WB@#CS]$/))
{
this.linkmap[anchor] = (match[2].trim());
}
}
}
this.initBoardAndDimensions();
if (this.startrow > this.endrow // check if diagram is at least
|| this.startcol > this.endcol // 1x1
|| this.endrow < 0 || this.endcol < 0
|| this.imageWidth < this.fontSize["w"]
|| this.imageHeight < this.fontSize["h"])
{this.diagram = null;
}
}
catch(error) {
this.diagram = null;
this.failureErrorMessage = 'Parsing of ASCII diagram failed';
}
} //end of parse function
/**
* Parse diagram and calculate board dimensions
**/
initBoardAndDimensions()
{
var diag;
// remove unnecessary chars, replace border chars
diag = this.diagram.replace(/[-|+]/g, '%');
diag = diag.replace(/[ \t\r\$]/g, '');
diag = diag.replace(/\n+/g,' \n');
// trim(preg_replace("/\n+/", " \n", $diag));
this.rows = diag.split("\n");
// find borders
this.startrow = 0;
this.startcol = 0;
this.endrow = this.rows.length - 1;
// top border
if (this.rows[0][1] == '%')
{
this.startrow++;
this.topborder = 1;
}
else
this.topborder = 0;
// bottom border
if (this.rows[this.endrow][1] == '%')
{
this.endrow--;
this.bottomborder = 1;
}
else
this.bottomborder = 0;
// left border
if (this.rows[this.startrow][0] == '%')
{
this.startcol++;
this.leftborder = 1;
}
else
this.leftborder = 0;
// right border
this.endcol = this.rows[this.startrow].length - 2;
if (this.rows[this.endrow][this.endcol] == '%')
{
this.endcol--;
this.rightborder = 1;
}
else
this.rightborder = 0;
/** Initialize image size.
* The goban is a matrix of rectangular cells, which can be empty,
* contain a stone, or a symbol. A cell's minimum size must accommodate
* a symbol in the font used, whose height and width are stored
* in an instance variable and default to h:16 and w:8 (equivalent to
* the px heights and width of a font size 2).
* The image's size adds room for two cells on all sides for the borders **/
var diameter = Math.floor(Math.sqrt(this.fontSize["h"]**2 + this.fontSize["w"]**2));
this.radius = diameter/2;
this.diameter = diameter;
this.imageWidth = diameter * (1+this.endcol-this.startcol) + 4;
this.imageHeight = diameter * (1+this.endrow-this.startrow) + 4;
this.offset_x = 2;
this.offset_y = 2;
// adjust image size if coordinates are needed
if (this.coordinates)
{
if ((this.bottomborder || this.topborder)
&&
(this.leftborder || this.rightborder))
{
var x = this.fontSize["w"]*2+4;
var y = this.fontSize["h"]+2;
this.imageWidth += x;
this.offset_x += x;
this.imageHeight += y;
this.offset_y += y;
}
else {
// cannot determine X *and* Y coordinates (missing borders)
this.coordinates = 0;
}
}
}
htmlspecialchars(text)
{
var map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
getTitle()
{
return this.htmlspecialchars(this.title);
}
createSvgErrorMessage(errorClass){
// Return an svgElement string with the error message
// poor man text wrapping, still unsupported in SVG 1.1
// var splitMessage = this.failureErrorMessage.match(/(.{1,15})/g);
var splitMessage = this.failureErrorMessage.split();
var wPerL = 4; //words per line
var lines = Math.floor(splitMessage.length/wPerL);
if (splitMessage % wPerL !==0){
lines++;};
var svgError = '<svg xmlns="http://www.w3.org/2000/svg">\n';
svgError += '<g> \n ';
svgError += '<rect x="0" y="0" rx="20" ry="20" width="300" ';
svgError += 'height="' + (lines * 50).toString() +'" ';
svgError += ' fill="red" stroke="black"';
svgError += 'class=\"' + errorClass + '\" > </rect>\n';
svgError += '<text x="30" y="30" font-size="15" fill="black">\n';
for (var i = 0; i < lines; i++)
{
svgError += splitMessage.slice((i*wPerL), (i+1)*wPerL)+ '\n';
}
svgError += '</text>\n';
svgError += '</g>\n</svg>\n';
return svgError;
}
createSVG()
/** Create the SVG image based on ASCII diagram
* returns an SVG object (an XML text file)
**/
{
// parse input diagram, create error SVG if failed
this.parseInput();
if (this.diagram === null) { //parsing failed
this.failureErrorMessage = 'Parsing of ASCII diagram failed';
return this.createSvgErrorMessage(errorClass);
}
else {
// parsing succeeded --> create SVG diagram
var imgSvg = {};
// 1. Create the SVG image element
imgSvg["openSvgTag"] = '<svg width = "'
+ this.imageWidth
+ '" height = "' +
this.imageHeight +
'">\n';
imgSvg["closeSvgTag"] = '</svg>\n';
// 2. Set up the default colors
var black = "rgb(0, 0, 0)";
var white ="rgb(255, 255, 255)";
var red ="rgb(255, 55, 55)";
var goban ="rgb(242, 176, 109)";
var gobanborder ="rgb(150, 110, 65)";
var gobanborder2 ="rgb(210, 145, 80)";
var gobanopen ="rgb(255, 210, 140)";
var link ="rgb(202, 106, 69)";
var markupColor = '';
var linkOpacity = 0.4; // Transparency of the linked areas on the goban
// 3. Setup the CSS classes for styling
var blackStoneClass = 'blackstone';
var whiteStoneClass = 'whitestone';
var gobanClass = 'goban';
var gobanBorderClass = 'gobanBorder';
var linkClass = 'linkClass';
var markupClass = 'markup';
var evenColorClass = 'evenColor';
var oddColorClass = 'oddColor';
var textClass = 'textClass';
var coordClass = 'coordClass';
var errorClass = 'errorClass';
// plus some default styles in case CSS classes are not present
// Text size in SVG behaves differently than in PHP's image
// Approximately half the height of our fontSize box is desired
// coordinates and auxiliary text. About 90% of the standard font for markup
var svgMarkupTextSize = 'style="font-size:' + (Math.floor(this.fontSize["h"]*0.9)).toString() + 'px"';
var svgDefaultTextSize = 'style="font-size:' + (this.fontSize["h"]/2).toString() + 'px"';
// 5. Create the background
imgSvg["background"] = '<rect x="0" y="0" width="' +
this.imageWidth + '" height = "' + this.imageHeight +
'" fill = "'+ goban + '"/>\n';
// 6. Draw the coordinates
if (this.coordinates)
{
imgSvg["coordinates"] = this.drawCoordinates(black, coordClass, svgDefaultTextSize);
}
else
{
imgSvg["coordinates"] = '';
}
// 7. Draw Goban border
this.drawGobanBorder(gobanborder,gobanborder2, gobanopen, white);
// 8. Draw stones, numbers etc. for each row and column
if (this.firstColor == 'W')
{
var evencolor = black;
var oddcolor = white;
} else {
evencolor = white;
oddcolor = black;
}
/** main drawing routine starts here
* imgSvg['svgDiagram'] is the string collecting
* all the svg elements for all the cells in the diagram
**/
imgSvg['svgDiagram'] = '';
for (var ypos = this.startrow; ypos <= this.endrow; ypos++)
{
// Get the ordinate of the element to draw
var elementY = (ypos - this.startrow) * (this.radius *2) +
this.radius + this.offset_y;
//for each character in the row
for (var xpos = this.startcol; xpos <= this.endcol; xpos++ )
{
// svgItem contains one or more svg elements
//(circles, intersection, marks, colored areas, etc.)
// with the drawing code for each cell in the diagram
var svgItem = '';
// get the absciss of the element to draw
var elementX = (xpos - this.startcol) * (this.radius *2) +
this.radius + this.offset_x;
// Get the character
var curchar = this.rows[ypos][xpos];
// FIXME: TODO
/** Is this a linked area? if so,
* add a square colored with link color
* to the link elements array
* and wrap the it in an "a" element with
* the proper anchor and link.
*
* We are following SVG 2.0 rules and using href
* instead of the xlink namespace.
* See https://www.w3.org/TR/SVG2/linking.html#URLReference
*/
if (typeof this.linkmap[curchar] !== 'undefined' &&
this.linkmap[curchar] !== null)
{
imgSvg["links"] += '<a href="' + this.linkmap[curchar]+ '" >\n';
imgSvg["links"] += '<rect x="' + (elementX - this.radius) +
'" y="' + (elementY -this.radius) +
'" width="' + (this.radius*2) +
'" height="' +(this.radius*2) +
'" stroke="'+ goban + '" fill="' + link +
'" fill-opacity="' + linkOpacity + '" />\n';
imgSvg["links"] += '</a>\n';
}
// {
// list($x, $y, $xx, $yy) = $this->_getLinkArea($xpos, $ypos);
// ImageFilledRectangle($img, $x, $y, $xx, $yy, $link);
// }
switch(curchar)
{
// if X, B, or # we have a black stone (marked or not)
case ('X'):
case ('B'):
case ('#'):
svgItem += this.drawStone(elementX,elementY,black,black);
if (curchar !== 'X')
{
svgItem += this.markIntersection(elementX,elementY, this.radius, red, curchar);
}
break;
// if O, W, or @ we have a white stone, marked or unmarked
case ('O'):
case ('W'):
case ('@'):
svgItem += this.drawStone(elementX,elementY,black,white);
if (curchar !== 'O')
{
svgItem += this.markIntersection(elementX,elementY,this.radius,red,curchar); }
break;
// if . , C or S we have EMPTY intersections possibly with hoshi, circle or square
case ('.'): // empty intersection, check location
// (edge, corner)
case (','):
case ('C'):
case ('S'):
var type = this.getIntersectionType(xpos,ypos);
svgItem += this.drawIntersection(elementX,elementY,black,type);
if (curchar !== '.')
{
var col = (curchar == ',') ? black : red;
svgItem += this.markIntersection(elementX,elementY,this.radius,col,curchar);
}
break;
// any other markup (including & / ( ) ! etc.)
default:
if (curchar % 2 == 1) //odd numbers
{
svgItem += this.drawStone(elementX,elementY,black,oddcolor);
markupColor = evencolor;
}
else if (curchar % 2 == 0 | curchar ==0) // even numbers
{
svgItem += this.drawStone(elementX,elementY,black, evencolor);
markupColor = oddcolor;
if (curchar == '0') {curchar = '10';}
}
else if (curchar >= 'a' && curchar <= 'z')
{
type = this.getIntersectionType(xpos,ypos);
svgItem += this.drawIntersection(elementX, elementY, black, type);
var bkColor = (typeof this.linkmap[curchar] !== 'undefined' && this.linkmap[curchar] !== null) ? link : goban;
// Draw a stone-sized circle under the letter to hide the intersection
svgItem += this.drawStone(elementX,elementY,goban,goban);
// then draw the letter
this.markIntersection(elementX, elementY, this.radius+4, bkColor, "@" );
markupColor = black;
//font++ ??? Unclear what this does. font starts up set at this.fontsize, which was 2
}
else
// unknown character
{break;}
var xOffset = (curchar.length == 2) ? this.fontSize["w"] : this.fontSize["w"]/2 ;
var yOffset = (this.fontSize["h"]/2 - 12.5 );
svgItem += '<text x="' + (elementX-xOffset).toString() +
'" y="' + (elementY - yOffset).toString() +
'" fill="' + markupColor + '" class="' + markupClass +
'" ' + svgMarkupTextSize + '>'+
curchar+
'</text>\n';
break;
} // end of switch curchar
imgSvg['svgDiagram'] += svgItem;
} // end of xpos loop
} // end of ypos loop
// 7. Assemble the complete svg element and return it
var svgElement = imgSvg["openSvgTag"] +
imgSvg["background"] +
imgSvg['svgDiagram'] +
imgSvg["links"] +
imgSvg['coordinates'] +
imgSvg["closeSvgTag"];
return svgElement;
}
}
drawStone(x, y, colorRing, colorInside)
/** Return Svg element for a stone
* x and y are the coords of the center of the diagram's cell
* colorRing, colorInside are stone colors (edge and body, resp.)
**/
{
var stone = "";
stone += '<circle cx="' +
x + '" cy = "' +
y + '" r = "' +
this.radius +
'" stroke = "' +
colorRing +
'" fill = "' +
colorInside +
'" />\n';
return stone;
}
markIntersection(x, y, radius, color, type)
/** Draws board markup and hoshi marks.
* x and y are the coords of the center of the diagram's cell
* type is one of W,B,C for circle or S,@,# for square
**/
{
var intersectionElements = '';
var svgElem;
switch(type)
{
case ('W'):
case ('B'):
case ('C'):
intersectionElements += '<circle cx="' +
x + '" cy = "' +
y + '" r = "' +
(radius - 3) +
'" stroke = "' +
color +
'" fill = "none"' +
'" />\n';
intersectionElements += '<circle cx="' +
x + '" cy = "' +
y + '" r = "' +
(radius - 2) +
'" stroke = "' +
color +
'" fill = "none"' +
'" />\n';
// intersectionElements += '<circle cx="' +
// x + '" cy = "' +
// y + '" r = "' +
// radius +
// '" stroke = "' +
// color +
// '" fill = "none"' +
// '" />\n';
break;
case ('S'):
case ('@'):
case ('#'):
intersectionElements += '<rect x="' +
(x-radius/2+1) + '" y = "' +
(y-radius/2+1) + '" width = "' +
7 + '" height = "' + 7 +
'" stroke = "' +
color +
'" fill = "none"' +
'" />\n';
break;
case (','):
intersectionElements += '<circle cx="' +
x + '" cy = "' +
y + '" r = "' +
3 +
'" stroke = "' +
color +
'" fill = "' + color +
'" />\n';
}
return intersectionElements ;
}
getIntersectionType(x, y)
/** Check if the intersection is on an edge or in a corner
* Returns one of these values, or their combination (for corners):
* U(pper), L(eft), R(ight), B(ottom)
**/
{
var type = '';
if (this.rows[y-1][x] == "%") {type = 'U';} // Upper row
if (this.rows[y+1][x] == "%") {type += 'B';} // Bottom row
if (this.rows[y][x-1] == "%") {type += 'L';} // Left column
if (this.rows[y][x+1] == "%") {type += 'R';} // Right column
return type;
}
drawIntersection(x, y, color, type)
/** x and y are the coordinates of the center of the cell
* type can be 'U', 'L', 'R', 'B', 'UL', 'BL', 'UR', 'BR'
* an empty type represents a middle (non-edge) intersection.
**/
{
var intersectionElements = '';
var svgElem;
if (!type.includes('U'))
{
svgElem = '<line x1="' + x + '" y1="' +
(y - this.radius) + '" x2="' + x + '" y2="' +
y + '" stroke="' + color + '" />\n';
intersectionElements += svgElem;
}
if (!type.includes('B'))
{
svgElem = '<line x1="' + x + '" y1="' +
(y + this.radius) + '" x2="' + x + '" y2="' +
y + '" stroke="' + color + '" />\n';
intersectionElements += svgElem;
}
if (!type.includes('L'))
{
svgElem = '<line x1="' + (x-this.radius) + '" y1="' +
y + '" x2="' + x + '" y2="' +
y + '" stroke="' + color + '" />\n';
intersectionElements += svgElem;
}
if (!type.includes('R'))
{
svgElem = '<line x1="' + (x+this.radius) + '" y1="' +
y + '" x2="' + x + '" y2="' +
y + '" stroke="' + color + '" />\n';
intersectionElements += svgElem;
}
return intersectionElements;
}
drawCoordinates(color, coordClass, SVGTextSize)
// Returns one or more svg elements with the Goban coordinates
{ var coordChars = 'ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghjklmnopqrstuvwxyz123456789',
coordY , coordX ,
topRowSvgElems = '', leftColSvgElems = '',
svgElem;
if (this.bottomborder)
{
coordY = this.endrow - this.startrow + 1;
}
else if (this.topborder)
{
coordY = this.boardSize;
}
if (this.leftborder)
{
coordX = 0;
}
else if (this.rightborder)
{
coordX = this.boardSize - this.endcol - 1;
if (coordX < 0) {coordX = 0;};
}
// coordinate calculations according to offsets and sizes
// in createSVG. See createSVG for values
// Offset from left border. May have to be adjusted for different fontsizes
var leftX = 6 + this.fontSize["w"];
var img_y = 12 + this.fontSize["h"]+2 +
this.radius - (this.fontSize["h"]/2);
for (var y = 0; y <= this.endrow-this.startrow-1; y++)
{
var Xoffset = (coordY >= 10)
? this.fontSize["w"] : this.fontSize["w"]/2;
svgElem = '<text x="' + (leftX - Xoffset) +
'" y="' + img_y +
'" class="' + coordClass +
'" '+ SVGTextSize +
'" color="' + color + '">'+
coordY.toString() +' </text>\n';
img_y += (this.radius*2)+ 0.5;
coordY--;
leftColSvgElems += svgElem;
}
// Offset from top of image. May have to be adjusted for different font sizes
var topY = 18;
var img_x = 2 + this.fontSize["w"]*2 +4 +
this.radius - this.fontSize["w"]/2;
for (var x = 0; x <= this.endcol-this.startcol; x++)
{
svgElem = '<text x="' + img_x +
'" y="' + topY + '" class="' + coordClass +
'" '+ SVGTextSize +
' color="' + color + '">'+
coordChars[coordX] +' </text>\n';
img_x += this.radius*2;
coordX++;
topRowSvgElems += svgElem;
}
return leftColSvgElems + topRowSvgElems;
}
drawGobanBorder(color, color2, open, white)
{
return '';
}
createSGF()
//FIX ME: STILL TO DO
/** Creates SGF based on ASCII diagram and title
* returns SGF as string or FALSE (if board not a square)
**/
{
return '';
}
}
exports.GoDiagram = GoDiagram;