andymeneely / squib

A Ruby DSL for prototyping card games.
http://squib.rocks
MIT License
916 stars 67 forks source link

Support for richer image positioning would be wonderful #238

Open bbugh opened 6 years ago

bbugh commented 6 years ago

I'm working on a game that is using photographs, and I want them to cover the art area. All of the art has been chosen so that the center of attention is in the middle of the art, so if we lose a small bit of edges, it's no big deal. In nanDECK, there was an option to draw the image centered, to best fit in a box, and then clip any overhang.

Unfortunately there's no anchor/positioning for images in Squib, which means I either had to change the source art each time I adjusted the design, or do the math manually. This has also ended up being quite ugly because I have to do a lot of array mapping in order to get things to fit into the "pass in an array" methodology.

It would be great if I could do something like:

png file: data['image'], x: 150, y: 150, valign: middle, align: center
# or
png file: data['image'], x: 150, y: 150, anchor: [:center, :middle]

Then at least I could draw over the image with the rest of the card and get the same effect.

PS Squib is really awesome, thanks for making it.

andymeneely commented 6 years ago

Yeah I'd be open to something like this. I'll have to think about the cleanest way to handle it.

For the situation you're describing, I often just make my artwork the size of the card. That way the layout doesn't look like a grid and the artwork can spill into nooks and crannies depending on the situation.

If you still need to chop the artwork there is always crop.

I think the idea of an anchor would be relatively easy to implement and simple. Having the anchor be at the center of the image means you can have varying sizes of images. We've started doing this with sprues, so doing it with anchor should be fine.

I do like the idea of having "special" words that you can put into x and y. Already "deck" is something you can put in. We can have other things like "middle" for x be width/2 and "middle" for y be height/2. That makes the logic how I handle arguments more situational, but I have some ideas on how to implement that cleanly and maintainably.

I'll definitely pursue this. I'm all for minimizing putzing around with x-y coordinates on things.

bbugh commented 6 years ago

For the situation you're describing, I often just make my artwork the size of the card. That way the layout doesn't look like a grid and the artwork can spill into nooks and crannies depending on the situation.

Unfortunately, that wouldn't make sense for our design (that we're finally happy with), but that's something we'll consider it for next time!

Here's how I ended up solving it in case anyone else runs into this. It doesn't do any clipping, the image is just drawn scaled either to width or height depending on the goal width/height, the way object-fit: cover works in CSS.

  IMAGE_WIDTH = inches(CARD_WIDTH)
  IMAGE_TOP = 164
  IMAGE_HEIGHT = 471

  # squib doesn't like redefining hash defaults so set them manually
  image_params = { file: data['imageUrl'], x: [], y: [], width: [], height: [] }

  data['imageUrl'].each do |path|
    source_width, source_height = FastImage.size(path)

    if (source_height / source_width.to_f) > (IMAGE_HEIGHT / IMAGE_WIDTH.to_f)
      fit_height = (source_height * IMAGE_WIDTH) / source_width.to_f
      image_params[:x] << 0
      image_params[:y] << IMAGE_TOP - ((fit_height - IMAGE_HEIGHT) / 2.0)
      image_params[:width] << :scale
      image_params[:height] << fit_height
    else
      fit_width = (IMAGE_HEIGHT * source_width) / source_height.to_f
      image_params[:x] << -((fit_width - IMAGE_WIDTH) / 2.0)
      image_params[:y] << IMAGE_TOP
      image_params[:width] << fit_width
      image_params[:height] << IMAGE_HEIGHT
    end
  end

  png image_params

(this code requires the fastimage library but you can use whatever you want to get the image size)

andymeneely commented 6 years ago

Been thinking about picking this up lately. Here's what I'm considering.

Add some more specials into various x-y coordinates:

Now those are just general-purpose aliases that would work on just about anything. They'd be handy if you're not sure of your final deck size and might change your mind later.

What if we also add anchor - just like with sprues' "position_reference" to the image methods? The options would be :center and :topleft.

I would also add anchor to text. That might be really tricky. Or not. I haven't really tried it yet.

I would also probably rename the sprues' "positional_reference" to "anchor". I like anchor more.

Suggestions?

LouisDeconinck commented 2 years ago

While I think the center of an object is by far the most useful and will be the most frequently used option, you could also make the four corners of an object be anchors.

An additional option in general for positioning which would be nice, is the ability to pass a percentage. So if you pass 25% as x, it will put the object at a quarter of your card. I see this is covered in #299.

I think adding an anchor to SVG, PNG and text would suffice. Like said earlier, having a center anchor for those should be priority as that will certainly solve most problems.