Wiki - KEONHACAI COPA

Thành viên:Mxn/OpenStreetMap.js

/**
 * Đưa khung bản đồ OpenStreetMap tiếng Việt vào các bài địa danh có thẻ
 * {{coord|display=title}}.
 * 
 * Xem [[Trợ giúp:OpenStreetMap]] và <http://wiki.osm.org/wiki/Vi:Main_Page>.
 */
mw.loader.using("mediawiki.util", function () {

var wpMapDefaults = {
    //* {string} Phiên bản Leaflet
    leafletVersion: "0.4.4",
    //* {number} Chiều cao bản đồ (điểm ảnh)
    height: 350,
    //* {string} Địa chỉ hình tượng ([[Tập tin:WMA button2b.png]])
    iconUrl: "//upload.wikimedia.org/wikipedia/commons/thumb/5/55/WMA_button2b.png/17px-WMA_button2b.png",
    
    /**
     * {string} Định dạng của các địa chỉ hình ảnh bản đồ. Ngoài các placeholder
     * chuẩn của Leaflet, kịch bản này hỗ trợ các placeholder sau:
     * 
     * <dl>
     * <dt>{layer}</dt><dd>tên của lớp bản đồ</dd>
     * </dl>
     * 
     * @see http://leaflet.cloudmade.com/reference.html#url-template
     */
    layerUrlFormat: location.protocol + "//{s}.www.toolserver.org/tiles/{layer}/{z}/{x}/{y}.png",
    
    // Địa phương hóa
    
    //* {string} Mã ngôn ngữ của các địa danh trên bản đồ
    language: mw.config.get("wgContentLanguage"),
    //* {string} Tooltip của hình tượng hiện/ẩn bản đổ
    iconTooltip: "Xem vị trí này trên bản đồ tương tác",
    //* {string} Phím tắt (không bao gồm Ctrl v.v.) hiện/ẩn bản đồ
    iconAccessKey: undefined,   // thí dụ "y"
    
    zoomIn: "Phóng to",
    zoomOut: "Thu nhỏ",
    
    layerBlank: "Bản đồ",
	layerLabels: "Địa danh",
    layerArticles: "Bài viết",
    
    /**
     * {string} Định dạng của lời ghi công những người đóng góp vào
     * OpenStreetMap. Chuỗi có thể có các placeholder sau:
     * 
     * <dl>
     * <dt>{osm}</dt>
     * <dd>liên kết đến #creditOsmUrl có văn bản #creditOsm</dd>
     * <dt>{osmLicense}</dt>
     * <dd>liên kết đến #creditOsmUrlLicenseUrl có văn bản #creditOsmLicense</dd>
     * <dt>{help}</dt>
     * <dd>liên kết đến #helpArticle có văn bản #help</dd>
     * </dl>
     */
    credit: "© những nguời đóng góp vào {osm} ({osmLicense}, {help})",
    
    creditOsm: "OpenStreetMap",
    creditOsmUrl: "//www.openstreetmap.org/",
    creditOsmLicense: "ODbL + CC BY-SA",
    creditOsmLicenseUrl: "//www.openstreetmap.org/copyright",
    
    help: "Trợ giúp",
    helpArticle: "Trợ giúp:OpenStreetMap",
	
	// WIWOSM
	
	layerShapes: "Hình dạng",
    creditShapes: "WIWOSM",
	creditShapesUrl: "//wiki.openstreetmap.org/wiki/WIWOSM?uselang=vi",
    
    // Bản đồ biển xa lộ Mỹ
    
    layerShields: "Biển xa lộ",
    shieldsUrlFormat: "http://elrond.aperiodic.net/mtiles/cutouts/{z}/{x}/{y}.png",
    creditShields: "Shields",
    creditShieldsUrl: "http://elrond.aperiodic.net/shields/",
    
    tunnelUrl: location.protocol + "//toolserver.org/~mxn/poitunnel.html",
};
window.wpMapConfig = $.extend({}, window.wpMapConfig, wpMapDefaults);

/**
 * Tải các kịch bản và bảng kiểu của thư viện bản đồ Leaflet của CloudMade. Hàm
 * này chạy một cách bất đồng bộ.
 * 
 * @param done  {function}  Hàm sẽ được gọi sau khi kịch bản của thư viện được
 *                          tải xong.
 */
function loadLeaflet(done) {
//    var root = "//toolserver.org/~osm/libs/leaflet/" + wpMapConfig.leafletVersion + "/dist/";
    var root = "//cdn.leafletjs.com/leaflet-" + wpMapConfig.leafletVersion + "/";
    mw.loader.load(root + "leaflet.css", "text/css");
    if ($.browser.msie && parseInt($.browser.version, 10) < 9) {
        mw.loader.load(root + "leaflet.ie.css", "text/css");
    }
    $.getScript(root + "leaflet.js").done(done);
}

/**
 * Cho ra định dạng của các địa chỉ hình bản đồ trong lớp được cho vào.
 * 
 * @param name  {string}    Tên của lớp bản đồ.
 * @returns {string}    Định dạng của địa chỉ hình bản đồ.
 */
function layerUrl(name) {
    return wpMapConfig.layerUrlFormat.replace("{layer}", name);
}

/**
 * Phân tích mảng chứa các chuỗi tham số thành một đối tượng tham số.
 * 
 * @param components    {array}     Các thành phần của tọa độ.
 * @param width         {number}    Chiều rộng hiện tại của bản đồ.
 * @returns {object}    Từ điển có tọa độ và các tham số.
 */
function parsedParameters(components, width) {
    //* Phân tích một thành phần của tọa độ.
    var parseCoord = function (pos, neg) {
        var i = 0, coord = 0;
        for (; i < components.length; i++) {
            var component = components[i].toUpperCase();
            if (!component || component == pos || component == neg) {
                if (component == neg) coord *= -1;
                break;
            }
            
            coord += parseFloat(component, 10) / Math.pow(60, i);
        }
        components.splice(0, i + 1);
        return coord;
    };
    
    // Phân tích vĩ độ và kinh độ.
    var lat = parseCoord("N", "S");
    var lng = parseCoord("E", "W");
    
    // Đưa các tham số khác vào từ điển.
    var params = {
        center: new L.LatLng(lat, lng),
    };
    for (var i = 0; i < components.length; i++) {
        var param = components[i].split(":");
        params[param[0]] = param[1];
    }
    
    // Phân tích các tham số tỷ lệ theo [[:en:Template:Coord#type:T]] và
    // [[OpenStreetMap:Zoom levels]].
    var zoomsByType = {
        country: 6, satellite: 6,
        adm1st: 9,
        adm2nd: 11,
        adm3rd: 12, mountain: 12, isle: 12, waterbody: 12, river: 12,
        city: 12,   // city(dân số) là 11–14, tùy dân số
        forest: 13, glacier: 13, event: 13,
        airport: 14,
        edu: 16, pass: 16, railwaystation: 16, landmark: 16,
    };
    var type = params.type ? (params.type.match(/(\w+)(?:\(([\d,]+)\))?/) || []) : [];
    params.zoom = zoomsByType[type[1]] || 11;
    if (type[1] == "city" && type[2]) {
        var pop = params.pop = parseInt(type[2].replace(",", ""), 10);
        if (pop >= 1e7) params.zoom = 11;
        else if (pop >= 1e5) params.zoom = 12;
        else if (pop >= 1e3) params.zoom = 13;
        else params.zoom = 14;
    }
    
    // 1:...
    var scalesByZoom = [5e8, 2.5e8, 1.5e8, 7e7, 3.5e7, 1.5e7, 1e7, 4e6, 2e6, 1e6,
                        1e5, 2.5e5, 1.5e5, 7e4, 3.5e4, 1.5e4, 8e3, 4e3, 2e3];
    if (params.scale) {
        params.scale = parseFloat(params.scale);
        for (var i = scalesByZoom.length - 1; i >= 0; i--) {
            if (params.scale <= scalesByZoom[i]) {
                params.zoom = i;
                break;
            }
        }
    }
    
    // Mét / điểm ảnh
    var mppByZoom = [156412, 78206, 39103, 19551, 9776, 4888, 2444, 1222,
                     610.984, 305.492, 152.746, 76.373, 38.187, 19.093, 9.547,
                     4.773, 2.387, 1.193, 0.596];
    if (params.dim) {
        var dim = parseFloat(params.dim, 10);
        var unit = params.dim.indexOf("km") < 0 ? 1 : 1e3;
        dim *= unit;
        for (var i = mppByZoom.length - 1; i >= 0; i--) {
            if (dim <= mppByZoom[i] * wpMapConfig.height) {
                params.zoom = i;
                break;
            }
        }
        if (width) {
            for (var i = mppByZoom.length - 1; i >= 0; i--) {
                if (dim <= mppByZoom[i] * width) {
                    params.zoom = Math.round((params.zoom + i) / 2.);
                    break;
                }
            }
        }
    }
    
    // [[en:ISO 3166-1 alpha-2]]
    if (params.region) params.country = params.region.match(/^\w\w(?=-)/);
    
    return params;
}
//window.parsedParameters = parsedParameters;                                     // debug

var earthRadius = 6378137 /* m */;
/**
 * Chuyển đổi các điểm EPSG:3857 (Mercator hình cầu) thành tọa độ.
 */
function unprojectLayerPoints(points) {
	if (typeof(points[0]) !== "number") {
		for (var i = 0; i < points.length; i++) {
			unprojectLayerPoints(points[i]);
		}
		return;
	}
	
	var pt = new L.Point(points[0], points[1]).divideBy(earthRadius);
	var coord = L.Projection.SphericalMercator.unproject(pt);
	points[0] = coord.lng;
	points[1] = coord.lat;
}

/**
 * Tạo ra đối tượng bản đồ và thiết lập nội dung.
 * 
 * @param id        {string}    ID của phần tử sẽ trở thành bản đồ.
 * @param params    {object}    Từ điển các tham số của bản đồ.
 * @returns {object}    Bản đồ Leaflet.
 */
function createMap(id, params) {
    // Tải các lớp OpenStreetMap.
    var osmAttrib = wpMapConfig.credit.replace("{osm}", "<a id='openstreetmap-credit' href='" +
                                               wpMapConfig.creditOsmUrl + "'>" + wpMapConfig.creditOsm + "</a>")
                                      .replace("{osmLicense}", "<a href='" + wpMapConfig.creditOsmLicenseUrl +
                                               "'>" + wpMapConfig.creditOsmLicense + "</a>")
                                      .replace("{help}", "<a href='" + mw.util.getUrl(wpMapConfig.helpArticle) +
                                               "'>" + wpMapConfig.help + "</a>");
    var blank = new L.TileLayer(layerUrl("osm-no-labels"), {
        attribution: osmAttrib,
    });
	var shapes = new L.GeoJSON(undefined, {
		style: function (feature) {
			return {
				opacity: 0.5,
				fillColor: "white",
				clickable: false,
			};
		},
	});
    var labels = new L.TileLayer(layerUrl("osm-labels-" + wpMapConfig.language));
    labels.on("tileerror", function (evt) {
        // Nếu lớp chưa có vị trí nào đó, thay thế bằng hình bản đồ đa ngôn ngữ.
        var layerName = "osm-labels-" + wpMapConfig.language;
        if (evt.url.indexOf(layerName) < 0) return;
        evt.tile.src = evt.url.replace(layerName, "osm");
    });
    var articles = new L.LayerGroup();
    
    // <a href='/wiki/Wikipedia:Quyền_tác_giả'>Wikipedia</a>
    
    // Tạo bản đồ.
    var map = new L.Map(id, {
        center: params.center,
        zoom: params.zoom,
        layers: [blank, shapes, labels, articles],
    });
    
    // Việt hóa các điều khiển.
    map.attributionControl.setPrefix("<a href='http://leaflet.cloudmade.com'>Leaflet</a>");
    $(".leaflet-control-zoom-in").attr("title", wpMapConfig.zoomIn);
    $(".leaflet-control-zoom-out").attr("title", wpMapConfig.zoomOut);
    
    // Tạo điều khiển để bật/tắt các lớp.
    var bases = {};
    bases[wpMapConfig.layerBlank] = blank;
    var overlays = {};
    overlays[wpMapConfig.layerLabels] = labels;
    
    // Thiết lập lớp biển xa lộ Mỹ.
    if (["US", "CA", "MX"].indexOf(params.country) >= 0) {
        var shieldsAttrib = ("<a id='shields-credit' href='" +
                             wpMapConfig.creditShieldsUrl + "'>" +
                             wpMapConfig.creditShields + "</a>");
        var shields = new L.TileLayer(wpMapConfig.shieldsUrlFormat, {
            attribution: shieldsAttrib,
        });
        overlays[wpMapConfig.layerShields] = shields;
    }
    
    overlays[wpMapConfig.layerShapes] = shapes;
    overlays[wpMapConfig.layerArticles] = articles;
    map.addControl(new L.Control.Layers(bases, overlays));
    
    // Liên kết đến vị trí hiện tại trên trang chủ OpenStreetMap.
    var updateOsmLink = function (link) {
        if (!link.length) return;
        var center = map.getCenter();
        var base = link.attr("href").match(/^[^?]+/);
        link.attr("href", base + "?lat=" + center.lat + "&lon=" + center.lng +
                  "&zoom=" + map.getZoom());
    };
    var updateOsmLinks = function () {
        updateOsmLink($("#openstreetmap-credit"));
        updateOsmLink($("#shields-credit"));
    };
    updateOsmLinks();
    map.on("moveend", updateOsmLinks);
    
    // Thiết lập lớp ghim và lớp hình dạng.
    var tunnel = $("#poi-tunnel");
    if (!tunnel.length) {
        tunnel = $("<iframe id='poi-tunnel' src='" + wpMapConfig.tunnelUrl + "'></iframe>");
        $(document.body).after(tunnel);
        tunnel.hide();
    }
	var receiveArticles = function (pois) {
        if (pois.length === undefined) return;
        articles.clearLayers();
        for (var i = 0; i < pois.length; i++) {
            if (!pois[i].visible) continue;
            var marker = new L.CircleMarker(new L.LatLng(pois[i].lat, pois[i].lon), {
                color: "red",
                opacity: 0.4,
                fillOpacity: 0.1,
                radius: 5,
            });
            articles.addLayer(marker);
            var content = mw.html.element("a", {
                href: mw.util.getUrl(pois[i].name),
                title: pois[i].name,
            }, pois[i].name);
            marker.bindPopup(content);
        }
	};
	var articleTitle = mw.config.get("wgTitle");
	var receiveShapes = function (json) {
        shapes.clearLayers();
		
		if (json.coordinates) unprojectLayerPoints(json.coordinates);
		else if (json.geometries) {
			for (var i = 0; i < json.geometries.length; i++) {
				unprojectLayerPoints(json.geometries[i].coordinates);
			}
		}
		
		if (shapes.addData(json) && json.type !== "Point") {
			var zoom = map.getBoundsZoom(shapes.getBounds());
			if (zoom > 1) map.fitBounds(shapes.getBounds());
			//else {
			//	var centerHemisphere = params.center.lng >= 0 ? 1 : -1;
			//	shapes.eachLayer(function (layer) {
			//		// Nếu hình đa giác cùng bán cầu với điểm trung tâm, thì
			//		// không cần di chuyển hình đa giác.
			//		var layerPt = (layer instanceof L.Marker ? layer.getLatLng() :
			//					   layer.getBounds().getCenter());
			//		var hemisphere = layerPt.lng >= 0 ? 1 : -1;
			//		if (centerHemisphere < 0 && hemisphere < 0) return;
			//		if (centerHemisphere > 0 && hemisphere > 0) return;
			//		
			//		if (layer instanceof L.Marker) {
			//			layer.setLatLng(layerPt.lat,
			//							layerPt.lng + 360 * centerHemisphere);
			//			return;
			//		}
			//		
			//		var coords = layer.getLatLngs();
			//		for (var i = 0; i < coords.length; i++) {
			//			coords[i].lng += 360 * centerHemisphere;
			//		}
			//		layer._latlngs = coords;	// tránh _convertLatLngs()
			//		layer.redraw();
			//	});
			//	zoom = map.getBoundsZoom(shapes.getBounds());
			//	if (zoom > 1) map.fitBounds(shapes.getBounds());
			//}
		}
	};
    addEventListener("message", function (evt) {
        if (evt.origin !== location.protocol + "//toolserver.org") return;
		
		var data = evt.data;
		if (data.length !== undefined) receiveArticles(data);	// poitunnel cũ
		else if (data.subject === "pois") receiveArticles(data.data);
		else if (data.subject === "shape") receiveShapes(data.data);
    }, false);
    var requestShapes = function () {
        tunnel[0].contentWindow.postMessage({
            subject: "shape",
			lang: wpMapConfig.language,
			article: articleTitle,
        }, wpMapConfig.tunnelUrl);
    };
    tunnel.load(requestShapes);
    var requestArticles = function () {
        tunnel[0].contentWindow.postMessage({
            subject: "pois",
			lang: wpMapConfig.language,
			bbox: map.getBounds().toBBoxString(),
        }, wpMapConfig.tunnelUrl);
    };
    tunnel.load(requestArticles);
    map.on("moveend", requestArticles);
    map.on("layeradd", function (evt) {
        if (evt.layer !== articles) return;
		requestArticles();
		map.on("moveend", requestArticles);
    });
    map.on("layerremove", function (evt) {
        if (evt.layer === articles) map.off("moveend", requestArticles);
    });
    
    // Đặt ghim vào vị trí của chủ đề bài.
    var marker = new L.Marker(params.center);
    map.addLayer(marker);
    var content = mw.html.element("strong", {}, articleTitle);
    marker.bindPopup(content);
    
    return map;
}

/**
 * Cài đặt khung bản đồ và hình tượng hiện/ẩn nó và gỡ bỏ WikiMiniAtlas.
 */
function installMap() {
    // Tìm tọa độ trong liên kết của GeoHack.
    var link = $("#coordinates a[href*='geohack']:not([href*='_globe:'])");
    var params = link && link.attr("href");
    params = params && params.match(/[?&]params=(.+?)(?:&|$)/);
    params = params && params[1].split("_");
    if (!params) return;
    
    // Tạo khung đựng bản đồ.
    $("#contentSub").append("<div id='openstreetmap-container' style='clear: both; display: none;'><div id='openstreetmap' style='height: " +
                            wpMapConfig.height + "px; width: 100%;'></div></div>");
    
    // Vô hiệu WikiMiniAtlas và xóa hình tượng của nó nếu bản đồ đã tải.
    $("#coordinates img").unbind("click").remove();
    wma_settings = {enabled: false};
    
    // Tạo hình tượng địa cầu.
    var icon = $("<a id='openstreetmap-icon' href='#'><img src='" +
                wpMapConfig.iconUrl + "' /></a>");
    
    // Đặt tooltip và phím tắt nếu có.
    var tooltip = wpMapConfig.iconTooltip;
    if (wpMapConfig.iconAccessKey) {
        tooltip += " [" + wpMapConfig.iconAccessKey + "]";
        icon.attr("accesskey", wpMapConfig.iconAccessKey);
    }
    icon.attr("title", tooltip);
    if (wpMapConfig.iconAccessKey) mw.util.updateTooltipAccessKeys(icon);
    
    // Khi nhấn chuột vào hình tượng, mở/đóng bản đồ.
    icon.click(function (evt) {
        // Nếu bản đồ đã được thiết lập, chỉ việc hiện/ẩn.
        var container = $("#openstreetmap-container");
        if (!container || container.hasClass("openstreetmap-loaded")) {
            container.slideToggle("slow", function () {
                this.map.setView(this.mapParams.center, this.mapParams.zoom);
            });
            return;
        }
        container.addClass("openstreetmap-loaded");
        
        loadLeaflet(function () {
            // Thiết lập và hiển thị bản đồ.
            container.slideDown("slow", function () {
                this.mapParams = parsedParameters(params, $(this).width());
//                console.log(this.mapParams);                                    // debug
                this.map = createMap("openstreetmap", this.mapParams);
            });
        });
    });
    
    // Chèn hình tượng đằng trước liên kết tọa độ.
    link.before(icon);
    link.before(" ");
};

$(installMap);

});
Wiki - Keonhacai copa chuyên cung cấp kiến thức thể thao, keonhacai tỷ lệ kèo, bóng đá, khoa học, kiến thức hằng ngày được chúng tôi cập nhật mỗi ngày mà bạn có thể tìm kiếm tại đây có nguồn bài viết: https://vi.wikipedia.org/wiki/Th%C3%A0nh_vi%C3%AAn:Mxn/OpenStreetMap.js