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.tilesfx.skins.WorldMapTileSkin Maven / Gradle / Ivy
/*
* Copyright (c) 2017 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.tilesfx.skins;
import eu.hansolo.tilesfx.tools.Country;
import eu.hansolo.tilesfx.tools.CountryPath;
import eu.hansolo.tilesfx.Tile;
import eu.hansolo.tilesfx.Tile.TextSize;
import eu.hansolo.tilesfx.chart.ChartData;
import eu.hansolo.tilesfx.events.LocationEvent;
import eu.hansolo.tilesfx.events.TileEvent;
import eu.hansolo.tilesfx.events.TileEvent.EventType;
import eu.hansolo.tilesfx.fonts.Fonts;
import eu.hansolo.tilesfx.tools.Helper;
import eu.hansolo.tilesfx.tools.Location;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableMap;
import javafx.collections.WeakListChangeListener;
import javafx.event.EventHandler;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.control.Tooltip;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Text;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static eu.hansolo.tilesfx.tools.Helper.clamp;
/**
* Created by hansolo on 19.12.16.
*/
public class WorldMapTileSkin extends TileSkin {
protected static final double PREFERRED_WIDTH = 500; //380; //510;
protected static final double PREFERRED_HEIGHT = 250;
private static final double MAP_ASPECT_RATIO = Helper.MAP_HEIGHT / Helper.MAP_WIDTH;
private Text titleText;
private Text text;
private Pane worldPane;
private Group group;
private Map> countryPaths;
private ObservableMap chartDataLocations;
private ObservableMap poiLocations;
private Map> handlerMap;
private ListChangeListener poiListener;
private ListChangeListener chartDataListener;
private Map> circleHandlerMap;
// ******************** Constructors **************************************
public WorldMapTileSkin(final Tile TILE) {
super(TILE);
}
// ******************** Initialization ************************************
@Override protected void initGraphics() {
super.initGraphics();
poiLocations = FXCollections.observableHashMap();
chartDataLocations = FXCollections.observableHashMap();
handlerMap = new HashMap<>();
circleHandlerMap = new HashMap<>();
countryPaths = tile.getCountryPaths();
String formatString = new StringBuilder("%.").append(tile.getDecimals()).append("f").toString();
poiListener = new WeakListChangeListener<>(change -> {
while (change.next()) {
if (change.wasAdded()) {
change.getAddedSubList().forEach(addedPoi -> {
String tooltipText = new StringBuilder(addedPoi.getName()).append("\n")
.append(addedPoi.getInfo())
.toString();
EventHandler handler = e -> addedPoi.fireLocationEvent(new LocationEvent(addedPoi));
Circle circle = new Circle(3, addedPoi.getColor());
Tooltip.install(circle, new Tooltip(tooltipText));
circleHandlerMap.put(circle, handler);
poiLocations.put(addedPoi, circle);
circle.setOnMousePressed(handler);
getPane().getChildren().add(circle);
});
} else if (change.wasRemoved()) {
change.getRemoved().forEach(removedPoi -> {
if (circleHandlerMap.get(removedPoi) != null) {
poiLocations.get(removedPoi).removeEventHandler(MouseEvent.MOUSE_PRESSED, circleHandlerMap.get(removedPoi));
}
getPane().getChildren().remove(removedPoi);
});
}
}
resize();
});
chartDataListener = new WeakListChangeListener<>(change -> {
while (change.next()) {
if (change.wasAdded()) {
change.getAddedSubList().forEach(addedData -> {
String tooltipText = new StringBuilder(addedData.getName()).append("\n")
.append(String.format(Locale.US, formatString, addedData.getValue()))
.toString();
EventHandler handler = e -> tile.fireTileEvent(new TileEvent(EventType.SELECTED_CHART_DATA, addedData));
Circle circle = new Circle(3, addedData.getLocation().getColor());
Tooltip.install(circle, new Tooltip(tooltipText));
circleHandlerMap.put(circle, handler);
chartDataLocations.put(addedData.getLocation(), circle);
circle.setOnMousePressed(handler);
getPane().getChildren().add(circle);
});
} else if (change.wasRemoved()) {
change.getRemoved().forEach(removedData -> {
if (circleHandlerMap.get(removedData) != null) {
chartDataLocations.get(removedData).removeEventHandler(MouseEvent.MOUSE_PRESSED, circleHandlerMap.get(removedData));
}
getPane().getChildren().remove(removedData);
});
}
}
resize();
});
tile.getPoiList()
.forEach(poi -> {
String tooltipText = new StringBuilder(poi.getName()).append("\n")
.append(poi.getInfo())
.toString();
Circle circle = new Circle(3, poi.getColor());
circle.setOnMousePressed(e -> poi.fireLocationEvent(new LocationEvent(poi)));
Tooltip.install(circle, new Tooltip(tooltipText));
poiLocations.put(poi, circle);
});
tile.getChartData()
.stream()
.filter(chartData -> chartData.getLocation() != null)
.forEach(chartData -> {
String tooltipText = new StringBuilder(chartData.getName()).append("\n")
.append(String.format(Locale.US, formatString, chartData.getValue()))
.toString();
Circle circle = new Circle(3, chartData.getLocation().getColor());
circle.setOnMousePressed(e -> tile.fireTileEvent(new TileEvent(EventType.SELECTED_CHART_DATA, chartData)));
Tooltip.install(circle, new Tooltip(tooltipText));
chartDataLocations.put(chartData.getLocation(), circle);
});
titleText = new Text();
titleText.setFill(tile.getTitleColor());
Helper.enableNode(titleText, !tile.getTitle().isEmpty());
text = new Text(tile.getUnit());
text.setFill(tile.getUnitColor());
Helper.enableNode(text, tile.isTextVisible());
Color fill = tile.getForegroundColor();
Color stroke = tile.getBackgroundColor();
worldPane = new Pane();
countryPaths.forEach((name, pathList) -> {
Country country = Country.valueOf(name);
pathList.forEach(path -> {
path.setFill(null == country.getColor() ? fill : country.getColor());
path.setStroke(stroke);
path.setStrokeWidth(0.2);
});
worldPane.getChildren().addAll(pathList);
});
group = new Group(worldPane);
getPane().getChildren().addAll(group, titleText, text);
getPane().getChildren().addAll(chartDataLocations.values());
getPane().getChildren().addAll(poiLocations.values());
}
@Override protected void registerListeners() {
super.registerListeners();
countryPaths.forEach((name , pathList) -> {
Country country = Country.valueOf(name);
EventHandler clickHandler = e -> tile.fireTileEvent(new TileEvent(EventType.SELECTED_CHART_DATA, new ChartData(country.getName(), country.getValue(), country.getColor())));
pathList.forEach(path -> {
handlerMap.put(path, clickHandler);
path.addEventHandler(MouseEvent.MOUSE_PRESSED, clickHandler);
});
});
tile.getPoiList().addListener(poiListener);
tile.getChartData().addListener(chartDataListener);
}
// ******************** Methods *******************************************
@Override protected void handleEvents(final String EVENT_TYPE) {
super.handleEvents(EVENT_TYPE);
if ("VISIBILITY".equals(EVENT_TYPE)) {
Helper.enableNode(titleText, !tile.getTitle().isEmpty());
Helper.enableNode(text, tile.isTextVisible());
} else if ("REFRESH".equals(EVENT_TYPE)) {
refresh();
}
}
@Override public void dispose() {
countryPaths.forEach((name, pathList) -> pathList.forEach(path -> path.removeEventHandler(MouseEvent.MOUSE_PRESSED, handlerMap.get(path))));
tile.getPoiList().removeListener(poiListener);
tile.getChartData().removeListener(chartDataListener);
handlerMap.clear();
circleHandlerMap.clear();
super.dispose();
}
private void setFillAndStroke() {
countryPaths.keySet().forEach(name -> {
Country country = Country.valueOf(name);
setCountryFillAndStroke(country, null == country.getColor() ? tile.getForegroundColor() : country.getColor(), tile.getBackgroundColor());
});
}
private void setCountryFillAndStroke(final Country COUNTRY, final Color FILL, final Color STROKE) {
List paths = countryPaths.get(COUNTRY.getName());
for (CountryPath path : paths) {
path.setFill(FILL);
path.setStroke(STROKE);
}
}
// ******************** Resizing ******************************************
@Override protected void resizeStaticText() {
double maxWidth = width - size * 0.1;
double fontSize = size * textSize.factor;
titleText.setFont(Fonts.latoRegular(fontSize));
if (titleText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(titleText, maxWidth, fontSize); }
switch(tile.getTitleAlignment()) {
default :
case LEFT : titleText.relocate(size * 0.05, size * 0.05); break;
case CENTER: titleText.relocate((width - titleText.getLayoutBounds().getWidth()) * 0.5, size * 0.05); break;
case RIGHT : titleText.relocate(width - (size * 0.05) - titleText.getLayoutBounds().getWidth(), size * 0.05); break;
}
fontSize = size * textSize.factor;
text.setText(tile.getText());
text.setFont(Fonts.latoRegular(fontSize));
if (text.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(text, maxWidth, fontSize); }
switch(tile.getTextAlignment()) {
default :
case LEFT : text.setX(size * 0.05); break;
case CENTER: text.setX((width - text.getLayoutBounds().getWidth()) * 0.5); break;
case RIGHT : text.setX(width - (size * 0.05) - text.getLayoutBounds().getWidth()); break;
}
text.setY(height - size * 0.05);
}
@Override protected void resize() {
super.resize();
width = tile.getWidth() - tile.getInsets().getLeft() - tile.getInsets().getRight();
height = tile.getHeight() - tile.getInsets().getTop() - tile.getInsets().getBottom();
size = width < height ? width : height;
double containerWidth = contentBounds.getWidth();
double containerHeight = contentBounds.getHeight();
if (width > 0 && height > 0) {
pane.setMaxSize(width, height);
pane.setPrefSize(width, height);
resizeStaticText();
resizeDynamicText();
double worldMapHeight = clamp(0, containerWidth * MAP_ASPECT_RATIO, containerHeight);
double worldMapWidth = clamp(0, containerWidth, containerHeight / MAP_ASPECT_RATIO);
worldPane.setCache(true);
worldPane.setCacheHint(CacheHint.SCALE);
worldPane.setScaleX(worldMapWidth / Helper.MAP_WIDTH * (TextSize.NORMAL == textSize ? 1.0 : 0.95));
worldPane.setScaleY(worldMapHeight / Helper.MAP_HEIGHT * (TextSize.NORMAL == textSize ? 1.0 : 0.95));
group.resize(worldMapWidth, worldMapHeight);
group.relocate((width - worldMapWidth) * 0.5, contentBounds.getY() + (contentBounds.getHeight() - worldMapHeight) * 0.5);
worldPane.setCache(false);
poiLocations.forEach((location, circle) -> {
double[] xy = Helper.latLonToXY(location.getLatitude(), location.getLongitude());
double x = xy[0] * worldPane.getScaleX() + group.getBoundsInParent().getMinX();
double y = xy[1] * worldPane.getScaleY() + group.getBoundsInParent().getMinY();
circle.setCenterX(x);
circle.setCenterY(y);
circle.setRadius(size * 0.0075);
});
chartDataLocations.forEach((location, circle) -> {
double[] xy = Helper.latLonToXY(location.getLatitude(), location.getLongitude());
double x = xy[0] * worldPane.getScaleX() + group.getBoundsInParent().getMinX();
double y = xy[1] * worldPane.getScaleY() + group.getBoundsInParent().getMinY();
circle.setCenterX(x);
circle.setCenterY(y);
circle.setRadius(size * 0.0075);
});
}
}
@Override protected void redraw() {
super.redraw();
titleText.setText(tile.getTitle());
text.setText(tile.getText());
resizeStaticText();
titleText.setFill(tile.getTitleColor());
text.setFill(tile.getTextColor());
}
private void refresh() {
Color fill = tile.getForegroundColor();
Color stroke = tile.getBackgroundColor();
countryPaths.forEach((name, pathList) -> {
Country country = Country.valueOf(name);
pathList.forEach(path -> {
path.setFill(null == country.getColor() ? fill : country.getColor());
path.setStroke(stroke);
path.setStrokeWidth(0.2);
});
});
}
}