The essence of the question lies in the change of the script that creates the points and background animation. Currently, the first point is set from the upper left edge of the screen and aligns points to opposite edges. The problem is that the logo in the center of the screen and on its corners should be 4 points. Picture to understand the problem:

enter image description here

That is, the starting point should be from the center of the visible area of ​​the screen with a shift to the left upwards by half the value of "pointDistance" and already from this point disperse to the edges of the screen.

I would be grateful for any help.

(function() { var width, height, canvas, ctx, points, target, animateHeader = true; var pointDistance = 85; var pointRadius = 2; var raf; // Main initHeader(); initAnimation(); addListeners(); function initHeader() { width = window.innerWidth; height = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); target = {}; canvas = document.getElementById('background-canvas'); canvas.width = width; canvas.height = height; ctx = canvas.getContext('2d'); // create points initPoints(); } // Event handling function addListeners() { if(!('ontouchstart' in window)) { window.addEventListener('mousemove', mouseMove); } window.addEventListener('resize', resize); } function initAnimation() { animate(); } function animate() { if(animateHeader) { drawPoints(); } requestAnimationFrame(animate); } function mouseMove(e) { var posx = posy = 0; if (e.pageX || e.pageY) { posx = e.pageX; posy = e.pageY; } else if (e.clientX || e.clientY) { posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; } target.x = posx; target.y = posy; } function resize() { width = window.innerWidth; height = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); canvas.width = width; canvas.height = height; for(var i in points) { TweenLite.killTweensOf(points[i]); } initPoints(); } function initPoints(){ // create points points = []; for(var x = 0; x <= width/pointDistance; x++) { for(var y = 0; y < height/pointDistance; y++) { var px = x*pointDistance; var py = y*pointDistance; var p = {x: px, originX: px, y: py, originY: py }; points.push(p); } } // for each point find the 5 closest points for(var i = 0; i < points.length; i++) { var closest = []; var p1 = points[i]; for(var j = 0; j < points.length; j++) { var p2 = points[j] if(!(p1 == p2)) { var placed = false; for(var k = 0; k < 5; k++) { if(!placed) { if(closest[k] == undefined) { closest[k] = p2; placed = true; } } } for(var k = 0; k < 5; k++) { if(!placed) { if(getDistance(p1, p2) < getDistance(p1, closest[k])) { closest[k] = p2; placed = true; } } } } } p1.closest = closest; } // assign a circle to each point for(var i in points) { var c = new Circle(points[i], pointRadius, 'rgba(255,255,255,0.3)'); points[i].circle = c; } } function drawPoints(){ ctx.clearRect(0,0,width,height); for(var i in points) { if(target){ if(Math.abs(getDistance(target, points[i])) < 4000) { points[i].opacity = 0.3; points[i].circle.opacity = 1; } else if(Math.abs(getDistance(target, points[i])) < 20000) { points[i].opacity = 0.2; points[i].circle.opacity = 1; } else if(Math.abs(getDistance(target, points[i])) < 40000) { points[i].opacity = 0.1; points[i].circle.opacity = 0.8; } else { points[i].opacity = 0; points[i].circle.opacity = 0.7; } } points[i].circle.color = 'rgba(180,180,180,1)'; drawLines(points[i]); points[i].circle.draw(); } } function shiftPoint(p) { TweenLite.to(p, 1+1*Math.random(), {x:p.originX+Math.random()*(pointDistance/2), y: p.originY+Math.random()*(pointDistance/2), ease:Circ.easeInOut, onComplete: function() { shiftPoint(p); }}); } function drawLines(p) { if(target){ for(var i in p.closest) { ctx.beginPath(); ctx.moveTo(px, py); ctx.lineTo(p.closest[i].x, p.closest[i].y); ctx.strokeStyle = 'rgba(110,110,110,'+p.opacity+')'; ctx.stroke(); } } } function Circle(pos,rad,color) { var _this = this; // constructor (function() { _this.pos = pos || null; _this.radius = rad || null; _this.color = color || null; })(); this.draw = function() { ctx.beginPath(); ctx.arc(_this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false); ctx.fillStyle = 'rgba(50,50,50,'+_this.opacity+')'; ctx.fill(); }; } // Util function getDistance(p1, p2) { return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2); } })(); 
 * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font: inherit; font-size: 100%; vertical-align: baseline; } audio, canvas, video { display: inline-block; } audio:not([controls]) { display: none; height: 0; } [hidden], template { display: none; } html { line-height: 1; } abbr[title] { border-bottom: 1px dotted; } b, strong { font-weight: bold; } dfn { font-style: italic; } mark { background: #ff0; color: #000; } code, kbd, pre, samp { font-size: 1em; } pre { white-space: pre-wrap; } q { quotes: "\201C" "\201D" "\2018" "\2019"; } small { font-size: 80%; } sub, sup { position: relative; vertical-align: baseline; font-size: 75%; line-height: 0; } sup { top: -0.5em; } sub { bottom: -0.25em; } img { border: 0; max-width: 100%; } svg:not(:root) { overflow: hidden; } figure { margin: 0; } fieldset { margin: 0 2px; padding: 0.35em 0.625em 0.75em; border: 1px solid #c0c0c0; } legend { padding: 0; border: 0; } button, html input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } button[disabled], html input[disabled] { cursor: default; } input[type="checkbox"], input[type="radio"] { padding: 0; } input[type="search"] { -webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box; -webkit-appearance: textfield; } input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } button::-moz-focus-inner, input::-moz-focus-inner { padding: 0; border: 0; } textarea { overflow: auto; vertical-align: top; } div { border: 0px; } ol, ul { list-style: none; } table { border-spacing: 0; } caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } q, blockquote { quotes: none; } q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; } a img { border: none; } /*------ General style ------*/ body { font-family: 'MagistralC', sans-serif; font-size: 1em; line-height: 1.2; background-color: #000; color: rgba(255,255,255,.85); overflow-x: hidden; -webkit-font-smoothing: antialiased; } hr { display: block; height: 0; border: 0; border-top: 1px solid #ededed; margin: .4em 0; padding: 0; } img { vertical-align: middle; } fieldset { border: 0; margin: 0; padding: 0; } textarea { resize: vertical; } blockquote { margin: 30px 0px 30px 15px; padding-left: 15px; position: relative; font-style: italic; font-weight: 300; border-left: 2px solid #39F; } a { color: #fff; text-decoration: underline; } a:hover { text-decoration: none; } .with-clear:after, .clr:after { display: table; clear: both; content: ''; } footer .middle, header .middle { padding: 0 30px; } .middle { margin: 0 auto; max-width: 1260px; padding: 60px 30px; background: #000; } { -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px } .img { transition:All 0.36s ease; -webkit-transition:All 0.36s ease; -moz-transition:All 0.36s ease; -o-transition:All 0.36s ease; } .img { position: absolute; width: 104%; height: 104%; left: -2%; top: -1%; background-repeat: no-repeat; background-position: center; background-size: cover; } .valign-middle { display: -ms-flexbox; display: -webkit-flex; display: flex; -ms-flex-align: center; -webkit-align-items: center; -webkit-box-align: center; align-items: center; height: 100vh; } #background-canvas { position: absolute; left: 0; top: 0; z-index: -1; } .logo-block { width: 85px; height: 85px; line-height: 85px; margin: 0 auto; text-transform: uppercase; text-align: center; color: #333; background: #ccc; } 
 <!DOCTYPE html> <html > <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>EM</title> <link rel="stylesheet" type="text/css" href="css/style.css"> </head> <body> <main> <div class="valign-middle"> <div class="logo-block">Logo</div> </div> </main> <canvas id="background-canvas"></canvas> <script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js'></script> <script src="js/points.js"></script> </body> </html> 

  • 1. Calculate the offsetX and offsetY offset by which the point nearest the corner of the logo should move, so that it falls exactly at its angle. 2. insert this offset into the function initPoints var px = x*pointDistance + offsetX and var py = y*pointDistance + offsetY - ravend
  • The point itself is not a problem. We have a distance between points pointDistance, divide it in half and set the offset. The problem is to set the first point to the center of the screen and multiply the remaining points from the center to the edge of the screen. - Alexey Giryayev pm

1 answer 1

It is necessary to calculate how much the position of the central cell of the grid differs and to displace each cell by the required amount, in this case the central square will coincide with the logo.

The offset can be calculated for example using the following formula:

 var logo = document.querySelector('.logo-block'); var shiftX = pointDistance + logo.offsetLeft - Math.ceil(width / pointDistance/2)*pointDistance; var shiftY = pointDistance + logo.offsetTop - Math.ceil(height / pointDistance/2)*pointDistance; 

Example:

 (function() { var width, height, canvas, ctx, points, target, animateHeader = true; var pointDistance = 85; var pointRadius = 2; var raf; // Main initHeader(); initAnimation(); addListeners(); function initHeader() { width = window.innerWidth; height = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); target = {}; canvas = document.getElementById('background-canvas'); canvas.width = width; canvas.height = height; ctx = canvas.getContext('2d'); // create points initPoints(); } // Event handling function addListeners() { if (!('ontouchstart' in window)) { window.addEventListener('mousemove', mouseMove); } window.addEventListener('resize', resize); } function initAnimation() { animate(); } function animate() { if (animateHeader) { drawPoints(); } requestAnimationFrame(animate); } function mouseMove(e) { var posx = posy = 0; if (e.pageX || e.pageY) { posx = e.pageX; posy = e.pageY; } else if (e.clientX || e.clientY) { posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; } target.x = posx; target.y = posy; } function resize() { width = window.innerWidth; height = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); canvas.width = width; canvas.height = height; for (var i in points) { TweenLite.killTweensOf(points[i]); } initPoints(); } function initPoints() { var logo = document.querySelector('.logo-block'); var shiftX = pointDistance + logo.offsetLeft - Math.ceil(width / pointDistance/2)*pointDistance; var shiftY = pointDistance + logo.offsetTop - Math.ceil(height / pointDistance/2)*pointDistance; // create points points = []; for (var x = 0; x <= width / pointDistance; x++) { for (var y = 0; y < height / pointDistance; y++) { var px = x * pointDistance + shiftX; var py = y * pointDistance + shiftY; var p = { x: px, originX: px, y: py, originY: py }; points.push(p); } } // for each point find the 5 closest points for (var i = 0; i < points.length; i++) { var closest = []; var p1 = points[i]; for (var j = 0; j < points.length; j++) { var p2 = points[j] if (!(p1 == p2)) { var placed = false; for (var k = 0; k < 5; k++) { if (!placed) { if (closest[k] == undefined) { closest[k] = p2; placed = true; } } } for (var k = 0; k < 5; k++) { if (!placed) { if (getDistance(p1, p2) < getDistance(p1, closest[k])) { closest[k] = p2; placed = true; } } } } } p1.closest = closest; } // assign a circle to each point for (var i in points) { var c = new Circle(points[i], pointRadius, 'rgba(255,255,255,0.3)'); points[i].circle = c; } } function drawPoints() { ctx.clearRect(0, 0, width, height); for (var i in points) { if (target) { if (Math.abs(getDistance(target, points[i])) < 4000) { points[i].opacity = 0.3; points[i].circle.opacity = 1; } else if (Math.abs(getDistance(target, points[i])) < 20000) { points[i].opacity = 0.2; points[i].circle.opacity = 1; } else if (Math.abs(getDistance(target, points[i])) < 40000) { points[i].opacity = 0.1; points[i].circle.opacity = 0.8; } else { points[i].opacity = 0; points[i].circle.opacity = 0.7; } } points[i].circle.color = 'rgba(180,180,180,1)'; drawLines(points[i]); points[i].circle.draw(); } } function shiftPoint(p) { TweenLite.to(p, 1 + 1 * Math.random(), { x: p.originX + Math.random() * (pointDistance / 2), y: p.originY + Math.random() * (pointDistance / 2), ease: Circ.easeInOut, onComplete: function() { shiftPoint(p); } }); } function drawLines(p) { if (target) { for (var i in p.closest) { ctx.beginPath(); ctx.moveTo(px, py); ctx.lineTo(p.closest[i].x, p.closest[i].y); ctx.strokeStyle = 'rgba(110,110,110,' + p.opacity + ')'; ctx.stroke(); } } } function Circle(pos, rad, color) { var _this = this; // constructor (function() { _this.pos = pos || null; _this.radius = rad || null; _this.color = color || null; })(); this.draw = function() { ctx.beginPath(); ctx.arc(_this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false); ctx.fillStyle = 'rgba(50,50,50,' + _this.opacity + ')'; ctx.fill(); }; } // Util function getDistance(p1, p2) { return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2); } })(); 
 * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font: inherit; font-size: 100%; vertical-align: baseline; } audio, canvas, video { display: inline-block; } audio:not([controls]) { display: none; height: 0; } [hidden], template { display: none; } html { line-height: 1; } abbr[title] { border-bottom: 1px dotted; } b, strong { font-weight: bold; } dfn { font-style: italic; } mark { background: #ff0; color: #000; } code, kbd, pre, samp { font-size: 1em; } pre { white-space: pre-wrap; } q { quotes: "\201C""\201D""\2018""\2019"; } small { font-size: 80%; } sub, sup { position: relative; vertical-align: baseline; font-size: 75%; line-height: 0; } sup { top: -0.5em; } sub { bottom: -0.25em; } img { border: 0; max-width: 100%; } svg:not(:root) { overflow: hidden; } figure { margin: 0; } fieldset { margin: 0 2px; padding: 0.35em 0.625em 0.75em; border: 1px solid #c0c0c0; } legend { padding: 0; border: 0; } button, html input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } button[disabled], html input[disabled] { cursor: default; } input[type="checkbox"], input[type="radio"] { padding: 0; } input[type="search"] { -webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box; -webkit-appearance: textfield; } input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } button::-moz-focus-inner, input::-moz-focus-inner { padding: 0; border: 0; } textarea { overflow: auto; vertical-align: top; } div { border: 0px; } ol, ul { list-style: none; } table { border-spacing: 0; } caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } q, blockquote { quotes: none; } q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; } a img { border: none; } /*------ General style ------*/ body { font-family: 'MagistralC', sans-serif; font-size: 1em; line-height: 1.2; background-color: #000; color: rgba(255, 255, 255, .85); overflow-x: hidden; -webkit-font-smoothing: antialiased; } hr { display: block; height: 0; border: 0; border-top: 1px solid #ededed; margin: .4em 0; padding: 0; } img { vertical-align: middle; } fieldset { border: 0; margin: 0; padding: 0; } textarea { resize: vertical; } blockquote { margin: 30px 0px 30px 15px; padding-left: 15px; position: relative; font-style: italic; font-weight: 300; border-left: 2px solid #39F; } a { color: #fff; text-decoration: underline; } a:hover { text-decoration: none; } .with-clear:after, .clr:after { display: table; clear: both; content: ''; } footer .middle, header .middle { padding: 0 30px; } .middle { margin: 0 auto; max-width: 1260px; padding: 60px 30px; background: #000; } { -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px } .img { transition: All 0.36s ease; -webkit-transition: All 0.36s ease; -moz-transition: All 0.36s ease; -o-transition: All 0.36s ease; } .img { position: absolute; width: 104%; height: 104%; left: -2%; top: -1%; background-repeat: no-repeat; background-position: center; background-size: cover; } .valign-middle { display: -ms-flexbox; display: -webkit-flex; display: flex; -ms-flex-align: center; -webkit-align-items: center; -webkit-box-align: center; align-items: center; height: 100vh; } #background-canvas { position: absolute; left: 0; top: 0; z-index: -1; } .logo-block { width: 85px; height: 85px; line-height: 85px; margin: 0 auto; text-transform: uppercase; text-align: center; color: #333; background: #ccc; } 
 <main> <div class="valign-middle"> <div class="logo-block">Logo</div> </div> </main> <canvas id="background-canvas"></canvas> <script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js'></script> 

  • This is exactly what was needed. It remains to cope with the task so that the dots are drawn outside the screen and the lines connecting these dots do not fall into one dense line on the right side of the screen. I think I can handle this. I am very grateful for the help and working example. - Alexey Giryayev