Ticket #23926: josm_legend.patch
File josm_legend.patch, 16.3 KB (added by , 4 months ago) |
---|
-
src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java
242 242 /* Colors (without custom alpha channel, if given) for HDOP painting. */ 243 243 hdopScale = ColorScale.createHSBScale(256).makeReversed().addTitle(tr("HDOP")); 244 244 qualityScale = ColorScale.createFixedScale(rtkLibQualityColors).addTitle(tr("Quality")).addColorBarTitles(rtkLibQualityNames); 245 fixScale = ColorScale.createFixedScale(gpsFixQualityColors).addTitle(tr("GPS fix ")).addColorBarTitles(gpsFixQualityNames);246 refScale = ColorScale.createCyclicScale(1).addTitle(tr("GPS ref"));247 dateScale = ColorScale.createHSBScale(256).addTitle(tr("T ime"));248 directionScale = ColorScale.createCyclicScale(256).setIntervalCount(4).addTitle(tr("Direction "));245 fixScale = ColorScale.createFixedScale(gpsFixQualityColors).addTitle(tr("GPS fix value")).addColorBarTitles(gpsFixQualityNames); 246 refScale = ColorScale.createCyclicScale(1).addTitle(tr("GPS Ref-ID")); 247 dateScale = ColorScale.createHSBScale(256).addTitle(tr("Track date")); 248 directionScale = ColorScale.createCyclicScale(256).setIntervalCount(4).addTitle(tr("Direction [°]")); 249 249 250 250 systemOfMeasurementChanged(null, null); 251 251 } … … 253 253 @Override 254 254 public void systemOfMeasurementChanged(String oldSoM, String newSoM) { 255 255 SystemOfMeasurement som = SystemOfMeasurement.getSystemOfMeasurement(); 256 velocityScale.addTitle(tr("Velocity , {0}", som.speedName));256 velocityScale.addTitle(tr("Velocity [{0}]", som.speedName)); 257 257 layer.invalidate(); 258 258 } 259 259 … … 554 554 } 555 555 556 556 /** 557 * @param minTime saves the start time of the track as epoch seconds 558 * @param maxTime saves the end time of the track as epoch seconds 559 */ 560 private double minTime; 561 private double maxTime; 562 563 /** 564 * gets the minimum (start) time of the track 565 */ 566 private double getMinTime() { 567 return minTime; 568 } 569 570 /** 571 * gets the maximum (end) time of the track 572 */ 573 private double getMaxTime() { 574 return maxTime; 575 } 576 577 /** 578 * sets the minimum (start) and maximum (end) time of the track 579 * @param minTime start time of the track 580 * @param maxTime end time of the track 581 */ 582 private void setMinMaxTime(double minTime, double maxTime) { 583 this.minTime = minTime; 584 this.maxTime = maxTime; 585 } 586 587 /** 557 588 * Calculate colors of way segments based on latest configuration settings 558 589 */ 559 590 public void calculateColors() { … … 622 653 Interval interval = data.getMinMaxTimeForAllTracks().orElse(new Interval(Instant.EPOCH, Instant.now())); 623 654 minval = interval.getStart().getEpochSecond(); 624 655 maxval = interval.getEnd().getEpochSecond(); 656 657 setMinMaxTime(minval, maxval); 658 625 659 dateScale.setRange(minval, maxval); 626 660 } 627 661 … … 641 675 if (!refs.isEmpty()) { 642 676 Collections.sort(refs); 643 677 String[] a = {}; 644 refScale = ColorScale.createCyclicScale(refs.size()).addTitle(tr("GPS ref ")).addColorBarTitles(refs.toArray(a));678 refScale = ColorScale.createCyclicScale(refs.size()).addTitle(tr("GPS ref ID")).addColorBarTitles(refs.toArray(a)); 645 679 refScale.setRange(0, refs.size()); 646 680 } 647 681 } … … 1618 1652 g.setComposite(AlphaComposite.SrcOver.derive(1.00f)); 1619 1653 1620 1654 if (colored == ColorMode.HDOP) { 1621 hdopScale.drawColorBar(g, w- 30, 50, 20, 100, 1.0);1655 hdopScale.drawColorBar(g, w-10, 50, 20, 100, 1.0, 0.0, 0.0); 1622 1656 } else if (colored == ColorMode.QUALITY) { 1623 qualityScale.drawColorBar(g, w- 30, 50, 20, 100, 1.0);1657 qualityScale.drawColorBar(g, w-10, 50, 20, 100, 1.0, 0.0, 0.0); 1624 1658 } else if (colored == ColorMode.FIX) { 1625 fixScale.drawColorBar(g, w- 30, 50, 20, 175, 1.0);1659 fixScale.drawColorBar(g, w-10, 50, 20, 175, 1.0, 0.0, 0.0); 1626 1660 } else if (colored == ColorMode.REF) { 1627 refScale.drawColorBar(g, w- 30, 50, 20, 175, 1.0);1661 refScale.drawColorBar(g, w-10, 50, 20, 175, 1.0, 0.0, 0.0); 1628 1662 } else if (colored == ColorMode.VELOCITY) { 1629 1663 SystemOfMeasurement som = SystemOfMeasurement.getSystemOfMeasurement(); 1630 velocityScale.drawColorBar(g, w- 30, 50, 20, 100, som.speedValue);1664 velocityScale.drawColorBar(g, w-10, 50, 20, 100, som.speedValue, 0.0, 0.0); 1631 1665 } else if (colored == ColorMode.DIRECTION) { 1632 directionScale.drawColorBar(g, w-30, 50, 20, 100, 180.0/Math.PI); 1666 directionScale.drawColorBar(g, w-10, 50, 20, 100, 180.0/Math.PI, 0.0, 0.0); 1667 } else if (colored == ColorMode.TIME) { 1668 dateScale.drawColorBar(g, w-10, 50, 20, 100, 1.0, getMinTime(), getMaxTime()); 1633 1669 } 1634 1670 } 1635 1671 -
src/org/openstreetmap/josm/tools/ColorScale.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.tools; 3 3 4 import static org.openstreetmap.josm.tools.I18n.marktr; 5 4 6 import java.awt.Color; 5 7 import java.awt.FontMetrics; 6 8 import java.awt.Graphics2D; 9 import java.awt.Font; 7 10 import java.util.Arrays; 11 import java.util.Date; 12 import java.time.ZoneId; 13 import java.time.Instant; 14 import java.time.ZonedDateTime; 15 import java.time.format.DateTimeFormatter; 8 16 17 import org.openstreetmap.josm.data.preferences.NamedColorProperty; 18 19 import javax.swing.UIManager; 20 9 21 /** 10 22 * Utility class that helps to work with color scale for coloring GPX tracks etc. 11 23 * @since 7319 … … 21 33 private String title = ""; 22 34 private int intervalCount = 5; 23 35 36 private static final Color LEGEND_BACKGROUND = new NamedColorProperty(marktr("gpx legend background"), new Color(180, 180, 180, 160)).get(); 37 private static final Color LEGEND_TEXT_OUTLINE_DARK = new NamedColorProperty(marktr("gpx legend text outline dark"), new Color(102, 102, 102)).get(); 38 private static final Color LEGEND_TEXT_OUTLINE_BRIGHT = new NamedColorProperty(marktr("gpx legend text outline bright"), new Color(204, 204, 204)).get(); 39 private static final Color LEGEND_TITLE = new NamedColorProperty(marktr("gpx legend title color"), new Color(0, 0, 0)).get(); 40 24 41 private ColorScale() { 25 42 26 43 } … … 225 242 } 226 243 227 244 /** 245 * draws an outline for the legend texts 246 * @param g The graphics to draw on 247 * @param txt The text to draw the outline 248 * @param x Text x 249 * @param y Text y 250 * @param color The color of the text 251 */ 252 public void drawOutline(Graphics2D g, String txt, int x, int y, Color color) { 253 int greenValue = color.getGreen(); 254 if (greenValue >= 170) { 255 g.setColor(LEGEND_TEXT_OUTLINE_DARK); 256 } else { 257 g.setColor(LEGEND_TEXT_OUTLINE_BRIGHT); 258 } 259 260 g.drawString(txt, x -1, y -1); 261 g.drawString(txt, x +1, y -1); 262 g.drawString(txt, x -1, y +1); 263 g.drawString(txt, x +1, y +1); 264 g.setColor(color); 265 } 266 267 /** 228 268 * Draws a color bar representing this scale on the given graphics 229 269 * @param g The graphics to draw on 230 270 * @param x Rect x … … 233 273 * @param h Rect height 234 274 * @param valueScale The scale factor of the values 235 275 */ 236 public void drawColorBar(Graphics2D g, int x, int y, int w, int h, double valueScale ) {276 public void drawColorBar(Graphics2D g, int x, int y, int w, int h, double valueScale, double minVal, double maxVal) { 237 277 int n = colors.length; 238 for (int i = 0; i < n; i++) { 239 g.setColor(colors[i]); 240 if (w < h) { 241 g.fillRect(x, y+i*h/n, w, h/n+1); 278 int fw, fh; 279 Font newFont = UIManager.getFont("PopupMenu.font"); 280 g.setFont(newFont); 281 FontMetrics fm = g.getFontMetrics(); 282 fh = fm.getHeight()/2; 283 int titleWidth = fm.stringWidth(title); 284 285 String txt; 286 Color color; 287 288 int arcWidth = 20; 289 int arcHeight = 20; 290 291 g.setColor(LEGEND_BACKGROUND); 292 int xText = x; 293 int xRect; 294 int rectWidth; 295 296 if (minVal == 0.0 && maxVal == 0.0) { 297 298 // calculates the width of the colorbar texts 299 if (colorBarTitles != null && colorBarTitles.length > 0) { 300 fw = Arrays.stream(colorBarTitles).mapToInt(fm::stringWidth).max().orElse(50); 242 301 } else { 243 g.fillRect(x+i*w/n, y, w/n+1, h); 302 fw = fm.stringWidth( 303 String.valueOf(Math.max((int) Math.abs(max * valueScale), (int) Math.abs(min * valueScale)))) 304 + fm.stringWidth("0.123"); 244 305 } 245 }246 306 247 int fw, fh; 248 FontMetrics fm = g.getFontMetrics(); 249 fh = fm.getHeight()/2; 250 if (colorBarTitles != null && colorBarTitles.length > 0) { 251 fw = Arrays.stream(colorBarTitles).mapToInt(fm::stringWidth).max().orElse(50); 307 // background rectangle 308 if (fw + w > titleWidth) { 309 rectWidth = w+fw+37; 310 xRect = x-rectWidth-10; 311 xText = xRect + 13; 312 g.fillRoundRect(xRect, (fh*3/2), rectWidth, h+y-(fh*3/2)+10, arcWidth, arcHeight+7); 313 } else { 314 if (titleWidth >= 120) { 315 titleWidth = 120; 316 } 317 rectWidth = w+titleWidth+27; 318 xRect = x-rectWidth-10; 319 xText = xRect+10+rectWidth/2-fw; 320 321 g.fillRoundRect(xRect, (fh*3/2), rectWidth, h+y-(fh*3/2)+10, arcWidth, arcHeight+7); 322 } 323 324 // colorbar 325 for (int i = 0; i < n; i++) { 326 g.setColor(colors[i]); 327 if (w < h) { 328 double factor = 1.07 + (0.045 * Math.log(n)); 329 if (n == 6) { 330 factor = 1.2; 331 g.fillRect(xText+fw+7, y-9+i*(int) (h/n*factor), w, (int) (h/n*factor)); 332 } else if (n < 200) { 333 g.fillRect(xText+fw+7, y-9+i*(int) (h/n*factor), w, (int) (h/n*factor)); 334 } else { 335 g.fillRect(xText+fw+7, y-9+i*h/(int) (n*0.875), w, (h/n+1)); 336 } 337 } else { 338 g.fillRect(xText+fw+7+i*w/n, y, w/n, h+1); 339 } 340 } 341 342 343 if (title != null) { 344 g.setColor(LEGEND_TITLE); 345 g.drawString(title, xRect+rectWidth/2-titleWidth/2, y-fh*3/2-10); 346 } 347 for (int i = 0; i <= intervalCount; i++) { 348 color = colors[(int) (1.0*i*n/intervalCount-1e-10)]; 349 g.setColor(color); 350 351 if (colorBarTitles != null && i < colorBarTitles.length) { 352 txt = colorBarTitles[i]; 353 } else { 354 final double val = min+i*(max-min)/intervalCount; 355 txt = String.format("%.3f", val*valueScale); 356 } 357 if (intervalCount == 0) { 358 drawOutline(g, txt, xText, y+h/2+fh/2, color); 359 g.drawString(txt, xText, y+h/2+fh/2); 360 } else if (w < h) { 361 drawOutline(g, txt, xText, y+i*h/intervalCount+fh/2, color); 362 g.drawString(txt, xText, y+i*h/intervalCount+fh/2); 363 } else { 364 drawOutline(g, txt, xText+i*w/intervalCount-fw/2-15, y+fh-5, color); 365 g.drawString(txt, xText+i*w/intervalCount-fw/2-15, y+fh-5); 366 } 367 } 252 368 } else { 253 fw = fm.stringWidth( 254 String.valueOf(Math.max((int) Math.abs(max * valueScale), (int) Math.abs(min * valueScale)))) 255 + fm.stringWidth("0.123"); 256 } 257 g.setColor(noDataColor); 258 if (title != null) { 259 g.drawString(title, x-fw-3, y-fh*3/2); 260 } 261 for (int i = 0; i <= intervalCount; i++) { 262 g.setColor(colors[(int) (1.0*i*n/intervalCount-1e-10)]); 263 String txt; 264 if (colorBarTitles != null && i < colorBarTitles.length) { 265 txt = colorBarTitles[i]; 369 String formatDay = "yyyy-MM-dd HH:mm"; 370 String formatTime = "HH:mm:ss"; 371 372 // calculates the width of the colorbar texts 373 if (maxVal-minVal > 86400) { 374 fw = fm.stringWidth(formatDay); 266 375 } else { 267 final double val = min+i*(max-min)/intervalCount; 268 txt = String.format("%.3f", val*valueScale); 376 fw = fm.stringWidth(formatTime); 269 377 } 270 if (intervalCount == 0) { 271 g.drawString(txt, x-fw-3, y+h/2+fh/2); 272 } else if (w < h) { 273 g.drawString(txt, x-fw-3, y+i*h/intervalCount+fh/2); 378 379 g.setColor(LEGEND_BACKGROUND); 380 381 // background rectangle 382 if (fw + w > titleWidth) { 383 rectWidth = w+fw+37; 384 xRect = x-rectWidth-10; 385 xText = xRect + 13; 386 g.fillRoundRect(xRect, (fh*3/2), rectWidth, h+y-(fh*3/2)+10, arcWidth, arcHeight+7); 274 387 } else { 275 g.drawString(txt, x+i*w/intervalCount-fw/2, y+fh-3); 388 if (titleWidth >= 120) { 389 titleWidth = 120; 390 } 391 rectWidth = w+titleWidth+27; 392 xRect = x-rectWidth-10; 393 xText = xRect+10+rectWidth/2-fw; 394 g.fillRoundRect(xRect, (fh*3/2), rectWidth, h+y-(fh*3/2)+10, arcWidth, arcHeight+7); 276 395 } 396 397 // colorbar 398 for (int i = 0; i < n; i++) { 399 g.setColor(colors[i]); 400 if (w < h) { 401 g.fillRect(xText+fw+7, y-9+i*h/(int) (n*0.875), w, (h/n+1)); 402 } else { 403 g.fillRect(xText+fw+7+i*w/n, y, w/n+1, h); 404 } 405 } 406 407 if (title != null) { 408 g.setColor(LEGEND_TITLE); 409 g.drawString(title, xRect+rectWidth/2-titleWidth/2, y-fh*3/2-10);; 410 } 411 412 for (int i = 0; i <= intervalCount; i++) { 413 color = colors[(int) (1.0*i*n/intervalCount-1e-10)]; 414 g.setColor(color); 415 416 if (colorBarTitles != null && i < colorBarTitles.length) { 417 txt = colorBarTitles[i]; 418 } else { 419 final double val = minVal+i*(maxVal-minVal)/intervalCount; 420 long longval = (long) val; 421 422 Date date = new Date(longval * 1000L); 423 Instant dateInst = date.toInstant(); 424 425 ZoneId gmt = ZoneId.of("GMT"); 426 ZonedDateTime zonedDateTime = dateInst.atZone(gmt); 427 428 String formatted; 429 430 if (maxVal-minVal > 86400) { 431 DateTimeFormatter day = DateTimeFormatter.ofPattern(formatDay); 432 formatted = zonedDateTime.format(day); 433 } else { 434 DateTimeFormatter time = DateTimeFormatter.ofPattern(formatTime); 435 formatted = zonedDateTime.format(time); 436 } 437 438 txt = formatted; 439 } 440 if (intervalCount == 0) { 441 drawOutline(g, txt, xText, y+h/2+fh/2, color); 442 g.drawString(txt, xText, y+h/2+fh/2); 443 } else if (w < h) { 444 drawOutline(g, txt, xText, y+i*h/intervalCount+fh/2, color); 445 g.drawString(txt, xText, y+i*h/intervalCount+fh/2); 446 } else { 447 drawOutline(g, txt, xText+i*w/intervalCount-fw/2-15, y+fh-5, color); 448 g.drawString(txt, xText+i*w/intervalCount-fw/2-15, y+fh-5); 449 } 450 } 277 451 } 452 g.setColor(noDataColor); 278 453 } 279 454 }