line
stmt
bran
cond
sub
pod
time
code
1
#############################################################################
2
# Define and check attributes for a Graph::Easy textual description.
3
#
4
#############################################################################
5
6
package Graph::Easy::Attributes;
7
8
$VERSION = '0.76';
9
10
package Graph::Easy;
11
12
48
48
26638
use strict;
48
53
48
1078
13
48
48
154
use warnings;
48
59
48
1066
14
48
48
19679
use utf8; # for examples like "Fähre"
48
331
48
247
15
16
# to make it easier to remember the attribute names:
17
my $att_aliases = {
18
'auto-label' => 'autolabel',
19
'auto-link' => 'autolink',
20
'auto-title' => 'autotitle',
21
'arrow-style' => 'arrowstyle',
22
'arrow-shape' => 'arrowshape',
23
'border-color' => 'bordercolor',
24
'border-style' => 'borderstyle',
25
'border-width' => 'borderwidth',
26
'font-size' => 'fontsize',
27
'label-color' => 'labelcolor',
28
'label-pos' => 'labelpos',
29
'text-style' => 'textstyle',
30
'text-wrap' => 'textwrap',
31
'point-style' => 'pointstyle',
32
'point-shape' => 'pointshape',
33
};
34
35
96
96
15488
sub _att_aliases { $att_aliases; }
36
37
#############################################################################
38
# color handling
39
40
# The W3C/SVG/CSS color scheme
41
42
my $color_names = {
43
w3c =>
44
{
45
inherit => 'inherit',
46
aliceblue => '#f0f8ff',
47
antiquewhite => '#faebd7',
48
aquamarine => '#7fffd4',
49
aqua => '#00ffff',
50
azure => '#f0ffff',
51
beige => '#f5f5dc',
52
bisque => '#ffe4c4',
53
black => '#000000',
54
blanchedalmond => '#ffebcd',
55
blue => '#0000ff',
56
blueviolet => '#8a2be2',
57
brown => '#a52a2a',
58
burlywood => '#deb887',
59
cadetblue => '#5f9ea0',
60
chartreuse => '#7fff00',
61
chocolate => '#d2691e',
62
coral => '#ff7f50',
63
cornflowerblue => '#6495ed',
64
cornsilk => '#fff8dc',
65
crimson => '#dc143c',
66
cyan => '#00ffff',
67
darkblue => '#00008b',
68
darkcyan => '#008b8b',
69
darkgoldenrod => '#b8860b',
70
darkgray => '#a9a9a9',
71
darkgreen => '#006400',
72
darkgrey => '#a9a9a9',
73
darkkhaki => '#bdb76b',
74
darkmagenta => '#8b008b',
75
darkolivegreen => '#556b2f',
76
darkorange => '#ff8c00',
77
darkorchid => '#9932cc',
78
darkred => '#8b0000',
79
darksalmon => '#e9967a',
80
darkseagreen => '#8fbc8f',
81
darkslateblue => '#483d8b',
82
darkslategray => '#2f4f4f',
83
darkslategrey => '#2f4f4f',
84
darkturquoise => '#00ced1',
85
darkviolet => '#9400d3',
86
deeppink => '#ff1493',
87
deepskyblue => '#00bfff',
88
dimgray => '#696969',
89
dodgerblue => '#1e90ff',
90
firebrick => '#b22222',
91
floralwhite => '#fffaf0',
92
forestgreen => '#228b22',
93
fuchsia => '#ff00ff',
94
gainsboro => '#dcdcdc',
95
ghostwhite => '#f8f8ff',
96
goldenrod => '#daa520',
97
gold => '#ffd700',
98
gray => '#808080',
99
green => '#008000',
100
greenyellow => '#adff2f',
101
grey => '#808080',
102
honeydew => '#f0fff0',
103
hotpink => '#ff69b4',
104
indianred => '#cd5c5c',
105
indigo => '#4b0082',
106
ivory => '#fffff0',
107
khaki => '#f0e68c',
108
lavenderblush => '#fff0f5',
109
lavender => '#e6e6fa',
110
lawngreen => '#7cfc00',
111
lemonchiffon => '#fffacd',
112
lightblue => '#add8e6',
113
lightcoral => '#f08080',
114
lightcyan => '#e0ffff',
115
lightgoldenrodyellow => '#fafad2',
116
lightgray => '#d3d3d3',
117
lightgreen => '#90ee90',
118
lightgrey => '#d3d3d3',
119
lightpink => '#ffb6c1',
120
lightsalmon => '#ffa07a',
121
lightseagreen => '#20b2aa',
122
lightskyblue => '#87cefa',
123
lightslategray => '#778899',
124
lightslategrey => '#778899',
125
lightsteelblue => '#b0c4de',
126
lightyellow => '#ffffe0',
127
limegreen => '#32cd32',
128
lime => '#00ff00',
129
linen => '#faf0e6',
130
magenta => '#ff00ff',
131
maroon => '#800000',
132
mediumaquamarine => '#66cdaa',
133
mediumblue => '#0000cd',
134
mediumorchid => '#ba55d3',
135
mediumpurple => '#9370db',
136
mediumseagreen => '#3cb371',
137
mediumslateblue => '#7b68ee',
138
mediumspringgreen => '#00fa9a',
139
mediumturquoise => '#48d1cc',
140
mediumvioletred => '#c71585',
141
midnightblue => '#191970',
142
mintcream => '#f5fffa',
143
mistyrose => '#ffe4e1',
144
moccasin => '#ffe4b5',
145
navajowhite => '#ffdead',
146
navy => '#000080',
147
oldlace => '#fdf5e6',
148
olivedrab => '#6b8e23',
149
olive => '#808000',
150
orangered => '#ff4500',
151
orange => '#ffa500',
152
orchid => '#da70d6',
153
palegoldenrod => '#eee8aa',
154
palegreen => '#98fb98',
155
paleturquoise => '#afeeee',
156
palevioletred => '#db7093',
157
papayawhip => '#ffefd5',
158
peachpuff => '#ffdab9',
159
peru => '#cd853f',
160
pink => '#ffc0cb',
161
plum => '#dda0dd',
162
powderblue => '#b0e0e6',
163
purple => '#800080',
164
red => '#ff0000',
165
rosybrown => '#bc8f8f',
166
royalblue => '#4169e1',
167
saddlebrown => '#8b4513',
168
salmon => '#fa8072',
169
sandybrown => '#f4a460',
170
seagreen => '#2e8b57',
171
seashell => '#fff5ee',
172
sienna => '#a0522d',
173
silver => '#c0c0c0',
174
skyblue => '#87ceeb',
175
slateblue => '#6a5acd',
176
slategray => '#708090',
177
slategrey => '#708090',
178
snow => '#fffafa',
179
springgreen => '#00ff7f',
180
steelblue => '#4682b4',
181
tan => '#d2b48c',
182
teal => '#008080',
183
thistle => '#d8bfd8',
184
tomato => '#ff6347',
185
turquoise => '#40e0d0',
186
violet => '#ee82ee',
187
wheat => '#f5deb3',
188
white => '#ffffff',
189
whitesmoke => '#f5f5f5',
190
yellowgreen => '#9acd32',
191
yellow => '#ffff00',
192
},
193
194
x11 => {
195
inherit => 'inherit',
196
aliceblue => '#f0f8ff',
197
antiquewhite => '#faebd7',
198
antiquewhite1 => '#ffefdb',
199
antiquewhite2 => '#eedfcc',
200
antiquewhite3 => '#cdc0b0',
201
antiquewhite4 => '#8b8378',
202
aquamarine => '#7fffd4',
203
aquamarine1 => '#7fffd4',
204
aquamarine2 => '#76eec6',
205
aquamarine3 => '#66cdaa',
206
aquamarine4 => '#458b74',
207
azure => '#f0ffff',
208
azure1 => '#f0ffff',
209
azure2 => '#e0eeee',
210
azure3 => '#c1cdcd',
211
azure4 => '#838b8b',
212
beige => '#f5f5dc',
213
bisque => '#ffe4c4',
214
bisque1 => '#ffe4c4',
215
bisque2 => '#eed5b7',
216
bisque3 => '#cdb79e',
217
bisque4 => '#8b7d6b',
218
black => '#000000',
219
blanchedalmond => '#ffebcd',
220
blue => '#0000ff',
221
blue1 => '#0000ff',
222
blue2 => '#0000ee',
223
blue3 => '#0000cd',
224
blue4 => '#00008b',
225
blueviolet => '#8a2be2',
226
brown => '#a52a2a',
227
brown1 => '#ff4040',
228
brown2 => '#ee3b3b',
229
brown3 => '#cd3333',
230
brown4 => '#8b2323',
231
burlywood => '#deb887',
232
burlywood1 => '#ffd39b',
233
burlywood2 => '#eec591',
234
burlywood3 => '#cdaa7d',
235
burlywood4 => '#8b7355',
236
cadetblue => '#5f9ea0',
237
cadetblue1 => '#98f5ff',
238
cadetblue2 => '#8ee5ee',
239
cadetblue3 => '#7ac5cd',
240
cadetblue4 => '#53868b',
241
chartreuse => '#7fff00',
242
chartreuse1 => '#7fff00',
243
chartreuse2 => '#76ee00',
244
chartreuse3 => '#66cd00',
245
chartreuse4 => '#458b00',
246
chocolate => '#d2691e',
247
chocolate1 => '#ff7f24',
248
chocolate2 => '#ee7621',
249
chocolate3 => '#cd661d',
250
chocolate4 => '#8b4513',
251
coral => '#ff7f50',
252
coral1 => '#ff7256',
253
coral2 => '#ee6a50',
254
coral3 => '#cd5b45',
255
coral4 => '#8b3e2f',
256
cornflowerblue => '#6495ed',
257
cornsilk => '#fff8dc',
258
cornsilk1 => '#fff8dc',
259
cornsilk2 => '#eee8cd',
260
cornsilk3 => '#cdc8b1',
261
cornsilk4 => '#8b8878',
262
crimson => '#dc143c',
263
cyan => '#00ffff',
264
cyan1 => '#00ffff',
265
cyan2 => '#00eeee',
266
cyan3 => '#00cdcd',
267
cyan4 => '#008b8b',
268
darkgoldenrod => '#b8860b',
269
darkgoldenrod1 => '#ffb90f',
270
darkgoldenrod2 => '#eead0e',
271
darkgoldenrod3 => '#cd950c',
272
darkgoldenrod4 => '#8b6508',
273
darkgreen => '#006400',
274
darkkhaki => '#bdb76b',
275
darkolivegreen => '#556b2f',
276
darkolivegreen1 => '#caff70',
277
darkolivegreen2 => '#bcee68',
278
darkolivegreen3 => '#a2cd5a',
279
darkolivegreen4 => '#6e8b3d',
280
darkorange => '#ff8c00',
281
darkorange1 => '#ff7f00',
282
darkorange2 => '#ee7600',
283
darkorange3 => '#cd6600',
284
darkorange4 => '#8b4500',
285
darkorchid => '#9932cc',
286
darkorchid1 => '#bf3eff',
287
darkorchid2 => '#b23aee',
288
darkorchid3 => '#9a32cd',
289
darkorchid4 => '#68228b',
290
darksalmon => '#e9967a',
291
darkseagreen => '#8fbc8f',
292
darkseagreen1 => '#c1ffc1',
293
darkseagreen2 => '#b4eeb4',
294
darkseagreen3 => '#9bcd9b',
295
darkseagreen4 => '#698b69',
296
darkslateblue => '#483d8b',
297
darkslategray => '#2f4f4f',
298
darkslategray1 => '#97ffff',
299
darkslategray2 => '#8deeee',
300
darkslategray3 => '#79cdcd',
301
darkslategray4 => '#528b8b',
302
darkslategrey => '#2f4f4f',
303
darkturquoise => '#00ced1',
304
darkviolet => '#9400d3',
305
deeppink => '#ff1493',
306
deeppink1 => '#ff1493',
307
deeppink2 => '#ee1289',
308
deeppink3 => '#cd1076',
309
deeppink4 => '#8b0a50',
310
deepskyblue => '#00bfff',
311
deepskyblue1 => '#00bfff',
312
deepskyblue2 => '#00b2ee',
313
deepskyblue3 => '#009acd',
314
deepskyblue4 => '#00688b',
315
dimgray => '#696969',
316
dimgrey => '#696969',
317
dodgerblue => '#1e90ff',
318
dodgerblue1 => '#1e90ff',
319
dodgerblue2 => '#1c86ee',
320
dodgerblue3 => '#1874cd',
321
dodgerblue4 => '#104e8b',
322
firebrick => '#b22222',
323
firebrick1 => '#ff3030',
324
firebrick2 => '#ee2c2c',
325
firebrick3 => '#cd2626',
326
firebrick4 => '#8b1a1a',
327
floralwhite => '#fffaf0',
328
forestgreen => '#228b22',
329
gainsboro => '#dcdcdc',
330
ghostwhite => '#f8f8ff',
331
gold => '#ffd700',
332
gold1 => '#ffd700',
333
gold2 => '#eec900',
334
gold3 => '#cdad00',
335
gold4 => '#8b7500',
336
goldenrod => '#daa520',
337
goldenrod1 => '#ffc125',
338
goldenrod2 => '#eeb422',
339
goldenrod3 => '#cd9b1d',
340
goldenrod4 => '#8b6914',
341
gray => '#c0c0c0',
342
gray0 => '#000000',
343
gray1 => '#030303',
344
gray2 => '#050505',
345
gray3 => '#080808',
346
gray4 => '#0a0a0a',
347
gray5 => '#0d0d0d',
348
gray6 => '#0f0f0f',
349
gray7 => '#121212',
350
gray8 => '#141414',
351
gray9 => '#171717',
352
gray10 => '#1a1a1a',
353
gray11 => '#1c1c1c',
354
gray12 => '#1f1f1f',
355
gray13 => '#212121',
356
gray14 => '#242424',
357
gray15 => '#262626',
358
gray16 => '#292929',
359
gray17 => '#2b2b2b',
360
gray18 => '#2e2e2e',
361
gray19 => '#303030',
362
gray20 => '#333333',
363
gray21 => '#363636',
364
gray22 => '#383838',
365
gray23 => '#3b3b3b',
366
gray24 => '#3d3d3d',
367
gray25 => '#404040',
368
gray26 => '#424242',
369
gray27 => '#454545',
370
gray28 => '#474747',
371
gray29 => '#4a4a4a',
372
gray30 => '#4d4d4d',
373
gray31 => '#4f4f4f',
374
gray32 => '#525252',
375
gray33 => '#545454',
376
gray34 => '#575757',
377
gray35 => '#595959',
378
gray36 => '#5c5c5c',
379
gray37 => '#5e5e5e',
380
gray38 => '#616161',
381
gray39 => '#636363',
382
gray40 => '#666666',
383
gray41 => '#696969',
384
gray42 => '#6b6b6b',
385
gray43 => '#6e6e6e',
386
gray44 => '#707070',
387
gray45 => '#737373',
388
gray46 => '#757575',
389
gray47 => '#787878',
390
gray48 => '#7a7a7a',
391
gray49 => '#7d7d7d',
392
gray50 => '#7f7f7f',
393
gray51 => '#828282',
394
gray52 => '#858585',
395
gray53 => '#878787',
396
gray54 => '#8a8a8a',
397
gray55 => '#8c8c8c',
398
gray56 => '#8f8f8f',
399
gray57 => '#919191',
400
gray58 => '#949494',
401
gray59 => '#969696',
402
gray60 => '#999999',
403
gray61 => '#9c9c9c',
404
gray62 => '#9e9e9e',
405
gray63 => '#a1a1a1',
406
gray64 => '#a3a3a3',
407
gray65 => '#a6a6a6',
408
gray66 => '#a8a8a8',
409
gray67 => '#ababab',
410
gray68 => '#adadad',
411
gray69 => '#b0b0b0',
412
gray70 => '#b3b3b3',
413
gray71 => '#b5b5b5',
414
gray72 => '#b8b8b8',
415
gray73 => '#bababa',
416
gray74 => '#bdbdbd',
417
gray75 => '#bfbfbf',
418
gray76 => '#c2c2c2',
419
gray77 => '#c4c4c4',
420
gray78 => '#c7c7c7',
421
gray79 => '#c9c9c9',
422
gray80 => '#cccccc',
423
gray81 => '#cfcfcf',
424
gray82 => '#d1d1d1',
425
gray83 => '#d4d4d4',
426
gray84 => '#d6d6d6',
427
gray85 => '#d9d9d9',
428
gray86 => '#dbdbdb',
429
gray87 => '#dedede',
430
gray88 => '#e0e0e0',
431
gray89 => '#e3e3e3',
432
gray90 => '#e5e5e5',
433
gray91 => '#e8e8e8',
434
gray92 => '#ebebeb',
435
gray93 => '#ededed',
436
gray94 => '#f0f0f0',
437
gray95 => '#f2f2f2',
438
gray96 => '#f5f5f5',
439
gray97 => '#f7f7f7',
440
gray98 => '#fafafa',
441
gray99 => '#fcfcfc',
442
gray100 => '#ffffff',
443
green => '#00ff00',
444
green1 => '#00ff00',
445
green2 => '#00ee00',
446
green3 => '#00cd00',
447
green4 => '#008b00',
448
greenyellow => '#adff2f',
449
grey => '#c0c0c0',
450
grey0 => '#000000',
451
grey1 => '#030303',
452
grey2 => '#050505',
453
grey3 => '#080808',
454
grey4 => '#0a0a0a',
455
grey5 => '#0d0d0d',
456
grey6 => '#0f0f0f',
457
grey7 => '#121212',
458
grey8 => '#141414',
459
grey9 => '#171717',
460
grey10 => '#1a1a1a',
461
grey11 => '#1c1c1c',
462
grey12 => '#1f1f1f',
463
grey13 => '#212121',
464
grey14 => '#242424',
465
grey15 => '#262626',
466
grey16 => '#292929',
467
grey17 => '#2b2b2b',
468
grey18 => '#2e2e2e',
469
grey19 => '#303030',
470
grey20 => '#333333',
471
grey21 => '#363636',
472
grey22 => '#383838',
473
grey23 => '#3b3b3b',
474
grey24 => '#3d3d3d',
475
grey25 => '#404040',
476
grey26 => '#424242',
477
grey27 => '#454545',
478
grey28 => '#474747',
479
grey29 => '#4a4a4a',
480
grey30 => '#4d4d4d',
481
grey31 => '#4f4f4f',
482
grey32 => '#525252',
483
grey33 => '#545454',
484
grey34 => '#575757',
485
grey35 => '#595959',
486
grey36 => '#5c5c5c',
487
grey37 => '#5e5e5e',
488
grey38 => '#616161',
489
grey39 => '#636363',
490
grey40 => '#666666',
491
grey41 => '#696969',
492
grey42 => '#6b6b6b',
493
grey43 => '#6e6e6e',
494
grey44 => '#707070',
495
grey45 => '#737373',
496
grey46 => '#757575',
497
grey47 => '#787878',
498
grey48 => '#7a7a7a',
499
grey49 => '#7d7d7d',
500
grey50 => '#7f7f7f',
501
grey51 => '#828282',
502
grey52 => '#858585',
503
grey53 => '#878787',
504
grey54 => '#8a8a8a',
505
grey55 => '#8c8c8c',
506
grey56 => '#8f8f8f',
507
grey57 => '#919191',
508
grey58 => '#949494',
509
grey59 => '#969696',
510
grey60 => '#999999',
511
grey61 => '#9c9c9c',
512
grey62 => '#9e9e9e',
513
grey63 => '#a1a1a1',
514
grey64 => '#a3a3a3',
515
grey65 => '#a6a6a6',
516
grey66 => '#a8a8a8',
517
grey67 => '#ababab',
518
grey68 => '#adadad',
519
grey69 => '#b0b0b0',
520
grey70 => '#b3b3b3',
521
grey71 => '#b5b5b5',
522
grey72 => '#b8b8b8',
523
grey73 => '#bababa',
524
grey74 => '#bdbdbd',
525
grey75 => '#bfbfbf',
526
grey76 => '#c2c2c2',
527
grey77 => '#c4c4c4',
528
grey78 => '#c7c7c7',
529
grey79 => '#c9c9c9',
530
grey80 => '#cccccc',
531
grey81 => '#cfcfcf',
532
grey82 => '#d1d1d1',
533
grey83 => '#d4d4d4',
534
grey84 => '#d6d6d6',
535
grey85 => '#d9d9d9',
536
grey86 => '#dbdbdb',
537
grey87 => '#dedede',
538
grey88 => '#e0e0e0',
539
grey89 => '#e3e3e3',
540
grey90 => '#e5e5e5',
541
grey91 => '#e8e8e8',
542
grey92 => '#ebebeb',
543
grey93 => '#ededed',
544
grey94 => '#f0f0f0',
545
grey95 => '#f2f2f2',
546
grey96 => '#f5f5f5',
547
grey97 => '#f7f7f7',
548
grey98 => '#fafafa',
549
grey99 => '#fcfcfc',
550
grey100 => '#ffffff',
551
honeydew => '#f0fff0',
552
honeydew1 => '#f0fff0',
553
honeydew2 => '#e0eee0',
554
honeydew3 => '#c1cdc1',
555
honeydew4 => '#838b83',
556
hotpink => '#ff69b4',
557
hotpink1 => '#ff6eb4',
558
hotpink2 => '#ee6aa7',
559
hotpink3 => '#cd6090',
560
hotpink4 => '#8b3a62',
561
indianred => '#cd5c5c',
562
indianred1 => '#ff6a6a',
563
indianred2 => '#ee6363',
564
indianred3 => '#cd5555',
565
indianred4 => '#8b3a3a',
566
indigo => '#4b0082',
567
ivory => '#fffff0',
568
ivory1 => '#fffff0',
569
ivory2 => '#eeeee0',
570
ivory3 => '#cdcdc1',
571
ivory4 => '#8b8b83',
572
khaki => '#f0e68c',
573
khaki1 => '#fff68f',
574
khaki2 => '#eee685',
575
khaki3 => '#cdc673',
576
khaki4 => '#8b864e',
577
lavender => '#e6e6fa',
578
lavenderblush => '#fff0f5',
579
lavenderblush1 => '#fff0f5',
580
lavenderblush2 => '#eee0e5',
581
lavenderblush3 => '#cdc1c5',
582
lavenderblush4 => '#8b8386',
583
lawngreen => '#7cfc00',
584
lemonchiffon => '#fffacd',
585
lemonchiffon1 => '#fffacd',
586
lemonchiffon2 => '#eee9bf',
587
lemonchiffon3 => '#cdc9a5',
588
lemonchiffon4 => '#8b8970',
589
lightblue => '#add8e6',
590
lightblue1 => '#bfefff',
591
lightblue2 => '#b2dfee',
592
lightblue3 => '#9ac0cd',
593
lightblue4 => '#68838b',
594
lightcoral => '#f08080',
595
lightcyan => '#e0ffff',
596
lightcyan1 => '#e0ffff',
597
lightcyan2 => '#d1eeee',
598
lightcyan3 => '#b4cdcd',
599
lightcyan4 => '#7a8b8b',
600
lightgoldenrod => '#eedd82',
601
lightgoldenrod1 => '#ffec8b',
602
lightgoldenrod2 => '#eedc82',
603
lightgoldenrod3 => '#cdbe70',
604
lightgoldenrod4 => '#8b814c',
605
lightgoldenrodyellow => '#fafad2',
606
lightgray => '#d3d3d3',
607
lightgrey => '#d3d3d3',
608
lightpink => '#ffb6c1',
609
lightpink1 => '#ffaeb9',
610
lightpink2 => '#eea2ad',
611
lightpink3 => '#cd8c95',
612
lightpink4 => '#8b5f65',
613
lightsalmon => '#ffa07a',
614
lightsalmon1 => '#ffa07a',
615
lightsalmon2 => '#ee9572',
616
lightsalmon3 => '#cd8162',
617
lightsalmon4 => '#8b5742',
618
lightseagreen => '#20b2aa',
619
lightskyblue => '#87cefa',
620
lightskyblue1 => '#b0e2ff',
621
lightskyblue2 => '#a4d3ee',
622
lightskyblue3 => '#8db6cd',
623
lightskyblue4 => '#607b8b',
624
lightslateblue => '#8470ff',
625
lightslategray => '#778899',
626
lightslategrey => '#778899',
627
lightsteelblue => '#b0c4de',
628
lightsteelblue1 => '#cae1ff',
629
lightsteelblue2 => '#bcd2ee',
630
lightsteelblue3 => '#a2b5cd',
631
lightsteelblue4 => '#6e7b8b',
632
lightyellow => '#ffffe0',
633
lightyellow1 => '#ffffe0',
634
lightyellow2 => '#eeeed1',
635
lightyellow3 => '#cdcdb4',
636
lightyellow4 => '#8b8b7a',
637
limegreen => '#32cd32',
638
linen => '#faf0e6',
639
magenta => '#ff00ff',
640
magenta1 => '#ff00ff',
641
magenta2 => '#ee00ee',
642
magenta3 => '#cd00cd',
643
magenta4 => '#8b008b',
644
maroon => '#b03060',
645
maroon1 => '#ff34b3',
646
maroon2 => '#ee30a7',
647
maroon3 => '#cd2990',
648
maroon4 => '#8b1c62',
649
mediumaquamarine => '#66cdaa',
650
mediumblue => '#0000cd',
651
mediumorchid => '#ba55d3',
652
mediumorchid1 => '#e066ff',
653
mediumorchid2 => '#d15fee',
654
mediumorchid3 => '#b452cd',
655
mediumorchid4 => '#7a378b',
656
mediumpurple => '#9370db',
657
mediumpurple1 => '#ab82ff',
658
mediumpurple2 => '#9f79ee',
659
mediumpurple3 => '#8968cd',
660
mediumpurple4 => '#5d478b',
661
mediumseagreen => '#3cb371',
662
mediumslateblue => '#7b68ee',
663
mediumspringgreen => '#00fa9a',
664
mediumturquoise => '#48d1cc',
665
mediumvioletred => '#c71585',
666
midnightblue => '#191970',
667
mintcream => '#f5fffa',
668
mistyrose => '#ffe4e1',
669
mistyrose1 => '#ffe4e1',
670
mistyrose2 => '#eed5d2',
671
mistyrose3 => '#cdb7b5',
672
mistyrose4 => '#8b7d7b',
673
moccasin => '#ffe4b5',
674
navajowhite => '#ffdead',
675
navajowhite1 => '#ffdead',
676
navajowhite2 => '#eecfa1',
677
navajowhite3 => '#cdb38b',
678
navajowhite4 => '#8b795e',
679
navy => '#000080',
680
navyblue => '#000080',
681
oldlace => '#fdf5e6',
682
olivedrab => '#6b8e23',
683
olivedrab1 => '#c0ff3e',
684
olivedrab2 => '#b3ee3a',
685
olivedrab3 => '#9acd32',
686
olivedrab4 => '#698b22',
687
orange => '#ffa500',
688
orange1 => '#ffa500',
689
orange2 => '#ee9a00',
690
orange3 => '#cd8500',
691
orange4 => '#8b5a00',
692
orangered => '#ff4500',
693
orangered1 => '#ff4500',
694
orangered2 => '#ee4000',
695
orangered3 => '#cd3700',
696
orangered4 => '#8b2500',
697
orchid => '#da70d6',
698
orchid1 => '#ff83fa',
699
orchid2 => '#ee7ae9',
700
orchid3 => '#cd69c9',
701
orchid4 => '#8b4789',
702
palegoldenrod => '#eee8aa',
703
palegreen => '#98fb98',
704
palegreen1 => '#9aff9a',
705
palegreen2 => '#90ee90',
706
palegreen3 => '#7ccd7c',
707
palegreen4 => '#548b54',
708
paleturquoise => '#afeeee',
709
paleturquoise1 => '#bbffff',
710
paleturquoise2 => '#aeeeee',
711
paleturquoise3 => '#96cdcd',
712
paleturquoise4 => '#668b8b',
713
palevioletred => '#db7093',
714
palevioletred1 => '#ff82ab',
715
palevioletred2 => '#ee799f',
716
palevioletred3 => '#cd6889',
717
palevioletred4 => '#8b475d',
718
papayawhip => '#ffefd5',
719
peachpuff => '#ffdab9',
720
peachpuff1 => '#ffdab9',
721
peachpuff2 => '#eecbad',
722
peachpuff3 => '#cdaf95',
723
peachpuff4 => '#8b7765',
724
peru => '#cd853f',
725
pink => '#ffc0cb',
726
pink1 => '#ffb5c5',
727
pink2 => '#eea9b8',
728
pink3 => '#cd919e',
729
pink4 => '#8b636c',
730
plum => '#dda0dd',
731
plum1 => '#ffbbff',
732
plum2 => '#eeaeee',
733
plum3 => '#cd96cd',
734
plum4 => '#8b668b',
735
powderblue => '#b0e0e6',
736
purple => '#a020f0',
737
purple1 => '#9b30ff',
738
purple2 => '#912cee',
739
purple3 => '#7d26cd',
740
purple4 => '#551a8b',
741
red => '#ff0000',
742
red1 => '#ff0000',
743
red2 => '#ee0000',
744
red3 => '#cd0000',
745
red4 => '#8b0000',
746
rosybrown => '#bc8f8f',
747
rosybrown1 => '#ffc1c1',
748
rosybrown2 => '#eeb4b4',
749
rosybrown3 => '#cd9b9b',
750
rosybrown4 => '#8b6969',
751
royalblue => '#4169e1',
752
royalblue1 => '#4876ff',
753
royalblue2 => '#436eee',
754
royalblue3 => '#3a5fcd',
755
royalblue4 => '#27408b',
756
saddlebrown => '#8b4513',
757
salmon => '#fa8072',
758
salmon1 => '#ff8c69',
759
salmon2 => '#ee8262',
760
salmon3 => '#cd7054',
761
salmon4 => '#8b4c39',
762
sandybrown => '#f4a460',
763
seagreen => '#2e8b57',
764
seagreen1 => '#54ff9f',
765
seagreen2 => '#4eee94',
766
seagreen3 => '#43cd80',
767
seagreen4 => '#2e8b57',
768
seashell => '#fff5ee',
769
seashell1 => '#fff5ee',
770
seashell2 => '#eee5de',
771
seashell3 => '#cdc5bf',
772
seashell4 => '#8b8682',
773
sienna => '#a0522d',
774
sienna1 => '#ff8247',
775
sienna2 => '#ee7942',
776
sienna3 => '#cd6839',
777
sienna4 => '#8b4726',
778
skyblue => '#87ceeb',
779
skyblue1 => '#87ceff',
780
skyblue2 => '#7ec0ee',
781
skyblue3 => '#6ca6cd',
782
skyblue4 => '#4a708b',
783
slateblue => '#6a5acd',
784
slateblue1 => '#836fff',
785
slateblue2 => '#7a67ee',
786
slateblue3 => '#6959cd',
787
slateblue4 => '#473c8b',
788
slategray => '#708090',
789
slategray1 => '#c6e2ff',
790
slategray2 => '#b9d3ee',
791
slategray3 => '#9fb6cd',
792
slategray4 => '#6c7b8b',
793
slategrey => '#708090',
794
snow => '#fffafa',
795
snow1 => '#fffafa',
796
snow2 => '#eee9e9',
797
snow3 => '#cdc9c9',
798
snow4 => '#8b8989',
799
springgreen => '#00ff7f',
800
springgreen1 => '#00ff7f',
801
springgreen2 => '#00ee76',
802
springgreen3 => '#00cd66',
803
springgreen4 => '#008b45',
804
steelblue => '#4682b4',
805
steelblue1 => '#63b8ff',
806
steelblue2 => '#5cacee',
807
steelblue3 => '#4f94cd',
808
steelblue4 => '#36648b',
809
tan => '#d2b48c',
810
tan1 => '#ffa54f',
811
tan2 => '#ee9a49',
812
tan3 => '#cd853f',
813
tan4 => '#8b5a2b',
814
thistle => '#d8bfd8',
815
thistle1 => '#ffe1ff',
816
thistle2 => '#eed2ee',
817
thistle3 => '#cdb5cd',
818
thistle4 => '#8b7b8b',
819
tomato => '#ff6347',
820
tomato1 => '#ff6347',
821
tomato2 => '#ee5c42',
822
tomato3 => '#cd4f39',
823
tomato4 => '#8b3626',
824
transparent => '#fffffe',
825
turquoise => '#40e0d0',
826
turquoise1 => '#00f5ff',
827
turquoise2 => '#00e5ee',
828
turquoise3 => '#00c5cd',
829
turquoise4 => '#00868b',
830
violet => '#ee82ee',
831
violetred => '#d02090',
832
violetred1 => '#ff3e96',
833
violetred2 => '#ee3a8c',
834
violetred3 => '#cd3278',
835
violetred4 => '#8b2252',
836
wheat => '#f5deb3',
837
wheat1 => '#ffe7ba',
838
wheat2 => '#eed8ae',
839
wheat3 => '#cdba96',
840
wheat4 => '#8b7e66',
841
white => '#ffffff',
842
whitesmoke => '#f5f5f5',
843
yellow => '#ffff00',
844
yellow1 => '#ffff00',
845
yellow2 => '#eeee00',
846
yellow3 => '#cdcd00',
847
yellow4 => '#8b8b00',
848
yellowgreen => '#9acd32',
849
# The following 12 colors exist here so that a "color: 3; colorscheme: accent3"
850
# will not report an "unknown color 3" from the Parser. As a side-effect
851
# you will not get an error for a plain "color: 3".
852
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
853
5 => '#fb9a99', 6 => '#e31a1c', 7 => '#fdbf6f', 8 => '#ff7f00',
854
9 => '#cab2d6', 10 => '#6a3d9a', 11 => '#ffff99', 12 => '#b15928',
855
},
856
# The following color specifications were developed by:
857
# Cynthia Brewer (http://colorbrewer.org/)
858
# See the LICENSE FILE for the full license that applies to them.
859
860
accent3 => {
861
1 => '#7fc97f', 2 => '#beaed4', 3 => '#fdc086',
862
},
863
accent4 => {
864
1 => '#7fc97f', 2 => '#beaed4', 3 => '#fdc086', 4 => '#ffff99',
865
},
866
accent5 => {
867
1 => '#7fc97f', 2 => '#beaed4', 3 => '#fdc086', 4 => '#ffff99',
868
5 => '#386cb0',
869
},
870
accent6 => {
871
1 => '#7fc97f', 2 => '#beaed4', 3 => '#fdc086', 4 => '#ffff99',
872
5 => '#386cb0', 6 => '#f0027f',
873
},
874
accent7 => {
875
1 => '#7fc97f', 2 => '#beaed4', 3 => '#fdc086', 4 => '#ffff99',
876
5 => '#386cb0', 6 => '#f0027f', 7 => '#bf5b17',
877
},
878
accent8 => {
879
1 => '#7fc97f', 2 => '#beaed4', 3 => '#fdc086', 4 => '#ffff99',
880
5 => '#386cb0', 6 => '#f0027f', 7 => '#bf5b17', 8 => '#666666',
881
},
882
blues3 => {
883
1 => '#deebf7', 2 => '#9ecae1', 3 => '#3182bd',
884
},
885
blues4 => {
886
1 => '#eff3ff', 2 => '#bdd7e7', 3 => '#6baed6', 4 => '#2171b5',
887
},
888
blues5 => {
889
1 => '#eff3ff', 2 => '#bdd7e7', 3 => '#6baed6', 4 => '#3182bd',
890
5 => '#08519c',
891
},
892
blues6 => {
893
1 => '#eff3ff', 2 => '#c6dbef', 3 => '#9ecae1', 4 => '#6baed6',
894
5 => '#3182bd', 6 => '#08519c',
895
},
896
blues7 => {
897
1 => '#eff3ff', 2 => '#c6dbef', 3 => '#9ecae1', 4 => '#6baed6',
898
5 => '#4292c6', 6 => '#2171b5', 7 => '#084594',
899
},
900
blues8 => {
901
1 => '#f7fbff', 2 => '#deebf7', 3 => '#c6dbef', 4 => '#9ecae1',
902
5 => '#6baed6', 6 => '#4292c6', 7 => '#2171b5', 8 => '#084594',
903
},
904
blues9 => {
905
1 => '#f7fbff', 2 => '#deebf7', 3 => '#c6dbef', 4 => '#9ecae1',
906
5 => '#6baed6', 6 => '#4292c6', 7 => '#2171b5', 8 => '#08519c',
907
9 => '#08306b',
908
},
909
brbg3 => {
910
1 => '#d8b365', 2 => '#f5f5f5', 3 => '#5ab4ac',
911
},
912
brbg4 => {
913
1 => '#a6611a', 2 => '#dfc27d', 3 => '#80cdc1', 4 => '#018571',
914
},
915
brbg5 => {
916
1 => '#a6611a', 2 => '#dfc27d', 3 => '#f5f5f5', 4 => '#80cdc1',
917
5 => '#018571',
918
},
919
brbg6 => {
920
1 => '#8c510a', 2 => '#d8b365', 3 => '#f6e8c3', 4 => '#c7eae5',
921
5 => '#5ab4ac', 6 => '#01665e',
922
},
923
brbg7 => {
924
1 => '#8c510a', 2 => '#d8b365', 3 => '#f6e8c3', 4 => '#f5f5f5',
925
5 => '#c7eae5', 6 => '#5ab4ac', 7 => '#01665e',
926
},
927
brbg8 => {
928
1 => '#8c510a', 2 => '#bf812d', 3 => '#dfc27d', 4 => '#f6e8c3',
929
5 => '#c7eae5', 6 => '#80cdc1', 7 => '#35978f', 8 => '#01665e',
930
},
931
brbg9 => {
932
1 => '#8c510a', 2 => '#bf812d', 3 => '#dfc27d', 4 => '#f6e8c3',
933
5 => '#f5f5f5', 6 => '#c7eae5', 7 => '#80cdc1', 8 => '#35978f',
934
9 => '#01665e',
935
},
936
brbg10 => {
937
1 => '#543005', 2 => '#8c510a', 3 => '#bf812d', 4 => '#dfc27d',
938
5 => '#f6e8c3', 6 => '#c7eae5', 7 => '#80cdc1', 8 => '#35978f',
939
9 => '#01665e', 10 => '#003c30',
940
},
941
brbg11 => {
942
1 => '#543005', 2 => '#8c510a', 3 => '#bf812d', 4 => '#dfc27d',
943
5 => '#f6e8c3', 6 => '#f5f5f5', 7 => '#c7eae5', 8 => '#80cdc1',
944
9 => '#35978f', 10 => '#01665e', 11 => '#003c30',
945
},
946
bugn3 => {
947
1 => '#e5f5f9', 2 => '#99d8c9', 3 => '#2ca25f',
948
},
949
bugn4 => {
950
1 => '#edf8fb', 2 => '#b2e2e2', 3 => '#66c2a4', 4 => '#238b45',
951
},
952
bugn5 => {
953
1 => '#edf8fb', 2 => '#b2e2e2', 3 => '#66c2a4', 4 => '#2ca25f',
954
5 => '#006d2c',
955
},
956
bugn6 => {
957
1 => '#edf8fb', 2 => '#ccece6', 3 => '#99d8c9', 4 => '#66c2a4',
958
5 => '#2ca25f', 6 => '#006d2c',
959
},
960
bugn7 => {
961
1 => '#edf8fb', 2 => '#ccece6', 3 => '#99d8c9', 4 => '#66c2a4',
962
5 => '#41ae76', 6 => '#238b45', 7 => '#005824',
963
},
964
bugn8 => {
965
1 => '#f7fcfd', 2 => '#e5f5f9', 3 => '#ccece6', 4 => '#99d8c9',
966
5 => '#66c2a4', 6 => '#41ae76', 7 => '#238b45', 8 => '#005824',
967
},
968
bugn9 => {
969
1 => '#f7fcfd', 2 => '#e5f5f9', 3 => '#ccece6', 4 => '#99d8c9',
970
5 => '#66c2a4', 6 => '#41ae76', 7 => '#238b45', 8 => '#006d2c',
971
9 => '#00441b',
972
},
973
bupu3 => {
974
1 => '#e0ecf4', 2 => '#9ebcda', 3 => '#8856a7',
975
},
976
bupu4 => {
977
1 => '#edf8fb', 2 => '#b3cde3', 3 => '#8c96c6', 4 => '#88419d',
978
},
979
bupu5 => {
980
1 => '#edf8fb', 2 => '#b3cde3', 3 => '#8c96c6', 4 => '#8856a7',
981
5 => '#810f7c',
982
},
983
bupu6 => {
984
1 => '#edf8fb', 2 => '#bfd3e6', 3 => '#9ebcda', 4 => '#8c96c6',
985
5 => '#8856a7', 6 => '#810f7c',
986
},
987
bupu7 => {
988
1 => '#edf8fb', 2 => '#bfd3e6', 3 => '#9ebcda', 4 => '#8c96c6',
989
5 => '#8c6bb1', 6 => '#88419d', 7 => '#6e016b',
990
},
991
bupu8 => {
992
1 => '#f7fcfd', 2 => '#e0ecf4', 3 => '#bfd3e6', 4 => '#9ebcda',
993
5 => '#8c96c6', 6 => '#8c6bb1', 7 => '#88419d', 8 => '#6e016b',
994
},
995
bupu9 => {
996
1 => '#f7fcfd', 2 => '#e0ecf4', 3 => '#bfd3e6', 4 => '#9ebcda',
997
5 => '#8c96c6', 6 => '#8c6bb1', 7 => '#88419d', 8 => '#810f7c',
998
9 => '#4d004b',
999
},
1000
dark23 => {
1001
1 => '#1b9e77', 2 => '#d95f02', 3 => '#7570b3',
1002
},
1003
dark24 => {
1004
1 => '#1b9e77', 2 => '#d95f02', 3 => '#7570b3', 4 => '#e7298a',
1005
},
1006
dark25 => {
1007
1 => '#1b9e77', 2 => '#d95f02', 3 => '#7570b3', 4 => '#e7298a',
1008
5 => '#66a61e',
1009
},
1010
dark26 => {
1011
1 => '#1b9e77', 2 => '#d95f02', 3 => '#7570b3', 4 => '#e7298a',
1012
5 => '#66a61e', 6 => '#e6ab02',
1013
},
1014
dark27 => {
1015
1 => '#1b9e77', 2 => '#d95f02', 3 => '#7570b3', 4 => '#e7298a',
1016
5 => '#66a61e', 6 => '#e6ab02', 7 => '#a6761d',
1017
},
1018
dark28 => {
1019
1 => '#1b9e77', 2 => '#d95f02', 3 => '#7570b3', 4 => '#e7298a',
1020
5 => '#66a61e', 6 => '#e6ab02', 7 => '#a6761d', 8 => '#666666',
1021
},
1022
gnbu3 => {
1023
1 => '#e0f3db', 2 => '#a8ddb5', 3 => '#43a2ca',
1024
},
1025
gnbu4 => {
1026
1 => '#f0f9e8', 2 => '#bae4bc', 3 => '#7bccc4', 4 => '#2b8cbe',
1027
},
1028
gnbu5 => {
1029
1 => '#f0f9e8', 2 => '#bae4bc', 3 => '#7bccc4', 4 => '#43a2ca',
1030
5 => '#0868ac',
1031
},
1032
gnbu6 => {
1033
1 => '#f0f9e8', 2 => '#ccebc5', 3 => '#a8ddb5', 4 => '#7bccc4',
1034
5 => '#43a2ca', 6 => '#0868ac',
1035
},
1036
gnbu7 => {
1037
1 => '#f0f9e8', 2 => '#ccebc5', 3 => '#a8ddb5', 4 => '#7bccc4',
1038
5 => '#4eb3d3', 6 => '#2b8cbe', 7 => '#08589e',
1039
},
1040
gnbu8 => {
1041
1 => '#f7fcf0', 2 => '#e0f3db', 3 => '#ccebc5', 4 => '#a8ddb5',
1042
5 => '#7bccc4', 6 => '#4eb3d3', 7 => '#2b8cbe', 8 => '#08589e',
1043
},
1044
gnbu9 => {
1045
1 => '#f7fcf0', 2 => '#e0f3db', 3 => '#ccebc5', 4 => '#a8ddb5',
1046
5 => '#7bccc4', 6 => '#4eb3d3', 7 => '#2b8cbe', 8 => '#0868ac',
1047
9 => '#084081',
1048
},
1049
greens3 => {
1050
1 => '#e5f5e0', 2 => '#a1d99b', 3 => '#31a354',
1051
},
1052
greens4 => {
1053
1 => '#edf8e9', 2 => '#bae4b3', 3 => '#74c476', 4 => '#238b45',
1054
},
1055
greens5 => {
1056
1 => '#edf8e9', 2 => '#bae4b3', 3 => '#74c476', 4 => '#31a354',
1057
5 => '#006d2c',
1058
},
1059
greens6 => {
1060
1 => '#edf8e9', 2 => '#c7e9c0', 3 => '#a1d99b', 4 => '#74c476',
1061
5 => '#31a354', 6 => '#006d2c',
1062
},
1063
greens7 => {
1064
1 => '#edf8e9', 2 => '#c7e9c0', 3 => '#a1d99b', 4 => '#74c476',
1065
5 => '#41ab5d', 6 => '#238b45', 7 => '#005a32',
1066
},
1067
greens8 => {
1068
1 => '#f7fcf5', 2 => '#e5f5e0', 3 => '#c7e9c0', 4 => '#a1d99b',
1069
5 => '#74c476', 6 => '#41ab5d', 7 => '#238b45', 8 => '#005a32',
1070
},
1071
greens9 => {
1072
1 => '#f7fcf5', 2 => '#e5f5e0', 3 => '#c7e9c0', 4 => '#a1d99b',
1073
5 => '#74c476', 6 => '#41ab5d', 7 => '#238b45', 8 => '#006d2c',
1074
9 => '#00441b',
1075
},
1076
greys3 => {
1077
1 => '#f0f0f0', 2 => '#bdbdbd', 3 => '#636363',
1078
},
1079
greys4 => {
1080
1 => '#f7f7f7', 2 => '#cccccc', 3 => '#969696', 4 => '#525252',
1081
},
1082
greys5 => {
1083
1 => '#f7f7f7', 2 => '#cccccc', 3 => '#969696', 4 => '#636363',
1084
5 => '#252525',
1085
},
1086
greys6 => {
1087
1 => '#f7f7f7', 2 => '#d9d9d9', 3 => '#bdbdbd', 4 => '#969696',
1088
5 => '#636363', 6 => '#252525',
1089
},
1090
greys7 => {
1091
1 => '#f7f7f7', 2 => '#d9d9d9', 3 => '#bdbdbd', 4 => '#969696',
1092
5 => '#737373', 6 => '#525252', 7 => '#252525',
1093
},
1094
greys8 => {
1095
1 => '#ffffff', 2 => '#f0f0f0', 3 => '#d9d9d9', 4 => '#bdbdbd',
1096
5 => '#969696', 6 => '#737373', 7 => '#525252', 8 => '#252525',
1097
},
1098
greys9 => {
1099
1 => '#ffffff', 2 => '#f0f0f0', 3 => '#d9d9d9', 4 => '#bdbdbd',
1100
5 => '#969696', 6 => '#737373', 7 => '#525252', 8 => '#252525',
1101
9 => '#000000',
1102
},
1103
oranges3 => {
1104
1 => '#fee6ce', 2 => '#fdae6b', 3 => '#e6550d',
1105
},
1106
oranges4 => {
1107
1 => '#feedde', 2 => '#fdbe85', 3 => '#fd8d3c', 4 => '#d94701',
1108
},
1109
oranges5 => {
1110
1 => '#feedde', 2 => '#fdbe85', 3 => '#fd8d3c', 4 => '#e6550d',
1111
5 => '#a63603',
1112
},
1113
oranges6 => {
1114
1 => '#feedde', 2 => '#fdd0a2', 3 => '#fdae6b', 4 => '#fd8d3c',
1115
5 => '#e6550d', 6 => '#a63603',
1116
},
1117
oranges7 => {
1118
1 => '#feedde', 2 => '#fdd0a2', 3 => '#fdae6b', 4 => '#fd8d3c',
1119
5 => '#f16913', 6 => '#d94801', 7 => '#8c2d04',
1120
},
1121
oranges8 => {
1122
1 => '#fff5eb', 2 => '#fee6ce', 3 => '#fdd0a2', 4 => '#fdae6b',
1123
5 => '#fd8d3c', 6 => '#f16913', 7 => '#d94801', 8 => '#8c2d04',
1124
},
1125
oranges9 => {
1126
1 => '#fff5eb', 2 => '#fee6ce', 3 => '#fdd0a2', 4 => '#fdae6b',
1127
5 => '#fd8d3c', 6 => '#f16913', 7 => '#d94801', 8 => '#a63603',
1128
9 => '#7f2704',
1129
},
1130
orrd3 => {
1131
1 => '#fee8c8', 2 => '#fdbb84', 3 => '#e34a33',
1132
},
1133
orrd4 => {
1134
1 => '#fef0d9', 2 => '#fdcc8a', 3 => '#fc8d59', 4 => '#d7301f',
1135
},
1136
orrd5 => {
1137
1 => '#fef0d9', 2 => '#fdcc8a', 3 => '#fc8d59', 4 => '#e34a33',
1138
5 => '#b30000',
1139
},
1140
orrd6 => {
1141
1 => '#fef0d9', 2 => '#fdd49e', 3 => '#fdbb84', 4 => '#fc8d59',
1142
5 => '#e34a33', 6 => '#b30000',
1143
},
1144
orrd7 => {
1145
1 => '#fef0d9', 2 => '#fdd49e', 3 => '#fdbb84', 4 => '#fc8d59',
1146
5 => '#ef6548', 6 => '#d7301f', 7 => '#990000',
1147
},
1148
orrd8 => {
1149
1 => '#fff7ec', 2 => '#fee8c8', 3 => '#fdd49e', 4 => '#fdbb84',
1150
5 => '#fc8d59', 6 => '#ef6548', 7 => '#d7301f', 8 => '#990000',
1151
},
1152
orrd9 => {
1153
1 => '#fff7ec', 2 => '#fee8c8', 3 => '#fdd49e', 4 => '#fdbb84',
1154
5 => '#fc8d59', 6 => '#ef6548', 7 => '#d7301f', 8 => '#b30000',
1155
9 => '#7f0000',
1156
},
1157
paired3 => {
1158
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a',
1159
},
1160
paired4 => {
1161
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1162
},
1163
paired5 => {
1164
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1165
5 => '#fb9a99',
1166
},
1167
paired6 => {
1168
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1169
5 => '#fb9a99', 6 => '#e31a1c',
1170
},
1171
paired7 => {
1172
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1173
5 => '#fb9a99', 6 => '#e31a1c', 7 => '#fdbf6f',
1174
},
1175
paired8 => {
1176
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1177
5 => '#fb9a99', 6 => '#e31a1c', 7 => '#fdbf6f', 8 => '#ff7f00',
1178
},
1179
paired9 => {
1180
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1181
5 => '#fb9a99', 6 => '#e31a1c', 7 => '#fdbf6f', 8 => '#ff7f00',
1182
9 => '#cab2d6',
1183
},
1184
paired10 => {
1185
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1186
5 => '#fb9a99', 6 => '#e31a1c', 7 => '#fdbf6f', 8 => '#ff7f00',
1187
9 => '#cab2d6', 10 => '#6a3d9a',
1188
},
1189
paired11 => {
1190
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1191
5 => '#fb9a99', 6 => '#e31a1c', 7 => '#fdbf6f', 8 => '#ff7f00',
1192
9 => '#cab2d6', 10 => '#6a3d9a', 11 => '#ffff99',
1193
},
1194
paired12 => {
1195
1 => '#a6cee3', 2 => '#1f78b4', 3 => '#b2df8a', 4 => '#33a02c',
1196
5 => '#fb9a99', 6 => '#e31a1c', 7 => '#fdbf6f', 8 => '#ff7f00',
1197
9 => '#cab2d6', 10 => '#6a3d9a', 11 => '#ffff99', 12 => '#b15928',
1198
},
1199
pastel13 => {
1200
1 => '#fbb4ae', 2 => '#b3cde3', 3 => '#ccebc5',
1201
},
1202
pastel14 => {
1203
1 => '#fbb4ae', 2 => '#b3cde3', 3 => '#ccebc5', 4 => '#decbe4',
1204
},
1205
pastel15 => {
1206
1 => '#fbb4ae', 2 => '#b3cde3', 3 => '#ccebc5', 4 => '#decbe4',
1207
5 => '#fed9a6',
1208
},
1209
pastel16 => {
1210
1 => '#fbb4ae', 2 => '#b3cde3', 3 => '#ccebc5', 4 => '#decbe4',
1211
5 => '#fed9a6', 6 => '#ffffcc',
1212
},
1213
pastel17 => {
1214
1 => '#fbb4ae', 2 => '#b3cde3', 3 => '#ccebc5', 4 => '#decbe4',
1215
5 => '#fed9a6', 6 => '#ffffcc', 7 => '#e5d8bd',
1216
},
1217
pastel18 => {
1218
1 => '#fbb4ae', 2 => '#b3cde3', 3 => '#ccebc5', 4 => '#decbe4',
1219
5 => '#fed9a6', 6 => '#ffffcc', 7 => '#e5d8bd', 8 => '#fddaec',
1220
},
1221
pastel19 => {
1222
1 => '#fbb4ae', 2 => '#b3cde3', 3 => '#ccebc5', 4 => '#decbe4',
1223
5 => '#fed9a6', 6 => '#ffffcc', 7 => '#e5d8bd', 8 => '#fddaec',
1224
9 => '#f2f2f2',
1225
},
1226
pastel23 => {
1227
1 => '#b3e2cd', 2 => '#fdcdac', 3 => '#cbd5e8',
1228
},
1229
pastel24 => {
1230
1 => '#b3e2cd', 2 => '#fdcdac', 3 => '#cbd5e8', 4 => '#f4cae4',
1231
},
1232
pastel25 => {
1233
1 => '#b3e2cd', 2 => '#fdcdac', 3 => '#cbd5e8', 4 => '#f4cae4',
1234
5 => '#e6f5c9',
1235
},
1236
pastel26 => {
1237
1 => '#b3e2cd', 2 => '#fdcdac', 3 => '#cbd5e8', 4 => '#f4cae4',
1238
5 => '#e6f5c9', 6 => '#fff2ae',
1239
},
1240
pastel27 => {
1241
1 => '#b3e2cd', 2 => '#fdcdac', 3 => '#cbd5e8', 4 => '#f4cae4',
1242
5 => '#e6f5c9', 6 => '#fff2ae', 7 => '#f1e2cc',
1243
},
1244
pastel28 => {
1245
1 => '#b3e2cd', 2 => '#fdcdac', 3 => '#cbd5e8', 4 => '#f4cae4',
1246
5 => '#e6f5c9', 6 => '#fff2ae', 7 => '#f1e2cc', 8 => '#cccccc',
1247
},
1248
piyg3 => {
1249
1 => '#e9a3c9', 2 => '#f7f7f7', 3 => '#a1d76a',
1250
},
1251
piyg4 => {
1252
1 => '#d01c8b', 2 => '#f1b6da', 3 => '#b8e186', 4 => '#4dac26',
1253
},
1254
piyg5 => {
1255
1 => '#d01c8b', 2 => '#f1b6da', 3 => '#f7f7f7', 4 => '#b8e186',
1256
5 => '#4dac26',
1257
},
1258
piyg6 => {
1259
1 => '#c51b7d', 2 => '#e9a3c9', 3 => '#fde0ef', 4 => '#e6f5d0',
1260
5 => '#a1d76a', 6 => '#4d9221',
1261
},
1262
piyg7 => {
1263
1 => '#c51b7d', 2 => '#e9a3c9', 3 => '#fde0ef', 4 => '#f7f7f7',
1264
5 => '#e6f5d0', 6 => '#a1d76a', 7 => '#4d9221',
1265
},
1266
piyg8 => {
1267
1 => '#c51b7d', 2 => '#de77ae', 3 => '#f1b6da', 4 => '#fde0ef',
1268
5 => '#e6f5d0', 6 => '#b8e186', 7 => '#7fbc41', 8 => '#4d9221',
1269
},
1270
piyg9 => {
1271
1 => '#c51b7d', 2 => '#de77ae', 3 => '#f1b6da', 4 => '#fde0ef',
1272
5 => '#f7f7f7', 6 => '#e6f5d0', 7 => '#b8e186', 8 => '#7fbc41',
1273
9 => '#4d9221',
1274
},
1275
piyg10 => {
1276
1 => '#8e0152', 2 => '#c51b7d', 3 => '#de77ae', 4 => '#f1b6da',
1277
5 => '#fde0ef', 6 => '#e6f5d0', 7 => '#b8e186', 8 => '#7fbc41',
1278
9 => '#4d9221', 10 => '#276419',
1279
},
1280
piyg11 => {
1281
1 => '#8e0152', 2 => '#c51b7d', 3 => '#de77ae', 4 => '#f1b6da',
1282
5 => '#fde0ef', 6 => '#f7f7f7', 7 => '#e6f5d0', 8 => '#b8e186',
1283
9 => '#7fbc41', 10 => '#4d9221', 11 => '#276419',
1284
},
1285
prgn3 => {
1286
1 => '#af8dc3', 2 => '#f7f7f7', 3 => '#7fbf7b',
1287
},
1288
prgn4 => {
1289
1 => '#7b3294', 2 => '#c2a5cf', 3 => '#a6dba0', 4 => '#008837',
1290
},
1291
prgn5 => {
1292
1 => '#7b3294', 2 => '#c2a5cf', 3 => '#f7f7f7', 4 => '#a6dba0',
1293
5 => '#008837',
1294
},
1295
prgn6 => {
1296
1 => '#762a83', 2 => '#af8dc3', 3 => '#e7d4e8', 4 => '#d9f0d3',
1297
5 => '#7fbf7b', 6 => '#1b7837',
1298
},
1299
prgn7 => {
1300
1 => '#762a83', 2 => '#af8dc3', 3 => '#e7d4e8', 4 => '#f7f7f7',
1301
5 => '#d9f0d3', 6 => '#7fbf7b', 7 => '#1b7837',
1302
},
1303
prgn8 => {
1304
1 => '#762a83', 2 => '#9970ab', 3 => '#c2a5cf', 4 => '#e7d4e8',
1305
5 => '#d9f0d3', 6 => '#a6dba0', 7 => '#5aae61', 8 => '#1b7837',
1306
},
1307
prgn9 => {
1308
1 => '#762a83', 2 => '#9970ab', 3 => '#c2a5cf', 4 => '#e7d4e8',
1309
5 => '#f7f7f7', 6 => '#d9f0d3', 7 => '#a6dba0', 8 => '#5aae61',
1310
9 => '#1b7837',
1311
},
1312
prgn10 => {
1313
1 => '#40004b', 2 => '#762a83', 3 => '#9970ab', 4 => '#c2a5cf',
1314
5 => '#e7d4e8', 6 => '#d9f0d3', 7 => '#a6dba0', 8 => '#5aae61',
1315
9 => '#1b7837', 10 => '#00441b',
1316
},
1317
prgn11 => {
1318
1 => '#40004b', 2 => '#762a83', 3 => '#9970ab', 4 => '#c2a5cf',
1319
5 => '#e7d4e8', 6 => '#f7f7f7', 7 => '#d9f0d3', 8 => '#a6dba0',
1320
9 => '#5aae61', 10 => '#1b7837', 11 => '#00441b',
1321
},
1322
pubu3 => {
1323
1 => '#ece7f2', 2 => '#a6bddb', 3 => '#2b8cbe',
1324
},
1325
pubu4 => {
1326
1 => '#f1eef6', 2 => '#bdc9e1', 3 => '#74a9cf', 4 => '#0570b0',
1327
},
1328
pubu5 => {
1329
1 => '#f1eef6', 2 => '#bdc9e1', 3 => '#74a9cf', 4 => '#2b8cbe',
1330
5 => '#045a8d',
1331
},
1332
pubu6 => {
1333
1 => '#f1eef6', 2 => '#d0d1e6', 3 => '#a6bddb', 4 => '#74a9cf',
1334
5 => '#2b8cbe', 6 => '#045a8d',
1335
},
1336
pubu7 => {
1337
1 => '#f1eef6', 2 => '#d0d1e6', 3 => '#a6bddb', 4 => '#74a9cf',
1338
5 => '#3690c0', 6 => '#0570b0', 7 => '#034e7b',
1339
},
1340
pubu8 => {
1341
1 => '#fff7fb', 2 => '#ece7f2', 3 => '#d0d1e6', 4 => '#a6bddb',
1342
5 => '#74a9cf', 6 => '#3690c0', 7 => '#0570b0', 8 => '#034e7b',
1343
},
1344
pubu9 => {
1345
1 => '#fff7fb', 2 => '#ece7f2', 3 => '#d0d1e6', 4 => '#a6bddb',
1346
5 => '#74a9cf', 6 => '#3690c0', 7 => '#0570b0', 8 => '#045a8d',
1347
9 => '#023858',
1348
},
1349
pubugn3 => {
1350
1 => '#ece2f0', 2 => '#a6bddb', 3 => '#1c9099',
1351
},
1352
pubugn4 => {
1353
1 => '#f6eff7', 2 => '#bdc9e1', 3 => '#67a9cf', 4 => '#02818a',
1354
},
1355
pubugn5 => {
1356
1 => '#f6eff7', 2 => '#bdc9e1', 3 => '#67a9cf', 4 => '#1c9099',
1357
5 => '#016c59',
1358
},
1359
pubugn6 => {
1360
1 => '#f6eff7', 2 => '#d0d1e6', 3 => '#a6bddb', 4 => '#67a9cf',
1361
5 => '#1c9099', 6 => '#016c59',
1362
},
1363
pubugn7 => {
1364
1 => '#f6eff7', 2 => '#d0d1e6', 3 => '#a6bddb', 4 => '#67a9cf',
1365
5 => '#3690c0', 6 => '#02818a', 7 => '#016450',
1366
},
1367
pubugn8 => {
1368
1 => '#fff7fb', 2 => '#ece2f0', 3 => '#d0d1e6', 4 => '#a6bddb',
1369
5 => '#67a9cf', 6 => '#3690c0', 7 => '#02818a', 8 => '#016450',
1370
},
1371
pubugn9 => {
1372
1 => '#fff7fb', 2 => '#ece2f0', 3 => '#d0d1e6', 4 => '#a6bddb',
1373
5 => '#67a9cf', 6 => '#3690c0', 7 => '#02818a', 8 => '#016c59',
1374
9 => '#014636',
1375
},
1376
puor3 => {
1377
1 => '#f1a340', 2 => '#f7f7f7', 3 => '#998ec3',
1378
},
1379
puor4 => {
1380
1 => '#e66101', 2 => '#fdb863', 3 => '#b2abd2', 4 => '#5e3c99',
1381
},
1382
puor5 => {
1383
1 => '#e66101', 2 => '#fdb863', 3 => '#f7f7f7', 4 => '#b2abd2',
1384
5 => '#5e3c99',
1385
},
1386
puor6 => {
1387
1 => '#b35806', 2 => '#f1a340', 3 => '#fee0b6', 4 => '#d8daeb',
1388
5 => '#998ec3', 6 => '#542788',
1389
},
1390
puor7 => {
1391
1 => '#b35806', 2 => '#f1a340', 3 => '#fee0b6', 4 => '#f7f7f7',
1392
5 => '#d8daeb', 6 => '#998ec3', 7 => '#542788',
1393
},
1394
puor8 => {
1395
1 => '#b35806', 2 => '#e08214', 3 => '#fdb863', 4 => '#fee0b6',
1396
5 => '#d8daeb', 6 => '#b2abd2', 7 => '#8073ac', 8 => '#542788',
1397
},
1398
puor9 => {
1399
1 => '#b35806', 2 => '#e08214', 3 => '#fdb863', 4 => '#fee0b6',
1400
5 => '#f7f7f7', 6 => '#d8daeb', 7 => '#b2abd2', 8 => '#8073ac',
1401
9 => '#542788',
1402
},
1403
purd3 => {
1404
1 => '#e7e1ef', 2 => '#c994c7', 3 => '#dd1c77',
1405
},
1406
purd4 => {
1407
1 => '#f1eef6', 2 => '#d7b5d8', 3 => '#df65b0', 4 => '#ce1256',
1408
},
1409
purd5 => {
1410
1 => '#f1eef6', 2 => '#d7b5d8', 3 => '#df65b0', 4 => '#dd1c77',
1411
5 => '#980043',
1412
},
1413
purd6 => {
1414
1 => '#f1eef6', 2 => '#d4b9da', 3 => '#c994c7', 4 => '#df65b0',
1415
5 => '#dd1c77', 6 => '#980043',
1416
},
1417
purd7 => {
1418
1 => '#f1eef6', 2 => '#d4b9da', 3 => '#c994c7', 4 => '#df65b0',
1419
5 => '#e7298a', 6 => '#ce1256', 7 => '#91003f',
1420
},
1421
purd8 => {
1422
1 => '#f7f4f9', 2 => '#e7e1ef', 3 => '#d4b9da', 4 => '#c994c7',
1423
5 => '#df65b0', 6 => '#e7298a', 7 => '#ce1256', 8 => '#91003f',
1424
},
1425
purd9 => {
1426
1 => '#f7f4f9', 2 => '#e7e1ef', 3 => '#d4b9da', 4 => '#c994c7',
1427
5 => '#df65b0', 6 => '#e7298a', 7 => '#ce1256', 8 => '#980043',
1428
9 => '#67001f',
1429
},
1430
puor10 => {
1431
1 => '#7f3b08', 2 => '#b35806', 3 => '#e08214', 4 => '#fdb863',
1432
5 => '#fee0b6', 6 => '#d8daeb', 7 => '#b2abd2', 8 => '#8073ac',
1433
9 => '#542788', 10 => '#2d004b',
1434
},
1435
puor11 => {
1436
1 => '#7f3b08', 2 => '#b35806', 3 => '#e08214', 4 => '#fdb863',
1437
5 => '#fee0b6', 6 => '#f7f7f7', 7 => '#d8daeb', 8 => '#b2abd2',
1438
9 => '#8073ac', 10 => '#542788', 11 => '#2d004b',
1439
},
1440
purples3 => {
1441
1 => '#efedf5', 2 => '#bcbddc', 3 => '#756bb1',
1442
},
1443
purples4 => {
1444
1 => '#f2f0f7', 2 => '#cbc9e2', 3 => '#9e9ac8', 4 => '#6a51a3',
1445
},
1446
purples5 => {
1447
1 => '#f2f0f7', 2 => '#cbc9e2', 3 => '#9e9ac8', 4 => '#756bb1',
1448
5 => '#54278f',
1449
},
1450
purples6 => {
1451
1 => '#f2f0f7', 2 => '#dadaeb', 3 => '#bcbddc', 4 => '#9e9ac8',
1452
5 => '#756bb1', 6 => '#54278f',
1453
},
1454
purples7 => {
1455
1 => '#f2f0f7', 2 => '#dadaeb', 3 => '#bcbddc', 4 => '#9e9ac8',
1456
5 => '#807dba', 6 => '#6a51a3', 7 => '#4a1486',
1457
},
1458
purples8 => {
1459
1 => '#fcfbfd', 2 => '#efedf5', 3 => '#dadaeb', 4 => '#bcbddc',
1460
5 => '#9e9ac8', 6 => '#807dba', 7 => '#6a51a3', 8 => '#4a1486',
1461
},
1462
purples9 => {
1463
1 => '#fcfbfd', 2 => '#efedf5', 3 => '#dadaeb', 4 => '#bcbddc',
1464
5 => '#9e9ac8', 6 => '#807dba', 7 => '#6a51a3', 8 => '#54278f',
1465
9 => '#3f007d',
1466
},
1467
rdbu10 => {
1468
1 => '#67001f', 2 => '#b2182b', 3 => '#d6604d', 4 => '#f4a582',
1469
5 => '#fddbc7', 6 => '#d1e5f0', 7 => '#92c5de', 8 => '#4393c3',
1470
9 => '#2166ac', 10 => '#053061',
1471
},
1472
rdbu11 => {
1473
1 => '#67001f', 2 => '#b2182b', 3 => '#d6604d', 4 => '#f4a582',
1474
5 => '#fddbc7', 6 => '#f7f7f7', 7 => '#d1e5f0', 8 => '#92c5de',
1475
9 => '#4393c3', 10 => '#2166ac', 11 => '#053061',
1476
},
1477
rdbu3 => {
1478
1 => '#ef8a62', 2 => '#f7f7f7', 3 => '#67a9cf',
1479
},
1480
rdbu4 => {
1481
1 => '#ca0020', 2 => '#f4a582', 3 => '#92c5de', 4 => '#0571b0',
1482
},
1483
rdbu5 => {
1484
1 => '#ca0020', 2 => '#f4a582', 3 => '#f7f7f7', 4 => '#92c5de',
1485
5 => '#0571b0',
1486
},
1487
rdbu6 => {
1488
1 => '#b2182b', 2 => '#ef8a62', 3 => '#fddbc7', 4 => '#d1e5f0',
1489
5 => '#67a9cf', 6 => '#2166ac',
1490
},
1491
rdbu7 => {
1492
1 => '#b2182b', 2 => '#ef8a62', 3 => '#fddbc7', 4 => '#f7f7f7',
1493
5 => '#d1e5f0', 6 => '#67a9cf', 7 => '#2166ac',
1494
},
1495
rdbu8 => {
1496
1 => '#b2182b', 2 => '#d6604d', 3 => '#f4a582', 4 => '#fddbc7',
1497
5 => '#d1e5f0', 6 => '#92c5de', 7 => '#4393c3', 8 => '#2166ac',
1498
},
1499
rdbu9 => {
1500
1 => '#b2182b', 2 => '#d6604d', 3 => '#f4a582', 4 => '#fddbc7',
1501
5 => '#f7f7f7', 6 => '#d1e5f0', 7 => '#92c5de', 8 => '#4393c3',
1502
9 => '#2166ac',
1503
},
1504
rdgy3 => {
1505
1 => '#ef8a62', 2 => '#ffffff', 3 => '#999999',
1506
},
1507
rdgy4 => {
1508
1 => '#ca0020', 2 => '#f4a582', 3 => '#bababa', 4 => '#404040',
1509
},
1510
rdgy5 => {
1511
1 => '#ca0020', 2 => '#f4a582', 3 => '#ffffff', 4 => '#bababa',
1512
5 => '#404040',
1513
},
1514
rdgy6 => {
1515
1 => '#b2182b', 2 => '#ef8a62', 3 => '#fddbc7', 4 => '#e0e0e0',
1516
5 => '#999999', 6 => '#4d4d4d',
1517
},
1518
rdgy7 => {
1519
1 => '#b2182b', 2 => '#ef8a62', 3 => '#fddbc7', 4 => '#ffffff',
1520
5 => '#e0e0e0', 6 => '#999999', 7 => '#4d4d4d',
1521
},
1522
rdgy8 => {
1523
1 => '#b2182b', 2 => '#d6604d', 3 => '#f4a582', 4 => '#fddbc7',
1524
5 => '#e0e0e0', 6 => '#bababa', 7 => '#878787', 8 => '#4d4d4d',
1525
},
1526
rdgy9 => {
1527
1 => '#b2182b', 2 => '#d6604d', 3 => '#f4a582', 4 => '#fddbc7',
1528
5 => '#ffffff', 6 => '#e0e0e0', 7 => '#bababa', 8 => '#878787',
1529
9 => '#4d4d4d',
1530
},
1531
rdpu3 => {
1532
1 => '#fde0dd', 2 => '#fa9fb5', 3 => '#c51b8a',
1533
},
1534
rdpu4 => {
1535
1 => '#feebe2', 2 => '#fbb4b9', 3 => '#f768a1', 4 => '#ae017e',
1536
},
1537
rdpu5 => {
1538
1 => '#feebe2', 2 => '#fbb4b9', 3 => '#f768a1', 4 => '#c51b8a',
1539
5 => '#7a0177',
1540
},
1541
rdpu6 => {
1542
1 => '#feebe2', 2 => '#fcc5c0', 3 => '#fa9fb5', 4 => '#f768a1',
1543
5 => '#c51b8a', 6 => '#7a0177',
1544
},
1545
rdpu7 => {
1546
1 => '#feebe2', 2 => '#fcc5c0', 3 => '#fa9fb5', 4 => '#f768a1',
1547
5 => '#dd3497', 6 => '#ae017e', 7 => '#7a0177',
1548
},
1549
rdpu8 => {
1550
1 => '#fff7f3', 2 => '#fde0dd', 3 => '#fcc5c0', 4 => '#fa9fb5',
1551
5 => '#f768a1', 6 => '#dd3497', 7 => '#ae017e', 8 => '#7a0177',
1552
},
1553
rdpu9 => {
1554
1 => '#fff7f3', 2 => '#fde0dd', 3 => '#fcc5c0', 4 => '#fa9fb5',
1555
5 => '#f768a1', 6 => '#dd3497', 7 => '#ae017e', 8 => '#7a0177',
1556
9 => '#49006a',
1557
},
1558
rdgy10 => {
1559
1 => '#67001f', 2 => '#b2182b', 3 => '#d6604d', 4 => '#f4a582',
1560
5 => '#fddbc7', 6 => '#e0e0e0', 7 => '#bababa', 8 => '#878787',
1561
9 => '#4d4d4d', 10 => '#1a1a1a',
1562
},
1563
rdgy11 => {
1564
1 => '#67001f', 2 => '#b2182b', 3 => '#d6604d', 4 => '#f4a582',
1565
5 => '#fddbc7', 6 => '#ffffff', 7 => '#e0e0e0', 8 => '#bababa',
1566
9 => '#878787', 10 => '#4d4d4d', 11 => '#1a1a1a',
1567
},
1568
rdylbu3 => {
1569
1 => '#fc8d59', 2 => '#ffffbf', 3 => '#91bfdb',
1570
},
1571
rdylbu4 => {
1572
1 => '#d7191c', 2 => '#fdae61', 3 => '#abd9e9', 4 => '#2c7bb6',
1573
},
1574
rdylbu5 => {
1575
1 => '#d7191c', 2 => '#fdae61', 3 => '#ffffbf', 4 => '#abd9e9',
1576
5 => '#2c7bb6',
1577
},
1578
rdylbu6 => {
1579
1 => '#d73027', 2 => '#fc8d59', 3 => '#fee090', 4 => '#e0f3f8',
1580
5 => '#91bfdb', 6 => '#4575b4',
1581
},
1582
rdylbu7 => {
1583
1 => '#d73027', 2 => '#fc8d59', 3 => '#fee090', 4 => '#ffffbf',
1584
5 => '#e0f3f8', 6 => '#91bfdb', 7 => '#4575b4',
1585
},
1586
rdylbu8 => {
1587
1 => '#d73027', 2 => '#f46d43', 3 => '#fdae61', 4 => '#fee090',
1588
5 => '#e0f3f8', 6 => '#abd9e9', 7 => '#74add1', 8 => '#4575b4',
1589
},
1590
rdylbu9 => {
1591
1 => '#d73027', 2 => '#f46d43', 3 => '#fdae61', 4 => '#fee090',
1592
5 => '#ffffbf', 6 => '#e0f3f8', 7 => '#abd9e9', 8 => '#74add1',
1593
9 => '#4575b4',
1594
},
1595
rdylbu10 => {
1596
1 => '#a50026', 2 => '#d73027', 3 => '#f46d43', 4 => '#fdae61',
1597
5 => '#fee090', 6 => '#e0f3f8', 7 => '#abd9e9', 8 => '#74add1',
1598
9 => '#4575b4', 10 => '#313695',
1599
},
1600
rdylbu11 => {
1601
1 => '#a50026', 2 => '#d73027', 3 => '#f46d43', 4 => '#fdae61',
1602
5 => '#fee090', 6 => '#ffffbf', 7 => '#e0f3f8', 8 => '#abd9e9',
1603
9 => '#74add1', 10 => '#4575b4', 11 => '#313695',
1604
},
1605
rdylgn3 => {
1606
1 => '#fc8d59', 2 => '#ffffbf', 3 => '#91cf60',
1607
},
1608
rdylgn4 => {
1609
1 => '#d7191c', 2 => '#fdae61', 3 => '#a6d96a', 4 => '#1a9641',
1610
},
1611
rdylgn5 => {
1612
1 => '#d7191c', 2 => '#fdae61', 3 => '#ffffbf', 4 => '#a6d96a',
1613
5 => '#1a9641',
1614
},
1615
rdylgn6 => {
1616
1 => '#d73027', 2 => '#fc8d59', 3 => '#fee08b', 4 => '#d9ef8b',
1617
5 => '#91cf60', 6 => '#1a9850',
1618
},
1619
rdylgn7 => {
1620
1 => '#d73027', 2 => '#fc8d59', 3 => '#fee08b', 4 => '#ffffbf',
1621
5 => '#d9ef8b', 6 => '#91cf60', 7 => '#1a9850',
1622
},
1623
rdylgn8 => {
1624
1 => '#d73027', 2 => '#f46d43', 3 => '#fdae61', 4 => '#fee08b',
1625
5 => '#d9ef8b', 6 => '#a6d96a', 7 => '#66bd63', 8 => '#1a9850',
1626
},
1627
rdylgn9 => {
1628
1 => '#d73027', 2 => '#f46d43', 3 => '#fdae61', 4 => '#fee08b',
1629
5 => '#ffffbf', 6 => '#d9ef8b', 7 => '#a6d96a', 8 => '#66bd63',
1630
9 => '#1a9850',
1631
},
1632
rdylgn10 => {
1633
1 => '#a50026', 2 => '#d73027', 3 => '#f46d43', 4 => '#fdae61',
1634
5 => '#fee08b', 6 => '#d9ef8b', 7 => '#a6d96a', 8 => '#66bd63',
1635
9 => '#1a9850', 10 => '#006837',
1636
},
1637
rdylgn11 => {
1638
1 => '#a50026', 2 => '#d73027', 3 => '#f46d43', 4 => '#fdae61',
1639
5 => '#fee08b', 6 => '#ffffbf', 7 => '#d9ef8b', 8 => '#a6d96a',
1640
9 => '#66bd63', 10 => '#1a9850', 11 => '#006837',
1641
},
1642
reds3 => {
1643
1 => '#fee0d2', 2 => '#fc9272', 3 => '#de2d26',
1644
},
1645
reds4 => {
1646
1 => '#fee5d9', 2 => '#fcae91', 3 => '#fb6a4a', 4 => '#cb181d',
1647
},
1648
reds5 => {
1649
1 => '#fee5d9', 2 => '#fcae91', 3 => '#fb6a4a', 4 => '#de2d26',
1650
5 => '#a50f15',
1651
},
1652
reds6 => {
1653
1 => '#fee5d9', 2 => '#fcbba1', 3 => '#fc9272', 4 => '#fb6a4a',
1654
5 => '#de2d26', 6 => '#a50f15',
1655
},
1656
reds7 => {
1657
1 => '#fee5d9', 2 => '#fcbba1', 3 => '#fc9272', 4 => '#fb6a4a',
1658
5 => '#ef3b2c', 6 => '#cb181d', 7 => '#99000d',
1659
},
1660
reds8 => {
1661
1 => '#fff5f0', 2 => '#fee0d2', 3 => '#fcbba1', 4 => '#fc9272',
1662
5 => '#fb6a4a', 6 => '#ef3b2c', 7 => '#cb181d', 8 => '#99000d',
1663
},
1664
reds9 => {
1665
1 => '#fff5f0', 2 => '#fee0d2', 3 => '#fcbba1', 4 => '#fc9272',
1666
5 => '#fb6a4a', 6 => '#ef3b2c', 7 => '#cb181d', 8 => '#a50f15',
1667
9 => '#67000d',
1668
},
1669
set13 => {
1670
1 => '#e41a1c', 2 => '#377eb8', 3 => '#4daf4a',
1671
},
1672
set14 => {
1673
1 => '#e41a1c', 2 => '#377eb8', 3 => '#4daf4a', 4 => '#984ea3',
1674
},
1675
set15 => {
1676
1 => '#e41a1c', 2 => '#377eb8', 3 => '#4daf4a', 4 => '#984ea3',
1677
5 => '#ff7f00',
1678
},
1679
set16 => {
1680
1 => '#e41a1c', 2 => '#377eb8', 3 => '#4daf4a', 4 => '#984ea3',
1681
5 => '#ff7f00', 6 => '#ffff33',
1682
},
1683
set17 => {
1684
1 => '#e41a1c', 2 => '#377eb8', 3 => '#4daf4a', 4 => '#984ea3',
1685
5 => '#ff7f00', 6 => '#ffff33', 7 => '#a65628',
1686
},
1687
set18 => {
1688
1 => '#e41a1c', 2 => '#377eb8', 3 => '#4daf4a', 4 => '#984ea3',
1689
5 => '#ff7f00', 6 => '#ffff33', 7 => '#a65628', 8 => '#f781bf',
1690
},
1691
set19 => {
1692
1 => '#e41a1c', 2 => '#377eb8', 3 => '#4daf4a', 4 => '#984ea3',
1693
5 => '#ff7f00', 6 => '#ffff33', 7 => '#a65628', 8 => '#f781bf',
1694
9 => '#999999',
1695
},
1696
set23 => {
1697
1 => '#66c2a5', 2 => '#fc8d62', 3 => '#8da0cb',
1698
},
1699
set24 => {
1700
1 => '#66c2a5', 2 => '#fc8d62', 3 => '#8da0cb', 4 => '#e78ac3',
1701
},
1702
set25 => {
1703
1 => '#66c2a5', 2 => '#fc8d62', 3 => '#8da0cb', 4 => '#e78ac3',
1704
5 => '#a6d854',
1705
},
1706
set26 => {
1707
1 => '#66c2a5', 2 => '#fc8d62', 3 => '#8da0cb', 4 => '#e78ac3',
1708
5 => '#a6d854', 6 => '#ffd92f',
1709
},
1710
set27 => {
1711
1 => '#66c2a5', 2 => '#fc8d62', 3 => '#8da0cb', 4 => '#e78ac3',
1712
5 => '#a6d854', 6 => '#ffd92f', 7 => '#e5c494',
1713
},
1714
set28 => {
1715
1 => '#66c2a5', 2 => '#fc8d62', 3 => '#8da0cb', 4 => '#e78ac3',
1716
5 => '#a6d854', 6 => '#ffd92f', 7 => '#e5c494', 8 => '#b3b3b3',
1717
},
1718
set33 => {
1719
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada',
1720
},
1721
set34 => {
1722
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1723
},
1724
set35 => {
1725
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1726
5 => '#80b1d3',
1727
},
1728
set36 => {
1729
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1730
5 => '#80b1d3', 6 => '#fdb462',
1731
},
1732
set37 => {
1733
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1734
5 => '#80b1d3', 6 => '#fdb462', 7 => '#b3de69',
1735
},
1736
set38 => {
1737
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1738
5 => '#80b1d3', 6 => '#fdb462', 7 => '#b3de69', 8 => '#fccde5',
1739
},
1740
set39 => {
1741
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1742
5 => '#80b1d3', 6 => '#fdb462', 7 => '#b3de69', 8 => '#fccde5',
1743
9 => '#d9d9d9',
1744
},
1745
set310 => {
1746
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1747
5 => '#80b1d3', 6 => '#fdb462', 7 => '#b3de69', 8 => '#fccde5',
1748
9 => '#d9d9d9', 10 => '#bc80bd',
1749
},
1750
set311 => {
1751
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1752
5 => '#80b1d3', 6 => '#fdb462', 7 => '#b3de69', 8 => '#fccde5',
1753
9 => '#d9d9d9', 10 => '#bc80bd', 11 => '#ccebc5',
1754
},
1755
set312 => {
1756
1 => '#8dd3c7', 2 => '#ffffb3', 3 => '#bebada', 4 => '#fb8072',
1757
5 => '#80b1d3', 6 => '#fdb462', 7 => '#b3de69', 8 => '#fccde5',
1758
9 => '#d9d9d9', 10 => '#bc80bd', 11 => '#ccebc5', 12 => '#ffed6f',
1759
},
1760
spectral3 => {
1761
1 => '#fc8d59', 2 => '#ffffbf', 3 => '#99d594',
1762
},
1763
spectral4 => {
1764
1 => '#d7191c', 2 => '#fdae61', 3 => '#abdda4', 4 => '#2b83ba',
1765
},
1766
spectral5 => {
1767
1 => '#d7191c', 2 => '#fdae61', 3 => '#ffffbf', 4 => '#abdda4',
1768
5 => '#2b83ba',
1769
},
1770
spectral6 => {
1771
1 => '#d53e4f', 2 => '#fc8d59', 3 => '#fee08b', 4 => '#e6f598',
1772
5 => '#99d594', 6 => '#3288bd',
1773
},
1774
spectral7 => {
1775
1 => '#d53e4f', 2 => '#fc8d59', 3 => '#fee08b', 4 => '#ffffbf',
1776
5 => '#e6f598', 6 => '#99d594', 7 => '#3288bd',
1777
},
1778
spectral8 => {
1779
1 => '#d53e4f', 2 => '#f46d43', 3 => '#fdae61', 4 => '#fee08b',
1780
5 => '#e6f598', 6 => '#abdda4', 7 => '#66c2a5', 8 => '#3288bd',
1781
},
1782
spectral9 => {
1783
1 => '#d53e4f', 2 => '#f46d43', 3 => '#fdae61', 4 => '#fee08b',
1784
5 => '#ffffbf', 6 => '#e6f598', 7 => '#abdda4', 8 => '#66c2a5',
1785
9 => '#3288bd',
1786
},
1787
spectral10 => {
1788
1 => '#9e0142', 2 => '#d53e4f', 3 => '#f46d43', 4 => '#fdae61',
1789
5 => '#fee08b', 6 => '#e6f598', 7 => '#abdda4', 8 => '#66c2a5',
1790
9 => '#3288bd', 10 => '#5e4fa2',
1791
},
1792
spectral11 => {
1793
1 => '#9e0142', 2 => '#d53e4f', 3 => '#f46d43', 4 => '#fdae61',
1794
5 => '#fee08b', 6 => '#ffffbf', 7 => '#e6f598', 8 => '#abdda4',
1795
9 => '#66c2a5', 10 => '#3288bd', 11 => '#5e4fa2',
1796
},
1797
ylgn3 => {
1798
1 => '#f7fcb9', 2 => '#addd8e', 3 => '#31a354',
1799
},
1800
ylgn4 => {
1801
1 => '#ffffcc', 2 => '#c2e699', 3 => '#78c679', 4 => '#238443',
1802
},
1803
ylgn5 => {
1804
1 => '#ffffcc', 2 => '#c2e699', 3 => '#78c679', 4 => '#31a354',
1805
5 => '#006837',
1806
},
1807
ylgn6 => {
1808
1 => '#ffffcc', 2 => '#d9f0a3', 3 => '#addd8e', 4 => '#78c679',
1809
5 => '#31a354', 6 => '#006837',
1810
},
1811
ylgn7 => {
1812
1 => '#ffffcc', 2 => '#d9f0a3', 3 => '#addd8e', 4 => '#78c679',
1813
5 => '#41ab5d', 6 => '#238443', 7 => '#005a32',
1814
},
1815
ylgn8 => {
1816
1 => '#ffffe5', 2 => '#f7fcb9', 3 => '#d9f0a3', 4 => '#addd8e',
1817
5 => '#78c679', 6 => '#41ab5d', 7 => '#238443', 8 => '#005a32',
1818
},
1819
ylgn9 => {
1820
1 => '#ffffe5', 2 => '#f7fcb9', 3 => '#d9f0a3', 4 => '#addd8e',
1821
5 => '#78c679', 6 => '#41ab5d', 7 => '#238443', 8 => '#006837',
1822
9 => '#004529',
1823
},
1824
ylgnbu3 => {
1825
1 => '#edf8b1', 2 => '#7fcdbb', 3 => '#2c7fb8',
1826
},
1827
ylgnbu4 => {
1828
1 => '#ffffcc', 2 => '#a1dab4', 3 => '#41b6c4', 4 => '#225ea8',
1829
},
1830
ylgnbu5 => {
1831
1 => '#ffffcc', 2 => '#a1dab4', 3 => '#41b6c4', 4 => '#2c7fb8',
1832
5 => '#253494',
1833
},
1834
ylgnbu6 => {
1835
1 => '#ffffcc', 2 => '#c7e9b4', 3 => '#7fcdbb', 4 => '#41b6c4',
1836
5 => '#2c7fb8', 6 => '#253494',
1837
},
1838
ylgnbu7 => {
1839
1 => '#ffffcc', 2 => '#c7e9b4', 3 => '#7fcdbb', 4 => '#41b6c4',
1840
5 => '#1d91c0', 6 => '#225ea8', 7 => '#0c2c84',
1841
},
1842
ylgnbu8 => {
1843
1 => '#ffffd9', 2 => '#edf8b1', 3 => '#c7e9b4', 4 => '#7fcdbb',
1844
5 => '#41b6c4', 6 => '#1d91c0', 7 => '#225ea8', 8 => '#0c2c84',
1845
},
1846
ylgnbu9 => {
1847
1 => '#ffffd9', 2 => '#edf8b1', 3 => '#c7e9b4', 4 => '#7fcdbb',
1848
5 => '#41b6c4', 6 => '#1d91c0', 7 => '#225ea8', 8 => '#253494',
1849
9 => '#081d58',
1850
},
1851
ylorbr3 => {
1852
1 => '#fff7bc', 2 => '#fec44f', 3 => '#d95f0e',
1853
},
1854
ylorbr4 => {
1855
1 => '#ffffd4', 2 => '#fed98e', 3 => '#fe9929', 4 => '#cc4c02',
1856
},
1857
ylorbr5 => {
1858
1 => '#ffffd4', 2 => '#fed98e', 3 => '#fe9929', 4 => '#d95f0e',
1859
5 => '#993404',
1860
},
1861
ylorbr6 => {
1862
1 => '#ffffd4', 2 => '#fee391', 3 => '#fec44f', 4 => '#fe9929',
1863
5 => '#d95f0e', 6 => '#993404',
1864
},
1865
ylorbr7 => {
1866
1 => '#ffffd4', 2 => '#fee391', 3 => '#fec44f', 4 => '#fe9929',
1867
5 => '#ec7014', 6 => '#cc4c02', 7 => '#8c2d04',
1868
},
1869
ylorbr8 => {
1870
1 => '#ffffe5', 2 => '#fff7bc', 3 => '#fee391', 4 => '#fec44f',
1871
5 => '#fe9929', 6 => '#ec7014', 7 => '#cc4c02', 8 => '#8c2d04',
1872
},
1873
ylorbr9 => {
1874
1 => '#ffffe5', 2 => '#fff7bc', 3 => '#fee391', 4 => '#fec44f',
1875
5 => '#fe9929', 6 => '#ec7014', 7 => '#cc4c02', 8 => '#993404',
1876
9 => '#662506',
1877
},
1878
ylorrd3 => {
1879
1 => '#ffeda0', 2 => '#feb24c', 3 => '#f03b20',
1880
},
1881
ylorrd4 => {
1882
1 => '#ffffb2', 2 => '#fecc5c', 3 => '#fd8d3c', 4 => '#e31a1c',
1883
},
1884
ylorrd5 => {
1885
1 => '#ffffb2', 2 => '#fecc5c', 3 => '#fd8d3c', 4 => '#f03b20',
1886
5 => '#bd0026',
1887
},
1888
ylorrd6 => {
1889
1 => '#ffffb2', 2 => '#fed976', 3 => '#feb24c', 4 => '#fd8d3c',
1890
5 => '#f03b20', 6 => '#bd0026',
1891
},
1892
ylorrd7 => {
1893
1 => '#ffffb2', 2 => '#fed976', 3 => '#feb24c', 4 => '#fd8d3c',
1894
5 => '#fc4e2a', 6 => '#e31a1c', 7 => '#b10026',
1895
},
1896
ylorrd8 => {
1897
1 => '#ffffcc', 2 => '#ffeda0', 3 => '#fed976', 4 => '#feb24c',
1898
5 => '#fd8d3c', 6 => '#fc4e2a', 7 => '#e31a1c', 8 => '#b10026',
1899
},
1900
ylorrd9 => {
1901
1 => '#ffffcc', 2 => '#ffeda0', 3 => '#fed976', 4 => '#feb24c',
1902
5 => '#fd8d3c', 6 => '#fc4e2a', 7 => '#e31a1c', 8 => '#bd0026',
1903
9 => '#800026',
1904
},
1905
};
1906
1907
# reverse mapping value => name
1908
my $color_values = { };
1909
my $all_color_names = { };
1910
1911
{
1912
# reverse mapping "#ff0000 => 'red'"
1913
# also build a list of all possible color names
1914
for my $n (sort keys %$color_names)
1915
{
1916
my $s = $color_names->{$n};
1917
$color_values->{ $n } = {};
1918
my $t = $color_values->{$n};
1919
# sort the names on their length
1920
for my $c (sort { length($a) <=> length($b) || $a cmp $b } keys %$s)
1921
{
1922
# don't add "blue1" if it is already set as "blue"
1923
$t->{ $s->{$c} } = $c unless exists $t->{ $s->{$c} };
1924
# mark as existing
1925
$all_color_names->{ $c } = undef;
1926
}
1927
}
1928
}
1929
1930
our $qr_custom_attribute = qr/^x-([a-z_0-9]+-)*[a-z_0-9]+\z/;
1931
1932
sub color_names
1933
{
1934
0
0
1
0
$color_names;
1935
}
1936
1937
sub color_name
1938
{
1939
# return "red" for "#ff0000"
1940
9
9
1
13
my ($self,$color,$scheme) = @_;
1941
1942
9
100
23
$scheme ||= 'w3c';
1943
9
100
43
$color_values->{$scheme}->{$color} || $color;
1944
}
1945
1946
sub color_value
1947
{
1948
# return "#ff0000" for "red"
1949
9
9
1
13
my ($self,$color,$scheme) = @_;
1950
1951
9
100
25
$scheme ||= 'w3c';
1952
1953
# 'w3c/red' => 'w3c', 'red'
1954
9
50
17
$scheme = $1 if $color =~ s/^([a-z0-9])\///;
1955
1956
9
50
50
$color_names->{$scheme}->{$color} || $color;
1957
}
1958
1959
sub _color_scheme
1960
{
1961
# check that a given color scheme is valid
1962
9
9
12
my ($self, $scheme) = @_;
1963
1964
9
50
22
return $scheme if $scheme eq 'inherit';
1965
9
100
30
exists $color_names->{ $scheme } ? $scheme : undef;
1966
}
1967
1968
sub _color
1969
{
1970
# Check that a given color name (like 'red'), or value (like '#ff0000')
1971
# or rgb(1,2,3) is valid. Used by valid_attribute().
1972
1973
# Note that for color names, the color scheme is not known here, so we
1974
# can only look if the color name is potentially possible. F.i. under
1975
# the Brewer scheme ylorrd9, '1' is a valid color name, while 'red'
1976
# would not. To resolve such conflicts, we will fallback to 'x11'
1977
# (the largest of the schemes) if the color name doesn't exist in
1978
# the current scheme.
1979
263
263
349
my ($self, $org_color) = @_;
1980
1981
263
339
$org_color = lc($org_color); # color names are case insensitive
1982
263
404
$org_color =~ s/\s//g; # remove spaces to unify format
1983
263
245
my $color = $org_color;
1984
1985
263
100
462
if ($color =~ s/^(w3c|[a-z]+\d{0,2})\///)
1986
{
1987
10
14
my $scheme = $1;
1988
10
50
34
return $org_color if exists $color_names->{$scheme}->{$color};
1989
# if it didn't work, then fall back to x11
1990
0
0
$scheme = 'x11';
1991
0
0
0
return (exists $color_names->{$scheme}->{$color} ? $org_color : undef);
1992
}
1993
1994
# scheme unknown, fall back to generic handling
1995
1996
# red => red
1997
253
100
716
return $org_color if exists $all_color_names->{$color};
1998
1999
# #ff0000 => #ff0000, rgb(1,2,3) => rgb(1,2,3)
2000
67
100
143
defined $self->color_as_hex($color) ? $org_color : undef;
2001
}
2002
2003
sub _hsv_to_rgb
2004
{
2005
# H=0..360, S=0..1.0, V=0..1.0
2006
35
35
4455
my ($h, $s, $v) = @_;
2007
2008
35
31
my $e = 0.0001;
2009
2010
35
100
88
if ($s < $e)
2011
{
2012
6
100
10
$v = abs(int(256 * $v)); $v = 255 if $v > 255;
6
9
2013
6
16
return ($v,$v,$v);
2014
}
2015
2016
29
23
my ($r,$g,$b);
2017
29
30
$h *= 360;
2018
2019
29
41
my $h1 = int($h / 60);
2020
29
28
my $f = $h / 60 - $h1;
2021
29
36
my $p = $v * (1 - $s);
2022
29
30
my $q = $v * (1 - ($s * $f));
2023
29
30
my $t = $v * (1 - ($s * (1-$f)));
2024
2025
29
100
100
118
if ($h1 == 0 || $h1 == 6)
100
100
100
50
2026
{
2027
16
21
$r = $v; $g = $t; $b = $p;
16
16
16
16
2028
}
2029
elsif ($h1 == 1)
2030
{
2031
4
5
$r = $q; $g = $v; $b = $p;
4
4
4
3
2032
}
2033
elsif ($h1 == 2)
2034
{
2035
2
1
$r = $p; $g = $v; $b = $t;
2
3
2
2
2036
}
2037
elsif ($h1 == 3)
2038
{
2039
4
3
$r = $p; $g = $q; $b = $v;
4
5
4
2
2040
}
2041
elsif ($h1 == 4)
2042
{
2043
3
4
$r = $t; $g = $p; $b = $v;
3
4
3
3
2044
}
2045
else
2046
{
2047
0
0
$r = $v; $g = $p; $b = $q;
0
0
0
0
2048
}
2049
# clamp values to 0.255
2050
29
30
$r = abs(int($r*256));
2051
29
27
$g = abs(int($g*256));
2052
29
25
$b = abs(int($b*256));
2053
29
100
43
$r = 255 if $r > 255;
2054
29
100
42
$g = 255 if $g > 255;
2055
29
100
42
$b = 255 if $b > 255;
2056
2057
29
74
($r,$g,$b);
2058
}
2059
2060
sub _hsl_to_rgb
2061
{
2062
# H=0..360, S=0..100, L=0..100
2063
21
21
401
my ($h, $s, $l) = @_;
2064
2065
21
19
my $e = 0.0001;
2066
21
100
40
if ($s < $e)
2067
{
2068
# achromatic or grey
2069
6
100
8
$l = abs(int(256 * $l)); $l = 255 if $l > 255;
6
9
2070
6
16
return ($l,$l,$l);
2071
}
2072
2073
15
12
my $t2;
2074
15
100
23
if ($l < 0.5)
2075
{
2076
2
3
$t2 = $l * ($s + 1);
2077
}
2078
else
2079
{
2080
13
19
$t2 = $l + $s - ($l * $s);
2081
}
2082
15
18
my $t1 = $l * 2 - $t2;
2083
2084
15
14
my ($r,$g,$b);
2085
2086
# 0..359
2087
15
100
21
$h %= 360 if $h >= 360;
2088
2089
# $h = 0..1
2090
15
13
$h /= 360;
2091
2092
15
12
my $tr = $h + 1/3;
2093
15
14
my $tg = $h;
2094
15
14
my $tb = $h - 1/3;
2095
2096
15
50
21
$tr += 1 if $tr < 0; $tr -= 1 if $tr > 1;
15
100
20
2097
15
50
18
$tg += 1 if $tg < 0; $tg -= 1 if $tg > 1;
15
50
21
2098
15
100
20
$tb += 1 if $tb < 0; $tb -= 1 if $tb > 1;
15
50
18
2099
2100
15
14
my $i = 0; my @temp3 = ($tr,$tg,$tb);
15
21
2101
15
10
my @rc;
2102
15
15
for my $c ($r,$g,$b)
2103
{
2104
45
32
my $t3 = $temp3[$i++];
2105
2106
45
100
81
if ($t3 < 1/6)
100
100
2107
{
2108
8
9
$c = $t1 + ($t2 - $t1) * 6 * $t3;
2109
}
2110
elsif ($t3 < 1/2)
2111
{
2112
15
11
$c = $t2;
2113
}
2114
elsif ($t3 < 2/3)
2115
{
2116
5
8
$c = $t1 + ($t2 - $t1) * 6 * (2/3 - $t3);
2117
}
2118
else
2119
{
2120
17
13
$c = $t1;
2121
}
2122
45
100
34
$c = int($c * 256); $c = 255 if $c > 255;
45
50
2123
45
42
push @rc, $c;
2124
}
2125
2126
15
42
@rc;
2127
}
2128
2129
my $factors = {
2130
'rgb' => [ 255, 255, 255, 255 ],
2131
'hsv' => [ 1, 1, 1, 255 ],
2132
'hsl' => [ 360, 1, 1, 255 ],
2133
};
2134
2135
sub color_as_hex
2136
{
2137
# Turn "red" or rgb(255,0,0) or "#f00" into "#ff0000". Return undef for
2138
# invalid colors.
2139
725
725
1
10440
my ($self,$color,$scheme) = @_;
2140
2141
725
100
1193
$scheme ||= 'w3c';
2142
725
809
$color = lc($color);
2143
# 'w3c/red' => 'w3c', 'red'
2144
725
50
1212
$scheme = $1 if $color =~ s/^([a-z0-9])\///;
2145
2146
# convert "red" to "ffff00"
2147
return $color_names->{$scheme}->{$color}
2148
725
100
2066
if exists $color_names->{$scheme}->{$color};
2149
2150
# fallback to x11 scheme if color doesn't exist
2151
return $color_names->{x11}->{$color}
2152
113
100
236
if exists $color_names->{x11}->{$color};
2153
2154
101
233
my $qr_num = qr/\s*
2155
((?:[0-9]{1,3}%?) | # 12%, 10, 2 etc
2156
(?:[0-9]?\.[0-9]{1,5}) ) # .1, 0.1, 2.5 etc
2157
/x;
2158
2159
# rgb(255,100%,1.0) => '#ffffff'
2160
101
100
1346
if ($color =~ /^(rgb|hsv|hsl)\($qr_num,$qr_num,$qr_num(?:,$qr_num)?\s*\)\z/)
2161
{
2162
57
100
85
my $r = $2; my $g = $3; my $b = $4; my $a = $5; $a = 255 unless defined $a;
57
52
57
65
57
53
57
98
2163
57
60
my $format = $1;
2164
2165
57
48
my $i = 0;
2166
57
64
for my $c ($r,$g,$b,$a)
2167
{
2168
# for the first value in HSL or HSV, use 360, otherwise 100. For RGB, use 255
2169
228
277
my $factor = $factors->{$format}->[$i++];
2170
2171
228
100
284
if ($c =~ /^([0-9]+)%\z/) # 10% => 25.5
2172
{
2173
15
35
$c = $1 * $factor / 100;
2174
}
2175
else
2176
{
2177
213
100
501
$c = $1 * $factor if $c =~ /^([0-9]+\.[0-9]+)\z/; # 0.1, 1.0
2178
}
2179
}
2180
2181
57
100
121
($r,$g,$b) = Graph::Easy::_hsv_to_rgb($r,$g,$b) if $format eq 'hsv';
2182
57
100
102
($r,$g,$b) = Graph::Easy::_hsl_to_rgb($r,$g,$b) if $format eq 'hsl';
2183
2184
57
50
47
$a = int($a); $a = 255 if $a > 255;
57
90
2185
2186
# #RRGGBB or #RRGGBBAA
2187
57
197
$color = sprintf("#%02x%02x%02x%02x", $r,$g,$b,$a);
2188
}
2189
2190
# turn #ff0 into #ffff00
2191
101
100
297
$color = "#$1$1$2$2$3$3" if $color =~ /^#([a-f0-9])([a-f0-9])([a-f[0-9])\z/;
2192
2193
# #RRGGBBff => #RRGGBB (alpha value of 255 is the default)
2194
101
255
$color =~ s/^(#......)ff\z/$1/i;
2195
2196
# check final color value to be #RRGGBB or #RRGGBBAA
2197
101
100
292
return undef unless $color =~ /^#([a-f0-9]{6}|[a-f0-9]{8})\z/i;
2198
2199
93
357
$color;
2200
}
2201
2202
sub text_style
2203
{
2204
# check whether the given list of textstyle attributes is valid
2205
20
20
1
24
my ($self, $style) = @_;
2206
2207
20
100
54
return $style if $style =~ /^(normal|none|)\z/;
2208
2209
15
41
my @styles = split /\s+/, $style;
2210
2211
15
50
64
return undef if grep(!/^(underline|overline|line-through|italic|bold)\z/, @styles);
2212
2213
15
25
$style;
2214
}
2215
2216
sub text_styles
2217
{
2218
# return a hash with the defined textstyles checked
2219
83
83
1
68
my ($self) = @_;
2220
2221
83
108
my $style = $self->attribute('textstyle');
2222
2223
83
100
128
return { none => 1 } if $style =~ /^(normal|none)\z/;
2224
81
100
160
return { } if $style eq '';
2225
2226
2
1
my $styles = {};
2227
2
9
for my $key ( split /\s+/, $style )
2228
{
2229
8
10
$styles->{$key} = 1;
2230
}
2231
2
4
$styles;
2232
}
2233
2234
sub text_styles_as_css
2235
{
2236
81
81
1
80
my ($self, $align, $fontsize) = @_;
2237
2238
81
59
my $style = '';
2239
81
122
my $ts = $self->text_styles();
2240
2241
81
50
163
$style .= " font-style: italic;" if $ts->{italic};
2242
81
50
113
$style .= " font-weight: bold;" if $ts->{bold};
2243
2244
81
50
33
325
if ($ts->{underline} || $ts->{none} || $ts->{overline} || $ts->{'line-through'})
66
33
2245
{
2246
# XXX TODO: HTML does seem to allow only one of them
2247
2
2
my @s;
2248
2
3
foreach my $k (qw/underline overline line-through none/)
2249
{
2250
8
100
17
push @s, $k if $ts->{$k};
2251
}
2252
2
5
my $s = join(' ', @s);
2253
2
50
6
$style .= " text-decoration: $s;" if $s;
2254
}
2255
2256
81
124
my $fs = $self->raw_attribute('fontsize');
2257
2258
81
100
123
$style .= " font-size: $fs;" if $fs;
2259
2260
81
100
114
if (!$align)
2261
{
2262
# XXX TODO: raw_attribute()?
2263
5
8
my $al = $self->attribute('align');
2264
5
50
15
$style .= " text-align: $al;" if $al;
2265
}
2266
2267
81
181
$style;
2268
}
2269
2270
sub _font_size_in_pixels
2271
{
2272
0
0
0
my ($self, $em, $val) = @_;
2273
2274
0
0
0
0
my $fs = $val; $fs = $self->attribute('fontsize') || '' if !defined $val;
0
0
2275
0
0
0
return $em if $fs eq '';
2276
2277
0
0
0
if ($fs =~ /^([\d.]+)em\z/)
0
0
2278
{
2279
0
0
$fs = $1 * $em;
2280
}
2281
elsif ($fs =~ /^([\d.]+)%\z/)
2282
{
2283
0
0
$fs = ($1 / 100) * $em;
2284
}
2285
# this is discouraged:
2286
elsif ($fs =~ /^([\d.]+)px\z/)
2287
{
2288
0
0
0
$fs = int($1 || 5);
2289
}
2290
else
2291
{
2292
0
0
$self->error("Illegal fontsize '$fs'");
2293
}
2294
0
0
$fs;
2295
}
2296
2297
# direction modifier in degrees
2298
my $modifier = {
2299
forward => 0, front => 0, left => -90, right => +90, back => +180,
2300
};
2301
2302
# map absolute direction to degrees
2303
my $dirs = {
2304
up => 0, north => 0, down => 180, south => 180, west => 270, east => 90,
2305
0 => 0, 180 => 180, 90 => 90, 270 => 270,
2306
};
2307
2308
# map absolute direction to side (south etc)
2309
my $sides = {
2310
north => 'north',
2311
south => 'south',
2312
east => 'east',
2313
west => 'west',
2314
up => 'north',
2315
down => 'south',
2316
0 => 'north',
2317
180 => 'south',
2318
90 => 'east',
2319
270 => 'west',
2320
};
2321
2322
sub _direction_as_number
2323
{
2324
743
743
851
my ($self,$dir) = @_;
2325
2326
743
809
my $d = $dirs->{$dir};
2327
743
50
1022
$self->_croak("$dir is not an absolut direction") unless defined $d;
2328
2329
743
1001
$d;
2330
}
2331
2332
sub _direction_as_side
2333
{
2334
512
512
464
my ($self,$dir) = @_;
2335
2336
512
100
1157
return unless exists $sides->{$dir};
2337
311
540
$sides->{$dir};
2338
}
2339
2340
sub _flow_as_direction
2341
{
2342
# Take a flow direction (0,90,180,270 etc), and a new direction (left|south etc)
2343
# and return the new flow. south et al will stay, while left|right etc depend
2344
# on the incoming flow.
2345
1966
1966
2084
my ($self, $inflow, $dir) = @_;
2346
2347
# in=south and dir=forward => south
2348
# in=south and dir=back => north etc
2349
# in=south and dir=east => east
2350
2351
# return 90 unless defined $dir;
2352
2353
1966
100
4893
if ($dir =~ /^(south|north|west|east|up|down|0|90|180|270)\z/)
2354
{
2355
# new direction is absolut, so inflow doesn't play a role
2356
# return 0,90,180 or 270
2357
1863
4094
return $dirs->{$dir};
2358
}
2359
2360
103
155
my $in = $dirs->{$inflow};
2361
103
126
my $modifier = $modifier->{$dir};
2362
2363
103
50
174
$self->_croak("$inflow,$dir results in undefined inflow") unless defined $in;
2364
103
50
141
$self->_croak("$inflow,$dir results in undefined modifier") unless defined $modifier;
2365
2366
103
103
my $out = $in + $modifier;
2367
103
172
$out -= 360 while $out >= 360; # normalize to 0..359
2368
103
164
$out += 360 while $out < 0; # normalize to 0..359
2369
2370
103
147
$out;
2371
}
2372
2373
sub _flow_as_side
2374
{
2375
# Take a flow direction (0,90,180,270 etc), and a new direction (left|south etc)
2376
# and return the new flow. south et al will stay, while left|right etc depend
2377
# on the incoming flow.
2378
205
205
207
my ($self, $inflow, $dir) = @_;
2379
2380
# in=south and dir=forward => south
2381
# in=south and dir=back => north etc
2382
# in=south and dir=east => east
2383
2384
# return 90 unless defined $dir;
2385
2386
205
100
405
if ($dir =~ /^(south|north|west|east|up|down|0|90|180|270)\z/)
2387
{
2388
# new direction is absolut, so inflow doesn't play a role
2389
# return east, west etc
2390
2
6
return $sides->{$dir};
2391
}
2392
2393
203
211
my $in = $dirs->{$inflow};
2394
203
229
my $modifier = $modifier->{$dir};
2395
2396
203
50
290
$self->_croak("$inflow,$dir results in undefined inflow") unless defined $in;
2397
203
50
228
$self->_croak("$inflow,$dir results in undefined modifier") unless defined $modifier;
2398
2399
203
169
my $out = $in + $modifier;
2400
203
50
252
$out -= 360 if $out >= 360; # normalize to 0..359
2401
2402
203
325
$sides->{$out};
2403
}
2404
2405
sub _direction
2406
{
2407
# check that a direction (south etc) is valid
2408
76
76
128
my ($self, $dir) = @_;
2409
2410
76
50
389
$dir =~ /^(south|east|west|north|down|up|0|90|180|270|front|forward|back|left|right)\z/ ? $dir : undef;
2411
}
2412
2413
sub _border_attribute_as_html
2414
{
2415
# Return "solid 1px red" from the individual border(style|color|width)
2416
# attributes, mainly for HTML output.
2417
94
94
106
my ($style, $width, $color, $scheme) = @_;
2418
2419
94
50
142
$style ||= '';
2420
94
50
147
$width = '' unless defined $width;
2421
94
50
127
$color = '' unless defined $color;
2422
2423
94
100
50
242
$color = Graph::Easy->color_as_hex($color,$scheme)||'' if $color !~ /^#/;
2424
2425
94
100
198
return $style if $style =~ /^(none|)\z/;
2426
2427
# width: 2px for double would collapse to one line
2428
92
100
125
$width = '' if $style =~ /^double/;
2429
2430
# convert the style and widths to something HTML can understand
2431
2432
92
50
124
$width = '0.5em' if $style eq 'broad';
2433
92
50
149
$width = '4px' if $style =~ /^bold/;
2434
92
50
111
$width = '1em' if $style eq 'wide';
2435
92
50
232
$style = 'solid' if $style =~ /(broad|wide|bold)\z/;
2436
92
50
127
$style = 'dashed' if $style eq 'bold-dash';
2437
92
100
122
$style = 'double' if $style eq 'double-dash';
2438
2439
92
100
269
$width = $width.'px' if $width =~ /^\s*\d+\s*\z/;
2440
2441
92
50
66
171
return '' if $width eq '' && $style ne 'double';
2442
2443
92
146
my $val = join(" ", $style, $width, $color);
2444
92
102
$val =~ s/^\s+//;
2445
92
146
$val =~ s/\s+\z//;
2446
2447
92
195
$val;
2448
}
2449
2450
sub _border_attribute
2451
{
2452
# Return "solid 1px red" from the individual border(style|color|width)
2453
# attributes. Used by as_txt().
2454
1165
1165
1108
my ($style, $width, $color) = @_;
2455
2456
1165
100
1714
$style ||= '';
2457
1165
50
1443
$width = '' unless defined $width;
2458
1165
50
1458
$color = '' unless defined $color;
2459
2460
1165
100
2483
return $style if $style =~ /^(none|)\z/;
2461
2462
1121
100
1721
$width = $width.'px' if $width =~ /^\s*\d+\s*\z/;
2463
2464
1121
2007
my $val = join(" ", $style, $width, $color);
2465
1121
1517
$val =~ s/^\s+//;
2466
1121
2658
$val =~ s/\s+\z//;
2467
2468
1121
4870
$val;
2469
}
2470
2471
sub _border_width_in_pixels
2472
{
2473
1895
1895
1602
my ($self, $em) = @_;
2474
2475
1895
100
2654
my $bw = $self->attribute('borderwidth') || '0';
2476
1895
100
2724
return 0 if $bw eq '0';
2477
2478
1831
50
2447
my $bs = $self->attribute('borderstyle') || 'none';
2479
2480
1831
100
2722
return 0 if $bs eq 'none';
2481
1809
100
2695
return 3 if $bs =~ /^bold/;
2482
1806
100
2314
return $em / 2 if $bs =~ /^broad/;
2483
1805
50
2438
return $em if $bs =~ /^wide/;
2484
2485
# width: 1 is 1px;
2486
1805
50
6711
return $bw if $bw =~ /^([\d.]+)\z/;
2487
2488
0
0
0
if ($bw =~ /^([\d.]+)em\z/)
0
0
2489
{
2490
0
0
$bw = $1 * $em;
2491
}
2492
elsif ($bw =~ /^([\d.]+)%\z/)
2493
{
2494
0
0
$bw = ($1 / 100) * $em;
2495
}
2496
# this is discouraged:
2497
elsif ($bw =~ /^([\d.]+)px\z/)
2498
{
2499
0
0
$bw = $1;
2500
}
2501
else
2502
{
2503
0
0
$self->error("Illegal borderwidth '$bw'");
2504
}
2505
0
0
$bw;
2506
}
2507
2508
sub _angle
2509
{
2510
# check an angle for being valid
2511
19
19
19
my ($self, $angle) = @_;
2512
2513
19
50
66
return undef unless $angle =~ /^([+-]?\d{1,3}|south|west|east|north|up|down|left|right|front|back|forward)\z/;
2514
2515
19
21
$angle;
2516
}
2517
2518
sub _uint
2519
{
2520
# check a small unsigned integer for being valid
2521
1
1
2
my ($self, $val) = @_;
2522
2523
1
50
6
return undef unless $val =~ /^\d+\z/;
2524
2525
1
2
$val = abs(int($val));
2526
1
50
3
$val = 4 * 1024 if $val > 4 * 1024;
2527
2528
1
2
$val;
2529
}
2530
2531
sub _font
2532
{
2533
# check a font-list for being valid
2534
3
3
6
my ($self, $font) = @_;
2535
2536
3
7
$font;
2537
}
2538
2539
sub split_border_attributes
2540
{
2541
# split "1px solid black" or "red dotted" into style, width and color
2542
39
39
1
48
my ($self,$border) = @_;
2543
2544
# special case
2545
39
100
82
return ('none', undef, undef) if $border eq '0';
2546
2547
# extract style
2548
36
38
my $style;
2549
36
181
$border =~
2550
35
52
s/(solid|dotted|dot-dot-dash|dot-dash|dashed|double-dash|double|bold-dash|bold|broad|wide|wave|none)/$style=$1;''/eg;
35
70
2551
2552
36
100
64
$style ||= 'solid';
2553
2554
# extract width
2555
36
53
$border =~ s/(\d+(px|em|%))//g;
2556
2557
36
100
79
my $width = $1 || '';
2558
36
93
$width =~ s/[^0-9]+//g; # leave only digits
2559
2560
36
49
$border =~ s/\s+//g; # rem unnec. spaces
2561
2562
# The left-over part must be a valid color.
2563
36
35
my $color = $border;
2564
36
100
82
$color = Graph::Easy->_color($border) if $border ne '';
2565
2566
36
50
58
$self->error("$border is not a valid bordercolor")
2567
unless defined $color;
2568
2569
36
100
63
$width = undef if $width eq '';
2570
36
100
53
$color = undef if $color eq '';
2571
36
50
65
$style = undef if $style eq '';
2572
36
138
($style,$width,$color);
2573
}
2574
2575
#############################################################################
2576
# attribute checking
2577
2578
# different types of attributes with pre-defined handling
2579
use constant {
2580
48
175122
ATTR_STRING => 0, # an arbitrary string
2581
ATTR_COLOR => 1, # color name or value like rgb(1,1,1)
2582
ATTR_ANGLE => 2, # 0 .. 359.99
2583
ATTR_PORT => 3, # east, etc.
2584
ATTR_UINT => 4, # a "small" unsigned integer
2585
ATTR_URL => 5,
2586
2587
# these cannot have "inherit", see ATTR_INHERIT_MIN
2588
ATTR_LIST => 6, # a list of values
2589
ATTR_LCTEXT => 7, # lowercase text (classname)
2590
ATTR_TEXT => 8, # titles, links, labels etc
2591
2592
ATTR_NO_INHERIT => 6,
2593
2594
ATTR_DESC_SLOT => 0,
2595
ATTR_MATCH_SLOT => 1,
2596
ATTR_DEFAULT_SLOT => 2,
2597
ATTR_EXAMPLE_SLOT => 3,
2598
ATTR_TYPE_SLOT => 4,
2599
2600
2601
48
48
282552
};
48
252
2602
2603
# Lists the attribute names along with
2604
# * a short description,
2605
# * regexp or sub name to match valid attributes
2606
# * default value
2607
# * an short example value
2608
# * type
2609
# * graph examples
2610
2611
my $attributes = {
2612
all => {
2613
align => [
2614
"The alignment of the label text.",
2615
[ qw/center left right/ ],
2616
{ default => 'center', group => 'left', edge => 'left' },
2617
'right',
2618
undef,
2619
"graph { align: left; label: My Graph; }\nnode {align: left;}\n ( Nodes:\n [ Right\\nAligned ] { align: right; } -- label\\n text -->\n { align: left; }\n [ Left\\naligned ] )",
2620
],
2621
2622
autolink => [
2623
"If set to something else than 'none', will use the appropriate attribute to automatically generate the L , unless L is already set. See the section about labels, titles, names and links for reference.",
2624
[ qw/label title name none inherit/ ],
2625
{ default => 'inherit', graph => 'none' },
2626
'title',
2627
],
2628
2629
autotitle => [
2630
"If set to something else than 'none', will use the appropriate attribute to automatically generate the L, unless L is already set. See the section about labels, titles, names and links for reference.",
2631
[ qw/label name none link inherit/ ],
2632
{ default => 'inherit', graph => 'none' },
2633
'label',
2634
],
2635
2636
autolabel => [
2637
"Will restrict the L text to N characters. N must be greater than 10. See the section about labels, titles, names and links for reference.",
2638
# for compatibility with older versions (pre v0.49), also allow "name,N"
2639
qr/^(name\s*,\s*)?[\d]{2,5}\z/,
2640
{ default => 'inherit', graph => '' },
2641
'20',
2642
undef,
2643
"graph { autolabel: 20; autotitle: name; }\n\n[ Bonn ]\n -- Acme Travels Incorporated -->\n [ Frankfurt (Main) / Flughafen ]",
2644
],
2645
2646
background => [
2647
"The background color, e.g. the color B the shape. Do not confuse with L. If set to inherit, the object will inherit the L color (B the background color!) of the parent e.g. the enclosing group or graph. See the section about color names and values for reference.",
2648
undef,
2649
# { default => 'inherit', graph => 'white', 'group.anon' => 'white', 'node.anon' => 'white' },
2650
'inherit',
2651
'rgb(255,0,0)',
2652
ATTR_COLOR,
2653
"[ Crimson ] { shape: circle; background: crimson; }\n -- Aqua Marine --> { background: #7fffd4; }\n [ Misty Rose ]\n { background: white; fill: rgb(255,228,221); shape: ellipse; }",
2654
],
2655
2656
class => [
2657
'The subclass of the object. See the section about class names for reference.',
2658
qr/^(|[a-zA-Z][a-zA-Z0-9_]*)\z/,
2659
'',
2660
'mynodeclass',
2661
ATTR_LCTEXT,
2662
],
2663
2664
color => [
2665
'The foreground/text/label color. See the section about color names and values for reference.',
2666
undef,
2667
'black',
2668
'rgb(255,255,0)',
2669
ATTR_COLOR,
2670
"[ Lime ] { color: limegreen; }\n -- label --> { color: blue; labelcolor: red; }\n [ Dark Orange ] { color: rgb(255,50%,0.01); }",
2671
],
2672
2673
colorscheme => [
2674
"The colorscheme to use for all color values. See the section about color names and values for reference and a list of possible values.",
2675
'_color_scheme',
2676
{ default => 'inherit', graph => 'w3c', },
2677
'x11',
2678
ATTR_STRING,
2679
"graph { colorscheme: accent8; } [ 1 ] { fill: 1; }\n"
2680
. " -> \n [ 3 ] { fill: 3; }\n"
2681
. " -> \n [ 4 ] { fill: 4; }\n"
2682
. " -> \n [ 5 ] { fill: 5; }\n"
2683
. " -> \n [ 6 ] { fill: 6; }\n"
2684
. " -> \n [ 7 ] { fill: 7; }\n"
2685
. " -> \n [ 8 ] { fill: 8; }\n" ,
2686
],
2687
2688
comment => [
2689
"A free-form text field containing a comment on this object. This will be embedded into output formats if possible, e.g. in HTML, SVG and Graphviz, but not ASCII or Boxart.",
2690
undef,
2691
'',
2692
'(C) by Tels 2007. All rights reserved.',
2693
ATTR_STRING,
2694
"graph { comment: German capitals; }\n [ Bonn ] --> [ Berlin ]",
2695
],
2696
2697
fill => [
2698
"The fill color, e.g. the color inside the shape. For the graph, this is the background color for the label. For edges, defines the color inside the arrow shape. See also L. See the section about color names and values for reference.",
2699
undef,
2700
{ default => 'white', graph => 'inherit', edge => 'inherit', group => '#a0d0ff',
2701
'group.anon' => 'white', 'node.anon' => 'inherit' },
2702
'rgb(255,0,0)',
2703
ATTR_COLOR,
2704
"[ Crimson ]\n {\n shape: circle;\n background: yellow;\n fill: red;\n border: 3px solid blue;\n }\n-- Aqua Marine -->\n {\n arrowstyle: filled;\n fill: red;\n }\n[ Two ]",
2705
],
2706
2707
'fontsize' => [
2708
"The size of the label text, best expressed in I (1.0em, 0.5em etc) or percent (100%, 50% etc)",
2709
qr/^\d+(\.\d+)?(em|px|%)?\z/,
2710
{ default => '0.8em', graph => '1em', node => '1em', },
2711
'50%',
2712
undef,
2713
"graph { fontsize: 200%; label: Sample; }\n\n ( Nodes:\n [ Big ] { fontsize: 1.5em; color: white; fill: darkred; }\n -- Small -->\n { fontsize: 0.2em; }\n [ Normal ] )",
2714
],
2715
2716
flow => [
2717
"The general direction in which edges will leave nodes first. On edges, influeces where the target node is place. Please see the section about flow control for reference.",
2718
'_direction',
2719
{ graph => 'east', default => 'inherit' },
2720
'south',
2721
undef,
2722
"graph { flow: up; }\n [ Enschede ] { flow: left; } -> [ Bielefeld ] -> [ Wolfsburg ]",
2723
],
2724
2725
font => [
2726
'A prioritized list of lower-case, unquoted values, separated by a comma. Values are either font family names (like "times", "arial" etc) or generic family names (like "serif", "cursive", "monospace"), the first recognized value will be used. Always offer a generic name as the last possibility.',
2727
'_font',
2728
{ default => 'serif', edge => 'sans-serif' },
2729
'arial, helvetica, sans-serif',
2730
undef,
2731
"graph { font: vinque, georgia, utopia, serif; label: Sample; }" .
2732
"\n\n ( Nodes:\n [ Webdings ] { font: Dingbats, webdings; }\n".
2733
" -- FlatLine -->\n { font: flatline; }\n [ Normal ] )",
2734
],
2735
2736
id => [
2737
"A unique identifier for this object, consisting only of letters, digits, or underscores.",
2738
qr/^[a-zA-Z0-9_]+\z/,
2739
'',
2740
'Bonn123',
2741
undef,
2742
"[ Bonn ] --> { id: 123; } [ Berlin ]",
2743
],
2744
2745
label => [
2746
"The text displayed as label. If not set, equals the name (for nodes) or no label (for edges, groups and the graph itself).",
2747
undef,
2748
undef,
2749
'My label',
2750
ATTR_TEXT,
2751
],
2752
2753
linkbase => [
2754
'The base URL prepended to all generated links. See the section about links for reference.',
2755
undef,
2756
{ default => 'inherit', graph => '/wiki/index.php/', },
2757
'http://en.wikipedia.org/wiki/',
2758
ATTR_URL,
2759
],
2760
2761
link => [
2762
'The link part, appended onto L. See the section about links for reference.',
2763
undef,
2764
'',
2765
'Graph',
2766
ATTR_TEXT,
2767
<
2768
node {
2769
autolink: name;
2770
textstyle: none;
2771
fontsize: 1.1em;
2772
}
2773
graph {
2774
linkbase: http://de.wikipedia.org/wiki/;
2775
}
2776
edge {
2777
textstyle: overline;
2778
}
2779
2780
[] --> [ Friedrichshafen ]
2781
-- Schiff --> { autolink: label; color: orange; title: Vrooom!; }
2782
[ Immenstaad ] { color: green; } --> [ Hagnau ]
2783
LINK_EOF
2784
],
2785
2786
title => [
2787
"The text displayed as mouse-over for nodes/edges, or as the title for the graph. If empty, no title will be generated unless L is set.",
2788
undef,
2789
'',
2790
'My title',
2791
ATTR_TEXT,
2792
],
2793
2794
format => [
2795
"The formatting language of the label. The default, C means nothing special will be done. When set to C, formatting codes like B<bold>
will change the formatting of the label. See the section about label text formatting for reference.",
2796
[ 'none', 'pod' ],
2797
'none',
2798
'pod',
2799
undef,
2800
<
2801
graph {
2802
format: pod;
2803
label: I am B and I;
2804
}
2805
node { format: pod; }
2806
edge { format: pod; }
2807
2808
[ U> ]
2809
--> { label: "S"; }
2810
[ O ]
2811
EOF
2812
],
2813
2814
textstyle => [
2815
"The style of the label text. Either 'none', or any combination (separated with spaces) of 'underline', 'overline', 'bold', 'italic', 'line-through'. 'none' disables underlines on links.",
2816
'text_style',
2817
'',
2818
'underline italic bold',
2819
undef,
2820
<
2821
graph {
2822
fontsize: 150%;
2823
label: Verbindung;
2824
textstyle: bold italic;
2825
}
2826
node {
2827
textstyle: underline bold;
2828
fill: #ffd080;
2829
}
2830
edge {
2831
textstyle: italic bold overline;
2832
}
2833
2834
[ Meersburg ] { fontsize: 2em; }
2835
-- F\x{e4}hre --> { fontsize: 1.2em; color: red; }
2836
[ Konstanz ]
2837
EOF
2838
],
2839
2840
textwrap => [
2841
"The default C makes the label text appear exactly as it was written, with manual line breaks applied. When set to a positive number, the label text will be wrapped after this number of characters. When set to C, the label text will be wrapped to make the node size as small as possible, depending on output format this may even be dynamic. When not C, manual line breaks and alignments on them are ignored.",
2842
qr/^(auto|none|\d{1,4})/,
2843
{ default => 'inherit', graph => 'none' },
2844
'auto',
2845
undef,
2846
"node { textwrap: auto; }\n ( Nodes:\n [ Frankfurt (Oder) liegt an der\n ostdeutschen Grenze und an der Oder ] -->\n [ Städte innerhalb der\n Ost-Westfahlen Region mit sehr langen Namen] )",
2847
],
2848
},
2849
2850
node => {
2851
bordercolor => [
2852
'The color of the L. See the section about color names and values for reference.',
2853
undef,
2854
{ default => '#000000' },
2855
'rgb(255,255,0)',
2856
ATTR_COLOR,
2857
"node { border: black bold; }\n[ Black ]\n --> [ Red ] { bordercolor: red; }\n --> [ Green ] { bordercolor: green; }",
2858
],
2859
2860
borderstyle => [
2861
'The style of the L. The special styles "bold", "broad", "wide", "double-dash" and "bold-dash" will set and override the L.',
2862
[ qw/none solid dotted dashed dot-dash dot-dot-dash double wave bold bold-dash broad double-dash wide/ ],
2863
{ default => 'none', 'node.anon' => 'none', 'group.anon' => 'none', node => 'solid', group => 'dashed' },
2864
'dotted',
2865
undef,
2866
"node { border: dotted; }\n[ Dotted ]\n --> [ Dashed ] { borderstyle: dashed; }\n --> [ broad ] { borderstyle: broad; }",
2867
],
2868
2869
borderwidth => [
2870
'The width of the L. Certain L-styles will override the width.',
2871
qr/^\d+(px|em)?\z/,
2872
'1',
2873
'2px',
2874
],
2875
2876
border => [
2877
'The border. Can be any combination of L, L and L.',
2878
undef,
2879
{ default => 'none', 'node.anon' => 'none', 'group.anon' => 'none', node => 'solid 1px #000000', group => 'dashed 1px #000000' },
2880
'dotted red',
2881
undef,
2882
"[ Normal ]\n --> [ Bold ] { border: bold; }\n --> [ Broad ] { border: broad; }\n --> [ Wide ] { border: wide; }\n --> [ Bold-Dash ] { border: bold-dash; }",
2883
],
2884
2885
basename => [
2886
"Controls the base name of an autosplit node. Ignored for all other nodes. Unless set, it is generated automatically from the node parts. Please see the section about autosplit for reference.",
2887
undef,
2888
'',
2889
'123',
2890
undef,
2891
"[ A|B|C ] { basename: A } [ 1 ] -> [ A.2 ]\n [ A|B|C ] [ 2 ] -> [ ABC.2 ]",
2892
],
2893
2894
group => [
2895
"Puts the node into this group.",
2896
undef,
2897
'',
2898
'Cities',
2899
undef,
2900
"[ A ] { group: Cities:; } ( Cities: [ B ] ) [ A ] --> [ B ]",
2901
],
2902
2903
size => [
2904
'The size of the node in columns and rows. Must be greater than 1 in each direction.',
2905
qr/^\d+\s*,\s*\d+\z/,
2906
'1,1',
2907
'3,2',
2908
],
2909
rows => [
2910
'The size of the node in rows. See also L.',
2911
qr/^\d+\z/,
2912
'1',
2913
'3',
2914
],
2915
columns => [
2916
'The size of the node in columns. See also L.',
2917
qr/^\d+\z/,
2918
'1',
2919
'2',
2920
],
2921
2922
offset => [
2923
'The offset of this node from the L node, in columns and rows. Only used if you also set the L node.',
2924
qr/^[+-]?\d+\s*,\s*[+-]?\d+\z/,
2925
'0,0',
2926
'3,2',
2927
undef,
2928
"[ A ] -> [ B ] { origin: A; offset: 2,2; }",
2929
],
2930
2931
origin => [
2932
'The name of the node, that this node is relativ to. See also L.',
2933
undef,
2934
'',
2935
'Cluster A',
2936
],
2937
2938
pointshape => [
2939
"Controls the style of a node that has a L of 'point'.",
2940
[ qw/star square dot circle cross diamond invisible x/ ],
2941
'star',
2942
'square',
2943
undef,
2944
"node { shape: point; }\n\n [ A ]".
2945
"\n -> [ B ] { pointshape: circle; }" .
2946
"\n -> [ C ] { pointshape: cross; }" .
2947
"\n -> [ D ] { pointshape: diamond; }" .
2948
"\n -> [ E ] { pointshape: dot; }" .
2949
"\n -> [ F ] { pointshape: invisible; }" .
2950
"\n -> [ G ] { pointshape: square; }" .
2951
"\n -> [ H ] { pointshape: star; }" .
2952
"\n -> [ I ] { pointshape: x; }" .
2953
"\n -> [ ☯ ] { shape: none; }"
2954
],
2955
2956
pointstyle => [
2957
"Controls the style of the L of a node that has a L of 'point'. " .
2958
"Note for backwards compatibility reasons, the shape names 'star', 'square', 'dot', 'circle', 'cross', 'diamond' and 'invisible' ".
2959
"are also supported, but should not be used here, instead set them via L.",
2960
[ qw/closed filled star square dot circle cross diamond invisible x/ ],
2961
'filled',
2962
'open',
2963
undef,
2964
"node { shape: point; pointstyle: closed; pointshape: diamond; }\n\n [ A ] --> [ B ] { pointstyle: filled; }",
2965
],
2966
2967
rank => [
2968
"The rank of the node, used by the layouter to find the order and placement of nodes. " .
2969
"Set to C (the default), C (useful for node lists) or a positive number. " .
2970
"See the section about ranks for reference and more examples.",
2971
qr/^(auto|same|\d{1,6})\z/,
2972
'auto',
2973
'same',
2974
undef,
2975
"[ Bonn ], [ Berlin ] { rank: same; }\n [ Bonn ] -> [ Cottbus ] -> [ Berlin ]",
2976
],
2977
2978
rotate => [
2979
"The rotation of the node shape, either an absolute value (like C, C, C or C<123>), or a relative value (like C<+12>, C<-90>, C, C). For relative angles, the rotation will be based on the node's L. Rotation is clockwise.",
2980
undef,
2981
'0',
2982
'180',
2983
ATTR_ANGLE,
2984
"[ Bonn ] { rotate: 45; } -- ICE --> \n [ Berlin ] { shape: triangle; rotate: -90; }",
2985
],
2986
2987
shape => [
2988
"The shape of the node. Nodes with shape 'point' (see L) have a fixed size and do not display their label. The border of such a node is the outline of the C, and the fill is the inside of the C. When the C is set to the value 'img', the L will be interpreted as an external image resource to display. In this case attributes like L, L etc. are ignored.",
2989
[ qw/ circle diamond edge ellipse hexagon house invisible invhouse invtrapezium invtriangle octagon parallelogram pentagon
2990
point triangle trapezium septagon rect rounded none img/ ],
2991
'rect',
2992
'circle',
2993
undef,
2994
"[ Bonn ] -> \n [ Berlin ] { shape: circle; }\n -> [ Regensburg ] { shape: rounded; }\n -> [ Ulm ] { shape: point; }\n -> [ Wasserburg ] { shape: invisible; }\n -> [ Augsburg ] { shape: triangle; }\n -> [ House ] { shape: img; label: img/house.png;\n border: none; title: My House; fill: inherit; }",
2995
],
2996
2997
}, # node
2998
2999
graph => {
3000
3001
bordercolor => [
3002
'The color of the L. See the section about color names and values for reference.',
3003
undef,
3004
{ default => '#000000' },
3005
'rgb(255,255,0)',
3006
ATTR_COLOR,
3007
"node { border: black bold; }\n[ Black ]\n --> [ Red ] { bordercolor: red; }\n --> [ Green ] { bordercolor: green; }",
3008
],
3009
3010
borderstyle => [
3011
'The style of the L. The special styles "bold", "broad", "wide", "double-dash" and "bold-dash" will set and override the L.',
3012
[ qw/none solid dotted dashed dot-dash dot-dot-dash double wave bold bold-dash broad double-dash wide/ ],
3013
{ default => 'none', 'node.anon' => 'none', 'group.anon' => 'none', node => 'solid', group => 'dashed' },
3014
'dotted',
3015
undef,
3016
"node { border: dotted; }\n[ Dotted ]\n --> [ Dashed ] { borderstyle: dashed; }\n --> [ broad ] { borderstyle: broad; }",
3017
],
3018
3019
borderwidth => [
3020
'The width of the L. Certain L-styles will override the width.',
3021
qr/^\d+(px|em)?\z/,
3022
'1',
3023
'2px',
3024
],
3025
3026
border => [
3027
'The border. Can be any combination of L, L and L.',
3028
undef,
3029
{ default => 'none', 'node.anon' => 'none', 'group.anon' => 'none', node => 'solid 1px #000000', group => 'dashed 1px #000000' },
3030
'dotted red',
3031
undef,
3032
"[ Normal ]\n --> [ Bold ] { border: bold; }\n --> [ Broad ] { border: broad; }\n --> [ Wide ] { border: wide; }\n --> [ Bold-Dash ] { border: bold-dash; }",
3033
],
3034
3035
gid => [
3036
"A unique ID for the graph. Useful if you want to include two graphs into one HTML page.",
3037
qr/^\d+\z/,
3038
'',
3039
'123',
3040
],
3041
3042
labelpos => [
3043
"The position of the graph label.",
3044
[ qw/top bottom/ ],
3045
'top',
3046
'bottom',
3047
ATTR_LIST,
3048
"graph { labelpos: bottom; label: My Graph; }\n\n [ Buxtehude ] -> [ Fuchsberg ]\n"
3049
],
3050
3051
output => [
3052
"The desired output format. Only used when calling Graph::Easy::output(), or by mediawiki-graph.",
3053
[ qw/ascii html svg graphviz boxart debug/ ],
3054
'',
3055
'ascii',
3056
ATTR_LIST,
3057
"graph { output: debug; }"
3058
],
3059
3060
root => [
3061
"The name of the root node, given as hint to the layouter to start the layout there. When not set, the layouter will pick a node at semi-random.",
3062
undef,
3063
'',
3064
'My Node',
3065
ATTR_TEXT,
3066
"graph { root: B; }\n # B will be at the left-most place\n [ A ] --> [ B ] --> [ C ] --> [ D ] --> [ A ]",
3067
],
3068
3069
type => [
3070
"The type of the graph, either undirected or directed.",
3071
[ qw/directed undirected/ ],
3072
'directed',
3073
'undirected',
3074
ATTR_LIST,
3075
"graph { type: undirected; }\n [ A ] --> [ B ]",
3076
],
3077
3078
}, # graph
3079
3080
edge => {
3081
3082
style => [
3083
'The line style of the edge. When set on the general edge class, this attribute changes only the style of all solid edges to the specified one.',
3084
[ qw/solid dotted dashed dot-dash dot-dot-dash bold bold-dash double-dash double wave broad wide invisible/], # broad-dash wide-dash/ ],
3085
'solid',
3086
'dotted',
3087
undef,
3088
"[ A ] -- solid --> [ B ]\n .. dotted ..> [ C ]\n - dashed - > [ D ]\n -- bold --> { style: bold; } [ E ]\n -- broad --> { style: broad; } [ F ]\n -- wide --> { style: wide; } [ G ]",
3089
],
3090
3091
arrowstyle => [
3092
'The style of the arrow. Open arrows are vee-shaped and the bit inside the arrow has the color of the L. Closed arrows are triangle shaped, with a background-color fill. Filled arrows are closed, too, but use the L color for the inside. If the fill color is not set, the L attribute will be used instead. An C of none creates undirected edges just like "[A] -- [B]" would do.',
3093
[ qw/none open closed filled/ ],
3094
'open',
3095
'closed',
3096
undef,
3097
"[ A ] -- open --> [ B ]\n -- closed --> { arrowstyle: closed; } [ C ]\n -- filled --> { arrowstyle: filled; } [ D ]\n -- filled --> { arrowstyle: filled; fill: lime; } [ E ]\n -- none --> { arrowstyle: none; } [ F ]",
3098
],
3099
3100
arrowshape => [
3101
'The basic shape of the arrow. Can be combined with each of L.',
3102
[ qw/triangle box dot inv line diamond cross x/ ],
3103
'triangle',
3104
'box',
3105
undef,
3106
"[ A ] -- triangle --> [ B ]\n -- box --> { arrowshape: box; } [ C ]\n" .
3107
" -- inv --> { arrowshape: inv; } [ D ]\n -- diamond --> { arrowshape: diamond; } [ E ]\n" .
3108
" -- dot --> { arrowshape: dot; } [ F ]\n" .
3109
" -- line --> { arrowshape: line; } [ G ] \n" .
3110
" -- plus --> { arrowshape: cross; } [ H ] \n" .
3111
" -- x --> { arrowshape: x; } [ I ] \n\n" .
3112
"[ a ] -- triangle --> { arrowstyle: filled; } [ b ]\n".
3113
" -- box --> { arrowshape: box; arrowstyle: filled; } [ c ]\n" .
3114
" -- inv --> { arrowshape: inv; arrowstyle: filled; } [ d ]\n" .
3115
" -- diamond --> { arrowshape: diamond; arrowstyle: filled; } [ e ]\n" .
3116
" -- dot --> { arrowshape: dot; arrowstyle: filled; } [ f ]\n" .
3117
" -- line --> { arrowshape: line; arrowstyle: filled; } [ g ] \n" .
3118
" -- plus --> { arrowshape: cross; arrowstyle: filled; } [ h ] \n" .
3119
" -- x --> { arrowshape: x; arrowstyle: filled; } [ i ] \n",
3120
],
3121
3122
labelcolor => [
3123
'The text color for the label. If unspecified, will fall back to L. See the section about color names and values for reference.',
3124
undef,
3125
'black',
3126
'rgb(255,255,0)',
3127
ATTR_COLOR,
3128
"[ Bonn ] -- ICE --> { labelcolor: blue; }\n [ Berlin ]",
3129
],
3130
3131
start => [
3132
'The starting port of this edge. See the section about joints for reference.',
3133
qr/^(south|north|east|west|left|right|front|back)(\s*,\s*-?\d{1,4})?\z/,
3134
'',
3135
'front, 0',
3136
ATTR_PORT,
3137
"[ Bonn ] -- NORTH --> { start: north; end: north; } [ Berlin ]",
3138
],
3139
3140
end => [
3141
'The ending port of this edge. See the section about joints for reference.',
3142
qr/^(south|north|east|west|right|left|front|back)(\s*,\s*-?\d{1,4})?\z/,
3143
'',
3144
'back, 0',
3145
ATTR_PORT,
3146
"[ Bonn ] -- NORTH --> { start: south; end: east; } [ Berlin ]",
3147
],
3148
3149
minlen => [
3150
'The minimum length of the edge, in cells. Defaults to 1. The minimum length is ' .
3151
'automatically increased for edges with joints.',
3152
undef,
3153
'1',
3154
'4',
3155
ATTR_UINT,
3156
"[ Bonn ] -- longer --> { minlen: 3; } [ Berlin ]\n[ Bonn ] --> [ Potsdam ] { origin: Bonn; offset: 2,2; }",
3157
],
3158
3159
autojoin => [
3160
'Controls whether the layouter can join this edge automatically with other edges leading to the same node. C means this edge will never joined with another edge automatically, C means always (if possible), even if the attributes on the edges do not match. C means only edges with the same set of attributes will be automatically joined together. See also C.',
3161
[qw/never always equals/],
3162
'never',
3163
'always',
3164
undef,
3165
"[ Bonn ], [ Aachen ]\n -- 1 --> { autojoin: equals; } [ Berlin ]",
3166
],
3167
3168
autosplit => [
3169
'Controls whether the layouter replace multiple edges leading from one node to other nodes with one edge splitting up. C means this edge will never be part of such a split, C means always (if possible), even if the attributes on the edges do not match. C means only edges with the same set of attributes will be automatically split up. See also C.',
3170
[qw/never always equals/],
3171
'never',
3172
'always',
3173
undef,
3174
"[ Bonn ]\n -- 1 --> { autosplit: equals; } [ Berlin ], [ Aachen ]",
3175
],
3176
3177
}, # edge
3178
3179
group => {
3180
bordercolor => [
3181
'The color of the L. See the section about color names and values for reference.',
3182
undef,
3183
{ default => '#000000' },
3184
'rgb(255,255,0)',
3185
ATTR_COLOR,
3186
"node { border: black bold; }\n[ Black ]\n --> [ Red ] { bordercolor: red; }\n --> [ Green ] { bordercolor: green; }",
3187
],
3188
3189
borderstyle => [
3190
'The style of the L. The special styles "bold", "broad", "wide", "double-dash" and "bold-dash" will set and override the L.',
3191
[ qw/none solid dotted dashed dot-dash dot-dot-dash double wave bold bold-dash broad double-dash wide/ ],
3192
{ default => 'none', 'node.anon' => 'none', 'group.anon' => 'none', node => 'solid', group => 'dashed' },
3193
'dotted',
3194
undef,
3195
"node { border: dotted; }\n[ Dotted ]\n --> [ Dashed ] { borderstyle: dashed; }\n --> [ broad ] { borderstyle: broad; }",
3196
],
3197
3198
borderwidth => [
3199
'The width of the L. Certain L-styles will override the width.',
3200
qr/^\d+(px|em)?\z/,
3201
'1',
3202
'2px',
3203
],
3204
3205
border => [
3206
'The border. Can be any combination of L, L and L.',
3207
undef,
3208
{ default => 'none', 'node.anon' => 'none', 'group.anon' => 'none', node => 'solid 1px #000000', group => 'dashed 1px #000000' },
3209
'dotted red',
3210
undef,
3211
"[ Normal ]\n --> [ Bold ] { border: bold; }\n --> [ Broad ] { border: broad; }\n --> [ Wide ] { border: wide; }\n --> [ Bold-Dash ] { border: bold-dash; }",
3212
],
3213
3214
nodeclass => [
3215
'The class into which all nodes of this group are put.',
3216
qr/^(|[a-zA-Z][a-zA-Z0-9_]*)\z/,
3217
'',
3218
'cities',
3219
],
3220
3221
edgeclass => [
3222
'The class into which all edges defined in this group are put. This includes edges that run between two nodes belonging to the same group.',
3223
qr/^(|[a-zA-Z][a-zA-Z0-9_]*)\z/,
3224
'',
3225
'connections',
3226
],
3227
3228
rank => [
3229
"The rank of the group, used by the layouter to find the order and placement of group. " .
3230
"Set to C (the default), C or a positive number. " .
3231
"See the section about ranks for reference and more examples.",
3232
qr/^(auto|same|\d{1,6})\z/,
3233
'auto',
3234
'same',
3235
undef,
3236
"( Cities: [ Bonn ], [ Berlin ] ) { rank: 0; } ( Rivers: [ Rhein ], [ Sieg ] ) { rank: 0; }",
3237
],
3238
3239
root => [
3240
"The name of the root node, given as hint to the layouter to start the layout there. When not set, the layouter will pick a node at semi-random.",
3241
undef,
3242
'',
3243
'My Node',
3244
ATTR_TEXT,
3245
"( Cities: [ A ] --> [ B ] --> [ C ] --> [ D ] --> [ A ] ) { root: B; }",
3246
],
3247
3248
group => [
3249
"Puts the group inside this group, nesting the two groups inside each other.",
3250
undef,
3251
'',
3252
'Cities',
3253
undef,
3254
"( Cities: [ Bonn ] ) ( Rivers: [ Rhein ] ) { group: Cities:; }",
3255
],
3256
3257
labelpos => [
3258
"The position of the group label.",
3259
[ qw/top bottom/ ],
3260
'top',
3261
'bottom',
3262
ATTR_LIST,
3263
"group { labelpos: bottom; }\n\n ( My Group: [ Buxtehude ] -> [ Fuchsberg ] )\n"
3264
],
3265
3266
}, # group
3267
3268
# These entries will be allowed temporarily during Graphviz parsing for
3269
# intermidiate values, like "shape=record".
3270
special => { },
3271
}; # end of attribute definitions
3272
3273
sub _allow_special_attributes
3274
{
3275
# store a hash with special temp. attributes
3276
224
224
203
my ($self, $att) = @_;
3277
224
321
$attributes->{special} = $att;
3278
}
3279
3280
sub _drop_special_attributes
3281
{
3282
# drop the hash with special temp. attributes
3283
1241
1241
1278
my ($self) = @_;
3284
3285
1241
2256
$attributes->{special} = {};
3286
}
3287
3288
sub _attribute_entries
3289
{
3290
# for building the manual page
3291
0
0
0
$attributes;
3292
}
3293
3294
sub border_attribute
3295
{
3296
# Return "1px solid red" from the border-(style|color|width) attributes,
3297
# mainly used by as_txt() output. Does not use colorscheme!
3298
2168
2168
1
2073
my ($self, $class) = @_;
3299
3300
2168
1353
my ($style,$width,$color);
3301
3302
2168
100
1595
my $g = $self; $g = $self->{graph} if ref($self->{graph});
2168
3605
3303
3304
2168
1428
my ($def_style, $def_color, $def_width);
3305
3306
# XXX TODO need no_default_attribute()
3307
2168
100
2563
if (defined $class)
3308
{
3309
1299
1830
$style = $g->attribute($class, 'borderstyle');
3310
1299
100
2490
return $style if $style eq 'none';
3311
3312
1077
1669
$def_style = $g->default_attribute('borderstyle');
3313
3314
1077
1525
$width = $g->attribute($class,'borderwidth');
3315
1077
1990
$def_width = $g->default_attribute($class,'borderwidth');
3316
1077
100
1742
$width = '' if $def_width eq $width;
3317
3318
1077
1275
$color = $g->attribute($class,'bordercolor');
3319
1077
1568
$def_color = $g->default_attribute($class,'bordercolor');
3320
1077
100
1814
$color = '' if $def_color eq $color;
3321
}
3322
else
3323
{
3324
869
1188
$style = $self->attribute('borderstyle');
3325
869
100
1405
return $style if $style eq 'none';
3326
3327
830
1271
$def_style = $self->default_attribute('borderstyle');
3328
3329
830
1114
$width = $self->attribute('borderwidth');
3330
830
1255
$def_width = $self->default_attribute('borderwidth');
3331
830
100
1356
$width = '' if $def_width eq $width;
3332
3333
830
987
$color = $self->attribute('bordercolor');
3334
830
1402
$def_color = $self->default_attribute('bordercolor');
3335
830
100
1451
$color = '' if $def_color eq $color;
3336
}
3337
3338
1907
100
66
5704
return '' if $def_style eq $style and $color eq '' && $width eq '';
66
3339
3340
1120
1669
Graph::Easy::_border_attribute($style, $width, $color);
3341
}
3342
3343
sub _unknown_attribute
3344
{
3345
# either just warn, or raise an error for unknown attributes
3346
54
54
52
my ($self, $name, $class) = @_;
3347
3348
54
100
78
if ($self->{_warn_on_unknown_attributes})
3349
{
3350
6
24
$self->warn("Ignoring unknown attribute '$name' for class $class")
3351
}
3352
else
3353
{
3354
48
123
$self->error("Error in attribute: '$name' is not a valid attribute name for a $class");
3355
}
3356
54
116
return;
3357
}
3358
3359
sub default_attribute
3360
{
3361
# Return the default value for the attribute.
3362
6274
6274
1
5653
my ($self, $class, $name) = @_;
3363
3364
# allow $self->default_attribute('fill');
3365
6274
100
8514
if (scalar @_ == 2)
3366
{
3367
3683
2631
$name = $class;
3368
3683
50
5945
$class = $self->{class} || 'graph';
3369
}
3370
3371
# get the base class: node.foo => node
3372
6274
4516
my $base_class = $class; $base_class =~ s/\..*//;
6274
5441
3373
3374
# Remap alias names without "-" to their hyphenated version:
3375
6274
100
8098
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3376
3377
# "x-foo-bar" is a custom attribute, so allow it always. The name must
3378
# consist only of letters and hyphens, and end in a letter or number.
3379
# Hyphens must be separated by letters. Custom attributes do not have a default.
3380
6274
50
14438
return '' if $name =~ $qr_custom_attribute;
3381
3382
# prevent ->{special}->{node} from springing into existence
3383
6274
50
4951
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
6274
7164
3384
3385
my $entry = $s->{$name} ||
3386
$attributes->{all}->{$name} ||
3387
6274
66
15316
$attributes->{$base_class}->{$name};
3388
3389
# Didn't found an entry:
3390
6274
50
8677
return $self->_unknown_attribute($name,$class) unless ref($entry);
3391
3392
# get the default attribute from the entry
3393
6274
4516
my $def = $entry->[ ATTR_DEFAULT_SLOT ]; my $val = $def;
6274
4104
3394
3395
# "node.subclass" gets the default from "node", 'edge' from 'default':
3396
# " { default => 'foo', 'node.anon' => 'none', node => 'solid' }":
3397
6274
100
7522
if (ref $def)
3398
{
3399
4341
3866
$val = $def->{$class};
3400
4341
100
5770
$val = $def->{$base_class} unless defined $val;
3401
4341
100
5621
$val = $def->{default} unless defined $val;
3402
}
3403
3404
6274
12892
$val;
3405
}
3406
3407
sub raw_attribute
3408
{
3409
# Return either the raw attribute set on an object (honoring inheritance),
3410
# or undef for when that specific attribute is not set. Does *not*
3411
# inspect class attributes.
3412
7354
7354
1
6522
my ($self, $name) = @_;
3413
3414
# Remap alias names without "-" to their hyphenated version:
3415
7354
50
10021
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3416
3417
7354
50
10638
my $class = $self->{class} || 'graph';
3418
7354
4950
my $base_class = $class; $base_class =~ s/\..*//;
7354
7532
3419
3420
# prevent ->{special}->{node} from springing into existence
3421
7354
50
5997
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
7354
8901
3422
3423
my $entry = $s->{$name} ||
3424
$attributes->{all}->{$name} ||
3425
7354
66
18436
$attributes->{$base_class}->{$name};
3426
3427
# create a fake entry for custom attributes
3428
7354
50
19275
$entry = [ '', undef, '', '', ATTR_STRING, '' ]
3429
if $name =~ $qr_custom_attribute;
3430
3431
# Didn't found an entry:
3432
7354
50
10514
return $self->_unknown_attribute($name,$class) unless ref($entry);
3433
3434
7354
100
16544
my $type = $entry->[ ATTR_TYPE_SLOT ] || ATTR_STRING;
3435
3436
7354
4627
my $val;
3437
3438
###########################################################################
3439
# Check the object directly first
3440
7354
6258
my $a = $self->{att};
3441
7354
100
8773
if (exists $a->{graph})
3442
{
3443
# for graphs, look directly in the class to save time:
3444
$val = $a->{graph}->{$name}
3445
1125
100
2028
if exists $a->{graph}->{$name};
3446
}
3447
else
3448
{
3449
6229
100
8572
$val = $a->{$name} if exists $a->{$name};
3450
}
3451
3452
# For "background", and objects that are in a group, we inherit "fill":
3453
$val = $self->{group}->color_attribute('fill')
3454
7354
50
33
11372
if $name eq 'background' && ref $self->{group};
3455
3456
7354
100
100
22012
return $val if !defined $val || $val ne 'inherit' ||
66
3457
$name =~ /^x-([a-z_]+-)*[a-z_]+([0-9]*)\z/;
3458
3459
# $val is defined, and "inherit" (and it is not a special attribute)
3460
3461
# for graphs, there is nothing to inherit from
3462
1
50
3
return $val if $class eq 'graph';
3463
3464
# we try classes in this order:
3465
# "node", "graph"
3466
3467
1
2
my @tries = ();
3468
# if the class is already "node", skip it:
3469
1
50
3
if ($class =~ /\./)
3470
{
3471
1
2
my $parent_class = $class; $parent_class =~ s/\..*//;
1
3
3472
1
2
push @tries, $parent_class;
3473
}
3474
3475
# If not part of a graph, we cannot have class attributes, but
3476
# we still can find default attributes. So fake a "graph":
3477
1
2
my $g = $self->{graph}; # for objects in a graph
3478
1
50
3
$g = { att => {} } unless ref($g); # for objects not in a graph
3479
3480
1
1
$val = undef;
3481
1
3
for my $try (@tries)
3482
{
3483
# print STDERR "# Trying class $try for attribute $name\n";
3484
3485
1
2
my $att = $g->{att}->{$try};
3486
3487
1
50
3
$val = $att->{$name} if exists $att->{$name};
3488
3489
# value was not defined, so get the default value
3490
1
50
4
if (!defined $val)
3491
{
3492
0
0
my $def = $entry->[ ATTR_DEFAULT_SLOT ]; $val = $def;
0
0
3493
3494
# "node.subclass" gets the default from "node", 'edge' from 'default':
3495
# " { default => 'foo', 'node.anon' => 'none', node => 'solid' }":
3496
0
0
0
if (ref $def)
3497
{
3498
0
0
$val = $def->{$try};
3499
0
0
0
0
if (!defined $val && $try =~ /\./)
3500
{
3501
0
0
my $base = $try; $base =~ s/\..*//;
0
0
3502
0
0
$val = $def->{$base};
3503
}
3504
0
0
0
$val = $def->{default} unless defined $val;
3505
}
3506
}
3507
# $val must now be defined, because default value must exist.
3508
3509
# print STDERR "# Found '$val' for $try\n";
3510
3511
1
50
2
if ($name ne 'label')
3512
{
3513
1
50
13
$self->warn("Uninitialized default for attribute '$name' on class '$try'\n")
3514
unless defined $val;
3515
}
3516
3517
1
50
4
return $val if $type >= ATTR_NO_INHERIT;
3518
3519
# got some value other than inherit or already at top of tree:
3520
1
50
33
16
return $val if defined $val && $val ne 'inherit';
3521
3522
# try next class in inheritance tree
3523
0
0
$val = undef;
3524
}
3525
3526
0
0
$val;
3527
}
3528
3529
sub color_attribute
3530
{
3531
# Just like get_attribute(), but for colors, and returns them as hex,
3532
# using the current colorscheme.
3533
332
332
1
284
my $self = shift;
3534
3535
332
583
my $color = $self->attribute(@_);
3536
3537
332
100
66
1154
if ($color !~ /^#/ && $color ne '')
3538
{
3539
297
456
my $scheme = $self->attribute('colorscheme');
3540
297
656
$color = Graph::Easy->color_as_hex($color, $scheme);
3541
}
3542
3543
332
716
$color;
3544
}
3545
3546
sub raw_color_attribute
3547
{
3548
# Just like raw_attribute(), but for colors, and returns them as hex,
3549
# using the current colorscheme.
3550
34
34
1
29
my $self = shift;
3551
3552
34
53
my $color = $self->raw_attribute(@_);
3553
34
100
116
return undef unless defined $color; # default to undef
3554
3555
7
50
33
27
if ($color !~ /^#/ && $color ne '')
3556
{
3557
7
15
my $scheme = $self->attribute('colorscheme');
3558
7
17
$color = Graph::Easy->color_as_hex($color, $scheme);
3559
}
3560
3561
7
18
$color;
3562
}
3563
3564
sub _attribute_entry
3565
{
3566
# return the entry defining an attribute, based on the attribute name
3567
452
452
404
my ($self, $class, $name) = @_;
3568
3569
# font-size => fontsize
3570
452
50
560
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3571
3572
452
286
my $base_class = $class; $base_class =~ s/\.(.*)//;
452
463
3573
3574
# prevent ->{special}->{node} from springing into existence
3575
452
50
360
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
452
503
3576
my $entry = $s->{$name} ||
3577
$attributes->{all}->{$name} ||
3578
452
66
1056
$attributes->{$base_class}->{$name};
3579
3580
452
599
$entry;
3581
}
3582
3583
sub attribute
3584
{
3585
71190
71190
1
68243
my ($self, $class, $name) = @_;
3586
3587
71190
48681
my $three_arg = 0;
3588
71190
100
82437
if (scalar @_ == 3)
3589
{
3590
# $self->attribute($class,$name) if only allowed on graphs
3591
return $self->error("Calling $self->attribute($class,$name) only allowed for graphs")
3592
8309
50
11177
if exists $self->{graph};
3593
3594
8309
50
19569
if ($class !~ /^(node|group|edge|graph\z)/)
3595
{
3596
0
0
return $self->error ("Illegal class '$class' when trying to get attribute '$name'");
3597
}
3598
8309
5434
$three_arg = 1;
3599
8309
100
11368
return $self->border_attribute($class) if $name eq 'border'; # virtual attribute
3600
}
3601
else
3602
{
3603
# allow calls of the style get_attribute('background');
3604
62881
43427
$name = $class;
3605
62881
100
50
81770
$class = $self->{class} || 'graph' if $name eq 'class'; # avoid deep recursion
3606
62881
100
75603
if ($name ne 'class')
3607
{
3608
62805
58036
$class = $self->{cache}->{class};
3609
62805
100
117212
$class = $self->class() unless defined $class;
3610
}
3611
3612
62881
100
84943
return $self->border_attribute() if $name eq 'border'; # virtual attribute
3613
62819
100
77792
return join (",",$self->size()) if $name eq 'size'; # virtual attribute
3614
}
3615
3616
# print STDERR "# called attribute($class,$name)\n";
3617
3618
# font-size => fontsize
3619
70252
100
93113
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3620
3621
70252
48927
my $base_class = $class; $base_class =~ s/\.(.*)//;
70252
61473
3622
70252
100
62907
my $sub_class = $1; $sub_class = '' unless defined $sub_class;
70252
85824
3623
70252
100
81014
if ($name eq 'class')
3624
{
3625
# "[A] { class: red; }" => "red"
3626
76
100
114
return $sub_class if $sub_class ne '';
3627
# "node { class: green; } [A]" => "green": fall through and let the code
3628
# below look up the attribute or fall back to the default '':
3629
}
3630
3631
# prevent ->{special}->{node} from springing into existence
3632
70243
100
54590
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
70243
82756
3633
my $entry = $s->{$name} ||
3634
$attributes->{all}->{$name} ||
3635
70243
66
169231
$attributes->{$base_class}->{$name};
3636
3637
# create a fake entry for custom attributes
3638
70243
100
182805
$entry = [ '', undef, '', '', ATTR_STRING, '' ]
3639
if $name =~ $qr_custom_attribute;
3640
3641
# Didn't found an entry:
3642
70243
50
93696
return $self->_unknown_attribute($name,$class) unless ref($entry);
3643
3644
70243
100
142474
my $type = $entry->[ ATTR_TYPE_SLOT ] || ATTR_STRING;
3645
3646
70243
43245
my $val;
3647
3648
70243
100
87940
if ($three_arg == 0)
3649
{
3650
###########################################################################
3651
# Check the object directly first
3652
62785
51821
my $a = $self->{att};
3653
62785
100
62284
if (exists $a->{graph})
3654
{
3655
# for graphs, look directly in the class to save time:
3656
$val = $a->{graph}->{$name}
3657
2212
100
3644
if exists $a->{graph}->{$name};
3658
}
3659
else
3660
{
3661
60573
100
80634
$val = $a->{$name} if exists $a->{$name};
3662
}
3663
3664
# For "background", and objects that are in a group, we inherit "fill":
3665
62785
50
66
91279
if ($name eq 'background' && $val && $val eq 'inherit')
33
3666
{
3667
0
0
my $parent = $self->parent();
3668
0
0
0
0
$val = $parent->color_attribute('fill') if $parent && $parent != $self;
3669
}
3670
3671
# XXX BENCHMARK THIS
3672
62785
100
66
89379
return $val if defined $val &&
66
3673
# no inheritance ("inherit" is just a normal string value)
3674
($type >= ATTR_NO_INHERIT ||
3675
# no inheritance since value is something else like "red"
3676
$val ne 'inherit' ||
3677
# for graphs, there is nothing to inherit from
3678
$class eq 'graph');
3679
}
3680
3681
# $val not defined, or 'inherit'
3682
3683
###########################################################################
3684
# Check the classes now
3685
3686
# print STDERR "# Called self->attribute($class,$name) (#2)\n";
3687
3688
# we try them in this order:
3689
# node.subclass, node, graph
3690
3691
# print STDERR "# $self->{name} class=$class ", join(" ", caller),"\n" if $name eq 'align';
3692
3693
68119
62274
my @tries = ();
3694
# skip "node.foo" if value is 'inherit'
3695
68119
100
103302
push @tries, $class unless defined $val;
3696
68119
100
89368
push @tries, $base_class if $class =~ /\./;
3697
68119
100
100
201363
push @tries, 'graph' unless @tries && $tries[-1] eq 'graph';
3698
3699
# If not part of a graph, we cannot have class attributes, but
3700
# we still can find default attributes. So fake a "graph":
3701
68119
59239
my $g = $self->{graph}; # for objects in a graph
3702
68119
100
97280
$g = { att => {} } unless ref($g); # for objects not in a graph
3703
3704
# XXX TODO should not happen
3705
68119
100
90768
$g = $self if $self->{class} eq 'graph'; # for the graph itself
3706
3707
68119
50228
$val = undef;
3708
TRY:
3709
68119
65006
for my $try (@tries)
3710
{
3711
# print STDERR "# Trying class $try for attribute $name\n" if $name eq 'align';
3712
3713
80667
69990
my $att = $g->{att}->{$try};
3714
3715
80667
100
97640
$val = $att->{$name} if exists $att->{$name};
3716
3717
# value was not defined, so get the default value (but not for subclasses!)
3718
80667
100
94011
if (!defined $val)
3719
{
3720
79195
60399
my $def = $entry->[ ATTR_DEFAULT_SLOT ]; $val = $def;
79195
49687
3721
3722
# "node.subclass" gets the default from "node", 'edge' from 'default':
3723
# " { default => 'foo', 'node.anon' => 'none', node => 'solid' }":
3724
79195
100
101702
if (ref $def)
3725
{
3726
38220
32906
$val = $def->{$try};
3727
38220
100
100
91128
if (!defined $val && $try =~ /\./)
3728
{
3729
1231
1023
my $base = $try; $base =~ s/\..*//;
1231
2315
3730
1231
1276
$val = $def->{$base};
3731
}
3732
# if this is not a subclass, get the default value
3733
38220
100
100
75021
next TRY if !defined $val && $try =~ /\./;
3734
3735
37336
100
52755
$val = $def->{default} unless defined $val;
3736
}
3737
}
3738
# $val must now be defined, because default value must exist.
3739
3740
# print STDERR "# Found '$val' for $try ($class)\n" if $name eq 'color';
3741
3742
79783
100
96682
if ($name ne 'label')
3743
{
3744
74206
50
85750
$self->warn("Uninitialized default for attribute '$name' on class '$try'\n")
3745
unless defined $val;
3746
}
3747
3748
79783
100
104907
return $val if $type >= ATTR_NO_INHERIT;
3749
3750
# got some value other than inherit or already at top of tree:
3751
72554
100
100
186200
last if defined $val && ($val ne 'inherit' || $try eq 'graph');
33
3752
3753
# try next class in inheritance tree
3754
11664
10909
$val = undef;
3755
}
3756
3757
# For "background", and objects that are in a group, we inherit "fill":
3758
60890
100
66
87810
if ($name eq 'background' && $val && $val eq 'inherit')
100
3759
{
3760
141
308
my $parent = $self->parent();
3761
141
100
66
494
$val = $parent->color_attribute('fill') if $parent && $parent != $self;
3762
}
3763
3764
# If we fell through here, $val is 'inherit' for graph. That happens
3765
# for instance for 'background':
3766
60890
128437
$val;
3767
}
3768
3769
sub unquote_attribute
3770
{
3771
# The parser leaves quotes and escapes in the attribute, these things
3772
# are only removed upon storing the attribute at the object/class.
3773
# Return the attribute unquoted (remove quotes on labels, links etc).
3774
2464
2464
1
3036
my ($self,$class,$name,$val) = @_;
3775
3776
# clean quoted strings
3777
# XXX TODO
3778
# $val =~ s/^["'](.*[^\\])["']\z/$1/;
3779
2464
3155
$val =~ s/^["'](.*)["']\z/$1/;
3780
3781
2464
1931
$val =~ s/\\([#"';\\])/$1/g; # reverse backslashed chars
3782
3783
# remove any %00-%1f, %7f and high-bit chars to avoid exploits and problems
3784
2464
3582
$val =~ s/%[^2-7][a-fA-F0-9]|%7f//g;
3785
3786
# decode %XX entities
3787
2464
1919
$val =~ s/%([2-7][a-fA-F0-9])/sprintf("%c",hex($1))/eg;
9
36
3788
3789
2464
3322
$val;
3790
}
3791
3792
sub valid_attribute
3793
{
3794
# Only for compatibility, use validate_attribute()!
3795
3796
# Check that an name/value pair is an valid attribute, returns:
3797
# scalar value: valid, new attribute
3798
# undef: not valid
3799
# []: unknown attribute (might also warn)
3800
84
84
1
30561
my ($self, $name, $value, $class) = @_;
3801
3802
84
153
my ($error,$newname,$v) = $self->validate_attribute($name,$value,$class);
3803
3804
84
100
100
218
return [] if defined $error && $error == 1;
3805
59
100
66
95
return undef if defined $error && $error == 2;
3806
57
84
$v;
3807
}
3808
3809
sub validate_attribute
3810
{
3811
# Check that an name/value pair is an valid attribute, returns:
3812
# $error, $newname, @values
3813
3814
# A possible new name is in $newname, this is f.i. used to convert
3815
# "font-size" # to "fontsize".
3816
3817
# Upon errors, $error contains the error code:
3818
# undef: all went well
3819
# 1 unknown attribute name
3820
# 2 invalid attribute value
3821
# 4 found multiple attributes, but these aren't
3822
# allowed at this place
3823
3824
1254
1254
1
13026
my ($self, $name, $value, $class, $no_multiples) = @_;
3825
3826
1254
50
1787
$self->error("Got reference $value as value, but expected scalar") if ref($value);
3827
1254
50
1666
$self->error("Got reference $name as name, but expected scalar") if ref($name);
3828
3829
# "x-foo-bar" is a custom attribute, so allow it always. The name must
3830
# consist only of letters and hyphens, and end in a letter. Hyphens
3831
# must be separated by letters.
3832
1254
100
4762
return (undef, $name, $value) if $name =~ $qr_custom_attribute;
3833
3834
1174
100
1803
$class = 'all' unless defined $class;
3835
1174
1153
$class =~ s/\..*\z//; # remove subclasses
3836
3837
# Remap alias names without "-" to their hyphenated version:
3838
1174
100
2052
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3839
3840
# prevent ->{special}->{node} from springing into existence
3841
1174
100
1182
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
1174
1782
3842
3843
my $entry = $s->{$name} ||
3844
1174
66
3901
$attributes->{all}->{$name} || $attributes->{$class}->{$name};
3845
3846
# Didn't found an entry:
3847
1174
100
1910
return (1,undef,$self->_unknown_attribute($name,$class)) unless ref($entry);
3848
3849
1120
1141
my $check = $entry->[ATTR_MATCH_SLOT];
3850
1120
100
2377
my $type = $entry->[ATTR_TYPE_SLOT] || ATTR_STRING;
3851
3852
1120
100
1672
$check = '_color' if $type == ATTR_COLOR;
3853
1120
100
1449
$check = '_angle' if $type == ATTR_ANGLE;
3854
1120
100
1493
$check = '_uint' if $type == ATTR_UINT;
3855
3856
1120
1780
my @values = ($value);
3857
3858
# split on "|", but not on "\|"
3859
# XXX TODO:
3860
# This will not work in case of mixed " $i \|\| 0| $a = 1;"
3861
3862
# When special attributes are set, we are parsing Graphviz, and do
3863
# not allow/use multiple attributes. So skip the split.
3864
1120
100
778
if (keys %{$attributes->{special}} == 0)
1120
2675
3865
{
3866
920
100
1697
@values = split (/\s*\|\s*/, $value, -1) if $value =~ /(^|[^\\])\|/;
3867
}
3868
3869
1120
100
954
my $multiples = 0; $multiples = 1 if @values > 1;
1120
1677
3870
1120
50
66
2246
return (4) if $no_multiples && $multiples; # | and no multiples => error
3871
3872
# check each part on it's own
3873
1120
791
my @rc;
3874
1120
1183
for my $v (@values)
3875
{
3876
# don't check empty parts for being valid
3877
1134
100
50
1949
push @rc, undef and next if $multiples && $v eq '';
100
3878
3879
1129
100
100
3778
if (defined $check && !ref($check))
100
3880
{
3881
48
48
283
no strict 'refs';
48
94
48
43021
3882
381
954
my $checked = $self->$check($v, $name);
3883
381
100
647
if (!defined $checked)
3884
{
3885
7
29
$self->error("Error in attribute: '$v' is not a valid $name for a $class");
3886
7
20
return (2);
3887
}
3888
374
470
push @rc, $checked;
3889
}
3890
elsif ($check)
3891
{
3892
431
100
867
if (ref($check) eq 'ARRAY')
3893
{
3894
# build a regexp from the list of words
3895
71
307
my $list = 'qr/^(' . join ('|', @$check) . ')\z/;';
3896
71
6519
$entry->[1] = eval($list);
3897
71
194
$check = $entry->[1];
3898
}
3899
431
100
2578
if ($v !~ $check) # invalid?
3900
{
3901
7
25
$self->error("Error in attribute: '$v' is not a valid $name for a $class");
3902
7
21
return (2);
3903
}
3904
3905
424
549
push @rc, $v; # valid
3906
}
3907
# entry found, but no specific check => anything goes as value
3908
317
386
else { push @rc, $v; }
3909
3910
# "ClAss" => "class" for LCTEXT entries
3911
1115
100
2053
$rc[-1] = lc($rc[-1]) if $type == ATTR_LCTEXT;
3912
}
3913
3914
# only one value ('green')
3915
1106
100
4068
return (undef, $name, $rc[0]) unless $multiples;
3916
3917
# multiple values ('green|red')
3918
10
35
(undef, $name, \@rc);
3919
}
3920
3921
###########################################################################
3922
###########################################################################
3923
3924
sub _remap_attributes
3925
{
3926
# Take a hash with:
3927
# {
3928
# class => {
3929
# color => 'red'
3930
# }
3931
# }
3932
# and remap it according to the given remap hash (similar structured).
3933
# Also encode/quote the value. Suppresses default attributes.
3934
2886
2886
3586
my ($self, $object, $att, $remap, $noquote, $encode, $color_remap ) = @_;
3935
3936
2886
2508
my $out = {};
3937
3938
2886
100
4581
my $class = $object || 'node';
3939
2886
100
50
6325
$class = $object->{class} || 'graph' if ref($object);
3940
2886
2941
$class =~ s/\..*//; # remove subclass
3941
3942
2886
2691
my $r = $remap->{$class};
3943
2886
2272
my $ra = $remap->{all};
3944
2886
2059
my $ral = $remap->{always};
3945
2886
2383
my $x = $remap->{x};
3946
3947
# This loop does also handle the individual "bordercolor" attributes.
3948
# If the output should contain only "border", but not "bordercolor", then
3949
# the caller must filter them out.
3950
3951
# do these attributes
3952
2886
7930
my @keys = sort keys %$att;
3953
3954
2886
2570
my $color_scheme = 'w3c';
3955
2886
100
5334
$color_scheme = $object->attribute('colorscheme') if ref($object);
3956
2886
100
100
9740
$color_scheme = $self->get_attribute($object,'colorscheme')
3957
if defined $object && !ref($object);
3958
3959
2886
50
33
7544
$color_scheme = $self->get_attribute('graph','colorscheme')
3960
if defined $color_scheme && $color_scheme eq 'inherit';
3961
3962
2886
2935
for my $atr (@keys)
3963
{
3964
5071
4868
my $val = $att->{$atr};
3965
3966
# Only for objects (not for classes like "node"), and not if
3967
# always says we need to always call the CODE handler:
3968
3969
5071
50
66
7849
if (!ref($object) && !exists $ral->{$atr})
3970
{
3971
# attribute not defined
3972
next if !defined $val || $val eq '' ||
3973
# or $remap says we should suppress it
3974
(exists $r->{$atr} && !defined $r->{$atr}) ||
3975
1141
100
100
5886
(exists $ra->{$atr} && !defined $ra->{$atr});
100
66
100
66
3976
}
3977
3978
4643
66
8064
my $entry = $attributes->{all}->{$atr} || $attributes->{$class}->{$atr};
3979
3980
4643
50
66
7070
if ($color_remap && defined $entry && defined $val)
66
3981
{
3982
# look up whether attribute is a color
3983
# if yes, convert to hex
3984
63
100
100
196
$val = $self->color_as_hex($val,$color_scheme)
3985
if ($entry->[ ATTR_TYPE_SLOT ]||ATTR_STRING) == ATTR_COLOR;
3986
}
3987
3988
4643
5818
my $temp = { $atr => $val };
3989
3990
# see if there is a handler for custom attributes
3991
4643
100
66
10761
if (exists $r->{$atr} || exists $ra->{$atr} || (defined $x && $atr =~ /^x-/))
100
66
3992
{
3993
3441
100
2731
my $rc = $r->{$atr}; $rc = $ra->{$atr} unless defined $rc;
3441
4545
3994
3441
100
3905
$rc = $x unless defined $rc;
3995
3996
# if given a code ref, call it to remap name and/or value
3997
3441
100
4292
if (ref($rc) eq 'CODE')
3998
{
3999
2055
1546
my @rc = &{$rc}($self,$atr,$val,$object);
2055
3544
4000
2055
2020
$temp = {};
4001
2055
3496
while (@rc)
4002
{
4003
2074
1694
my $a = shift @rc; my $v = shift @rc;
2074
1435
4004
2074
100
66
8043
$temp->{ $a } = $v if defined $a && defined $v;
4005
}
4006
}
4007
else
4008
{
4009
# otherwise, rename the attribute name if nec.
4010
1386
1211
$temp = { };
4011
1386
100
100
3673
$temp = { $rc => $val } if defined $val && defined $rc;
4012
}
4013
}
4014
4015
4643
9441
for my $at (sort keys %$temp)
4016
{
4017
2594
2355
my $v = $temp->{$at};
4018
4019
2594
100
66
11140
next if !defined $at || !defined $v || $v eq '';
100
4020
4021
# encode critical characters (including "), but only if the value actually
4022
# contains anything else than '%' (so rgb(10%,0,0) stays as it is)
4023
4024
2211
100
100
5223
$v =~ s/([;"%\x00-\x1f])/sprintf("%%%02x",ord($1))/eg
7
20
4025
if $encode && $v =~ /[;"\x00-\x1f]/;
4026
# quote if nec.
4027
2211
50
2708
$v = '"' . $v . '"' unless $noquote;
4028
4029
2211
4804
$out->{$at} = $v;
4030
}
4031
}
4032
4033
2886
6274
$out;
4034
}
4035
4036
sub raw_attributes
4037
{
4038
# return all set attributes on this object (graph/node/group/edge) as
4039
# an anonymous hash ref
4040
436
436
1
1039
my $self = shift;
4041
4042
436
50
635
my $class = $self->{class} || 'graph';
4043
4044
436
348
my $att = $self->{att};
4045
436
100
607
$att = $self->{att}->{graph} if $class eq 'graph';
4046
4047
436
66
675
my $g = $self->{graph} || $self;
4048
4049
436
396
my $out = {};
4050
436
100
615
if (!$g->{strict})
4051
{
4052
2
8
for my $name (sort keys %$att)
4053
{
4054
6
10
my $val = $att->{$name};
4055
6
50
8
next unless defined $val; # set to undef?
4056
4057
6
9
$out->{$name} = $val;
4058
}
4059
2
5
return $out;
4060
}
4061
4062
434
325
my $base_class = $class; $base_class =~ s/\..*//;
434
470
4063
434
896
for my $name (sort keys %$att)
4064
{
4065
506
438
my $val = $att->{$name};
4066
506
100
586
next unless defined $val; # set to undef?
4067
4068
500
555
$out->{$name} = $val;
4069
4070
500
100
735
next unless $val eq 'inherit';
4071
4072
# prevent ->{special}->{node} from springing into existence
4073
1
50
2
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
1
2
4074
my $entry = $s->{$name} ||
4075
$attributes->{all}->{$name} ||
4076
1
33
5
$attributes->{$base_class}->{$name};
4077
4078
# Didn't found an entry:
4079
1
50
2
return $self->_unknown_attribute($name,$class) unless ref($entry);
4080
4081
1
50
3
my $type = $entry->[ ATTR_TYPE_SLOT ] || ATTR_STRING;
4082
4083
# need to inherit value?
4084
1
50
3
$out->{$name} = $self->attribute($name) if $type < ATTR_NO_INHERIT;
4085
}
4086
4087
434
715
$out;
4088
}
4089
4090
sub get_attributes
4091
{
4092
# Return all effective attributes on this object (graph/node/group/edge) as
4093
# an anonymous hash ref. This respects inheritance and default values.
4094
# Does not return custom attributes, see get_custom_attributes().
4095
70
70
1
63
my $self = shift;
4096
4097
70
50
117
$self->error("get_attributes() doesn't take arguments") if @_ > 0;
4098
4099
70
67
my $att = {};
4100
70
136
my $class = $self->main_class();
4101
4102
# f.i. "all", "node"
4103
70
80
for my $type ('all', $class)
4104
{
4105
140
101
for my $a (sort keys %{$attributes->{$type}})
140
862
4106
{
4107
2284
2597
my $val = $self->attribute($a); # respect inheritance
4108
2284
100
4246
$att->{$a} = $val if defined $val;
4109
}
4110
}
4111
4112
70
116
$att;
4113
}
4114
4115
package Graph::Easy::Node;
4116
4117
BEGIN
4118
{
4119
48
48
16674
*custom_attributes = \&get_custom_attributes;
4120
}
4121
4122
sub get_custom_attributes
4123
{
4124
# Return all custom attributes on this object (graph/node/group/edge) as
4125
# an anonymous hash ref.
4126
0
0
1
my $self = shift;
4127
4128
0
0
$self->error("get_custom_attributes() doesn't take arguments") if @_ > 0;
4129
4130
0
my $att = {};
4131
4132
0
for my $key (sort keys %{$self->{att}})
0
4133
{
4134
0
$att->{$key} = $self->{att}->{$key};
4135
}
4136
4137
0
$att;
4138
}
4139
4140
1;
4141
__END__