# Angular+Mqtt+PHP+MariaDB+Leaflet
## [先參照前篇完成基本leafmap](https://hackmd.io/@109213067/BJBlg0Mio/https%3A%2F%2Fhackmd.io%2FuIjQMqtqQM64Z1LnXKzOgw%3Fview)
## 流程
Angular前端新增標記 -> PHP(傳給Mqtt) -> Angular接收Mqtt訊息 -> PHP(存進MariaDB) + 在Leaflet上新增標記 -> 顯示在Angular前端
## 程式碼
### MariaDB
* 新增table存放地圖標記(id,座標1,座標2,座標名稱)
```sql=1
CREATE TABLE `mqttMap` (`id` int(10) NOT NULL PRIMARY KEY auto_increment,`p1` varchar(50) NOT NULL,`p2` varchar(50) NOT NULL,`text` varchar(50) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
### PHP
* 新增sendMqttMap.php(傳送地圖標記給Mqtt):
```php=1
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS');
header('Access-Control-Max-Age: 3600');
header('Access-Control-Allow-Headers: Content-Type,Access-Control-Allow-Headers, Authorization, X-Requested-With');
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
header('Access-Control-Allow-Credentials: true');
$data = json_decode(file_get_contents("php://input"));
if (!isset($data->message)) {
echo json_encode(['success' => 0, 'message' => 'field is empty!']);
exit;
};
$message = $data->message;
//$message = "321";
require('vendor/autoload.php');
use \PhpMqtt\Client\MqttClient;
use \PhpMqtt\Client\ConnectionSettings;
$server = '192.168.1.244'; // ip
$port = 1883;
$clientId = rand(5, 15);
$username = 'emqx_user';
$password = null;
$clean_session = false;
$connectionSettings = new ConnectionSettings();
$connectionSettings
->setUsername($username)
->setPassword(null)
->setKeepAliveInterval(60) // Last Will 設定
->setLastWillTopic('emqx/test/last-will')
->setLastWillMessage('client disconnect')
->setLastWillQualityOfService(1);
$mqtt = new MqttClient($server, $port, $clientId);
$mqtt->connect($connectionSettings);
// 發布 (topic_name, context)
$mqtt->publish('Map', $message, 0);
// 放開連線
$mqtt->disconnect();
?>
```
* 新增storeMqttMap.php(地圖標記存進資料庫):
```php=1
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS');
header('Access-Control-Max-Age: 3600');
header('Access-Control-Allow-Headers: Content-Type,Access-Control-Allow-Headers, Authorization, X-Requested-With');
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
header('Access-Control-Allow-Credentials: true');
$servername = "localhost";
$username = "kenny";
$password = "Kenny061256";
$dbname = "test";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
//
$data = json_decode(file_get_contents("php://input"));
//echo json_encode($data->message);
if (!isset($data->p1)||!isset($data->p2)||!isset($data->text)) {
echo json_encode(['success' => 0, 'message' => 'some fields are empty!']);
exit;
};
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$p1 = $data->p1;
$p2 = $data->p2;
$text = $data->text;
$sql = "insert into `mqttMap`(p1,p2,text)values(";
$sql .= "'".$p1."',";
$sql .= "'".$p2."',";
$sql .= "'".$text."')";
//$conn->execute($sql);
$conn->query($sql);
$conn->close();
?>
```
### Angular
* data.service.ts新增呼叫sendMqttMap.php:
```c#=1
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable()
export class DataService {
constructor(private http: HttpClient) {}
getData() {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem('token'),
'Access-Control-Alllow-Origin': '*',
'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE"'
})
};
return this.http.post('http://localhost/data.php', httpOptions);
}
addData(job: Object){
return this.http.post('http://localhost/insert.php', job);
}
searchData(job: Object){
return this.http.post('http://localhost/search.php', job);
}
editData(job: Object){
return this.http.post('http://localhost/edit.php', job);
}
deleteData(job: Object){
return this.http.post('http://localhost/delete.php', job);
}
sendMqtt(text: Object){
return this.http.post('http://localhost/connectMqtt.php',text);
}
storeMqtt(text:Object){
return this.http.post('http://localhost/storeMqtt.php',text);
}
sendMqttMap(text: Object){
return this.http.post('http://localhost/sendMqttMap.php',text);
}
storeMqttMap(mark:Object){
return this.http.post('http://localhost/storeMqttMap.php',mark);
}
}
```
* leafmap.component.html新增輸入欄位:
```html=1
<h1>Map</h1>
<input #p1 placeholder="p1"/>
<input #p2 placeholder="p2"/>
<input #p3 placeholder="text"/>
<button (click)="sendMqtt(p1.value,p2.value,p3.value); p1.value='';p2.value='';p3.value=''">send</button>
<div class="map-container">
<div class="map-frame">
<div id="map"></div>
</div>
</div>
```
* leafmap.component.ts新增接收、傳遞Mqtt、新增標記:
```c#=1
import { Component,OnInit} from '@angular/core';
import * as L from 'leaflet';
import { icon, Marker } from 'leaflet';
import { MqttService } from 'ngx-mqtt';
import { DataService } from '../data.service';
@Component({
selector: 'app-leafmap',
templateUrl: './leafmap.component.html',
styleUrls: ['./leafmap.component.css']
})
export class LeafmapComponent{
map:any;
newMark:string="";
MarkList:string[]=[];
constructor(private dataService: DataService,private mqttService: MqttService) {}
ngOnInit() {
this.mqttService.connect();
this.mqttService.observe('Map').subscribe((message)=>{
this.newMark = message.payload.toString();
this.MarkList = this.newMark.split(",");
const mark = {p1:this.MarkList[0],p2:this.MarkList[1],text:this.MarkList[2]}
this.dataService.storeMqttMap(mark).subscribe(response=>{
});
this.addMarker(this.MarkList[0],this.MarkList[1],this.MarkList[2]);
});
const iconRetinaUrl = 'assets/marker-icon-2x.png';
const iconUrl = 'assets/marker-icon.png';
const shadowUrl = 'assets/marker-shadow.png';
const iconDefault = icon ({
iconRetinaUrl,
iconUrl,
shadowUrl,
iconSize: [25,41],
iconAnchor: [12,41],
popupAnchor: [1,-34],
tooltipAnchor: [16,-28],
shadowSize: [41,41]
});
Marker.prototype.options.icon = iconDefault;
this.map = L.map('map', {
center: [23.952672279106505, 120.92716871995295],
zoom: 16
});
const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
minZoom: 3,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
});
const marker1 = L
.marker([23.952672279106505, 120.92716871995295],{title:'管院'})
.addTo(this.map)
.bindPopup("<h1>管院在這裡</h1>");
const marker2 = L
.marker([23.941804203963905, 120.9308004137981],{title:''})
.addTo(this.map)
.bindPopup("<h1>住的地方</h1>")
const marker3 = L
.marker([22.69037999999579, 120.32945971836486],{title:'管院'})
.addTo(this.map)
.bindPopup("<h1>我家啦</h1>")
const marker4 = L
.marker([23.128122197367723, 113.34752774482281],{title:'管院'})
.addTo(this.map)
.bindPopup("<h1>暨南大学</h1>")
marker1.openPopup();
tiles.addTo(this.map);
}
addMarker(p1:string,p2:string,text:string) {
const marker4 = L
.marker([this.convertNum(p1), this.convertNum(p2)],{title:text})
.addTo(this.map)
.bindPopup("<h1>"+text+"</h1>")
}
sendMqtt(p1:string,p2:string,text:string) {
const addmark = {message:p1+","+p2+","+text};
this.dataService.sendMqttMap(addmark).subscribe(response => {
alert('send mark to Mqtt!');
//window.location.reload();
});
}
convertNum(text:string) {
return parseFloat(text);
}
}
```