天天看點

網頁繪制可實時變色的路網地圖 D3 + OSM + STOMP

1.關于osm資料處理與可視化可以參見我這篇::(我是另一個快樂引流标簽^ _ ^)

2.關于stomp可以看我這篇:(我是快樂引流标簽^ _ ^)

這次的效果是一旦打開網頁就自動向伺服器發送請求擷取資料并自動繪制到網頁

不多廢話,按照步驟上代碼:

Stomp連接配接部分(JS)

/**
 * 建立連接配接,我這裡控制異步處理全部用的是setTimeout,建議為了代碼可讀和可維護,盡量使用事件監聽
 * 這裡偷懶還是采用的廣播模式,建議使用1對1通訊哈
 */
		function setCon(getData){
				stompClient.connect({},function (frame){
				//console.log("伺服器連接配接"+frame);
				setTimeout(2000);
				getData();
				});
	
		};
                
		//自動訂閱消息頻道并互動
		//訂閱以擷取消息	
	 	//訂閱之後發送send開啟交流,每收到一次就再發送一個send
		function getData(){
			setTimeout(function(){
				stompClient.subscribe("/system/china_motor", function(mes){
	 		    	dataLog = JSON.parse(mes.body);
	 		    	//處理得到的資料
				temp = Object.keys(dataLog);
	 		    	arr=(Object.values(dataLog));
				arr = arr[0];
                                //重新整理資料
				refreshData(arr,temp);
                                //确定循環好了就再發送請求    
                                stompClient.send("/app/china_motor",{},"iamready");
				})
			},1000)
                        setTimeout(function(){stompClient.send("/app/china_motor",{},"iamready")},1000);
		};
                
		//周遊形式重新整理path标簽
		function refreshData(arr,temp){
			svg.selectAll("path").each(function (d,i) {
		            if (arr.includes(i)) {
		                d3.select(this).attr("stroke",temp);
		              }
		            })
		}
		
	//連結關閉
	function sendGoodBye(){
		stompClient.send("/app/china_motor",{},"iamfinished");
	}
	function disconnect(){
	 	stompClient.disconnect();
	 }

           

JS用戶端部分

<svg class ="china"></svg>
	<script>
        //設定大小
    const svgWidth = 1200;
    const svgHeight =900;
    const padding = 1;
    
    const svg = d3.select(".china")
        .attr("height", svgHeight)
        .attr("width", svgWidth);

		/*
		 * 建立一個地理投影
		 * .center 設定投影中心位置
		 * .scale 設定縮放系數 
		 */
	const x0 = padding;
	const y0 = padding;
	const x1 = svgWidth - padding * 2;
	const y1 = svgHeight - padding * 2;
	const projection = d3.geoMercator().fitExtent(
			[
				[x0,y0],
				[x1,y1],
			],china
		 );
		//中心對齊可以再修改一下,提高速度-。-
		//  建立路徑生成器path
		var path = d3.geoPath().projection(projection);

		 //渲染地圖 
	const mapPath = svg.selectAll("path");
        //加載資料,這裡我沒有給出資料源,可以看我之前的部落格
		  mapPath.data(china.features)
			.join('path')
			.attr('d', path)
			//.attr('id',china.features.properties.valueof(osm_id))
			.attr("stroke-width", 2)
			.attr("stroke", "#00cc00")
			.attr("fill", "#000000");
			
	//前面全部處理好了就建立連接配接開始通信
	var linstener = "/system/china_motor"
	socket = new SockJS('/stomp');
	stompClient = Stomp.over(socket);
	var data;
	setCon(getData);
	</script>

<script>
//當退出頁面或者改變頁面時就關閉連結,防止占用
 window.onbeforeunload = function(e) {
	sendGoodBye();
	disconnect();
	} 
</script>
    
           

伺服器部分:

//這裡還沒有接入資料庫,使用随機數測試一下。。
    	@MessageMapping("/china_motor")
	@SendTo("/system/china_motor")
	public void sentMotor(@Payload String name) throws InterruptedException {
		int size = 0;
		int a = 0;
		int max = 248306;
		int big = 0;
		String color;
		System.out.println(name);
		trafficStream ts = new trafficStream();
		if(name.equals("iamready")) {
                //生成随機數測試
			Random rd = new Random();
			a = rd.nextInt(3);
			switch(a) {
			case 0: 
				color="#ff0000";
				size = 1000;
				break;
			case 1:
				color="#ffff00";
				size = 10000;
				break;
			case 2:
				color="##00cc00";
				size = 10000;
				break;
			default:
				color = "##00cc00";
				size = 10000;
				;
			}
			int[] sort = new int [size];
			sort = ts.randomArray(0, max, size);
			Map<String,int[]> msg = new HashMap<String, int[]>();
			msg.put(color, sort);
			Thread.sleep(6000);
			peopelFlow.convertAndSend("/system/china_motor",msg);
		}
                //處理完畢事件
		else if(name.equals("iamfinished")) {
				System.out.println("connect finished");
				peopelFlow.setSendTimeout(j);
		}
	}	
           

stompConfig部分:

public static final String BROKER_CHINA = "/system/china_motor";
	@Override
	public void configureMessageBroker(MessageBrokerRegistry config) {
			//用于指定用戶端可以訂閱哪些位址
			config.enableSimpleBroker(BROKER_CHINA);
			//用戶端發送消息的服務端位址字首
			config.setApplicationDestinationPrefixes("/app");
			//服務端發給 制定 用戶端的字首 /system/msg 是廣播 /user/system/msg則是制定用戶端
			config.setUserDestinationPrefix("/user");
		}
	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		//SockJS 用于定義連接配接節點
		registry.addEndpoint("/stomp")//.setHandshakeHandler(new CustomHandler())//.setAllowedOrigins("*")
                        .withSockJS();		
	}
	//配置線程數量(pool),防止錯順序
	@Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        registration.taskExecutor().corePoolSize(1).maxPoolSize(1);
    }

           

效果展示:

網頁繪制可實時變色的路網地圖 D3 + OSM + STOMP

放大看看~

網頁繪制可實時變色的路網地圖 D3 + OSM + STOMP
網頁繪制可實時變色的路網地圖 D3 + OSM + STOMP

根據設定的資料量和随即機率,黃色很快就填滿了

由于是随機資料,是以看起來有點假,但是确實是根據伺服器端的資料實時更新的。

背景資料也看得到:

網頁繪制可實時變色的路網地圖 D3 + OSM + STOMP

存在的主要問題:

  1. 上文提過的js應該使用事件監聽處理異步事件
  2. 算法沒有優化,占用了大量的計算和記憶體資源
  3. 資料量太大導緻網頁加載慢以及stomp封包處理慢
  4. 資料不完整,可以再加入OSM_Roads裡面的’motor_link’以完整資料

其實還有蠻多其他小瑕疵的。

害,以後有心情再優化吧-。-

希望各位多多指教,提出意見。

繼續閱讀