Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pattern fill in fabricjs makes render slow

I was try to make a clip mask effect on a big picture what I've done is use picture as pattern and set it to the svg paths which support the shape.

check the jsfiddle here(maybe a little slow)

http://jsfiddle.net/minzojian/xwurbwvn/

please check the code above

enter image description here

and the result is ok,but as u drag the shape,u can find out it is not smooth,why is that?

If pattern is not the best solution,how to make irregular clip mask effect then?

like image 866
Kent Wood Avatar asked Nov 03 '25 19:11

Kent Wood


1 Answers

1 USE SMALLER PATTERN

Check updated fiddle. http://jsfiddle.net/xwurbwvn/3/

 patternSourceCanvas.setDimensions({
     width: obj.width + 55,
     height: obj.height + 55
 });

One thing is to shape your staticCanvas used for creating the pattern to the dimension of the object you are about to fill. As you see there is a "plus something" to add to the canvas. This is because the pattern fill gets shifted of half width of the path and the shifted back again ( this is to accomodate centered transforming ), so if you do not have those extra width you will see white instead.

With this solution it is smoother, not super smooth, just smoother.

 var canvas = new fabric.Canvas('canvas');

 fabric.loadSVGFromURL('http://sharepage.lunastudio.cn/flower.svg', function (objects, options) {
 var obj = fabric.util.groupSVGElements(objects, options);
 fabric.Image.fromURL('http://sharepage.lunastudio.cn/Penguins.jpg', function (img) {
     var patternSourceCanvas = new fabric.StaticCanvas();
     patternSourceCanvas.setDimensions({
         width: obj.width + 55,
         height: obj.height + 55
     });
     patternSourceCanvas.add(img);

     var s = patternSourceCanvas.getElement();
     var pattern = new fabric.Pattern({
         source: s,
         repeat: 'no-repeat'
     });
     obj.paths.forEach(function(item) {
         item.fill = pattern;
     });
     canvas.add(obj);
 });
 });
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id='canvas' width="400" height="400" style="border:#000 1px solid;"></canvas>

2 USE SMALLER PATTERN ON A SINGLE SHAPE

For a smoother experience, optimize your svg like in this fiddle: http://jsfiddle.net/xwurbwvn/4/

var canvas = new fabric.Canvas('canvas');

 fabric.loadSVGFromURL('data:image/svg+xml;utf8,<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"  width="345.657px" height="345.657px" viewBox="0 0 345.657 345.657" enable-background="new 0 0 345.657 345.657" xml:space="preserve"><g><path fill="#25A296" d="M111.14,35.006c16.891,16.892,0.734,52.632,13.953,88.862c-37.21-12.24-71.971,2.938-88.862-13.953 C21.787,95.472,23.012,78.091,34.272,66.83c6.854-6.854,18.359-7.834,27.907-5.875c-1.959-9.548-0.979-20.809,5.875-27.907 C79.315,21.787,96.696,20.563,111.14,35.006z M31.824,118.973c23.99,0,37.699,36.72,72.705,52.877c-35.006,17.625-48.96,52.877-72.705,52.877 C11.261,224.727,0,211.752,0,195.595c0-9.792,7.344-18.604,15.423-23.745C7.344,166.464,0,157.896,0,148.104 C0,131.947,11.261,118.973,31.824,118.973z M35.007,234.519c16.891-16.892,52.632-0.734,88.862-13.954c-12.24,37.21,2.938,71.972-13.954,88.862 c-14.443,14.443-31.824,13.22-43.085,1.959c-6.854-6.854-7.833-18.36-5.875-27.907c-9.547,1.958-20.808,0.979-27.907-5.875 C21.787,266.342,20.563,248.961,35.007,234.519z M118.973,313.833c0-23.99,36.72-37.699,52.877-72.705c17.625,35.006,52.877,48.96,52.877,72.705 c0,20.563-12.975,31.824-29.132,31.824c-9.792,0-18.604-7.344-23.745-15.422c-5.386,8.078-13.953,15.422-23.745,15.422 C131.947,345.657,118.973,334.396,118.973,313.833z M234.519,310.651c-16.892-16.892-0.734-52.633-13.954-88.862c37.21,12.239,71.972-2.938,88.862,13.953 c14.443,14.443,13.22,31.824,1.959,43.085c-6.854,6.854-18.36,7.833-27.907,5.875c1.958,9.547,0.979,20.808-5.875,27.907 C266.342,323.87,248.962,325.094,234.519,310.651z M313.833,226.685c-23.99,0-37.699-36.72-72.705-52.877c35.006-17.626,48.96-52.877,72.705-52.877 c20.563,0,31.824,12.975,31.824,29.131c0,9.792-7.344,18.605-15.422,23.746c8.078,5.386,15.422,13.953,15.422,23.745 C345.657,213.71,334.396,226.685,313.833,226.685z M310.651,111.139c-16.892,16.892-52.633,0.734-88.862,13.954c12.239-37.21-2.938-71.972,13.953-88.862 c14.443-14.443,31.824-13.22,43.085-1.959c6.854,6.854,7.833,18.36,5.875,27.907c9.547-1.958,20.808-0.979,27.907,5.875 C323.87,79.314,325.094,96.695,310.651,111.139z M120.687,31.823c0,23.991,36.72,39.413,52.877,74.42c17.625-35.007,52.876-50.674,52.876-74.42 C226.439,11.261,213.466,0,197.309,0c-9.792,0-18.604,7.344-23.745,15.422C168.178,7.344,159.609,0,149.817,0 C133.661,0,120.687,11.261,120.687,31.823z" /></g></svg>', function (objects, options) {
 var obj = fabric.util.groupSVGElements(objects, options);
 fabric.Image.fromURL('http://sharepage.lunastudio.cn/Penguins.jpg', function (img) {
     var patternSourceCanvas = new fabric.StaticCanvas();
     patternSourceCanvas.add(img);
     patternSourceCanvas.renderAll();
     patternSourceCanvas.setDimensions({
         width: obj.getWidth() * 1.5,
         height: obj.getHeight() * 1.5
     });
     var s = patternSourceCanvas.getElement();

     var pattern = new fabric.Pattern({
         source: s,
         repeat: 'no-repeat'
     });
     obj.paths.forEach(function (item) {
         item.fill = pattern;
     });
     canvas.add(obj);
     canvas.renderAll();
 });

 });
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id='canvas' width="400" height="400" style="border:#000 1px solid;"></canvas>

here the SVG is created as a single path, and so fabric has to do just one patternFill and not 8 of them ( one for every hearth )

3 USE ALTERNATIVES

Which is the best way to make clip path you ask.

Well it depends on what are you clipping.

You have basically 3 way: pattern fill of a shape (that is not clipping) clipping the image with a path using globalCompositeOperation

To clip the image you have to have a SINGLE shape, not 8 of them, so basically with my second example:

var canvas = new fabric.Canvas('canvas');

 fabric.loadSVGFromURL('data:image/svg+xml;utf8,<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"  width="345.657px" height="345.657px" viewBox="0 0 345.657 345.657" enable-background="new 0 0 345.657 345.657" xml:space="preserve"><g><path fill="#25A296" d="M111.14,35.006c16.891,16.892,0.734,52.632,13.953,88.862c-37.21-12.24-71.971,2.938-88.862-13.953 C21.787,95.472,23.012,78.091,34.272,66.83c6.854-6.854,18.359-7.834,27.907-5.875c-1.959-9.548-0.979-20.809,5.875-27.907 C79.315,21.787,96.696,20.563,111.14,35.006z M31.824,118.973c23.99,0,37.699,36.72,72.705,52.877c-35.006,17.625-48.96,52.877-72.705,52.877 C11.261,224.727,0,211.752,0,195.595c0-9.792,7.344-18.604,15.423-23.745C7.344,166.464,0,157.896,0,148.104 C0,131.947,11.261,118.973,31.824,118.973z M35.007,234.519c16.891-16.892,52.632-0.734,88.862-13.954c-12.24,37.21,2.938,71.972-13.954,88.862 c-14.443,14.443-31.824,13.22-43.085,1.959c-6.854-6.854-7.833-18.36-5.875-27.907c-9.547,1.958-20.808,0.979-27.907-5.875 C21.787,266.342,20.563,248.961,35.007,234.519z M118.973,313.833c0-23.99,36.72-37.699,52.877-72.705c17.625,35.006,52.877,48.96,52.877,72.705 c0,20.563-12.975,31.824-29.132,31.824c-9.792,0-18.604-7.344-23.745-15.422c-5.386,8.078-13.953,15.422-23.745,15.422 C131.947,345.657,118.973,334.396,118.973,313.833z M234.519,310.651c-16.892-16.892-0.734-52.633-13.954-88.862c37.21,12.239,71.972-2.938,88.862,13.953 c14.443,14.443,13.22,31.824,1.959,43.085c-6.854,6.854-18.36,7.833-27.907,5.875c1.958,9.547,0.979,20.808-5.875,27.907 C266.342,323.87,248.962,325.094,234.519,310.651z M313.833,226.685c-23.99,0-37.699-36.72-72.705-52.877c35.006-17.626,48.96-52.877,72.705-52.877 c20.563,0,31.824,12.975,31.824,29.131c0,9.792-7.344,18.605-15.422,23.746c8.078,5.386,15.422,13.953,15.422,23.745 C345.657,213.71,334.396,226.685,313.833,226.685z M310.651,111.139c-16.892,16.892-52.633,0.734-88.862,13.954c12.239-37.21-2.938-71.972,13.953-88.862 c14.443-14.443,31.824-13.22,43.085-1.959c6.854,6.854,7.833,18.36,5.875,27.907c9.547-1.958,20.808-0.979,27.907,5.875 C323.87,79.314,325.094,96.695,310.651,111.139z M120.687,31.823c0,23.991,36.72,39.413,52.877,74.42c17.625-35.007,52.876-50.674,52.876-74.42 C226.439,11.261,213.466,0,197.309,0c-9.792,0-18.604,7.344-23.745,15.422C168.178,7.344,159.609,0,149.817,0 C133.661,0,120.687,11.261,120.687,31.823z" /></g></svg>', function (objects, options) {
 fabric.Image.fromURL('http://sharepage.lunastudio.cn/Penguins.jpg', function (img) {
     img.clipTo = function(ctx) {
       objects[0]._render(ctx);
     }
     img.scale(0.1);
     canvas.add(img);
     canvas.renderAll();
 });

 });
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id='canvas' width="400" height="400" style="border:#000 1px solid;"></canvas>

For global composite operation is different: You have to make a group between svg ( first object ) and image ( second object ) and then set the globalCompositeOperation of svg to "destination-in".

like image 198
AndreaBogazzi Avatar answered Nov 05 '25 10:11

AndreaBogazzi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!