Va ô cuntinutu

Mòdulu:Bozza/GianAntonucci/PusizzioniNtâMappa

Dâ Wikipedia, la nciclupidìa lìbbira.

Mòdulu:Bozza/GianAntonucci/PusizzioniNtâMappa metti nu puntu supra a na mappa. A pusizzioni si conta 'n pircintuali e nun 'n pixel, accussì a mmàggini si po' fari granni o nica e u puntu nun si movi.

Comu si usa

[cancia lu còdici]
{{#invoke:Bozza/GianAntonucci/PusizzioniNtâMappa|main
| map = Sicilia
| lat = 38.1157
| lon = 13.3615
| label = Palermu
| width = 250
}}

Cu na pàggina lijata a Wikidata basta chistu, chi u restu si piglia sulu:

{{#invoke:Bozza/GianAntonucci/PusizzioniNtâMappa|main}}

I paràmitri

[cancia lu còdici]
Paràmitru Zoccu fa Pridifinitu
map Nomu dâ mappa (na sutta-pàggina di /dati/) si piglia di Wikidata
lat / lon Cuurdinati 'n gradi dicimali P625
coordinates Cuurdinati 'n na stringa: «38.1, 13.3» o «38°06′40″N 13°21′40″E» —
wikidata ID dâ ntità chiḍḍa dâ pàggina
label Testu accantu ô puntu. Cu none nun si vidi l'etichetta di Wikidata
width Larghizza 'n pixel 280
position Unni sta l'etichetta: right, left, top, bottom right
marker_color Culuri dû puntu red
marker_size Diàmitru dû puntu 'n pixel 8
caption Testu sutta â mappa —
show_caption Cu se, piglia a didascalìa dâ mappa no
fallback Mappa di ripiegu siḍḍu chiḍḍa addumannata nun cc'è —
simple Cu se, torna sulu u nomu dâ mmàggini no

Nomi autirnativi

[cancia lu còdici]
Cunzigghiatu Fùncianu puru
lat / lon latitude / longitude, long
coordinates coord
wikidata from
marker_color marker
position label_position
label = none show_label = no

Cc'è puru label_size (a grannizza dû testu, pi diri 85%) e name, chi si usa comu etichetta quannu Wikidata nun nni duna una.

Comu si scegghi a mappa

[cancia lu còdici]

U mòdulu prova, unu appressu a l'àutru:

  1. a mappa scrivuta 'n map;
  2. siḍḍu u puntu casca fora dî cunfini di ḍḍa mappa, chiḍḍi scrivuti ntô campu related dâ mappa stissa;
  3. siḍḍu map nun fu datu, acchiana pi l'àrbulu amministrativu di Wikidata (P131, e poi P17) finu a chi trova nu locu chi teni na mappa.

Accussì: Palermu si disigna supra â Sicilia; Milanu casca fora e passa a l'Italia; Tokyo casca fora di tutti dui e passa ô Munnu.

Prima chistu nun succidìa: nu puntu fora dî cunfini s'appiccicava ô cantu dâ mappa, e nuḍḍu capìa pirchì.

I mappi chi cci sunnu

[cancia lu còdici]
Pàggina Mmàggini Passa a
/dati/Sicilia Italy Sicily location map.svg Italia, Munnu
/dati/Italia Italy location map.svg Munnu
/dati/Giappuni Japan location map.svg Munnu
/dati/Munnu World location map (equirectangular 180).svg —

Comu si junci na mappa nova

[cancia lu còdici]

Si crìa na sutta-pàggina Mòdulu:Bozza/GianAntonucci/PusizzioniNtâMappa/dati/<nomu>:

return {
    nomu   = 'Missina',
    image  = 'Map of comune of Messina (metropolitan city of Messina, region Sicily, Italy).svg',

    top    = 38.35,   -- cunfini di tramuntana, 'n gradi dicimali
    bottom = 38.05,   -- cunfini di menzujornu
    left   = 15.40,   -- cunfini di punenti
    right  = 15.65,   -- cunfini di livanti

    caption = 'Pusizzioni ntâ pruvincia di Missina',
    related = { 'Sicilia', 'Italia', 'Munnu' },
}

I cunfini s'ànnu a pigghiari dâ mmàggini stissa. Su' i stissi chi usa Module:Location map/data/... supra â Wikipedia 'n ngrisi, e cunvèni cupiàrili di ḍḍà 'nveci di scrìvirli a occhiu.

U nomu dâ sutta-pàggina è chiḍḍu chi si cerca quannu s'acchiana pi l'àrbulu di Wikidata: s'àvi a chiamari comu l'etichetta siciliana (o ngrisa) dû locu.

  • I cunfini dâ mappa Giappuni s'ànnu a cuntrullari: nun sunnu chiḍḍi chi usa a Wikipedia 'n ngrisi pâ stissa mmàggini.
  • U mòdulu càrrica u so CSS di Mudeḍḍu:PusizzioniNtâMappa/stili.css. Prima i stili stàvanu tutti scrivuti dintra ô Lua.
  • A riga local PRUDUZZIONI = false, 'n testa ô mòdulu, si cancia a true u jornu chi i pàggini nèscinu dâ bozza.
  • Siḍḍu nun si trova nuḍḍa mappa, u mòdulu nun stampa nenti e metti a pàggina 'n Catigurìa:Pàggini senza mappa di pusizzioni.

--------------------------------------------------------------------------------
-- Mòdulu:Bozza/GianAntonucci/PusizzioniNtâMappa
--------------------------------------------------------------------------------
-- Metti nu puntu supra a na mappa, calculannu a pusizzioni 'n pircintuali,
-- accussì a mmàggini si po' fari granni o nica senza chi u puntu si movi.
--
-- I dati dî mappi stannu 'n sutta-pàggini:
--   Mòdulu:Bozza/GianAntonucci/PusizzioniNtâMappa/dati/Sicilia
--
-- Usu:
--   {{#invoke:Bozza/GianAntonucci/PusizzioniNtâMappa|main|map=Sicilia|lat=38.1|lon=13.3}}
--   {{#invoke:Bozza/GianAntonucci/PusizzioniNtâMappa|main|wikidata=Q2656|width=250}}
--------------------------------------------------------------------------------

require('strict')

local p = {}

local cfg   = mw.loadData('Mòdulu:Bozza/GianAntonucci/Cunfigurazzioni')
local stigghi = require('Mòdulu:Bozza/GianAntonucci/Stigghi')

local yesno = stigghi.yesno

local LARGHIZZA_PRIDIFINUTA = 280
local PRUFUNNITA_MASSIMA = 4

-- Comu 'n Mòdulu:Tèssira: cancia PRUDUZZIONI u jornu dâ pubbricazzioni.
local PRUDUZZIONI = false
local CSS = PRUDUZZIONI
    and 'Mudeḍḍu:PusizzioniNtâMappa/stili.css'
    or  'Utenti:GianAntonucci/Bozza/Mudeḍḍu:PusizzioniNtâMappa/stili.css'

--------------------------------------------------------------------------------
-- 1) DATI DÎ MAPPI
--------------------------------------------------------------------------------

--- Càrrica i dati di na mappa. Prova u nomu accussì com'è, tuttu nicu e
-- cû primu carattiri granni.
-- I risultati si tènunu 'n memoria pirchì a stissa mappa si cerca cchiù voti
-- quannu si acchiana pi l'àrbulu amministrativu.
local cacheMappi = {}

local function getMapData(mapName)
    if stigghi.isBlank(mapName) then return nil end
    mapName = mw.text.trim(mapName)

    if cacheMappi[mapName] ~= nil then
        return cacheMappi[mapName] or nil
    end

    local varianti = {
        mapName,
        mw.ustring.lower(mapName),
        stigghi.ucfirst(mw.ustring.lower(mapName)),
    }

    -- mw.loadData e nun require: i dati si càrricanu na vota sula pi tutta a
    -- pàggina, macari siḍḍu cc'è cchiù di na mappa.
    for _, nomu in ipairs(varianti) do
        local ok, dati = pcall(mw.loadData, cfg.modules.mappaDati .. nomu)
        if ok and type(dati) == 'table' and dati.image then
            cacheMappi[mapName] = dati
            return dati
        end
    end

    cacheMappi[mapName] = false
    return nil
end

--- Pircintuali x/y dî cuurdinati. Torna puru siḍḍu u puntu casca DINTRA
-- â mappa: siḍḍu casca fora è megghiu circari na mappa cchiù larga.
local function getPositionRatios(lat, lon, mapData)
    local top, bottom = mapData.top, mapData.bottom
    local left, right = mapData.left, mapData.right

    if not (top and bottom and left and right) then return nil, nil, false end
    if right == left or top == bottom then return nil, nil, false end

    local xRatio = (lon - left) / (right - left)
    local yRatio = (top - lat) / (top - bottom)

    local dintra = xRatio >= 0 and xRatio <= 1 and yRatio >= 0 and yRatio <= 1

    xRatio = math.max(0, math.min(1, xRatio))
    yRatio = math.max(0, math.min(1, yRatio))

    return xRatio * 100, yRatio * 100, dintra
end

--- Cerca a mappa giusta: prima chiḍḍa dumannata, poi (siḍḍu u puntu casca
-- fora) chiḍḍi 'n "related", chi finu a ora nun s'usàvanu mai.
local function chooseMap(mapName, lat, lon, visitati)
    visitati = visitati or {}
    if stigghi.isBlank(mapName) or visitati[mapName] then return nil end
    visitati[mapName] = true

    local dati = getMapData(mapName)
    if not dati then return nil end

    local x, y, dintra = getPositionRatios(lat, lon, dati)
    if not x then return nil end
    if dintra then return dati, x, y end

    -- U puntu casca fora: pruvamu na mappa cchiù larga
    if type(dati.related) == 'table' then
        for _, autra in ipairs(dati.related) do
            local d2, x2, y2 = chooseMap(autra, lat, lon, visitati)
            if d2 then return d2, x2, y2 end
        end
    end

    -- Nuḍḍa mappa cchiù larga: tinemu chista, cû puntu ntô cantu
    return dati, x, y
end

--------------------------------------------------------------------------------
-- 2) CUURDINATI
--------------------------------------------------------------------------------

--- Leggi cuurdinati scrivuti a manu: "38.11, 13.36" o "38°06′40″N 13°21′40″E".
local function parseCoordinates(coordStr)
    if stigghi.isBlank(coordStr) then return nil, nil end
    coordStr = mw.text.trim(coordStr)

    local lat, lon = coordStr:match('^([%-%+]?%d+%.?%d*)%s*[,;]%s*([%-%+]?%d+%.?%d*)$')
    if lat and lon then return tonumber(lat), tonumber(lon) end

    local latDeg, latMin, latSec, latDir, lonDeg, lonMin, lonSec, lonDir =
        coordStr:match("(%d+)°%s*(%d*)['′]?%s*([%d%.]*)[\"″]?%s*([NSns])%s*,?%s*(%d+)°%s*(%d*)['′]?%s*([%d%.]*)[\"″]?%s*([EWew])")

    if latDeg then
        lat = tonumber(latDeg) + (tonumber(latMin) or 0) / 60 + (tonumber(latSec) or 0) / 3600
        if latDir:upper() == 'S' then lat = -lat end
        lon = tonumber(lonDeg) + (tonumber(lonMin) or 0) / 60 + (tonumber(lonSec) or 0) / 3600
        if lonDir:upper() == 'W' then lon = -lon end
        return lat, lon
    end

    return nil, nil
end

--- Cuurdinati e riggiuni pigghiati di Wikidata.
local function getWikidataInfo(wikidataId)
    local info = {}
    local entityId = stigghi.blankToNil(wikidataId) or mw.wikibase.getEntityIdForCurrentPage()
    if not entityId then return info end

    info.id = entityId

    local ok, coords = pcall(mw.wikibase.getBestStatements, entityId, 'P625')
    if ok and coords and coords[1] and coords[1].mainsnak.snaktype == 'value' then
        local v = coords[1].mainsnak.datavalue.value
        info.lat, info.lon = v.latitude, v.longitude
    end

    -- Acchianamu pi l'àrbulu amministrativu finu a chi truvamu na mappa:
    -- cumuni -> pruvincia -> riggiuni -> statu.
    local visitati = {}
    local function cerca(entId, propName, depth)
        if depth > PRUFUNNITA_MASSIMA or visitati[entId] then return nil end
        visitati[entId] = true

        local okStmt, stmts = pcall(mw.wikibase.getBestStatements, entId, propName)
        if not okStmt or not stmts then return nil end

        for _, claim in ipairs(stmts) do
            if claim.mainsnak.snaktype == 'value' and claim.mainsnak.datavalue then
                local id = claim.mainsnak.datavalue.value.id
                if id then
                    local label = mw.wikibase.getLabel(id)
                    if label and getMapData(label) then return label end

                    local enLabel = mw.wikibase.getLabelByLang(id, 'en')
                    if enLabel and getMapData(enLabel) then return enLabel end

                    local supra = cerca(id, propName, depth + 1)
                    if supra then return supra end
                end
            end
        end
        return nil
    end

    info.region = cerca(entityId, 'P131', 1)
    if not info.region then
        visitati = {}
        info.region = cerca(entityId, 'P17', 1)
    end

    return info
end

--------------------------------------------------------------------------------
-- 3) CUSTRUZZIONI DÂ MAPPA
--------------------------------------------------------------------------------

function p._main(args)
    local mapName = args.map or args[1]
    local lat = tonumber(args.lat or args.latitude)
    local lon = tonumber(args.lon or args.longitude or args.long)

    if not lat or not lon then
        lat, lon = parseCoordinates(args.coordinates or args.coord)
    end

    local wikidataId = args.wikidata or args.from
    if not lat or not lon or stigghi.isBlank(mapName) then
        local info = getWikidataInfo(wikidataId)
        lat = lat or info.lat
        lon = lon or info.lon
        if stigghi.isBlank(mapName) then mapName = info.region end
        wikidataId = wikidataId or info.id
    end

    if not lat or not lon then return '' end

    local mapData, xPercent, yPercent = chooseMap(mapName, lat, lon)
    if not mapData then
        mapData, xPercent, yPercent = chooseMap(args.fallback, lat, lon)
    end
    if not mapData then
        return stigghi.trackingCategory('mapNotFound')
    end

    if yesno(args.simple, false) then
        return mapData.image
    end

    --------------------------------------------------------------------------
    -- Etichetta
    --------------------------------------------------------------------------
    local mustraEtichetta = true
    local etichetta = args.label

    if stigghi.isNotBlank(etichetta) and mw.ustring.lower(etichetta) == 'none' then
        etichetta, mustraEtichetta = nil, false
    end
    if yesno(args.show_label, true) == false then
        mustraEtichetta = false
    end

    if stigghi.isBlank(etichetta) then
        if wikidataId then
            etichetta = mw.wikibase.getLabel(wikidataId)
        end
        etichetta = etichetta or args.name or mw.title.getCurrentTitle().text
    end

    --------------------------------------------------------------------------
    -- Custruzzioni. Usamu mw.html: scappa l'attribbuti dî so cuntu, accussì
    -- nu nomu comu "L'Aquila" nun spacca cchiù u title=.
    --------------------------------------------------------------------------
    local larghizza = tonumber(args.width) or LARGHIZZA_PRIDIFINUTA
    local tagghiaPuntu = tonumber(args.marker_size) or 8
    local culuriPuntu = args.marker_color or args.marker or 'red'
    local pusizzioni = args.position or args.label_position or 'right'
    local scartu = tagghiaPuntu / 2

    local root = mw.html.create('div'):addClass('locmap')

    local mmaggini = { 'File:' .. mapData.image, larghizza .. 'px', 'link=' }
    if stigghi.isNotBlank(mapData.caption) then
        table.insert(mmaggini, 'alt=' .. mapData.caption)
    end
    root:wikitext('[[' .. table.concat(mmaggini, '|') .. ']]')

    local strati = root:tag('div'):addClass('locmap_strati')

    strati:tag('div')
        :addClass('locmap_puntu')
        :attr('title', etichetta)
        :css('left', string.format('%.4f%%', xPercent))
        :css('top',  string.format('%.4f%%', yPercent))
        :css('width',  tagghiaPuntu .. 'px')
        :css('height', tagghiaPuntu .. 'px')
        :css('margin-left', string.format('%.1fpx', -scartu))
        :css('margin-top',  string.format('%.1fpx', -scartu))
        :css('background-color', culuriPuntu)

    if mustraEtichetta then
        local nodu = strati:tag('div'):addClass('locmap_etichetta')
        if stigghi.isNotBlank(args.label_size) then
            nodu:css('font-size', args.label_size)
        end

        local stacco = string.format('%.1fpx', scartu + 2)

        if pusizzioni == 'left' or (pusizzioni == 'right' and xPercent > 80) then
            nodu:addClass('locmap_etichetta_manca')
                :css('right', string.format('%.4f%%', 100 - xPercent))
                :css('margin-right', stacco)
                :css('top', string.format('%.4f%%', yPercent))
                :css('margin-top', string.format('%.1fpx', -scartu))
        elseif pusizzioni == 'top' then
            nodu:addClass('locmap_etichetta_supra')
                :css('left', string.format('%.4f%%', xPercent))
                :css('bottom', string.format('%.4f%%', 100 - yPercent))
                :css('margin-bottom', stacco)
        elseif pusizzioni == 'bottom' then
            nodu:addClass('locmap_etichetta_sutta')
                :css('left', string.format('%.4f%%', xPercent))
                :css('top', string.format('%.4f%%', yPercent))
                :css('margin-top', stacco)
        else
            nodu:addClass('locmap_etichetta_dritta')
                :css('left', string.format('%.4f%%', xPercent))
                :css('margin-left', stacco)
                :css('top', string.format('%.4f%%', yPercent))
                :css('margin-top', string.format('%.1fpx', -scartu))
        end

        nodu:wikitext(etichetta)
    end

    local didascalia = args.caption
    if stigghi.isBlank(didascalia) and yesno(args.show_caption, false) then
        didascalia = mapData.caption
    end
    if stigghi.isNotBlank(didascalia) then
        root:tag('div'):addClass('locmap_didascalia'):wikitext(didascalia)
    end

    -- U CSS: prima si stava tuttu scrivutu a manu dintra a l'attribbutu style=.
    -- Ora sta 'n TemplateStyles, accussì si po' cànciari senza tuccari u Lua e
    -- funcia puru cû tema scuru.
    local css = ''
    local ok, tag = pcall(function()
        return mw.getCurrentFrame():extensionTag{
            name = 'templatestyles',
            args = { src = CSS },
        }
    end)
    if ok and tag then css = tag end

    return css .. tostring(root)
end

function p.main(frame)
    return p._main(stigghi.getArgs(frame))
end

return p