Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
eu.hansolo.medusa.skins.KpiSkin Maven / Gradle / Ivy
/*
* 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.tools.Helper;
import javafx.beans.InvalidationListener;
import javafx.geometry.Insets;
import javafx.scene.CacheHint;
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.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import java.util.Locale;
import static eu.hansolo.medusa.tools.Helper.formatNumber;
/**
* Created by hansolo on 15.01.16.
*/
public class KpiSkin extends GaugeSkinBase {
private double size;
private double oldValue;
private Arc barBackground;
private Arc thresholdBar;
private Path needle;
private Rotate needleRotate;
private Text titleText;
private Text valueText;
private Text minValueText;
private Text maxValueText;
private Text thresholdText;
private Pane pane;
private double angleRange;
private double minValue;
private double range;
private double angleStep;
private Locale locale;
private InvalidationListener currentValueListener;
// ******************** Constructors **************************************
public KpiSkin(Gauge gauge) {
super(gauge);
if (gauge.isAutoScale()) gauge.calcAutoScale();
angleRange = Helper.clamp(90.0, 180.0, gauge.getAngleRange());
oldValue = gauge.getValue();
minValue = gauge.getMinValue();
range = gauge.getRange();
angleStep = angleRange / range;
locale = gauge.getLocale();
currentValueListener = o -> rotateNeedle(gauge.getCurrentValue());
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.getBarColor());
barBackground.setStrokeWidth(PREFERRED_WIDTH * 0.02819549 * 2);
barBackground.setStrokeLineCap(StrokeLineCap.BUTT);
barBackground.setFill(null);
thresholdBar = new Arc(PREFERRED_WIDTH * 0.5, PREFERRED_HEIGHT * 0.696, PREFERRED_WIDTH * 0.275, PREFERRED_WIDTH * 0.275, -angleRange * 0.5 + 90, 0);
thresholdBar.setType(ArcType.OPEN);
thresholdBar.setStroke(gauge.getThresholdColor());
thresholdBar.setStrokeWidth(PREFERRED_WIDTH * 0.02819549 * 2);
thresholdBar.setStrokeLineCap(StrokeLineCap.BUTT);
thresholdBar.setFill(null);
needleRotate = new Rotate((gauge.getValue() - oldValue - minValue) * angleStep);
needle = new Path();
needle.setFillRule(FillRule.EVEN_ODD);
needle.getTransforms().setAll(needleRotate);
needle.setFill(gauge.getNeedleColor());
needle.setStrokeWidth(0);
needle.setStroke(Color.TRANSPARENT);
titleText = new Text(gauge.getTitle());
titleText.setFill(gauge.getTitleColor());
Helper.enableNode(titleText, !gauge.getTitle().isEmpty());
valueText = new Text(formatNumber(gauge.getFormatString(), gauge.getDecimals(), gauge.getCurrentValue()));
valueText.setFill(gauge.getValueColor());
Helper.enableNode(valueText, gauge.isValueVisible());
minValueText = new Text(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMinValue()));
minValueText.setFill(gauge.getTitleColor());
maxValueText = new Text(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMaxValue()));
maxValueText.setFill(gauge.getTitleColor());
thresholdText = new Text(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getThreshold()));
thresholdText.setFill(gauge.getTitleColor());
Helper.enableNode(thresholdText, Double.compare(gauge.getThreshold(), gauge.getMinValue()) != 0 && Double.compare(gauge.getThreshold(), gauge.getMaxValue()) != 0);
pane = new Pane(barBackground, thresholdBar, needle, titleText, valueText, minValueText, maxValueText, thresholdText);
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);
}
// ******************** 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());
minValue = gauge.getMinValue();
range = gauge.getRange();
angleStep = angleRange / range;
redraw();
}
}
private void rotateNeedle(final double VALUE) {
double needleStartAngle = angleRange * 0.5;
double targetAngle = (VALUE - minValue) * angleStep - needleStartAngle;
targetAngle = Helper.clamp(-needleStartAngle, -needleStartAngle + angleRange, targetAngle);
needleRotate.setAngle(targetAngle);
valueText.setText(formatNumber(gauge.getFormatString(), gauge.getDecimals(), VALUE));
resizeValueText();
}
private void drawNeedle() {
double needleWidth = size * 0.064;
double needleHeight = size * 0.44;
needle.setCache(false);
needle.getElements().clear();
needle.getElements().add(new MoveTo(0.1875 * needleWidth, 0.0));
needle.getElements().add(new CubicCurveTo(0.1875 * needleWidth, 0.0,
0.1875 * needleWidth, 0.8727272727272727 * needleHeight,
0.1875 * needleWidth, 0.8727272727272727 * needleHeight));
needle.getElements().add(new CubicCurveTo(0.0625 * needleWidth, 0.8818181818181818 * needleHeight,
0.0, 0.9 * needleHeight,
0.0, 0.9272727272727272 * needleHeight));
needle.getElements().add(new CubicCurveTo(0.0, 0.9636363636363636 * needleHeight,
0.25 * needleWidth, needleHeight,
0.5 * needleWidth, needleHeight));
needle.getElements().add(new CubicCurveTo(0.75 * needleWidth, needleHeight,
needleWidth, 0.9636363636363636 * needleHeight,
needleWidth, 0.9272727272727272 * needleHeight));
needle.getElements().add(new CubicCurveTo(needleWidth, 0.9 * needleHeight,
0.9375 * needleWidth, 0.8818181818181818 * needleHeight,
0.8125 * needleWidth, 0.8727272727272727 * needleHeight));
needle.getElements().add(new CubicCurveTo(0.8125 * needleWidth, 0.8727272727272727 * needleHeight,
0.8125 * needleWidth, 0.0,
0.8125 * needleWidth, 0.0));
needle.getElements().add(new LineTo(0.1875 * needleWidth, 0.0));
needle.getElements().add(new ClosePath());
needle.setCache(true);
needle.setCacheHint(CacheHint.ROTATE);
}
@Override public void dispose() {
gauge.currentValueProperty().removeListener(currentValueListener);
super.dispose();
}
// ******************** Resizing ******************************************
private void resizeValueText() {
double maxWidth = 0.86466165 * size;
double fontSize = 0.192 * size;
valueText.setFont(Fonts.latoRegular(fontSize));
if (valueText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(valueText, maxWidth, fontSize); }
valueText.relocate((size - valueText.getLayoutBounds().getWidth()) * 0.5, (size * 0.744));
}
private void resizeStaticText() {
double maxWidth = 0.98 * size;
double fontSize = size * 0.104;
double textRadius;
double textAngle;
double sinValue;
double cosValue;
double textX;
double textY;
titleText.setFont(Fonts.latoRegular(fontSize));
if (titleText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(titleText, maxWidth, fontSize); }
titleText.relocate(size * 0.02, size * 0.02);
maxWidth = size * 0.144;
fontSize = size * 0.048;
maxValueText.setFont(Fonts.latoRegular(fontSize));
if (maxValueText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(maxValueText, maxWidth, fontSize); }
textRadius = size * 0.45;
sinValue = Math.sin(Math.toRadians(90 + (180 - angleRange) * 0.5));
cosValue = Math.cos(Math.toRadians(90 + (180 - angleRange) * 0.5));
textX = size * 0.5 + textRadius * sinValue;
textY = size * 0.672 + textRadius * cosValue;
maxValueText.setTranslateX(-maxValueText.getLayoutBounds().getWidth() * 0.5);
maxValueText.setTranslateY(-maxValueText.getLayoutBounds().getHeight() * 0.5);
maxValueText.relocate(textX, textY);
minValueText.setFont(Fonts.latoRegular(maxValueText.getFont().getSize()));
if (minValueText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(minValueText, maxWidth, fontSize); }
sinValue = Math.sin(Math.toRadians(-90 - (180 - angleRange) * 0.5));
cosValue = Math.cos(Math.toRadians(-90 - (180 - angleRange) * 0.5));
textX = size * 0.5 + textRadius * sinValue;
textY = size * 0.672 + textRadius * cosValue;
minValueText.setTranslateX(-minValueText.getLayoutBounds().getWidth() * 0.5);
minValueText.setTranslateY(-minValueText.getLayoutBounds().getHeight() * 0.5);
minValueText.relocate(textX, textY);
fontSize = size * 0.08;
thresholdText.setFont(Fonts.latoRegular(fontSize));
if (thresholdText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(thresholdText, maxWidth, fontSize); }
textRadius = size * 0.5;
textAngle = (gauge.getThreshold() - minValue) * angleStep;
sinValue = Math.sin(Math.toRadians(180 + angleRange * 0.5 - textAngle));
cosValue = Math.cos(Math.toRadians(180 + angleRange * 0.5 - textAngle));
textX = size * 0.5 + textRadius * sinValue;
textY = size * 0.72 + textRadius * cosValue;
thresholdText.setTranslateX(-thresholdText.getLayoutBounds().getWidth() * 0.5);
thresholdText.setTranslateY(-thresholdText.getLayoutBounds().getHeight() * 0.5);
thresholdText.relocate(textX, textY);
}
@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;
if (width > 0 && height > 0) {
double centerX = size * 0.5;
double centerY = size * 0.696;
double barRadius = size * 0.275;
double barWidth = size * 0.216;
pane.setMaxSize(size, size);
pane.relocate((width - size) * 0.5, (height - size) * 0.5);
barBackground.setCenterX(centerX);
barBackground.setCenterY(centerY - size * 0.008);
barBackground.setRadiusX(barRadius);
barBackground.setRadiusY(barRadius);
barBackground.setStrokeWidth(barWidth);
barBackground.setStartAngle(angleRange * 0.5 + 90);
barBackground.setLength(-angleRange);
thresholdBar.setCenterX(centerX);
thresholdBar.setCenterY(centerY - size * 0.008);
thresholdBar.setRadiusX(barRadius);
thresholdBar.setRadiusY(barRadius);
thresholdBar.setStrokeWidth(barWidth);
thresholdBar.setStartAngle(90 - angleRange * 0.5);
thresholdBar.setLength((gauge.getMaxValue() - gauge.getThreshold()) * angleStep);
drawNeedle();
needle.relocate((size - 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();
resizeValueText();
}
}
@Override protected void redraw() {
pane.setBorder(new Border(new BorderStroke(gauge.getBorderPaint(), BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(gauge.getBorderWidth() / PREFERRED_WIDTH * size))));
pane.setBackground(new Background(new BackgroundFill(gauge.getBackgroundPaint(), CornerRadii.EMPTY, Insets.EMPTY)));
locale = gauge.getLocale();
titleText.setText(gauge.getTitle());
minValueText.setText(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMinValue()));
maxValueText.setText(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getMaxValue()));
thresholdText.setText(String.format(locale, "%." + gauge.getTickLabelDecimals() + "f", gauge.getThreshold()));
resizeStaticText();
barBackground.setStroke(gauge.getBarColor());
thresholdBar.setStroke(gauge.getThresholdColor());
needle.setFill(gauge.getNeedleColor());
titleText.setFill(gauge.getTitleColor());
minValueText.setFill(gauge.getTitleColor());
maxValueText.setFill(gauge.getTitleColor());
thresholdText.setFill(gauge.getTitleColor());
valueText.setFill(gauge.getValueColor());
thresholdText.setVisible(Double.compare(gauge.getThreshold(), gauge.getMinValue()) != 0 && Double.compare(gauge.getThreshold(), gauge.getMaxValue()) != 0);
}
}