Encontrando um Hypotenuse com JavaScript

Recentemente, tive a ideia de um site que permitiu que você fizesse idéias ideais. Aqui estava o que eu basicamente tinha imaginado:

Um usuário começaria com uma idéia central ou pensamento e seria capaz de se ramificar idéias ou pensamentos relacionados. Isso seria ótimo para planejar lições, apresentações ou mesmo estudar. Como eu estava fazendo uma idéia dessa idéia, eu criei 4 componentes que o projeto precisaria:

1 Uma entrada / Textarea

2 Um botão para criar um novo ramo de uma idéia.

3 Uma linha para conectar visualmente a idéia e a idéia ramificada.

Para fazer isso, rapidamente corri um problema. Criar uma entrada / textarea é fácil. Criar um botão que cria uma nova entrada / textarea também é bastante fácil. A peça difícil é visualmente projetá-lo de uma forma que é funcional e faz sentido visualmente. Por exemplo, por motivos de simplicidade, poderíamos simplesmente ter cada botão que crie um novo elemento de formulário, coloque o elemento de formulário verticalmente abaixo do elemento anterior. Embora isso seja mais simples do ponto de vista da programação, visualmente, não faria muito sentido para o usuário, pois seria difícil dizer qual caixa de texto ramificada estava conectada a qual idéia anterior ou caixa de texto. Como geralmente me serve bem, eu decidi começar pequeno, e ver se eu poderia começar a trabalhar mecanicamente em pequena escala primeiro. Comecei com pontos, cada ponto que representa uma caixa de texto / elemento. Cada ponto tem 25 pixels de largura e 25 pixels de altura, de cor preta. Meu primeiro objetivo foi adicionar um novo ponto quando o primeiro ponto é clicado e, em seguida, distribuir pontos subseqüentes ao redor do primeiro ponto sempre que for clicado. Para resolver isso, criei uma variável chamada "clique" e configurá-la para 0; Então, em cada evento de clique, eu adiciono um.

 Deixe clicar = 0; 
$ ('botão'). clique (function () {
cliques = cliques + 1;

Então eu crio um elemento dentro de uma instrução if.

 se (cliques == 1) { 
deixe blackDot = document.createElement ('div');
blackDot.id = "outerDiv1";
document.body.appendChild (blackDot);
document.getElementById ('container'). appendChild (blackDot);
blackDot.className = "blackDotClass";
}

Esse é o básico disso. Então eu adiciono uma margem superior e esquerda para isso. O não está incluído na classe "blackDotClass" porque a margem será diferente para cada elemento criado. Por exemplo, o primeiro ponto estará à direita do elemento pai, o segundo ponto criado estará abaixo dele e o terceiro à esquerda, etc, etc. Vou inseri-lo assim:

 se (cliques == 1) { 
deixe blackDot = document.createElement ('div');
blackDot.id = "blackDotID1";
document.body.appendChild (blackDot);
document.getElementById ('container'). appendChild (blackDot);
blackDot.style.marginTop = "25px";
blackDot.style.marginLeft = "200px";
blackDot.className = "blackDotClass";
}

Então, se o ponto original for clicado uma segunda vez, poderíamos fazer algo como isto:

 se (cliques == 2) { 
deixe blackDot = document.createElement ('div');
blackDot.id = "blackDotID2";
document.body.appendChild (blackDot);
document.getElementById ('container'). appendChild (blackDot);
blackDot.style.marginTop = "0px";
blackDot.style.marginLeft = "200px";
blackDot.className = "blackDotClass";
}

A única coisa que mudamos é o "ID" e a margem superior. Então, para o terceiro elemento, provavelmente mudaremos a margem superior e esquerda, para colocar cada novo elemento em um círculo ao redor do ponto original. Esta parte é simples, mas ainda assim, isso seria confuso para um usuário sem linhas físicas que conectam um ponto para outro. Caso contrário, novamente, seria muito difícil dizer quais elementos estão realmente conectados, sem nada mais do que espaços.

Minha idéia inicial para resolver isso era usar polígonos. Uma vez que cada "ponto" ou "elemento" ou qualquer outro que usamos tenha um conjunto de coordenadas x e y, eu poderia usar a coordenada do elemento pai e as coordenadas para desenhar uma linha de polígono de um elemento para o próximo. Aqui está um diagrama do que eu tinha imaginado:

Na verdade, experimentei várias iterações desta idéia antes de chegar à conclusão de que os polígonos svg não funcionariam. A razão é que os polígonos são um elemento svg e devem estar dentro de um recipiente svg. Por causa disso, você não está simplesmente juntando um com b. Mas você também está alinhando-os com o próprio elemento svg, que tem seu próprio conjunto de dimensões. Tome isso, por exemplo:

Você pode iniciar o processo e ter tudo alinhado corretamente e acabar com o exemplo acima, onde a linha não se conecta do ponto a ao ponto b. Naturalmente, a suposição é que a linha não é suficientemente longa e é um problema com as coordenadas ou o comprimento do polígono. Quando você é problema, pode ser que o contêiner svg não seja o tamanho certo ou não esteja alinhado corretamente. O que você realmente tem é o seguinte:

Você está na linha está certo e suas coordenadas podem estar corretas, mas porque o contêiner svg é muito pequeno, você vê apenas uma pequena porção do polígono real. Claro, você pode fazer uma borda ao redor do recipiente para ver onde está, mas imagine o quão complexo isso acontece quando você tem vários elementos, então os recipientes de svg e os polígonos … é um pesadelo.

Então, encontrei uma solução um pouco mais simples. Apenas uma div, com uma largura de 1 e uma borda. Cada vez que eu clico em "A" e crio um novo elemento filho "B", eu também crio um terceiro elemento, "C", uma linha que liga os dois, ou um div com uma borda, entre os dois elementos.

Se A e B estiverem no mesmo eixo X, e o visor estiver configurado para inline, ou estiverem contidos em uma etiqueta de extensão, seu trabalho será feito, pois você não precisa de nenhum cálculo para o eixo y. No entanto, novamente, do ponto de vista do usuário, seria difícil saber onde idéias e elementos estão conectados se tudo estiver em linha reta. Assim, nestes diagramas de mapeamento mental, geralmente eles tendem a ser de forma circular. Então, aqui é o que eu criei. Depois de criar B, clicando em A, recebo as coordenadas de cada um, como fiz com o polígono.

 deixe element1 = dot1.getBoundingClientRect (); 
deixe element2 = dot2.getBoundingClientRect ();
console.log (element1);
console.log (element2);

Eu também quero encontrar o ponto médio do meu elemento. Caso o meu ponto seja 300px grande, não quero que a linha se conecte ao topo, mas ao meio. Faço isso dividindo a altura e a largura em 2, que são dados que posso encontrar na minha função "getboundingClient".

 Deixe midpointX1 = element1.width / 2; 
Deixe o ponto intermediárioY1 = element1.height / 2;

Deixe midpointX2 = element2.width / 2;
Deixe o ponto intermediário Y2 = elemento2.height / 2;

Agora, meu processo de pensamento é esse. Se eu conheço as coordenadas x e y, também incluídas na função "getBoudningClient", então espero que possamos fazer algumas matemáticas. O que eu quero saber é o comprimento da linha que conectaria os dois elementos e o ângulo da linha. Posso fazer isso com alguma trigonometria. Primeiro, vou encontrar o comprimento com o Teorema de Pitágoras: A quadrado + B quadrado = C ao quadrado.

Ao transformar o relacionamento dos dois elementos nos cantos de um triângulo, podemos usar matemática para descobrir o comprimento da linha, como mencionei acima, e então podemos usar a tangente para descobrir o ângulo da linha. O que vou fazer é criar uma função que leva as coordenadas de ambos e as executa para encontrar o que estou procurando.

 Deixe midpointX1 = element1.width / 2; 
Deixe o ponto intermediárioY1 = element1.height / 2;

Deixe midpointX2 = element2.width / 2;
Deixe o ponto intermediário Y2 = elemento2.height / 2;

Deixe top1 = element1.top - midpointY1;
Deixe top2 = element2.top - midpointY2;
deixe left1 = element1.left - ponto médioX1;
deixe left2 = element2.left - midpointX2;

função findTriangle (w, x, y, z) {

Deixe a diferença = função (a, b) {retornar Math.abs (a - b); }
deixar oposto = diferença (w, x);
deixe adjacente = diferença (y, z);

deixe hypotenuseLengthSquared = Math.pow (oposto, 2) + Math.pow (adjacente, 2);
console.log (hypotenuseLengthSquared);

deixe hypotenuseLength = Math.sqrt (hypotenuseLengthSquared);
console.log (duração de hipotenusa);
console.log (adjacente);

Deixe o ângulo = Math.atan (oposto / adjacente) * 100;
console.log (ângulo);
retorno [oposto, adjacente, hipotenuseLongo, ângulo];
}
Deixe triangle = findTriangle (top1, top2, left1, left2);
console.log (triângulo);

A função "findTriangle" leva o elemento para cima e para a esquerda, menos o ponto intermediário, assumindo que nossos elementos são simétricos e dá basicamente as coordenadas x e y de ambos os elementos para calcular o ângulo eo comprimento da hipotenusa. Eu também tenho a função de retornar os lados adjacentes e opostos no caso de eu precisar usá-los mais tarde também. Agora, vou criar meu div, usando essas coordenadas e retornando.

 deixe newDiv = document.createElement ('div'); 
newDiv.id = "teste";
document.body.appendChild (newDiv);
document.getElementById ('dot1'). appendChild (newDiv);
newDiv.style.borderColor = "# 1cce3a";
newDiv.style.borderWidth = "3px";
newDiv.style.borderStyle = "sólido";
newDiv.style.borderColor = "# 1cce3a";
newDiv.style.width = "" + triângulo [2] + "px";
newDiv.style.transform = "rotate (" + triangle [3] + "deg)";
newDiv.style.zIndex = -1;

Como minha declaração de retorno é uma matriz, quando eu chamo para a largura e a transformação do meu elemento, estou usando apenas os índices de matrizes que eu preciso [2] e [3].

Agora, eu posso executar exatamente a mesma função dentro da minha segunda declaração if. Uma vez que o segundo ponto aparecerá um pouco mais baixo no DOM do que o primeiro, a função calculará a distância entre os dois e retornará a linha de conexão (div) para que eles sejam visualmente conectados na tela, e podemos ter algo semelhante ao Qual foi a minha visão original. No entanto, mesmo com esses cálculos precisos, as coisas podem facilmente ficar mal aqui. Por exemplo, se o recipiente estiver configurado para uma exibição de flexbox, ele descartará todos os cálculos. Mas, em geral, é um exercício muito divertido.

Uma das principais razões para escrever isso é que, como homem mais jovem, detestai matemática. Não fui bom com isso, e com toda a honestidade, não enviei muito esforço. Mesmo quando primeiro aprendendo JavaScript, eu me deparo com esses exercícios onde você precisaria encontrar algum número obscuro através de uma fórmula complicada. E eu sempre pensaria em mim mesmo: "Por que eu sempre precisaria usar isso? É inútil !! ". Eu sei pelo menos para mim, quando eu tenho esses pensamentos, eu imediatamente começar a sintonizar. Mas, durante este processo, foi legal ver quão incrivelmente prático e útil é usar o teorema de Pitágoras e outras equações de trigonometria. O ponto é, se você também se sentir assim, não sintonize. Você pode precisar usar essa informação mais cedo do que você pensa! Sinta-se livre para contatar comentários ou perguntas. Obrigado!

Texto original em inglês.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *