View Javadoc
1   /*
2    * Copyright (c) 2011-2024 PrimeFaces Extensions
3    *
4    *  Permission is hereby granted, free of charge, to any person obtaining a copy
5    *  of this software and associated documentation files (the "Software"), to deal
6    *  in the Software without restriction, including without limitation the rights
7    *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    *  copies of the Software, and to permit persons to whom the Software is
9    *  furnished to do so, subject to the following conditions:
10   *
11   *  The above copyright notice and this permission notice shall be included in
12   *  all copies or substantial portions of the Software.
13   *
14   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20   *  THE SOFTWARE.
21   */
22  package org.primefaces.extensions.component.osmap;
23  
24  import java.io.IOException;
25  import java.util.Iterator;
26  import java.util.List;
27  
28  import javax.faces.FacesException;
29  import javax.faces.component.UIComponent;
30  import javax.faces.context.FacesContext;
31  import javax.faces.context.ResponseWriter;
32  
33  import org.primefaces.model.map.*;
34  import org.primefaces.renderkit.CoreRenderer;
35  import org.primefaces.util.WidgetBuilder;
36  
37  public class OSMapRenderer extends CoreRenderer {
38  
39      @Override
40      public void decode(FacesContext context, UIComponent component) {
41          decodeBehaviors(context, component);
42      }
43  
44      @Override
45      public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
46          OSMap map = (OSMap) component;
47  
48          encodeMarkup(facesContext, map);
49          encodeScript(facesContext, map);
50      }
51  
52      protected void encodeMarkup(FacesContext context, OSMap map) throws IOException {
53          ResponseWriter writer = context.getResponseWriter();
54          String clientId = map.getClientId(context);
55  
56          writer.startElement("div", map);
57          writer.writeAttribute("id", clientId + "_map", null);
58          if (map.getStyle() != null) {
59              writer.writeAttribute("style", map.getStyle(), null);
60          }
61          if (map.getStyleClass() != null) {
62              writer.writeAttribute("class", map.getStyleClass(), null);
63          }
64  
65          writer.endElement("div");
66      }
67  
68      protected void encodeScript(FacesContext context, OSMap map) throws IOException {
69  
70          String[] parts = map.getCenter().split(",");
71  
72          WidgetBuilder wb = getWidgetBuilder(context);
73          wb.init("OSMap", map);
74          wb.attr("center", map.getCenter());
75          wb.nativeAttr("map",
76                      "L.map('" + map.getClientId() + "_map', { dragging: " + map.isDraggable() + ", zoomControl: " + map.isZoomControl() + ", scrollWheelZoom: "
77                                  + map.isScrollWheel() + " } ).setView(['"
78                                  + parts[0].trim() + "', '"
79                                  + parts[1].trim() + "'], " + map.getZoom() + ")");
80  
81          String tileUrl = "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
82          String attribution = "&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a>";
83  
84          if (map.getTileUrl() != null) {
85              tileUrl = map.getTileUrl();
86          }
87  
88          if (map.getAttribution() != null) {
89              attribution = map.getAttribution();
90          }
91  
92          wb.nativeAttr("tile", "L.tileLayer('" + tileUrl + "', { attribution: '" + attribution + "' })");
93  
94          encodeOverlays(context, map);
95  
96          // Client events
97          if (map.getOnPointClick() != null) {
98              wb.callback("onPointClick", "function(event)", map.getOnPointClick() + ";");
99          }
100 
101         encodeClientBehaviors(context, map);
102 
103         wb.finish();
104     }
105 
106     protected void encodeOverlays(FacesContext context, OSMap map) throws IOException {
107         MapModel model = map.getModel();
108 
109         // Overlays
110         if (model != null) {
111             if (!model.getMarkers().isEmpty()) {
112                 encodeMarkers(context, map);
113             }
114             if (!model.getPolylines().isEmpty()) {
115                 encodePolylines(context, map);
116             }
117             if (!model.getPolygons().isEmpty()) {
118                 encodePolygons(context, map);
119             }
120             if (!model.getCircles().isEmpty()) {
121                 encodeCircles(context, map);
122             }
123             if (!model.getRectangles().isEmpty()) {
124                 encodeRectangles(context, map);
125             }
126         }
127     }
128 
129     protected void encodeMarkers(FacesContext context, OSMap map) throws IOException {
130         ResponseWriter writer = context.getResponseWriter();
131         MapModel model = map.getModel();
132 
133         writer.write(",markers:[");
134 
135         for (Iterator<Marker> iterator = model.getMarkers().iterator(); iterator.hasNext();) {
136             Marker marker = iterator.next();
137             encodeMarker(context, marker);
138 
139             if (iterator.hasNext()) {
140                 writer.write(",\n");
141             }
142         }
143         writer.write("]");
144     }
145 
146     protected void encodeMarker(FacesContext context, Marker marker) throws IOException {
147         ResponseWriter writer = context.getResponseWriter();
148 
149         writer.write("L.marker([");
150         writer.write(marker.getLatlng().getLat() + ", " + marker.getLatlng().getLng() + "]");
151 
152         writer.write(", {customId:'" + marker.getId() + "'");
153 
154         if (marker.getIcon() != null) {
155             writer.write(", icon:");
156             encodeIcon(context, marker.getIcon());
157         }
158         if (marker.isDraggable()) {
159             writer.write(",draggable: true");
160         }
161 
162         writer.write("})");
163     }
164 
165     protected void encodeIcon(FacesContext context, Object icon) throws IOException {
166         ResponseWriter writer = context.getResponseWriter();
167         if (icon instanceof String) {
168             writer.write("'" + icon + "'");
169         }
170         else {
171             throw new FacesException("OSMap marker icon must be String");
172         }
173     }
174 
175     protected void encodePolylines(FacesContext context, OSMap map) throws IOException {
176         ResponseWriter writer = context.getResponseWriter();
177         MapModel model = map.getModel();
178 
179         writer.write(",polylines:[");
180 
181         for (Iterator<Polyline> lines = model.getPolylines().iterator(); lines.hasNext();) {
182             Polyline polyline = lines.next();
183 
184             writer.write("L.polyline([");
185 
186             encodePaths(context, polyline.getPaths());
187 
188             writer.write("], {customId:'" + polyline.getId() + "'");
189 
190             writer.write(",opacity:" + polyline.getStrokeOpacity());
191             writer.write(",weight:" + polyline.getStrokeWeight());
192 
193             if (polyline.getStrokeColor() != null) {
194                 writer.write(",color:'" + polyline.getStrokeColor() + "'");
195             }
196 
197             writer.write("})");
198 
199             if (lines.hasNext()) {
200                 writer.write(",");
201             }
202         }
203 
204         writer.write("]");
205     }
206 
207     protected void encodePolygons(FacesContext context, OSMap map) throws IOException {
208         ResponseWriter writer = context.getResponseWriter();
209         MapModel model = map.getModel();
210 
211         writer.write(",polygons:[");
212 
213         for (Iterator<Polygon> polygons = model.getPolygons().iterator(); polygons.hasNext();) {
214             Polygon polygon = polygons.next();
215 
216             writer.write("L.polygon([");
217 
218             encodePaths(context, polygon.getPaths());
219 
220             writer.write("], {customId:'" + polygon.getId() + "'");
221 
222             writer.write(",opacity:" + polygon.getStrokeOpacity());
223             writer.write(",weight:" + polygon.getStrokeWeight());
224             writer.write(",fillOpacity:" + polygon.getFillOpacity());
225 
226             if (polygon.getStrokeColor() != null) {
227                 writer.write(",color:'" + polygon.getStrokeColor() + "'");
228             }
229             if (polygon.getFillColor() != null) {
230                 writer.write(",fillColor:'" + polygon.getFillColor() + "'");
231             }
232             writer.write("})");
233 
234             if (polygons.hasNext()) {
235                 writer.write(",");
236             }
237         }
238 
239         writer.write("]");
240     }
241 
242     protected void encodeCircles(FacesContext context, OSMap map) throws IOException {
243         ResponseWriter writer = context.getResponseWriter();
244         MapModel model = map.getModel();
245 
246         writer.write(",circles:[");
247 
248         for (Iterator<Circle> circles = model.getCircles().iterator(); circles.hasNext();) {
249             Circle circle = circles.next();
250 
251             writer.write("L.circle([");
252             writer.write(circle.getCenter().getLat() + ", " + circle.getCenter().getLng() + "]");
253 
254             writer.write(", {customId:'" + circle.getId() + "'");
255 
256             writer.write(",radius:" + circle.getRadius());
257 
258             writer.write(",opacity:" + circle.getStrokeOpacity());
259             writer.write(",weight:" + circle.getStrokeWeight());
260             writer.write(",fillOpacity:" + circle.getFillOpacity());
261 
262             if (circle.getStrokeColor() != null) {
263                 writer.write(",color:'" + circle.getStrokeColor() + "'");
264             }
265             if (circle.getFillColor() != null) {
266                 writer.write(",fillColor:'" + circle.getFillColor() + "'");
267             }
268 
269             writer.write("})");
270 
271             if (circles.hasNext()) {
272                 writer.write(",");
273             }
274         }
275 
276         writer.write("]");
277     }
278 
279     protected void encodeRectangles(FacesContext context, OSMap map) throws IOException {
280         ResponseWriter writer = context.getResponseWriter();
281         MapModel model = map.getModel();
282 
283         writer.write(",rectangles:[");
284 
285         for (Iterator<Rectangle> rectangles = model.getRectangles().iterator(); rectangles.hasNext();) {
286             Rectangle rectangle = rectangles.next();
287 
288             LatLng ne = rectangle.getBounds().getNorthEast();
289             LatLng sw = rectangle.getBounds().getSouthWest();
290 
291             writer.write("L.rectangle([");
292             writer.write("[" + sw.getLat() + ", " + sw.getLng() + "],[" + ne.getLat() + ", " + ne.getLng() + "]");
293             writer.write("]");
294 
295             writer.write(", {customId:'" + rectangle.getId() + "'");
296 
297             writer.write(",opacity:" + rectangle.getStrokeOpacity());
298             writer.write(",weight:" + rectangle.getStrokeWeight());
299             writer.write(",fillOpacity:" + rectangle.getFillOpacity());
300 
301             if (rectangle.getStrokeColor() != null) {
302                 writer.write(",color:'" + rectangle.getStrokeColor() + "'");
303             }
304             if (rectangle.getFillColor() != null) {
305                 writer.write(",fillColor:'" + rectangle.getFillColor() + "'");
306             }
307 
308             writer.write("})");
309 
310             if (rectangles.hasNext()) {
311                 writer.write(",");
312             }
313         }
314 
315         writer.write("]");
316     }
317 
318     protected void encodePaths(FacesContext context, List<LatLng> paths) throws IOException {
319         ResponseWriter writer = context.getResponseWriter();
320 
321         for (Iterator<LatLng> coords = paths.iterator(); coords.hasNext();) {
322             LatLng coord = coords.next();
323 
324             writer.write("[" + coord.getLat() + ", " + coord.getLng() + "]");
325 
326             if (coords.hasNext()) {
327                 writer.write(",");
328             }
329 
330         }
331     }
332 
333     @Override
334     public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
335         // Do Nothing
336     }
337 
338     @Override
339     public boolean getRendersChildren() {
340         return true;
341     }
342 }