elrumordelaluz / outline-stroke

Convert stroked SVG into the outlined version
https://outline-stroke.vercel.app/
126 stars 7 forks source link

Using this with a svgson object #1

Closed SnooHD closed 6 years ago

SnooHD commented 6 years ago

Is it possible to use a svgson path object instead of a string? I am looping through a object created with svgson, and I need to outline strokes when i run into them.

Thanks in advance!

elrumordelaluz commented 6 years ago

@SnooHD interesting use-case!

Unfortunately the input need to be a String or a Buffer. A solution could be convert the Object intro <svg> again, pass through outline-stroke and the again svgson.

If you want to share more info/code I am super happy to collaborate to find a cool solution that fits for your specific case.

SnooHD commented 6 years ago

I am working on a upload tool for svg shapes, these shapes afterwards will be free transformed by a user (selecting, dragging, rotate, scale, change colors etc.)

So if a shape is uploaded without a fill, i want to change the stroke to an outline so that the shape can be handled as any other shape. (its mainly to avoid confusion for the user, especially because for other shapes its NOT possible to set colors to 'none')

So i parse the file with svgson, loop through the objects and change certain attributes so they can work with my tool. The moment fill="none" and stroke is set, i want to convert it to an outline, and update the d attribute in my svgson object.

elrumordelaluz commented 6 years ago

each shape is an <svg>…</svg> file?

SnooHD commented 6 years ago

It are not single shapes, the svg files can contain many paths, and all of these paths need to be checked individually, so at the end, its the path data from svgson that i end up with.

I just ran into this package: https://github.com/danmarshall/svg-path-outline

It seems to do the job perfectly for my use case!

elrumordelaluz commented 6 years ago

@SnooHD came in mind a possible and probably elegant solution.

Let me know if you solved, otherwise will elaborate here or in a gist.

SnooHD commented 6 years ago

Hello, i managed to solve it! Thanks for thinking along ;)

elrumordelaluz commented 6 years ago

awesome!

elrumordelaluz commented 6 years ago

@SnooHD I am curious about two thing regarding the lib svg-path-outline, in case you could reply based on the use you are doing:

I am thinking in start playing around with this library to implement some stuff here.

Thanks in advance

SnooHD commented 6 years ago

Hi @elrumordelaluz, sorry for my late response. svg-path-outline makes it possible to create an outer or inner outline and takes in account the different joints as well (but i guess you can simply read that on the package page anyways). It keeps the current offset, so the coordinates don't change :).

I have not tested the performance, for my use case it doesn't matter that much. But i don't notice any difference with or without this package.

elrumordelaluz commented 6 years ago

Thank you @SnooHD Yes I wen a little deep in the lib and basically is bridge into maker.js library.

Since you are using it just, with

Is there a way to create the path data at the same position of the original, without offset? I wanted to know for example, if you could obtain the rect I am showing below, same appearance but filled instead of using stroke:

<svg viewbox="0 0 12 12">
  <rect width=10 height=10 x=1 y=1 fill=none stroke=blue stroke-width=2 />
</svg>
SnooHD commented 6 years ago

Hmm im not sure if I am completely understanding what you want to achieve just yet. Is this what you would want to end up with? <path d="M1,1 L11,1 L11,11 L1,11 z" fill="blue" />

The stroke always sets an inner AND outer offset, but x & y are not altered in any way. So you could convert the rect to a path and position it on x & y. Then you could simply remove the stroke all together, and change it to a fill, right?

If you want to keep the outer stroke's position, you could just take half of the stroke-width and use it to recalculate x & y. (for example: x =- stroke-width / 2).

In case you are wondering how you might position the shape (Though I think you know..?) I first parse the path with parse-svg-path, then i normalized the path to bezier curves with curvify-svg-path. This way its a lot easier to manipulate the paths, because well, it's only using curves.

Now something like this would do the job:

export const movePath = (d, x, y) => {
  for(let i=0;i<d.length;i++){
    const points = d[i];
    for(let j=0;j<points.length; j++){
      //first value is always the type
      if(j > 0){
        if(j % 2 == 0){
          //set all even values (y)
          points[j] += y;
        }else{
          //set all uneven values (x)
          points[j] += x;
        }
      }
    }
  }

  return d;
}

Hope this helps. Snoo

elrumordelaluz commented 6 years ago

Yes, the pathed version of this rect results in what you shows, but what I am looking for is to convert that d into something more complex that represents that stroke but without stroke.

Sounds a bit confusing, but essentially this is what outline-stroke solves in some way, the same result as if you have the square showed above opened in Illustrator and applied Outline stroke.

The result should be something like:

<svg viewBox="0 0 12 12">
  <path fill="#f00" d="M12,12H0V0h12V12z M2,10h8V2H2V10z"/>
</svg>

See the last square here

Let me know if is clearer the point, and in case you were talking about the same I missed something.

SnooHD commented 6 years ago

Thanks for the codepen, it cleared things up a bit. Typically speaking, this is exactly what i am actually doing as well haha. So the difficult part would be making sure that joints are taken in account.. this is the whole reason i decided to use svg-path-outline.

But i guess, if i can ignore the joints, you could simply take the rect, and change it to a path. Then you scale the path * (stroke-width / 2). So now you have the outer stroke. Then scale the original path again, but this time by / (stroke-width / 2). So now we have the outer and inner paths, so by pushing them together in the same d attribute, we can accomplish the result.

Dont forget to have a look at the fill-rule attribute :)