svg六角半色调图案

ONY*_*NYX 3 html css svg

我一直在搜索google,但没有关于此问题的答案或文章。我想创建一个六边形网格,但我需要半色调图案,因此在该图案中可能需要多个六角形。下面的代码生成六边形的图案,但不是半色调图案。我需要半色调图案才能水平移动。我有Adobe的半色调图案的此链接,但网格太小且垂直,但我希望水平。这是我在codepen上制作的六边形网格的链接。有人可以告诉我使六边形的图案水平成半色调图案吗?

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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

enx*_*eta 7

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;
}
Run Code Online (Sandbox Code Playgroud)
svg{background:white; border:1px solid;width:90vh;}
polygon{fill:black}
Run Code Online (Sandbox Code Playgroud)
<svg id="svg" viewBox = "0 0 200 200" >  
</svg>
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)
svg{background:white; border:1px solid;}
polygon{fill:black}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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