/* * 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.Section; import eu.hansolo.medusa.tools.Helper; import javafx.beans.InvalidationListener; import javafx.geometry.Insets; 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.layout.Region; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; import java.util.List; import java.util.Locale; import static eu.hansolo.medusa.tools.Helper.clamp; import static eu.hansolo.medusa.tools.Helper.formatNumber; /** * Created by hansolo on 30.11.16. */ public class TileTextKpiSkin extends GaugeSkinBase { private double size; private Region barBackground; private Rectangle barClip; private Rectangle bar; private Text titleText; private Text valueText; private Text unitText; private Text percentageText; private Text percentageUnitText; private Rectangle maxValueRect; private Text maxValueText; private Text maxValueUnitText; private Pane pane; private double minValue; private double maxValue; private double range; private double stepSize; private String formatString; private Locale locale; private List<Section> sections; private boolean sectionsVisible; private Color barColor; private InvalidationListener currentValueListener; // ******************** Constructors ************************************** public TileTextKpiSkin(Gauge gauge) { super(gauge); if (gauge.isAutoScale()) gauge.calcAutoScale(); minValue = gauge.getMinValue(); maxValue = gauge.getMaxValue(); range = gauge.getRange(); stepSize = PREFERRED_WIDTH / range; formatString = new StringBuilder("%.").append(Integer.toString(gauge.getDecimals())).append("f").toString(); locale = gauge.getLocale(); sections = gauge.getSections(); sectionsVisible = gauge.getSectionsVisible(); barColor = gauge.getBarColor(); currentValueListener = o -> setBar(gauge.getCurrentValue()); initGraphics(); registerListeners(); setBar(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 Region(); barBackground.setBackground(new Background(new BackgroundFill(gauge.getBarBackgroundColor(), new CornerRadii(0.0, 0.0, 0.025, 0.025, true), Insets.EMPTY))); barClip = new Rectangle(); bar = new Rectangle(); bar.setFill(gauge.getBarColor()); bar.setStroke(null); bar.setClip(barClip); titleText = new Text(); titleText.setFill(gauge.getTitleColor()); Helper.enableNode(titleText, !gauge.getTitle().isEmpty()); valueText = new Text(); valueText.setFill(gauge.getValueColor()); Helper.enableNode(valueText, gauge.isValueVisible()); unitText = new Text(gauge.getUnit()); unitText.setFill(gauge.getUnitColor()); Helper.enableNode(unitText, !gauge.getUnit().isEmpty()); percentageText = new Text(); percentageText.setFill(gauge.getBarColor()); percentageUnitText = new Text("%"); percentageUnitText.setFill(gauge.getBarColor()); maxValueRect = new Rectangle(); maxValueRect.setFill(gauge.getThresholdColor()); maxValueText = new Text(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMaxValue())); maxValueText.setFill(gauge.getBackgroundPaint()); maxValueUnitText = new Text(gauge.getUnit()); maxValueUnitText.setFill(gauge.getBackgroundPaint()); pane = new Pane(barBackground, bar, titleText, valueText, unitText, percentageText, percentageUnitText, maxValueRect, maxValueText, maxValueUnitText); pane.setBorder(new Border(new BorderStroke(gauge.getBorderPaint(), BorderStrokeStyle.SOLID, new CornerRadii(PREFERRED_WIDTH * 0.025), new BorderWidths(gauge.getBorderWidth())))); pane.setBackground(new Background(new BackgroundFill(gauge.getBackgroundPaint(), new CornerRadii(PREFERRED_WIDTH * 0.025), Insets.EMPTY))); getChildren().setAll(pane); } @Override protected void registerListeners() { super.registerListeners(); gauge.currentValueProperty().addListener(currentValueListener); } // ******************** Methods ******************************************* @Override protected void handleEvents(final String EVENT_TYPE) { super.handleEvents(EVENT_TYPE); if ("RECALC".equals(EVENT_TYPE)) { minValue = gauge.getMinValue(); maxValue = gauge.getMaxValue(); range = gauge.getRange(); stepSize = size / range; redraw(); } else if ("VISIBLITY".equals(EVENT_TYPE)) { Helper.enableNode(titleText, !gauge.getTitle().isEmpty()); Helper.enableNode(valueText, gauge.isValueVisible()); Helper.enableNode(unitText, !gauge.getUnit().isEmpty()); } else if ("SECTION".equals(EVENT_TYPE)) { sections = gauge.getSections(); } } private void setBar(final double VALUE) { double targetValue = (clamp(minValue, maxValue, VALUE) - minValue) * stepSize; bar.setWidth(targetValue); valueText.setText(formatNumber(gauge.getLocale(), gauge.getFormatString(), gauge.getDecimals(), VALUE)); percentageText.setText(String.format(locale, formatString, ((VALUE - minValue) / range * 100))); maxValueRect.setFill(VALUE > maxValue ? barColor : gauge.getThresholdColor()); resizeDynamicText(); if (sectionsVisible && !sections.isEmpty()) { setBarColor(VALUE); } } private void setBarColor(final double VALUE) { Color color = barColor; for(Section section : sections) { if (section.contains(VALUE)) { color = section.getColor(); break; } } bar.setFill(color); percentageText.setFill(color); percentageUnitText.setFill(color); } @Override public void dispose() { gauge.currentValueProperty().removeListener(currentValueListener); super.dispose(); } // ******************** Resizing ****************************************** private void resizeDynamicText() { double maxWidth = unitText.isVisible() ? size * 0.725 : size * 0.9; double fontSize = 0.24 * size; valueText.setFont(Fonts.latoRegular(fontSize)); if (valueText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(valueText, maxWidth, fontSize); } if (unitText.isVisible()) { valueText.relocate(size * 0.925 - valueText.getLayoutBounds().getWidth() - unitText.getLayoutBounds().getWidth(), size * 0.15); } else { valueText.relocate(size * 0.95 - valueText.getLayoutBounds().getWidth(), size * 0.15); } percentageUnitText.relocate(percentageText.getLayoutBounds().getMaxX() + size * 0.075, size * 0.75); } private void resizeStaticText() { double maxWidth = size * 0.9; double fontSize = size * 0.06; titleText.setFont(Fonts.latoRegular(fontSize)); if (titleText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(titleText, maxWidth, fontSize); } titleText.relocate(size * 0.05, size * 0.05); maxWidth = size * 0.15; unitText.setFont(Fonts.latoRegular(fontSize)); if (unitText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(unitText, maxWidth, fontSize); } unitText.relocate(size * 0.95 - unitText.getLayoutBounds().getWidth(), size * 0.3275); maxWidth = size * 0.45; fontSize = size * 0.18; percentageText.setFont(Fonts.latoRegular(fontSize)); if (percentageText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(percentageText, maxWidth, fontSize); } percentageText.relocate(size * 0.05, size * 0.695); maxWidth = size * 0.1; fontSize = size * 0.12; percentageUnitText.setFont(Fonts.latoRegular(fontSize)); if (percentageUnitText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(percentageUnitText, maxWidth, fontSize); } percentageUnitText.relocate(percentageText.getLayoutBounds().getMaxX() + size * 0.075, size * 0.75); maxWidth = size * 0.2; fontSize = size * 0.05; maxValueUnitText.setFont(Fonts.latoRegular(fontSize)); if (maxValueUnitText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(maxValueUnitText, maxWidth, fontSize); } maxValueUnitText.setX((size * 0.925) - maxValueUnitText.getLayoutBounds().getWidth()); maxValueUnitText.setY(size * 0.855); maxWidth = size * 0.45; fontSize = size * 0.08; maxValueText.setFont(Fonts.latoRegular(fontSize)); if (maxValueText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(maxValueText, maxWidth, fontSize); } if (unitText.isVisible()) { maxValueText.setX((size * 0.925) - (size * 0.01 + maxValueText.getLayoutBounds().getWidth() + maxValueUnitText.getLayoutBounds().getWidth())); } else { maxValueText.setX((size * 0.925) - maxValueText.getLayoutBounds().getWidth()); } maxValueText.setY(size * 0.855); } @Override protected void resize() { double width = gauge.getWidth() - gauge.getInsets().getLeft() - gauge.getInsets().getRight(); double height = gauge.getHeight() - gauge.getInsets().getTop() - gauge.getInsets().getBottom(); size = width < height ? width : height; stepSize = size / range; if (width > 0 && height > 0) { pane.setMaxSize(size, size); pane.relocate((width - size) * 0.5, (height - size) * 0.5); barBackground.setPrefSize(size, size * 0.035); barBackground.relocate(0, size * 0.965); barClip.setX(0); barClip.setY(size * 0.95); barClip.setWidth(size); barClip.setHeight(size * 0.05); barClip.setArcWidth(size * 0.025); barClip.setArcHeight(size * 0.025); bar.setX(0); bar.setY(size * 0.965); bar.setWidth(clamp(minValue, maxValue, gauge.getCurrentValue()) * stepSize); bar.setHeight(size * 0.035); resizeStaticText(); resizeDynamicText(); maxValueRect.setWidth((maxValueText.getLayoutBounds().getWidth() + maxValueUnitText.getLayoutBounds().getWidth()) + size * 0.06); maxValueRect.setHeight(maxValueText.getLayoutBounds().getHeight() * 1.01); maxValueRect.setX((size * 0.95) - maxValueRect.getWidth()); maxValueRect.setY(size * 0.7775); maxValueRect.setArcWidth(size * 0.025); maxValueRect.setArcHeight(size * 0.025); } } @Override protected void redraw() { pane.setBorder(new Border(new BorderStroke(gauge.getBorderPaint(), BorderStrokeStyle.SOLID, new CornerRadii(size * 0.025), new BorderWidths(gauge.getBorderWidth() / PREFERRED_WIDTH * size)))); pane.setBackground(new Background(new BackgroundFill(gauge.getBackgroundPaint(), new CornerRadii(size * 0.025), Insets.EMPTY))); locale = gauge.getLocale(); formatString = new StringBuilder("%.").append(Integer.toString(gauge.getDecimals())).append("f").toString(); titleText.setText(gauge.getTitle()); percentageText.setText(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getValue() / range * 100)); maxValueText.setText(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMaxValue())); maxValueUnitText.setText(gauge.getUnit()); resizeStaticText(); barBackground.setBackground(new Background(new BackgroundFill(gauge.getBarBackgroundColor().brighter().brighter(), new CornerRadii(0.0, 0.0, size * 0.025, size * 0.025, false), Insets.EMPTY))); barColor = gauge.getBarColor(); if (sectionsVisible && !sections.isEmpty()) { setBarColor(gauge.getValue()); } else { bar.setFill(barColor); } titleText.setFill(gauge.getTitleColor()); maxValueText.setFill(gauge.getBackgroundPaint()); maxValueUnitText.setFill(gauge.getBackgroundPaint()); valueText.setFill(gauge.getValueColor()); unitText.setFill(gauge.getUnitColor()); } }