TransWikia.com

Selecionar parte de uma imagem

Stack Overflow em Português Asked on November 30, 2021

Dada a seguinte imagem:
Mapa

Como posso fazer em javascript para selecionar um país e pinta-lo?

3 Answers

"Como posso fazer em javascript para selecionar um país e pinta-lo?" (Imagens rasterizadas)

https://en.wikipedia.org/wiki/Flood_fill
https://en.wikipedia.org/wiki/Graph_traversal
https://en.wikipedia.org/wiki/Connected-component_labeling
http://www.algorytm.org/podstawy-grafiki/flood-fill/flood-fill-js.html (implementação recursiva 4 e 8 direções) (áreas < ~40000 pixeis)

'use strict';

let draw = async ( ) => {

const targetColor = 0xffffffff|0; // int32 rgba (cor branca).
let randomColor; // cor de preechimento.
const colorTolerance = 55; // 55 // 1 - 128 - 1020.
/*
let src = 'JirA9.gif'; // https://i.stack.imgur.com/JirA9.gif
*/
let src = URL.createObjectURL( new Blob( [ 
( await (await fetch( 'https://upload.wikimedia.org/wikipedia/commons/4/4d/BlankMap-World.svg' )).text() )
.replace( /#000000/g, '#ffffff' )
.replace( /#ffffff/g, '#99aaff' )
.replace( /#c0c0c0/g, '#ffffff' ) 
], { type:'image/svg+xml' } )
);

let canvas = document.getElementById( 'Mapa' );
let W, H, ctx;

let load  = (   ) => {
W = img.naturalWidth;
H = img.naturalHeight;
canvas = Object.assign( canvas, { 
style: `
transform: scale(${canvas.width / W}, ${canvas.height / H}); 
transform-origin: 0px 0px; 
`,
width:  W, 
height: H 
} );
ctx = canvas.getContext( '2d', { alpha: false } );
ctx.fillStyle = '#99AAFF'; // '#FFFFFF';
ctx.fillRect( 0, 0, W, H );
ctx.drawImage( img, 0, 0 );
}

let img = Object.assign( new Image( ), 
{ /*crossOrigin: 'anonymous',*/ src: src, /*onload: load*/ } );
img.addEventListener( 'load', load );

let rv = new Int32Array( 1000 );
crypto.getRandomValues( rv );
rv.sort();
//rv.sort((a, b) => b - a);
let it = 0;

let click = ( ev ) => {
let x = ev.offsetX * W / W|0;
let y = ev.offsetY * H / H|0;
randomColor = rv[ ++it ];
let imgData = ctx.getImageData( 0, 0, W, H );
let data = new Int32Array( imgData.data.buffer );
if( data[ ( y * W + x ) ] != targetColor ) return;
let pixToCheck = [ x, y ];
/*
while( pixToCheck[0] ){ // ===> Algoritmo I
y = pixToCheck.pop();
x = pixToCheck.pop();
data[ ( y * W + x ) ] == targetColor && ( data[ ( y * W + x ) ] = randomColor ) && pixToCheck.push( 
(x), (y + 1), // N
(x), (y - 1), // S
(x + 1), (y), // E
(x - 1), (y)  // O
);
}
*/
let color, colorDiff;
while( pixToCheck.length > 0 ){ // ===> Variante A
y = pixToCheck.pop();
x = pixToCheck.pop();
color = data[ ( y * W + x ) ];
if( !( color != randomColor ) ) continue;
colorDiff = (targetColor & 255) - (color & 255) + (targetColor >>>  8 & 255) - (color >>>  8 & 255) + (targetColor >>> 16 & 255) - (color >>> 16 & 255) + (targetColor >>> 24 & 255) - (color >>> 24 & 255);
if( !( colorDiff > -colorTolerance && colorDiff < colorTolerance ) ) continue;
data[ ( y * W + x ) ] = randomColor;
pixToCheck.push( 
(x + 1), (y), 
(x - 1), (y), 
(x), (y + 1), 
(x), (y - 1) 
);
}
ctx.putImageData( imgData, 0, 0 );
}

canvas.addEventListener( 'click', click );
}; draw()
<canvas title="click" id="Mapa" width="1000" height="508"></canvas>


Nota: No código acima variante A e algoritmo I podem ser usados em separado com as seguintes diferenças:

inserir a descrição da imagem aqui

Resultado com https://i.stack.imgur.com/JirA9.gif

inserir a descrição da imagem aqui

Imagens SVG sem elementos rasterizados:

(async () => {

let Mapa = document.querySelector( '.Mapa' );
let srcSVG = new DOMParser()
.parseFromString( await (await fetch( 'https://upload.wikimedia.org/wikipedia/commons/4/4d/BlankMap-World.svg' )).text(), 'image/svg+xml' )
.querySelector( 'svg' );
srcSVG.style.transform = `scale(${Mapa.width.baseVal.value / srcSVG.width.baseVal.value}, ${Mapa.height.baseVal.value / srcSVG.height.baseVal.value})`;
srcSVG.style.transformOrigin = '0 0';
srcSVG.addEventListener( 'click', ( ev ) => {
if( ev.target.id != 'ocean' ) ev.target.style.fill = `rgba(
${ Math.random() * 256 & 255 }, /*R*/
    ${ Math.random() * 256 & 255 }, /*G*/
        ${ Math.random() * 256 & 255 }, /*B*/
            ${ 1.0 } /*A*/
            )`;
            }
);

Mapa.parentNode.replaceChild( srcSVG, Mapa );
})();
<svg xmlns="http://www.w3.org/2000/svg" class="Mapa" width="1000" height="508"></svg>

Answered by João Machado on November 30, 2021

Imagino que a solução mais eficaz seria o uso de SVG; Sugiro que busque um mapa como esse em svg, sendo ele representado de tal forma que se assemelhe ao exemplo abaixo:

<svg id="mapa-mundi">
  <path id="brasil" d="..." />
  <path id="usa" d="..." />
</svg>

E então vc poderia manipular livremente cada país usando JQuery e colorindo cada país de maneira independente, baseado na interação do usuário...

<style>
  .colored{ fill:lightcoral }
</style>

$("#mapa-mundi > path").on("click",function() {
  $(this).toggleClass('colored');
});

Answered by Vinicius Colares on November 30, 2021

Pintar exatamente a imagem eu acho que não é possível, pelo motivo de ela ser uma imagem .gif.

Há algumas outras opções, mas trabalhosas...

  1. reproduzir cada país como uma imagem separada, sem fundo, colocando-as sobrepostas a uma imagem com o fundo azul. "Recortar" e Posicionar estas imagens será bem trabalhoso. Vc pode usar o GIMP para recortar as imagens. Para cada recorde vc deverá salvar uma nova imagem

    Nomear os arquivos como -Branco. A parte importante seria o "-Branco", que deve ser exatamente igual

  2. Criar uma cópia destas imagens coloridas. As inserindo na mesma posição da imagem em branco, com style='display:none' para escondê-la, nomeie-as como "-Pintado", o "-Pintado" deve ser exatamente igual.

  3. Em cada uma das imagens, tanto nas brancas como nas coloridas, colocar o seguinte código:

    onclick="pais = this.src.split(-); this.src=(pais[1]=="Branco"?pais[0]+"-Pintado":pais[0]+'-Branco')

Vc pode testar isso com imagens simples antes, como quadrados ou algo assim, antes de arriscar-se a ter todo o trabalho de separar as imagens

Outra opção seria vc usar uma imagem vetorial com , mas isso também te daria trabalho.

A opção do Vector maps é a mais indicada caso você não precise exatamente desta imagem

Answered by jefissu on November 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP