g-harel/blobs

Apply an image as fill

michecode opened this issue · 5 comments

Hi I've been tinkering to try to get the fill to apply an image but it's not working

This is my current approach from scavenging stack overflow. A lot of the answers are pretty old but I'm not sure why they wouldn't work.

const blobSvgString = blobs2.svg(
  {
    seed: plant.botanicalName,
    extraPoints: 5,
    randomness: 2,
    size: 1000
  },
  {
    fill: 'url(#blob-image)'
  }
);
const blobContainer = document.getElementById('blob');
blobContainer.innerHTML = blobSvgString;
const defsMarkup = `
  <defs>
    <pattern id="blob-image" patternUnits="userSpaceOnUse" width="1000" height="1000">
      <image href="url(/images/iridescent-gradient.png)" x="0" y="0" width="1000" height="1000" />
    </pattern>
  </defs>
`;
const range = document.createRange();
const fragment = range.createContextualFragment(defsMarkup);
const svgEl = document.querySelector('#blob svg');
svgEl.insertBefore(fragment, svgEl.firstChild);

Wondering if you can provide any insight or if I'm not using it right. Thanks :) !!

Hm I've never tried filling one with an image, but I'll take a look!

My first thoughts were trying to copy the svg element after it's been manipulated to see what that looks like. You can also try using the svgPath api to build your own svg element, by default it looks like this. I'm also pretty confident that cropping out an image in the shape of a blob is possible with a canvas as a last resort.

Got it working! Ignore the broken website lol but I stole how https://lokesh-coder.github.io/blobs.app/ handled it.

Code:

<div class="absolute top-0 left-0 -z-50 mx-[5%] h-screen w-[90vw]">
  <svg
    viewBox={`0 150 ${screenWidth} ${screenHeight + 150}`}
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="100%"
    id="blobSvg"
>
  <defs>
    <clipPath id="shape">
      <path id="blob" d={path} fill="#d1d8e0" />
    </clipPath>
  </defs>
  <image
    x="0"
    y="0"
    width="100%"
    height="100%"
    clip-path="url(#shape)"
    xlink:href="/images/(image-file)"
    preserveAspectRatio="none"
  />
  </svg>
</div>

Screenshot 2023-03-03 at 3 05 06 PM

While I have an issue open do you have any idea how to constrain the blob generation within a certain box and generate to almost fill it?

Screenshot 2023-03-03 at 3 09 57 PM

My goal is to generate a blob similar to the figma mock above. So generate to fill more horizontally(?) Thanks for the help so far.

Yay that looks great!

I'd recommend just stretching the blob. Because they're ellipse shaped I thought the stretch would be enough and one size argument would be enough. I'm open to your thoughts though, it would be straightforward to add an aspect ratio variable if you're not happy with what they look like.

I spent the weekend learning a bunch about svgs lol. So you're right about the aspect ratio but when using clip paths for images you need to use a transform instead. I ended up using an svg mask with an image underneath and then stretching a standard blob!
image
Honestly this took so long for my specific case and I don't think it's worth your time to actually build in image support since its so specific 😭 I'm gonna go ahead and close it, maybe someone in the future can use this a reference. Thanks for the help though!

Happy to help, look forward to seeing the completed project!