Current marker distance to map bounds - google-maps-api-3

i need the current distance between the marker and the map bounds to decide: draw the tipbox left, right, over or under the marker.
I set the position of the tipbox with these lines of code:
Label.prototype.draw = function() {
var projection = this.getProjection();
var position = projection.fromLatLngToDivPixel(this.get('position'));
// position of tipbox, depends on margin to map boaunds
var div = this.div_;
var mapWidth = parseInt($('#mapBox').css('width'));
var mapHeight = parseInt($('#mapBox').css('height'));
div.style.left = (position.x-(parseInt(div.style.width)/2)) + 'px';
div.style.top = position.y + 'px';
div.style.display = 'inline';
$('.tipBox-inner').html(''+position.x);
};
But if i drag the page, the position.x or position.y return the same number of pixels. As you can see on the image, the x position is at 300px(!). I would draw the tipbox in top of the marker, if the marker is at the bottom of page and so on.

Ok i found a solution myself. I get the distance(px) to margin in the mouseover-Event of the marker:
google.maps.event.addListener(marker, 'mouseover', function(event) {
label = new Label({
map: map
});
label.bindTo('position', marker, 'position');
var pixel = label.getProjection().fromLatLngToContainerPixel(event.latLng);
label.set('mouseX', pixel.x);
label.set('mouseY', pixel.y);
});
Now i can use mouseX and mouseY in draw-functionf of the Label with this.get('mouseX')

Related

paperjs - draw a line with arrows

Im trying to draw a line with arrow using paperjs but it does not produce the desired output.
http://jsfiddle.net/1j6nLa7c/
$(document).ready(function(){
paper.install(window)
paper.setup('myCanvas')
x1 = 100;
y1 = 100;
r = 100;
theta = .7;
var path = new Path();
path.strokeColor = 'black';
var start = new Point(100, 100);
path.moveTo(start);
path.lineTo(x1+r*Math.cos(theta), y1+r*Math.sin(theta));
path.simplify(300)
var vector = path.getPointAt(path.length).subtract(path.getPointAt(path.length-25))
var arrowVector = vector.normalize(18);
var path2 = new Path({
segments: [path.getPointAt(path.length) + arrowVector.rotate(145), path.getPointAt(path.length), path.getPointAt(path.length) + arrowVector.rotate(-145)],
fillColor: 'black',
strokeWidth: 6,
});
path2.scale(1.3);
})
Here's some code that creates an arrow. The object is initialized with mouse down point and draws an arrow with the tip at the point the mouse is dragged to.
function Arrow (mouseDownPoint) {
this.start = mouseDownPoint;
this.headLength = 20;
this.tailLength = 9;
this.headAngle = 35;
this.tailAngle = 110
}
Arrow.prototype.draw = function (point) {
var end = point;
var arrowVec = this.start.subtract(end);
// parameterize {headLength: 20, tailLength: 6, headAngle: 35, tailAngle: 110}
// construct the arrow
var arrowHead = arrowVec.normalize(this.headLength);
var arrowTail = arrowHead.normalize(this.tailLength);
var p3 = end; // arrow point
var p2 = end.add(arrowHead.rotate(-this.headAngle)); // leading arrow edge angle
var p4 = end.add(arrowHead.rotate(this.headAngle)); // ditto, other side
var p1 = p2.add(arrowTail.rotate(this.tailAngle)); // trailing arrow edge angle
var p5 = p4.add(arrowTail.rotate(-this.tailAngle)); // ditto
// specify all but the last segment, closed does that
this.path = new paper.Path(this.start, p1, p2, p3, p4, p5);
this.path.closed = true;
this.path.strokeWidth = 1
this.path.strokColor = 'black'
this.path.fillColor = 'black'
return this.path
}
I like the tapered tail but you can get rid of that by fiddling with the constructor lengths.
Here's a sketch with the mouse handling

wrong border coords on draw a polygon with the fabric.js

i try to draw a polygon with the mouse , and i have found that example on jsfiddle: http://jsfiddle.net/Kienz/ujefxh7w/.
the problem is that when we finish the draw and try to selet the object, the borders are outside of the shape.
can we fixe that or is it a fabric.js bug?
as we can also see on the official fabricjs.com/ page, on the front page examples, the free hand drawings are also out of the border frame.
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c');
// Do some initializing stuff
fabric.Object.prototype.set({
transparentCorners: false,
cornerColor: 'rgba(102,153,255,0.5)',
cornerSize: 12,
padding: 7
});
// ADD YOUR CODE HERE
var mode = "add",
currentShape;
canvas.observe("mouse:move", function (event) {
var pos = canvas.getPointer(event.e);
if (mode === "edit" && currentShape) {
var points = currentShape.get("points");
points[points.length - 1].x = pos.x - currentShape.get("left");
points[points.length - 1].y = pos.y - currentShape.get("top");
currentShape.set({
points: points
});
canvas.renderAll();
}
});
canvas.observe("mouse:down", function (event) {
var pos = canvas.getPointer(event.e);
if (mode === "add") {
var polygon = new fabric.Polygon([{
x: pos.x,
y: pos.y
}, {
x: pos.x + 0.5,
y: pos.y + 0.5
}], {
fill: 'blue',
opacity: 0.5,
selectable: false
});
currentShape = polygon;
canvas.add(currentShape);
mode = "edit";
} else if (mode === "edit" && currentShape && currentShape.type === "polygon") {
var points = currentShape.get("points");
points.push({
x: pos.x - currentShape.get("left"),
y: pos.y - currentShape.get("top")
});
currentShape.set({
points: points
});
canvas.renderAll();
}
});
fabric.util.addListener(window, 'keyup', function (e) {
if (e.keyCode === 27) {
if (mode === 'edit' || mode === 'add') {
mode = 'normal';
currentShape.set({
selectable: true
});
currentShape._calcDimensions(false);
currentShape.setCoords();
} else {
mode = 'add';
}
currentShape = null;
}
canvas.renderAll();
})
THE PROBLEM
_calcDimensions() calculates width, height, minX and minY of the polygon, so as you can see with this fiddle http://jsfiddle.net/ujefxh7w/90/ the centerpoint of our polygon (that is calculated using width and height) will be changed after calling _calcDimensions() (before this, the centerpoint's value was equal to the top-left point because width and height were zero).
However we inserted all points to the polygon by subtracting the left-top position to them, but after calling _calcDimensions() those points will be rendered by starting from the "new" (correct) centerpoint, as you can see from your fiddle.
Moreover we have to handle minX and minY offsets introduced by _calcDimensions(). If we don't do this you can manage to draw some shapes with some area of out the bounds. (e.g. draw a triangle with those coordinates [(100,100),(150,50),(200,200)], the second point will be out of bound).
THE SOLUTION
We have to
add minX and minY offset to the left-top position of our shape and subtracting them from the new points's values
recalculate points's coordinates by using the actual centerpoint and the left-top position of our polygon
http://jsfiddle.net/ujefxh7w/115/
fabric.util.addListener(window, 'keyup', function (e) {
if (e.keyCode === 27) {
if (mode === 'edit' || mode === 'add') {
mode = 'normal';
// remove last useless point
var points = currentShape.get("points");
points.pop();
currentShape.set({points: points});
// call helpers
currentShape._calcDimensions();
currentShape.setCoords();
// adjust shape position by using minX and minY offsets
var minx = currentShape.get("minX");
var miny = currentShape.get("minY");
currentShape.set({
left: currentShape.get("left") + minx,
top: currentShape.get("top") + miny
});
// adjust points coordinates by
// 1- subtracting the center point coords
// 2- adding the left-top coords
// 3- subtracting minX and minY offsets
var pCenter = currentShape.getCenterPoint();
var l = currentShape.get("left");
var t = currentShape.get("top");
var adjPoints = currentShape.get("points").map(function(p) {
return {
x: p.x - pCenter.x + l - minx,
y: p.y - pCenter.y + t - miny
};
});
currentShape.set({
points: adjPoints,
selectable: true
});
canvas.setActiveObject(currentShape);
canvas.renderAll();
} else {
mode = 'add';
}
currentShape = null;
}
});

d3 putting multi pie chart on map

I want to put multi pie chart on d3 map but I'm confused how to do it.
I'm noob at d3 so I searched about the issue and made below code.
Someone suggested that I should make two seperate svgs so I did it.
There are two svgs. one has a map, and the other has multiple pie chart.
Now I have a problem with mapping these pies on map.
I don't know how to map these pies with geo coordinates...
It's just browser(?) coordinates so I want to change it.
and I want to zoom and pan map correctly with pies...
hope your help...
summary
I have two problems
putting multiple pie charts on right map place
zoom and pan correctly
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v0.min.js"></script>
<script>
var width = 960, height = 500;
var projection = d3.geo.mercator().center([ 127.46, 36.00 ])
.scale(4000).translate([ width / 2, height / 2 ]);
var color = d3.scale.category20();
//first svg
var svg = d3.select("body").append("svg").attr("width", width).attr(
"height", height);
var path = d3.geo.path().projection(projection);
var radius = 30;
var arc = d3.svg.arc().innerRadius(radius - 100).outerRadius(
radius - 20);
var g = svg.append("g");
var rawFile = new XMLHttpRequest();
rawFile.open("GET", "/tourdata.txt", false);
var allText;
rawFile.onreadystatechange = function() {
if (rawFile.readyState === 4) {
if (rawFile.status === 200 || rawFile.status == 0) {
allText = rawFile.responseText;
}
}
}
rawFile.send(null);
var lines = allText.split('\n');
var timeTable = new Array();
var res = lines[0].split(", ");
var currentTime = res[1];
var currentDate = res[0];
var timeInformation = new Array();
var corInformation = new Array();
var timeCorTable = new Array();
for ( var i = 0; i < lines.length; i++) {
var res = lines[i].split(", ");
if (currentDate != res[0] || currentTime != res[1]) {
currentDate = res[0];
currentTime = res[1];
timeTable[currentDate + ":" + currentTime] = timeInformation;
timeCorTable[currentDate + ":" + currentTime] = timeCorTable;
timeInformation = new Array();
corInformation = new Array();
}
if (timeInformation[res[2] + "," + res[3]] == undefined) {
corInformation.push(res[2] + "," + res[3]);
timeInformation.push([ res[4], res[5], res[6], res[7], res[8],
res[9], res[10], res[11], res[12], res[13] ]);
}
}
timeTable.push(timeInformation);
timeCorTable.push(corInformation);
var data = timeTable;
console.log(timeCorTable[0]);
// load and display the World
d3.json("kor.json",
function(error, topology) {
// load and display the cities
var geo = topojson.object(topology,
topology.objects['kor.geo']).geometries;
g.selectAll('path').data(geo).enter().append('path').attr(
'd', path)
});
console.log(data[0]);
//second svg that has multiple pies
var svgSvg = d3.select("body").select("svg").selectAll("g").data(timeTable[0]).enter().append("svg:svg").attr(
"width", width).attr("height", height).append("svg:g").style(//svg:g make pie group
"opacity", 0.8).attr("transform", function(d, i) {
var split = timeCorTable[0][i].split(",");
//console.log(split[0]);
var point = [split[0], split[1]];
console.log(projection(point[0], point[1])[0]);
return ("translate(" + projection(point[0], point[1])[0] + "," + projection(point[0], point[1])[1] + ")");
});
svgSvg.selectAll("path").data(d3.layout.pie()).enter().append(
"svg:path").attr("d",
d3.svg.arc().innerRadius(10).outerRadius(30)).style("fill", function(d, i) { return color(i); });
// zoom and pan
var zoom = d3.behavior.zoom().on(
"zoom",
function() {
g.attr("transform", "translate("
+ d3.event.translate.join(",") + ")scale("
+ d3.event.scale + ")");
g.selectAll("path").attr("d", path.projection(projection));
svgSvg.attr("transform", "translate("
+ d3.event.translate.join(",") + ")scale("
+ d3.event.scale + ")");
});
svg.call(zoom)
</script>

How to add a random point inside a polygon in Google Maps?

I have a bounds to a place and created a polygon of that place.
How can I generate a random point inside the bounds of that polygon?
One way of doing it. This will calculate the bounds of the polygon, then guess a random point inside that bounds, if the point is contained by the polygon, it will put a marker there.
// calculate the bounds of the polygon
var bounds = new google.maps.LatLngBounds();
for (var i=0; i < polygon.getPath().getLength(); i++) {
bounds.extend(polygon.getPath().getAt(i));
}
var sw = bounds.getSouthWest();
var ne = bounds.getNorthEast();
// Guess 100 random points inside the bounds,
// put a marker at the first one contained by the polygon and break out of the loop
for (var i = 0; i < 100; i++) {
var ptLat = Math.random() * (ne.lat() - sw.lat()) + sw.lat();
var ptLng = Math.random() * (ne.lng() - sw.lng()) + sw.lng();
var point = new google.maps.LatLng(ptLat,ptLng);
if (google.maps.geometry.poly.containsLocation(point,polygon)) {
var marker = new google.maps.Marker({position:point, map:map});
break;
}
}
working fiddle
working fiddle with up to 100 random points
var polygon;
function initialize() {
var map = new google.maps.Map(document.getElementById("map"),
{
zoom: 4,
center: new google.maps.LatLng(22.7964, 79.8456),
mapTypeId: google.maps.MapTypeId.HYBRID
});
var coords =
[
new google.maps.LatLng(18.979026,72.949219), //Mumbai
new google.maps.LatLng(28.613459,77.255859), //Delhi
new google.maps.LatLng(22.512557,88.417969), //Kolkata
new google.maps.LatLng(12.940322,77.607422) //Bengaluru
];
polygon = new google.maps.Polygon({
paths: coords,
strokeColor: "#0000FF",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#0000FF",
fillOpacity: 0.26
});
polygon.setMap(map);
var bounds = new google.maps.LatLngBounds();
for (var i=0; i < polygon.getPath().getLength(); i++) {
bounds.extend(polygon.getPath().getAt(i));
}
var sw = bounds.getSouthWest();
var ne = bounds.getNorthEast();
for (var i = 0; i < 100; i++) {
var ptLat = Math.random() * (ne.lat() - sw.lat()) + sw.lat();
var ptLng = Math.random() * (ne.lng() - sw.lng()) + sw.lng();
var point = new google.maps.LatLng(ptLat,ptLng);
if (google.maps.geometry.poly.containsLocation(point,polygon)) {
var marker = new google.maps.Marker({position:point, map:map});
var infowindow = new google.maps.InfoWindow({});
google.maps.event.addListener(marker, "click", function(evt) {
infowindow.setContent(marker.getPosition().toUrlValue(6));
infowindow.open(map, marker);
});
break;
}
}
}
google.maps.event.addDomListener(window, 'load', initialize);
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="map" style="width: 530px; height: 500px">
</div>

Draw polygon of 100 pixels on mouseclick

I need to draw a square polygon of 100x100 screenpixels whereever I click on the Google map (Amsterdam, lat 52, lng 4), on every zoomlevel, with e.latlng at the center of the polygon. I tried to figure it out using fromLatLngToPoint, fromPointToLatLng, scale and worldCoordinates, but I can't get the polygon drawn. If someone likes this puzzle I would appreciate the solution very much.
(I want to use this as a simple start to edit the polygon to a more complex shape, not using the DrawingManager)
I tried:
google.maps.event.addListener(map, 'click', function(e) {
var scale = Math.pow(2, map.getZoom());
var nw = new google.maps.LatLng(map.getBounds().getNorthEast().lat(),map.getBounds().getSouthWest().lng());
var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
var worldCoordinate = map.getProjection().fromLatLngToPoint(e.latLng);
var deX = Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale);
var deY = Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale);
// so far so good, deX and deY give the centerpixel
var deNW = map.getProjection().fromPointToLatLng(new google.maps.Point(deX-50,deY-50));
var deNO = map.getProjection().fromPointToLatLng(new google.maps.Point(deX+50,deY-50));
var deZO = map.getProjection().fromPointToLatLng(new google.maps.Point(deX+50,deY+50));
var deZW = map.getProjection().fromPointToLatLng(new google.maps.Point(deX-50,deY+50));
var dePathArray = [deNW, deNO, deZO, deZW];
deObjectNew = new google.maps.Polygon({
paths: dePathArray,
strokeColor: '#000000',
strokeWeight: 1,
fillColor: "#FF0000",
fillOpacity: 0.3,
});
deObjectNew.setMap(map);
});
Got it:
var deNW = deKaart.getProjection().fromPointToLatLng(new google.maps.Point((deX-50)/scale+worldCoordinateNW.x,(deY-50)/scale+worldCoordinateNW.y));
var deNO = deKaart.getProjection().fromPointToLatLng(new google.maps.Point((deX+50)/scale+worldCoordinateNW.x,(deY-50)/scale+worldCoordinateNW.y));
var deZO = deKaart.getProjection().fromPointToLatLng(new google.maps.Point((deX+50)/scale+worldCoordinateNW.x,(deY+50)/scale+worldCoordinateNW.y));
var deZW = deKaart.getProjection().fromPointToLatLng(new google.maps.Point((deX-50)/scale+worldCoordinateNW.x,(deY+50)/scale+worldCoordinateNW.y));

Resources