anonymoose
anonymoose

Reputation: 1243

Clip Image to Oval Shape

I have a fabric.JS canvas that I can add objects to, but I'd like to be able to clip these objects like in the fabricjs.com clip demos, but into an oval shape.

Here is what I'm working with so far (JSFiddle). I can currently crop the object to a circle shape.

var canvas = new fabric.Canvas("c");
canvas.isDrawingMode = false;

// create a rectangle object
var rect = new fabric.Rect({
  left: 100,
  top: 100,
  fill: 'red',
  width: 200,
  height: 200
});

$("#clipCircle").click(function() {
  var obj = canvas.getActiveObject();
  if (!obj) return;

  if (obj.clipTo) {
    obj.clipTo = null;
  } else {
    var radius = obj.width < obj.height ? (obj.width / 2) : (obj.height / 2);
    obj.clipTo = function(ctx) {
      ctx.arc(0, 0, radius, 0, Math.PI * 2, true);
    };
  }
  canvas.renderAll();
});

// "add" rectangle onto canvas
canvas.add(rect);

// select, draw
$("#select").click(function() {
  canvas.isDrawingMode = false;
});
$("#draw").click(function() {
  canvas.isDrawingMode = true;
});
var activeObject = null;
canvas.on('selection:created', function(options) {
  activeObject = options.target;
  $("#alpha").slider("option", "value", activeObject.opacity);
});
canvas.on('selection:updated', function(options) {
  activeObject = options.target;
  $("#alpha").slider("option", "value", activeObject.opacity);
});
canvas.on('selection:cleared', function(options) {
  activeObject = null;
});
$("#alpha").slider({
  max: 1,
  min: 0,
  step: 0.1,
  value: 1,
  slide: function(event, ui) {
    activeObject && (activeObject.opacity = ui.value)
    canvas.requestRenderAll();
  },
  stop: function(event, ui) {
    canvas.requestRenderAll();
  }
});
canvas {
  border: solid 1px #000;
}

fieldset {
  max-width: 350px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="400" height="400"></canvas>
<br>
<button id="draw">Draw</button>
<button id="select">Select</button>
<button id="clipCircle">Crop to Circle</button>
<button id="clipOval">Crop to Oval</button>
<br>
<br>
<fieldset>
  <legend>Controls</legend>
  <label for="alpha">Opactity</label>
  <div id="alpha" name="alpha"></div>
</fieldset>

How might I accomplish this? Thanks in advance.

Upvotes: 2

Views: 683

Answers (1)

aaronedmistone
aaronedmistone

Reputation: 999

Here is my suggestion, this worked for me with your example.

By scaling the ctx to 0.5 on one axis you can then project a normal sphere scaled to an oval shape, then restore the ctx.

var radius = obj.width < obj.height ? (obj.width / 2) : (obj.height / 2);
obj.clipTo = function(ctx) {
    ctx.scale(0.5, 1);
    ctx.arc(0, 0, radius, 0, Math.PI * 2, true);
    ctx.restore();
};

Screenshot:

This produces the following red shape when clipping your red cube object:

cool beans

Upvotes: 2

Related Questions