Skip to content

Instantly share code, notes, and snippets.

@lovemyliwu
Last active April 18, 2020 16:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lovemyliwu/ccb66f65fabcc02571966145be885327 to your computer and use it in GitHub Desktop.
Save lovemyliwu/ccb66f65fabcc02571966145be885327 to your computer and use it in GitHub Desktop.
<html>
<title>照片元信息转换为GeoJSON数据并可视化</title>
<style>
.thumb, canvas {
height: 75px;
border: 1px solid #000;
margin: 10px 5px 0 0;
}
#container {
width: 100%;
height: 100%;
}
#list, #geojson {
overflow: auto;
max-width: 50%;
max-height: 20%;
}
</style>
<body>
<div>
<input type="file" id="files" name="files[]" multiple/>
<button id="render">render map</button>
</div>
<div>
<output id="list"></output>
</div>
<div>
<output id="geojson"></output>
</div>
<div id="container"></div>
</body>
<script src="https://cdn.jsdelivr.net/npm/blueimp-load-image@3.0.0/js/load-image.all.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
<script src="https://webapi.amap.com/maps?v=1.4.15&key=56d5a8792fff13a32ecd190e975bfee9"></script>
<script src="https://cdn.jsdelivr.net/npm/gcoord@0.2.3/dist/gcoord.js"></script>
<script id="renderMap">
let map;
const infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -30)});
// 点击位置显示照片
function markerClickHandler(e) {
infoWindow.setContent(e.target.content);
infoWindow.open(map, e.target.getPosition());
}
function renderMap() {
let data = geoJSONData;
if (!data) {
alert('please select image file!');
return;
}
let center = gcoord.transform(
data.features[0].geometry.coordinates,
gcoord.WGS84,
gcoord.GCJ02
);
// 初始化map
map = new AMap.Map('container', {
center: center
});
// 加载GeoJSON图层
let layer = new AMap.GeoJSON({
geoJSON: data,
// 转换为高德需要的数据
getMarker: function (feature, position) {
// 坐标转换
position = gcoord.transform(
position,
gcoord.WGS84,
gcoord.GCJ02
);
let marker = new AMap.Marker({
position: position
});
marker.content = `<img class="thumb" src="${feature.properties.objectURL}" name="${feature.properties.name}"/>`;
marker.on('click', markerClickHandler);
return marker
}
});
layer.setMap(map);
}
</script>
<script id="makeData">
let selectedImages = [];
let metaContainer = [];
let objectURLS = [];
let geoJSONData;
let proxyObjectURLS = {
set: function (target, property, value, receiver) {
if (property === 'length') {
generateGeoJSON();
}
return (target[property] = value);
}
};
objectURLS = new Proxy(objectURLS, proxyObjectURLS);
function ConvertDMSToDD(degrees, minutes, seconds, direction) {
var dd = degrees + (minutes / 60) + (seconds / 3600);
if (direction == "S" || direction == "W") {
dd = dd * -1;
}
return dd;
}
function getCoordinates(GPSLatitude, GPSLatitudeRef, GPSLongitude, GPSLongitudeRef) {
// Calculate latitude decimal
var latDegree = parseFloat(GPSLatitude[0]);
var latMinute = parseFloat(GPSLatitude[1]);
var latSecond = parseFloat(GPSLatitude[2]);
var latFinal = ConvertDMSToDD(latDegree, latMinute, latSecond, GPSLatitudeRef);
console.log(latFinal);
// Calculate longitude decimal
var lonDegree = parseFloat(GPSLongitude[0]);
var lonMinute = parseFloat(GPSLongitude[1]);
var lonSecond = parseFloat(GPSLongitude[2]);
var lonFinal = ConvertDMSToDD(lonDegree, lonMinute, lonSecond, GPSLongitudeRef);
console.log(lonFinal);
return [lonFinal, latFinal];
}
// 组装GeoJSON
function generateGeoJSON() {
let data = {
"type": "FeatureCollection",
"features": []
};
for (const [index, meta] of metaContainer.entries()) {
const file = selectedImages[index];
const allTag = meta.exif.getAll();
let properties = {
"name": file.name,
"objectURL": objectURLS[index]
};
data['features'].push({
"type": "Feature",
"properties": properties,
"geometry": {
"type": "Point",
"coordinates": getCoordinates(
allTag.GPSInfo.GPSLatitude.split(','),
allTag.GPSInfo.GPSLatitudeRef,
allTag.GPSInfo.GPSLongitude.split(','),
allTag.GPSInfo.GPSLongitudeRef
)
}
});
}
renderGeoJSON(data);
geoJSONData = data;
}
function renderGeoJSON(data) {
document.querySelector('#geojson').innerHTML = '';
let el = document.createElement('pre');
el.setAttribute('class', 'geojson');
el.innerText = JSON.stringify(data, null, " ");
document.querySelector('#geojson').appendChild(el);
}
async function renderThumbnail(file) {
loadImage(
file,
async function (img, meta) {
if (!meta.exif) {
alert(`image:${file.name} not contain exif data, skipped`);
return;
}
const allTag = meta.exif.getAll();
if (!allTag.GPSInfo) {
alert(`image:${file.name} not contain gps data, skipped`);
return;
}
document.querySelector('#list').appendChild(img);
// 分离元数据
metaContainer.push(meta);
const blob = await new Promise(resolve => img.toBlob(resolve));
const objectURL = URL.createObjectURL(blob);
objectURLS.push(objectURL);
},
{orientation: true, canvas: true, meta: true} // Options
);
}
// 读取照片
async function handleFileSelect(event) {
for (let file of event.target.files) {
if (!file.type.match('image.*')) {
continue;
}
selectedImages.push(file);
await renderThumbnail(file);
}
}
document.querySelector('#files').addEventListener('change', handleFileSelect, false);
document.querySelector('#render').addEventListener('click', renderMap, false);
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment