Highcharts: Dynamically size a solid gauge chart - javascript

I would like a solid gauge chart that adequately fills it's container. The only way to do this is to give it a size of over 100%.
pane: {
center: ['50%', '85%'],
size: '140%',
startAngle: -90,
endAngle: 90,
background: {
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || '#EEE',
innerRadius: '60%',
outerRadius: '100%',
shape: 'arc'
}
},
I also want the containing div to be vertically resizable, the problem being that, when it is resized, the chart eventually resizes outside of it's parent div's boundaries.
$('#resizer').resizable({
handles: {'s': '#sgrip'},
resize: function() {
var chart = $('#container-speed').highcharts();
chart.setSize(
this.offsetWidth - 20,
this.offsetHeight - 20,
false
);
}
});
Is there any way around this?
See example:
http://jsfiddle.net/swj1naq2/

Solved it by deciding on a maximum allowed width and preventing the chart from further resizing when this maximum is breached (using the only changing variable which is height).
$('#resizer').resizable({
handles: {'s': '#sgrip'},
resize: function() {
var chart = $('#container-speed').highcharts();
// Get approx 70% of container width
var maxAllowedWidth = (this.offsetWidth * 0.7)
var containerHeight = $(chart.container).height();
// Max allowed width should be about 70% of containers
// height so keeping within this boundary will prevent spill
if(containerHeight >= maxAllowedWidth && this.offsetHeight - 20 > containerHeight){
return;
}
chart.setSize(
this.offsetWidth - 20,
this.offsetHeight - 20,
false
);
}
});
http://jsfiddle.net/dzudn5jq/3/

Related

How to add properties to a rect when scaling on fabricjs when importing JSON?

I have a function where the rect, on scaling, cannot pass from the 20px limits on width or height, and its working fine.
document.getElementById("rectanglebtn").onclick = () => {
var rect = new fabric.Rect({
fill: fillcolor,
width: 100,
height: 100,
objectCaching: false,
stroke: "#fff",
strokeWidth: 0,
rx: 4,
ry: 4,
});
rect.minScaleLimit = 50 / rect.getScaledWidth();
rect.on('scaling', function () {
if (rect.getScaledWidth() < 20) {
rect.width = 20;
console.log("small")
}
if (rect.getScaledHeight() < 20) {
rect.height = 20;
console.log("small")
} else {}
this.set({
width: this.width * this.scaleX,
height: this.height * this.scaleY,
scaleX: 1,
scaleY: 1,
})
})
canvas.add(rect);
}
When I try to save this into a JSON, and then import it again, the previous rect with the scaling limits doesn't work like when I create a new one.
Maybe because the on scaling function is inside the rect function, and it doesn't allow to read the on scaling, but I cannot take it out because then the rect wouldn't be defined..
Maybe I should put an on scaling function on the loadfromJSON import function, but I don't really know how to do it either..
Any helps?

Fabricjs - How to detect total width/height of canvas where objects exist

So I want to save the canvas based on scale 1 and I want to include all existing/visible objects.
So right now, my canvas is 600x400 and if I were to save it, it would only save what's inside that 600x400, and it respects zoom level (a higher zoom will see less things, a lower zoom will see more things but smaller).
I've gotten around this by running this code:
let zoom = this.canvas.getZoom();
this.canvas.setZoom(1);
let url = this.canvas.toDataURL({width: 1000, height: 700, multiplier: 1});
this.canvas.setZoom(zoom);
window.open(
url,
'_blank' // <- This is what makes it open in a new window.
);
What this does is save the image as 1000x700, so stuff that were past 600px but under 1000 still gets saved.
However, this is hard coded. So I was wondering if there was an existing function or a clean/simple way to detect where all the objects are in and returns the full size (width and height).
fiddle: http://jsfiddle.net/1pxceaLj/3/
Update 1:
var gr = new this.fabric.Group([], {
left: 0,
top: 0
});
this.canvas.forEachObject( (o) => {
gr.add(o);
});
this.canvas.add(gr);
this.canvas.renderAll();
console.log(gr.height, gr.width); // 0 0
Solution
Using group was the best idea. Best example: http://jsfiddle.net/softvar/mRA8Z/
function selectAllCanvasObjects(){
var objs = canvas.getObjects().map(function(o) {
return o.set('active', true);
});
var group = new fabric.Group(objs, {
originX: 'center',
originY: 'center'
});
canvas._activeObject = null;
canvas.setActiveGroup(group.setCoords()).renderAll();
console.log(canvas.getActiveGroup().height);
}
One possibility would be to create a kind of Container using a fabricjs group and adding all created objects to this container.
I updated your fiddle here: http://jsfiddle.net/1pxceaLj/4/
Thus, you could just use group.width and group.height, perhaps adding a little offset or minimum values, and there you are having dynamical value to pass into toDataUrl even when having a smaller canvas.
code:
var canvas = new fabric.Canvas('c');
var shadow = {
color: 'rgba(0,0,0,0.6)',
blur: 20,
offsetX: 10,
offsetY: 10,
opacity: 0.6,
fillShadow: true,
strokeShadow: true
}
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: "#FF0000",
stroke: "#000",
width: 100,
height: 100,
strokeWidth: 10,
opacity: .8
});
var rect2 = new fabric.Rect({
left: 800,
top: 100,
fill: "#FF0000",
stroke: "#000",
width: 100,
height: 100,
strokeWidth: 10,
opacity: .8
});
rect.setShadow(shadow);
//canvas.add(rect);
//canvas.add(rect2);
var gr = new fabric.Group([ rect, rect2 ], {
left: 0,
top: 0
});
canvas.add(gr);
function save()
{
alert(gr.width);
alert(gr.height);
let zoom = canvas.getZoom();
var minheight = 700;
canvas.setZoom(1);
let url = this.canvas.toDataURL({width: gr.width, height: gr.height > minheight ? gr.height : minheight, multiplier: 1});
canvas.setZoom(zoom);
window.open(
url,
'_blank'
);
}

Possible to override bounding box selection area in fabricjs - controls option

Here, we are working in fabric.js with creating design tool.We have create custom selection area for canvas object in fabric.js. I read source code in fabric.js, it generates square box for bounding box, but I want change to my custom. Selection area appearance. Can someone please advise me?
We want custom selection area appearance.
We have tried this code context.setLineDash() for selection area.
if (fabric.StaticCanvas.supports('setLineDash') === true) {
ctx.setLineDash([4, 4]);
}
Refer code from Github.But won`t working fine for my working area.
Here we have attached Borderdasharray Property creation in fabric function
fabric.Object.prototype.set({
borderColor: 'green',
cornerColor: 'purple',
cornerSize: 33,
transparentCorners: false,padding:4,
borderDashArray:[50,25]
});
But we need to create animated dancing dots/moving dots for that selection area in fabric.js.
How can we create custom selection area in fabric.js?
For an animated "borderDashArray", the MDN Documentation on lineDashOffset provides a Marching Ants example with the following (fiddle demo):
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var offset = 0;
function draw() {
  ctx.clearRect(0,0, canvas.width, canvas.height);
  ctx.setLineDash([4, 2]);
  ctx.lineDashOffset = -offset;
  ctx.strokeRect(10,10, 100, 100);
}
function march() {
  offset++;
  if (offset > 16) {
    offset = 0;
  }
  draw();
  setTimeout(march, 20);
}
march();
Based on fabricjs object_interactivity.mixin.js drawBorders function, the above can be applied as follows:
fabric.Object.prototype.set({
borderColor: 'green',
cornerColor: 'purple',
cornerSize: 33,
transparentCorners: false,padding:14,
borderDashArray:[50,25]
});
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c',{width: 500, height: 500});
textbox = new fabric.Textbox('Hello, World!', {
width: 200,
height: 200,
top: 80,
left: 80,
fontSize: 50,
textAlign: 'center',
});
canvas.add(textbox);
textbox2 = new fabric.Textbox('Hello, World!', {
width: 200,
height: 200,
top: 160,
left: 160,
fontSize: 50,
textAlign: 'center',
});
canvas.add(textbox2);
canvas.renderAll();
canvas.setActiveObject(textbox);
var offset = 0;
(function animate() {
offset++;
if (offset > 75) {
offset = 0;
}
canvas.contextContainer.lineDashOffset = -offset;
canvas.renderAll();
fabric.util.requestAnimFrame(animate);
})();
canvas.on('after:render', function() {
canvas.contextContainer.strokeStyle = 'green';
canvas.contextContainer.setLineDash([50,25]);
canvas.forEachObject(function(obj) {
var bound = obj.getBoundingRect();
canvas.contextContainer.strokeRect(
bound.left + 0.5,
bound.top + 0.5,
bound.width,
bound.height
);
})
});
fabricjs border animation fiddle demo.
For customization :
borderDashArray: Dash stroke of borders
cornerDashArray: Dash stroke of corners
cornerStrokeColor: If corners are filled, this property controls the color of the stroke
cornerStyle: standrd 'rect' or 'circle'
selectionBackgroundColor: add an opaque or transparent layer to the selected object.
For use this :
fabric.Object.prototype.set({
transparentCorners: false,
borderDashArray: ......

How to stop control border padding increase when scaling an object on FabricJS?

How to stop control border padding increase when scaling an object on FabricJS?
I have a rectangle
canvas = new fabric.Canvas('c', {
backgroundColor: '#FFFFFF'
});
// create a rectangle object
var rect = new fabric.Rect({
left: 200,
top: 185,
fill: 'red',
width: 100,
height: 100,
padding: 0
});
https://jsfiddle.net/wwexsh1f/2/
Scaled Rectangle Image
When I scale my rectangle with mouse or rect.scaleTo function the control border padding also increases although padding set to 0.
How to stop padding increase on scaling?
Set strokeWidth = 0;
var rect = new fabric.Rect({
left: 200,
top: 185,
fill: 'red',
width: 100,
height: 100,
padding: 0,
strokeWidth : 0
});
It scales with the object

Rect with stroke, the stroke line is mis-transformed when scaled

I have got a lot of helps from this site and contributors here, thanks. Now I have a question about the Rectangle in Fabric.js with stroke, as I used it as kind of placeholder for images and text, when I scaled it, the border line width is scaled too, I think it's kind a problem as I want to keep the border width not changed.
var canvas = new fabric.Canvas("c1");
var el = new fabric.Rect({
originX: "left",
originY: "top",
left: 5,
top: 5,
stroke: "#ccc",
strokWidth: 1,
fill: 'transparent',
opacity: 1,
width: 200,
height: 200,
cornerSize: 6
});
canvas.add (el);
canvas.renderAll ();
See example here http://jsfiddle.net/9yb46/, try scale it horizontally. And a image is here too, and see the left border and right border width, supposed as same as top and bottom border, but not:
This can be done so that you can scale independently.
In the scaling event check the width, height and scale factors, set the height and width to the new effective values and reset the scaleX and scaleY.
This quite probably will break other things that are scaled with the object so you'd have to handle those attributes in a similar fashion.
Demo Fiddle.
var canvas = new fabric.Canvas("c1");
var el = new fabric.Rect({
originX: "left",
originY: "top",
left: 5,
top: 5,
stroke: "rgb(0,0,0)",
strokeWidth: 1,
fill: 'transparent',
opacity: 1,
width: 200,
height: 200,
cornerSize: 6
});
el.on({
'scaling': function(e) {
var obj = this,
w = obj.width * obj.scaleX,
h = obj.height * obj.scaleY,
s = obj.strokeWidth;
obj.set({
'height' : h,
'width' : w,
'scaleX' : 1,
'scaleY' : 1
});
}
});
canvas.add (el);
canvas.renderAll ();
First of all you have miss-typed the name of the property in your fiddle : strokWidth - e is missing. But this is not the cause of the problem since the default value for the strokeWidth is 1.
The scaled stroke issue is the expected behavior and what you ask to do is not. Anyway, before you check my code, read here and here and maybe some more here.
Then try this code to help with your needs, this will work perfectly only if you keep the scale ratio of your rectangle as 1:1 (scaleX = scaleY).
This is jsfiddle:
var canvas = new fabric.Canvas("c1");
var el = new fabric.Rect({
originX: "left",
originY: "top",
left: 5,
top: 5,
stroke: "rgb(0,0,0)",
strokeWidth: 1,
fill: 'transparent',
opacity: 1,
width: 200,
height: 200,
cornerSize: 6
});
el.myCustomOptionKeepStrokeWidth = 1;
canvas.on({
'object:scaling': function(e) {
var obj = e.target;
if(obj.myCustomOptionKeepStrokeWidth){
var newStrokeWidth = obj.myCustomOptionKeepStrokeWidth / ((obj.scaleX + obj.scaleY) / 2);
obj.set('strokeWidth',newStrokeWidth);
}
}
});
canvas.add (el);
canvas.renderAll ();
Fabricjs now has a strokeUniform property on fabric.Rect that can be used to prevent the stroke width from mis-transforming.
When you set strokeUniform to false it will scale with the object if true it will match the pixel size of the stroke width.
var el = new fabric.Rect({
originX: "left",
originY: "top",
left: 5,
top: 5,
stroke: "#ccc",
strokWidth: 1,
fill: 'transparent',
opacity: 1,
width: 200,
height: 200,
cornerSize: 6,
strokeUniform: true
});

Categories

Resources