For faster navigation, this Iframe is preloading the Wikiwand page for Module:Carte.

Module:Carte

 Documentation[voir] [modifier] [historique] [purger]


Utilisation

Fonctions exportables :

  • fonction p.multimap() permet de localiser un point sur une carte, ou sur plusieurs cartes. Cette fonction doit être appelée depuis un autre module. Elle est notamment utilisé par Module:Infobox pour géolocaliser l'article. Elle prend un seul argument, une table non nommée, qui prend elle-même les clés suivantes :
  • maplist : (chaîne) la liste des cartes à utiliser, séparées par des slashs,par exemple "Paris/France"
  • latitude : latitude de l'objet à géolocaliser
  • longitude : longitude de l'objet à géolocaliser
  • point : image à utiliser pour le point (par défaut file:Red pog.svg, voir Module:Carte/Points pour la liste complète).
  • width : largeur de la carte
  • fonction p.map(frame) appel de la fonction p.multimap, mais depuis le "frame"

Les cartes utilisées sont celles paramétrées dans les sous-pages de Module:Carte/données.

Voir aussi Module:Map


Voir les statistiques d'utilisation du module sur l'outil wstat.

local p = {}
local pointmod = require('Module:Carte/Points')
local linguistic = require('Module:Linguistique')
local maintenance = ''
local coord  = require('Module:Coordinates')
local wd = require('Module:Wikidata')
local function loaddata(name) 
	return require('Module:Carte/données/' .. mw.ustring.lower(name))
end

local divstyle = {
	['clear'] = 'right',
	['width'] ='auto',
	['text-align'] = 'center',
	['font-size'] = '0.9em',
	['line-height'] = '1.4em',
	['margin'] = '0 0 0.5em 1em',
	['max-width'] = '325px',
	['word-wrap'] = 'break-word',
	['max-width'] = '99%',
	['height'] = 'auto',
	['justify-content'] = 'space-around',
	['align-items'] = 'center',
}

local function addmaintenancecat(cat, sortkey) -- ajoute du texte à la string maintenance en cas de problème
	if mw.title.getCurrentTitle().namespace ~= 0 then
		return
	end
	maintenance = maintenance .. '[[Category:' .. cat .. ']]'
end

-- 'Projection conique avec DL'  
local function dllat(latitude, longitude, mapdata) -- conique avec DL
	local val = 
	 	(mapdata.y0 +
	 		( mapdata.iheight/2 - mapdata.y0 ) *
	 		(1 - mapdata.t *
	 			(latitude - mapdata.centrallat) *
	 			(0.01745329252 + 0.00000177219231 * (latitude - mapdata.centrallat) ^2)
	 		)*
	 		( 1- 0.00015230871 * (longitude-mapdata.centrallong) ^2 * mapdata.s^2)
	 	) / mapdata.iheight

	return val
end

local function dllong(latitude, longitude, mapdata)
	local val = 
		( (mapdata.x0 or (mapdata.iwidth/2)) + 
			( mapdata.iheight/2 - mapdata.y0 ) *
			( 1 -mapdata.t * 
				(latitude-mapdata.centrallat) *
				( 0.01745329252 + 0.00000177219231 * (latitude-mapdata.centrallat) * (latitude-mapdata.centrallat) )
			) * 
		(longitude-mapdata.centrallong) * mapdata.s *
		(0.01745329252 - 0.000000886096156 * (longitude-(mapdata.centrallong)) * (longitude-(mapdata.centrallong))
			* mapdata.s^2
		)
	) / mapdata.iwidth
	return val 
end

--longitude équirectangulaire
local function equirecLong(longitude, mapdata)
	local left, right = mapdata.left, mapdata.right
	if right < left then -- si la carte passe le méridien 180
		right = 360 + right
		if longitude < 0 then longitude = (360 + longitude) end
	end
	return  (longitude - left) / (right - left) 
end

local function equirecLat(latitude, mapdata)
	return (latitude - mapdata.top) / (mapdata.bottom - mapdata.top) 	
end

----------------------------------
local function numericcoord(val) -- met en format numériques les coordonnées qui sont parfois sous la forme degré/min/sec
	return tonumber(val) or tonumber(coord.dms2dec({args={val))))
end

local function pointposition(latitude, longitude, mapdata)
	if not (latitude and longitude) then
		return nil --?
	end
	
	if longitude > 180 then -- les caprices des coordonnées extraterrestres
		longitude = -360 + longitude
	elseif longitude < -180 then
		longitude = 360 - longitude
	end
		
	local ypos, xpos
	if mapdata.x and mapdata.y then -- pour les cartes complexes : calcul de la position à partir de formules en Wikicode dans les clés "x" et "y"
		xpos = mapdata.x(latitude, longitude) / 100
		ypos = mapdata.y(latitude, longitude) / 100

	elseif mapdata.projection ==  'Projection équirectangulaire' then
		ypos = equirecLat(latitude, mapdata)
		xpos =  equirecLong(longitude, mapdata)
	elseif mapdata.projection == 'Projection conique avec DL' then
		ypos = dllat(latitude, longitude, mapdata)
		xpos = dllong(latitude, longitude, mapdata)
	end
	return ypos, xpos
end

local function placepoint(mapdata, point) -- fonction d'aige pour buildmap point est une table contenant latitude, longitude, type de point...

	local ypos, xpos = pointposition(point.latitude, point.longitude, mapdata)

	if (not xpos) or (not ypos) then
		return "données de géolocalisation invalides"
	end

	if (ypos > 1.1) or (xpos) > 1.1 or (ypos < -0.1) or (xpos < -0.1) then 
		return '[[Category:Article avec une géolocalisation hors-carte]]' .. 'les coordonnées indiquées sont hors de la carte de géolocalisation demandée'
	end
	
	local pointsize = tostring(point.pointsize or '8')
	local pointtext = point.text or ''
	local pointtype = point.pointtype or 'default'
	local pointimage = pointmod[pointtype]
	if not pointimage then
		pointimage = pointmod.default
		addmaintenancecat('Page avec un modèle de point de carte non pris en charge')
	end

	local htmlheight = tostring(ypos * 100) .. '%'
	local htmlwidth = tostring(xpos * 100) .. '%'

	local pointdiv = mw.html.create('div')
		:css{position = 'absolute', border = 'none', top = htmlheight, left = htmlwidth}
		:tag('div')
			:css{position = 'absolute', top = '-4px', left = '-4px', ['line-height'] = '0', width = '8px'}
			:wikitext('[[Fichier:' .. pointimage .. '|' .. pointsize .. 'px|class=noviewer]]')
			:tag('span') 
			:css{position = 'absolute', ['text-align'] = 'left', width = '150px'}
			:wikitext(pointtext)
			:done()
		:allDone()
			
	return pointdiv
end

local function buildmap(file, caption, alt, width, mapdata, pointtable, defaultpoint)
	local map = mw.html.create('div')
		:css(divstyle)
		:addClass("geobox")
		:wikitext(caption)
		:tag('table')
			:addClass('DebutCarte')
			:attr({border="0", cellspacing="0", cellpadding="0"})
			:css({margin = '0', border = 'none', padding = '0', width = 'auto'})
				:tag('tr')
					:tag('td')
						:tag('div')
							:css({position= 'relative', margin = "auto", width = '100%', ['text-align'] = 'right' })
							:wikitext('[[File:' .. file .. '|frameless|' .. width .. 'px' .. '|' .. alt .. '|class=noviewer]]' )
	
	for i, j in pairs(pointtable or{}) do -- pour chque point à placer, do
		if not j.pointtype then
			j.pointtype = defaultpoint
		end
		map:node(placepoint(mapdata,j))
	end
	return map:done():done():done():done()
end

local function maxpoints(points)
	if not points then
		return nil
	end
	local minlat, maxlat, minlong, maxlong = points[1].latitude, points[1].latitude, points[1].longitude, points[1].longitude
	for i, point in ipairs(points) do
		minlat = math.min(point.latitude, minlat)
		maxlat = math.max(point.latitude, maxlat)
		minlong = math.min(point.longitude, minlong)
		maxlong = math.max(point.longitude, maxlong)
	end
	return minlat, maxlat, minlong, maxlong
	end

local function guesszoom(ids)
	if (not ids) then
		return nil
	end
	local item = ids[1]
	local area = wd.formatStatements{entity = item, property = "P2046", targetunit = "square kilometer", displayformat = "raw"}
	if (not area) or not(tonumber(area)) then
		return nil
	end
	area = tonumber(area)
	if area > 100000 then
		return 3
	end
	if area > 10000 then
		return 4
	end
	if area > 1000 then
		return 5
	end
	if area > 100 then
		return 6
	end
	return 7
end

local function guesszoom2(minlat, maxlat, minlong, maxlong)
	if not (minlat and maxlat and minlong and maxlong) or ((minlat == maxlat) and (minlong == maxlong) ) then
		return nil
	end
	local x = coord._distance({latitude = (maxlat + minlat / 2), longitude = minlong}, {latitude = (maxlat + minlat / 2), longitude =  maxlong })
	local y = coord._distance({latitude = 0, longitude = minlong}, {latitude = 0, longitude = maxlong})
	local dist = math.max(x, y) -- à ajuster si la carte n'est pas carrée
	if (dist > 512) then
		return 4
	elseif (dist > 256) then
		return 5		
	elseif (dist > 128) then
		return 6
	elseif (dist> 64) then
		return 7
	elseif (dist > 32) then
		return 8
	elseif (dist > 16) then
		return 9
	elseif (dist > 8) then
		return 10
	elseif (dist > 4) then
		return 11
	elseif (dist > 2) then
		return 12
	end
	return 13
end

local function buildInteractiveMap(width, pointtable, default_zoom, ids, shapecolor)
	-- On fait un hack pour générer une valeur par défaut pour la latitude et la longitude
	local geojson = {}


	shapecolor = shapecolor or '#800000'
	for i, point in pairs(pointtable or{}) do -- pour chque point à placer, do
		table.insert(geojson, {
			['type'] = 'Feature',
			['geometry'] = {
				['type'] = "Point",
				['coordinates'] = { point.longitude, point.latitude }
			},
			['properties'] = {
				['title'] = point.text or '',
				['marker-symbol'] = point.marker,
				['marker-color'] =  point.markercolor or "#224422",
			}
    	})

	if ids then
		local geojson2 = {
		['type'] = 'ExternalData',
    		['service'] = 'geoshape',
  		['ids'] = ids,
  		properties = {
  		  	['fill'] = shapecolor or '#800000',
  		},
		}
		table.insert(geojson, geojson2)
	end

	end
	
	local minlat, maxlat, minlong, maxlong = maxpoints(pointtable)
	local center_lat = (maxlat + minlat) / 2
	local center_long = (maxlong + minlong) / 2
	-- 180e méridien
	if (maxlong - minlong) > 180 then
		centerlong = centerlong - 180
	end
	local args = {
    		['height'] = width,
    		['width'] = width,
    		['frameless'] = 'frameless',
    		['align'] = 'center',
    		['latitude'] = center_lat,
    		['longitude'] = center_long,
    		['zoom'] = default_zoom or guesszoom(ids) or guesszoom2(minlat, maxlat, minlong, maxlong) or 13
    	}
	return mw.getCurrentFrame():extensionTag('mapframe', mw.text.jsonEncode(geojson), args)
end

local function builddynamicmap(map, maptype, width, pointtable, caption, defaultpoint, globe, default_zoom, ids, shapecolor) -- fonction d'aide pour multimap
	if map == '-' then
		return
	end
	if map == 'interactive' then
		if (globe and (globe ~= 'earth')) then
			return nil
		end
		return buildInteractiveMap(width, pointtable, default_zoom, ids, shapecolor)
	end

	local success, mapdata = pcall(loaddata, map)
	if not success or not mapdata.images then
		addmaintenancecat('Page avec des données de géolocalisation non prises en charge')
	end
	local name = mapdata.name or '?'

	-- analyse linguistique pour le texte de la carte
	local datagender = mapdata.genre or ''
	local gender = string.sub(datagender, 1, 1) -- ms = masculin-singulier, fp = féminin pluriel etc.
	local number = string.sub(datagender, 2, 2)
	local determiner = mapdata.determiner
	local ofstring = linguistic.of(name, gender, number, determiner) -- restitue "de France" ou "du Japon"

	local mapname = mapdata.name
	local file = mapdata.images[maptype] or mapdata.images['default']  or mapdata.images[1]
	if not file then
		 file = mapdata.images['default']
	end
	local alt = 'voir sur la carte ' .. ofstring
	local caption = 'Localisation sur la carte ' .. ofstring
	return buildmap(file, caption, alt, width, mapdata, pointtable, defaultpoint)
end

local function guessmaps(params)
	-- cas non terriens
	local globe = params.globe
	if globe and (globe ~= 'earth') then
		local maps = {
			moon = 'Lune',
			mars = 'Mars',
			mercury = 'Mercure',
			neptune = 'Neptune',
			venus = 'Vénus',
			callisto = 'Callisto',
			ceres = 'Cérès',
			charon = 'Charon',
			enceladus = 'Encelade',
			europa = 'Europe',
			io = 'Io',
			iapetus = 'Japet',
			ganymede = 'Ganymède',
			pluto = 'Pluton',
			tethys = 'Téthys',
			titan = 'Titan',
			triton = 'Triton',
			vesta = 'Vesta',
		}
		return maps[mw.ustring.lower(globe)]
	end
	
	-- autres cas

	local data = require('Module:Carte/données')
	local validmaps = {}
	local lat = tonumber(params.latitude) or tonumber(coord.dms2dec({args={params.latitude))))
	local long = tonumber(params.longitude) or tonumber(coord.dms2dec({args={params.longitude))))
	if not lat or not long then return nil end
	for i, map in pairs(data) do
		if lat < map.top and lat > map.bottom then
			if map.left > map.right  then -- correction pour les cartes passant le méridien 180
				if long < 0 then
					map.left = map.left - 360
				else
					map.right = 360 + map.right
				end
			end
			if (long > map.left and long < map.right) then
				table.insert(validmaps, map)
			end
		end
	end
	if #validmaps == 0 then
		return nil
	end
	
	local function area(map) -- fonction simple juste pour pouvoir classer apprximativement les cartes pas superficie
		return (math.abs(map.top - map.bottom)) * (math.abs(map.left- map.right)) 
	end
	
	table.sort(validmaps, function(a, b) return area(a) < area(b) end)

	local chosenmaps = {} -- on ne les gardes pas toutes, ça serait souvent trop

	local havezone = {} -- paramètre "zone" des carte déjà obtenu, pour ne pas avoir le même deux fois: { zone = {nom de la carte, position de la carte} }

	local forbiddenzones = { -- zone peu utiles, à ne pas utiliser par défaut
		['future région française'] = true,
		['france'] = true, -- utilisé pour des zone non administratives, généalement pas pratique
		['italie'] = true,
	}

	local function addmap(map, pos) -- ajoute la carte à la liste et enregistre qu'elle a une carte avec ce paramètre "zone"
		if pos then
			chosenmaps[pos] = map.name
			havezone[map.zone] = {map, pos} 
		else
			table.insert(chosenmaps, map.name)
			if map.zone then
				havezone[map.zone] = {map, #chosenmaps} 
			end
		end
	end

	local function centrality(map)
		-- retourne un indice ah hoc de centralité, plus faible si le point est près d'un bord
		local function compute(point, end1, end2)
			local pct = (point - end1) / (end2- end1)
			return 0.5 - math.abs(0.5 - pct)
		end
		local latcentrality = compute(lat, map.top, map.bottom)
		local longcentrality = compute(long, map.left, map.right)
		return math.min(latcentrality, longcentrality)
	end

	for i, map in pairs(validmaps) do
		if not(havezone[map.zone]) and  (not forbiddenzones[map.zone]) and #chosenmaps < 3 then
			addmap(map)
		end
		if map.zone and havezone[map.zone] and (centrality(map) > centrality(havezone[map.zone][1] ))  then -- si deux cartes ont le même paramètre "zone", on prend la mieux centrée
			addmap(map, havezone[map.zone][2])
		end
	end
	addmaintenancecat('Carte de localisation ajoutée par Module:Carte')
	return chosenmaps
end

function p.multimap(params)
	local maplist = params.maplist
	local globe = params.globe
	if not maplist and params.guessmaps ~= '-' then -- guessmaps pourrait prendre d'autres paramètres (échelle, etc.)
		maplist = guessmaps(params)
	end
	if type(maplist) == 'string' then
		if maplist == 'non' or maplist == 'pas pertinent' or maplist == 'non' then
			return
		elseif maplist == 'interactive' and globe and globe ~= 'earth' then
			maplist = guessmaps(params)
		end
		maplist = mw.text.split(maplist, '/', true)
	end
	local staticmaps = params.staticmaps
	if type(staticmaps == 'string') then
		staticmaps = {staticmaps}
	end

	if (not maplist)  and (not staticmaps) then
		return nil
	end
	local maptype = params.maptype -- à retravailler pour quand on veut la même région, mais avec plusieurs types de carte
	local width = params.width
	local pointtable = params.pointtable
	local caption = params.caption
	local defaultpoint = params.pointtype
	local default_zoom = params.default_zoom
	local ids = params.ids -- wikidata ids
	if not pointtable then -- pointtable est la liste des points à placer, mais lorsqu'il n'y a qu'un seul, on peut simplement avoir latitude et longitude
		pointtable = ((latitude = params.latitude, longitude = params.longitude, marker = params.marker, markercolor = params.markercolor))
	end
	for i=#pointtable, 1, -1 do
		local point = pointtable[i]
		point.latitude =  numericcoord(point.latitude)
		point.longitude =  numericcoord(point.longitude)
		if not ( point.latitude and point.longitude ) then
			table.remove( pointtable, i )
		end
		point.markercolor = point.markercolor or params.markercolor
		point.marker = point.marker or params.marker
	end
	if #pointtable == 0 then
		return
	end
	-- traitement de la largeur
	if width and tonumber(width) then
		width = tonumber(width)
	else
		width = 280
	end-- si pas un nombre, erreur ?
	local div =  mw.html.create('div'):addClass('img_toggle')
	
 	--transition: appel aux [[Modèle:Géolocalisation/]] n en l'absence de données dans le module
	for i, j in ipairs(maplist or {}) do
		if j == '' then break end
		if j ~= 'interactive' then
			local success, data = pcall(loaddata, j) 
			if not success then
		 		local mapliststring = table.concat(maplist, '/')
				return mw.getCurrentFrame():expandTemplate{title = 'Infobox/Géolocalisation multiple/transition', args = {['géolocalisation'] = mapliststring, type = maptype, latitude = params.latitude or pointtable[1].latitude, longitude = params.longitude or pointtable[1].longitude)) 
					.. '[[Catégorie:Page avec des données de géolocalisation non prises en charge]]'
			end
		end
	end
	for i = #maplist, 1, -1 do
		if maplist[i] ~= '' then
			local newmap = builddynamicmap( maplist[i], maptype, width, pointtable, caption, defaultpoint, globe, default_zoom, ids, params.shapecolor)
			div:node(newmap)
			div:tag('span'):wikitext(maintenance)
		end
	end
	for i, file in pairs(staticmaps or {}) do
		if j == '' then break end
		local caption = "Carte de localisation"
		local alt = "Voir la carte détaillée"
		local newmap = buildmap( file, caption, alt, width)
		div:node(newmap)
		div:tag('span'):wikitext(maintenance)
	end
	return tostring(div)
end

function p.map(frame)
	local args = frame.args
	-- utilisation du franaçs
	args.maplist =  mw.text.split( args.carte, '/', true)
	return p.multimap(args)
end

return p
{{bottomLinkPreText}} {{bottomLinkText}}
Module:Carte
Listen to this article

This browser is not supported by Wikiwand :(
Wikiwand requires a browser with modern capabilities in order to provide you with the best reading experience.
Please download and use one of the following browsers:

This article was just edited, click to reload
This article has been deleted on Wikipedia (Why?)

Back to homepage

Please click Add in the dialog above
Please click Allow in the top-left corner,
then click Install Now in the dialog
Please click Open in the download dialog,
then click Install
Please click the "Downloads" icon in the Safari toolbar, open the first download in the list,
then click Install
{{::$root.activation.text}}

Install Wikiwand

Install on Chrome Install on Firefox
Don't forget to rate us

Tell your friends about Wikiwand!

Gmail Facebook Twitter Link

Enjoying Wikiwand?

Tell your friends and spread the love:
Share on Gmail Share on Facebook Share on Twitter Share on Buffer

Our magic isn't perfect

You can help our automatic cover photo selection by reporting an unsuitable photo.

This photo is visually disturbing This photo is not a good choice

Thank you for helping!


Your input will affect cover photo selection, along with input from other users.