【发布时间】:2018-02-20 05:34:12
【问题描述】:
所以,我正在构建一个网络应用程序,它使用谷歌地图的 API 来显示一个带有一些标记的地图,每次你点击一个标记,它应该显示来自该位置的 5 篇文章,这些文章由谷歌新闻提供,问题是,我对 javascript 和 web 开发还很陌生,我已经尝试了好几个小时来自己解决这个问题,但我不知道如何解决。我将保留我的 JS 文件和我的使用 flask 处理服务器请求的 python 文件,但我确信服务器端没有任何问题。
js:
// Google Map
var map;
// markers for map
var markers = [];
// info window
var info = new google.maps.InfoWindow();
// execute when the DOM is fully loaded
$(function() {
// styles for map
// https://developers.google.com/maps/documentation/javascript/styling
var styles = [
// hide Google's labels
{
featureType: "all",
elementType: "labels",
stylers: [
{visibility: "off"}
]
},
// hide roads
{
featureType: "road",
elementType: "geometry",
stylers: [
{visibility: "off"}
]
}
];
// options for map
// https://developers.google.com/maps/documentation/javascript/reference#MapOptions
var options = {
center: {lat: 42.3770, lng: -71.1256}, // Cambridge, MA
disableDefaultUI: true,
mapTypeId: google.maps.MapTypeId.ROADMAP,
maxZoom: 14,
panControl: true,
styles: styles,
zoom: 13,
zoomControl: true
};
// get DOM node in which map will be instantiated
var canvas = $("#map-canvas").get(0);
// instantiate map
map = new google.maps.Map(canvas, options);
// configure UI once Google Map is idle (i.e., loaded)
google.maps.event.addListenerOnce(map, "idle", configure);
});
/**
* Adds marker for place to map.
*/
function addMarker(place)
{
// initialize marker
var marker = new google.maps.Marker({
position: {lat: place.latitude, lng: place.longitude},
map: map,
title: place.place_name + ', ' + place.admin_name1,
icon: "http://maps.google.com/mapfiles/kml/pal2/icon31.png"
});
// add marker with its place to markers array
markers.push({marker, place});
index = markers.length - 1
// add event listener to the marker
google.maps.event.addListener(markers[index].marker, 'click', showArticles(markers[index]))
}
/**
* Gets the articles to be displayed
*/
function showArticles(local)
{
var parameters = {
geo: local.place.place_name
};
// get articles for the place
json = $.getJSON(Flask.url_for("articles"), parameters);
// store those articles in a string containing html
html = "<ul>"
json.done(function (){
if(json.responseJSON){
for (var i = 0; i < json.responseJSON.length; i++){
html += "<li><a src=\"" + json.responseJSON[i].link + "\">" + json.responseJSON[i].title + "</a></li>";
}
html += "</ul>"
console.log(json.responseJSON)
console.log(html)
showInfo(local.marker, html)
}}).fail(function (){
showInfo(local.marker, "")
})
}
/**
* Configures application.
*/
function configure()
{
// update UI after map has been dragged
google.maps.event.addListener(map, "dragend", function() {
// if info window isn't open
// http://stackoverflow.com/a/12410385
if (!info.getMap || !info.getMap())
{
update();
}
});
// update UI after zoom level changes
google.maps.event.addListener(map, "zoom_changed", function() {
update();
});
// configure typeahead
$("#q").typeahead({
highlight: false,
minLength: 1
},
{
display: function(suggestion) { return null; },
limit: 10,
source: search,
templates: {
suggestion: Handlebars.compile(
"<div>" +
"{{place_name}}, {{admin_name1}}, {{postal_code}}" +
"</div>"
)
}
});
// re-center map after place is selected from drop-down
$("#q").on("typeahead:selected", function(eventObject, suggestion, name) {
// set map's center
map.setCenter({lat: parseFloat(suggestion.latitude), lng: parseFloat(suggestion.longitude)});
// update UI
update();
});
// hide info window when text box has focus
$("#q").focus(function(eventData) {
info.close();
});
// re-enable ctrl- and right-clicking (and thus Inspect Element) on Google Map
// https://chrome.google.com/webstore/detail/allow-right-click/hompjdfbfmmmgflfjdlnkohcplmboaeo?hl=en
document.addEventListener("contextmenu", function(event) {
event.returnValue = true;
event.stopPropagation && event.stopPropagation();
event.cancelBubble && event.cancelBubble();
}, true);
// update UI
update();
// give focus to text box
$("#q").focus();
}
/**
* Removes markers from map.
*/
function removeMarkers()
{
for(var i = 0; i < markers.length; i++){
markers[i].marker.setMap(null)
}
markers = []
}
/**
* Searches database for typeahead's suggestions.
*/
function search(query, syncResults, asyncResults)
{
// get places matching query (asynchronously)
var parameters = {
q: query
};
$.getJSON(Flask.url_for("search"), parameters)
.done(function(data, textStatus, jqXHR) {
// call typeahead's callback with search results (i.e., places)
asyncResults(data);
})
.fail(function(jqXHR, textStatus, errorThrown) {
// log error to browser's console
console.log(errorThrown.toString());
// call typeahead's callback with no results
asyncResults([]);
});
}
/**
* Shows info window at marker with content.
*/
function showInfo(marker, content)
{
// start div
var div = "<div id='info'>";
if (typeof(content) == "undefined")
{
// http://www.ajaxload.info/
div += "<img alt='loading' src='/static/ajax-loader.gif'/>";
}
else
{
div += content
}
// end div
div += "</div>";
// set info window's content
info.setContent(div);
// open info window (if not already open)
info.open(map, marker);
}
/**
* Updates UI's markers.
*/
function update()
{
// get map's bounds
var bounds = map.getBounds();
var ne = bounds.getNorthEast();
var sw = bounds.getSouthWest();
// get places within bounds (asynchronously)
var parameters = {
ne: ne.lat() + "," + ne.lng(),
q: $("#q").val(),
sw: sw.lat() + "," + sw.lng()
};
$.getJSON(Flask.url_for("update"), parameters)
.done(function(data, textStatus, jqXHR) {
// remove old markers from map
removeMarkers();
// add new markers to map
for (var i = 0; i < data.length; i++)
{
addMarker(data[i]);
}
})
.fail(function(jqXHR, textStatus, errorThrown) {
// log error to browser's console
console.log(errorThrown.toString());
});
};
Python:
import os
import re
from flask import Flask, jsonify, render_template, request, url_for
from flask_jsglue import JSGlue
from cs50 import SQL
from helpers import lookup
# configure application
app = Flask(__name__)
JSGlue(app)
# ensure responses aren't cached
if app.config["DEBUG"]:
@app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
# configure CS50 Library to use SQLite database
db = SQL("sqlite:///mashup.db")
@app.route("/")
def index():
"""Render map."""
if not os.environ.get("API_KEY"):
raise RuntimeError("API_KEY not set")
return render_template("index.html", key=os.environ.get("API_KEY"))
@app.route("/articles")
def articles():
"""Look up articles for geo."""
# get geo
geo = request.args.get("geo")
# if there is no geo, return error
if geo == '' or geo == None:
raise RuntimeError("missing geo")
# get articles for this geo
articles = lookup(geo)
if len(articles) > 5:
articles = articles[:5]
# return them as a json object
return jsonify(articles)
@app.route("/search")
def search():
"""Search for places that match query."""
place = request.args.get("q") + "%"
# get everything that mathes this query
places = db.execute("SELECT * FROM places WHERE postal_code LIKE :place OR place_name LIKE :place OR admin_name1 LIKE :place LIMIT 10", place=place)
# return them as objects
return jsonify(places)
@app.route("/update")
def update():
"""Find up to 10 places within view."""
# ensure parameters are present
if not request.args.get("sw"):
raise RuntimeError("missing sw")
if not request.args.get("ne"):
raise RuntimeError("missing ne")
# ensure parameters are in lat,lng format
if not re.search("^-?\d+(?:\.\d+)?,-?\d+(?:\.\d+)?$", request.args.get("sw")):
raise RuntimeError("invalid sw")
if not re.search("^-?\d+(?:\.\d+)?,-?\d+(?:\.\d+)?$", request.args.get("ne")):
raise RuntimeError("invalid ne")
# explode southwest corner into two variables
(sw_lat, sw_lng) = [float(s) for s in request.args.get("sw").split(",")]
# explode northeast corner into two variables
(ne_lat, ne_lng) = [float(s) for s in request.args.get("ne").split(",")]
# find 10 cities within view, pseudorandomly chosen if more within view
if (sw_lng <= ne_lng):
# doesn't cross the antimeridian
rows = db.execute("""SELECT * FROM places
WHERE :sw_lat <= latitude AND latitude <= :ne_lat AND (:sw_lng <= longitude AND longitude <= :ne_lng)
GROUP BY country_code, place_name, admin_code1
ORDER BY RANDOM()
LIMIT 10""",
sw_lat=sw_lat, ne_lat=ne_lat, sw_lng=sw_lng, ne_lng=ne_lng)
else:
# crosses the antimeridian
rows = db.execute("""SELECT * FROM places
WHERE :sw_lat <= latitude AND latitude <= :ne_lat AND (:sw_lng <= longitude OR longitude <= :ne_lng)
GROUP BY country_code, place_name, admin_code1
ORDER BY RANDOM()
LIMIT 10""",
sw_lat=sw_lat, ne_lat=ne_lat, sw_lng=sw_lng, ne_lng=ne_lng)
# output places as JSON
return jsonify(rows)
这是我在运行页面时出现在控制台上的错误,如果需要,我可以留下一个指向运行应用程序的服务器的链接。 enter image description here
【问题讨论】:
-
错误信息和代码的图片不是很有用。请在您的问题中提供错误的完整文本(可能对标题也有帮助),以及产生该错误的minimal reproducible example。
-
对不起,这是唯一出现的错误,如果我尝试从代码中删除任何内容,我会以某种方式破坏应用程序。这是应用程序的链接,它目前正在运行,也许你可以在控制台ide50-lucalopes.cs50.io 中找到一些东西,再说一次,我对编程很陌生,做了一个多月,网络编程只是一个多星期了,很抱歉我无法提供更多信息。
-
@geocodezip 请向我询问更具体的内容,我很乐意为您提供。
标签: javascript python google-maps google-maps-api-3