Browse Source

样式和marker控制选项 control_marker

HuangKai 3 months ago
parent
commit
4cff2fed0f
4 changed files with 287 additions and 4 deletions
  1. 60 0
      public/style.mapcss
  2. 2 1
      src/view/App.js
  3. 1 1
      src/view/layers/HistoryTrack.js
  4. 224 2
      src/view/layers/Styled.js

+ 60 - 0
public/style.mapcss

@@ -495,6 +495,66 @@ node[amenity] {
 	fill-color: white;
 }
 
+/** All devices **//** fill-color: #FFDAAD;**/
+*[device][device!=showcase] {
+	fill-color: #FFDAAD;
+	opacity: 1;
+	fill-opacity: 1;
+	icon-image: url('device_$[device].png');
+	icon-width: 8;
+	icon-height: 8;
+	icon-opacity: 1;
+	text: name;
+}
+
+node[device] {
+	color: #00E5EE;
+	fill-opacity: 1;
+	fill-color: white;
+}
+
+*[area_type] {	
+	color: #828282;
+	opacity: 0.9;
+	width: 1;
+}
+
+*[area_type=none] {	
+	fill-color: #ffffff;
+	fill-opacity: 1;
+}
+
+	
+*[area_type=background] {	
+	fill-color: #e8e8e8;
+	fill-opacity: 0.9;
+}
+
+*[area_type=catering] {	
+	fill-color: #efe5ce;
+	fill-opacity: 1;
+}
+
+*[area_type=shop] {	
+	fill-color: #d8e0ca;
+	fill-opacity: 1;
+}
+
+*[area_type=service] {	
+	fill-color: #d0dee2;
+	fill-opacity: 1;
+}
+
+*[area_type=toilet] {	
+	fill-color: #ead6d6;
+	fill-opacity: 1;
+}
+
+*[area_type=counter] {	
+	fill-color: #e8c377;
+	fill-opacity: 1;
+}
+
 /** Comfort amenities **/
 *[amenity=toilets],
 *[public_transport=waiting_area],

+ 2 - 1
src/view/App.js

@@ -38,9 +38,10 @@ export default class App {
 		};
 
 		window.CONFIG = {
-			data_min_zoom: 18,
+			data_min_zoom: 14,
 			map_initial_zoom: params.zoom || 18,
 			map_initial_latlng: params.center ? [params.center.lat, params.center.lng] : [39.9087, 116.3974],
+			map_zoom_control_marker: params.control_marker ? params.control_marker : false,
 		};
 
 	}

+ 1 - 1
src/view/layers/HistoryTrack.js

@@ -22,7 +22,7 @@ class HistoryTrack extends Component {
 		// console.log(this.map, this.props);
 
 		PubSub.subscribe("his.play.ctrl", (msg, data) => {
-			console.log(data.state);
+			// console.log(data.state);
 			if(!this.track){
 				console.error("需要先设置track数据!")
 				alert("需要先设置track数据!");

+ 224 - 2
src/view/layers/Styled.js

@@ -11,7 +11,7 @@
  */
 
 import { Path, withLeaflet } from 'react-leaflet';
-import { CircleMarker, GeoJSON, Icon, LayerGroup, Marker, Polygon, Polyline } from 'leaflet';
+import { CircleMarker, DivIcon, GeoJSON, Icon, LayerGroup, Marker, Polygon, Polyline } from 'leaflet';
 import deepEqual from 'fast-deep-equal';
 import PubSub from 'pubsub-js';
 
@@ -37,6 +37,21 @@ const MyIcon = Icon.extend({
  */
 class StyledLayer extends Path {
 	createLeafletElement(props) {
+		if(window.CONFIG.map_zoom_control_marker){
+			//clone data
+			this.cahedFeatures = JSON.parse(JSON.stringify(props.data.features));
+
+			//sub event
+			PubSub.subscribe("map.zoom.changed", (msg, data) => {			
+				this.leafletElement.clearLayers();
+				this.props.data.features = this._filterData(data.zoom);
+				this._populateLayer(this.leafletElement, this.props);	
+				this._sortFeaturesZIndex(this.leafletElement);
+			})
+
+			//filter data
+			props.data.features = this._filterData(props.leaflet.map.getZoom())
+		}
 		// Add some defaults
 		const thatStyler = props.styler.getFeatureStyle.bind(props.styler);
 		const myprops = Object.assign({}, {
@@ -65,7 +80,20 @@ class StyledLayer extends Path {
 		this._sortFeaturesZIndex(this.leafletElement);
 	}
 
+    componentWillUnmount(){
+		this.leafletElement.clearLayers();
+
+        PubSub.unsubscribe("map.zoom.changed")
+    }
+
 	updateLeafletElement(fromProps, toProps) {
+		if(window.CONFIG.map_zoom_control_marker){
+			//clone data
+			this.cahedFeatures = JSON.parse(JSON.stringify(toProps.data.features));
+
+			//filter data
+			toProps.data.features = this._filterData(toProps.leaflet.map.getZoom())
+		}
 		// Add style property according to styler
 		if(!toProps.style) {
 			toProps = Object.assign({}, toProps, { style: toProps.styler.getFeatureStyle.bind(toProps.styler) });
@@ -91,6 +119,67 @@ class StyledLayer extends Path {
 		this._sortFeaturesZIndex(this.leafletElement);
 	}
 
+	/**
+	 * filter data by zoom
+	 * @private
+	 */
+	_filterData(zoom) {
+		//zoom>=20 show all markers
+		//zoom==19 show half markers
+		//zoom==18 hide all text markers
+		//zoom<=17 hide al markers
+
+		//clone data
+		let pp = JSON.parse(JSON.stringify(this.cahedFeatures));
+		
+		if (zoom === 19) {
+			pp.map(f => {
+				let ft = f;
+				if(ft.properties.tags.show_type && ft.properties.tags.poi_no){
+					if(ft.properties.tags.poi_no % 2 !== 0){
+						ft.properties.tags.show_type = "none"
+					}
+				}
+				if(ft.id.startsWith("node/")){
+					if(ft.properties.tags.poi_no % 2 !== 0){
+						ft.geometry.coordinates[0] = 20000
+					}
+				}
+				return ft;
+			});
+		} else if (zoom === 18) {
+			pp.map(f => {
+				let ft = f;
+				if(ft.properties.tags.show_type){
+					if(ft.properties.tags.poi_no % 4 !== 0){
+						ft.properties.tags.show_type = "none"
+					}
+					if(ft.properties.tags.show_type === "text"){
+						ft.properties.tags.show_type = "none"
+					}
+				}
+				if(ft.id.startsWith("node/")){
+					if(ft.properties.tags.poi_no % 4 !== 0){
+						ft.geometry.coordinates[0] = 20000
+					}
+				}
+				return ft;
+			});
+		} else if (zoom <= 17) {
+			pp.map(f => {
+				let ft = f;
+				if(ft.properties.tags.show_type){
+					ft.properties.tags.show_type = "none"
+				}
+				if(ft.id.startsWith("node/")){
+					ft.geometry.coordinates[0] = 20000
+				}
+				return ft;
+			});
+		}
+		return pp
+	}
+
 	/**
 	 * Sort features by size and type
 	 * @private
@@ -121,7 +210,39 @@ class StyledLayer extends Path {
 
 		this._featureIcons = new LayerGroup();
 
-		const featuresWithIcons = layer.getLayers().filter(l => l.options && l.options.iconImage && (!this.props.selection || l.feature.id !== this.props.selection.id));
+		const layers = layer.getLayers();
+		
+		const featuresWithTexts = layers.filter(l => {
+			return l.feature 
+				&& l.feature.properties 
+				&& l.feature.properties.tags 
+				&& l.feature.properties.tags.show_type !== "none"
+				&& (l.feature.properties.tags.name !== "" && l.feature.properties.tags.name !== "卫生间") 
+				&& l.feature.properties.tags.area_type !== "7" 
+				&& l.feature.geometry 
+				&& l.feature.geometry.type 
+				&& (l.feature.geometry.type === "MultiPolygon" || l.feature.geometry.type === "Polygon")
+				&& (!this.props.selection || l.feature.id !== this.props.selection.id)
+		})
+		const textWidth = 500;
+		const textHeight = 20;
+		featuresWithTexts.forEach(l => {
+			const coords = l.getLatLng ? l.getLatLng() : (l.getBounds ? l.getBounds().getCenter() : null);
+
+			if(coords) {
+				let div = this._createNameMarkerByType(l.feature.properties.tags.name, l.feature.properties.tags.show_type);
+				let icon = new DivIcon({
+					iconSize: [textWidth, textHeight],
+					html: div,
+					className: "area_name_marker"
+				});
+
+				let marker = new Marker(coords, { icon: icon, interactive: false });
+				this._featureIcons.addLayer(marker);
+			}
+		});
+
+		const featuresWithIcons = layers.filter(l => l.options && l.options.iconImage && (!this.props.selection || l.feature.id !== this.props.selection.id));
 		const iconSize = 20;
 
 		featuresWithIcons.forEach(l => {
@@ -147,6 +268,107 @@ class StyledLayer extends Path {
 		layer.addLayer(this._featureIcons);
 	}
 
+	/**
+	 * Name marker create by type
+	 * @private
+	 */
+	_createNameMarkerByType(name, type)
+	{
+		let src;
+		switch (type) {
+			case "none":
+				return null;
+			case "text":
+				return this._createDivIcon(name);
+			case "icon_text":
+				src = window.EDITOR_URL + "img/icons/shop_music.png";
+				return this._createImageDivIcon(src, name, false);
+			case "icon_text_border":
+				src = window.EDITOR_URL + "img/icons/shop_music.png";
+				return this._createImageDivIcon(src, name);
+		
+			default:
+				return null;
+		}
+	}
+
+	/**
+	 * Create divIcon elememnt
+	 * @private
+	 */
+	_createDivIcon(name)
+	{
+		let div = document.createElement('div');
+		div.style.backgroundColor = "rgba(0, 0, 0, 0)";
+		div.style.pointerEvents = "none";
+		div.style.verticalAlign = "middle";
+		div.style.textAlign = "center";
+		div.style.color = "rgb(135, 36, 6)";
+		div.style.textShadow = "1px 0px 0px #fff, -1px 0px 0px #fff, 0px 1px 0px #fff, 0px -1px 0px #fff";
+		div.innerText = name;
+
+		return div;
+	}
+
+	/**
+	 * Create divIcon elememnt with img
+	 * @private
+	 */
+	_createImageDivIcon(src, name, bordered = true)
+	{
+		let divOut = document.createElement('div');
+		divOut.style.verticalAlign = "middle";
+		divOut.style.textAlign = "center";
+
+		let divMid = document.createElement('div');
+		divMid.style.width = "auto";
+		divMid.style.display = "inline-block";
+		divMid.style.verticalAlign = "middle";
+		divMid.style.textAlign = "left";
+		divMid.style.textIndent = "3px";
+		divMid.style.pointerEvents = "none";
+		divMid.style.paddingRight = "5px";
+		divMid.style.color = "rgb(135, 36, 6)";
+		divMid.style.textShadow = "1px 0px 0px #fff, -1px 0px 0px #fff, 0px 1px 0px #fff, 0px -1px 0px #fff";
+		// divMid.style.paddingBottom = "2px";
+		if(bordered){
+			divMid.style.backgroundColor = "beige";
+			divMid.style.border = "solid";
+			divMid.style.borderColor = "black";
+			divMid.style.borderWidth = "1px";
+			divMid.style.borderRadius = "8px";
+		}
+		divMid.innerText = name;
+		
+		let divIn = document.createElement('div');
+		divIn.style.backgroundColor = "white";
+		divIn.style.height = "20px";
+		divIn.style.width = "20px";
+		divIn.style.verticalAlign = "middle";
+		divIn.style.textAlign = "left";
+		divIn.style.pointerEvents = "none";
+		divIn.style.marginLeft = "-5px";
+		divIn.style.marginTop = "-1px";
+		divIn.style.border = "solid";
+		divIn.style.borderColor = "black";
+		divIn.style.borderWidth = "1.5px";
+		divIn.style.borderRadius = "12px";
+		divIn.style.float = "left";
+		
+		let img = document.createElement('img');
+		img.src = src;
+		img.style.pointerEvents = "none";
+		img.style.height = "16px";
+		img.style.width = "16px";
+		img.style.marginLeft = "-2px";
+		img.style.marginTop = "-2px";
+
+		divOut.append(divMid);
+		divMid.append(divIn);
+		divIn.append(img);
+		return divOut;
+	}
+
 	/**
 	 * Load content into the leaflet layer
 	 * @private