All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.hansolo.medusa.skins.IndicatorSkin Maven / Gradle / Ivy

There is a newer version: 16.0.0
Show newest version
/*
 * Copyright (c) 2016 by Gerrit Grunwald
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package eu.hansolo.medusa.skins;

import eu.hansolo.medusa.Fonts;
import eu.hansolo.medusa.Gauge;
import eu.hansolo.medusa.Gauge.ScaleDirection;
import eu.hansolo.medusa.Section;
import eu.hansolo.medusa.tools.Helper;
import javafx.beans.InvalidationListener;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.scene.CacheHint;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.ClosePath;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.FillRule;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeType;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.scene.transform.Rotate;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;


/**
 * Created by hansolo on 16.01.16.
 */
public class IndicatorSkin extends GaugeSkinBase {
    protected static final double PREFERRED_WIDTH  = 250;
    protected static final double PREFERRED_HEIGHT = 165;
    protected static final double MINIMUM_WIDTH    = 50;
    protected static final double MINIMUM_HEIGHT   = 50;
    protected static final double MAXIMUM_WIDTH    = 1024;
    protected static final double MAXIMUM_HEIGHT   = 1024;
    private static final double   ASPECT_RATIO     = 0.59375;
    private double                width;
    private double                height;
    private double                oldValue;
    private Arc                   barBackground;
    private Pane                  sectionLayer;
    private Arc                   bar;
    private Path                  needle;
    private MoveTo                needleMoveTo1;
    private CubicCurveTo          needleCubicCurveTo2;
    private CubicCurveTo          needleCubicCurveTo3;
    private CubicCurveTo          needleCubicCurveTo4;
    private CubicCurveTo          needleCubicCurveTo5;
    private CubicCurveTo          needleCubicCurveTo6;
    private CubicCurveTo          needleCubicCurveTo7;
    private ClosePath             needleClosePath8;
    private Rotate                needleRotate;
    private Text                  minValueText;
    private Text                  maxValueText;
    private Text                  titleText;
    private Pane                  pane;
    private double                angleRange;
    private double                minValue;
    private double                range;
    private double                angleStep;
    private double                startAngle;
    private boolean               colorGradientEnabled;
    private int                   noOfGradientStops;
    private boolean               sectionsAlwaysVisible;
    private boolean               sectionsVisible;
    private List
sections; private Tooltip needleTooltip; private String formatString; private Locale locale; private Color barColor; private Tooltip barTooltip; private InvalidationListener currentValueListener; private InvalidationListener sectionAlwaysVisibleListener; // ******************** Constructors ************************************** public IndicatorSkin(Gauge gauge) { super(gauge); if (gauge.isAutoScale()) gauge.calcAutoScale(); angleRange = Helper.clamp(90.0, 180.0, gauge.getAngleRange()); startAngle = getStartAngle(); oldValue = gauge.getValue(); minValue = gauge.getMinValue(); range = gauge.getRange(); angleStep = angleRange / range; colorGradientEnabled = gauge.isGradientBarEnabled(); noOfGradientStops = gauge.getGradientBarStops().size(); sectionsAlwaysVisible = gauge.getSectionsAlwaysVisible(); sectionsVisible = gauge.getSectionsVisible(); sections = gauge.getSections(); formatString = new StringBuilder("%.").append(Integer.toString(gauge.getDecimals())).append("f").toString(); locale = gauge.getLocale(); barColor = gauge.getBarColor(); currentValueListener = o -> rotateNeedle(gauge.getCurrentValue()); sectionAlwaysVisibleListener = o -> bar.setVisible(!gauge.getSectionsAlwaysVisible()); initGraphics(); registerListeners(); rotateNeedle(gauge.getCurrentValue()); } // ******************** Initialization ************************************ private void initGraphics() { // Set initial size if (Double.compare(gauge.getPrefWidth(), 0.0) <= 0 || Double.compare(gauge.getPrefHeight(), 0.0) <= 0 || Double.compare(gauge.getWidth(), 0.0) <= 0 || Double.compare(gauge.getHeight(), 0.0) <= 0) { if (gauge.getPrefWidth() > 0 && gauge.getPrefHeight() > 0) { gauge.setPrefSize(gauge.getPrefWidth(), gauge.getPrefHeight()); } else { gauge.setPrefSize(PREFERRED_WIDTH, PREFERRED_HEIGHT); } } barBackground = new Arc(PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.696, PREFERRED_WIDTH * 0.275, PREFERRED_WIDTH * 0.275, angleRange * 0.5 + 90, -angleRange); barBackground.setType(ArcType.OPEN); barBackground.setStroke(gauge.getBarBackgroundColor()); barBackground.setStrokeWidth(PREFERRED_WIDTH * 0.02819549 * 2); barBackground.setStrokeLineCap(StrokeLineCap.BUTT); barBackground.setFill(null); sectionLayer = new Pane(); sectionLayer.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY))); bar = new Arc(PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.696, PREFERRED_WIDTH * 0.275, PREFERRED_WIDTH * 0.275, angleRange * 0.5 + 90, 0); bar.setType(ArcType.OPEN); bar.setStroke(gauge.getBarColor()); bar.setStrokeWidth(PREFERRED_WIDTH * 0.02819549 * 2); bar.setStrokeLineCap(StrokeLineCap.BUTT); bar.setFill(null); //bar.setMouseTransparent(sectionsAlwaysVisible ? true : false); bar.setVisible(!sectionsAlwaysVisible); needleRotate = new Rotate((gauge.getValue() - oldValue - minValue) * angleStep); needleMoveTo1 = new MoveTo(); needleCubicCurveTo2 = new CubicCurveTo(); needleCubicCurveTo3 = new CubicCurveTo(); needleCubicCurveTo4 = new CubicCurveTo(); needleCubicCurveTo5 = new CubicCurveTo(); needleCubicCurveTo6 = new CubicCurveTo(); needleCubicCurveTo7 = new CubicCurveTo(); needleClosePath8 = new ClosePath(); needle = new Path(needleMoveTo1, needleCubicCurveTo2, needleCubicCurveTo3, needleCubicCurveTo4, needleCubicCurveTo5, needleCubicCurveTo6, needleCubicCurveTo7, needleClosePath8); needle.setFillRule(FillRule.EVEN_ODD); needle.getTransforms().setAll(needleRotate); needle.setFill(gauge.getNeedleColor()); needle.setPickOnBounds(false); needle.setStrokeType(StrokeType.INSIDE); needle.setStrokeWidth(1); needle.setStroke(gauge.getBackgroundPaint()); needleTooltip = new Tooltip(String.format(locale, formatString, gauge.getValue())); needleTooltip.setTextAlignment(TextAlignment.CENTER); Tooltip.install(needle, needleTooltip); minValueText = new Text(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMinValue())); minValueText.setFill(gauge.getTitleColor()); Helper.enableNode(minValueText, gauge.getTickLabelsVisible()); maxValueText = new Text(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMaxValue())); maxValueText.setFill(gauge.getTitleColor()); Helper.enableNode(maxValueText, gauge.getTickLabelsVisible()); titleText = new Text(gauge.getTitle()); titleText.setFill(gauge.getTitleColor()); Helper.enableNode(titleText, !gauge.getTitle().isEmpty()); if (!sections.isEmpty() && sectionsVisible && !sectionsAlwaysVisible) { barTooltip = new Tooltip(); barTooltip.setTextAlignment(TextAlignment.CENTER); Tooltip.install(bar, barTooltip); } pane = new Pane(barBackground, sectionLayer, bar, needle, minValueText, maxValueText, titleText); pane.setBorder(new Border(new BorderStroke(gauge.getBorderPaint(), BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(gauge.getBorderWidth())))); pane.setBackground(new Background(new BackgroundFill(gauge.getBackgroundPaint(), CornerRadii.EMPTY, Insets.EMPTY))); getChildren().setAll(pane); } @Override protected void registerListeners() { super.registerListeners(); gauge.currentValueProperty().addListener(currentValueListener); gauge.sectionsAlwaysVisibleProperty().addListener(sectionAlwaysVisibleListener); } // ******************** Methods ******************************************* @Override protected void handleEvents(final String EVENT_TYPE) { super.handleEvents(EVENT_TYPE); if ("RECALC".equals(EVENT_TYPE)) { angleRange = Helper.clamp(90.0, 180.0, gauge.getAngleRange()); startAngle = getStartAngle(); minValue = gauge.getMinValue(); range = gauge.getRange(); sections = gauge.getSections(); angleStep = angleRange / range; redraw(); rotateNeedle(gauge.getCurrentValue()); } else if ("FINISHED".equals(EVENT_TYPE)) { String text = String.format(locale, formatString, gauge.getValue()); needleTooltip.setText(text); double value = gauge.getValue(); if (gauge.isValueVisible()) { Bounds bounds = barBackground.localToScreen(barBackground.getBoundsInLocal()); double tooltipAngle = needleRotate.getAngle(); double sinValue = Math.sin(Math.toRadians(90 + angleRange * 0.5 - tooltipAngle)); double cosValue = Math.cos(Math.toRadians(90 + angleRange * 0.5 - tooltipAngle)); double needleTipX = bounds.getMinX() + bounds.getWidth() * 0.5 + bounds.getHeight() * sinValue; double needleTipY = bounds.getMinY() + bounds.getHeight() * 0.8 + bounds.getHeight() * cosValue; if (value < (gauge.getMinValue() + (gauge.getRange() * 0.5))) { needleTipX -= text.length() * 7; } needleTooltip.show(needle, needleTipX, needleTipY); } if (sections.isEmpty() || sectionsAlwaysVisible) return; for (Section section : sections) { if (section.contains(value)) { barTooltip.setText(section.getText()); break; } } } else if ("VISIBILITY".equals(EVENT_TYPE)) { Helper.enableNode(titleText, !gauge.getTitle().isEmpty()); } } private double getStartAngle() { ScaleDirection scaleDirection = gauge.getScaleDirection(); switch(scaleDirection) { //case COUNTER_CLOCKWISE: return 180 - angleRange * 0.5; case CLOCKWISE : default : return 180 + angleRange * 0.5; } } private void rotateNeedle(final double VALUE) { double needleStartAngle = angleRange * 0.5; double targetAngle = Helper.clamp(-needleStartAngle, -needleStartAngle + angleRange, ((gauge.getCurrentValue() - minValue) * angleStep - needleStartAngle)); needleRotate.setAngle(targetAngle); bar.setLength(-90 - targetAngle); setBarColor(VALUE); } private void setBarColor(final double VALUE) { if (!sectionsVisible && !colorGradientEnabled) { bar.setStroke(barColor); } else if (colorGradientEnabled && noOfGradientStops > 1) { bar.setStroke(gauge.getGradientLookup().getColorAt((VALUE - minValue) / range)); } else { bar.setStroke(barColor); for (Section section : sections) { if (section.contains(VALUE)) { bar.setStroke(section.getColor()); break; } } } } @Override public void dispose() { gauge.currentValueProperty().removeListener(currentValueListener); gauge.sectionsAlwaysVisibleProperty().removeListener(sectionAlwaysVisibleListener); super.dispose(); } // ******************** Resizing ****************************************** private void resizeStaticText() { double maxWidth = width * 0.28472222; double fontSize = height * 0.12631579; minValueText.setFont(Fonts.latoRegular(fontSize)); if (minValueText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(minValueText, maxWidth, fontSize); } minValueText.relocate((width * 0.28472222) - minValueText.getLayoutBounds().getWidth(), height * 0.885); maxValueText.setFont(Fonts.latoRegular(fontSize)); if (maxValueText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(maxValueText, maxWidth, fontSize); } maxValueText.relocate(width * 0.71527778, height * 0.885); maxWidth = width * 0.9; titleText.setFont(Fonts.latoRegular(fontSize)); if (titleText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(titleText, maxWidth, fontSize); } titleText.relocate((width - titleText.getLayoutBounds().getWidth()) * 0.5, height * 0.95); } @Override protected void resize() { width = gauge.getWidth() - gauge.getInsets().getLeft() - gauge.getInsets().getRight(); height = gauge.getHeight() - gauge.getInsets().getTop() - gauge.getInsets().getBottom(); if (ASPECT_RATIO * width > height) { width = 1 / (ASPECT_RATIO / height); } else if (1 / (ASPECT_RATIO / height) > width) { height = ASPECT_RATIO * width; } if (width > 0 && height > 0) { double centerX = width * 0.5; double centerY = height * 0.85; double barRadius = height * 0.54210526; double barWidth = width * 0.28472222; pane.setMaxSize(width, height); pane.relocate((gauge.getWidth() - width) * 0.5, (gauge.getHeight() - height) * 0.5); barBackground.setCenterX(centerX); barBackground.setCenterY(centerY); barBackground.setRadiusX(barRadius); barBackground.setRadiusY(barRadius); barBackground.setStrokeWidth(barWidth); barBackground.setStartAngle(angleRange * 0.5 + 90); barBackground.setLength(-angleRange); if (sectionsVisible && sectionsAlwaysVisible) { sectionLayer.setPrefSize(width, height); drawSections(); } double needleStartAngle = angleRange * 0.5; double targetAngle = Helper.clamp(-needleStartAngle, -needleStartAngle + angleRange, ((gauge.getCurrentValue() - minValue) * angleStep - needleStartAngle)); bar.setCenterX(centerX); bar.setCenterY(centerY); bar.setRadiusX(barRadius); bar.setRadiusY(barRadius); bar.setStrokeWidth(barWidth); bar.setStartAngle(angleRange * 0.5 + 90); bar.setLength(-90 - targetAngle); double needleWidth = height * 0.13157895; double needleHeight = height * 0.91315789; needle.setCache(true); needleMoveTo1.setX(0.0); needleMoveTo1.setY(0.927953890489914 * needleHeight); needleCubicCurveTo2.setControlX1(0); needleCubicCurveTo2.setControlY1(0.968299711815562 * needleHeight); needleCubicCurveTo2.setControlX2(0.22 * needleWidth); needleCubicCurveTo2.setControlY2(needleHeight); needleCubicCurveTo2.setX(0.5 * needleWidth); needleCubicCurveTo2.setY(needleHeight); needleCubicCurveTo3.setControlX1(0.78 * needleWidth); needleCubicCurveTo3.setControlY1(needleHeight); needleCubicCurveTo3.setControlX2(needleWidth); needleCubicCurveTo3.setControlY2(0.968299711815562 * needleHeight); needleCubicCurveTo3.setX(needleWidth); needleCubicCurveTo3.setY(0.927953890489914 * needleHeight); needleCubicCurveTo4.setControlX1(needleWidth); needleCubicCurveTo4.setControlY1(0.92507204610951 * needleHeight); needleCubicCurveTo4.setControlX2(0.6 * needleWidth); needleCubicCurveTo4.setControlY2(0.0144092219020173 * needleHeight); needleCubicCurveTo4.setX(0.6 * needleWidth); needleCubicCurveTo4.setY(0.0144092219020173 * needleHeight); needleCubicCurveTo5.setControlX1(0.6 * needleWidth); needleCubicCurveTo5.setControlY1(0.0144092219020173 * needleHeight); needleCubicCurveTo5.setControlX2(0.58 * needleWidth); needleCubicCurveTo5.setControlY2(0); needleCubicCurveTo5.setX(0.5 * needleWidth); needleCubicCurveTo5.setY(0); needleCubicCurveTo6.setControlX1(0.42 * needleWidth); needleCubicCurveTo6.setControlY1(0); needleCubicCurveTo6.setControlX2(0.4 * needleWidth); needleCubicCurveTo6.setControlY2(0.0144092219020173 * needleHeight); needleCubicCurveTo6.setX(0.4 * needleWidth); needleCubicCurveTo6.setY(0.0144092219020173 * needleHeight); needleCubicCurveTo7.setControlX1(0.4 * needleWidth); needleCubicCurveTo7.setControlY1(0.0144092219020173 * needleHeight); needleCubicCurveTo7.setControlX2(0); needleCubicCurveTo7.setControlY2(0.92507204610951 * needleHeight); needleCubicCurveTo7.setX(0); needleCubicCurveTo7.setY(0.927953890489914 * needleHeight); needle.setCache(true); needle.setCacheHint(CacheHint.ROTATE); needle.relocate((width - needle.getLayoutBounds().getWidth()) * 0.5, centerY - needle.getLayoutBounds().getHeight() + needle.getLayoutBounds().getWidth() * 0.5); needleRotate.setPivotX(needle.getLayoutBounds().getWidth() * 0.5); needleRotate.setPivotY(needle.getLayoutBounds().getHeight() - needle.getLayoutBounds().getWidth() * 0.5); resizeStaticText(); } } @Override protected void redraw() { pane.setBorder(new Border(new BorderStroke(gauge.getBorderPaint(), BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(gauge.getBorderWidth() / PREFERRED_HEIGHT * height)))); pane.setBackground(new Background(new BackgroundFill(gauge.getBackgroundPaint(), CornerRadii.EMPTY, Insets.EMPTY))); barColor = gauge.getBarColor(); locale = gauge.getLocale(); formatString = new StringBuilder("%.").append(Integer.toString(gauge.getDecimals())).append("f").toString(); colorGradientEnabled = gauge.isGradientBarEnabled(); noOfGradientStops = gauge.getGradientBarStops().size(); sectionsVisible = gauge.getSectionsVisible(); minValueText.setText(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMinValue())); maxValueText.setText(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMaxValue())); resizeStaticText(); barBackground.setStroke(gauge.getBarBackgroundColor()); bar.setStroke(gauge.getBarColor()); needle.setFill(gauge.getNeedleColor()); minValueText.setVisible(gauge.getTickLabelsVisible()); maxValueText.setVisible(gauge.getTickLabelsVisible()); minValueText.setFill(gauge.getTitleColor()); maxValueText.setFill(gauge.getTitleColor()); titleText.setFill(gauge.getTitleColor()); } private void drawSections() { if (sections.isEmpty()) return; sectionLayer.getChildren().clear(); double centerX = width * 0.5; double centerY = height * 0.85; double barRadius = height * 0.54210526; double barWidth = width * 0.28472222; List sectionBars = new ArrayList<>(sections.size()); for (Section section : sections) { Arc sectionBar = new Arc(centerX, centerY, barRadius, barRadius, angleRange * 0.5 + 90 - (section.getStart() * angleStep), -((section.getStop() - section.getStart()) - minValue) * angleStep); sectionBar.setType(ArcType.OPEN); sectionBar.setStroke(section.getColor()); sectionBar.setStrokeWidth(barWidth); sectionBar.setStrokeLineCap(StrokeLineCap.BUTT); sectionBar.setFill(null); Tooltip sectionTooltip = new Tooltip(new StringBuilder(section.getText()).append("\n").append(String.format(Locale.US, "%.2f", section.getStart())).append(" - ").append(String.format(Locale.US, "%.2f", section.getStop())).toString()); sectionTooltip.setTextAlignment(TextAlignment.CENTER); Tooltip.install(sectionBar, sectionTooltip); sectionBars.add(sectionBar); } sectionLayer.getChildren().addAll(sectionBars); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy