var buscaAjaxEmAndamento = null; var localidadesAjax = null; $(document).ready(function () { // $('#preco-min, #preco-max, #area-max, #area-min').selectpicker('destroy').editableSelect({ effects: 'default', filter: false }); var cmd = $("#cmd").val(); $('#transacao').change(function () { trocarTiposImoveis(); trocarFaixaValores(); if (cmd == "imoveis" || cmd == "imovel") { // se página de resultado ou ficha do imóvel, já refazer a busca buscarImoveis(1); // REFAZ A BUSCA, SEM PEDIR CLIQUE NO BOTÃO DE BUSCA } }); $("#tipo-imovel").change(function () { if (!$("#tipo-imovel").val()) { $(".buscador").find('.buscar-imoveis').find("button").addClass("erro"); } else { $(".buscador").find('.buscar-imoveis').find("button").removeClass("erro"); } if (cmd == "imoveis" || cmd == "imovel") { // se página de resultado ou ficha do imóvel, já refazer a busca buscarImoveis(2); // REFAZ A BUSCA, SEM PEDIR CLIQUE NO BOTÃO DE BUSCA } }); $('.precoMinimo,.precoMaximo').maskedInput("000.000.000.000.000,00", {reverse: true}); var xhr; $('#localidade').autoComplete({ minChars: 3, source: function (term, response) { try { xhr.abort(); } catch (e) { console.log("error ajax auto complete", e.message); } xhr = $.post('/ajax-pegar-localidades', {localidade: term}, function (data) { response(data); }); }, renderItem: function (item, search) { search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi"); response = null; if (item.bairros !== "" && item.bairros !== undefined && (item.bairros.length > 0)) { response = "
Bairros
"; zebrado_0 = null; zn_0 = 0; for (var i = 0; i < item.bairros.length; i++) { if (zn_0 % 2 === 0) { zebrado_0 = 'par'; } else { zebrado_0 = 'impar'; } response += '
' + item.bairros[i].localidade.replace(re, "$1") + '
'; zn_0++; } } if (item.cidades !== "" && item.cidades !== undefined && (item.cidades.length > 0)) { response = "
Cidades
"; zebrado_1 = null; zn_1 = 0; for (var i = 0; i < item.cidades.length; i++) { if (zn_1 % 2 === 0) { zebrado_1 = 'par'; } else { zebrado_1 = 'impar'; } response += '
' + item.cidades[i].localidade.replace(re, "$1") + '
'; zn_1++; } } return response; }, onSelect: function (e, term, item) { buscarImoveis(3); } }); $(".buscar-imoveis").change(function () { var cmd = $("#cmd").val(); if (cmd == "imoveis" || cmd == "imovel") { // se página de resultado ou ficha do imóvel, já refazer a busca buscarImoveis(4); } }); $("body").on('click', '#buscar', function(){ buscarImoveis("b"); }); $("#localidade").keyup(function () { if ($(this).val().length > 3) { $("#localidade").removeClass("erro"); } }); $(".buscar").click(function () { buscarImoveis(6); }); $("#pesquisar-codigo").click(function () { var obj = $("#codigo-buscar"); if (obj.val() == "") { obj.addClass("erro"); } else { obj.removeClass("erro"); buscarImoveis("c"); } }); $(".banner").click(function() { var local = $(this).attr("local"); $.post("ajax-registrar-clique-banner", {'id': $(this).attr("id"), 'local': $(this).attr("local"), 'url': document.location.href}, function (url) { // direcionar para a página do banner if(url != ""){ if(local == "1") { window.location = url; } else { window.open(url, '_blank'); } } } ); ; }); $(".registrar-clique").click(function() { $.post("ajax-registrar-clique-resultado-busca", {'pag': 'res', 'id-imovel': $("#id_imovel").val(), 'id': $(this).attr("id")}, function() { }); }); }); function carregarVerTelefone() { $('.b-contatar').find('#ver-telefone').on('click', function () { $(this).addClass("ativo"); $(this).find('.texto').hide('slow'); $(this).find('.telefones').show('slow'); }); } function maisFiltros() { $('#mais-filtros').on('click', function () { $('.mais-filtros').toggle('slow'); if ($(this).text() == 'MAIS FILTROS') { $(this).text('MENOS FILTROS'); $(".buscador").addClass("area-mais-filtros"); } else { $(this).text('MAIS FILTROS'); $(".buscador").removeClass("area-mais-filtros"); } }); } function buscarImoveis(controle, parametro) { $(".buscar").attr('disabled', 'disabled'); var cmd = $("#cmd").val(); var erros = ""; if (!$("#transacao").val()) { $("#transacao").addClass("erro"); erros += ",transação"; } else { $("#transacao").removeClass("erro"); } if ( ($("#tipo-imovel").val() == "" || $("#tipo-imovel").val() == "0") && cmd != "imobiliaria" ) { $(".buscador").find('.buscar-imoveis').find("button").addClass("erro"); erros += ",localidade"; } else { $(".buscador").find('.buscar-imoveis').find("button").removeClass("erro"); } if (!$("#localidade").val()) { $("#localidade").addClass("erro"); erros += ",localidade"; } else { if($("#localidade").val().split(',')[1] != undefined && $("#localidade").val().split(',')[1].trim() != ''){ $("#localidade").removeClass("erro"); }else{ $("#localidade").addClass("erro"); erros += ",localidade"; } } if (erros != "") { $("#msg-erro").html("Por favor, preencha os dados faltantes: " + erros.substr(1)); $("#erro-falta-de-dados").fadeTo(2000, 500).slideUp(500, function () { $("#erro-falta-de-dados").slideUp(500); }); } else { if (controle == undefined) { controle = (cmd == "imoveis" ? "" : "h"); // clique no botão 'BUSCAR' da página principal OU no imóvel } fazerBuscaImoveis(controle, parametro); } $(".buscar").removeAttr('disabled'); } function removerFiltroBuscador(filtro, naoRefazerBusca) { naoRefazerBusca = naoRefazerBusca ? true : false; ajustarFiltroEliminadoNaTela(filtro); var filtros = ""; var idsTiposImoveis = ""; var idsBairros = ""; var idsImobiliarias = ""; var quartos = ""; var vagasGaragem = ""; var banheiros = ""; var outrasOpcoes = ""; $(".filtro-aplicado").each(function () { var valor = $(this).attr("value"); if (!valor || (valor && valor != filtro)) { if (valor.substr(0, 4) == "tip-") { idsTiposImoveis += ";" + valor.substr(4); } else if (valor.substr(0, 4) == "bai-") { idsBairros += ";" + valor.substr(4); } else if (valor.substr(0, 4) == "imb-") { idsImobiliarias += ";" + valor.substr(4); } else if (valor.substr(0, 4) == "qto-") { quartos += ";" + valor.substr(4); } else if (valor.substr(0, 4) == "vag-") { vagasGaragem += ";" + valor.substr(4); } else if (valor.substr(0, 4) == "bnh-") { banheiros += ";" + valor.substr(4); } else if (valor.substr(0, 4) == "out-") { outrasOpcoes += ";" + valor.substr(4); } else if (valor.substr(0, 4) == "vli-" || valor.substr(0, 4) == "vls-" || valor.substr(0, 4) == "ari-" || valor.substr(0, 4) == "ars-") { filtros += "," + valor.substr(0, 3) + "=" + valor.substr(4); } else { filtros += "," + valor + "=" + $(this).html().trim(); } } }); if (idsTiposImoveis != "") { filtros += ",idtip=" + idsTiposImoveis.substr(1); } if (idsBairros != "") { filtros += ",idbai=" + idsBairros.substr(1); } if (idsImobiliarias != "") { filtros += ",idimb=" + idsImobiliarias.substr(1); } if (quartos != "") { filtros += ",qto=" + quartos.substr(1); } if (vagasGaragem != "") { filtros += ",vag=" + vagasGaragem.substr(1); } if (banheiros != "") { filtros += ",bnh=" + banheiros.substr(1); } if (outrasOpcoes != "") { filtros += ",out=" + outrasOpcoes.substr(1); } if (!naoRefazerBusca) { fazerBuscaImoveis("f", filtros.substr(1)); } } function ajustarFiltroEliminadoNaTela(filtro) { if (filtro.substr(0, 4) == "vli-") { $("#preco-min").val($("#preco-min option:first").val()); } else if (filtro.substr(0, 4) == "vls-") { $("#preco-max").val($("#preco-max option:first").val()); } else if (filtro.substr(0, 4) == "ari-") { $("#area-min").val($("#area-min option:first").val()); } else if (filtro.substr(0, 4) == "ars-") { $("#area-max").val($("#area-max option:first").val()); } else if (filtro.substr(0, 4) == "qto-") { ajustarFiltroSelectNaTela("quartos", filtro); } else if (filtro.substr(0, 4) == "vag-") { ajustarFiltroSelectNaTela("vagas", filtro); } else if (filtro.substr(0, 4) == "bnh-") { ajustarFiltroSelectNaTela("banheiros", filtro); } else if (filtro.substr(0, 4) == "out-") { $("#" + filtro).prop("checked", false); } } function ajustarFiltroSelectNaTela(id, filtro) { $(('#' + id) + ' :selected').each(function () { if ($(this).attr("id") == filtro) { $(this).prop("selected", false); } }); $(('#' + id)).selectpicker("refresh"); } function buscaImoveisDeCoordenadas(coordenadas) { buscarImoveis("a", coordenadas); } function buscarImoveisMapa() { buscarImoveis("m"); } function adicionarCliqueOrdenacao() { $('#ordenacao').change(function () { buscarImoveis("o"); }); } function adicionarCliquesImoveis() { $(document).find(".imovel").each( function (i) { $(this).find('.ir-ficha-imovel').each( function () { $(this).on('mouseup', function () { var idImovel = pegarIdImovel($(this)); var url = pegarUrlImovel($(this)); $.post("ajax-registrar-clique-resultado-busca", {'pag': 'res', 'id-imovel': idImovel, 'id': $(this).attr("id")}, function () { } ); }); } ); } ); } $(function () { $('#refinar-busca').click(function () { var btn = $(this); btn.html("Esconder Refinar Busca").css({ cursor: "wait" }); $(".refinar").slideToggle("slow", function () { btn.css({ cursor: "pointer" }); if ($(this).is(":hidden")) { btn.html("Refinar Busca"); } }); }); /* End Refina Busca*/ $(window).on('resize', function () { if (!$(".toggle").is(":visible") && !$(".refinar").is(':visible')) { $(".refinar").css({'display': ''}); } }); var tfocus = false; var localidadeAnterior = $('#localidade').val(); $('#localidade').on("focus, click", function (e) { if ($(this).val().length > 0 && tfocus || tfocus === false) { localidadeAnterior = $('#localidade').val(); $(this).val(""); } e.stopPropagation(); $(this).popover({ trigger: 'manual', container: '.input-group-icon', template: '', html: true, content: function () { return $('#busca_popover').html(); } }); if ($(this).val().length <= 0) { $(this).popover('show'); } }).keyup(function (e) { e.stopPropagation(); if ($(this).val().length >= 1) { $(this).popover('hide'); } }).blur(function (e) { e.stopPropagation(); tfocus = true; // $('#localidade').popover("destroy"); $(this).popover('hide'); if ($(this).val().length == 0) { $(this).val(localidadeAnterior); } }), $(".ir-para-busca").click(function () { irPara(SITE + "/imoveis/" + $(this).attr("alvo")); }), $(".ir-para-topo").click(function () { irParaTopo(); }), $(".posicionar-buscador").click(function () { var link_text = $(this).text(); $("#localidade").popover({ trigger: 'manual', container: '.input-group-icon', template: '', html: true, content: function () { $('#busca_popover_rodape').find("p strong").text(link_text); return $('#busca_popover_rodape').html(); } }).keyup(function (e) { e.stopPropagation(); if ($(this).val().length >= 1) { $(this).popover('hide'); } }).blur(function (e) { e.stopPropagation(); $(this).popover('destroy'); }); $("#localidade").popover('show'); posicionarBuscador($(this).attr("id-transacao"), "#menu-cabecalho"); }); }); function posicionarBuscador(idTransacao, posicao) { $('#transacao option[value=' + idTransacao + ']').attr('selected', 'selected'); $('#transacao').selectpicker("refresh"); trocarTiposImoveis(); irParaTopo(posicao); $("#localidade").focus(); } function trocarTiposImoveis() { // $.ajaxSetup({async: false}); $.post("ajax-pegar-tipos-imoveis", {'transacao': $("#transacao").val(), 'tipo-imovel': $("#tipo-imovel").val(), 'tipo': $("#tipo-imovel").attr("tipo")}, function (html) { $("#tipo-imovel").html(html); } ); } function trocarFaixaValores() { $.post("ajax-pegar-faixa-valores", {'transacao': $("#transacao").val()}, function (html) { // $("#preco-min, #preco-max").editableSelect('destroy'); // $("#preco-min, #preco-max").html(html); // $("#preco-min, #preco-max").editableSelect({ effects: 'default', filter: false }); $("#preco-min").html(html).selectpicker('refresh'); $("#preco-max").html(html).selectpicker('refresh'); } ); } function pegarIdImovel(obj) { while (($(obj) && $(obj).attr("id-imovel")) == undefined) { obj = $(obj).parent(); } return $(obj).attr("id-imovel"); } function pegarUrlImovel(obj) { while (!$(obj).hasClass("imovel")) { obj = $(obj).parent(); } var url = $(obj).find(".url").attr("url-imovel"); if (url != undefined && url != "/?") { return url; } else { return ""; } } function fazerBuscaImoveis(controle, parametro) { controle = (controle != undefined ? controle : ""); $('.bloco-aguarde').show(); /* * controle: * nada: faz a busca na página 1 e atualiza toda a página de resultado * a: busca imóveis nas coordenadas passadas em 'parametro' * b: busca vinda do botão 'buscar imóvel' * c: busca imóveis com código(imobiliária) passado em 'parametro' * f: busca imóveis com os filtros passados em 'parametro' * h: busca vinda da home * l: busca vinda do 'limpar filtros' * m: busca do mapa * 2: quando trocou o select do tipo de imóvel */ if (controle != "+" || (controle == "+" && !buscaAjaxEmAndamento)) { if (buscaAjaxEmAndamento) { buscaAjaxEmAndamento.abort(); buscaAjaxEmAndamento = null; } var filtrosAplicar = ""; if (controle == "a") { coordenadasMapa = parametro; } else { coordenadasMapa = $("#coordenadasMapa").val(); } var tipoImovel = ""; $('#tipo-imovel :selected').each(function () { if ($(this).val().trim() != "") { tipoImovel += "," + ($(this).val().trim()); } }); tipoImovel = tipoImovel.substr(1); var tipo = $('#tipo-imovel').attr("tipo"); var idsTiposImoveis = ""; // NÃO FUNCIONOU // if(controle != "b") { // clicado no botão 'buscar'... pegar os tipos de imóveis do grupo // $(".filtro-aplicado").each(function () { // pegar dos filtros aplicados // var valor = $(this).attr("value"); // if (valor.substr(0, 4) == "tip-") { // idsTiposImoveis += ";" + valor.substr(4); // } // }); // } idsTiposImoveis = idsTiposImoveis.substr(1); if (controle == "f") { // aplicar na busca somente os filtros da sessão 'filtros aplicados' filtrosAplicar = parametro + ",tip=" + tipoImovel + ",tipi=" + tipo; } else { var cmd = $('#cmd').val(); var transacao = $('#transacao').val(); var localidade = $('#localidade').val(); var idImobiliaria = $('#id-imobiliaria').val(); // página de imobiliárias idImobiliaria = idImobiliaria == undefined ? "" : idImobiliaria; if (controle == "b" || controle == "h") { // vindo da home ou da página de imobiliárias //$("#lista-imoveis").html("Aguarde o carregamento dos imóveis..."); $.post("ajax-montar-url-busca", {'transacao': transacao, 'tipo-imovel': tipoImovel, 'localidade': localidade, 'tipo': tipo, 'cmd': cmd, 'id-imobiliaria': idImobiliaria}, function (url) { irPara(SITE + "/" + url); } ); } else { var valorMinimo = (null != $("#preco-min").val()) ? $("#preco-min").val().replaceAll(".", "").replaceAll(",",".") : ''; console.log('VM: '+ valorMinimo); var valorMaximo = (null != $("#preco-max").val()) ? $("#preco-max").val().replaceAll(".", "").replaceAll(",",".") : ''; var areaMinima = (null != $("#area-min").val()) ? $("#area-min").val().replaceAll(".", "").replaceAll(",",".") : ''; var areaMaxima = (null != $("#area-max").val()) ? $("#area-max").val().replaceAll(".", "").replaceAll(",",".") : ''; var dormitorios = ""; $('#quartos :selected').each(function () { if ($(this).val().trim() != "") { dormitorios += (dormitorios == "" ? "" : ";") + ($(this).val().trim()); } }); var vagasGaragem = ""; $('#vagas :selected').each(function () { if ($(this).val().trim() != "") { vagasGaragem += (vagasGaragem == "" ? "" : ";") + ($(this).val().trim()); } }); var banheiros = ""; $('#banheiros :selected').each(function () { if ($(this).val().trim() != "") { banheiros += (banheiros == "" ? "" : ";") + ($(this).val().trim()); } }); var somenteCodigo = ""; var codigoBuscar = ""; if (controle == "c") { somenteCodigo = $("#somente-codigo").prop("checked"); codigoBuscar = $("#codigo-buscar").val(); } var outrasCaracteristicas = ""; $(".buscar").each( function () { outrasCaracteristicas += $(this).prop("checked") ? "1" : "0"; } ); } } if (controle == "+") { var pagina = $("#pagina").val(); pagina++; } else { pagina = 1; } $("#pagina").val(pagina); $("#pag").html(pagina); var ordenacao = $("#ordenacao").val(); var idLogBusca = $("#idLogBusca").val(); var visualizacao = $(".visualizacao.visualizacao-ativa").attr("id"); if (visualizacao == 'mapa' && coordenadasMapa == '') controle = 'm'; // //----------------------- if(controle != "f") { var idsBairros = ""; var idsImobiliarias = ""; var outrasOpcoes = ""; var filtrosAplicar = ",ord=" + ordenacao; if(valorMinimo != "") { filtrosAplicar += ",vli=" + valorMinimo; } if(valorMaximo != "") { filtrosAplicar += ",vls=" + valorMaximo; } if(areaMinima != "") { filtrosAplicar += ",ari=" + areaMinima; } if(areaMaxima != "") { filtrosAplicar += ",ars=" + areaMaxima; } if(transacao != "") { filtrosAplicar += ",trs=" + transacao; } if(outrasCaracteristicas != "") { filtrosAplicar += ",out1=" + outrasCaracteristicas; } if(tipo.toLowerCase() == "grupo") { filtrosAplicar += ",idgrp=" + tipoImovel; } if(idImobiliaria != "") { filtrosAplicar += ",idimb=" + idImobiliaria; } if(idLogBusca != "") { filtrosAplicar += ",idbus=" + idLogBusca; } if(localidade != "") { filtrosAplicar += ",loc=" + localidade.replace(",",";"); } $(".filtro-aplicado").each(function () { var valor = $(this).attr("value"); if (valor.substr(0, 4) == "tip-") { idsTiposImoveis += (idsTiposImoveis == "" ? "" : ";") + valor.substr(4); } else if (valor.substr(0, 4) == "bai-") { idsBairros += (idsBairros == "" ? "" : ";") + valor.substr(4); } else if (valor.substr(0, 4) == "imb-") { idsImobiliarias += (idsImobiliarias == "" ? "" : ";") + valor.substr(4); } else if (valor.substr(0, 4) == "vli-" || valor.substr(0, 4) == "vls-" || valor.substr(0, 4) == "ari-" || valor.substr(0, 4) == "ars-") { filtrosAplicar += (filtrosAplicar == ""? "" : ",") + valor.substr(0, 3) + "=" + valor.substr(4); } else if (localidade == "" && (valor == "cid" || valor == "uf")) { // pegar cidade e uf se não encontrou na caixa de texto filtrosAplicar += (filtrosAplicar == ""? "" : ",") + valor + "=" + $(this).html().trim(); } }); if (idsTiposImoveis != "" && controle != "2") { // ao trocar o tipo de imóvel, não considerar o que tinha nos filtros filtrosAplicar += ",idtip=" + idsTiposImoveis; } if (idsBairros != "") { filtrosAplicar += ",idbai=" + idsBairros; } if (idsImobiliarias != "") { filtrosAplicar += ",idimb=" + idsImobiliarias; } if (dormitorios != "") { filtrosAplicar += ",qto=" + dormitorios; } if (vagasGaragem != "") { filtrosAplicar += ",vag=" + vagasGaragem; } if (banheiros != "") { filtrosAplicar += ",bnh=" + banheiros; } if (outrasOpcoes != "") { filtrosAplicar += ",out=" + outrasOpcoes; } if(codigoBuscar != "") { filtrosAplicar += ",cod=" + codigoBuscar; if(somenteCodigo === true) { filtrosAplicar += ",scod=true"; } } } // //----------------------- if (controle != "m") { // $("#lista-imoveis").html("Aguarde o carregamento dos imóveis..."); } buscaAjaxEmAndamento = $.post("ajax-buscar-imoveis", // {'url': document.location.href, 'transacao': transacao, 'tipo-imovel': tipoImovel, 'ids-tipos-imoveis': idsTiposImoveis, 'tipo': tipo, 'localidade': localidade, 'valor-minimo': valorMinimo, 'valor-maximo': valorMaximo, 'area-minima': areaMinima, 'area-maxima': areaMaxima, 'dormitorios': dormitorios, 'vagas-garagem': vagasGaragem, 'banheiros': banheiros, 'pagina': pagina, 'outras-caracteristicas': outrasCaracteristicas, 'codigo-buscar': codigoBuscar, 'somente-codigo': somenteCodigo, 'controle': controle, 'filtros': filtrosAplicar, 'coordenadas-mapa': coordenadasMapa, 'ordenacao': ordenacao, 'visualizacao': visualizacao, 'id-log-busca': idLogBusca, 'id-imobiliaria': idImobiliaria}, {'url': document.location.href, 'pagina': pagina, 'controle': controle, 'filtros': filtrosAplicar, 'coordenadas-mapa': coordenadasMapa, 'ordenacao': ordenacao, 'visualizacao': visualizacao}, function (html) { if (controle == "m") { // mapa mapa = null; initMap(html.imoveis); // função está no arquivo resultado-busca.js $('.lista-filtros-aplicados').html(html.filtros); var imoveis_encontrados = ''; if (html.qtImoveisEncontrados == 0) imoveis_encontrados = 'Nenhum imóvel encontrado'; else if (html.qtImoveisEncontrados == 1) imoveis_encontrados = '1 imóvel encontrado'; else imoveis_encontrados = html.qtImoveisEncontrados + ' imóveis encontrados'; $('.imoveis-encontrados').html(imoveis_encontrados); } else if (controle == "+") { // paginação ou ordenação $("#lista-imoveis").append(html); $(document).find('.super-destaque').find('.left').click(); // dispara click para carregar todas as imagens do super destaque } else { $("#resultado-busca").html(html); $(document).find('.super-destaque').find('.left').click(); // dispara click para carregar todas as imagens do super destaque var url = document.location.href; var novaURL = $("#novaURL").val(); if (url != SITE + "/" +novaURL) { $(document).prop("title",$("#tituloPagina").val()); if(novaURL != undefined && novaURL.trim() != ''){ window.history.pushState("", "", SITE + "/" +novaURL); } } } buscaAjaxEmAndamento = null; $('select:not(.no-select2)').selectpicker("refresh"); loadImoveis.hide(); } ); } } // local https://github.com/googlemaps/v3-utility-library/blob/master/markerclusterer/src/markerclusterer.js // ==ClosureCompiler== // @compilation_level ADVANCED_OPTIMIZATIONS // @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/maps/google_maps_api_v3_3.js // ==/ClosureCompiler== /** * @name MarkerClusterer for Google Maps v3 * @version version 1.0.1 * @author Luke Mahe * @fileoverview * The library creates and manages per-zoom-level clusters for large amounts of * markers. *
* This is a v3 implementation of the * v2 MarkerClusterer. */ /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A Marker Clusterer that clusters markers. * * @param {google.maps.Map} map The Google map to attach to. * @param {Array.=} opt_markers Optional markers to add to * the cluster. * @param {Object=} opt_options support the following options: * 'gridSize': (number) The grid size of a cluster in pixels. * 'maxZoom': (number) The maximum zoom level that a marker can be part of a * cluster. * 'zoomOnClick': (boolean) Whether the default behaviour of clicking on a * cluster is to zoom into it. * 'averageCenter': (boolean) Wether the center of each cluster should be * the average of all markers in the cluster. * 'minimumClusterSize': (number) The minimum number of markers to be in a * cluster before the markers are hidden and a count * is shown. * 'styles': (object) An object that has style properties: * 'url': (string) The image url. * 'height': (number) The image height. * 'width': (number) The image width. * 'anchor': (Array) The anchor position of the label text. * 'textColor': (string) The text color. * 'textSize': (number) The text size. * 'backgroundPosition': (string) The position of the backgound x, y. * @constructor * @extends google.maps.OverlayView */ function MarkerClusterer(map, opt_markers, opt_options) { // MarkerClusterer implements google.maps.OverlayView interface. We use the // extend function to extend MarkerClusterer with google.maps.OverlayView // because it might not always be available when the code is defined so we // look for it at the last possible moment. If it doesn't exist now then // there is no point going ahead :) this.extend(MarkerClusterer, google.maps.OverlayView); this.map_ = map; /** * @type {Array.} * @private */ this.markers_ = []; /** * @type {Array.} */ this.clusters_ = []; this.sizes = [53, 56, 66, 78, 90]; /** * @private */ this.styles_ = []; /** * @type {boolean} * @private */ this.ready_ = false; var options = opt_options || {}; /** * @type {number} * @private */ this.gridSize_ = options['gridSize'] || 60; /** * @private */ this.minClusterSize_ = options['minimumClusterSize'] || 2; /** * @type {?number} * @private */ this.maxZoom_ = options['maxZoom'] || null; this.styles_ = options['styles'] || []; /** * @type {string} * @private */ this.imagePath_ = options['imagePath'] || this.MARKER_CLUSTER_IMAGE_PATH_; /** * @type {string} * @private */ this.imageExtension_ = options['imageExtension'] || this.MARKER_CLUSTER_IMAGE_EXTENSION_; /** * @type {boolean} * @private */ this.zoomOnClick_ = true; if (options['zoomOnClick'] != undefined) { this.zoomOnClick_ = options['zoomOnClick']; } /** * @type {boolean} * @private */ this.averageCenter_ = false; if (options['averageCenter'] != undefined) { this.averageCenter_ = options['averageCenter']; } this.setupStyles_(); this.setMap(map); /** * @type {number} * @private */ this.prevZoom_ = this.map_.getZoom(); // Add the map event listeners var that = this; google.maps.event.addListener(this.map_, 'zoom_changed', function() { // Determines map type and prevent illegal zoom levels var zoom = that.map_.getZoom(); var minZoom = that.map_.minZoom || 0; var maxZoom = Math.min(that.map_.maxZoom || 100, that.map_.mapTypes[that.map_.getMapTypeId()].maxZoom); zoom = Math.min(Math.max(zoom,minZoom),maxZoom); if (that.prevZoom_ != zoom) { that.prevZoom_ = zoom; that.resetViewport(); } }); google.maps.event.addListener(this.map_, 'idle', function() { that.redraw(); }); // Finally, add the markers if (opt_markers && (opt_markers.length || Object.keys(opt_markers).length)) { this.addMarkers(opt_markers, false); } } /** * The marker cluster image path. * * @type {string} * @private */ MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ = '../images/m'; /** * The marker cluster image path. * * @type {string} * @private */ MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_EXTENSION_ = 'png'; /** * Extends a objects prototype by anothers. * * @param {Object} obj1 The object to be extended. * @param {Object} obj2 The object to extend with. * @return {Object} The new extended object. * @ignore */ MarkerClusterer.prototype.extend = function(obj1, obj2) { return (function(object) { for (var property in object.prototype) { this.prototype[property] = object.prototype[property]; } return this; }).apply(obj1, [obj2]); }; /** * Implementaion of the interface method. * @ignore */ MarkerClusterer.prototype.onAdd = function() { this.setReady_(true); }; /** * Implementaion of the interface method. * @ignore */ MarkerClusterer.prototype.draw = function() {}; /** * Sets up the styles object. * * @private */ MarkerClusterer.prototype.setupStyles_ = function() { if (this.styles_.length) { return; } for (var i = 0, size; size = this.sizes[i]; i++) { this.styles_.push({ url: this.imagePath_ + (i + 1) + '.' + this.imageExtension_, height: size, width: size }); } }; /** * Fit the map to the bounds of the markers in the clusterer. */ MarkerClusterer.prototype.fitMapToMarkers = function() { var markers = this.getMarkers(); var bounds = new google.maps.LatLngBounds(); for (var i = 0, marker; marker = markers[i]; i++) { bounds.extend(marker.getPosition()); } this.map_.fitBounds(bounds); }; /** * Sets the styles. * * @param {Object} styles The style to set. */ MarkerClusterer.prototype.setStyles = function(styles) { this.styles_ = styles; }; /** * Gets the styles. * * @return {Object} The styles object. */ MarkerClusterer.prototype.getStyles = function() { return this.styles_; }; /** * Whether zoom on click is set. * * @return {boolean} True if zoomOnClick_ is set. */ MarkerClusterer.prototype.isZoomOnClick = function() { return this.zoomOnClick_; }; /** * Whether average center is set. * * @return {boolean} True if averageCenter_ is set. */ MarkerClusterer.prototype.isAverageCenter = function() { return this.averageCenter_; }; /** * Returns the array of markers in the clusterer. * * @return {Array.} The markers. */ MarkerClusterer.prototype.getMarkers = function() { return this.markers_; }; /** * Returns the number of markers in the clusterer * * @return {Number} The number of markers. */ MarkerClusterer.prototype.getTotalMarkers = function() { return this.markers_.length; }; /** * Sets the max zoom for the clusterer. * * @param {number} maxZoom The max zoom level. */ MarkerClusterer.prototype.setMaxZoom = function(maxZoom) { this.maxZoom_ = maxZoom; }; /** * Gets the max zoom for the clusterer. * * @return {number} The max zoom level. */ MarkerClusterer.prototype.getMaxZoom = function() { return this.maxZoom_; }; /** * The function for calculating the cluster icon image. * * @param {Array.} markers The markers in the clusterer. * @param {number} numStyles The number of styles available. * @return {Object} A object properties: 'text' (string) and 'index' (number). * @private */ MarkerClusterer.prototype.calculator_ = function(markers, numStyles) { var index = 0; var count = markers.length; var dv = count; while (dv !== 0) { dv = parseInt(dv / 10, 10); index++; } index = Math.min(index, numStyles); return { text: count, index: index }; }; /** * Set the calculator function. * * @param {function(Array, number)} calculator The function to set as the * calculator. The function should return a object properties: * 'text' (string) and 'index' (number). * */ MarkerClusterer.prototype.setCalculator = function(calculator) { this.calculator_ = calculator; }; /** * Get the calculator function. * * @return {function(Array, number)} the calculator function. */ MarkerClusterer.prototype.getCalculator = function() { return this.calculator_; }; /** * Add an array of markers to the clusterer. * * @param {Array.} markers The markers to add. * @param {boolean=} opt_nodraw Whether to redraw the clusters. */ MarkerClusterer.prototype.addMarkers = function(markers, opt_nodraw) { if (markers.length) { for (var i = 0, marker; marker = markers[i]; i++) { this.pushMarkerTo_(marker); } } else if (Object.keys(markers).length) { for (var marker in markers) { this.pushMarkerTo_(markers[marker]); } } if (!opt_nodraw) { this.redraw(); } }; /** * Pushes a marker to the clusterer. * * @param {google.maps.Marker} marker The marker to add. * @private */ MarkerClusterer.prototype.pushMarkerTo_ = function(marker) { marker.isAdded = false; if (marker['draggable']) { // If the marker is draggable add a listener so we update the clusters on // the drag end. var that = this; google.maps.event.addListener(marker, 'dragend', function() { marker.isAdded = false; that.repaint(); }); } this.markers_.push(marker); }; /** * Adds a marker to the clusterer and redraws if needed. * * @param {google.maps.Marker} marker The marker to add. * @param {boolean=} opt_nodraw Whether to redraw the clusters. */ MarkerClusterer.prototype.addMarker = function(marker, opt_nodraw) { this.pushMarkerTo_(marker); if (!opt_nodraw) { this.redraw(); } }; /** * Removes a marker and returns true if removed, false if not * * @param {google.maps.Marker} marker The marker to remove * @return {boolean} Whether the marker was removed or not * @private */ MarkerClusterer.prototype.removeMarker_ = function(marker) { var index = -1; if (this.markers_.indexOf) { index = this.markers_.indexOf(marker); } else { for (var i = 0, m; m = this.markers_[i]; i++) { if (m == marker) { index = i; break; } } } if (index == -1) { // Marker is not in our list of markers. return false; } marker.setMap(null); this.markers_.splice(index, 1); return true; }; /** * Remove a marker from the cluster. * * @param {google.maps.Marker} marker The marker to remove. * @param {boolean=} opt_nodraw Optional boolean to force no redraw. * @return {boolean} True if the marker was removed. */ MarkerClusterer.prototype.removeMarker = function(marker, opt_nodraw) { var removed = this.removeMarker_(marker); if (!opt_nodraw && removed) { this.resetViewport(); this.redraw(); return true; } else { return false; } }; /** * Removes an array of markers from the cluster. * * @param {Array.} markers The markers to remove. * @param {boolean=} opt_nodraw Optional boolean to force no redraw. */ MarkerClusterer.prototype.removeMarkers = function(markers, opt_nodraw) { var removed = false; for (var i = 0, marker; marker = markers[i]; i++) { var r = this.removeMarker_(marker); removed = removed || r; } if (!opt_nodraw && removed) { this.resetViewport(); this.redraw(); return true; } }; /** * Sets the clusterer's ready state. * * @param {boolean} ready The state. * @private */ MarkerClusterer.prototype.setReady_ = function(ready) { if (!this.ready_) { this.ready_ = ready; this.createClusters_(); } }; /** * Returns the number of clusters in the clusterer. * * @return {number} The number of clusters. */ MarkerClusterer.prototype.getTotalClusters = function() { return this.clusters_.length; }; /** * Returns the google map that the clusterer is associated with. * * @return {google.maps.Map} The map. */ MarkerClusterer.prototype.getMap = function() { return this.map_; }; /** * Sets the google map that the clusterer is associated with. * * @param {google.maps.Map} map The map. */ MarkerClusterer.prototype.setMap = function(map) { this.map_ = map; }; /** * Returns the size of the grid. * * @return {number} The grid size. */ MarkerClusterer.prototype.getGridSize = function() { return this.gridSize_; }; /** * Sets the size of the grid. * * @param {number} size The grid size. */ MarkerClusterer.prototype.setGridSize = function(size) { this.gridSize_ = size; }; /** * Returns the min cluster size. * * @return {number} The grid size. */ MarkerClusterer.prototype.getMinClusterSize = function() { return this.minClusterSize_; }; /** * Sets the min cluster size. * * @param {number} size The grid size. */ MarkerClusterer.prototype.setMinClusterSize = function(size) { this.minClusterSize_ = size; }; /** * Extends a bounds object by the grid size. * * @param {google.maps.LatLngBounds} bounds The bounds to extend. * @return {google.maps.LatLngBounds} The extended bounds. */ MarkerClusterer.prototype.getExtendedBounds = function(bounds) { var projection = this.getProjection(); // Turn the bounds into latlng. var tr = new google.maps.LatLng(bounds.getNorthEast().lat(), bounds.getNorthEast().lng()); var bl = new google.maps.LatLng(bounds.getSouthWest().lat(), bounds.getSouthWest().lng()); // Convert the points to pixels and the extend out by the grid size. var trPix = projection.fromLatLngToDivPixel(tr); trPix.x += this.gridSize_; trPix.y -= this.gridSize_; var blPix = projection.fromLatLngToDivPixel(bl); blPix.x -= this.gridSize_; blPix.y += this.gridSize_; // Convert the pixel points back to LatLng var ne = projection.fromDivPixelToLatLng(trPix); var sw = projection.fromDivPixelToLatLng(blPix); // Extend the bounds to contain the new bounds. bounds.extend(ne); bounds.extend(sw); return bounds; }; /** * Determins if a marker is contained in a bounds. * * @param {google.maps.Marker} marker The marker to check. * @param {google.maps.LatLngBounds} bounds The bounds to check against. * @return {boolean} True if the marker is in the bounds. * @private */ MarkerClusterer.prototype.isMarkerInBounds_ = function(marker, bounds) { return bounds.contains(marker.getPosition()); }; /** * Clears all clusters and markers from the clusterer. */ MarkerClusterer.prototype.clearMarkers = function() { this.resetViewport(true); // Set the markers a empty array. this.markers_ = []; }; /** * Clears all existing clusters and recreates them. * @param {boolean} opt_hide To also hide the marker. */ MarkerClusterer.prototype.resetViewport = function(opt_hide) { // Remove all the clusters for (var i = 0, cluster; cluster = this.clusters_[i]; i++) { cluster.remove(); } // Reset the markers to not be added and to be invisible. for (var i = 0, marker; marker = this.markers_[i]; i++) { marker.isAdded = false; if (opt_hide) { marker.setMap(null); } } this.clusters_ = []; }; /** * */ MarkerClusterer.prototype.repaint = function() { var oldClusters = this.clusters_.slice(); this.clusters_.length = 0; this.resetViewport(); this.redraw(); // Remove the old clusters. // Do it in a timeout so the other clusters have been drawn first. window.setTimeout(function() { for (var i = 0, cluster; cluster = oldClusters[i]; i++) { cluster.remove(); } }, 0); }; /** * Redraws the clusters. */ MarkerClusterer.prototype.redraw = function() { this.createClusters_(); }; /** * Calculates the distance between two latlng locations in km. * @see http://www.movable-type.co.uk/scripts/latlong.html * * @param {google.maps.LatLng} p1 The first lat lng point. * @param {google.maps.LatLng} p2 The second lat lng point. * @return {number} The distance between the two points in km. * @private */ MarkerClusterer.prototype.distanceBetweenPoints_ = function(p1, p2) { if (!p1 || !p2) { return 0; } var R = 6371; // Radius of the Earth in km var dLat = (p2.lat() - p1.lat()) * Math.PI / 180; var dLon = (p2.lng() - p1.lng()) * Math.PI / 180; var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); var d = R * c; return d; }; /** * Add a marker to a cluster, or creates a new cluster. * * @param {google.maps.Marker} marker The marker to add. * @private */ MarkerClusterer.prototype.addToClosestCluster_ = function(marker) { var distance = 40000; // Some large number var clusterToAddTo = null; var pos = marker.getPosition(); for (var i = 0, cluster; cluster = this.clusters_[i]; i++) { var center = cluster.getCenter(); if (center) { var d = this.distanceBetweenPoints_(center, marker.getPosition()); if (d < distance) { distance = d; clusterToAddTo = cluster; } } } if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) { clusterToAddTo.addMarker(marker); } else { var cluster = new Cluster(this); cluster.addMarker(marker); this.clusters_.push(cluster); } }; /** * Creates the clusters. * * @private */ MarkerClusterer.prototype.createClusters_ = function() { if (!this.ready_) { return; } // Get our current map view bounds. // Create a new bounds object so we don't affect the map. var mapBounds = new google.maps.LatLngBounds(this.map_.getBounds().getSouthWest(), this.map_.getBounds().getNorthEast()); var bounds = this.getExtendedBounds(mapBounds); for (var i = 0, marker; marker = this.markers_[i]; i++) { if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) { this.addToClosestCluster_(marker); } } }; /** * A cluster that contains markers. * * @param {MarkerClusterer} markerClusterer The markerclusterer that this * cluster is associated with. * @constructor * @ignore */ function Cluster(markerClusterer) { this.markerClusterer_ = markerClusterer; this.map_ = markerClusterer.getMap(); this.gridSize_ = markerClusterer.getGridSize(); this.minClusterSize_ = markerClusterer.getMinClusterSize(); this.averageCenter_ = markerClusterer.isAverageCenter(); this.center_ = null; this.markers_ = []; this.bounds_ = null; this.clusterIcon_ = new ClusterIcon(this, markerClusterer.getStyles(), markerClusterer.getGridSize()); } /** * Determins if a marker is already added to the cluster. * * @param {google.maps.Marker} marker The marker to check. * @return {boolean} True if the marker is already added. */ Cluster.prototype.isMarkerAlreadyAdded = function(marker) { if (this.markers_.indexOf) { return this.markers_.indexOf(marker) != -1; } else { for (var i = 0, m; m = this.markers_[i]; i++) { if (m == marker) { return true; } } } return false; }; /** * Add a marker the cluster. * * @param {google.maps.Marker} marker The marker to add. * @return {boolean} True if the marker was added. */ Cluster.prototype.addMarker = function(marker) { if (this.isMarkerAlreadyAdded(marker)) { return false; } if (!this.center_) { this.center_ = marker.getPosition(); this.calculateBounds_(); } else { if (this.averageCenter_) { var l = this.markers_.length + 1; var lat = (this.center_.lat() * (l-1) + marker.getPosition().lat()) / l; var lng = (this.center_.lng() * (l-1) + marker.getPosition().lng()) / l; this.center_ = new google.maps.LatLng(lat, lng); this.calculateBounds_(); } } marker.isAdded = true; this.markers_.push(marker); var len = this.markers_.length; if (len < this.minClusterSize_ && marker.getMap() != this.map_) { // Min cluster size not reached so show the marker. marker.setMap(this.map_); } if (len == this.minClusterSize_) { // Hide the markers that were showing. for (var i = 0; i < len; i++) { this.markers_[i].setMap(null); } } if (len >= this.minClusterSize_) { marker.setMap(null); } this.updateIcon(); return true; }; /** * Returns the marker clusterer that the cluster is associated with. * * @return {MarkerClusterer} The associated marker clusterer. */ Cluster.prototype.getMarkerClusterer = function() { return this.markerClusterer_; }; /** * Returns the bounds of the cluster. * * @return {google.maps.LatLngBounds} the cluster bounds. */ Cluster.prototype.getBounds = function() { var bounds = new google.maps.LatLngBounds(this.center_, this.center_); var markers = this.getMarkers(); for (var i = 0, marker; marker = markers[i]; i++) { bounds.extend(marker.getPosition()); } return bounds; }; /** * Removes the cluster */ Cluster.prototype.remove = function() { this.clusterIcon_.remove(); this.markers_.length = 0; delete this.markers_; }; /** * Returns the center of the cluster. * * @return {number} The cluster center. */ Cluster.prototype.getSize = function() { return this.markers_.length; }; /** * Returns the center of the cluster. * * @return {Array.} The cluster center. */ Cluster.prototype.getMarkers = function() { return this.markers_; }; /** * Returns the center of the cluster. * * @return {google.maps.LatLng} The cluster center. */ Cluster.prototype.getCenter = function() { return this.center_; }; /** * Calculated the extended bounds of the cluster with the grid. * * @private */ Cluster.prototype.calculateBounds_ = function() { var bounds = new google.maps.LatLngBounds(this.center_, this.center_); this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds); }; /** * Determines if a marker lies in the clusters bounds. * * @param {google.maps.Marker} marker The marker to check. * @return {boolean} True if the marker lies in the bounds. */ Cluster.prototype.isMarkerInClusterBounds = function(marker) { return this.bounds_.contains(marker.getPosition()); }; /** * Returns the map that the cluster is associated with. * * @return {google.maps.Map} The map. */ Cluster.prototype.getMap = function() { return this.map_; }; /** * Updates the cluster icon */ Cluster.prototype.updateIcon = function() { var zoom = this.map_.getZoom(); var mz = this.markerClusterer_.getMaxZoom(); if (mz && zoom > mz) { // The zoom is greater than our max zoom so show all the markers in cluster. for (var i = 0, marker; marker = this.markers_[i]; i++) { marker.setMap(this.map_); } return; } if (this.markers_.length < this.minClusterSize_) { // Min cluster size not yet reached. this.clusterIcon_.hide(); return; } var numStyles = this.markerClusterer_.getStyles().length; var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles); this.clusterIcon_.setCenter(this.center_); this.clusterIcon_.setSums(sums); this.clusterIcon_.show(); }; /** * A cluster icon * * @param {Cluster} cluster The cluster to be associated with. * @param {Object} styles An object that has style properties: * 'url': (string) The image url. * 'height': (number) The image height. * 'width': (number) The image width. * 'anchor': (Array) The anchor position of the label text. * 'textColor': (string) The text color. * 'textSize': (number) The text size. * 'backgroundPosition: (string) The background postition x, y. * @param {number=} opt_padding Optional padding to apply to the cluster icon. * @constructor * @extends google.maps.OverlayView * @ignore */ function ClusterIcon(cluster, styles, opt_padding) { cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView); this.styles_ = styles; this.padding_ = opt_padding || 0; this.cluster_ = cluster; this.center_ = null; this.map_ = cluster.getMap(); this.div_ = null; this.sums_ = null; this.visible_ = false; this.setMap(this.map_); } /** * Triggers the clusterclick event and zoom's if the option is set. */ ClusterIcon.prototype.triggerClusterClick = function() { var markerClusterer = this.cluster_.getMarkerClusterer(); // Trigger the clusterclick event. google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_); if (markerClusterer.isZoomOnClick()) { // Zoom into the cluster. this.map_.fitBounds(this.cluster_.getBounds()); } }; /** * Adding the cluster icon to the dom. * @ignore */ ClusterIcon.prototype.onAdd = function() { this.div_ = document.createElement('DIV'); if (this.visible_) { var pos = this.getPosFromLatLng_(this.center_); this.div_.style.cssText = this.createCss(pos); this.div_.innerHTML = this.sums_.text; } var panes = this.getPanes(); panes.overlayMouseTarget.appendChild(this.div_); var that = this; google.maps.event.addDomListener(this.div_, 'click', function() { that.triggerClusterClick(); }); }; /** * Returns the position to place the div dending on the latlng. * * @param {google.maps.LatLng} latlng The position in latlng. * @return {google.maps.Point} The position in pixels. * @private */ ClusterIcon.prototype.getPosFromLatLng_ = function(latlng) { var pos = this.getProjection().fromLatLngToDivPixel(latlng); pos.x -= parseInt(this.width_ / 2, 10); pos.y -= parseInt(this.height_ / 2, 10); return pos; }; /** * Draw the icon. * @ignore */ ClusterIcon.prototype.draw = function() { if (this.visible_) { var pos = this.getPosFromLatLng_(this.center_); this.div_.style.top = pos.y + 'px'; this.div_.style.left = pos.x + 'px'; } }; /** * Hide the icon. */ ClusterIcon.prototype.hide = function() { if (this.div_) { this.div_.style.display = 'none'; } this.visible_ = false; }; /** * Position and show the icon. */ ClusterIcon.prototype.show = function() { if (this.div_) { var pos = this.getPosFromLatLng_(this.center_); this.div_.style.cssText = this.createCss(pos); this.div_.style.display = ''; } this.visible_ = true; }; /** * Remove the icon from the map */ ClusterIcon.prototype.remove = function() { this.setMap(null); }; /** * Implementation of the onRemove interface. * @ignore */ ClusterIcon.prototype.onRemove = function() { if (this.div_ && this.div_.parentNode) { this.hide(); this.div_.parentNode.removeChild(this.div_); this.div_ = null; } }; /** * Set the sums of the icon. * * @param {Object} sums The sums containing: * 'text': (string) The text to display in the icon. * 'index': (number) The style index of the icon. */ ClusterIcon.prototype.setSums = function(sums) { this.sums_ = sums; this.text_ = sums.text; this.index_ = sums.index; if (this.div_) { this.div_.innerHTML = sums.text; } this.useStyle(); }; /** * Sets the icon to the the styles. */ ClusterIcon.prototype.useStyle = function() { var index = Math.max(0, this.sums_.index - 1); index = Math.min(this.styles_.length - 1, index); var style = this.styles_[index]; this.url_ = style['url']; this.height_ = style['height']; this.width_ = style['width']; this.textColor_ = style['textColor']; this.anchor_ = style['anchor']; this.textSize_ = style['textSize']; this.backgroundPosition_ = style['backgroundPosition']; }; /** * Sets the center of the icon. * * @param {google.maps.LatLng} center The latlng to set as the center. */ ClusterIcon.prototype.setCenter = function(center) { this.center_ = center; }; /** * Create the css text based on the position of the icon. * * @param {google.maps.Point} pos The position. * @return {string} The css style text. */ ClusterIcon.prototype.createCss = function(pos) { var style = []; style.push('background-image:url(' + this.url_ + ');'); var backgroundPosition = this.backgroundPosition_ ? this.backgroundPosition_ : '0 0'; style.push('background-position:' + backgroundPosition + ';'); if (typeof this.anchor_ === 'object') { if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 && this.anchor_[0] < this.height_) { style.push('height:' + (this.height_ - this.anchor_[0]) + 'px; padding-top:' + this.anchor_[0] + 'px;'); } else { style.push('height:' + this.height_ + 'px; line-height:' + this.height_ + 'px;'); } if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 && this.anchor_[1] < this.width_) { style.push('width:' + (this.width_ - this.anchor_[1]) + 'px; padding-left:' + this.anchor_[1] + 'px;'); } else { style.push('width:' + this.width_ + 'px; text-align:center;'); } } else { style.push('height:' + this.height_ + 'px; line-height:' + this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;'); } var txtColor = this.textColor_ ? this.textColor_ : 'black'; var txtSize = this.textSize_ ? this.textSize_ : 11; style.push('cursor:pointer; top:' + pos.y + 'px; left:' + pos.x + 'px; color:' + txtColor + '; position:absolute; font-size:' + txtSize + 'px; font-family:Arial,sans-serif; font-weight:bold'); return style.join(''); }; // Export Symbols for Closure // If you are not going to compile with closure then you can remove the // code below. window['MarkerClusterer'] = MarkerClusterer; MarkerClusterer.prototype['addMarker'] = MarkerClusterer.prototype.addMarker; MarkerClusterer.prototype['addMarkers'] = MarkerClusterer.prototype.addMarkers; MarkerClusterer.prototype['clearMarkers'] = MarkerClusterer.prototype.clearMarkers; MarkerClusterer.prototype['fitMapToMarkers'] = MarkerClusterer.prototype.fitMapToMarkers; MarkerClusterer.prototype['getCalculator'] = MarkerClusterer.prototype.getCalculator; MarkerClusterer.prototype['getGridSize'] = MarkerClusterer.prototype.getGridSize; MarkerClusterer.prototype['getExtendedBounds'] = MarkerClusterer.prototype.getExtendedBounds; MarkerClusterer.prototype['getMap'] = MarkerClusterer.prototype.getMap; MarkerClusterer.prototype['getMarkers'] = MarkerClusterer.prototype.getMarkers; MarkerClusterer.prototype['getMaxZoom'] = MarkerClusterer.prototype.getMaxZoom; MarkerClusterer.prototype['getStyles'] = MarkerClusterer.prototype.getStyles; MarkerClusterer.prototype['getTotalClusters'] = MarkerClusterer.prototype.getTotalClusters; MarkerClusterer.prototype['getTotalMarkers'] = MarkerClusterer.prototype.getTotalMarkers; MarkerClusterer.prototype['redraw'] = MarkerClusterer.prototype.redraw; MarkerClusterer.prototype['removeMarker'] = MarkerClusterer.prototype.removeMarker; MarkerClusterer.prototype['removeMarkers'] = MarkerClusterer.prototype.removeMarkers; MarkerClusterer.prototype['resetViewport'] = MarkerClusterer.prototype.resetViewport; MarkerClusterer.prototype['repaint'] = MarkerClusterer.prototype.repaint; MarkerClusterer.prototype['setCalculator'] = MarkerClusterer.prototype.setCalculator; MarkerClusterer.prototype['setGridSize'] = MarkerClusterer.prototype.setGridSize; MarkerClusterer.prototype['setMaxZoom'] = MarkerClusterer.prototype.setMaxZoom; MarkerClusterer.prototype['onAdd'] = MarkerClusterer.prototype.onAdd; MarkerClusterer.prototype['draw'] = MarkerClusterer.prototype.draw; Cluster.prototype['getCenter'] = Cluster.prototype.getCenter; Cluster.prototype['getSize'] = Cluster.prototype.getSize; Cluster.prototype['getMarkers'] = Cluster.prototype.getMarkers; ClusterIcon.prototype['onAdd'] = ClusterIcon.prototype.onAdd; ClusterIcon.prototype['draw'] = ClusterIcon.prototype.draw; ClusterIcon.prototype['onRemove'] = ClusterIcon.prototype.onRemove; Object.keys = Object.keys || function(o) { var result = []; for(var name in o) { if (o.hasOwnProperty(name)) result.push(name); } return result; };var mapa; var drawingManager; var quantidade = null; var scroll = 0; var verificador = 0; $(document).ready(function () { // $('select').selectpicker(); $(document).scroll(function () { // -- valmir // var num = parseInt($(document).scrollTop()) % parseInt($("#publicidade-3").height()); // if(num < 100) { // if(parseInt($("#publicidade-3").height()) >= parseInt($(document).scrollTop())) { // $("#publicidade-3").css("top", "auto").css("position","relative"); // } // else if(parseInt($("#publicidade-3").css("top")) + parseInt($("#publicidade-3").height()) <= (parseInt($("#lista-imoveis").height()) - parseInt($("#lista-imoveis").offset().top)) ) { // $("#publicidade-3").animate($("#publicidade-3").css("top", parseInt($(document).scrollTop()) - parseInt($("#col-esquerda").offset().top) - parseInt($("#filtros-aplicados").height()), 'slow')); // } // } // -- valmir var topPadrao = 800; // andre var tamanhoFiltros = $('#filtros-aplicados').height(); var numBanners = $("#publicidade-3 .banner").length; if(numBanners > 0){ if(parseInt($(document).scrollTop()) > topPadrao){ $("#publicidade-3").css("top", parseInt($(document).scrollTop())-(parseInt(topPadrao)+parseInt(scroll)) ); if(verificador == 1){ scroll -= (numBanners <= 2) ? 0.5 : 5; if($(document).scrollTop() < parseInt($('#publicidade-3 div:first-child').offset().top)){ verificador = 0; } }else{ scroll += (numBanners <= 2) ? 0.5 : 5; if( ($(document).scrollTop()+$('#publicidade-3 div:last-child').height()) > parseInt($('#publicidade-3 div:last-child').offset().top)) { verificador = 1; } } } if(parseInt($(document).scrollTop())+topPadrao > $('.lista-imoveis').height()){ $("#publicidade-3").css("top",(parseInt($('.lista-imoveis').height()) + tamanhoFiltros) - (topPadrao+parseInt($("#publicidade-3").height()))) ; } if(parseInt($(document).scrollTop()) <= topPadrao+tamanhoFiltros){ $("#publicidade-3").css("top",0); } } // andre // var altura = $('#lista-imoveis').offset().top + $('#lista-imoveis').height(); // var item = $('#lista-imoveis .imovel:last').offset().top-$('#lista-imoveis .imovel:last').height(); // console.log($(document).scrollTop()+' >= '+item); // if ($(document).scrollTop() >= item ) { // console.log('carregou'); // var pagina = $("#pagina").val(); // var quantidadeImoveis = $('#qtImoveisEncontrados').text(); // if(pagina <= 5) { // fazerBuscaImoveis("+"); // } // else { // deixar visivel o botão de 'carregar mais imóveis' // if(pagina == Math.ceil(quantidadeImoveis / 10)) // $('.bloco-carregar-mais').hide(); // carregarMaisImoveis(); // } // } // var item = $('#lista-imoveis .imovel:last').offset().top-($('#lista-imoveis .imovel:last').height()*0.8); //const item = $('#lista-imoveis .card-imovel:last').offset().top-($('#lista-imoveis .imovel:last').height()*3); // if (($(document).scrollTop() ) >= item) { // if(!$('.sem-imoveis').is(':visible')){ // var pagina = $("#pagina").val(); // if(null == quantidade){ // quantidade = $('#lista-imoveis .imovel').length; // } // var quantidadeImoveis = $('#qtImoveisEncontrados').text(); // if(pagina <= 5) { // if(pagina <= Math.ceil(quantidadeImoveis / quantidade)) // fazerBuscaImoveis("+"); // } // else { // deixar visivel o botão de 'carregar mais imóveis' // if(pagina == Math.ceil(quantidadeImoveis / quantidade)){ // $('.bloco-carregar-mais').hide(); // } // carregarMaisImoveis(); // } // } // } }); maisFiltros(); visualizacao(); exibeBotaoVoltarTopo(); abreModalContatar(); carregarVerTelefone(); carregaAcaoMarcarArea(); semImoveis(); if ($('#exibir-modal-sugestoes-baseadas').val() == 1) $('#modal-sugestoes-baseadas').modal(); carregarCarrossel('#lista-imoveis'); // função em geral.js // clickBotaoDireito(); }); // function clickBotaoDireito(){ // var menu = $(".menu"); // $(document).mouseup(function(){ // menu.hide(); // }); // $('.ir-ficha-imovel').contextmenu(function(e) { // menu.show(); // menu.css('marginLeft', e.pageX + 'px'); // menu.css('marginTop', e.pageY + 'px'); // e.preventDefault(); // menu.find('a').attr('id-imovel', pegarIdImovel(e.target)); // menu.find('.url').attr('url-imovel', pegarUrlImovel(e.target)); // }); // } function semImoveis(){ $(document).on('click','.sem-imoveis', function(){ irParaTopo(); }); } function exibeBotaoVoltarTopo() { $(document).scroll(function () { var posicaoScroll = $(document).scrollTop(); // obtem a quantidade de scroll no momento if (posicaoScroll > 1400) { $('#voltar-topo img').show('slow'); } else { $('#voltar-topo img').hide('slow'); } }); $(document).on('click','#voltar-topo', function () { irParaTopo(); }); } function carregarMaisImoveis() { $('#carregar-mais-imoveis').show('slow'); $('#carregar-mais-imoveis').on('click', function () { fazerBuscaImoveis("+"); }); } function visualizacao() { $(document).on('click','.visualizacao', function () { var visualizacao_ant = $('.visualizacao-ativa').attr('id'); $('.visualizacao').removeClass('visualizacao-ativa'); $(this).addClass('visualizacao-ativa'); $('#lista-imoveis').attr('class', '').addClass('row ' + $(this).attr('id') + '-imoveis'); if ($(this).attr('id') == 'mapa') { $('.mapa').show('slow'); $('.tipo-ordenacao').hide(); $('#carregar-mais-imoveis').addClass('dNone'); $('.imoveis-encontrados').addClass('dNone'); $('.imoveis-encontrados.do-mapa').removeClass('dNone'); $('.bloco-aguarde.botton').addClass('dNone'); carregarMapa(); } else { $('.tipo-ordenacao').show(); $('.marcar-area').hide(); $('.mapa').hide('slow'); $('.imoveis-encontrados').removeClass('dNone'); $('.imoveis-encontrados.do-mapa').addClass('dNone'); $('#carregar-mais-imoveis').removeClass('dNone'); if(visualizacao_ant == 'mapa'){ mapa = null; fazerBuscaImoveis(); } } irParaTopo('#resultado-busca'); }); if($('.visualizacao-ativa').attr('id') == 'mapa'){ $('.mapa').show('slow'); $('.tipo-ordenacao').hide(); $('#carregar-mais-imoveis').addClass('dNone'); $('.imoveis-encontrados').addClass('dNone'); $('.imoveis-encontrados.do-mapa').removeClass('dNone'); $('.bloco-aguarde.botton').addClass('dNone'); carregarMapa(); } } function maisFiltros() { $('#mais-filtros').on('click', function () { $('.mais-filtros').toggle('slow'); if ($(this).text() == 'MAIS FILTROS') { $(this).text('MENOS FILTROS'); $(".buscador").addClass("area-mais-filtros"); } else { $(this).text('MAIS FILTROS'); $(".buscador").removeClass("area-mais-filtros"); } }); } function carregaAcaoMarcarArea(){ $(document).on('click', '.marcar-area', function () { if ($(this).hasClass('desmarcar')) { drawingManager.setMap(null); $('.marcar-area').removeClass('desmarcar'); } else { desenharNoMapa(); $('.marcar-area').addClass('desmarcar'); } }); } function carregarMapa() { $('.aguarde').show(); // if (mapa == null) buscarImoveisMapa(); // função em geral/buscador.js // else $('.marcar-area').show(); } function initMap(dadosJson) { var latitude = ''; var longitude = ''; var markerCluster; locations = new Array(); dados = new Array(); var i = 0; // console.log(dadosJson); // $.each(dadosJson, function (y, item) { // if (item.latitude != '' || item.longitude != "") { // // console.log(item); // locations[i] = (new google.maps.LatLng(item.latitude, item.longitude)); // dados[i] = new Object(); // dados[i].id_imovel = item.id_imovel; // dados[i].valor = item.preco; // dados[i].foto = item.foto; // dados[i].descricao = item.descricao_imovel; // i++; // } // }) $.each(dadosJson, function (y, item) { // latitude = item.latitude; // longitude = item.longitude; if (item.latitude != '' || item.longitude != "") { // * locations[i] = (new google.maps.LatLng(item.latitude, item.longitude)); dados[i] = new Object(); dados[i].id_imovel = item.id_imovel; dados[i].valor = item.preco; dados[i].foto = item.foto; dados[i].descricao = item.descricao_imovel; i++; // * if (mapa == null) { var position = new google.maps.LatLng(item.latitude, item.longitude); mapa = new google.maps.Map(document.getElementById('map'), { zoom: 11, center: position, scrollwheel: true }); definirCentroCidade($('#localidade').val()); google.maps.event.trigger(mapa, 'resize'); $('.marcar-area').show(); } } }) var infowindow = new google.maps.InfoWindow({maxWidth: 300}); var markers = locations.map(function (location, i) { var marker = new google.maps.Marker({ position: location, animation: google.maps.Animation.DROP, label: { text: dados[i].valor, color: 'white', fontSize: '12px' }, title: dados[i].descricao, color: '#fff', customInfo: i, icon: { url: '/site/imagens/mapa/pin-preco.png', labelOrigin: new google.maps.Point(40, 13) }//pinSymbol('#118bbe') }); google.maps.event.addListener(marker, 'click', function (cluster) { var arr = [dados[i]]; infowindow.setContent(imovelHTML(arr)); infowindow.open(mapa, this); }); return marker; }); if(null != mapa){ markerCluster = new MarkerClusterer(mapa, markers, {imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'}); google.maps.event.addListener(markerCluster, 'clusterclick', function (cluster) { var markers = cluster.getMarkers(); var coordenadas = ''; var cont = 0; var arr = new Array(); var i = 0; if (markers.length > 1 && markers.length < 20) { /* só exibe o info no cluster casso o numero de markers dele seja > 1 && < 20 e as coordenadas sejam as mesmas */ for (var y = 0; y < markers.length; y++) { var latLng = markers[y].position.lat().toString().substr(0, 8) + ',' + markers[y].position.lng().toString().substr(0, 8); if (coordenadas != '' && coordenadas.indexOf(latLng) < 0) { /* caso latLng não exista no array de coordenadas, quer dizer que latLng é diferente */ cont++; } else { coordenadas += latLng; arr[i] = dados[markers[y].customInfo]; /* cria um pino para que o infoWindow possa aparecer nas coordenadas certas, esse pino não é exibido na tela. */ var m = new google.maps.Marker({position: markers[y].position, icon: '/site/imagens/mapa/ponto.png'}); m.setMap(mapa); i++; } } /* se cont == 0 quer dizer que não existem coordenadas diferentes nesse cluster então o infoWindow é exibido */ if (cont == 0) { infowindow.setContent(imovelHTML(arr)); infowindow.open(mapa, m); } } }); } } function definirCentroCidade(cidade){ geocoder = new google.maps.Geocoder(); geocoder.geocode({'address': cidade + ', Brasil', 'region': 'BR'}, function (results, status) { if (status == google.maps.GeocoderStatus.OK) { if (results[0]) { lat = results[0].geometry.location.lat(); lon = results[0].geometry.location.lng(); position = new google.maps.LatLng(lat, lon); mapa.setCenter(position); } } }) } function desenharNoMapa() { var polyOptions = { strokeWeight: 3, color: "#B9005C", strokeColor: "#118bbe", fillColor: "#000000", fillOpacity: 0.15, editable: false }; if (drawingManager == null) { drawingManager = new google.maps.drawing.DrawingManager({ drawingMode: google.maps.drawing.OverlayType.POLYGON, drawingControl: true, drawingControlOptions: { position: google.maps.ControlPosition.TOP_CENTER, drawingModes: [ google.maps.drawing.OverlayType.POLYGON ] }, polygonOptions: polyOptions }); } drawingManager.setMap(mapa); google.maps.event.addListener(drawingManager, 'polygoncomplete', function (polygon) { var pontosRegiao = polygon.getPath(); var coordenadas = ''; for (var i = 0; i < pontosRegiao.length; i++) { coordenadas += pontosRegiao.getAt(i).lat() + ' ' + pontosRegiao.getAt(i).lng()+';'; } coordenadas += pontosRegiao.getAt(0).lat() + ' ' + pontosRegiao.getAt(0).lng(); drawingManager.setMap(null); buscaImoveisDeCoordenadas(coordenadas); // funcao em buscador.js }); } function imovelHTML(dados) { var html = ''; for (var i = 0; i < dados.length; i++) { html += '
' + // ''+ '
' + '' + '
' + '
' + '
' + 'R$ ' + dados[i].valor + '
' + '
' + dados[i].descricao + '
' + '
'; } return html; } function carregarVerTelefone() { $('.b-contatar').find('#ver-telefone').on('click', function () { $(this).addClass("ativo"); $(this).find('.texto').hide('slow'); $(this).find('.telefones').show('slow'); }); } function ocultarTelefone() { $('.contatar #ver-telefone').removeClass("ativo"); $('.contatar #ver-telefone').find('.texto').show(); $('.contatar #ver-telefone').find('.telefones').hide(); } function abreModalContatar() { $(document).on('click','.falar-agora', function () { var telefones = ''; var idImovel = pegarIdImovel($(this)); // funcao em buscador.js $.post("ajax-modal-falar-agora", {'id-imovel': idImovel, 'transacao': $("#transacao").val()}, function (retorno) { ocultarTelefone(); $('.enviar').removeAttr('disabled'); $('.modal-falar-agora .nome-imobiliaria').text(retorno.nome_imobiliaria); $('.modal-falar-agora .mensagem').val(retorno.mensagem); $('.modal-falar-agora #id_imovel').val(idImovel); $('.modal-falar-agora #id_transacao').val(retorno.id_transacao); telefones += 'Telefone: ' + retorno.telefone.split(',')[0] + '
'; if (retorno.telefone.split(',')[1] != undefined && retorno.telefone.split(',')[1] != '') { telefones += 'Whatsapp: ' + retorno.telefone.split(',')[1].replace('*', ''); } $('.modal-falar-agora .ver-telefone .telefones').html(telefones); if (retorno.logo != '') { $('.modal-falar-agora .logo-imobiliaria img').attr('src', "http://chavefacil.com.br/imagem?imagem=http://chavefacil.com.br/site/imagens/logos/imobiliarias/" + retorno.id_imobiliaria + ".jpg,w=123"); $('.modal-falar-agora .logo-imobiliaria').removeClass('dNone'); } else { $('.modal-falar-agora .logo-imobiliaria').addClass('dNone'); } $('#modal-falar-agora').modal(); } ); }); }