Ticket #23926: josm_legend_2.patch

File josm_legend_2.patch, 17.0 KB (added by Pauline, 13 months ago)
  • src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java

     
    242242        /* Colors (without custom alpha channel, if given) for HDOP painting. */
    243243        hdopScale = ColorScale.createHSBScale(256).makeReversed().addTitle(tr("HDOP"));
    244244        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("Time"));
    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 [°]"));
    249249
    250250        systemOfMeasurementChanged(null, null);
    251251    }
     
    253253    @Override
    254254    public void systemOfMeasurementChanged(String oldSoM, String newSoM) {
    255255        SystemOfMeasurement som = SystemOfMeasurement.getSystemOfMeasurement();
    256         velocityScale.addTitle(tr("Velocity, {0}", som.speedName));
     256        velocityScale.addTitle(tr("Velocity [{0}]", som.speedName));
    257257        layer.invalidate();
    258258    }
    259259
     
    554554    }
    555555
    556556    /**
     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    /**
    557588     *  Calculate colors of way segments based on latest configuration settings
    558589     */
    559590    public void calculateColors() {
     
    622653            Interval interval = data.getMinMaxTimeForAllTracks().orElse(new Interval(Instant.EPOCH, Instant.now()));
    623654            minval = interval.getStart().getEpochSecond();
    624655            maxval = interval.getEnd().getEpochSecond();
     656
     657            setMinMaxTime(minval, maxval);
     658
    625659            dateScale.setRange(minval, maxval);
    626660        }
    627661
     
    641675            if (!refs.isEmpty()) {
    642676                Collections.sort(refs);
    643677                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));
    645679                refScale.setRange(0, refs.size());
    646680            }
    647681        }
     
    16181652        g.setComposite(AlphaComposite.SrcOver.derive(1.00f));
    16191653
    16201654        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);
    16221656        } 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);
    16241658        } 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);
    16261660        } 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);
    16281662        } else if (colored == ColorMode.VELOCITY) {
    16291663            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);
    16311665        } 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);
     1667        } else if (colored == ColorMode.TIME) {
     1668            dateScale.drawColorBarTime(g, w-10, 50, 20, 100, 1.0, getMinTime(), getMaxTime());
    16331669        }
    16341670    }
    16351671
  • src/org/openstreetmap/josm/tools/ColorScale.java

     
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.tools;
    33
     4import static org.openstreetmap.josm.tools.I18n.marktr;
     5
    46import java.awt.Color;
    57import java.awt.FontMetrics;
    68import java.awt.Graphics2D;
     9import java.awt.Font;
    710import java.util.Arrays;
     11import java.util.Date;
     12import java.time.ZoneId;
     13import java.time.Instant;
     14import java.time.ZonedDateTime;
     15import java.time.format.DateTimeFormatter;
    816
     17import org.openstreetmap.josm.data.preferences.NamedColorProperty;
     18
     19import javax.swing.UIManager;
     20
    921/**
    1022 * Utility class that helps to work with color scale for coloring GPX tracks etc.
    1123 * @since 7319
     
    2133    private String title = "";
    2234    private int intervalCount = 5;
    2335
     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
    2441    private ColorScale() {
    2542
    2643    }
     
    225242    }
    226243
    227244    /**
     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    /**
    228268     * Draws a color bar representing this scale on the given graphics
    229269     * @param g The graphics to draw on
    230270     * @param x Rect x
    231271     * @param y Rect y
    232      * @param w Rect width
    233      * @param h Rect height
     272     * @param w Color bar width
     273     * @param h Color bar height
    234274     * @param valueScale The scale factor of the values
    235275     */
    236276    public void drawColorBar(Graphics2D g, int x, int y, int w, int h, double valueScale) {
    237277        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);
    242             } else {
    243                 g.fillRect(x+i*w/n, y, w/n+1, h);
    244             }
    245         }
    246278
     279        // color bar texts width & height
    247280        int fw, fh;
     281
     282        Font newFont = UIManager.getFont("PopupMenu.font");
     283        g.setFont(newFont);
    248284        FontMetrics fm = g.getFontMetrics();
    249285        fh = fm.getHeight()/2;
     286        int titleWidth = fm.stringWidth(title);
     287
     288        String txt;
     289        Color color;
     290
     291        int arcWidth = 20;
     292        int arcHeight = 20;
     293
     294        g.setColor(LEGEND_BACKGROUND);
     295        int xText = x;
     296        int xRect;
     297        int rectWidth;
     298
     299        // padding from text to edge of rectangle
     300        int padding = 19;
     301
     302        // calculates the width of the color bar texts
    250303        if (colorBarTitles != null && colorBarTitles.length > 0) {
    251              fw = Arrays.stream(colorBarTitles).mapToInt(fm::stringWidth).max().orElse(50);
     304            fw = Arrays.stream(colorBarTitles).mapToInt(fm::stringWidth).max().orElse(50);
    252305        } else {
    253306            fw = fm.stringWidth(
    254307                    String.valueOf(Math.max((int) Math.abs(max * valueScale), (int) Math.abs(min * valueScale))))
    255308                    + fm.stringWidth("0.123");
    256309        }
    257         g.setColor(noDataColor);
     310
     311        // background rectangle
     312        if (fw + w > titleWidth) {
     313            rectWidth = w + fw + padding * 2;
     314            xRect = x - rectWidth;
     315            xText = xRect + (int) (padding / 1.2);
     316            g.fillRoundRect(xRect, (fh * 3 / 2), rectWidth, h + y - (fh * 3 / 2) + (int) (padding / 1.5), arcWidth, arcHeight);
     317        } else {
     318            if (titleWidth >= 120) {
     319                titleWidth = 120;
     320            }
     321            rectWidth = w + titleWidth + padding + padding / 2;
     322            xRect = x - rectWidth;
     323            xText = xRect + padding / 2 + rectWidth / 2 - fw;
     324
     325            g.fillRoundRect(xRect, (fh * 3 / 2), rectWidth, h + y - (fh * 3 / 2) + (int) (padding / 1.5), arcWidth, arcHeight);
     326        }
     327
     328        // colorbar
     329        for (int i = 0; i < n; i++) {
     330            g.setColor(colors[i]);
     331            if (w < h) {
     332                double factor = 1.07 + (0.045 * Math.log(n));
     333                if (n == 6) {
     334                    factor = 1.2;
     335                    g.fillRect(xText + fw + padding / 3, y - padding / 2 + i * (int) (h / n * factor), w, (int) (h / n * factor));
     336                } else if (n < 200) {
     337                    g.fillRect(xText + fw + padding / 3, y - padding / 2 + i * (int) (h / n * factor), w, (int) (h / n * factor));
     338                } else {
     339                    g.fillRect(xText + fw + padding / 3, y - padding / 2 + i * h / (int) (n * 0.875), w, (h / n + 1));
     340                }
     341            } else {
     342                g.fillRect(xText + fw + 7 + i * w / n, y, w / n, h + 1);
     343            }
     344        }
     345
     346        // legend title
    258347        if (title != null) {
    259             g.drawString(title, x-fw-3, y-fh*3/2);
     348            g.setColor(LEGEND_TITLE);
     349            g.drawString(title, xRect + rectWidth / 2 - titleWidth / 2, y - fh * 3 / 2 - 10);
    260350        }
     351
     352        // legend texts
    261353        for (int i = 0; i <= intervalCount; i++) {
    262             g.setColor(colors[(int) (1.0*i*n/intervalCount-1e-10)]);
    263             String txt;
     354            color = colors[(int) (1.0 * i * n / intervalCount - 1e-10)];
     355            g.setColor(color);
     356
    264357            if (colorBarTitles != null && i < colorBarTitles.length) {
    265358                txt = colorBarTitles[i];
    266359            } else {
     
    268361                txt = String.format("%.3f", val*valueScale);
    269362            }
    270363            if (intervalCount == 0) {
    271                 g.drawString(txt, x-fw-3, y+h/2+fh/2);
     364                drawOutline(g, txt, xText, y + h / 2 + fh / 2, color);
     365                g.drawString(txt, xText, y + h / 2 + fh / 2);
    272366            } else if (w < h) {
    273                 g.drawString(txt, x-fw-3, y+i*h/intervalCount+fh/2);
     367                drawOutline(g, txt, xText, y + i * h / intervalCount + fh / 2, color);
     368                g.drawString(txt, xText, y + i * h / intervalCount + fh / 2);
    274369            } else {
    275                 g.drawString(txt, x+i*w/intervalCount-fw/2, y+fh-3);
     370                drawOutline(g, txt, xText + i * w / intervalCount - fw / 2 - (int) (padding / 1.3), y + fh - 5, color);
     371                g.drawString(txt, xText + i * w / intervalCount - fw / 2 - (int) (padding / 1.3), y + fh - 5);
    276372            }
    277373        }
     374
     375        g.setColor(noDataColor);
    278376    }
     377
     378    /**
     379     * Draws a color bar representing the time scale on the given graphics
     380     * @param g The graphics to draw on
     381     * @param x Rect x
     382     * @param y Rect y
     383     * @param w Color bar width
     384     * @param h Color bar height
     385     * @param valueScale The scale factor of the values
     386     * @param minVal start time of the track
     387     * @param maxVal end time of the track
     388     */
     389    public void drawColorBarTime(Graphics2D g, int x, int y, int w, int h, double valueScale, double minVal, double maxVal) {
     390        int n = colors.length;
     391
     392        // color bar texts width & height
     393        int fw, fh;
     394
     395        Font newFont = UIManager.getFont("PopupMenu.font");
     396        g.setFont(newFont);
     397        FontMetrics fm = g.getFontMetrics();
     398        fh = fm.getHeight()/2;
     399        int titleWidth = fm.stringWidth(title);
     400
     401        String txt;
     402        Color color;
     403
     404        int arcWidth = 20;
     405        int arcHeight = 20;
     406
     407        g.setColor(LEGEND_BACKGROUND);
     408        int xText = x;
     409        int xRect;
     410        int rectWidth;
     411
     412        // padding from text to edge of rectangle
     413        int padding = 19;
     414
     415        String formatDay = "yyyy-MM-dd      HH:mm";
     416        String formatTime = "HH:mm:ss";
     417
     418        // calculates the width of the colorbar texts
     419        if (maxVal-minVal > 86400) {
     420            fw = fm.stringWidth(formatDay);
     421        } else {
     422            fw = fm.stringWidth(formatTime);
     423        }
     424
     425        g.setColor(LEGEND_BACKGROUND);
     426
     427        // background rectangle
     428        if (fw + w > titleWidth) {
     429            rectWidth = w + fw + padding * 2;
     430            xRect = x - rectWidth;
     431            xText = xRect + (int) (padding / 1.2);
     432            g.fillRoundRect(xRect, (fh * 3 / 2), rectWidth, h + y - (fh * 3 / 2) + (int) (padding / 1.5), arcWidth, arcHeight);
     433        } else {
     434            if (titleWidth >= 120) {
     435                titleWidth = 120;
     436            }
     437            rectWidth = w + titleWidth + padding + padding / 2;
     438            xRect = x - rectWidth;
     439            xText = xRect + padding / 2 + rectWidth / 2 - fw;
     440            g.fillRoundRect(xRect, (fh * 3 / 2), rectWidth, h + y - (fh * 3 / 2) + (int) (padding / 1.5), arcWidth, arcHeight);
     441        }
     442
     443        // colorbar
     444        for (int i = 0; i < n; i++) {
     445            g.setColor(colors[i]);
     446            if (w < h) {
     447                g.fillRect(xText + fw + padding / 3, y - padding / 2 + i * h / (int) (n * 0.875), w, (h / n + 1));
     448            } else {
     449                g.fillRect(xText + fw + padding / 3 + i * w / n, y, w / n + 1, h);
     450            }
     451        }
     452
     453        // legend title
     454        if (title != null) {
     455            g.setColor(LEGEND_TITLE);
     456            g.drawString(title, xRect + rectWidth / 2 - titleWidth / 2, y - fh * 3 / 2 - padding / 2);;
     457        }
     458
     459        // legend texts
     460        for (int i = 0; i <= intervalCount; i++) {
     461            color = colors[(int) (1.0 * i * n / intervalCount - 1e-10)];
     462            g.setColor(color);
     463
     464            if (colorBarTitles != null && i < colorBarTitles.length) {
     465                txt = colorBarTitles[i];
     466            } else {
     467                final double val = minVal + i * (maxVal - minVal) / intervalCount;
     468                long longval = (long) val;
     469
     470                Date date = new Date(longval * 1000L);
     471                Instant dateInst = date.toInstant();
     472
     473                ZoneId gmt = ZoneId.of("GMT");
     474                ZonedDateTime zonedDateTime = dateInst.atZone(gmt);
     475
     476                String formatted;
     477
     478                if (maxVal-minVal > 86400) {
     479                    DateTimeFormatter day = DateTimeFormatter.ofPattern(formatDay);
     480                    formatted = zonedDateTime.format(day);
     481                } else {
     482                    DateTimeFormatter time = DateTimeFormatter.ofPattern(formatTime);
     483                    formatted = zonedDateTime.format(time);
     484                }
     485
     486                txt = formatted;
     487            }
     488            if (intervalCount == 0) {
     489                drawOutline(g, txt, xText, y + h / 2 + fh / 2, color);
     490                g.drawString(txt, xText, y + h / 2 + fh / 2);
     491            } else if (w < h) {
     492                drawOutline(g, txt, xText, y + i * h / intervalCount + fh / 2, color);
     493                g.drawString(txt, xText, y + i * h / intervalCount + fh / 2);
     494            } else {
     495                drawOutline(g, txt, xText + i * w / intervalCount - fw / 2 - (int) (padding / 1.3), y + fh - 5, color);
     496                g.drawString(txt, xText + i * w / intervalCount - fw / 2 - (int) (padding / 1.3), y + fh - 5);
     497            }
     498        }
     499
     500        g.setColor(noDataColor);
     501    }
    279502}