/* * SPDX-License-Identifier: Apache-2.0 * * Copyright 2016-2020 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 * * https://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.Tile; import eu.hansolo.tilesfx.Tile.MapProvider; import eu.hansolo.tilesfx.events.LocationEventListener; import eu.hansolo.tilesfx.fonts.Fonts; import eu.hansolo.tilesfx.tools.Helper; import eu.hansolo.tilesfx.tools.Location; import javafx.application.Platform; import javafx.collections.ListChangeListener; import javafx.concurrent.Worker; import javafx.event.EventHandler; import javafx.scene.input.MouseEvent; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; import java.net.URL; import java.time.format.DateTimeFormatter; import java.util.List; /** * Created by hansolo on 12.02.17. */ public class MapTileSkin extends TileSkin { private static final DateTimeFormatter DF = DateTimeFormatter.ISO_LOCAL_DATE; private static final DateTimeFormatter TF = DateTimeFormatter.ISO_LOCAL_TIME; private Text titleText; private Text text; private WebView webView; private WebEngine webEngine; private boolean readyToGo; private EventHandler<MouseEvent> mouseHandler; private LocationEventListener locationListener; private ListChangeListener<Location> poiListener; // ******************** Constructors ************************************** public MapTileSkin(final Tile TILE) { super(TILE); } // ******************** Initialization ************************************ @Override protected void initGraphics() { super.initGraphics(); mouseHandler = event -> { if (event.getClickCount() == 2) { centerLocation(); } }; locationListener = e -> redraw(); poiListener = c -> { while (c.next()) { if (c.wasPermutated()) { // Get items that have been permutated in list for (int i = c.getFrom(); i < c.getTo(); ++i) { updatePoi(tile.getPoiList().get(i)); } } else if (c.wasUpdated()) { // Get items that have been updated in list for (int i = c.getFrom(); i < c.getTo(); ++i) { updatePoi(tile.getPoiList().get(i)); } } else if (c.wasAdded()) { c.getAddedSubList().forEach(poi -> addPoi(poi)); } else if (c.wasRemoved()) { c.getRemoved().forEach(poi -> removePoi(poi)); } } }; titleText = new Text(); titleText.setFill(tile.getTitleColor()); Helper.enableNode(titleText, !tile.getTitle().isEmpty()); text = new Text(tile.getText()); text.setFill(tile.getTextColor()); Helper.enableNode(text, tile.isTextVisible()); webView = new WebView(); webView.setMinSize(size * 0.9, tile.isTextVisible() ? size * 0.72 : size * 0.795); webView.setMaxSize(size * 0.9, tile.isTextVisible() ? size * 0.72 : size * 0.795); webView.setPrefSize(size * 0.9, tile.isTextVisible() ? size * 0.72 : size * 0.795); webEngine = webView.getEngine(); webEngine.getLoadWorker().stateProperty().addListener((ov, o, n) -> { if (Worker.State.SUCCEEDED == n) { readyToGo = true; if (MapProvider.BW != tile.getMapProvider()) { changeMapProvider(tile.getMapProvider()); } updateLocation(); updateLocationColor(); tile.getPoiList().forEach(poi -> addPoi(poi)); addTrack(tile.getTrack()); updateTrackColor(); } }); URL maps = Tile.class.getResource("osm.html"); webEngine.load(maps.toExternalForm()); getPane().getChildren().addAll(titleText, webView, text); } @Override protected void registerListeners() { super.registerListeners(); pane.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseHandler); tile.getPoiList().addListener(poiListener); } // ******************** 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()); webView.setMaxSize(size * 0.9, tile.isTextVisible() ? size * 0.68 : size * 0.795); webView.setPrefSize(size * 0.9, tile.isTextVisible() ? size * 0.68 : size * 0.795); } else if ("LOCATION".equals(EVENT_TYPE)) { tile.getCurrentLocation().addLocationEventListener(locationListener); updateLocation(); } else if ("TRACK".equals(EVENT_TYPE)) { addTrack(tile.getTrack()); } else if ("MAP_PROVIDER".equals(EVENT_TYPE)) { changeMapProvider(tile.getMapProvider()); } } @Override public void dispose() { pane.removeEventHandler(MouseEvent.MOUSE_CLICKED, mouseHandler); tile.getCurrentLocation().removeLocationEventListener(locationListener); tile.getPoiList().removeListener(poiListener); super.dispose(); } private void updateLocation() { if (readyToGo) { Platform.runLater(() -> { Location location = tile.getCurrentLocation(); double lat = location.getLatitude(); double lon = location.getLongitude(); String name = location.getName(); String info = location.getInfo(); int zoomLevel = location.getZoomLevel(); StringBuilder scriptCommand = new StringBuilder(); scriptCommand.append("window.lat = ").append(lat).append(";") .append("window.lon = ").append(lon).append(";") .append("window.locationName = \"").append(name).append("\";") .append("window.locationInfo = \"").append(info.toString()).append("\";") .append("window.zoomLevel = ").append(zoomLevel).append(";") .append("document.moveMarker(window.locationName, window.locationInfo, window.lat, window.lon, window.zoomLevel);"); webEngine.executeScript(scriptCommand.toString()); }); } } private void updatePoi(final Location POI) { removePoi(POI); addPoi(POI); } private void addPoi(final Location POI) { if (readyToGo) { Platform.runLater(() -> { double lat = POI.getLatitude(); double lon = POI.getLongitude(); String name = POI.getName(); String info = POI.getInfo(); String color = POI.getColor().toString().replace("0x", "#"); StringBuilder scriptCommand = new StringBuilder(); scriptCommand.append("window.lat = ").append(lat).append(";") .append("window.lon = ").append(lon).append(";") .append("window.locationName = \"").append(name).append("\";") .append("window.locationInfo = \"").append(info.toString()).append("\";") .append("window.poiColor = \"").append(color).append("\";") .append("document.addPoi(window.locationName, window.locationInfo, window.lat, window.lon, window.poiColor);"); webEngine.executeScript(scriptCommand.toString()); }); } } private void removePoi(final Location POI) { if (readyToGo) { Platform.runLater(() -> { String name = POI.getName(); StringBuilder scriptCommand = new StringBuilder(); scriptCommand.append("window.locationName = \"").append(name).append("\";") .append("document.removePoi(window.locationName);"); webEngine.executeScript(scriptCommand.toString()); }); } } private void updateLocationColor() { if (readyToGo) { Platform.runLater(() -> { String locationColor = tile.getCurrentLocation().getColor().toString().replace("0x", "#"); StringBuilder scriptCommand = new StringBuilder(); scriptCommand.append("window.locationColor = '").append(locationColor).append("';") .append("document.setLocationColor(window.locationColor);"); webEngine.executeScript(scriptCommand.toString()); }); } } private void updateTrackColor() { if (readyToGo) { Platform.runLater(() -> { String trackColor = tile.getTrackColor().styleName; StringBuilder scriptCommand = new StringBuilder(); scriptCommand.append("window.trackColor = '").append(trackColor).append("';") .append("document.setTrackColor(window.trackColor);"); webEngine.executeScript(scriptCommand.toString()); }); } } private void centerLocation() { if (readyToGo) { Platform.runLater(() -> { StringBuilder scriptCommand = new StringBuilder(); scriptCommand.append("window.zoomLevel = ").append(tile.getCurrentLocation().getZoomLevel()).append(";"); scriptCommand.append("document.zoomToLocation(window.zoomLevel);"); webEngine.executeScript(scriptCommand.toString()); }); } } private void addTrack(final List<Location> LOCATIONS) { if (LOCATIONS.isEmpty()) { if (readyToGo) { Platform.runLater(() -> { StringBuilder scriptCommand = new StringBuilder(); scriptCommand.append("document.clearTrack();"); webEngine.executeScript(scriptCommand.toString()); }); return; } } int length = LOCATIONS.size(); if (length <= 4) return; if (readyToGo) { Platform.runLater(() -> { StringBuilder scriptCommand = new StringBuilder(); double lat1; double lon1; double lat2; double lon2; String name; String date; String time; String trackColor = tile.getTrackColor().styleName; for (int i = 0 ; i < length - 1 ; i++) { scriptCommand.setLength(0); lat1 = LOCATIONS.get(i).getLatitude(); lon1 = LOCATIONS.get(i).getLongitude(); lat2 = LOCATIONS.get(i + 1).getLatitude(); lon2 = LOCATIONS.get(i + 1).getLongitude(); name = LOCATIONS.get(i).getName(); date = DF.format(LOCATIONS.get(i).getZonedDateTime()); time = TF.format(LOCATIONS.get(i).getZonedDateTime()); scriptCommand.append("window.lat1 = ").append(lat1).append(";") .append("window.lon1 = ").append(lon1).append(";") .append("window.lat2 = ").append(lat2).append(";") .append("window.lon2 = ").append(lon2).append(";") .append("window.locationName = \"").append(name).append("\";") .append("window.locationDate = \"").append(date).append("\";") .append("window.locationTime = \"").append(time).append("\";") .append("window.trackColor = \"").append(trackColor).append("\";") .append("document.addToTrack(window.lat1, window.lon1, window.lat2, window.lon2,window.locationName, window.locationDate, window.locationTime, window.trackColor);"); webEngine.executeScript(scriptCommand.toString()); } // Start Marker scriptCommand.setLength(0); lat1 = LOCATIONS.get(0).getLatitude(); lon1 = LOCATIONS.get(0).getLongitude(); name = LOCATIONS.get(0).getName(); date = DF.format(LOCATIONS.get(0).getZonedDateTime()); time = TF.format(LOCATIONS.get(0).getZonedDateTime()); scriptCommand.append("window.lat1 = ").append(lat1).append(";") .append("window.lon1 = ").append(lon1).append(";") .append("window.locationName = \"").append(name).append("\";") .append("window.locationDate = \"").append(date).append("\";") .append("window.locationTime = \"").append(time).append("\";") .append("document.addStartPoiMarker(window.lat1, window.lon1, window.locationName, window.locationDate, window.locationTime);"); webEngine.executeScript(scriptCommand.toString()); // Stop Marker scriptCommand.setLength(0); lat1 = LOCATIONS.get(length - 1).getLatitude(); lon1 = LOCATIONS.get(length - 1).getLongitude(); name = LOCATIONS.get(length - 1).getName(); date = DF.format(LOCATIONS.get(length - 1).getZonedDateTime()); time = TF.format(LOCATIONS.get(length - 1).getZonedDateTime()); scriptCommand.append("window.lat1 = ").append(lat1).append(";") .append("window.lon1 = ").append(lon1).append(";") .append("window.locationName = \"").append(name).append("\";") .append("window.locationDate = \"").append(date).append("\";") .append("window.locationTime = \"").append(time).append("\";") .append("document.addStopPoiMarker(window.lat1, window.lon1, window.locationName, window.locationDate, window.locationTime);"); webEngine.executeScript(scriptCommand.toString()); }); } } private void changeMapProvider(final MapProvider PROVIDER) { if (readyToGo) { Platform.runLater(() -> { StringBuilder scriptCommand = new StringBuilder(); scriptCommand.append("window.provider = '").append(PROVIDER.name).append("';") .append("document.changeMapProvider(window.provider);"); webEngine.executeScript(scriptCommand.toString()); }); } } // ******************** Resizing ****************************************** @Override protected void resizeStaticText() { double maxWidth = width - size * 0.1; double fontSize = size * textSize.factor; boolean customFontEnabled = tile.isCustomFontEnabled(); Font customFont = tile.getCustomFont(); Font font = (customFontEnabled && customFont != null) ? Font.font(customFont.getFamily(), fontSize) : Fonts.latoRegular(fontSize); titleText.setFont(font); 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; } text.setFont(font); 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 (tile.isShowing() && width > 0 && height > 0) { pane.setMaxSize(width, height); pane.setPrefSize(width, height); if (containerWidth > 0 && containerHeight > 0) { webView.setMinSize(containerWidth, containerHeight); webView.setMaxSize(containerWidth, containerHeight); webView.setPrefSize(containerWidth, containerHeight); webView.relocate(contentBounds.getX(), contentBounds.getY()); } resizeStaticText(); } } @Override protected void redraw() { super.redraw(); titleText.setText(tile.getTitle()); text.setText(tile.getText()); resizeStaticText(); titleText.setFill(tile.getTitleColor()); text.setFill(tile.getTextColor()); updateLocationColor(); updateTrackColor(); } }