All Downloads are FREE. Search and download functionalities are using the official Maven repository.
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.fx.countries.WorldPane Maven / Gradle / Ivy
package eu.hansolo.fx.countries;
import eu.hansolo.fx.countries.font.Fonts;
import eu.hansolo.fx.countries.tools.ColorMapping;
import eu.hansolo.fx.countries.tools.Constants;
import eu.hansolo.fx.countries.tools.CountryPath;
import eu.hansolo.fx.countries.tools.HeatMap;
import eu.hansolo.fx.countries.tools.HeatMapBuilder;
import eu.hansolo.fx.countries.tools.Helper;
import eu.hansolo.fx.countries.tools.Mapping;
import eu.hansolo.fx.countries.tools.OpacityDistribution;
import eu.hansolo.fx.countries.tools.Poi;
import eu.hansolo.fx.countries.tools.Point;
import javafx.application.Platform;
import javafx.beans.DefaultProperty;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.BooleanPropertyBase;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.DoublePropertyBase;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.event.WeakEventHandler;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.SVGPath;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.scene.text.TextAlignment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static javafx.scene.input.MouseEvent.MOUSE_ENTERED;
import static javafx.scene.input.MouseEvent.MOUSE_EXITED;
import static javafx.scene.input.MouseEvent.MOUSE_PRESSED;
import static javafx.scene.input.MouseEvent.MOUSE_RELEASED;
@DefaultProperty("children")
public class WorldPane extends Region {
private static final double PREFERRED_WIDTH = 1009;
private static final double PREFERRED_HEIGHT = 665;
private static final double MINIMUM_WIDTH = 50;
private static final double MINIMUM_HEIGHT = 50;
private static final double MAXIMUM_WIDTH = 4096;
private static final double MAXIMUM_HEIGHT = 4096;
private static final Map> COUNTRY_PATHS = Country.getCopyOfCountryPaths();
private double size;
private double width;
private double height;
private HeatMap heatmap;
private Canvas canvas;
private GraphicsContext ctx;
private Pane pane;
private Group group;
private double scaleX;
private double scaleY;
private Color _fill;
private ObjectProperty fill;
private Color _stroke;
private ObjectProperty stroke;
private double _lineWidth;
private DoubleProperty lineWidth;
private Color _poiFill;
private ObjectProperty poiFill;
private Color _poiStroke;
private ObjectProperty poiStroke;
private Color _poiTextFill;
private ObjectProperty poiTextFill;
private boolean _hoverEnabled;
private BooleanProperty hoverEnabled;
private boolean _selectionEnabled;
private BooleanProperty selectionEnabled;
private Country _selectedCountry;
private ObjectProperty selectedCountry;
private Country formerSelectedCountry;
private Color _hoverColor;
private ObjectProperty hoverColor;
private Color _pressedColor;
private ObjectProperty pressedColor;
private Color _selectedColor;
private ObjectProperty selectedColor;
private boolean _poisVisible;
private BooleanProperty poisVisible;
private boolean _poiTextVisible;
private BooleanProperty poiTextVisible;
private ObservableList pois;
private List heatmapSpots;
private BooleanBinding showing;
private ListChangeListener poiListChangeListener;
// internal event handlers
protected EventHandler _mouseEnterHandler;
protected EventHandler _mousePressHandler;
protected EventHandler _mouseReleaseHandler;
protected EventHandler _mouseExitHandler;
// exposed event handlers
private EventHandler mouseEnterHandler;
private EventHandler mousePressHandler;
private EventHandler mouseReleaseHandler;
private EventHandler mouseExitHandler;
// ******************** Constructors **************************************
public WorldPane() {
this._fill = Constants.FILL;
this._stroke = Constants.STROKE;
this._lineWidth = 1;
this._poiFill = Constants.POI_FILL;
this._poiStroke = Color.TRANSPARENT;
this._poisVisible = false;
this._poiTextVisible = false;
this._poiTextFill = Constants.TEXT_FILL;
this._hoverEnabled = false;
this._selectionEnabled = false;
this._selectedCountry = null;
this.formerSelectedCountry = null;
this._hoverColor = Color.web("#3b5b6b");
this._pressedColor = Color.DARKBLUE;
this._selectedColor = Color.web("#28596f");
this.pois = FXCollections.observableArrayList();
this.heatmapSpots = new ArrayList<>();
this.poiListChangeListener = c -> {
while (c.next()) {
if (c.wasAdded()) {
} else if (c.wasRemoved()) {
}
}
redraw();
};
this._mouseEnterHandler = evt -> handleMouseEvent(evt, mouseEnterHandler);
this._mousePressHandler = evt -> handleMouseEvent(evt, mousePressHandler);
this._mouseReleaseHandler = evt -> handleMouseEvent(evt, mouseReleaseHandler);
this._mouseExitHandler = evt -> handleMouseEvent(evt, mouseExitHandler);
initGraphics();
registerListeners();
}
// ******************** Initialization ************************************
private void initGraphics() {
if (Double.compare(getPrefWidth(), 0.0) <= 0 || Double.compare(getPrefHeight(), 0.0) <= 0 || Double.compare(getWidth(), 0.0) <= 0 || Double.compare(getHeight(), 0.0) <= 0) {
if (getPrefWidth() > 0 && getPrefHeight() > 0) {
setPrefSize(getPrefWidth(), getPrefHeight());
} else {
setPrefSize(PREFERRED_WIDTH, PREFERRED_HEIGHT);
}
}
heatmap = HeatMapBuilder.create()
.prefSize(PREFERRED_WIDTH, PREFERRED_HEIGHT)
.colorMapping(ColorMapping.INFRARED_4)
.spotRadius(5)
.fadeColors(true)
.opacityDistribution(OpacityDistribution.LINEAR)
.heatMapOpacity(0.75)
.build();
heatmap.setMouseTransparent(true);
heatmap.setVisible(false);
heatmap.setManaged(false);
canvas = new Canvas(PREFERRED_WIDTH, PREFERRED_HEIGHT);
ctx = canvas.getGraphicsContext2D();
canvas.setMouseTransparent(true);
COUNTRY_PATHS.entrySet().forEach(entry -> {
Country country = entry.getKey();
entry.getValue().forEach(path -> {
path.setFill(null == country.getFill() ? getFill() : country.getFill());
path.setStroke(null == country.getStroke() ? getStroke() : country.getStroke());
path.setStrokeWidth(getLineWidth());
path.setStrokeLineCap(StrokeLineCap.ROUND);
path.setStrokeLineJoin(StrokeLineJoin.ROUND);
path.setOnMouseEntered(new WeakEventHandler<>(_mouseEnterHandler));
path.setOnMousePressed(new WeakEventHandler<>(_mousePressHandler));
path.setOnMouseReleased(new WeakEventHandler<>(_mouseReleaseHandler));
path.setOnMouseExited(new WeakEventHandler<>(_mouseExitHandler));
});
});
group = new Group();
COUNTRY_PATHS.entrySet().forEach(entry -> group.getChildren().addAll(entry.getValue()));
pane = new Pane(group);
setBackground(Constants.BACKGROUND);
getChildren().setAll(pane, canvas, heatmap);
}
private void registerListeners() {
widthProperty().addListener(o -> resize());
heightProperty().addListener(o -> resize());
pois.addListener(poiListChangeListener);
if (null != getScene()) {
setupBinding();
} else {
sceneProperty().addListener((o1, ov1, nv1) -> {
if (null == nv1) { return; }
if (null != getScene().getWindow()) {
setupBinding();
} else {
sceneProperty().get().windowProperty().addListener((o2, ov2, nv2) -> {
if (null == nv2) { return; }
setupBinding();
});
}
});
}
}
private void setupBinding() {
showing = Bindings.createBooleanBinding(() -> {
if (getScene() != null && getScene().getWindow() != null) {
return getScene().getWindow().isShowing();
} else {
return false;
}
}, sceneProperty(), getScene().windowProperty(), getScene().getWindow().showingProperty());
showing.addListener(o -> {
if (showing.get()) {
resize();
List scaledSpots = new ArrayList<>();
heatmapSpots.forEach(spot -> {
final Point p = Helper.latLonToXY(spot);
final double x = p.getX() * scaleX;
final double y = p.getY() * scaleY;
scaledSpots.add(new Point(x, y));
});
heatmap.setSpots(scaledSpots);
}
});
}
// ******************** Methods *******************************************
@Override protected double computeMinWidth(final double height) { return MINIMUM_WIDTH; }
@Override protected double computeMinHeight(final double width) { return MINIMUM_HEIGHT; }
@Override protected double computePrefWidth(final double height) { return super.computePrefWidth(height); }
@Override protected double computePrefHeight(final double width) { return super.computePrefHeight(width); }
@Override protected double computeMaxWidth(final double height) { return MAXIMUM_WIDTH; }
@Override protected double computeMaxHeight(final double width) { return MAXIMUM_HEIGHT; }
@Override public ObservableList getChildren() { return super.getChildren(); }
public void setBackground(final Paint paint) {
setBackground(new Background(new BackgroundFill(paint, CornerRadii.EMPTY, Insets.EMPTY)));
}
public Color getFill() { return null == fill ? _fill : fill.get(); }
public void setFill(final Color fill) {
if (null == this.fill) {
_fill = fill;
COUNTRY_PATHS.entrySet().forEach(entry -> entry.getValue().forEach(countryPath -> countryPath.setFill(null == entry.getKey().getFill() ? fill : entry.getKey().getFill())));
} else {
this.fill.set(fill);
}
}
public ObjectProperty fillProperty() {
if (null == fill) {
fill = new ObjectPropertyBase<>(_fill) {
@Override protected void invalidated() {
COUNTRY_PATHS.entrySet().forEach(entry -> entry.getValue().forEach(countryPath -> countryPath.setFill(null == entry.getKey().getFill() ? get() : entry.getKey().getFill())));
}
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "fill"; }
};
_fill = null;
}
return fill;
}
public Color getStroke() { return null == stroke ? _stroke : stroke.get(); }
public void setStroke(final Color stroke) {
if (null == this.stroke) {
_stroke = stroke;
COUNTRY_PATHS.entrySet().forEach(entry -> entry.getValue().forEach(countryPath -> countryPath.setStroke(null == entry.getKey().getStroke() ? stroke : entry.getKey().getStroke())));
} else {
this.stroke.set(stroke);
}
}
public ObjectProperty strokeProperty() {
if (null == stroke) {
stroke = new ObjectPropertyBase<>(_stroke) {
@Override protected void invalidated() {
COUNTRY_PATHS.entrySet().forEach(entry -> entry.getValue().forEach(countryPath -> countryPath.setStroke(null == entry.getKey().getStroke() ? get() : entry.getKey().getStroke())));
}
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "stroke"; }
};
_stroke = null;
}
return stroke;
}
public double getLineWidth() { return null == lineWidth ? _lineWidth : lineWidth.get(); }
public void setLineWidth(final double lineWidth) {
if (null == this.lineWidth) {
_lineWidth = lineWidth;
COUNTRY_PATHS.entrySet().forEach(entry -> entry.getValue().forEach(countryPath -> countryPath.setStrokeWidth(lineWidth)));
} else {
this.lineWidth.set(lineWidth);
}
}
public DoubleProperty lineWidthProperty() {
if (null == lineWidth) {
lineWidth = new DoublePropertyBase(_lineWidth) {
@Override protected void invalidated() {
COUNTRY_PATHS.entrySet().forEach(entry -> entry.getValue().forEach(countryPath -> countryPath.setStrokeWidth(get())));
}
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "lineWidth"; }
};
}
return lineWidth;
}
public Color getPoiFill() { return null == poiFill ? _poiFill : poiFill.get(); }
public void setPoiFill(final Color poiFill) {
if (null == this.poiFill) {
_poiFill = poiFill;
redraw();
} else {
this.poiFill.set(poiFill);
}
}
public ObjectProperty poiFillProperty() {
if (null == poiFill) {
poiFill = new ObjectPropertyBase<>(_poiFill) {
@Override protected void invalidated() { redraw(); }
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "poiFill"; }
};
_poiFill = null;
}
return poiFill;
}
public Color getPoiStroke() { return null == poiStroke ? _poiStroke : poiStroke.get(); }
public void setPoiStroke(final Color poiStroke) {
if (null == this.poiStroke) {
_poiStroke = poiStroke;
redraw();
} else {
this.poiStroke.set(poiStroke);
}
}
public ObjectProperty poiStrokeProperty() {
if (null == poiStroke) {
poiStroke = new ObjectPropertyBase<>(_poiStroke) {
@Override protected void invalidated() { redraw(); }
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "poiStroke"; }
};
_poiStroke = null;
}
return poiStroke;
}
public boolean getPoisVisible() { return null == poisVisible ? _poisVisible : poisVisible.get(); }
public void setPoisVisible(final boolean poisVisible) {
if (null == this.poisVisible) {
_poisVisible = poisVisible;
redraw();
} else {
this.poisVisible.set(poisVisible);
}
}
public BooleanProperty poisVisibleProperty() {
if (null == poisVisible) {
poisVisible = new BooleanPropertyBase(_poisVisible) {
@Override protected void invalidated() { redraw(); }
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "poisVisible"; }
};
}
return poisVisible;
}
public boolean getPoiTextVisible() { return null == poiTextVisible ? _poiTextVisible : poiTextVisible.get(); }
public void setPoiTextVisible(final boolean poiTextVisible) {
if (null == this.poiTextVisible) {
_poiTextVisible = poiTextVisible;
redraw();
} else {
this.poiTextVisible.set(poiTextVisible);
}
}
public BooleanProperty poiTextVisibleProperty() {
if (null == poiTextVisible) {
poiTextVisible = new BooleanPropertyBase(_poiTextVisible) {
@Override protected void invalidated() { redraw(); }
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "poiTextVisible"; }
};
}
return poiTextVisible;
}
public Color getPoiTextFill() { return null == poiTextFill ? _poiTextFill : poiTextFill.get(); }
public void setPoiTextFill(final Color poiTextFill) {
if (null == this.poiTextFill) {
_poiTextFill = poiTextFill;
redraw();
} else {
this.poiTextFill.set(poiTextFill);
}
}
public ObjectProperty poiTextFillProperty() {
if (null == poiTextFill) {
poiTextFill = new ObjectPropertyBase<>(_poiTextFill) {
@Override protected void invalidated() { redraw(); }
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "poiTextFill"; }
};
_poiTextFill = null;
}
return poiTextFill;
}
public List getPois() { return Collections.unmodifiableList(pois); }
public void addPoi(final Poi poi) {
if (!pois.contains(poi)) { pois.add(poi); }
}
public void removePoi(final Poi poi) {
if (pois.contains(poi)) { pois.remove(poi); }
}
public void addPois(final List pois) {
this.pois.removeListener(poiListChangeListener);
pois.forEach(poi -> addPoi(poi));
this.pois.addListener(poiListChangeListener);
redraw();
}
public void removePois(final List pois) {
this.pois.removeListener(poiListChangeListener);
pois.forEach(poi -> removePoi(poi));
this.pois.addListener(poiListChangeListener);
redraw();
}
public boolean isShowing() { return null != showing && showing.get(); }
public BooleanBinding showingProperty() { return showing; }
// ******************** Interaction ***************************************
public boolean isHoverEnabled() { return null == hoverEnabled ? _hoverEnabled : hoverEnabled.get(); }
public void setHoverEnabled(final boolean hoverEnabled) {
if (null == this.hoverEnabled) {
_hoverEnabled = hoverEnabled;
} else {
this.hoverEnabled.set(hoverEnabled);
}
}
public BooleanProperty hoverEnabledProperty() {
if (null == hoverEnabled) {
hoverEnabled = new BooleanPropertyBase(_hoverEnabled) {
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "hoverEnabled"; }
};
}
return hoverEnabled;
}
public boolean isSelectionEnabled() { return null == selectionEnabled ? _selectionEnabled : selectionEnabled.get(); }
public void setSelectionEnabled(final boolean selectionEnabled) {
if (null == this.selectionEnabled) {
_selectionEnabled = selectionEnabled;
} else {
this.selectionEnabled.set(selectionEnabled);
}
}
public BooleanProperty selectionEnabledProperty() {
if (null == selectionEnabled) {
selectionEnabled = new BooleanPropertyBase() {
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "selectionEnabled"; }
};
}
return selectionEnabled;
}
public Country getSelectedCountry() { return null == selectedCountry ? _selectedCountry : selectedCountry.get(); }
public void setSelectedCountry(final Country selectedCountry) {
if (null == this.selectedCountry) {
_selectedCountry = selectedCountry;
} else {
this.selectedCountry.set(selectedCountry);
}
}
public ObjectProperty selectedCountryProperty() {
if (null == selectedCountry) {
selectedCountry = new ObjectPropertyBase<>(_selectedCountry) {
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "selectedCountry"; }
};
_selectedCountry = null;
}
return selectedCountry;
}
public Color getHoverColor() { return null == hoverColor ? _hoverColor : hoverColor.getValue(); }
public void setHoverColor(final Color hoverColor) {
if (null == this.hoverColor) {
_hoverColor = hoverColor;
} else {
this.hoverColor.setValue(hoverColor);
}
}
public ObjectProperty hoverColorProperty() {
if (null == hoverColor) {
hoverColor = new ObjectPropertyBase<>(_hoverColor) {
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "hoverColor"; }
};
_hoverColor = null;
}
return hoverColor;
}
public Color getPressedColor() { return null == pressedColor ? _pressedColor : pressedColor.getValue(); }
public void setPressedColor(final Color pressedColor) {
if (null == this.pressedColor) {
_pressedColor = pressedColor;
} else {
this.pressedColor.setValue(pressedColor);
}
}
public ObjectProperty pressedColorProperty() {
if (null == pressedColor) {
pressedColor = new ObjectPropertyBase<>(_pressedColor) {
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "pressedColor"; }
};
_pressedColor = null;
}
return pressedColor;
}
public Color getSelectedColor() { return null == selectedColor ? _selectedColor : selectedColor.getValue(); }
public void setSelectedColor(final Color selectedColor) {
if (null == this.selectedColor) {
_selectedColor = selectedColor;
} else {
this.selectedColor.setValue(selectedColor);
}
}
public ObjectProperty selectedColorProperty() {
if (null == selectedColor) {
selectedColor = new ObjectPropertyBase<>(_selectedColor) {
@Override public Object getBean() { return WorldPane.this; }
@Override public String getName() { return "selectedColor"; }
};
_selectedColor = null;
}
return selectedColor;
}
public void setMouseEnterHandler(final EventHandler handler) { mouseEnterHandler = handler; }
public void setMousePressHandler(final EventHandler handler) { mousePressHandler = handler; }
public void setMouseReleaseHandler(final EventHandler handler) { mouseReleaseHandler = handler; }
public void setMouseExitHandler(final EventHandler handler) { mouseExitHandler = handler; }
// ******************** Heatmap related ***********************************
public boolean isHeatmapVisible() { return heatmap.isVisible(); }
public void setHeatmapVisible(final boolean heatmapVisible) {
heatmap.setManaged(heatmapVisible);
heatmap.setVisible(heatmapVisible);
}
public Mapping getHeatmapColorMapping() { return heatmap.getColorMapping(); }
public void setHeatmapColorMapping(final Mapping colorMapping) { heatmap.setColorMapping(colorMapping); }
public double getHeatmapSpotRadius() { return heatmap.getSpotRadius(); }
public void setHeatmapSpotRadius(final double spotRadius) { heatmap.setSpotRadius(spotRadius); }
public boolean isHeatmapFadeColors() { return heatmap.isFadeColors(); }
public void setHeatmapFadeColors(final boolean fadeColors) { heatmap.setFadeColors(fadeColors); }
public OpacityDistribution getHeatmapOpacityDistribution() { return heatmap.getOpacityDistribution(); }
public void setHeatmapOpacityDistribution(final OpacityDistribution opacityDistribution) { heatmap.setOpacityDistribution(opacityDistribution); }
public double getHeatmapOpacity() { return heatmap.getOpacity(); }
public void setHeatmapOpacity(final double opacity) { heatmap.setOpacity(opacity); }
public List getHeatmapSpots() { return heatmapSpots; }
public void setHeatmapSpots(final List spots) {
heatmapSpots.clear();
heatmapSpots.addAll(spots);
Platform.runLater(() -> {
List scaledSpots = new ArrayList<>();
heatmapSpots.forEach(spot -> {
final Point p = Helper.latLonToXY(spot);
final double x = p.getX() * scaleX;
final double y = p.getY() * scaleY;
scaledSpots.add(new Point(x, y));
});
heatmap.setSpots(scaledSpots);
});
redraw();
}
public void addHeatmapSpot(final Point spot) {
if (heatmapSpots.contains(spot)) { return; }
heatmapSpots.add(spot);
Platform.runLater(() -> {
final Point p = Helper.latLonToXY(spot);
final double x = p.getX() * scaleX;
final double y = p.getY() * scaleY;
heatmap.addSpot(x, y);
});
redraw();
}
public void clearHeatmap() {
heatmapSpots.clear();
heatmap.clearHeatMap();
}
// ******************** EventHandling *************************************
private void handleMouseEvent(final MouseEvent event, final EventHandler handler) {
final CountryPath countryPath = (CountryPath) event.getSource();
final String countryName = countryPath.getName();
final Country country = Country.valueOf(countryName);
final List paths = COUNTRY_PATHS.get(country);
final EventType type = event.getEventType();
if (MOUSE_ENTERED == type) {
if (isHoverEnabled()) {
Color color = isSelectionEnabled() && country.equals(getSelectedCountry()) ? getSelectedColor() : getHoverColor();
for (SVGPath path : paths) { path.setFill(color); }
}
} else if (MOUSE_PRESSED == type) {
if (isSelectionEnabled()) {
Color color;
if (null == getSelectedCountry()) {
setSelectedCountry(country);
color = getSelectedColor();
} else {
color = null == getSelectedCountry().getFill() ? getFill() : getSelectedCountry().getFill();
}
for (SVGPath path : COUNTRY_PATHS.get(getSelectedCountry())) { path.setFill(color); }
} else {
if (isHoverEnabled()) {
for (SVGPath path : paths) { path.setFill(getPressedColor()); }
}
}
} else if (MOUSE_RELEASED == type) {
Color color;
if (isSelectionEnabled()) {
if (formerSelectedCountry == country) {
setSelectedCountry(null);
color = null == country.getFill() ? getFill() : country.getFill();
} else {
setSelectedCountry(country);
color = getSelectedColor();
}
formerSelectedCountry = getSelectedCountry();
} else {
color = getHoverColor();
}
if (isHoverEnabled()) {
for (SVGPath path : paths) { path.setFill(color); }
}
} else if (MOUSE_EXITED == type) {
if (isHoverEnabled()) {
Color color = isSelectionEnabled() && country.equals(getSelectedCountry()) ? getSelectedColor() : getFill();
for (SVGPath path : paths) {
path.setFill(null == country.getFill() || country == getSelectedCountry() ? color : country.getFill());
}
}
}
if (null != handler) handler.handle(event);
}
// ******************** Layout *******************************************
@Override public void layoutChildren() {
super.layoutChildren();
}
private void resize() {
width = getWidth()- getInsets().getLeft() - getInsets().getRight();
height = getHeight() - getInsets().getTop() - getInsets().getBottom();
size = width < height ? width : height;
if (Constants.ASPECT_RATIO * width > height) {
width = 1 / (Constants.ASPECT_RATIO / height);
} else if (1 / (Constants.ASPECT_RATIO / height) > width) {
height = Constants.ASPECT_RATIO * width;
}
if (width > 0 && height > 0) {
scaleX = width / pane.getWidth();
scaleY = height / pane.getHeight();
double scaledLineWidth = getLineWidth() / scaleX;
double relocateX = (getWidth() - pane.getWidth()) * 0.5;
double relocateY = (getHeight() - pane.getHeight()) * 0.5;
pane.setCache(true);
pane.setCacheHint(CacheHint.SCALE);
pane.setScaleX(scaleX);
pane.setScaleY(scaleY);
pane.setCache(false);
COUNTRY_PATHS.entrySet().forEach(entry -> {
entry.getValue().forEach(path -> path.setStrokeWidth(scaledLineWidth));
});
pane.relocate(relocateX, relocateY);
canvas.setWidth(pane.getWidth() * scaleX);
canvas.setHeight(pane.getHeight() * scaleY);
canvas.relocate((getWidth() - canvas.getWidth()) * 0.5, (getHeight() - canvas.getHeight()) * 0.5);
heatmap.setFitWidth(pane.getWidth() * scaleX);
heatmap.setFitHeight(pane.getHeight() * scaleY);
heatmap.relocate((getWidth() - canvas.getWidth()) * 0.5, (getHeight() - canvas.getHeight()) * 0.5);
redraw();
}
}
private void redraw() {
double width = canvas.getWidth();
double height = canvas.getHeight();
double fontsize = size * 0.0125;
ctx.clearRect(0, 0, width, height);
ctx.setFont(Fonts.opensansLight(fontsize));
ctx.setTextBaseline(VPos.CENTER);
ctx.setTextAlign(TextAlignment.CENTER);
// Draw pois
if (getPoisVisible()) {
Map points = new HashMap<>();
pois.forEach(poi -> {
ctx.setFill(null == poi.getFill() ? getPoiFill() : poi.getFill());
ctx.setStroke(null == poi.getStroke() ? getPoiStroke() : poi.getStroke());
final Point p = Helper.latLonToXY(poi.getLonLat());
final double x = p.getX() * scaleX;
final double y = p.getY() * scaleY;
if (null == poi.getImage() && null == poi.getSvgPath()) {
final double r;
final double d;
switch (poi.getPointSize()) {
case TINY -> { r = 0.5; d = 1; }
case SMALL -> { r = 1; d = 2; }
case NORMAL -> { r = 1.5; d = 3; }
case BIG -> { r = 2.5; d = 5; }
case HUGE -> { r = 5; d = 10; }
default -> { r = 1; d = 2; }
}
if (d >= 1) {
ctx.fillOval(x - r, y - r, d, d);
}
} else {
if (null != poi.getImage()) {
Image img = poi.getImage();
ctx.drawImage(img, x - img.getWidth() * 0.5, y - img.getHeight() * 0.5, img.getWidth(), img.getHeight());
}
if (null != poi.getSvgPath() && null != poi.getSvgPathDim()) {
ctx.save();
ctx.translate(x - poi.getSvgPathDim().getWidth() * 0.5, y - poi.getSvgPathDim().getHeight() * 0.5);
ctx.beginPath();
ctx.appendSVGPath(poi.getSvgPath());
ctx.closePath();
ctx.setFill(Color.LIME);
ctx.fill();
ctx.stroke();
ctx.restore();
}
}
points.put(poi, new Point(x, y));
});
if (getPoiTextVisible() && fontsize > 6) {
ctx.setFill(getPoiTextFill());
points.entrySet().forEach(entry -> {
ctx.fillText(entry.getKey().getName(), entry.getValue().getX(), entry.getValue().getY() - fontsize);
});
}
}
}
}