Last active
April 18, 2020 16:28
-
-
Save lovemyliwu/ccb66f65fabcc02571966145be885327 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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