Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

svg hexagon halftone pattern

Tags:

html

css

svg

I've been searching google but there is no answers or articles to this question. I want to create a grid of hexagons but I need it in a halftone pattern, so I might need more than one hexagon in the pattern. Below is the code that generates a pattern of hexagons but not in halftone pattern. I need the halftone pattern to go horizontally. I have this link of the halftone pattern from adobe but the grid is too small and it goes vertically but I want it horizontally. Here is a link of the grid of hexagons I made on codepen. Could someone show me to make a pattern of hexagons go horizontally in a halftone pattern, please?

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
  background: black;
}
svg {
  background: rgb(125, 155, 132);
}

polygon {
  fill: rgb(125, 155, 132);
  stroke-width: 1;
  stroke: #000;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
         <defs>
            <pattern id="hexagons" width="50" height="43.4" 
            patternUnits="userSpaceOnUse" 
            patternTransform="scale(2)">
                <polygon 
                points="24.8,22 37.3,29.2 37.3,43.7 24.8,50.9 12.3,43.7 12.3,29.2" 
                id="hex" shape-rendering="geometricPrecision" />
                <use xlink:href="#hex" x="25" />
                <use xlink:href="#hex" x="-25" />
                <use xlink:href="#hex" x="12.5" y="-21.7" />
                <use xlink:href="#hex" x="-12.5" y="-21.7" />
            </pattern>
         </defs>
        <rect width="100%" height="100%" fill="url(#hexagons)" />
    </svg>
like image 682
ONYX Avatar asked Dec 18 '22 16:12

ONYX


1 Answers

Since the radiuses of the hexagons are a variable of x you can't use patterns here. the main idea is this:

  • the svg background is white;
  • the hexagons have fill:black;
  • in order to draw the hexagons you need to calculate the center of the of the circumscribed circle. You do it using the value of the radius of the circumscribed circle R. This is generating a hexagonal lattice.
  • Inside the hexagonal lattice you need to change the radius of the of the circumscribed circle for the hexagons in function of y like this: let r = R * Math.sin(angle) where the angle is in function of the x value and calculates like this: let angle = map(x, 0, H, 0, Math.PI); This means that the x is taking a value between 0 and 200 (H) and the angle will have a value between o and Math.PI.

Please read the comments in my code.

const SVG_NS = 'http://www.w3.org/2000/svg';
const SVG_XLINK = "http://www.w3.org/1999/xlink"
// variables used to draw the hexagon stack
let R = 5;// the radius of the circumscribed circle
let h = R * Math.sin(Math.PI / 3);//half height of the hexagon
let offset = 1.5 * R;//used to offset every second row of hexagons
let W = 200,H=200;//svg's viewBox = "0 0 200 200"

//draw the hexagonal lattice
let i = 0;
for(let y = 0; y<H; y+=h){
i++
let o = (i%2 == 0) ? offset : 0;
for(let x = o; x<W; x+=3*R){
  hex(x,y)
}
}


 // a function used to draw the hexagom
 // the radius of the hexagon depends on the x value
 function hex(x,y) {
    // the radius of the drawn hexagon is in function of the x value
    let angle = map(x, 0, H, 0, Math.PI);
    let r = R * Math.sin(angle) - .5
   
    let points = ""
    for (var a = 0; a < 6; a++) {
      let o = {}
      o.x = x + r * Math.cos(a * Math.PI / 3);
      o.y = y + r * Math.sin(a * Math.PI / 3);
      points+= `${o.x}, ${o.y} `
    } 
   
     let hexagon = drawSVGelmt({points:points},"polygon", svg)
  }



// a function used to draw a new svg element
function drawSVGelmt(o,tag, parent) {
  
  let elmt = document.createElementNS(SVG_NS, tag);
  for (let name in o) {
    if (o.hasOwnProperty(name)) {
      elmt.setAttributeNS(null, name, o[name]);
    }
  }
  parent.appendChild(elmt);
  return elmt;
}


function map(n, a, b, _a, _b) {
  let d = b - a;
  let _d = _b - _a;
  let u = _d / d;
  return _a + n * u;
}
svg{background:white; border:1px solid;width:90vh;}
polygon{fill:black}
<svg id="svg" viewBox = "0 0 200 200" >  
</svg>

UPDATE

The OP is commenting:

Thats kinda what I want but I'm trying to make a pattern so I can then use that patter for a mask for an image

and latter:

basically what you have made works but I need the pattern to repeat across the page becuase the image will be 100% width and about 800px height

In this case you can put all the hexagons in a group and use clipPath to clip the group like so:

var SVG_NS = 'http://www.w3.org/2000/svg';
var SVG_XLINK = "http://www.w3.org/1999/xlink"
let H = 800,W=500
var R = 5;
//var l = R;
var h = R * Math.sin(Math.PI / 3);
var offset = 1.5 * R;



let i = 0;
for(let y = 0; y<H; y+=h){
i++
let o = (i%2 == 0) ? offset : 0;
for(let x = o; x<W; x+=3*R){
  hex(x,y)
}
}

 function hex(x,y) {
    let angle = map(x, 0, W, 0, Math.PI);
    let r = R * Math.sin(angle) - .5
   
    let points = ""
    for (var a = 0; a < 6; a++) {
      let o = {}
      o.x = x + r * Math.cos(a * Math.PI / 3);
      o.y = y + r * Math.sin(a * Math.PI / 3);
      points+= `${o.x}, ${o.y} `
    } 
   
     let hexagon = drawSVGelmt({points:points},"polygon", svg)
  }




function drawSVGelmt(o,tag, parent) {
  
  let elmt = document.createElementNS(SVG_NS, tag);
  for (let name in o) {
    if (o.hasOwnProperty(name)) {
      elmt.setAttributeNS(null, name, o[name]);
    }
  }
  parent.appendChild(elmt);
  return elmt;
}


function map(n, a, b, _a, _b) {
  let d = b - a;
  let _d = _b - _a;
  let u = _d / d;
  return _a + n * u;
}
svg{background:white; border:1px solid;}
polygon{fill:black}
<svg viewBox = "0 0 500 800" > 
<clipPath  id="clip">
  <polygon points="250,0 100,100 0 300 100,600 200,800 400,600 500,500 400,200 250,0"/>
</clipPath>
  
<g id="svg" style="clip-path: url(#clip)"></g>
</svg>

And if you don't specify the width of the svg element, it will take all the width available i.e: 100%.

like image 59
enxaneta Avatar answered Dec 29 '22 00:12

enxaneta