为所有 Google 个标记生成单个全局信息窗口

Generate single global infowindow for all Google markers

我有这个代码是从另一个 post 那里得到的。我是 JavaScript 的新手,并尝试对其进行修改,以便在我单击标记时,我希望在打开新信息窗口之前关闭先前的信息窗口以保持地图清洁。我知道这个问题已经回答了很多次。

我已经完成了我的研究试图修复此代码,但我缺少 java 限制了我。

这是我的来源:

function cCustomMapping(options) {
    var self = this;
    var pOptions = options,
        pData, pMap;
    var currentInfoWindow = null;
    var activeWindow
    self.getOptions = function() {
        return pOptions;
    };

    self.setData = function(data) {
        pData = data;
        return pData;
    };

    self.getData = function() {
        return pData;
    };

    self.afterResetBoundingBox = function(bounds) {
        // called when map size is adjusted to bounds
        return bounds;
    };

    self.beforeMapRendering = function(myOptions) {
        // make any map rendering adjustments here
        return myOptions;
    };

    self.afterMapRendering = function(theMap) {
        // store map opject
        pMap = theMap;
        return pMap;
    };

    self.afterMarkerCreate = function(cj) {
        // play around with marker info window etc.
        return cj;
    };

    self.setParams = function(qParams) {
        // play around with parameters
        pParams = qParams;

        return pParams;
    };

    self.getParams = function() {
        return pParams;
    };

    self.markerOnClick = function(cj) {
        // when a marker is clicked
        return cj
            //setIcon('https://www.google.com/mapfiles/marker_green.png');
    };

    self.markerAfterClick = function(cj) {
        // affter a marker click is processed
        return cj;
    };

}

function mcpherDataPopulate() {
    var mcpherData = {
        'framework': {
            'control': {
                'browser': 'default',
                'zoomlevelonselect': 18,
                'resizeboundingbox': 1,
                'shape': 'circle'
            }
        },
        'cJobject': [

            {
                'title': '007',
                'content': '\<b\>7 - (19119)\</b\>\<br\>6480 ANDERSON ST\<br\>',
                'lat': '40.059088',
                'lng': '-75.172762',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '010',
                'content': '\<b\>10 - (19119)\</b\>\<br\>6463 ARDLEIGH ST\<br\>',
                'lat': '40.057609',
                'lng': '-75.172873',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '011',
                'content': '\<b\>11 - (19119)\</b\>\<br\>6475 ARDLEIGH ST\<br\>',
                'lat': '40.0579279',
                'lng': '-75.173392',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '012',
                'content': '\<b\>12 - (19119)\</b\>\<br\>6610 ARDLEIGH ST\<br\>',
                'lat': '40.058337',
                'lng': '-75.175411',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '017',
                'content': '\<b\>17 - (19150)\</b\>\<br\>1501 Barringer St\<br\>',
                'lat': '40.062211',
                'lng': '-75.166986',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19150'
                }],
            },

            {
                'title': '018',
                'content': '\<b\>18 - (19150)\</b\>\<br\>1534 Barringer St\<br\>',
                'lat': '40.062918',
                'lng': '-75.165485',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19150'
                }],
            },

            {
                'title': '019',
                'content': '\<b\>19 - (19119)\</b\>\<br\>1215 E Cardeza St\<br\>',
                'lat': '40.059621',
                'lng': '-75.171835',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '020',
                'content': '\<b\>20 - (19119)\</b\>\<br\>1231 E Cardeza St\<br\>',
                'lat': '40.060054',
                'lng': '-75.171412',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '021',
                'content': '\<b\>21 - (19119)\</b\>\<br\>1235 E Cardeza St\<br\>',
                'lat': '40.060166',
                'lng': '-75.171306',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '022',
                'content': '\<b\>22 - (19119)\</b\>\<br\>1236 E Cardeza St\<br\>',
                'lat': '40.059989',
                'lng': '-75.170865',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '023',
                'content': '\<b\>23 - (19119)\</b\>\<br\>1313 E Cardeza St\<br\>',
                'lat': '40.061115',
                'lng': '-75.170365',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '024',
                'content': '\<b\>24 - (19119)\</b\>\<br\>1335 E Cardeza St\<br\>',
                'lat': '40.061804',
                'lng': '-75.169701',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19119'
                }],
            },

            {
                'title': '025',
                'content': '\<b\>25 - (19150)\</b\>\<br\>1607 E Cardeza St\<br\>',
                'lat': '40.064291',
                'lng': '-75.167243',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19150'
                }],
            },

            {
                'title': '026',
                'content': '\<b\>26 - (19150)\</b\>\<br\>1332 E Cliveden St\<br\>',
                'lat': '40.061041',
                'lng': '-75.168595',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19150'
                }],
            },

            {
                'title': '027',
                'content': '\<b\>27 - (19150)\</b\>\<br\>1407 E Cliveden St\<br\>',
                'lat': '40.061981',
                'lng': '-75.16842',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19150'
                }],
            },

            {
                'title': '028',
                'content': '\<b\>28 - (19150)\</b\>\<br\>1607 E Cliveden St\<br\>',
                'lat': '40.064017',
                'lng': '-75.166444',
                'color': '#0000FF',
                'size': '0',
                'category': [{
                    'ZipCode': '19150'
                }],
            }

        ]
    };

    return mcpherData;
};

// -- this section is main
function initialize() {

        mcpherData = mcpherDataPopulate();
        customMapping.setData(mcpherData);

        if (mcpherData.cJobject.length > 0) {
            mcpherData.cJobject.sort(function(a, b) {
                return a.title.toLowerCase() < b.title.toLowerCase() ? -1 : (a.title.toLowerCase() > b.title.toLowerCase() ? 1 : 0);
            });

            var myOptions = {
                center: new google.maps.LatLng(mcpherData.cJobject[0].lat, mcpherData.cJobject[0].lng),
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };

            // get parameters if any
            var qparams = mcpherGetqparams();
            qparams = customMapping.setParams(qparams);

            var cj = mcpherData.cJobject;
            var bounds = new google.maps.LatLngBounds();
            for (var i = 0; i < cj.length; i++) {
                cj[i].childIndex = i;
                bounds.extend(new google.maps.LatLng(cj[i].lat, cj[i].lng));
            }

            if (!qparams['zoom']) qparams['zoom'] = 2;
            myOptions['zoom'] = parseInt(qparams['zoom']);
            // create the map

            // opportunity to change options
            myOptions = customMapping.beforeMapRendering(myOptions);

            gMap = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
            gMap.fitBounds(bounds);

            customMapping.afterMapRendering(gMap);

            // add the excel data
            for (var i = 0; i < cj.length; i++) {
                mcpherAddMarker(cj[i]);
            }

            // Set up combox

            category();
            quickLink(-1);
            makeFlightGroups();
            initialCategory();
        }
    }
    //----


//---- this section is catfacunctions
// flightpath stuff
function createSquareCoords(p, size) {
    // size will be in meters convert to km
    return [
        destinationLatLng(p, size / 1000, 45),
        destinationLatLng(p, size / 1000, 135),
        destinationLatLng(p, size / 1000, 225),
        destinationLatLng(p, size / 1000, 315),
        destinationLatLng(p, size / 1000, 45)
    ];
}

function destinationLatLng(p, size, heading) {
    var d = size / earthRadius();
    var lat1 = toRadians(p.lat());
    var lon1 = toRadians(p.lng());
    var brng = toRadians(heading);
    var lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) +
        Math.cos(lat1) * Math.sin(d) * Math.cos(brng));
    var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(d) * Math.cos(lat1),
        Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));
    lon2 = (lon2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
    return new google.maps.LatLng(fromRadians(lat2), fromRadians(lon2));

}

function earthRadius() {
    return 6371.0;
}

function toType(obj) {
    return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}

function isArray(arg) {
    return toType(arg) == 'array';
}

function toRadians(deg) {
    return Math.PI / 180 * deg;
}

function fromRadians(rad) {
    return 180 / Math.PI * rad;
}

function createFlightGroups() {
    var flightGroups = [];
    var cj = mcpherData.cJobject;
    var fg;
    for (var i = 0; i < cj.length; i++) {
        if (fg = cj[i].flightGroup) {
            if (flightGroups.indexOf(fg) == -1) {
                flightGroups.push(fg);
            }
            cj[i].flightGroupIndex = flightGroups.indexOf(fg);
        } else cj[i].flightGroupIndex = -1;
    }
    return flightGroups;
}

function initialCategory() {
    // sets initial category using the first select element
    var cj = mcpherData.cJobject;
    var c, p;
    var combos = getAllCombos();
    if (combos.length > 0) {
        var cats = createCategories(combos[0]);
        for (var i = 0; i < cj.length; i++) {
            if (c = cj[i].startCategory) {
                if ((p = cats.indexOf(c)) != -1) {
                    var elem = document.getElementById('selectcategory0');
                    elem.value = p;
                    dealWithCategories(elem);
                    return p;
                }
            }
        }
    }
    return -1;
}

// this is because IE doesnt have indexOf...
if (!Array.indexOf) {
    Array.prototype.indexOf = function(obj, start) {
        for (var i = (start || 0); i < this.length; i++) {
            if (this[i] == obj) {
                return i;
            }
        }
        return -1;
    }
}

function resetBoundingBox(force) {
    var z = mcpherData.framework && mcpherData.framework.control && mcpherData.framework.control.resizeboundingbox ?
        mcpherData.framework.control.resizeboundingbox : false;
    if ((z || force) && !vMap) {
        // dont do for vizmap apps - reset bounding box to visible items
        var cj = mcpherData.cJobject;
        var bounds = new google.maps.LatLngBounds();
        for (var i = 0; i < cj.length; i++) {
            if (cj[i].marker.visible) bounds.extend(new google.maps.LatLng(cj[i].lat, cj[i].lng));
        }
        gMap.fitBounds(bounds);
    }
    customMapping.afterResetBoundingBox(bounds);
}

function makeFlightGroups() {

    var flightGroups = createFlightGroups();
    var cj = mcpherData.cJobject;

    for (var j = 0; j < flightGroups.length; j++) {
        var flightCoords = [];
        var color = "#FF0000";
        for (var i = 0; i < cj.length; i++) {
            if (j == cj[i].flightGroupIndex) {
                flightCoords.push(cj[i].marker.position);
                if (cj[i].flightColor) color = cj[i].flightColor;
            }
        }
        if (flightCoords.length) {
            flightGroups[j].flightPath = new google.maps.Polyline({
                path: flightCoords,
                strokeColor: color,
                strokeOpacity: 1.0,
                strokeWeight: 2,
                map: gMap
            });
        }
    }
    return flightGroups;
}

function createPoly(cj, p) {
    if (cj.size) {
        if (mcpherData.framework.control.shape == "square") {
            return new google.maps.Polygon({
                paths: createSquareCoords(p, cj.size),
                strokeColor: cj.color,
                strokeOpacity: 0.8,
                strokeWeight: 1,
                map: gMap,
                fillColor: cj.color,
                fillOpacity: 0.20
            });
        } else { // assume circle for backward comp.
            var circle = {
                strokeColor: cj.color,
                strokeOpacity: 0.8,
                strokeWeight: 1,
                fillColor: cj.color,
                fillOpacity: 0.20,
                map: gMap,
                center: p,
                radius: parseFloat(cj.size),
            };
            return new google.maps.Circle(circle);
        }
    }
}
infoWindowClosed = true;

function mcpherAddMarker(cj) {
    var p = new google.maps.LatLng(cj.lat, cj.lng);
    cj.circle = createPoly(cj, p);

    var marker = new google.maps.Marker({
        position: p,
        map: gMap,
        title: cj.title
            //icon: 'https://www.google.com/mapfiles/marker_black.png'
    });
    cj.marker = marker;
    //cj.infowindow = null;

    if (cj.image) marker.setIcon(cj.image);
    if (cj.content) {
        var c = document.createElement("div");
        c.innerHTML = cj.content;


        cj.infowindow = new google.maps.InfoWindow({
            content: c
        });
        //google.maps.event.addListener(cj.marker, 'click', function() {
        //cj.infowindow = null;//cj.infowindow.open( null, null ); 

        //markerClick(gMap, cj);

        //});
        //}
        //cj = customMapping.afterMarkerCreate(cj);

        //return cj.marker;
        //}  /
        google.maps.event.addListener(cj.marker, "click", function() {
            markerClick(gMap, cj);
            //cj = customMapping.markerOnClick(cj);
            //if (cj.infowindow) cj.infowindow.close();
            //cj.infowindow.open(omap, cj.marker);
            //cj.infowindow.open (omap,cj.marker);
            //adjustZoom(cj);
            //cj = customMapping.markerAfterClick(cj);
            //cj.marker.setIcon('https://www.google.com/mapfiles/marker_green.png');
        });
    }
    cj = customMapping.afterMarkerCreate(cj);
    return cj.marker;
}

function markerClick(omap, cj) {
    cj = customMapping.markerOnClick(cj);
    cj.infowindow.open(omap, cj.marker);
    adjustZoom(cj);
    cj = customMapping.markerAfterClick(cj);
    cj.marker.setIcon('https://www.google.com/mapfiles/marker_green.png');
    //currentInfoWindow = cj.infowindow;
}

function adjustZoom(cj) {
    var z = mcpherData.framework && mcpherData.framework.control && mcpherData.framework.control.zoomlevelonselect ?
        parseInt(mcpherData.framework.control.zoomlevelonselect) : null;
    if (z) {
        if (gMap.getZoom() == z) {
            resetBoundingBox(true);
        } else {
            gMap.setZoom(z);
            gMap.setCenter(cj.marker.getPosition());
        }
    }

}

function mcpherGetqparams() {
    // get parameters
    var ps = {};
    location.search.substr(1).split("&")
        .forEach(function(p) {
            ps[p.split("=")[0]] = p.split("=")[1]
        });
    return ps;
}


function dealWithQuickLink(selValue) {
    if (vMap) {
        var nextSpot = vMap.spots[selValue];
        vMap.gotoAnotherSpot(vMap.currentSpot, nextSpot);
        if (vMap.provider == 'maps') nextSpot.createInfoWindow(0);
    } else {
        var cj = mcpherData.cJobject[selValue];
        if (cj.infowindow) {
            cj.infowindow.open(gMap, cj.marker);
        }
        adjustZoom(cj);
        return cj.infowindow;
    }
}

function findMySpot(cj) {
    // return the spot to which this cj belongs
    if (vMap) {
        for (var i = 0; i < vMap.spots.length; i++) {
            if (cj.SpotID === vMap.spots[i].spotId) return (vMap.spots[i]);
        }
        return null;
    } else
        return cj;

}

function dealWithCategories() {
    var combos = getAllCombos();
    // start by not showing anything, except where theres no categories
    var cj = mcpherData.cJobject;
    for (var j = 0; j < cj.length; j++) {
        var mySpot = findMySpot(cj[j]);
        mySpot.marker.setVisible(combos.length == 0);
        if (mySpot.circle) {
            mySpot.circle.setVisible(combos.length == 0);
        }
    }
    // need appear in each category

    for (var j = 0; j < cj.length && combos.length > 0; j++) {
        var show = [];
        for (var i = 0; i < combos.length; i++) {
            var selElem = document.getElementById('selectcategory' + i);
            if (selElem.value != 0) {
                // we have a filter operating
                var cats = createCategories(combos[i]);
                var target = cats[selElem.value];
                if (vMap) {
                    var c = cj[j];
                    if (c.hasOwnProperty(combos[i])) {
                        if (c[combos[i]] == target) show[i] = true;
                    }
                } else {
                    for (var k = 0; k < cj[j].category.length; k++) {
                        for (m in cj[j].category[k]) {
                            if (m == combos[i]) {
                                if (cj[j].category[k][m] == target) show[i] = true;
                            }
                        }
                    }
                }
            } else {
                show[i] = true;
            }
        }
        // show it?
        var x = 0;
        for (var k = 0; k < combos.length; k++) {
            if (show[k] === true) x++;
        }
        if (x == combos.length) {
            var mySpot = findMySpot(cj[j]);
            mySpot.marker.setVisible(true);

            if (mySpot.circle) {
                mySpot.circle.setVisible(true);
            }
        }
    }
    // reset to show only filtered spots
    quickLink();

}

function quickLink(selCategory) {
    var comboElem = document.getElementById('comboquicklink');

    if (comboElem) {
        if (selCategory == -1) { //first time in
            var selElem = document.createElement('select');
            selElem.id = "quickLinks";
        } else {
            var selElem = document.getElementById('quickLinks');
            selElem.options.length = 0;
        }
        // depends on type of app
        var cj = vMap ? vMap.spots : mcpherData.cJobject;

        mcpherAddEvent(selElem, "change", function() {
            dealWithQuickLink(selElem.value);
        }, false, true);

        for (var i = 0; i < cj.length; i++) {
            // only show visible spots
            var workit = true;
            if (cj[i].marker) workit = cj[i].marker.visible;
            if (workit) {
                var o = document.createElement('option');
                o.text = cj[i].title;
                o.value = i;
                selElem.value = o.value;
                try {
                    selElem.add(o, null);
                } catch (error) {
                    selElem.add(o);
                }
            }
        }

        comboElem.appendChild(selElem);
    }
    resetBoundingBox();
}

function createCategories(categoryName) {
    var cats = [];
    var cj = mcpherData.cJobject;
    for (var i = 0; i < cj.length; i++) {
        // find the matching object
        if (vMap) {
            if (cj[i].hasOwnProperty(categoryName)) {
                if (cats.indexOf(cj[i][categoryName]) == -1) cats.push(cj[i][categoryName]);
            }
        } else {
            for (var j = 0; j < cj[i].category.length; j++) {
                if (cj[i].category[j].hasOwnProperty(categoryName)) {
                    if (cats.indexOf(cj[i].category[j][categoryName]) == -1) cats.push(cj[i].category[j][categoryName]);
                }
            }

        }

    }
    cats.sort().splice(0, 0, 'all categories');
    return cats;
}

function category() {

    var comboElem = document.getElementById('combocategory');
    if (comboElem) {
        var combos = getAllCombos();
        for (var j = 0; j < combos.length; j++) {
            var selElem = document.createElement('select');
            selElem.id = "selectcategory" + j;
            var cats = createCategories(combos[j]);
            mcpherAddEvent(selElem, "change", function() {
                dealWithCategories(selElem);
            }, false, true);

            for (var i = 0; i < cats.length; i++) {
                var o = document.createElement('option');
                o.text = cats[i];
                o.value = i;
                try {
                    selElem.add(o, null);
                } catch (error) {
                    selElem.add(o);
                }
            }
            var d = document.createElement('span');
            var t = document.createTextNode(combos[j]);
            d.appendChild(t);
            d.appendChild(selElem);
            comboElem.appendChild(d);

        }
    }
}

function getAllCombos() {
    var combos = [];
    if (vMap) {
        for (var i = 0; vMap.framework.spots.categories && i < vMap.framework.spots.categories.length; i++)
            combos.push(vMap.framework.spots.categories[i]);
    } else {
        var cj = mcpherData.cJobject;
        for (var i = 0; i < cj.length; i++) {
            if (isArray(cj[i].category)) {
                for (var j = 0; j < cj[i].category.length; j++) {
                    for (k in cj[i].category[j])
                        if (combos.indexOf(k) == -1) {
                            combos.push(k);
                        }
                }
            }
        }
    }
    return combos;
}

// this section is functions as far as after /head

function mcpherAddEvent(o, e, f, b, complain) {
    // because IE is different
    if (o.addEventListener) return (o.addEventListener(e, f, b));

    else if (o.attachEvent) return (o.attachEvent('on' + e, f));
    else if (complain) alert('browser doesnt support events');

    return (null);

}

var mcpherData;
var gMap;
var vMap;
var customMapping = new cCustomMapping({
    type: 'default'
});
html {
    height: 100%
}
body {
    height: 100%;
    margin: 0;
    padding: 0;
    color: Gray;
    background-color: WhiteSmoke;
}
#map_canvas {
    height: 100%
}
.mcquicklink {
    margin-left: 20px;
    margin-right: 20px;
    display: inline;
    font-family: sans-serif;
    float: right;
}
.mccategory {
    margin-left: 20px;
    margin-right: 20px;
    display: inline;
    font-family: sans-serif;
    float: right;
}
.mcheading {
    display: inline;
    font-family: sans-serif;
}
<html>

<head>
    <meta name='viewport' content='initial-scale=1.0, user-scalable=no' />
    <style type='text/css'>
    </style>
    <script type='text/javascript' src='http://maps.googleapis.com/maps/api/js?sensor=false'></script>
    <script type='text/javascript' src='http://www.google.com/jsapi'></script>
    <script type='text/javascript' src='http://apis.google.com/js/client.js'></script>
    <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>

    <script type='text/javascript' src='http://xliberation.com/t/gas/js/scriptdbapi.js'></script>
    <script type='text/javascript' src='http://xliberation.com/t/gas/js/firsttime.js'></script>
    <script type='text/javascript' src='http://xliberation.com/cdn/js/ccookie.js'></script>
</head>

<body onload="initialize()">
    <div id="comboquicklink" class="mcquicklink">Quick Links</div>
    <div id="combocategory" class="mccategory"></div>
    <div id="heading" class="mcheading">Tax Sale Map by Chrisol Real-estate
        <a href="http://phillyanyhouse.com">phillyanyhouse.com</a>
    </div>
    <div id="map_canvas" style="width: 100%; height: 90%"></div>

</body>

</html>

可能最简单的方法是修改 markerOnClick 函数,在这种情况下,一旦下一个信息 window 将被初始化,当前 (currentInfoWindow) 将被关闭:

self.markerOnClick = function (cj) {
        // when a marker is clicked
        if (currentInfoWindow) currentInfoWindow.close();  //close current info window  
        currentInfoWindow = cj.infowindow; //save current info window
        return cj;
};