ibrierley / Snap.svg.FreeTransform

Free transform tool for Snap.svg elements
36 stars 10 forks source link

Update bbox() values of the transform tool #3

Open ghost opened 7 years ago

ghost commented 7 years ago

Is it possible to update the bbox() values of the FreeTransform plugin dynamically, for instance if I change the stroke size on a dynamically I need to update the FreeTransform plugin to account for the increase in size.

I was thinking if I get the bbox() values of the I'm re-styling on the fly I could then pass these values to the plugin to resize the FreeTransform handles etc ...

Is this possible?

ibrierley commented 7 years ago

Have you tried the updateHandles() method ? Could you do a minimal jsfiddle if not ?

ghost commented 7 years ago

I have tried the updateHandles() method but it doesn't appear to have any effect in this scenario.

I've created a jFiddle demonstrating the issue here: https://jsfiddle.net/9qvwLss7

Click the rectangle or the text element to change the stroke or font size to a random value, note that the handles do not update.

neilliang commented 7 years ago

It's kind of the same issue with this one #2.

ghost commented 7 years ago

@neilliang yes, seems to be some cross-over between the 2 issues.

I tried using .unplug() to remove the free transform and then re-applying the free transform plugin to the same element but the handles start to get transformed.

See this jsFiddle for demo using .unplug() to remove the FT plugin, then re-applying it: https://jsfiddle.net/zL8ytjoo/

To see the issue: Drag a corner of the rectangle or text element to make it much larger, click the rectangle or text element, handles are now larger than the size set (as is the dashed line around the element).

screen shot 2017-07-19 at 09 46 38
neilliang commented 7 years ago

Yes, the handle's size is also discussed at #2. The handle size is an issue. It's need to be fixed if @ibrierley has time for this.

ibrierley commented 7 years ago

Not sure it's the same issue (not saying there isn't a separate one tho as per other thread). I think the issue with this case if I'm understanding it right, is that SVG doesn't take into consideration stroke widths on bounding boxes.

Problem with this, is that I think it's quite hard to do (it may seem easier for a rect, but then when you get to complex paths it will get fiddly).

I'll have a think though if there are any workarounds.

ghost commented 7 years ago

Yes exactly that @ibrierley, for instance with a text element changing the font size of the element does not updated the bounding boxes.

I was wondering if there was a way to get the new dimensions of the text element and then pass those back to the FT plugin and get it to update the bounding box. However experimenting I've not be able to do so, I even tried overwriting the .bbox values for the FT plugin with the new .bbox values of the text element but couldn't get the FT plugin to act on those updates.

Appreciate the prompt replies, thanks.

ibrierley commented 7 years ago

Only quick workaround I can think of, is something to scale the bbox outwards by choice. Just testing an example at http://svg.dabbles.info/fttest/test1.html which introduces an extra option of bboxScale (at 1.5). Not sure if that would be useful. It's untested, quite possibly buggy :), so I'm not going to commit it to dev or anything atm.

I think there is still a bug related to the other issue mentioned (with the transform not quite being in sync with a handle drag), but I'm finding it difficult to reproduce consistently, but if you can find it and reproduce it, let me know.

ghost commented 7 years ago

Hmm scale bboxScale might work for our case, if we could update it based on the new scale of the element - if I can remember to how to calculate the scale of the element from the matrix.

The handle size being inconsistent is one of the main issues for me, if I could .unplug() then re-init the element with the FT plugin without the handles transforming I'd be winning.

Thanks for this.

ibrierley commented 7 years ago

Hmm I think if I'm understanding you right, it will still resize it (ie that's based on the bbox + bboxScale rather than just bboxScale), and that will still vary if you readd it, if that makes sense.

I'm maybe misunderstanding a little though, are you trying to get a consistent size handle across various displayed elements that never changes (so every handle is always the same size whatever), or just so when you double click it, it doesn't change the size ?

ghost commented 7 years ago

Ah ok, yes to clarify; I'd like the same handle size across various elements that never changes - so every handle is always the same size - whatever.

I don't want the handle size to scale/transform, I'd like it to be fixed.

ibrierley commented 7 years ago

Ok, makes perfect sense actually. I think some bits would need a major rewrite, which makes sense, just being honest, I don't have time to do just atm. I will have a think though, just don't want you reliant on a quick fix, so you may want to look at an alternate solution.

ghost commented 7 years ago

No worries dude your comments so far have been helpful - any pointers or suggestions for places to start?

ibrierley commented 7 years ago

Nothing specific that does everything already that I'm aware of..there's a few part solutions that may be of use depending on your requirement.

There is snap svg pan zoom https://github.com/hueitan/snap.svg.zpd I'm not sure if it has handles to rotate, but it's a long time since I've looked.

The original Raphael freetransform possibly works better if converted or if you are happy working with Raphael (it avoids certain issues as it was backwards compatible, but you may need to work on importing files, I think there is a plugin, but I assume it would have problems with svg groups for example).

If you are happy to dive in, you could take a look at the github stuff here and amend, but it takes a lot of getting your head around, as I didn't code it originally, just tried to convert it, one of the older versions before the extra transform stuff was added could be useful, but I think there's possibly issues either way.

I also started a Snap toolkit to help with transform stuff at http://svg.dabbles.info/snaptoolkit/snappan.html and https://github.com/ibrierley/snaptoolkit it doesn't have handles (other than 2 circles) but I did try and write it originally so it would work with hammer.js (so would work with all touch stuff), and write it so it's easy to add ones own stuff (ie a toolkit rather than a solution). It probably has bugs as well tho!

The other possible solution if you're not set on svg, but want something very close, is fabric.js which has good handle support built in, and tries to do canvas in svg format.

ibrierley commented 7 years ago

Actually, it may be worth your while trying setting the bboxScale to a sort of inverse value based on the objects bounding box or something (i.e the bigger it is, the smaller the scale you want) and doing an updateHandle(). I think it will be a bit buggy and inconsistent maybe, but it depends on your needs.

ibrierley commented 7 years ago

I've had a bit of time to look at it, and I've pushed a new version to the development branch. If you get chance, I'd like to know if it resolves the issues.

I had to do some fundamental rewrites, which possibly brought it more in line with the original workings, so it doesn't try and adapt to the transforms on the element being repositioned.

The downside is, if you unplug and plug, if the element was rotated previously, the ft handles etc, will be back in default positions (which actually I think sounds reasonable anyway). I've also got it working with sets I think.

The handles etc shouldn't rescale now, so if there are any new (different) issues, maybe raise a different bug. If it's related to this, keep them in this thread.

ghost commented 7 years ago

... where do I send beer? :)

I think I can deal with rotation in a different manner, I likely add a seperate control into the UI to deal with element rotation and disable rotation with the FT plugin.

Great stuff, thanks again!

ibrierley commented 7 years ago

If you wanted to experiment, you could try http://svg.dabbles.info/fttestnew/snap.svg.free_transform_rotatedhandle.js where I just added an option initRotatedHandle and let me know how you get on.

ghost commented 7 years ago

I'll need to create a sample for you to look at and see the issue; Almost problem solved, the rotate handles stay in the correct place but the dotted box around the element changes size depending on the angle of rotation.

Screenshot below but will create a jsFiddle to replicate soon.

ft-initrotatedhandle

ibrierley commented 7 years ago

Is that with the dev version or the experimental link above ? Just testing in Chrome it seems to behave, but I notice in Opera there is an issue. Which browser are you using out of interest ?

ibrierley commented 7 years ago

Ah nope, did it in Chrome as well, maybe best to leave the experimental one (if thats the one you are using), as I wasn't so confident some bugs wouldn't sneak in there, as it was a bit of a hack to get it working.

ghost commented 7 years ago

Yes the experimental version (http://svg.dabbles.info/fttestnew/snap.svg.free_transform_rotatedhandle.js)

I'm testing in Chrome too - Version 59.0.3071.115 (Official Build) (64-bit)

I think its because I'm having to .unplug() the FT tool after changing the font-size dynamically.

ghost commented 7 years ago

Cool, I will dabble a little and share any thought or progress (although I'm not particularly confident).

ibrierley commented 7 years ago

I think the problem is that the bounding box is calculated for the rotated element, and then it's also rotated. Not a quick fix, and conflicts with some of the changes I did to get around that, so I would stay away from the experimental one. I will have a ponder though, but assume that ones no good, and just use the dev version for the time.

ibrierley commented 7 years ago

I think for the moment, I'm going to leave it as it is on dev. That at least is consistent.

I think one of the issues, is that there are quite a few non obvious edge cases treating transformed objects differently. For example, should the handles be rotated if its an element that's rotated. Should the handles be rotated if there is an inner element that is rotated, but in a group that isn't rotated (so visually looks exactly the same). What if the elements are part of a set. Just to think about 3 off the top of my head. I'm happy to ponder and think further though with any suggestions.

ghost commented 7 years ago

Might be slightly off topic, so happy to open a seperate issue, but is there any other way to (I want to say update by there is already an updateHandles() method), lets say refresh the handles and box without calling .unplug()?

ibrierley commented 7 years ago

What are you wanting it to do different compared to updateHandles() ?

ghost commented 7 years ago

If I apply the FT tool to a text element, then change the font size, rather than resizing with the tool, I'd like the handles and box position to update based on the new size without having to unplug.

ibrierley commented 7 years ago

Ah ok, it does that for me if I'm understanding right, eg http://svg.dabbles.info/fttestnew/test2.html ? (doubleclick elements)

ghost commented 7 years ago

Yes but it calls .unplug() first before then re-applying ...

If thats the 'way' to deal with this then thats ok, just wondered if it was possible without the .unplug()

function textClick() {
    var element = s.select('#id-2');
  element.attr({
    fontSize: Math.floor(Math.random() * 70) + 10 // generate a random number between 20 - 5
  });
  **ftText.unplug();**
  // add ft to rect again
  ftText = s.freeTransform(text, { 
    snap: { rotate: 15, drag: 50, scale: 0.5 },
    drag: true,
    rotate: true,
    scale: true,
    size: 10,
    keepRatio: true,
    draw: 'bbox',
bboxScale: 1
  });
  ftText.updateHandles();
}
ibrierley commented 7 years ago

I don't think this is going to be possible short term, but as ever will ponder.