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.75';
9
10
package Graph::Easy;
11
12
49
49
48074
use strict;
49
103
49
1898
13
49
49
323
use warnings;
49
101
49
2075
14
49
49
63506
use utf8; # for examples like "Fähre"
49
473
49
299
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
98
98
31904
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
22
my ($self,$color,$scheme) = @_;
1941
1942
9
100
31
$scheme ||= 'w3c';
1943
9
100
161
$color_values->{$scheme}->{$color} || $color;
1944
}
1945
1946
sub color_value
1947
{
1948
# return "#ff0000" for "red"
1949
9
9
1
23
my ($self,$color,$scheme) = @_;
1950
1951
9
100
29
$scheme ||= 'w3c';
1952
1953
# 'w3c/red' => 'w3c', 'red'
1954
9
50
30
$scheme = $1 if $color =~ s/^([a-z0-9])\///;
1955
1956
9
50
72
$color_names->{$scheme}->{$color} || $color;
1957
}
1958
1959
sub _color_scheme
1960
{
1961
# check that a given color scheme is valid
1962
9
9
27
my ($self, $scheme) = @_;
1963
1964
9
50
34
return $scheme if $scheme eq 'inherit';
1965
9
100
49
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
658
my ($self, $org_color) = @_;
1980
1981
263
602
$org_color = lc($org_color); # color names are case insensitive
1982
263
617
$org_color =~ s/\s//g; # remove spaces to unify format
1983
263
411
my $color = $org_color;
1984
1985
263
100
786
if ($color =~ s/^(w3c|[a-z]+\d{0,2})\///)
1986
{
1987
10
23
my $scheme = $1;
1988
10
50
50
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
1289
return $org_color if exists $all_color_names->{$color};
1998
1999
# #ff0000 => #ff0000, rgb(1,2,3) => rgb(1,2,3)
2000
67
100
306
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
4429
my ($h, $s, $v) = @_;
2007
2008
35
56
my $e = 0.0001;
2009
2010
35
100
287
if ($s < $e)
2011
{
2012
6
100
12
$v = abs(int(256 * $v)); $v = 255 if $v > 255;
6
15
2013
6
25
return ($v,$v,$v);
2014
}
2015
2016
29
35
my ($r,$g,$b);
2017
29
43
$h *= 360;
2018
2019
29
60
my $h1 = int($h / 60);
2020
29
57
my $f = $h / 60 - $h1;
2021
29
50
my $p = $v * (1 - $s);
2022
29
54
my $q = $v * (1 - ($s * $f));
2023
29
44
my $t = $v * (1 - ($s * (1-$f)));
2024
2025
29
100
100
352
if ($h1 == 0 || $h1 == 6)
100
100
100
50
2026
{
2027
16
28
$r = $v; $g = $t; $b = $p;
16
24
16
26
2028
}
2029
elsif ($h1 == 1)
2030
{
2031
4
6
$r = $q; $g = $v; $b = $p;
4
6
4
7
2032
}
2033
elsif ($h1 == 2)
2034
{
2035
2
4
$r = $p; $g = $v; $b = $t;
2
4
2
3
2036
}
2037
elsif ($h1 == 3)
2038
{
2039
4
5
$r = $p; $g = $q; $b = $v;
4
6
4
5
2040
}
2041
elsif ($h1 == 4)
2042
{
2043
3
5
$r = $t; $g = $p; $b = $v;
3
3
3
5
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
47
$r = abs(int($r*256));
2051
29
40
$g = abs(int($g*256));
2052
29
39
$b = abs(int($b*256));
2053
29
100
69
$r = 255 if $r > 255;
2054
29
100
63
$g = 255 if $g > 255;
2055
29
100
69
$b = 255 if $b > 255;
2056
2057
29
113
($r,$g,$b);
2058
}
2059
2060
sub _hsl_to_rgb
2061
{
2062
# H=0..360, S=0..100, L=0..100
2063
21
21
454
my ($h, $s, $l) = @_;
2064
2065
21
27
my $e = 0.0001;
2066
21
100
58
if ($s < $e)
2067
{
2068
# achromatic or grey
2069
6
100
13
$l = abs(int(256 * $l)); $l = 255 if $l > 255;
6
14
2070
6
25
return ($l,$l,$l);
2071
}
2072
2073
15
20
my $t2;
2074
15
100
31
if ($l < 0.5)
2075
{
2076
2
5
$t2 = $l * ($s + 1);
2077
}
2078
else
2079
{
2080
13
28
$t2 = $l + $s - ($l * $s);
2081
}
2082
15
20
my $t1 = $l * 2 - $t2;
2083
2084
15
17
my ($r,$g,$b);
2085
2086
# 0..359
2087
15
100
39
$h %= 360 if $h >= 360;
2088
2089
# $h = 0..1
2090
15
26
$h /= 360;
2091
2092
15
21
my $tr = $h + 1/3;
2093
15
15
my $tg = $h;
2094
15
19
my $tb = $h - 1/3;
2095
2096
15
50
36
$tr += 1 if $tr < 0; $tr -= 1 if $tr > 1;
15
100
34
2097
15
50
47
$tg += 1 if $tg < 0; $tg -= 1 if $tg > 1;
15
50
34
2098
15
100
29
$tb += 1 if $tb < 0; $tb -= 1 if $tb > 1;
15
50
36
2099
2100
15
21
my $i = 0; my @temp3 = ($tr,$tg,$tb);
15
32
2101
15
22
my @rc;
2102
15
17
for my $c ($r,$g,$b)
2103
{
2104
45
67
my $t3 = $temp3[$i++];
2105
2106
45
100
107
if ($t3 < 1/6)
100
100
2107
{
2108
8
14
$c = $t1 + ($t2 - $t1) * 6 * $t3;
2109
}
2110
elsif ($t3 < 1/2)
2111
{
2112
15
25
$c = $t2;
2113
}
2114
elsif ($t3 < 2/3)
2115
{
2116
5
15
$c = $t1 + ($t2 - $t1) * 6 * (2/3 - $t3);
2117
}
2118
else
2119
{
2120
17
26
$c = $t1;
2121
}
2122
45
100
52
$c = int($c * 256); $c = 255 if $c > 255;
45
76
2123
45
85
push @rc, $c;
2124
}
2125
2126
15
71
@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
12438
my ($self,$color,$scheme) = @_;
2140
2141
725
100
2830
$scheme ||= 'w3c';
2142
725
1686
$color = lc($color);
2143
# 'w3c/red' => 'w3c', 'red'
2144
725
50
2506
$scheme = $1 if $color =~ s/^([a-z0-9])\///;
2145
2146
# convert "red" to "ffff00"
2147
725
100
5578
return $color_names->{$scheme}->{$color}
2148
if exists $color_names->{$scheme}->{$color};
2149
2150
# fallback to x11 scheme if color doesn't exist
2151
113
100
465
return $color_names->{x11}->{$color}
2152
if exists $color_names->{x11}->{$color};
2153
2154
101
461
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
2988
if ($color =~ /^(rgb|hsv|hsl)\($qr_num,$qr_num,$qr_num(?:,$qr_num)?\s*\)\z/)
2161
{
2162
57
100
133
my $r = $2; my $g = $3; my $b = $4; my $a = $5; $a = 255 unless defined $a;
57
111
57
118
57
97
57
149
2163
57
106
my $format = $1;
2164
2165
57
79
my $i = 0;
2166
57
110
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
477
my $factor = $factors->{$format}->[$i++];
2170
2171
228
100
496
if ($c =~ /^([0-9]+)%\z/) # 10% => 25.5
2172
{
2173
15
59
$c = $1 * $factor / 100;
2174
}
2175
else
2176
{
2177
213
100
875
$c = $1 * $factor if $c =~ /^([0-9]+\.[0-9]+)\z/; # 0.1, 1.0
2178
}
2179
}
2180
2181
57
100
201
($r,$g,$b) = Graph::Easy::_hsv_to_rgb($r,$g,$b) if $format eq 'hsv';
2182
57
100
320
($r,$g,$b) = Graph::Easy::_hsl_to_rgb($r,$g,$b) if $format eq 'hsl';
2183
2184
57
50
89
$a = int($a); $a = 255 if $a > 255;
57
210
2185
2186
# #RRGGBB or #RRGGBBAA
2187
57
308
$color = sprintf("#%02x%02x%02x%02x", $r,$g,$b,$a);
2188
}
2189
2190
# turn #ff0 into #ffff00
2191
101
100
622
$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
364
$color =~ s/^(#......)ff\z/$1/i;
2195
2196
# check final color value to be #RRGGBB or #RRGGBBAA
2197
101
100
482
return undef unless $color =~ /^#([a-f0-9]{6}|[a-f0-9]{8})\z/i;
2198
2199
93
492
$color;
2200
}
2201
2202
sub text_style
2203
{
2204
# check whether the given list of textstyle attributes is valid
2205
20
20
1
34
my ($self, $style) = @_;
2206
2207
20
100
78
return $style if $style =~ /^(normal|none|)\z/;
2208
2209
15
48
my @styles = split /\s+/, $style;
2210
2211
15
50
98
return undef if grep(!/^(underline|overline|line-through|italic|bold)\z/, @styles);
2212
2213
15
40
$style;
2214
}
2215
2216
sub text_styles
2217
{
2218
# return a hash with the defined textstyles checked
2219
83
83
1
166
my ($self) = @_;
2220
2221
83
268
my $style = $self->attribute('textstyle');
2222
2223
83
100
248
return { none => 1 } if $style =~ /^(normal|none)\z/;
2224
81
100
293
return { } if $style eq '';
2225
2226
2
4
my $styles = {};
2227
2
8
for my $key ( split /\s+/, $style )
2228
{
2229
8
18
$styles->{$key} = 1;
2230
}
2231
2
7
$styles;
2232
}
2233
2234
sub text_styles_as_css
2235
{
2236
81
81
1
236
my ($self, $align, $fontsize) = @_;
2237
2238
81
186
my $style = '';
2239
81
364
my $ts = $self->text_styles();
2240
2241
81
50
238
$style .= " font-style: italic;" if $ts->{italic};
2242
81
50
218
$style .= " font-weight: bold;" if $ts->{bold};
2243
2244
81
50
66
1464
if ($ts->{underline} || $ts->{none} || $ts->{overline} || $ts->{'line-through'})
66
66
2245
{
2246
# XXX TODO: HTML does seem to allow only one of them
2247
2
5
my @s;
2248
2
5
foreach my $k (qw/underline overline line-through none/)
2249
{
2250
8
100
20
push @s, $k if $ts->{$k};
2251
}
2252
2
7
my $s = join(' ', @s);
2253
2
50
10
$style .= " text-decoration: $s;" if $s;
2254
}
2255
2256
81
358
my $fs = $self->raw_attribute('fontsize');
2257
2258
81
100
229
$style .= " font-size: $fs;" if $fs;
2259
2260
81
100
210
if (!$align)
2261
{
2262
# XXX TODO: raw_attribute()?
2263
5
31
my $al = $self->attribute('align');
2264
5
50
25
$style .= " text-align: $al;" if $al;
2265
}
2266
2267
81
259
$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
1657
my ($self,$dir) = @_;
2325
2326
743
1751
my $d = $dirs->{$dir};
2327
743
50
1693
$self->_croak("$dir is not an absolut direction") unless defined $d;
2328
2329
743
1923
$d;
2330
}
2331
2332
sub _direction_as_side
2333
{
2334
512
512
875
my ($self,$dir) = @_;
2335
2336
512
100
1843
return unless exists $sides->{$dir};
2337
311
1079
$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
3868
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
9772
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
8700
return $dirs->{$dir};
2358
}
2359
2360
103
243
my $in = $dirs->{$inflow};
2361
103
272
my $modifier = $modifier->{$dir};
2362
2363
103
50
230
$self->_croak("$inflow,$dir results in undefined inflow") unless defined $in;
2364
103
50
329
$self->_croak("$inflow,$dir results in undefined modifier") unless defined $modifier;
2365
2366
103
148
my $out = $in + $modifier;
2367
103
270
$out -= 360 while $out >= 360; # normalize to 0..359
2368
103
261
$out += 360 while $out < 0; # normalize to 0..359
2369
2370
103
279
$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
341
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
668
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
9
return $sides->{$dir};
2391
}
2392
2393
203
347
my $in = $dirs->{$inflow};
2394
203
410
my $modifier = $modifier->{$dir};
2395
2396
203
50
420
$self->_croak("$inflow,$dir results in undefined inflow") unless defined $in;
2397
203
50
430
$self->_croak("$inflow,$dir results in undefined modifier") unless defined $modifier;
2398
2399
203
268
my $out = $in + $modifier;
2400
203
50
431
$out -= 360 if $out >= 360; # normalize to 0..359
2401
2402
203
740
$sides->{$out};
2403
}
2404
2405
sub _direction
2406
{
2407
# check that a direction (south etc) is valid
2408
76
76
264
my ($self, $dir) = @_;
2409
2410
76
50
627
$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
222
my ($style, $width, $color, $scheme) = @_;
2418
2419
94
50
303
$style ||= '';
2420
94
50
220
$width = '' unless defined $width;
2421
94
50
276
$color = '' unless defined $color;
2422
2423
94
100
50
423
$color = Graph::Easy->color_as_hex($color,$scheme)||'' if $color !~ /^#/;
2424
2425
94
100
372
return $style if $style =~ /^(none|)\z/;
2426
2427
# width: 2px for double would collapse to one line
2428
92
100
217
$width = '' if $style =~ /^double/;
2429
2430
# convert the style and widths to something HTML can understand
2431
2432
92
50
248
$width = '0.5em' if $style eq 'broad';
2433
92
50
241
$width = '4px' if $style =~ /^bold/;
2434
92
50
287
$width = '1em' if $style eq 'wide';
2435
92
50
462
$style = 'solid' if $style =~ /(broad|wide|bold)\z/;
2436
92
50
223
$style = 'dashed' if $style eq 'bold-dash';
2437
92
100
201
$style = 'double' if $style eq 'double-dash';
2438
2439
92
100
526
$width = $width.'px' if $width =~ /^\s*\d+\s*\z/;
2440
2441
92
50
66
292
return '' if $width eq '' && $style ne 'double';
2442
2443
92
256
my $val = join(" ", $style, $width, $color);
2444
92
203
$val =~ s/^\s+//;
2445
92
294
$val =~ s/\s+\z//;
2446
2447
92
357
$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
2576
my ($style, $width, $color) = @_;
2455
2456
1165
100
3103
$style ||= '';
2457
1165
50
2719
$width = '' unless defined $width;
2458
1165
50
2309
$color = '' unless defined $color;
2459
2460
1165
100
6468
return $style if $style =~ /^(none|)\z/;
2461
2462
1121
100
4150
$width = $width.'px' if $width =~ /^\s*\d+\s*\z/;
2463
2464
1121
3477
my $val = join(" ", $style, $width, $color);
2465
1121
3086
$val =~ s/^\s+//;
2466
1121
5364
$val =~ s/\s+\z//;
2467
2468
1121
10761
$val;
2469
}
2470
2471
sub _border_width_in_pixels
2472
{
2473
1895
1895
4070
my ($self, $em) = @_;
2474
2475
1895
100
4855
my $bw = $self->attribute('borderwidth') || '0';
2476
1895
100
4853
return 0 if $bw eq '0';
2477
2478
1831
50
5169
my $bs = $self->attribute('borderstyle') || 'none';
2479
2480
1831
100
14163
return 0 if $bs eq 'none';
2481
1809
100
5334
return 3 if $bs =~ /^bold/;
2482
1806
100
3867
return $em / 2 if $bs =~ /^broad/;
2483
1805
50
7265
return $em if $bs =~ /^wide/;
2484
2485
# width: 1 is 1px;
2486
1805
50
10721
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
31
my ($self, $angle) = @_;
2512
2513
19
50
86
return undef unless $angle =~ /^([+-]?\d{1,3}|south|west|east|north|up|down|left|right|front|back|forward)\z/;
2514
2515
19
41
$angle;
2516
}
2517
2518
sub _uint
2519
{
2520
# check a small unsigned integer for being valid
2521
1
1
5
my ($self, $val) = @_;
2522
2523
1
50
9
return undef unless $val =~ /^\d+\z/;
2524
2525
1
5
$val = abs(int($val));
2526
1
50
5
$val = 4 * 1024 if $val > 4 * 1024;
2527
2528
1
3
$val;
2529
}
2530
2531
sub _font
2532
{
2533
# check a font-list for being valid
2534
3
3
12
my ($self, $font) = @_;
2535
2536
3
11
$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
85
my ($self,$border) = @_;
2543
2544
# special case
2545
39
100
142
return ('none', undef, undef) if $border eq '0';
2546
2547
# extract style
2548
36
59
my $style;
2549
36
705
$border =~
2550
35
73
s/(solid|dotted|dot-dot-dash|dot-dash|dashed|double-dash|double|bold-dash|bold|broad|wide|wave|none)/$style=$1;''/eg;
35
308
2551
2552
36
100
151
$style ||= 'solid';
2553
2554
# extract width
2555
36
86
$border =~ s/(\d+(px|em|%))//g;
2556
2557
36
100
150
my $width = $1 || '';
2558
36
167
$width =~ s/[^0-9]+//g; # leave only digits
2559
2560
36
87
$border =~ s/\s+//g; # rem unnec. spaces
2561
2562
# The left-over part must be a valid color.
2563
36
62
my $color = $border;
2564
36
100
134
$color = Graph::Easy->_color($border) if $border ne '';
2565
2566
36
50
89
$self->error("$border is not a valid bordercolor")
2567
unless defined $color;
2568
2569
36
100
106
$width = undef if $width eq '';
2570
36
100
141
$color = undef if $color eq '';
2571
36
50
79
$style = undef if $style eq '';
2572
36
301
($style,$width,$color);
2573
}
2574
2575
#############################################################################
2576
# attribute checking
2577
2578
# different types of attributes with pre-defined handling
2579
use constant {
2580
49
387389
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
49
49
817133
};
49
503
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 (usefull 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. Usefull 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
434
my ($self, $att) = @_;
3277
224
637
$attributes->{special} = $att;
3278
}
3279
3280
sub _drop_special_attributes
3281
{
3282
# drop the hash with special temp. attributes
3283
1241
1241
2619
my ($self) = @_;
3284
3285
1241
5427
$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
3788
my ($self, $class) = @_;
3299
3300
2168
2563
my ($style,$width,$color);
3301
3302
2168
100
7577
my $g = $self; $g = $self->{graph} if ref($self->{graph});
2168
8225
3303
3304
2168
4427
my ($def_style, $def_color, $def_width);
3305
3306
# XXX TODO need no_default_attribute()
3307
2168
100
5112
if (defined $class)
3308
{
3309
1299
4019
$style = $g->attribute($class, 'borderstyle');
3310
1299
100
5669
return $style if $style eq 'none';
3311
3312
1077
3095
$def_style = $g->default_attribute('borderstyle');
3313
3314
1077
3799
$width = $g->attribute($class,'borderwidth');
3315
1077
4142
$def_width = $g->default_attribute($class,'borderwidth');
3316
1077
100
3943
$width = '' if $def_width eq $width;
3317
3318
1077
2801
$color = $g->attribute($class,'bordercolor');
3319
1077
3660
$def_color = $g->default_attribute($class,'bordercolor');
3320
1077
100
3387
$color = '' if $def_color eq $color;
3321
}
3322
else
3323
{
3324
869
2287
$style = $self->attribute('borderstyle');
3325
869
100
2737
return $style if $style eq 'none';
3326
3327
830
2715
$def_style = $self->default_attribute('borderstyle');
3328
3329
830
2712
$width = $self->attribute('borderwidth');
3330
830
2566
$def_width = $self->default_attribute('borderwidth');
3331
830
100
3490
$width = '' if $def_width eq $width;
3332
3333
830
2398
$color = $self->attribute('bordercolor');
3334
830
2931
$def_color = $self->default_attribute('bordercolor');
3335
830
100
2706
$color = '' if $def_color eq $color;
3336
}
3337
3338
1907
100
66
11949
return '' if $def_style eq $style and $color eq '' && $width eq '';
66
3339
3340
1120
3395
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
89
my ($self, $name, $class) = @_;
3347
3348
54
100
116
if ($self->{_warn_on_unknown_attributes})
3349
{
3350
6
48
$self->warn("Ignoring unknown attribute '$name' for class $class")
3351
}
3352
else
3353
{
3354
48
171
$self->error("Error in attribute: '$name' is not a valid attribute name for a $class");
3355
}
3356
54
185
return;
3357
}
3358
3359
sub default_attribute
3360
{
3361
# Return the default value for the attribute.
3362
6274
6274
1
12502
my ($self, $class, $name) = @_;
3363
3364
# allow $self->default_attribute('fill');
3365
6274
100
18642
if (scalar @_ == 2)
3366
{
3367
3683
5759
$name = $class;
3368
3683
50
10685
$class = $self->{class} || 'graph';
3369
}
3370
3371
# get the base class: node.foo => node
3372
6274
9217
my $base_class = $class; $base_class =~ s/\..*//;
6274
16282
3373
3374
# Remap alias names without "-" to their hyphenated version:
3375
6274
100
18585
$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
28957
return '' if $name =~ $qr_custom_attribute;
3381
3382
# prevent ->{special}->{node} from springing into existance
3383
6274
50
20033
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
6274
15525
3384
3385
6274
66
68512
my $entry = $s->{$name} ||
3386
$attributes->{all}->{$name} ||
3387
$attributes->{$base_class}->{$name};
3388
3389
# Didn't found an entry:
3390
6274
50
16548
return $self->_unknown_attribute($name,$class) unless ref($entry);
3391
3392
# get the default attribute from the entry
3393
6274
9823
my $def = $entry->[ ATTR_DEFAULT_SLOT ]; my $val = $def;
6274
16217
3394
3395
# "node.subclass" gets the default from "node", 'edge' from 'default':
3396
# " { default => 'foo', 'node.anon' => 'none', node => 'solid' }":
3397
6274
100
24049
if (ref $def)
3398
{
3399
4341
7955
$val = $def->{$class};
3400
4341
100
14610
$val = $def->{$base_class} unless defined $val;
3401
4341
100
10884
$val = $def->{default} unless defined $val;
3402
}
3403
3404
6274
31288
$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
15463
my ($self, $name) = @_;
3413
3414
# Remap alias names without "-" to their hyphenated version:
3415
7354
50
21125
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3416
3417
7354
50
21558
my $class = $self->{class} || 'graph';
3418
7354
9953
my $base_class = $class; $base_class =~ s/\..*//;
7354
14117
3419
3420
# prevent ->{special}->{node} from springing into existance
3421
7354
50
15065
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
7354
20505
3422
3423
7354
66
62753
my $entry = $s->{$name} ||
3424
$attributes->{all}->{$name} ||
3425
$attributes->{$base_class}->{$name};
3426
3427
# create a fake entry for custom attributes
3428
7354
50
49322
$entry = [ '', undef, '', '', ATTR_STRING, '' ]
3429
if $name =~ $qr_custom_attribute;
3430
3431
# Didn't found an entry:
3432
7354
50
18377
return $self->_unknown_attribute($name,$class) unless ref($entry);
3433
3434
7354
100
30544
my $type = $entry->[ ATTR_TYPE_SLOT ] || ATTR_STRING;
3435
3436
7354
11119
my $val;
3437
3438
###########################################################################
3439
# Check the object directly first
3440
7354
13604
my $a = $self->{att};
3441
7354
100
17303
if (exists $a->{graph})
3442
{
3443
# for graphs, look directly in the class to save time:
3444
1125
100
4004
$val = $a->{graph}->{$name}
3445
if exists $a->{graph}->{$name};
3446
}
3447
else
3448
{
3449
6229
100
15563
$val = $a->{$name} if exists $a->{$name};
3450
}
3451
3452
# For "background", and objects that are in a group, we inherit "fill":
3453
7354
50
33
28029
$val = $self->{group}->color_attribute('fill')
3454
if $name eq 'background' && ref $self->{group};
3455
3456
7354
100
100
47659
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
4
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
5
if ($class =~ /\./)
3470
{
3471
1
2
my $parent_class = $class; $parent_class =~ s/\..*//;
1
5
3472
1
3
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
1
my $g = $self->{graph}; # for objects in a graph
3478
1
50
4
$g = { att => {} } unless ref($g); # for objects not in a graph
3479
3480
1
2
$val = undef;
3481
1
3
for my $try (@tries)
3482
{
3483
# print STDERR "# Trying class $try for attribute $name\n";
3484
3485
1
3
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
3
if ($name ne 'label')
3512
{
3513
1
50
4
$self->warn("Uninitialized default for attribute '$name' on class '$try'\n")
3514
unless defined $val;
3515
}
3516
3517
1
50
3
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
17
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
583
my $self = shift;
3534
3535
332
1080
my $color = $self->attribute(@_);
3536
3537
332
100
66
2011
if ($color !~ /^#/ && $color ne '')
3538
{
3539
297
821
my $scheme = $self->attribute('colorscheme');
3540
297
1550
$color = Graph::Easy->color_as_hex($color, $scheme);
3541
}
3542
3543
332
1207
$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
64
my $self = shift;
3551
3552
34
109
my $color = $self->raw_attribute(@_);
3553
34
100
192
return undef unless defined $color; # default to undef
3554
3555
7
50
33
57
if ($color !~ /^#/ && $color ne '')
3556
{
3557
7
25
my $scheme = $self->attribute('colorscheme');
3558
7
34
$color = Graph::Easy->color_as_hex($color, $scheme);
3559
}
3560
3561
7
204
$color;
3562
}
3563
3564
sub _attribute_entry
3565
{
3566
# return the entry defining an attribute, based on the attribute name
3567
452
452
780
my ($self, $class, $name) = @_;
3568
3569
# font-size => fontsize
3570
452
50
1096
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3571
3572
452
598
my $base_class = $class; $base_class =~ s/\.(.*)//;
452
918
3573
3574
# prevent ->{special}->{node} from springing into existance
3575
452
50
695
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
452
921
3576
452
100
2836
my $entry = $s->{$name} ||
3577
$attributes->{all}->{$name} ||
3578
$attributes->{$base_class}->{$name};
3579
3580
452
1224
$entry;
3581
}
3582
3583
sub attribute
3584
{
3585
71190
71190
1
158792
my ($self, $class, $name) = @_;
3586
3587
71190
105609
my $three_arg = 0;
3588
71190
100
171906
if (scalar @_ == 3)
3589
{
3590
# $self->attribute($class,$name) if only allowed on graphs
3591
8309
50
29665
return $self->error("Calling $self->attribute($class,$name) only allowed for graphs")
3592
if exists $self->{graph};
3593
3594
8309
50
41341
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
11644
$three_arg = 1;
3599
8309
100
24257
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
100961
$name = $class;
3605
62881
100
50
161080
$class = $self->{class} || 'graph' if $name eq 'class'; # avoid deep recursion
3606
62881
100
148641
if ($name ne 'class')
3607
{
3608
62805
152894
$class = $self->{cache}->{class};
3609
62805
100
239243
$class = $self->class() unless defined $class;
3610
}
3611
3612
62881
100
168092
return $self->border_attribute() if $name eq 'border'; # virtual attribute
3613
62819
100
144366
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
189639
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3620
3621
70252
92865
my $base_class = $class; $base_class =~ s/\.(.*)//;
70252
122706
3622
70252
100
133439
my $sub_class = $1; $sub_class = '' unless defined $sub_class;
70252
188352
3623
70252
100
144896
if ($name eq 'class')
3624
{
3625
# "[A] { class: red; }" => "red"
3626
76
100
218
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 existance
3632
70243
100
124284
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
70243
162380
3633
70243
100
574659
my $entry = $s->{$name} ||
3634
$attributes->{all}->{$name} ||
3635
$attributes->{$base_class}->{$name};
3636
3637
# create a fake entry for custom attributes
3638
70243
100
375095
$entry = [ '', undef, '', '', ATTR_STRING, '' ]
3639
if $name =~ $qr_custom_attribute;
3640
3641
# Didn't found an entry:
3642
70243
50
177525
return $self->_unknown_attribute($name,$class) unless ref($entry);
3643
3644
70243
100
300541
my $type = $entry->[ ATTR_TYPE_SLOT ] || ATTR_STRING;
3645
3646
70243
85998
my $val;
3647
3648
70243
100
165548
if ($three_arg == 0)
3649
{
3650
###########################################################################
3651
# Check the object directly first
3652
62785
102693
my $a = $self->{att};
3653
62785
100
143509
if (exists $a->{graph})
3654
{
3655
# for graphs, look directly in the class to save time:
3656
2212
100
8087
$val = $a->{graph}->{$name}
3657
if exists $a->{graph}->{$name};
3658
}
3659
else
3660
{
3661
60573
100
169305
$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
168377
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
185641
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
133168
my @tries = ();
3694
# skip "node.foo" if value is 'inherit'
3695
68119
100
227080
push @tries, $class unless defined $val;
3696
68119
100
186649
push @tries, $base_class if $class =~ /\./;
3697
68119
100
100
377786
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
169948
my $g = $self->{graph}; # for objects in a graph
3702
68119
100
208883
$g = { att => {} } unless ref($g); # for objects not in a graph
3703
3704
# XXX TODO should not happen
3705
68119
100
200980
$g = $self if $self->{class} eq 'graph'; # for the graph itself
3706
3707
68119
105003
$val = undef;
3708
TRY:
3709
68119
130454
for my $try (@tries)
3710
{
3711
# print STDERR "# Trying class $try for attribute $name\n" if $name eq 'align';
3712
3713
80667
168877
my $att = $g->{att}->{$try};
3714
3715
80667
100
196926
$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
201740
if (!defined $val)
3719
{
3720
79195
133055
my $def = $entry->[ ATTR_DEFAULT_SLOT ]; $val = $def;
79195
107657
3721
3722
# "node.subclass" gets the default from "node", 'edge' from 'default':
3723
# " { default => 'foo', 'node.anon' => 'none', node => 'solid' }":
3724
79195
100
181990
if (ref $def)
3725
{
3726
38220
73049
$val = $def->{$try};
3727
38220
100
100
171800
if (!defined $val && $try =~ /\./)
3728
{
3729
1231
2342
my $base = $try; $base =~ s/\..*//;
1231
5525
3730
1231
3501
$val = $def->{$base};
3731
}
3732
# if this is not a subclass, get the default value
3733
38220
100
100
147663
next TRY if !defined $val && $try =~ /\./;
3734
3735
37336
100
122321
$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
200796
if ($name ne 'label')
3743
{
3744
74206
50
181938
$self->warn("Uninitialized default for attribute '$name' on class '$try'\n")
3745
unless defined $val;
3746
}
3747
3748
79783
100
215223
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
545348
last if defined $val && ($val ne 'inherit' || $try eq 'graph');
33
3752
3753
# try next class in inheritance tree
3754
11664
24708
$val = undef;
3755
}
3756
3757
# For "background", and objects that are in a group, we inherit "fill":
3758
60890
100
66
168449
if ($name eq 'background' && $val && $val eq 'inherit')
100
3759
{
3760
141
654
my $parent = $self->parent();
3761
141
100
66
863
$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
310771
$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
5900
my ($self,$class,$name,$val) = @_;
3775
3776
# clean quoted strings
3777
# XXX TODO
3778
# $val =~ s/^["'](.*[^\\])["']\z/$1/;
3779
2464
15241
$val =~ s/^["'](.*)["']\z/$1/;
3780
3781
2464
4513
$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
14011
$val =~ s/%[^2-7][a-fA-F0-9]|%7f//g;
3785
3786
# decode %XX entities
3787
2464
5369
$val =~ s/%([2-7][a-fA-F0-9])/sprintf("%c",hex($1))/eg;
9
54
3788
3789
2464
14676
$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
54716
my ($self, $name, $value, $class) = @_;
3801
3802
84
195
my ($error,$newname,$v) = $self->validate_attribute($name,$value,$class);
3803
3804
84
100
100
311
return [] if defined $error && $error == 1;
3805
59
100
66
128
return undef if defined $error && $error == 2;
3806
57
151
$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
24321
my ($self, $name, $value, $class, $no_multiples) = @_;
3825
3826
1254
50
3248
$self->error("Got reference $value as value, but expected scalar") if ref($value);
3827
1254
50
2982
$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
10346
return (undef, $name, $value) if $name =~ $qr_custom_attribute;
3833
3834
1174
100
3318
$class = 'all' unless defined $class;
3835
1174
2497
$class =~ s/\..*\z//; # remove subclasses
3836
3837
# Remap alias names without "-" to their hyphenated version:
3838
1174
100
4388
$name = $att_aliases->{$name} if exists $att_aliases->{$name};
3839
3840
# prevent ->{special}->{node} from springing into existance
3841
1174
100
2529
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
1174
3888
3842
3843
1174
100
15755
my $entry = $s->{$name} ||
3844
$attributes->{all}->{$name} || $attributes->{$class}->{$name};
3845
3846
# Didn't found an entry:
3847
1174
100
4166
return (1,undef,$self->_unknown_attribute($name,$class)) unless ref($entry);
3848
3849
1120
2813
my $check = $entry->[ATTR_MATCH_SLOT];
3850
1120
100
4802
my $type = $entry->[ATTR_TYPE_SLOT] || ATTR_STRING;
3851
3852
1120
100
2999
$check = '_color' if $type == ATTR_COLOR;
3853
1120
100
2354
$check = '_angle' if $type == ATTR_ANGLE;
3854
1120
100
2460
$check = '_uint' if $type == ATTR_UINT;
3855
3856
1120
3416
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
1455
if (keys %{$attributes->{special}} == 0)
1120
5738
3865
{
3866
920
100
3546
@values = split (/\s*\|\s*/, $value, -1) if $value =~ /(^|[^\\])\|/;
3867
}
3868
3869
1120
100
3161
my $multiples = 0; $multiples = 1 if @values > 1;
1120
2924
3870
1120
50
66
4710
return (4) if $no_multiples && $multiples; # | and no multiples => error
3871
3872
# check each part on it's own
3873
1120
1512
my @rc;
3874
1120
2096
for my $v (@values)
3875
{
3876
# don't check empty parts for being valid
3877
1134
100
50
3347
push @rc, undef and next if $multiples && $v eq '';
100
3878
3879
1129
100
100
12719
if (defined $check && !ref($check))
100
3880
{
3881
49
49
696
no strict 'refs';
49
167
49
88815
3882
381
1840
my $checked = $self->$check($v, $name);
3883
381
100
1044
if (!defined $checked)
3884
{
3885
7
52
$self->error("Error in attribute: '$v' is not a valid $name for a $class");
3886
7
36
return (2);
3887
}
3888
374
1260
push @rc, $checked;
3889
}
3890
elsif ($check)
3891
{
3892
431
100
1797
if (ref($check) eq 'ARRAY')
3893
{
3894
# build a regexp from the list of words
3895
71
828
my $list = 'qr/^(' . join ('|', @$check) . ')\z/;';
3896
71
17000
$entry->[1] = eval($list);
3897
71
510
$check = $entry->[1];
3898
}
3899
431
100
5860
if ($v !~ $check) # invalid?
3900
{
3901
7
40
$self->error("Error in attribute: '$v' is not a valid $name for a $class");
3902
7
32
return (2);
3903
}
3904
3905
424
1011
push @rc, $v; # valid
3906
}
3907
# entry found, but no specific check => anything goes as value
3908
317
698
else { push @rc, $v; }
3909
3910
# "ClAss" => "class" for LCTEXT entries
3911
1115
100
5504
$rc[-1] = lc($rc[-1]) if $type == ATTR_LCTEXT;
3912
}
3913
3914
# only one value ('green')
3915
1106
100
8754
return (undef, $name, $rc[0]) unless $multiples;
3916
3917
# multiple values ('green|red')
3918
10
67
(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 (similiar structured).
3933
# Also encode/quote the value. Suppresses default attributes.
3934
2886
2886
7506
my ($self, $object, $att, $remap, $noquote, $encode, $color_remap ) = @_;
3935
3936
2886
5481
my $out = {};
3937
3938
2886
100
9901
my $class = $object || 'node';
3939
2886
100
50
24627
$class = $object->{class} || 'graph' if ref($object);
3940
2886
7027
$class =~ s/\..*//; # remove subclass
3941
3942
2886
7170
my $r = $remap->{$class};
3943
2886
5566
my $ra = $remap->{all};
3944
2886
4319
my $ral = $remap->{always};
3945
2886
4992
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
15692
my @keys = sort keys %$att;
3953
3954
2886
6832
my $color_scheme = 'w3c';
3955
2886
100
13677
$color_scheme = $object->attribute('colorscheme') if ref($object);
3956
2886
100
100
23056
$color_scheme = $self->get_attribute($object,'colorscheme')
3957
if defined $object && !ref($object);
3958
3959
2886
50
33
17258
$color_scheme = $self->get_attribute('graph','colorscheme')
3960
if defined $color_scheme && $color_scheme eq 'inherit';
3961
3962
2886
6042
for my $atr (@keys)
3963
{
3964
5071
16582
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
16636
if (!ref($object) && !exists $ral->{$atr})
3970
{
3971
# attribute not defined
3972
1141
100
100
12208
next if !defined $val || $val eq '' ||
100
66
100
66
3973
# or $remap says we should suppress it
3974
(exists $r->{$atr} && !defined $r->{$atr}) ||
3975
(exists $ra->{$atr} && !defined $ra->{$atr});
3976
}
3977
3978
4643
100
30111
my $entry = $attributes->{all}->{$atr} || $attributes->{$class}->{$atr};
3979
3980
4643
50
66
17834
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
360
$val = $self->color_as_hex($val,$color_scheme)
3985
if ($entry->[ ATTR_TYPE_SLOT ]||ATTR_STRING) == ATTR_COLOR;
3986
}
3987
3988
4643
13985
my $temp = { $atr => $val };
3989
3990
# see if there is a handler for custom attributes
3991
4643
100
100
34764
if (exists $r->{$atr} || exists $ra->{$atr} || (defined $x && $atr =~ /^x-/))
100
66
3992
{
3993
3441
100
7284
my $rc = $r->{$atr}; $rc = $ra->{$atr} unless defined $rc;
3441
10269
3994
3441
100
7752
$rc = $x unless defined $rc;
3995
3996
# if given a code ref, call it to remap name and/or value
3997
3441
100
8583
if (ref($rc) eq 'CODE')
3998
{
3999
2055
2997
my @rc = &{$rc}($self,$atr,$val,$object);
2055
7909
4000
2055
4483
$temp = {};
4001
2055
9112
while (@rc)
4002
{
4003
2074
3784
my $a = shift @rc; my $v = shift @rc;
2074
3033
4004
2074
100
66
17108
$temp->{ $a } = $v if defined $a && defined $v;
4005
}
4006
}
4007
else
4008
{
4009
# otherwise, rename the attribute name if nec.
4010
1386
3957
$temp = { };
4011
1386
100
100
6735
$temp = { $rc => $val } if defined $val && defined $rc;
4012
}
4013
}
4014
4015
4643
23805
for my $at (sort keys %$temp)
4016
{
4017
2594
5329
my $v = $temp->{$at};
4018
4019
2594
100
66
28507
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
13154
$v =~ s/([;"%\x00-\x1f])/sprintf("%%%02x",ord($1))/eg
7
40
4025
if $encode && $v =~ /[;"\x00-\x1f]/;
4026
# quote if nec.
4027
2211
50
6299
$v = '"' . $v . '"' unless $noquote;
4028
4029
2211
14727
$out->{$at} = $v;
4030
}
4031
}
4032
4033
2886
15678
$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
2069
my $self = shift;
4041
4042
436
50
1496
my $class = $self->{class} || 'graph';
4043
4044
436
732
my $att = $self->{att};
4045
436
100
2049
$att = $self->{att}->{graph} if $class eq 'graph';
4046
4047
436
66
1217
my $g = $self->{graph} || $self;
4048
4049
436
843
my $out = {};
4050
436
100
1358
if (!$g->{strict})
4051
{
4052
2
14
for my $name (sort keys %$att)
4053
{
4054
6
16
my $val = $att->{$name};
4055
6
50
14
next unless defined $val; # set to undef?
4056
4057
6
13
$out->{$name} = $val;
4058
}
4059
2
9
return $out;
4060
}
4061
4062
434
747
my $base_class = $class; $base_class =~ s/\..*//;
434
1412
4063
434
2098
for my $name (sort keys %$att)
4064
{
4065
506
1140
my $val = $att->{$name};
4066
506
100
1083
next unless defined $val; # set to undef?
4067
4068
500
1841
$out->{$name} = $val;
4069
4070
500
100
1696
next unless $val eq 'inherit';
4071
4072
# prevent ->{special}->{node} from springing into existance
4073
1
50
2
my $s = $attributes->{special}; $s = $s->{$class} if exists $s->{$class};
1
5
4074
1
33
18
my $entry = $s->{$name} ||
4075
$attributes->{all}->{$name} ||
4076
$attributes->{$base_class}->{$name};
4077
4078
# Didn't found an entry:
4079
1
50
5
return $self->_unknown_attribute($name,$class) unless ref($entry);
4080
4081
1
50
5
my $type = $entry->[ ATTR_TYPE_SLOT ] || ATTR_STRING;
4082
4083
# need to inherit value?
4084
1
50
6
$out->{$name} = $self->attribute($name) if $type < ATTR_NO_INHERIT;
4085
}
4086
4087
434
1616
$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
125
my $self = shift;
4096
4097
70
50
1564
$self->error("get_attributes() doesn't take arguments") if @_ > 0;
4098
4099
70
190
my $att = {};
4100
70
449
my $class = $self->main_class();
4101
4102
# f.i. "all", "node"
4103
70
142
for my $type ('all', $class)
4104
{
4105
140
168
for my $a (sort keys %{$attributes->{$type}})
140
1448
4106
{
4107
2284
8186
my $val = $self->attribute($a); # respect inheritance
4108
2284
100
9182
$att->{$a} = $val if defined $val;
4109
}
4110
}
4111
4112
70
530
$att;
4113
}
4114
4115
package Graph::Easy::Node;
4116
4117
BEGIN
4118
{
4119
49
49
29736
*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__