dotLines: initial adding

This commit is contained in:
Sheldan
2025-08-08 23:50:33 +02:00
parent 7337a4c917
commit 8c86e89470
9 changed files with 1140 additions and 0 deletions

40
dotLines/src/index.html Normal file
View File

@@ -0,0 +1,40 @@
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>dotLines</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html, body, div, canvas {
margin: 0;
padding: 0;
}
html, body { width:100%; height:100%; }
canvas { display:block; }
#pauseBtn {
left: 0px;
}
#showAllBtn {
left: 60px;
}
#download {
left: 150px;
top: 3px;
}
</style>
</head>
<body>
<div id="content">
<canvas id="canvas" ></canvas>
<input type="button" class="top" id="pauseBtn" value="pause" onclick="pause()" />
<input type="button" class="top" id="showAllBtn" value="show all" onclick="showAll()" />
<a id="download" class="top" onclick="downloadCanvasCommon('dotLines', canvas)">Download</a> <br>
</div>
<script type="module" src="js/main.js"></script>
</body>
</html>

169
dotLines/src/js/main.js Normal file
View File

@@ -0,0 +1,169 @@
import {
docReady, getMousePos, pointDistance, roundedRandom
} from "canvas-common";
var canvas;
var ctx;
var drawn = {};
var mousePos = {};
var animationId;
var config = {
size: {
height: window.innerHeight,
width: window.innerWidth
},
dotLines: {
dotAmount: (window.innerHeight * window.innerWidth) / 4000,
boxWidth: 50,
boxHeight: 50,
maxLinks: 10,
mouseRange: 100,
numberOfIncrements: 50,
paused: false,
showAll: false,
minOpacity: 0.1,
fps: 30,
linkRange: 100
}
};
var currentNum = 0;
var dots = [];
function createDots() {
for (var i = 0; i < config.dotLines.dotAmount; i++) {
var dot = {};
dot.x = roundedRandom(config.size.width);
dot.y = roundedRandom(config.size.height);
dot.origin = {x: dot.x, y: dot.y};
createTarget(dot);
startDotMovement(dot);
dot.num = currentNum++;
dot.links = [];
dots.push(dot);
}
}
function createLines() {
dots.forEach(function (linkingDot) {
dots.forEach(function (linkedDot) {
if (linkingDot.links.length >= config.dotLines.maxLinks || linkedDot.links.length >= config.dotLines.maxLinks) return;
var dist = pointDistance(linkingDot, linkedDot);
if (dist < config.dotLines.linkRange && linkedDot.links.indexOf(linkingDot) == -1) {
linkingDot.links.push(linkedDot);
}
})
})
}
function renderDot(dotToRender) {
if (dotToRender.num in drawn) return;
var mouseDistance = pointDistance(dotToRender, mousePos);
if ((mouseDistance > config.dotLines.mouseRange || mouseDistance == undefined || isNaN(parseInt(mouseDistance))) && !config.dotLines.showAll) return;
drawn[dotToRender.num] = 1;
ctx.beginPath();
ctx.moveTo(dotToRender.x, dotToRender.y);
var alpha = Math.max(config.dotLines.minOpacity, 1 - (mouseDistance / config.dotLines.mouseRange));
// in case we want to show everything with full opacity
//var alpha = Math.max(!config.dotLines.showAll ? config.dotLines.minOpacity : 1, 1 - (mouseDistance / config.dotLines.mouseRange));
ctx.fillStyle = 'rgba(255, 0, 0, ' + alpha + ')';
ctx.arc(dotToRender.x, dotToRender.y, 3, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.strokeStyle = 'rgba(255, 0, 0, ' + alpha + ')';
dotToRender.links.forEach(function (tar) {
ctx.moveTo(dotToRender.x, dotToRender.y);
ctx.lineTo(tar.x, tar.y);
});
ctx.stroke();
dotToRender.links.forEach(renderDot)
}
function createTarget(dot) {
dot.target = {
x: dot.origin.x - config.dotLines.boxWidth / 2 + roundedRandom(config.dotLines.boxWidth),
y: dot.origin.y - config.dotLines.boxHeight / 2 + roundedRandom(config.dotLines.boxHeight)
};
}
function startDotMovement(dot) {
dot.targetReached = false;
createTarget(dot);
var dist = pointDistance(dot, dot.target);
var vect = {
x: dot.target.x - dot.x,
y: dot.target.y - dot.y
};
vect.x /= dist;
vect.y /= dist;
dot.distRemaining = dist;
dot.vect = vect;
}
function act(dot) {
if (dot.targetReached) {
startDotMovement(dot);
dot.x += dot.vect.x * (dot.distRemaining / config.dotLines.numberOfIncrements);
dot.y += dot.vect.y * (dot.distRemaining / config.dotLines.numberOfIncrements);
} else {
dot.x += dot.vect.x * (dot.distRemaining / config.dotLines.numberOfIncrements);
dot.y += dot.vect.y * (dot.distRemaining / config.dotLines.numberOfIncrements);
if (pointDistance(dot, dot.target) < 10) {
dot.targetReached = true;
}
}
}
function renderDots() {
drawn = {};
ctx.clearRect(0, 0, config.size.width, config.size.height);
dots.forEach(renderDot);
dots.forEach(act);
setTimeout(function () {
if(!config.dotLines.paused) {
animationId = requestAnimationFrame(renderDots);
}
}, 1000 / config.dotLines.fps)
}
function setMousePos(e) {
mousePos = getMousePos(canvas, e);
}
function pause() {
config.dotLines.paused = !config.dotLines.paused;
if (!config.dotLines.paused) {
animationId = requestAnimationFrame(renderDots);
} else {
cancelAnimationFrame(animationId);
}
}
function showAll() {
config.dotLines.showAll = !config.dotLines.showAll;
}
docReady(function () {
canvas = document.getElementById('canvas');
canvas.width = config.size.width;
canvas.height = config.size.height;
canvas.onmousemove = setMousePos;
ctx = canvas.getContext("2d");
createDots();
createLines();
requestAnimationFrame(renderDots);
});

View File

@@ -0,0 +1,24 @@
// Avoid `console` errors in browsers that lack a console.
(function() {
var method;
var noop = function () {};
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});
while (length--) {
method = methods[length];
// Only stub undefined methods.
if (!console[method]) {
console[method] = noop;
}
}
}());
// Place any jQuery/helper plugins in here.