Google analytics: tracking not working in subdomain - google-analytics

I have a website which has multiple subdomains. GA code is implemented in both root & subdomain1. While the root GA tracking is working perfectly, no counts are registered in the subdomain1.root.com. Both use the same tracking id.
Below is the code for root.
<script type="text/javascript">
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-TRACKINGCODE-1', 'root.com');
ga('send', 'pageview');
</script>
Tracking code for the subdomain1
<script type="text/javascript">
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-TRACKINGCODE-1', 'root.com');
ga('send', 'pageview');
</script>
I see the website address in the subdomain code is pointing to the root address. Is this a cause of concern? Or what am I missing?

I found this link for tracking subdomains with a Root domain, but I don't know where to implement the code: https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingSite#domainSubDomains
Code they say to use:
var pageTracker = _gat._getTracker('UA-12345-1');
pageTracker._setDomainName('example-petstore.com');
pageTracker._trackPageview();

Related

LiipImagineBundle / Retina

Is it possible to somehow configure bundle to generate images also for retina display, like #2x?
Or can someone give me an advice how to deal with retina?
Thanks
According to this comment by nahakiole, there are 2 solutions for this:
You can either use the picture element which would provide the syntax
to declare multiple sources for an image.
http://w3c.github.io/html/semantics-embedded-content.html#the-picture-element
The other method which we've tried was, if you can guarantee that the
image exists, to use a modified version of the retina.js which adds
_retina to the filter name and checks if a image with this name exists.
Modified version of retina.js by nahakiole:
/*-----------------------------------------------------------------------------------*/
/* RETINA.JS
/*-----------------------------------------------------------------------------------*/
(function () {
var regex = /(media\/cache\/filter_[A-Z]+)/i //Added this
function t(e) {
this.path = e;
var t = this.path.split("."),
n = t.slice(0, t.length - 1).join("."),
r = t[t.length - 1];
this.at_2x_path = (n + '.' + r).replace(regex, '$1_retina') //Changed that
}
function n(e) {
this.el = e, this.path = new t(this.el.getAttribute("src"));
var n = this;
this.path.check_2x_variant(function (e) {
e && n.swap()
})
}
var e = typeof exports == "undefined" ? window : exports;
e.RetinaImagePath = t, t.confirmed_paths = [], t.prototype.is_external = function () {
return !!this.path.match(/^https?\:/i) && !this.path.match("//" + document.domain)
}, t.prototype.check_2x_variant = function (e) {
var n, r = this;
if (this.is_external()) return e(!1);
if (this.at_2x_path in t.confirmed_paths) return e(!0);
n = new XMLHttpRequest, n.open("HEAD", this.at_2x_path), n.onreadystatechange = function () {
return n.readyState != 4 ? e(!1) : n.status >= 200 && n.status <= 399 ? (t.confirmed_paths.push(r.at_2x_path), e(!0)) : e(!1)
}, n.send()
}, e.RetinaImage = n, n.prototype.swap = function (e) {
function n() {
t.el.complete ? (t.el.setAttribute("width", t.el.offsetWidth), t.el.setAttribute("height", t.el.offsetHeight), t.el.setAttribute("src", e)) : setTimeout(n, 5)
}
typeof e == "undefined" && (e = this.path.at_2x_path);
var t = this;
n()
}, e.devicePixelRatio > 1 && (window.onload = function () {
var e = document.getElementsByTagName("img"),
t = [],
r, i;
for (r = 0; r < e.length; r++) i = e[r], t.push(new n(i))
})
})();

Compute path between 2 points with Google Map Direction Service

I'm trying to draw a path between points on a map. I have an array of 2 points (for my tests).
I can draw them on the map easily but it looks like the Direction Service is not working as expected.
This is what I should get according google map:
But this is what I get:
Here is the Jsfiddle.
And here is my testing code:
var map = undefined;
function initialize()
{
var mapOptions = {
center: new google.maps.LatLng(-33.885026, 151.268316),
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoom: 14
};
map = new google.maps.Map(document.getElementById("map"), mapOptions);
}
jQuery(document).ready(function($)
{
initialize();
loadPaths(map);
});
function loadPaths(gmap)
{
var latlngbounds = new google.maps.LatLngBounds(),
infoWindow = new google.maps.InfoWindow(),
pathPoints = [],
index=0,
positions = [
{latitude: "-33.88914",longitude: "151.25673"},
{latitude: "-33.888",longitude: "151.2623"},
];
// The fix
positions.reverse();
$.each(positions, function(k, v) {
var myLatlng = new google.maps.LatLng(v.latitude, v.longitude);
pathPoints.push(myLatlng);
index++;
});
// Intialize the Path Array
var path = new google.maps.MVCArray();
// Intialise the Direction Service
var service = new google.maps.DirectionsService();
var iconSymbol = {
path: 'M 40 20 L 80 20 L 100 40 L 100 140 L 20 140 L 20 40 Z',
anchor: new google.maps.Point(60, 10),
scale: 0.15,
strokeColor: '#000000',
strokeWeight: 1,
fillColor: 'steelblue',
fillOpacity: 0.8,
};
// Set the Path Stroke Color
var poly = new google.maps.Polyline({
map: gmap,
strokeColor: '#dd0000',
icons: [{
icon: iconSymbol
}]
});
// Draw the path for this vehicle
// We compute the path between each point to follow the road
for (var i = 0; i < pathPoints.length; i++) {
// If it's not the last point
if ((i + 1) < pathPoints.length) {
var src = pathPoints[i];
var des = pathPoints[i + 1];
// We had the starting point to the poly path
path.push(src);
// We compute the path between the 2 points
service.route({
origin: src,
destination: des,
travelMode: google.maps.DirectionsTravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.IMPERIAL
}, function (result, status) {
if (status == google.maps.DirectionsStatus.OK) {
// We add the new computed points
for (var i = 0, len = result.routes[0].overview_path.length; i < len; i++) {
path.push(result.routes[0].overview_path[i]);
}
}
});
}
}
// Set the path of the polyline to draw it
poly.setPath(path);
}
UPDATE
I've fixed the issue of the path thanks to #anto
But I still have an issue time to time, the path is not drew on the road. I think it's an asynchronous issue with the service callback function but I'm not sure how I can fix it.
If I relaunch the script in jsfiddle it's working randomly, but sometime I end up with this kind of drawing:
UPDATE 2
It looks like using a recursive function is fixing most of it, except that my last point is not drawn: http://jsfiddle.net/maxwell2022/wY32u/11/
As click on google map first time its create start point as click second time on map it creates end point in map and displays route on map
> var map;
> var infowindow = new google.maps.InfoWindow();
> var wayA;
> var wayB;
> var geocoder = new google.maps.Geocoder();
> var directionsDisplay = new google.maps.DirectionsRenderer({
> suppressMarkers: true,
> panel: document.getElementById('right-panel'),
> draggable: true
> });
> var directionsService = new google.maps.DirectionsService();
> var data = {};
> initMap();
> function initMap() {
> debugger;
> map = new google.maps.Map(document.getElementById('rmap'), {
> center: new google.maps.LatLng(23.030357, 72.517845),
> zoom: 15
> });
> google.maps.event.addListener(map, "click", function (event) {
> if (!wayA) {
> wayA = new google.maps.Marker({
> position: event.latLng,
> map: map,
> icon: "https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=S|00FF00|000000"
> });
> } else {
> if (!wayB) {
> debugger;
> wayB = new google.maps.Marker({
> position: event.latLng,
> map: map,
> icon: "https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=E|FF0000|000000"
> });
> calculateAndDisplayRoute(directionsService, directionsDisplay, wayA, wayB);
> }
> }
> });
> }
> function computeTotalDistance(result) {
> var total = 0;
> var myroute = result.routes[0];
> for (var i = 0; i < myroute.legs.length; i++) {
> total += myroute.legs[i].distance.value;
> }
> total = total / 1000;
> return total;
> }
> function computeTotalDuration(result) {
> var total = 0;
> var myroute = result.routes[0].legs[0].duration.text;
> return myroute;
> }
> function calculateAndDisplayRoute(directionsService, directionsDisplay, wayA, wayB) {
> debugger;
> directionsDisplay.setMap(map);
> google.maps.event.addListener(directionsDisplay, 'directions_changed', function () {
> debugger;
> calculateAndDisplayRoute(directionsService, directionsDisplay.getDirections(), wayA, wayB);
> });
> directionsService.route({
> origin: wayA.getPosition(),
> destination: wayB.getPosition(),
> optimizeWaypoints: true,
> travelMode: 'DRIVING'
> }, function (response, status) {
> if (status === 'OK') {
> debugger;
>
> var route = response.routes[0];
> wayA.setMap(null);
> wayB.setMap(null);
> pinA = new google.maps.Marker({
> position: route.legs[0].start_location,
> map: map,
> icon: "https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=S|00FF00|000000"
> }),
> pinB = new google.maps.Marker({
> position: route.legs[0].end_location,
> map: map,
> icon: "https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=E|FF0000|000000"
> });
> google.maps.event.addListener(pinA, 'click', function () {
> infowindow.setContent("<b>Route Start Address = </b>" + route.legs[0].start_address + " <br/>" + route.legs[0].start_location);
> infowindow.open(map, this);
> });
> google.maps.event.addListener(pinB, 'click', function () {
> debugger;
> infowindow.setContent("<b>Route End Address = </b>" + route.legs[0].end_address + " <br/><b>Distance=</b> " +
> computeTotalDistance(directionsDisplay.getDirections()) + " Km
> <br/><b>Travel time=</b> " +
> computeTotalDuration(directionsDisplay.getDirections()) + " <br/> " +
> route.legs[0].end_location);
> infowindow.open(map, this);
> });
> } else {
> window.alert('Directions request failed due to ' + status);
> }
> directionsDisplay.setDirections(response);
> });
> }

Handling class attribute assignments in Polymaps

I'm a social science person increasingly getting into web programming for data vis work so apologies if this question is dumb. I'm working on a polymaps implementation to visualize country level data over time. I reads in json temporal data and a geojson world map and spits out a quantile chloropleth map that iterates over monthly entries. The heart of this is a country formating function that binds a colorbrewer class to the country geojson objects (see below). This works find for the animation portion. The problem is that I am using a custom d3 layer that displays the date of the data currently displayed and acts as a mouseover control to stop the animation and choose a date or to choose a date once the animation is through. It does this by creating an blank svg element that uses the d3.scale() function to round mouse input to an integer that matches the index of the month desired. I've front loaded all the other calculations on load so that the only thing that happens at mouse over is the change of svg class (this is basically the same as Tom Carden's wealth of nations implementation on Bostock's d3 page here). Unfortunately, this still overloads the browser pretty quickly. Is there another way to do this that I'm totally missing? I admit im new to geojson so maybe some way to construct an array of classes with in the class attribute of the geojson object? Thanks a ton of any help.
function foo(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
EDIT: I'm adding the full script below.
<meta charset="utf-8">
<script src="scripts/d3.v3.js"></script>
<script src="scripts/polymaps.js"></script>
<script src="scripts/nns.js"></script>
<script>
//Polymaps namespace
var po = org.polymaps;
//Chart dimensions
var margin = {top: 20, right: 20, bottom: 20, left: 20};
var w = 960 - margin.right;
var h = 500 - margin.top - margin.bottom;
// Create the map object, add it to #map div
var map = po.map()
.container(d3.select("#map").append("svg:svg").attr("width", w + margin.left + margin.right).attr("height",h +margin.top + margin.bottom).node())
.center({lat: 28, lon: 0})
.zoom(1.85)
.zoomRange([1.5, 4.5])
.add(po.interact());
// Add the CloudMade image tiles as a base layer…
map.add(po.image()
.url(po.url("http://{S}tile.cloudmade.com"
+ "/1a1b06b230af4efdbb989ea99e9841af" // http://cloudmade.com/register
+ "/20760/256/{Z}/{X}/{Y}.png")
.hosts(["a.", "b.", "c.", ""])));
//Import contribution data
d3.json("assets/contributionsTCC1990-1991.json", function(data){
//find length of json data object and loop over it at interval
var dataLength = Object.keys(data).length;
//Create date key/value array using construtor
function date_array_constructor() {
var dateArray = {};
for(var i = 0; i < dataLength; i++) {
var d = i + 1;
dateArray[d] = data[i].date;
}
return dateArray;
}
var dateArray = date_array_constructor();
// Insert date label/control layer and add SVG elements that take on attributes determined by load function
var labelLayer = d3.select("#map svg").insert("svg:g");
map.add(po.geoJson()
.url("assets/world.json")
.tile(false)
.zoom(3)
.on("load", load));
map.container().setAttribute("class", "Blues");
map.add(po.compass()
.pan("none"));
function find_max(data, dataLength) {
var max = 0;
for(var i in data) {
if(data[i] > max) {
max = data[i] + 1;
}
}
return max;
}
function max_array_constructor(data, dataLength) {
var maxArray = {};
for(var i=0;i<dataLength;i++) {
var d = i+1;
maxArray[d] = find_max(data[i].contributions);
}
return maxArray;
}
var maxArray = max_array_constructor(data, dataLength);
function contribution_array_constructor(data, dataLength, tccName, feature) {
var contributions = {};
//iterate over date entries
for(var i=0;i<dataLength;i++) {
//contribution iterator
contributions[i+1] = 0;
for(x in data[i].contributions){
if(x == tccName) {
contributions[i+1] = data[i].contributions[x];
}
}
}
return contributions;
}
function format_array_constructor(data, dataLength, maxArray, feature) {
var formats = {};
// console.log(feature.data.contributions);
//iterate over date entries
for(var i=0;i<dataLength;i++) {
var percentile = feature.data.contributions[i+1] / maxArray[i+1];
if(percentile != 0){
var v = "q" + ((~~(percentile*7)) + 2) + "-" + 9;
}else{
var v = "countries";
}
formats[i+1] = v;
}
return formats;
}
///////////////////////////////
//load function
///////////////////////////////
function load(e) {
//Bind geojson and json
var geojson = e.features;
console.log(geojson);
geojson.dates = dateArray;
for(var x = 0; x < geojson.length; x++) {
// var tccID = geojson[x].data.id;
var tccName = geojson[x].data.properties.name;
geojson[x].data.contributions = contribution_array_constructor(data, dataLength, tccName, geojson[x]);
geojson[x].data.formats = format_array_constructor(data, dataLength, maxArray, geojson[x]);
}
//Insert date label
var dateLabel = labelLayer.append("text")
.attr("class", "date label")
.attr("text-anchor", "end")
.attr("x", w-670)
.attr("y", h )
.text(dateArray[1]);
//Add interactive overlay for date label
var box = dateLabel.node().getBBox();
var overlay = labelLayer.append("rect")
.attr("class", "overlay")
.attr("x", box.x)
.attr("y", box.y)
.attr("opacity",0)
.attr("width", box.width)
.attr("height", box.height)
.on("mouseover",enable_interaction);
function country_class_constructor(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
function foo(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
//incrementor function
function incrementor(local, geojson, dateArray) {
setTimeout(function() {
//set date label to current iteration
d3.transition(dateLabel).text(dateArray[local]);
//construct country classes
country_class_constructor(local, geojson);
// console.log(geojson);
}, 500*local);
}
///////////////////////////////
//Increment on load
///////////////////////////////
country_class_constructor(1, geojson)
for(var i=1; i< dataLength; i++) {
//Set incrementer as local variable
var local = i+1;
var timer = incrementor(local, geojson, dateArray);
}
///////////////////////////////
//interaction element
///////////////////////////////
function enable_interaction(){
var dateScale = d3.scale.linear()
.domain([1,Object.keys(dateArray).length])
.range([box.x + 10, box.x + box.width - 10])
.clamp(true);
timer = null;
overlay
.on("mouseover", mouse_over)
.on("mouseout",mouse_out)
.on("mousemove",mouse_move)
.on("touchmove",mouse_move);
function mouse_over() {
dateLabel.classed("active", true);
}
function mouse_out() {
dateLabel.classed("active", false);
}
function mouse_move() {
update_map(dateScale.invert(d3.mouse(this)[0]),data);
// displayYear(dateScale.invert(d3.mouse(this)[0]));
}
function update_map(userInput) {
var date = Math.floor(userInput);
d3.transition(dateLabel).text(dateArray[date]);
// console.log(date);
// country_class_constructor(date, geojson);
foo(date, geojson);
}
}
}
});
</script>
Edit 2: I forgot to add the JSON format. See below for two months of data:
[
{"date":"11/90",
"contributions":{
"Algeria":7,
"Argentina":39,
"Australia":41,
"Austria":967,
"Bangladesh":5,
"Belgium":4,
"Brazil":27,
"Canada":1002,
"Chile":7,
"China":5,
"Colombia":12,
"Czech Republic":6,
"Denmark":374,
"Ecuador":21,
"Fiji":719,
"Finland":992,
"France":525,
"Germany":13,
"Ghana":892,
"Hungary":15,
"India":40,
"Indonesia":5,
"Ireland":814,
"Italy":79,
"Jordan":6,
"Kenya":7,
"Malaysia":15,
"Nepal":851,
"Netherlands":15,
"New Zealand":22,
"Nigeria":2,
"Norway":924,
"Poland":165,
"Republic of the Congo":6,
"Russia":35,
"Senegal":4,
"Serbia":17,
"Spain":63,
"Sweden":738,
"Switzerland":5,
"Turkey":2,
"United Kingdom":769,
"United States":33,
"Uruguay":10,
"Venezuela":23,
"Zambia":6
}
},
{"date":"12/90",
"contributions":{
"Algeria":7,
"Argentina":39,
"Australia":41,
"Austria":967,
"Bangladesh":5,
"Belgium":4,
"Brazil":27,
"Canada":1002,
"Chile":7,
"China":5,
"Colombia":12,
"Czech Republic":6,
"Denmark":374,
"Ecuador":21,
"Fiji":719,
"Finland":992,
"France":525,
"Germany":13,
"Ghana":892,
"Hungary":15,
"India":40,
"Indonesia":5,
"Ireland":814,
"Italy":79,
"Jordan":6,
"Kenya":7,
"Malaysia":15,
"Nepal":851,
"Netherlands":15,
"New Zealand":22,
"Nigeria":2,
"Norway":924,
"Poland":165,
"Republic of the Congo":6,
"Russia":35,
"Senegal":4,
"Serbia":17,
"Spain":63,
"Sweden":738,
"Switzerland":5,
"Turkey":2,
"United Kingdom":769,
"United States":33,
"Uruguay":10,
"Venezuela":23,
"Zambia":6
}
}
]
After hours of debugging, it turns out that the nns.js library was causing me problems. Each iteration of the animation was creating a new set of DOM objects which started to max out the browser at 25,000. The solution was to use nss to create the initial state and then using the following function to change the class of each svg element.
function country_class_constructor(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
element = document.getElementById(n);
element.className["animVal"] = geojson[x].data.formats[local];
element.className["baseVal"] = geojson[x].data.formats[local];
}

Google Maps DistanceMatrix callback

I am using Google Maps Distance Matrix and what I need is two different distances,
at the moment I have the following:-
var start = arrObjLatLngs[0];
var end = arrObjLatLngs[arrObjLatLngs.length - 1];
var base = new google.maps.LatLng(52.781048888889, -1.2110222222222546);
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [base],
destinations: [start, end],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.DirectionsUnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, callback);
function callback(response, status) {
if (status == google.maps.DistanceMatrixStatus.OK) {
var origins = response.originAddresses;
var destinations = response.destinationAddresses;
for (var i = 0; i < origins.length; i++) {
var results = response.rows[i].elements;
for (var j = 0; j < results.length; j++) {
var element = results[j];
var distance = Math.round(parseFloat(element.distance.text));
alert(distance);
var duration = element.duration.text;
var from = origins[i];
var to = destinations[j];
}
}
}
}
When I alert($distance); I get two responses, e.g. 15 and 10
What I need is two seperate values, i.e. if I alert($runinPickup); I get 15 , if I alert alert($runinDestination); I get 10.
I thought they were in an array so I have tried alert(distance[0]) but this comes back as undefined.
Do I have to do two seperate getDistanceMatrix requests or is there a way to seperate the two values?

Drawing a polygon around a polyline in google maps

I am trying to create a polygon around an existing polyline. I thought of drawing polylines parallel to the existing polyline and then joining them to create a polygon. I tried unsuccessfully to do the math to draw the parallel lines. I found this link which I used to create the polylines on either sides.
http://wtp2.appspot.com/ParallelLines.htm
It seemed exactly what I was looking for. I started the conversion from v2 to v3. I tried to keep to minimal code and deleted the rest. I have also removed the listener for change in zoom level which was present in the original code.
It worked perfectly when I used a small fixed polyline. However when I increased the size of the polyline the parallel polylines began to go haywire.
The code that I have is :
var points = null;
var map;
var line1;
var line2;
var prj = null;
var idlelistener;
var gapPx = 2;
var weight = 4;
function BDCCParallelLines(maps, point, bounds) {
map = maps;
points = point;
//map.fitBounds(bounds);
MyOverlay.prototype = new google.maps.OverlayView();
MyOverlay.prototype.onAdd = function() { }
MyOverlay.prototype.onRemove = function() { }
MyOverlay.prototype.draw = function() { }
function MyOverlay(map) { this.setMap(map); }
var overlay = new MyOverlay(map);
// Wait for idle map
idlelistener = google.maps.event.addListener(map, 'idle', function() {
// Get projection
prj = overlay.getProjection();
recalc();
})
}
function recalc() {
google.maps.event.removeListener(idlelistener);
var zoom = this.map.getZoom();
//left and right swapped throughout!
var pts1 = new google.maps.MVCArray();//left side of center
var pts2 = new google.maps.MVCArray();//right side of center
//shift the pts array away from the centre-line by half the gap + half the line width
var o = (this.gapPx + this.weight)/2;
var p2l,p2r;
for (var i=1; i<this.points.length; i+=2){
var p1lm1;
var p1rm1;
var p2lm1;
var p2rm1;
var thetam1;
var p1 = this.prj.fromLatLngToContainerPixel(this.points.getAt(i-1),zoom) //**fromLatLngToPixel
var p2 = this.prj.fromLatLngToContainerPixel(this.points.getAt(i),zoom) //**fromLatLngToPixel
var theta = Math.atan2(p1.x-p2.x,p1.y-p2.y) + (Math.PI/2);
var dl = Math.sqrt(((p1.x-p2.x)*(p1.x-p2.x))+((p1.y-p2.y)*(p1.y-p2.y)));
if(theta > Math.PI)
theta -= Math.PI*2;
var dx = Math.round(o * Math.sin(theta));
var dy = Math.round(o * Math.cos(theta));
var p1l = new google.maps.Point(p1.x+dx,p1.y+dy); //GPoint
var p1r = new google.maps.Point(p1.x-dx,p1.y-dy);
p2l = new google.maps.Point(p2.x+dx,p2.y+dy);
p2r = new google.maps.Point(p2.x-dx,p2.y-dy);
if(i==1){ //first point
pts1.push(this.prj.fromContainerPixelToLatLng(p1l),zoom); //**fromPixelToLatLng
pts2.push(this.prj.fromContainerPixelToLatLng(p1r),zoom); //**fromPixelToLatLng
}
else{ // mid points
if(theta == thetam1){
// adjacent segments in a straight line
pts1.push(this.prj.fromContainerPixelToLatLng(p1l),zoom);
pts2.push(this.prj.fromContainerPixelToLatLng(p1r),zoom);
}
else{
var pli = this.intersect(p1lm1,p2lm1,p1l,p2l);
var pri = this.intersect(p1rm1,p2rm1,p1r,p2r);
var dlxi = (pli.x-p1.x);
var dlyi = (pli.y-p1.y);
var drxi = (pri.x-p1.x);
var dryi = (pri.y-p1.y);
var di = Math.sqrt((drxi*drxi)+(dryi*dryi));
var s = o / di;
var dTheta = theta - thetam1;
if(dTheta < (Math.PI*2))
dTheta += Math.PI*2;
if(dTheta > (Math.PI*2))
dTheta -= Math.PI*2;
if(dTheta < Math.PI){
//intersect point on outside bend
pts1.push(this.prj.fromContainerPixelToLatLng(p2lm1),zoom);
pts1.push(this.prj.fromContainerPixelToLatLng(new google.maps.Point(p1.x+(s*dlxi),p1.y+(s*dlyi))),zoom);
pts1.push(this.prj.fromContainerPixelToLatLng(p1l));
}
else if (di < dl){
pts1.push(this.prj.fromContainerPixelToLatLng(pli),zoom);
}
else{
pts1.push(this.prj.fromContainerPixelToLatLng(p2lm1),zoom);
pts1.push(this.prj.fromContainerPixelToLatLng(p1l),zoom);
}
dxi = (pri.x-p1.x)*(pri.x-p1.x);
dyi = (pri.y-p1.y)*(pri.y-p1.y);
if(dTheta > Math.PI){
//intersect point on outside bend
pts2.push(this.prj.fromContainerPixelToLatLng(p2rm1),zoom);
pts2.push(this.prj.fromContainerPixelToLatLng(new google.maps.Point(p1.x+(s*drxi),p1.y+(s*dryi))),zoom);
pts2.push(this.prj.fromContainerPixelToLatLng(p1r),zoom);
}
else if(di<dl)
pts2.push(this.prj.fromContainerPixelToLatLng(pri),zoom);
else{
pts2.push(this.prj.fromContainerPixelToLatLng(p2rm1),zoom);
pts2.push(this.prj.fromContainerPixelToLatLng(p1r),zoom);
}
}
}
p1lm1 = p1l;
p1rm1 = p1r;
p2lm1 = p2l;
p2rm1 = p2r;
thetam1 = theta;
}
pts1.push(this.prj.fromContainerPixelToLatLng(p2l),zoom);//final point
pts2.push(this.prj.fromContainerPixelToLatLng(p2r),zoom);
this.line1 = new google.maps.Polyline({
map: map,
path: pts1,
strokeColor: "#0000FF",
strokeWeight: 4,
strokeOpacity: 1.0
});
this.line2 = new google.maps.Polyline({
map: map,
path: pts2,
strokeColor: "#0000FF",
strokeWeight: 4,
strokeOpacity: 1.0
});*/
createPolygon(pts1,pts2);
}
function intersect(p0,p1,p2,p3)
{
// this function computes the intersection of the sent lines p0-p1 and p2-p3
// and returns the intersection point,
var a1,b1,c1, // constants of linear equations
a2,b2,c2,
det_inv, // the inverse of the determinant of the coefficient matrix
m1,m2; // the slopes of each line
var x0 = p0.x;
var y0 = p0.y;
var x1 = p1.x;
var y1 = p1.y;
var x2 = p2.x;
var y2 = p2.y;
var x3 = p3.x;
var y3 = p3.y;
// compute slopes, note the cludge for infinity, however, this will
// be close enough
if ((x1-x0)!=0)
m1 = (y1-y0)/(x1-x0);
else
m1 = 1e+10; // close enough to infinity
if ((x3-x2)!=0)
m2 = (y3-y2)/(x3-x2);
else
m2 = 1e+10; // close enough to infinity
// compute constants
a1 = m1;
a2 = m2;
b1 = -1;
b2 = -1;
c1 = (y0-m1*x0);
c2 = (y2-m2*x2);
// compute the inverse of the determinate
det_inv = 1/(a1*b2 - a2*b1);
// use Kramers rule to compute xi and yi
var xi=((b1*c2 - b2*c1)*det_inv);
var yi=((a2*c1 - a1*c2)*det_inv);
return new google.maps.Point(Math.round(xi),Math.round(yi)); // ** CHANGED HERE
}
function createPolygon(side1,side2){
var a = new Array();
for(var i = 0; i < side1.length;i++){
a.push(side1.getAt(i))
}
for(var i = side1.length-1; i >=0;i--){
a.push(side2.getAt(i));
}
drawPolylinePolygon(a)
}
function drawPolylinePolygon(a){
a.push(a[0]);
var color = getColor(false);
var polygon_options = {
paths: a,
strokeColor: color,
strokeOpacity: 0.7,
strokeWeight: 2,
fillColor: color,
fillOpacity: 0.2
};
current_polygon = new google.maps.Polygon(polygon_options);
current_polygon.setMap(map);
}
The createPolygon() function is used to merge the two polylines to create a polygon.
This is the html page :
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<title></title>
<script src="http://maps.google.com/maps/api/js?sensor=true&libraries=drawing,geometry" type="text/javascript"></script>
<script src="BDCCParallelLines.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
var map;
function linesMap(){
var latlng1 = new google.maps.LatLng(51.42, -0.95);
var mapOptions = {zoom: 22, center:latlng1, mapTypeId: google.maps.MapTypeId.ROADMAP, mapTypeControl: false};
var map = new google.maps.Map(document.getElementById('mapLines'),mapOptions);
var pts = new Array();
var latlngbounds = new google.maps.LatLngBounds();
pts.push (new google.maps.LatLng(51.42, -0.97));
latlngbounds.extend(new google.maps.LatLng(51.42, -0.97));
pts.push (new google.maps.LatLng(51.43, -0.96));
latlngbounds.extend(new google.maps.LatLng(51.43, -0.96));
pts.push (new google.maps.LatLng(51.425, -0.955));
latlngbounds.extend(new google.maps.LatLng(51.425, -0.955));
pts.push (new google.maps.LatLng(51.42, -0.95));//straight at zoom = 13
latlngbounds.extend(new google.maps.LatLng(51.42, -0.95));
pts.push (new google.maps.LatLng(51.43, -0.94));
latlngbounds.extend(new google.maps.LatLng(51.43, -0.94));
pts.push (new google.maps.LatLng(51.43, -0.9375));//horz & straight
latlngbounds.extend(new google.maps.LatLng(51.43, -0.9375));
pts.push (new google.maps.LatLng(51.43, -0.935));
latlngbounds.extend(new google.maps.LatLng(51.43, -0.935));
pts.push (new google.maps.LatLng(51.425, -0.935));
latlngbounds.extend(new google.maps.LatLng(51.425, -0.935));
pts.push (new google.maps.LatLng(51.42, -0.935));//vert & straight
latlngbounds.extend(new google.maps.LatLng(51.42, -0.935));
var poly = new BDCCParallelLines(map,pts,latlngbounds);
var poly2 = new google.maps.Polyline({
map: map,
path: pts,
strokeColor: "#FF0000",
strokeWeight: 2,
strokeOpacity: 1.0
});
}
//]]>
</script>
</head>
<body onload="linesMap();"
style="font-weight: bold; font-size: large; font-family: Arial; background-color: #cccc99">
<div id="mapLines" style="width: 800px; height: 600px">
</div>
</body>
</html>
After searching I came across this article where Ben seems to have the same problem. The image on the link shows the exact same problem I'm having.
Google maps api parallel path lines
I would like to know if there is any way that I can improve on the existing code for the parallel polylines or if there is any other way the end result I am looking for is a polygon around the polyline.
You should use a Buffer-function that exists in any spatial-API or database, one example are
sharpmap.

Resources