Skip to content

Instantly share code, notes, and snippets.

@poppycocker
Last active December 18, 2015 13:49
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 poppycocker/5792513 to your computer and use it in GitHub Desktop.
Save poppycocker/5792513 to your computer and use it in GitHub Desktop.
// http://advpro.co.jp/Devlop/?p=530
Number.prototype.toRadian = function() {
return this * Math.PI / 180;
};
Number.prototype.toDeg = function() {
return this * 180 / Math.PI;
};
L.Point.prototype.cross = function(p1, p2) {
var p01 = this.subtract(p1),
p02 = this.subtract(p2);
return p01.x * p02.y - p01.y * p02.x;
};
L.PolygonArea = L.Polygon.extend({
onAdd: function(map) {
L.Polygon.prototype.onAdd.call(this, map);
this.on('edit', this._measureArea);
this._measureArea();
},
_measureArea: function() {
if (this._latlngs.length < 3) {
if (this._tooltip) {
this._map.removeLayer(this._tooltip);
this._tooltip = null;
}
return;
}
var xyPoints = this._latLngs2XYs(),
SDoubled = 0,
cur, nxt;
for (var i = 0, l = xyPoints.length; i < l; i++) {
cur = xyPoints[i];
nxt = (i === l - 1 ? xyPoints[0] : xyPoints[i + 1]);
SDoubled += (cur.x - nxt.x) * (cur.y + nxt.y);
}
var S = Math.round(Math.abs(SDoubled / 2) * 10) / 10 + 'm<sup>2</sup>';
var medianXY = this._calcMedianPoint(xyPoints);
var tooltipPos = this._xy2LatLng(medianXY);
this._showAreaValue(S, tooltipPos);
},
_latLngs2XYs: function(basis) {
// http://www.eva.hi-ho.ne.jp/tokada/map/distance_calculation.htm
basis = basis || this._latlngs[0];
var M = Math,
R_MAJOR = L.Projection.Mercator.R_MAJOR,
// rangeOK = function(point) {
// return M.abs(point.lat) <= 85 && M.abs(point.lng) <= 180;
// },
xyPoints = [],
blatRad = basis.lat.toRadian(),
blngRad = basis.lng.toRadian(),
tlatRad, tlngRad, x, y;
this._latlngs.forEach(function(latLng) {
tlatRad = latLng.lat.toRadian();
tlngRad = latLng.lng.toRadian();
y = M.sin(tlngRad - blngRad) * M.cos(tlatRad) * R_MAJOR;
x = (M.cos(blatRad) * M.sin(tlatRad) - M.sin(blatRad) * M.cos(tlatRad) * M.cos(tlngRad - blngRad)) * R_MAJOR;
xyPoints.push(L.point(x, y));
});
return xyPoints;
},
_xy2LatLng: function(point, basis) {
basis = basis || this._latlngs[0];
var M = Math,
blatRad = basis.lat.toRadian(),
blngRad = basis.lng.toRadian(),
x = point.x,
y = point.y,
dist = M.sqrt(x * x + y * y);
if (dist >= 20000000) {
return basis;
}
var brg = M.atan2(y, x),
d = dist / L.Projection.Mercator.R_MAJOR,
latRad = M.asin(M.sin(blatRad) * M.cos(d) + M.cos(blatRad) * M.sin(d) * M.cos(brg)),
lngRad = blngRad + M.atan2(M.sin(brg) * M.sin(d) * M.cos(blatRad), (M.cos(d) - M.sin(blatRad) * M.sin(latRad)));
lngRad = (lngRad + M.PI) % (2 * M.PI) - M.PI;
return L.latLng(latRad.toDeg(), lngRad.toDeg());
},
_calcMedianPoint: function(xyPoints) {
// http://www.not-enough.org/abe/manual/argo/center-of-mass.html
var P = L.point(0, 0),
areaSum = 0.0,
p0 = xyPoints[0],
a, Pc, pa, pb, i;
for (i = 1; i < xyPoints.length - 1; i++) {
pa = xyPoints[i];
pb = xyPoints[i + 1];
a = p0.cross(pa, pb) / 2;
Pc = p0.add(pa).add(pb).divideBy(3);
areaSum += a;
P._add(Pc.multiplyBy(a));
}
return P.divideBy(areaSum);
},
_showAreaValue: function(val, latLng) {
if (this._tooltip) {
this._updateTooltip(val, latLng);
} else {
this._createTooltip(val, latLng);
}
// centering tooltip text
var icon = this._tooltip._icon;
icon.style.width = icon.style.height = 'auto';
icon.style.marginLeft = icon.offsetWidth / -2 + 'px';
icon.style.marginTop = icon.offsetHeight / -2 + 'px';
icon.style.marginRight = icon.style.marginBottom = 0;
},
_createTooltip: function(val, latLng) {
var icon = L.divIcon({
className: 'leaflet-polygonarea-tooltip'
});
this._tooltip = L.marker(latLng, {
icon: icon,
clickable: false
}).addTo(this._map);
this._tooltip._icon.innerHTML = val;
},
_updateTooltip: function(val, latLng) {
this._tooltip.setLatLng(latLng);
this._tooltip._icon.innerHTML = val;
}
});
L.polygonArea = function(latlngs, options) {
return new L.PolygonArea(latlngs, options);
};
// TODO: ポリゴン生成時のオプション指定できるように
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment