Sequenciar Imagens
O aprendiz organiza imagens (ou cards) na ordem correta. Reforça compreensão de processos sequenciais, cronologias e procedimentos ordenados.
Experimente
Ordene o Crescimento da Planta
Clique ou arraste as imagens até a sequência, na ordem certa.
Arraste entre duas imagens já posicionadas para inserir ali; clique ou arraste de volta para a lista para remover.
Sequência vazia — clique ou arraste as imagens abaixo.
Imagens
Código-fonte
Dados de exemplo
Cada item tem uma imagem, uma legenda e a posição correta na sequência.
| 1 |
<?php
|
| 2 |
$itens = [
|
| 3 |
['id' => 'i1', 'ordem' => 1, 'imagem' => 'ovo.jpg', 'legenda' => 'Ovo'],
|
| 4 |
['id' => 'i2', 'ordem' => 2, 'imagem' => 'lagarta.jpg', 'legenda' => 'Lagarta'],
|
| 5 |
['id' => 'i3', 'ordem' => 3, 'imagem' => 'crisalida.jpg', 'legenda' => 'Crisálida'],
|
| 6 |
['id' => 'i4', 'ordem' => 4, 'imagem' => 'borboleta.jpg', 'legenda' => 'Borboleta'],
|
| 7 |
];
|
| 8 |
$embaralhados = $itens;
|
| 9 |
shuffle($embaralhados);
|
| 10 |
?>
|
Estrutura da questão
A sequência construída nasce vazia; as próprias imagens se movem pra lá a partir da bandeja abaixo.
| 1 |
<div class="questao" data-tipo="sequenciar-imagens" data-total="<?= count($itens) ?>">
|
| 2 |
|
| 3 |
<p class="questao-instrucao">Clique ou arraste as imagens até a sequência, na ordem certa.</p>
|
| 4 |
|
| 5 |
<div class="sequencia">
|
| 6 |
<p class="sequencia-vazia">Sequência vazia — clique ou arraste as imagens abaixo.</p>
|
| 7 |
</div>
|
| 8 |
|
| 9 |
<div class="opcoes">
|
| 10 |
<?php foreach ($embaralhados as $item): ?>
|
| 11 |
<button type="button" class="item" draggable="true" data-ordem="<?= $item['ordem'] ?>" data-id="<?= $item['id'] ?>">
|
| 12 |
<img src="<?= $item['imagem'] ?>" alt="<?= htmlspecialchars($item['legenda']) ?>">
|
| 13 |
<span class="legenda"><?= htmlspecialchars($item['legenda']) ?></span>
|
| 14 |
<span class="posicao"></span>
|
| 15 |
</button>
|
| 16 |
<?php endforeach; ?>
|
| 17 |
</div>
|
Ações da questão
Verificar, o painel de resultado e o botão de reiniciar — os dois últimos nascem ocultos.
| 1 |
<button type="button" class="questao-verificar">Verificar</button>
|
| 2 |
|
| 3 |
<div class="questao-painel" hidden>
|
| 4 |
<p class="questao-painel-mensagem"></p>
|
| 5 |
</div>
|
| 6 |
|
| 7 |
<button type="button" class="questao-reset" hidden>Tentar novamente</button>
|
| 8 |
|
| 9 |
</div>
|
Área da sequência
Nasce vazia com uma mensagem central; vira uma fileira de cartões conforme as imagens entram.
| 1 |
.sequencia {
|
| 2 |
display: flex;
|
| 3 |
flex-wrap: wrap;
|
| 4 |
gap: 8px;
|
| 5 |
min-height: 60px;
|
| 6 |
margin-bottom: 8px;
|
| 7 |
padding: 12px;
|
| 8 |
border: 1px solid #c7d2fe;
|
| 9 |
border-radius: 12px;
|
| 10 |
background: rgba(99, 102, 241, 0.05);
|
| 11 |
}
|
| 12 |
|
| 13 |
.sequencia-vazia {
|
| 14 |
margin: 0;
|
| 15 |
width: 100%;
|
| 16 |
text-align: center;
|
| 17 |
font-size: 13px;
|
| 18 |
color: #64748b;
|
| 19 |
}
|
Bandeja de imagens disponíveis
Onde os itens começam, antes de entrarem na sequência.
| 1 |
.opcoes {
|
| 2 |
display: flex;
|
| 3 |
flex-wrap: wrap;
|
| 4 |
gap: 8px;
|
| 5 |
margin: 16px 0;
|
| 6 |
}
|
Cartão com imagem
Foto em cima, legenda colada embaixo — mesma continuidade visual usada nas outras atividades de imagem do catálogo.
| 1 |
.item {
|
| 2 |
position: relative;
|
| 3 |
display: block;
|
| 4 |
width: 96px;
|
| 5 |
border: 2px solid #cbd5e1;
|
| 6 |
border-radius: 10px;
|
| 7 |
overflow: hidden;
|
| 8 |
background: #f8fafc;
|
| 9 |
font: inherit;
|
| 10 |
cursor: grab;
|
| 11 |
}
|
| 12 |
|
| 13 |
.item img {
|
| 14 |
display: block;
|
| 15 |
width: 100%;
|
| 16 |
aspect-ratio: 1 / 1;
|
| 17 |
object-fit: cover;
|
| 18 |
}
|
| 19 |
|
| 20 |
.item .legenda {
|
| 21 |
display: block;
|
| 22 |
padding: 6px 8px;
|
| 23 |
font-size: 12px;
|
| 24 |
font-weight: 500;
|
| 25 |
text-align: center;
|
| 26 |
}
|
| 27 |
|
| 28 |
.item.arrastando {
|
| 29 |
opacity: 0.5;
|
| 30 |
}
|
Selo de posição
Só aparece enquanto a imagem está dentro da sequência — mostra o lugar que ela ocupa ali, atualizado a cada mudança.
| 1 |
.posicao {
|
| 2 |
display: none;
|
| 3 |
position: absolute;
|
| 4 |
top: 4px;
|
| 5 |
right: 4px;
|
| 6 |
width: 20px;
|
| 7 |
height: 20px;
|
| 8 |
align-items: center;
|
| 9 |
justify-content: center;
|
| 10 |
border-radius: 999px;
|
| 11 |
background: #4f46e5;
|
| 12 |
color: #fff;
|
| 13 |
font-size: 11px;
|
| 14 |
font-weight: 700;
|
| 15 |
}
|
| 16 |
.item.na-sequencia .posicao {
|
| 17 |
display: flex;
|
| 18 |
}
|
Indicador de inserção
Uma linha vertical aparece do lado em que o item solto vai entrar, enquanto ele é arrastado sobre outro já posicionado.
| 1 |
.item[data-insercao="antes"]::before,
|
| 2 |
.item[data-insercao="depois"]::after {
|
| 3 |
content: '';
|
| 4 |
position: absolute;
|
| 5 |
top: 4px;
|
| 6 |
bottom: 4px;
|
| 7 |
width: 3px;
|
| 8 |
border-radius: 999px;
|
| 9 |
background: #6366f1;
|
| 10 |
}
|
| 11 |
.item[data-insercao="antes"]::before { left: -5px; }
|
| 12 |
.item[data-insercao="depois"]::after { right: -5px; }
|
Ações
Botões de largura total, um de cada vez na tela.
| 1 |
.questao-verificar,
|
| 2 |
.questao-reset {
|
| 3 |
display: block;
|
| 4 |
width: 100%;
|
| 5 |
padding: 12px 16px;
|
| 6 |
border: none;
|
| 7 |
border-radius: 10px;
|
| 8 |
font: inherit;
|
| 9 |
font-weight: 600;
|
| 10 |
cursor: pointer;
|
| 11 |
}
|
| 12 |
|
| 13 |
.questao-verificar {
|
| 14 |
background: #4f46e5;
|
| 15 |
color: #fff;
|
| 16 |
}
|
| 17 |
|
| 18 |
.questao-reset {
|
| 19 |
background: #e5e7eb;
|
| 20 |
color: #1f2937;
|
| 21 |
}
|
Estado oculto
O atributo hidden nativo tem a mesma especificidade da regra de exibição acima — sem isto, "Tentar novamente" apareceria antes de verificar.
| 1 |
.questao-verificar[hidden],
|
| 2 |
.questao-reset[hidden] {
|
| 3 |
display: none;
|
| 4 |
}
|
Painel de resultado
Caixa de destaque com o resultado da verificação.
| 1 |
.questao-painel {
|
| 2 |
margin: 16px 0;
|
| 3 |
padding: 16px;
|
| 4 |
border-radius: 12px;
|
| 5 |
background: #1e3a8a;
|
| 6 |
color: #dbeafe;
|
| 7 |
font-weight: 600;
|
| 8 |
}
|
Encontrar os elementos da questão
Localiza a sequência, a bandeja de imagens e as ações.
| 1 |
document.addEventListener('DOMContentLoaded', function () {
|
| 2 |
document.querySelectorAll('.questao[data-tipo="sequenciar-imagens"]').forEach(function (questao) {
|
| 3 |
var seq = questao.querySelector('.sequencia');
|
| 4 |
var vazia = seq.querySelector('.sequencia-vazia');
|
| 5 |
var opcoes = questao.querySelector('.opcoes');
|
| 6 |
var verificar = questao.querySelector('.questao-verificar');
|
| 7 |
var painel = questao.querySelector('.questao-painel');
|
| 8 |
var reset = questao.querySelector('.questao-reset');
|
| 9 |
var total = parseInt(questao.dataset.total, 10) || 0;
|
| 10 |
// O item sendo arrastado no momento, de qualquer origem.
|
| 11 |
var arrastado = null;
|
| 12 |
var travada = false;
|
| 13 |
|
| 14 |
function itensDaSequencia() {
|
| 15 |
return Array.prototype.slice.call(seq.querySelectorAll('.item'));
|
| 16 |
}
|
| 17 |
|
| 18 |
function legenda(item) {
|
| 19 |
return item.querySelector('.legenda').textContent.trim();
|
| 20 |
}
|
Mover um item
Um único ponto de movimentação — insere na sequência numa posição específica (ou no fim) ou devolve pra bandeja, atualizando os selos de posição.
| 1 |
function atualizar() {
|
| 2 |
var itens = itensDaSequencia();
|
| 3 |
vazia.hidden = itens.length > 0;
|
| 4 |
itens.forEach(function (item, i) { item.querySelector('.posicao').textContent = i + 1; });
|
| 5 |
}
|
| 6 |
|
| 7 |
function inserir(item, referencia) {
|
| 8 |
seq.insertBefore(item, referencia || null);
|
| 9 |
item.classList.add('na-sequencia');
|
| 10 |
atualizar();
|
| 11 |
}
|
| 12 |
|
| 13 |
function devolver(item) {
|
| 14 |
opcoes.appendChild(item);
|
| 15 |
item.classList.remove('na-sequencia');
|
| 16 |
atualizar();
|
| 17 |
}
|
Clicar e arrastar
Clique alterna entre bandeja e fim da sequência; arrastar sobre um item já posicionado insere antes ou depois dele, conforme o lado do cursor — só faz sentido calcular isso quando o alvo já está na sequência.
| 1 |
questao.querySelectorAll('.item').forEach(function (item) {
|
| 2 |
item.addEventListener('click', function (evento) {
|
| 3 |
evento.stopPropagation();
|
| 4 |
if (travada) return;
|
| 5 |
if (item.classList.contains('na-sequencia')) devolver(item);
|
| 6 |
else inserir(item, null);
|
| 7 |
});
|
| 8 |
|
| 9 |
item.addEventListener('dragstart', function (evento) {
|
| 10 |
if (travada) { evento.preventDefault(); return; }
|
| 11 |
arrastado = item;
|
| 12 |
item.classList.add('arrastando');
|
| 13 |
evento.dataTransfer.setData('text/plain', item.dataset.id);
|
| 14 |
});
|
| 15 |
item.addEventListener('dragend', function () {
|
| 16 |
item.classList.remove('arrastando');
|
| 17 |
delete item.dataset.insercao;
|
| 18 |
arrastado = null;
|
| 19 |
});
|
| 20 |
|
| 21 |
item.addEventListener('dragover', function (evento) {
|
| 22 |
if (travada || !arrastado || arrastado === item || !item.classList.contains('na-sequencia')) return;
|
| 23 |
evento.preventDefault();
|
| 24 |
var caixa = item.getBoundingClientRect();
|
| 25 |
item.dataset.insercao = evento.clientX < caixa.left + caixa.width / 2 ? 'antes' : 'depois';
|
| 26 |
});
|
| 27 |
item.addEventListener('dragleave', function () { delete item.dataset.insercao; });
|
| 28 |
item.addEventListener('drop', function (evento) {
|
| 29 |
if (travada || !arrastado || arrastado === item || !item.classList.contains('na-sequencia')) return;
|
| 30 |
evento.preventDefault();
|
| 31 |
var antes = item.dataset.insercao === 'antes';
|
| 32 |
delete item.dataset.insercao;
|
| 33 |
inserir(arrastado, antes ? item : item.nextSibling);
|
| 34 |
});
|
| 35 |
});
|
Espaço vazio como alvo
Soltar fora de qualquer item — na sequência manda pro fim; na bandeja devolve.
| 1 |
seq.addEventListener('dragover', function (evento) { if (arrastado && !travada) evento.preventDefault(); });
|
| 2 |
seq.addEventListener('drop', function (evento) {
|
| 3 |
if (travada || evento.target.closest('.item')) return;
|
| 4 |
evento.preventDefault();
|
| 5 |
if (arrastado) inserir(arrastado, null);
|
| 6 |
});
|
| 7 |
|
| 8 |
opcoes.addEventListener('dragover', function (evento) { if (arrastado && !travada) evento.preventDefault(); });
|
| 9 |
opcoes.addEventListener('drop', function (evento) {
|
| 10 |
if (travada) return;
|
| 11 |
evento.preventDefault();
|
| 12 |
if (arrastado && arrastado.classList.contains('na-sequencia')) devolver(arrastado);
|
| 13 |
});
|
Verificar
Confere se cada posição tem o item certo; trava a questão e mostra o resultado.
| 1 |
verificar.addEventListener('click', function () {
|
| 2 |
var itens = itensDaSequencia();
|
| 3 |
if (itens.length < total) {
|
| 4 |
painel.querySelector('.questao-painel-mensagem').textContent = 'Coloque todas as imagens na sequência antes de verificar.';
|
| 5 |
painel.hidden = false;
|
| 6 |
return;
|
| 7 |
}
|
| 8 |
|
| 9 |
var certo = itens.every(function (item, i) { return parseInt(item.dataset.ordem, 10) === i + 1; });
|
| 10 |
painel.querySelector('.questao-painel-mensagem').textContent = certo
|
| 11 |
? 'Correto! Sequência na ordem certa.'
|
| 12 |
: 'Sequência incorreta.';
|
| 13 |
painel.hidden = false;
|
| 14 |
|
| 15 |
verificar.hidden = true;
|
| 16 |
reset.hidden = false;
|
| 17 |
travada = true;
|
| 18 |
});
|
Reiniciar
Devolve todos os itens pra bandeja e destrava a questão.
| 1 |
reset.addEventListener('click', function () {
|
| 2 |
travada = false;
|
| 3 |
itensDaSequencia().forEach(function (item) { devolver(item); });
|
| 4 |
painel.hidden = true;
|
| 5 |
verificar.hidden = false;
|
| 6 |
reset.hidden = true;
|
| 7 |
});
|