Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

consider adding image shape type #80

Open
oppenheimer- opened this issue Nov 21, 2019 · 8 comments · May be fixed by #243
Open

consider adding image shape type #80

oppenheimer- opened this issue Nov 21, 2019 · 8 comments · May be fixed by #243
Labels
feature request A neat new idea for this project help wanted Issue could use a contributor

Comments

@oppenheimer-
Copy link

Next to rectangles and ellipses, i'd love to see the option of using images as particle shapes.

One could use it with the standard shape array like ['image', 'image', 'circle'] to accomodate for distribution of a single image next to common shapes.
To get the single image source, it would be one way to just define it in the confetti object like:

confetti: {
  image: {
    source: 'URL',
    options: {}
  }
}

Another way could be defining a set of images in shapes as well: ['images']. Probability should fit the current system, but can be precised in its own child images' property.

To define them we use another object inside confetti:

confetti: {
  images: [
    image: {
      source: 'URL',
      chance: 0.5
      options: {}
    },
    image: {
      source: 'URL',
      chance: 0.5
      options: {}
    }
  ]
}

Thanks for this awesome project which looks by far the best! ✌🥳

@catdad catdad added the feature request A neat new idea for this project label Nov 22, 2019
@catdad
Copy link
Owner

catdad commented Nov 22, 2019

Okay, so I am just thinking out loud here... You got me thinking when I read this issue, and obviously, I made this:

image

But as much as I think that is super cool, there are some real problems. With rectangles and circles, we can do some very basic math and then draw an exact shape on the canvas. With anything else (and I played around with the idea of images, paths #81, and text #82), we need to relinquish all transformation to the canvas, which can be quite costly. In the example image above, the animation crawled... we are talking like 7fps.

I am going to need to think about this a bit more and see if I can come up with something that performs well.

@oppenheimer-
Copy link
Author

Maybe it's possible to 'dumb down' the calculations by reducing complexity from matrices down to points. so deformation would be an option. At least this is what i understand in my humble understanding of the matter.

@catdad catdad changed the title make sprites/images a shape option consider adding image shape type Dec 10, 2019
@catdad catdad added the help wanted Issue could use a contributor label Dec 14, 2019
@swhitf
Copy link
Contributor

swhitf commented May 14, 2020

I know this ticket is a year old, but I use this library extensively at the moment and would be interested in the ability to use emoji (or other small images) in place of the confetti. Would it be feasible to pre-render the rotation of the image to a sprite sheet during the loading or first pass and then use the sprite on subsequent renders to just plop the appropriate frame in place?

@catdad
Copy link
Owner

catdad commented May 18, 2020

I am not ruling that option out. I have been playing with it in the #117-sprites branch (and created #117 to track this issue). I am not too happy with it yet though. Even generating several sprites and randomizing the starting frame, I am not getting the kind of variation I want. The performance is pretty good though.

@betagole
Copy link

@catdad Do you have documentation on how to use your sprites branch? I'm currently using the script tag

<script src="https://cdn.jsdelivr.net/npm/canvas-confetti/dist/confetti.browser.min.js" async></script>

and this line in my typescript

    this.confetti(Object.assign({}, defaults, { particleCount, origin: { x: this.randomInRange(0.7, 0.9), y: Math.random() - 0.2 }, colors: ['#ffffff', '#f0554b', '#4d6faa'], zIndex: 999 }));

and I would love to be able to use different images in the confetti.

@catdad
Copy link
Owner

catdad commented Jan 30, 2021

The sprites branch is not ready for production or even usable. It is a work in progress

@Ryan2128
Copy link

Ryan2128 commented Jan 30, 2021

Hello @catdad , I want to use your outstanding work to make a snowflake mask. Snowflakes can be pictures or drawn on canvas.

Is it supported in now version? Or do I need to wait for this feature to be merged?

@lionel-rowe
Copy link

lionel-rowe commented Dec 2, 2024

Actually seems pretty simple to implement (edit: updated version that allows sprite sheets):

async function shapeFromImage(imageData) {
    const { src, scalar = 1 } = imageData
    const scale = 1 / scalar

    const img = new Image()
    img.src = src

    await new Promise((res) => img.addEventListener('load', res))

    const size = 10 * scalar

    const sx = imageData.x ?? 0
    const sy = imageData.y ?? 0
    const sWidth = imageData.width ?? img.naturalWidth
    const sHeight = imageData.height ?? img.naturalHeight

    const x = 0
    const y = 0
    const width = size
    const height = size * sHeight / sWidth

    const canvas = new OffscreenCanvas(width, height)
    const ctx = canvas.getContext('2d')
    ctx.drawImage(img, sx, sy, sWidth, sHeight, x, y, width, height)
        
    return {
        type: 'bitmap',
        bitmap: canvas.transferToImageBitmap(),
        // copied from `shapeFromText`
        matrix: [scale, 0, 0, scale, -width * scale / 2, -height * scale / 2],
    }
}

Usage example:

const shape = await shapeFromImage({
    src: 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw',
    scalar: 2,
})

confetti({
    spread: 360,
    ticks: 200,
    gravity: 0,
    decay: 0.9,
    startVelocity: 40,
    shapes: [shape],
    scalar: 2,
    particleCount: 50,
})

Or with sprite sheet:

const shapes = await Promise.all(rects.map(({ x, y, width, height }) => {
    return shapeFromImage({ src, scalar, x, y, width, height })
}))

confetti({ ...options, shapes })

Note that src must be "origin-clean" (i.e. you may get problems if the image is hosted at a different origin). If the resource can be fetched cross-origin, you can do something like URL.createObjectURL(await (await fetch(src)).blob()), or if all else fails, data URIs will always do the trick.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request A neat new idea for this project help wanted Issue could use a contributor
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants