1
1
package geoscript.carto
2
2
3
3
import geoscript.feature.Schema
4
+ import geoscript.geom.Bounds
4
5
import geoscript.geom.Geometry
6
+ import geoscript.geom.LineString
5
7
import geoscript.layer.Layer
6
8
import geoscript.proj.Projection
7
9
import geoscript.render.Map
10
+ import geoscript.style.ColorMap
8
11
import geoscript.workspace.Memory
9
12
10
13
import javax.imageio.ImageIO
@@ -20,6 +23,7 @@ import java.awt.font.TextAttribute
20
23
import java.awt.geom.GeneralPath
21
24
import java.text.AttributedString
22
25
import java.text.DecimalFormat
26
+ import java.text.NumberFormat
23
27
import java.text.SimpleDateFormat
24
28
25
29
/**
@@ -122,7 +126,7 @@ class Java2DCartoBuilder implements CartoBuilder {
122
126
FontMetrics fontMetrics = graphics. fontMetrics
123
127
String text = " N"
124
128
int textHeight = fontMetrics. height
125
- drawString(text, new Rectangle (0 , height - textHeight, width, textHeight), HorizontalAlign . CENTER , VerticalAlign . BOTTOM )
129
+ drawString(text, new Rectangle (x, y + ( height - textHeight) , width, textHeight), HorizontalAlign . CENTER , VerticalAlign . BOTTOM )
126
130
height = height - textHeight
127
131
}
128
132
@@ -164,10 +168,10 @@ class Java2DCartoBuilder implements CartoBuilder {
164
168
FontMetrics fontMetrics = graphics. fontMetrics
165
169
int textWidth = [fontMetrics. stringWidth(" N" ), fontMetrics. stringWidth(" E" ), fontMetrics. stringWidth(" S" ), fontMetrics. stringWidth(" W" )]. max()
166
170
int textHeight = fontMetrics. height
167
- drawString(" N" , new Rectangle ((width / 2 - textWidth / 2 ) as int , 0 , textWidth, textHeight), HorizontalAlign . CENTER , VerticalAlign . TOP )
168
- drawString(" E" , new Rectangle (width - textWidth, (height / 2 - textHeight / 2 ) as int , textWidth, textHeight), HorizontalAlign . RIGHT , VerticalAlign . MIDDLE )
169
- drawString(" S" , new Rectangle ((width / 2 - textWidth / 2 ) as int , height - textHeight, textWidth, textHeight), HorizontalAlign . CENTER , VerticalAlign . TOP )
170
- drawString(" W" , new Rectangle (0 , (height / 2 - textHeight / 2 ) as int , textWidth, textHeight), HorizontalAlign . LEFT , VerticalAlign . MIDDLE )
171
+ drawString(" N" , new Rectangle (x + (width / 2 - textWidth / 2 ) as int , y , textWidth, textHeight), HorizontalAlign . CENTER , VerticalAlign . TOP )
172
+ drawString(" E" , new Rectangle (x + ( width - textWidth), y + (height / 2 - textHeight / 2 ) as int , textWidth, textHeight), HorizontalAlign . RIGHT , VerticalAlign . MIDDLE )
173
+ drawString(" S" , new Rectangle (x + (width / 2 - textWidth / 2 ) as int , y + ( height - textHeight) , textWidth, textHeight), HorizontalAlign . CENTER , VerticalAlign . TOP )
174
+ drawString(" W" , new Rectangle (x, y + (height / 2 - textHeight / 2 ) as int , textWidth, textHeight), HorizontalAlign . LEFT , VerticalAlign . MIDDLE )
171
175
x = x + textWidth
172
176
y = y + textHeight
173
177
width = width - (textWidth * 2 )
@@ -398,6 +402,170 @@ class Java2DCartoBuilder implements CartoBuilder {
398
402
this
399
403
}
400
404
405
+ @Override
406
+ CartoBuilder legend (LegendItem legendItem ) {
407
+
408
+ // Draw background
409
+ if (legendItem. backgroundColor) {
410
+ graphics. color = legendItem. backgroundColor
411
+ graphics. fillRect(legendItem. x, legendItem. y, legendItem. width, legendItem. height)
412
+ }
413
+
414
+ // Draw title
415
+ graphics. font = legendItem. titleFont
416
+ graphics. color = legendItem. titleColor
417
+ FontMetrics fm = graphics. fontMetrics
418
+ int titleHeight = fm. height
419
+ drawString(legendItem. title, new Rectangle (legendItem. x, legendItem. y, legendItem. width, titleHeight), HorizontalAlign . LEFT , VerticalAlign . MIDDLE )
420
+
421
+ // Draw Entries
422
+ graphics. font = legendItem. textFont
423
+ graphics. color = legendItem. textColor
424
+ fm = graphics. fontMetrics
425
+
426
+ // Keep track of the entry x and y
427
+ int entryX = legendItem. x
428
+ int entryY = legendItem. y + titleHeight + legendItem. gapBetweenEntries
429
+ int maxTextWidth = -1
430
+
431
+ legendItem. entries. eachWithIndex { LegendItem.LegendEntry entry , int i ->
432
+
433
+ if (entry. type == LegendItem.LegendEntryType . COLORMAP ) {
434
+
435
+ // Draw title
436
+ graphics. color = legendItem. textColor
437
+ Rectangle titleRectangle = new Rectangle (entryX, entryY, legendItem. legendEntryWidth * 2 , fm. height)
438
+ drawString(entry. title, titleRectangle, HorizontalAlign . LEFT , VerticalAlign . MIDDLE )
439
+ entryY + = fm. height + legendItem. gapBetweenEntries
440
+
441
+ NumberFormat numberFormat = new DecimalFormat (legendItem. numberFormat)
442
+ ColorMap colorMap = entry. symbolizer as ColorMap
443
+ colorMap. values. each { java.util.Map value ->
444
+
445
+ String title = numberFormat. format(value. quantity)
446
+ String colorHex = " ${ value.color} "
447
+
448
+ Rectangle symbolRectangle = new Rectangle (
449
+ entryX,
450
+ entryY,
451
+ legendItem. legendEntryWidth,
452
+ legendItem. legendEntryHeight
453
+ )
454
+ graphics. color = Color . decode(colorHex)
455
+ graphics. fill(symbolRectangle)
456
+
457
+ Rectangle textRectangle = new Rectangle (
458
+ entryX + legendItem. legendEntryWidth + legendItem. gapBetweenEntries,
459
+ entryY,
460
+ legendItem. legendEntryWidth,
461
+ legendItem. legendEntryHeight
462
+ )
463
+ maxTextWidth = Math . max(maxTextWidth, fm. stringWidth(title) + legendItem. gapBetweenEntries)
464
+ graphics. color = legendItem. textColor
465
+ drawString(title, textRectangle, HorizontalAlign . LEFT , VerticalAlign . MIDDLE )
466
+
467
+ entryY + = legendItem. legendEntryHeight
468
+ }
469
+
470
+ entryY + = legendItem. gapBetweenEntries
471
+
472
+ } else if (entry. type == LegendItem.LegendEntryType . IMAGE ) {
473
+
474
+ // Draw Image
475
+ Rectangle imageRectangle = new Rectangle (entryX, entryY, legendItem. legendEntryWidth, legendItem. legendEntryHeight)
476
+ graphics. drawImage(entry. image, imageRectangle. x as int , imageRectangle. y as int , imageRectangle. width as int , imageRectangle. height as int , null )
477
+
478
+ // Draw title
479
+ graphics. color = legendItem. textColor
480
+ Rectangle titleRectangle = new Rectangle (
481
+ entryX + legendItem. legendEntryWidth + legendItem. gapBetweenEntries,
482
+ entryY,
483
+ legendItem. legendEntryWidth,
484
+ legendItem. legendEntryHeight
485
+ )
486
+ drawString(entry. title, titleRectangle, HorizontalAlign . LEFT , VerticalAlign . MIDDLE )
487
+
488
+ entryY + = legendItem. legendEntryHeight + legendItem. gapBetweenEntries
489
+
490
+ } else if (entry. type == LegendItem.LegendEntryType . GROUP ) {
491
+
492
+ // Draw title
493
+ graphics. color = legendItem. textColor
494
+ Rectangle titleRectangle = new Rectangle (entryX, entryY, legendItem. legendEntryWidth * 2 , fm. height)
495
+ drawString(entry. title, titleRectangle, HorizontalAlign . LEFT , VerticalAlign . MIDDLE )
496
+ entryY + = fm. height + legendItem. gapBetweenEntries
497
+
498
+ } else /* POINT, LINE, POLYGON */ {
499
+
500
+ Rectangle symbolRectangle = new Rectangle (
501
+ entryX,
502
+ entryY,
503
+ legendItem. legendEntryWidth,
504
+ legendItem. legendEntryHeight
505
+ )
506
+
507
+ Geometry geometry
508
+ if (entry. type == LegendItem.LegendEntryType . POLYGON ) {
509
+ geometry = new Bounds (2 , 2 , legendItem. legendEntryWidth - 2 , legendItem. legendEntryHeight - 2 ). geometry
510
+ } else if (entry. type == LegendItem.LegendEntryType . LINE ) {
511
+ geometry = new LineString ([[0 , legendItem. legendEntryHeight / 2], [legendItem.legendEntryWidth, legendItem.legendEntryHeight / 2 ]])
512
+ } else if (entry. type == LegendItem.LegendEntryType . POINT ) {
513
+ geometry = new geoscript.geom.Point ((legendItem. legendEntryWidth / 2) as int, (legendItem.legendEntryHeight / 2 ) as int )
514
+ }
515
+
516
+ Layer layer = Layer . fromGeometry(" polygon" , geometry, style : entry. symbolizer)
517
+ Map map = new Map (
518
+ width : legendItem. legendEntryWidth,
519
+ height : legendItem. legendEntryHeight,
520
+ fixAspectRatio : false ,
521
+ bounds : new Bounds (0 , 0 , legendItem. legendEntryWidth, legendItem. legendEntryHeight),
522
+ layers : [layer]
523
+ )
524
+ graphics. drawImage(map. renderToImage(), symbolRectangle. x as int , symbolRectangle. y as int , null )
525
+
526
+ Rectangle textRectangle = new Rectangle (
527
+ entryX + legendItem. legendEntryWidth + legendItem. gapBetweenEntries,
528
+ entryY,
529
+ legendItem. legendEntryWidth,
530
+ legendItem. legendEntryHeight
531
+ )
532
+ maxTextWidth = Math . max(maxTextWidth, fm. stringWidth(entry. title) + legendItem. gapBetweenEntries)
533
+ drawString(entry. title, textRectangle, HorizontalAlign . LEFT , VerticalAlign . MIDDLE )
534
+
535
+ entryY + = legendItem. legendEntryHeight + legendItem. gapBetweenEntries
536
+ }
537
+
538
+ // Are there more entries?
539
+ if (i < (legendItem. entries. size() - 1 )) {
540
+ // Check to make sure the next entry can fit in the remaining space
541
+ int nextHeight = getLegendItemHeight(legendItem, legendItem. entries[i + 1 ])
542
+ if ((entryY + nextHeight) > legendItem. height) {
543
+ // Move the entry x over to the right to a separate column
544
+ entryX + = legendItem. legendEntryWidth + legendItem. gapBetweenEntries + maxTextWidth
545
+ // Reset the entry y to the top
546
+ entryY = legendItem. y + titleHeight + legendItem. gapBetweenEntries
547
+ // Reset the max text width
548
+ maxTextWidth = -1
549
+ }
550
+ }
551
+ }
552
+ this
553
+ }
554
+
555
+ private int getLegendItemHeight (LegendItem item , LegendItem.LegendEntry entry ) {
556
+ int height
557
+ if (entry. type == LegendItem.LegendEntryType . COLORMAP ) {
558
+ graphics. font = item. textFont
559
+ height = graphics. fontMetrics. height + item. gapBetweenEntries + (entry. symbolizer. values. size() * item. legendEntryHeight) + item. gapBetweenEntries
560
+ } else if (entry. type == LegendItem.LegendEntryType . GROUP ) {
561
+ graphics. font = item. textFont
562
+ height = graphics. fontMetrics. height + item. gapBetweenEntries
563
+ } else {
564
+ height = item. legendEntryHeight + item. gapBetweenEntries
565
+ }
566
+ height
567
+ }
568
+
401
569
private void drawString (String text , Rectangle rectangle , HorizontalAlign horizontalAlign , VerticalAlign verticalAlign ) {
402
570
drawString(text, rectangle, horizontalAlign, verticalAlign, false )
403
571
}
0 commit comments