Related
Here's my code:
ngAfterContentChecked() {
this.updateGUI();
}
#HostListener('window:resize', ['$event'])
onResize(event) {
this.updateGUI();
}
updateGUI() {
let mainToolbar = this.helpers.getBoundingClientRect(document.getElementById('main-toolbar'));
this.mainSidenavContentHeight = document.documentElement.clientHeight - mainToolbar.height;
let recipeBuilder = this.helpers.getBoundingClientRect(document.getElementById('recipe-builder'));
if (recipeBuilder !== null) {
this.mainSidenavContentHeight -= recipeBuilder.height;
console.log("recipeBuilder");
}
console.log("updateGUI");
}
// helpers
static getBoundingClientRect(element) {
if (element === null) {
return null;
}
var rect = element.getBoundingClientRect();
return {
top: rect.top,
right: rect.right,
bottom: rect.bottom,
left: rect.left,
width: rect.width,
height: rect.height,
x: rect.x,
y: rect.y
};
}
Switching to a component (i.e. load by route) where recipe-builder is not more present anymore, the first time it logs:
recipeBuilder
updateGUI
Buw ff I click some seconds later, only:
updateGUI
So it seems first time I load the component, recipe-builder is still active on DOM, thus it calculate its height (which I don't want, of course).
What's the correct way to manage this in Angular? i.e. retrieve DOM properties of a HTML component and be sure they are unloaded when "destroyed"?
I use Threejs and I would like to create a function to display a descriptive card (Render() of Satllite.js) when I click on a Sphere. (Satellite.js)
/********** Imports **********/
import React, { PureComponent } from 'react';
import * as THREE from 'three';
import satData from '../data/sat.json';
export class Satellites extends PureComponent {
constructor(props) {
super(props)
this.state = { open: true }
this.x = {};
this.mouse = {};
this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2();
}
onDocumentMouseDown = event => {
event.preventDefault()
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
// find intersections
this.raycaster.setFromCamera(this.mouse, this.props.camera)
this.intersects = this.raycaster.intersectObjects(
this.scene.className("card"),
false
)
if (this.intersects.length > 0) {
if (this.intersects[0].object.callback)
this.intersects[0].object.callback()
this.intersects[0].className(".card")
this.particle = new THREE.Sprite(this.particleMaterial)
this.particle.position.copy(this.intersects[0].point)
this.particle.scale.x = this.particle.scale.y = 16
this.props.scene.add(this.particle)
}
}
componentDidMount() {
// Satellite Sphere
// this.geometry = new THREE.SphereGeometry( this.props.data.r, 32, 32 );
this.geometry = new THREE.SphereGeometry(10, 32, 32)
this.material = new THREE.MeshBasicMaterial({ color: 0xffff00 })
this.sphere = new THREE.Mesh(this.geometry, this.material)
this.sphere.callback = function() {
console.log('Toto!')
}
this.sphere.position.set(50, 50, 50)
this.props.scene.add(this.sphere)
document.addEventListener('mousedown', this.onDocumentMouseDown, true)
}
// componentDidUpdate() {
// // update satelite pos.
// const radius = 10;
// const scale = radius * 1;
// this.sphere.scale.x = scale;
// this.sphere.scale.y = scale;
// this.sphere.scale.z = scale;
// }
componentWillUnmount() {
document.removeEventListener('mousedown', this.onDocumentMouseDown);
}
render() {
return (
<div>
{satData.map((satDetail, index) => {
return <div key={index} className="card">
<h2>{satDetail.satName.toUpperCase()}</h2>
<div className="cardImg" >
<img src={satDetail.satImg} alt={satDetail.satAlt} />
</div>
<div>
<p>Altitude : <span>{satDetail.alt}</span> km</p>
<p>Longitude : <span>{satDetail.long}</span> °</p>
<p>Latitude : <span>{satDetail.lat}</span> °</p>
</div>
<button onClick={this.closeModal}>Fermer</button>
</div>
})}
</div>
)
}
}
More details here
I got the code of a tutorial that show white squares but I would like to display my div ".card" which is in the "Render"
What is the method ?
Thanks for help !
This answer involves many topics combined, basically you need:
Raycast the mouse click and find the object intersection,
Get info by picked object,
Display it if object was selected, or hide if nothing was picked by mouse.
Test it here: http://jsfiddle.net/mmalex/9k4qbL8s/
let cardShown = false;
function showCard(userText) {
var divElement = $("#card");
if (divElement) {
if (!cardShown) {
divElement.css({
display: "block",
opacity: 0,
height: "0px"
});
}
divElement.text("Object color: " + userText);
if (!cardShown) {
setTimeout(function() {
divElement.css({
opacity: 1,
height: "16px"
});
}, 25);
}
cardShown = true;
}
}
function hideCard() {
var divElement = $("#card");
if (divElement) {
divElement.css({
height: "0px",
opacity: 0
});
cardShown = false;
}
}
var scene = new THREE.Scene();
var raycaster = new THREE.Raycaster();
//create some camera
camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 5;
camera.position.y = 5;
camera.position.z = 5;
camera.lookAt(0, 0, 0);
var controls = new THREE.OrbitControls(camera);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0x595959));
document.body.appendChild(renderer.domElement);
// white spotlight shining from the side, casting a shadow
var spotLight = new THREE.SpotLight(0xffffff, 2.5, 25, Math.PI / 6);
spotLight.position.set(4, 10, 7);
scene.add(spotLight);
// collect objects for raycasting,
// for better performance don't raytrace all scene
var clickableObjects = [];
var colors = new RayysWebColors();
for (let k = 0; k < 12; k++) {
var size = 0.5;
var geometry = new THREE.BoxGeometry(size, 0.2, size);
var randomColor = colors.pickRandom();
var material = new THREE.MeshPhongMaterial({
color: randomColor.hex,
transparent: true,
opacity: 0.75
});
var cube = new THREE.Mesh(geometry, material);
cube.userData.userText = randomColor.name;
cube.applyMatrix(new THREE.Matrix4().makeTranslation(k % 3, 0, Math.floor(k / 3) - 1));
scene.add(cube);
clickableObjects.push(cube);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
// this will be 2D coordinates of the current mouse position, [0,0] is middle of the screen.
var mouse = new THREE.Vector2();
var clickedObj; // this objects is hovered at the moment
// Following two functions will convert mouse coordinates
// from screen to three.js system (where [0,0] is in the middle of the screen)
function updateMouseCoords(event, coordsObj) {
coordsObj.x = ((event.clientX - renderer.domElement.offsetLeft + 0.5) / window.innerWidth) * 2 - 1;
coordsObj.y = -((event.clientY - renderer.domElement.offsetTop + 0.5) / window.innerHeight) * 2 + 1;
}
function onMouseUp(event) {
updateMouseCoords(event, mouse);
latestMouseProjection = undefined;
clickedObj = undefined;
raycaster.setFromCamera(mouse, camera); {
var intersects = raycaster.intersectObjects(clickableObjects);
if (intersects.length > 0) {
latestMouseProjection = intersects[0].point;
clickedObj = intersects[0].object;
showCard(clickedObj.userData.userText);
} else {
clickedObj = undefined;
hideCard();
}
}
}
window.addEventListener('mouseup', onMouseUp, false);
animate();
I am building an ExtJS4 Web Application. I have a form that the user can fill up. I am able to do basic CRUD on the data that the user inputs. I added functionality to this by enabling the user to print the form. To achieve this, I wrote an override for the form.Panel X-Types as such. I modified a code I found online:
print: function(pnl) {
if (!pnl) {
pnl = this;
}
// instantiate hidden iframe
var iFrameId = "printerFrame";
var printFrame = Ext.get(iFrameId);
if (printFrame === null) {
printFrame = Ext.getBody().appendChild({
id: iFrameId,
tag: 'iframe',
cls: 'x-hidden',
style: {
display: "none"
}
});
}
var cw = printFrame.dom.contentWindow;
var stylesheets = "";
var markup;
// instantiate application stylesheets in the hidden iframe
var printTask = new Ext.util.DelayedTask(function(){
// print the iframe
cw.print();
// destroy the iframe
Ext.fly(iFrameId).destroy();
});
var strTask = new Ext.util.DelayedTask(function(){
var str = Ext.String.format('<html><head>{0}</head><body>{1}</body></html>',stylesheets,markup);
// output to the iframe
cw.document.open();
cw.document.write(str);
cw.document.close();
// remove style attrib that has hardcoded height property
// cw.document.getElementsByTagName('DIV')[0].removeAttribute('style');
printTask.delay(500);
});
var markUpTask = new Ext.util.DelayedTask(function(){
// get the contents of the panel and remove hardcoded overflow properties
markup = pnl.getEl().dom.innerHTML;
while (markup.indexOf('overflow: auto;') >= 0) {
markup = markup.replace('overflow: auto;', '');
}
while (markup.indexOf('background: rgb(255, 192, 203) !important;') >= 0) {
markup = markup.replace('background: rgb(255, 192, 203) !important;', 'background: pink !important;');
}
strTask.delay(500);
});
var styleSheetConcatTask = new Ext.util.DelayedTask(function(){
// various style overrides
stylesheets += ''.concat(
"<style>",
".x-panel-body {overflow: visible !important;}",
// experimental - page break after embedded panels
// .x-panel {page-break-after: always; margin-top: 10px}",
"</style>"
);
markUpTask.delay(500);
});
var styleSheetCreateTask = new Ext.util.DelayedTask(function(){
for (var i = 0; i < document.styleSheets.length; i++) {
stylesheets += Ext.String.format('<link rel="stylesheet" href="{0}" />', document.styleSheets[i].href);
}
styleSheetConcatTask.delay(500);
});
styleSheetCreateTask.delay(500);
}
I used the delay functions to ensure that the function finishes its operations because there are times that the print preview fails.
This code works, it can print out text fields, labels, as well as field sets. However, it does not render radio buttons at all. Now, I am not sure why it does not.
I am using : https://github.com/angular-ui/ui-grid.info/tree/gh-pages/release/3.0.0-RC.18
<div ui-grid="gridOptions" style="height:765px"></div>
When I hard code the value, as shown above, the grid spreads out and everything works as expected.
However, if I do the following...
$scope.gridStyle = 'height:'+numRows*rowHeight+'px' //(765px);
<div ui-grid="gridOptions" style="{{gridStyle}}"></div>
The height is printed in the div and div widens but the content itself widens to only around 340px. The space that is left is blank, so instead of 25 rows I see only 8. I have to scroll down, while there is a whole 400px free in the grid. The ui-grid-viewport and ui-grid-canvas are both not using this space...
Why can't the ui-grid-viewport use that space?
I use ui-grid - v3.0.0-rc.20 because a scrolling issue is fixed when you go full height of container. Use the ui.grid.autoResize module will dynamically auto resize the grid to fit your data. To calculate the height of your grid use the function below. The ui-if is optional to wait until your data is set before rendering.
angular.module('app',['ui.grid','ui.grid.autoResize']).controller('AppController', ['uiGridConstants', function(uiGridConstants) {
...
$scope.gridData = {
rowHeight: 30, // set row height, this is default size
...
};
...
$scope.getTableHeight = function() {
var rowHeight = 30; // your row height
var headerHeight = 30; // your header height
return {
height: ($scope.gridData.data.length * rowHeight + headerHeight) + "px"
};
};
...
<div ui-if="gridData.data.length>0" id="grid1" ui-grid="gridData" class="grid" ui-grid-auto-resize ng-style="getTableHeight()"></div>
A simpler approach is set use css combined with setting the minRowsToShow and virtualizationThreshold value dynamically.
In stylesheet:
.ui-grid, .ui-grid-viewport {
height: auto !important;
}
In code, call the below function every time you change your data in gridOptions. maxRowToShow is the value you pre-defined, for my use case, I set it to 25.
ES5:
setMinRowsToShow(){
//if data length is smaller, we shrink. otherwise we can do pagination.
$scope.gridOptions.minRowsToShow = Math.min($scope.gridOptions.data.length, $scope.maxRowToShow);
$scope.gridOptions.virtualizationThreshold = $scope.gridOptions.minRowsToShow ;
}
.ui-grid, .ui-grid-viewport,.ui-grid-contents-wrapper, .ui-grid-canvas {
height: auto !important;
}
UPDATE:
The HTML was requested so I've pasted it below.
<div ui-grid="gridOptions" class="my-grid"></div>
ORIGINAL:
We were able to adequately solve this problem by using responsive CSS (#media) that sets the height and width based on screen real estate. Something like (and clearly you can add more based on your needs):
#media (min-width: 1024px) {
.my-grid {
width: 772px;
}
}
#media (min-width: 1280px) {
.my-grid {
width: 972px;
}
}
#media (min-height: 768px) {
.my-grid {
height: 480px;
}
}
#media (min-height: 900px) {
.my-grid {
height: 615px;
}
}
The best part about this solution is that we need no resize event handling to monitor for grid size changes. It just works.
I like Tony approach. It works, but I decided to implement in different way. Here my comments:
1) I did some tests and when using ng-style, Angular evaluates ng-style content, I mean getTableHeight() function more than once. I put a breakpoint into getTableHeight() function to analyze this.
By the way, ui-if was removed. Now you have ng-if build-in.
2) I prefer to write a service like this:
angular.module('angularStart.services').factory('uiGridService', function ($http, $rootScope) {
var factory = {};
factory.getGridHeight = function(gridOptions) {
var length = gridOptions.data.length;
var rowHeight = 30; // your row height
var headerHeight = 40; // your header height
var filterHeight = 40; // your filter height
return length * rowHeight + headerHeight + filterHeight + "px";
}
factory.removeUnit = function(value, unit) {
return value.replace(unit, '');
}
return factory;
});
And then in the controller write the following:
angular.module('app',['ui.grid']).controller('AppController', ['uiGridConstants', function(uiGridConstants) {
...
// Execute this when you have $scope.gridData loaded...
$scope.gridHeight = uiGridService.getGridHeight($scope.gridData);
And at the HTML file:
<div id="grid1" ui-grid="gridData" class="grid" ui-grid-auto-resize style="height: {{gridHeight}}"></div>
When angular applies the style, it only has to look in the $scope.gridHeight variable and not to evaluate a complete function.
3) If you want to calculate dynamically the height of an expandable grid, it is more complicated. In this case, you can set expandableRowHeight property. This fixes the reserved height for each subgrid.
$scope.gridData = {
enableSorting: true,
multiSelect: false,
enableRowSelection: true,
showFooter: false,
enableFiltering: true,
enableSelectAll: false,
enableRowHeaderSelection: false,
enableGridMenu: true,
noUnselect: true,
expandableRowTemplate: 'subGrid.html',
expandableRowHeight: 380, // 10 rows * 30px + 40px (header) + 40px (filters)
onRegisterApi: function(gridApi) {
gridApi.expandable.on.rowExpandedStateChanged($scope, function(row){
var height = parseInt(uiGridService.removeUnit($scope.jdeNewUserConflictsGridHeight,'px'));
var changedRowHeight = parseInt(uiGridService.getGridHeight(row.entity.subGridNewUserConflictsGrid, true));
if (row.isExpanded)
{
height += changedRowHeight;
}
else
{
height -= changedRowHeight;
}
$scope.jdeNewUserConflictsGridHeight = height + 'px';
});
},
columnDefs : [
{ field: 'GridField1', name: 'GridField1', enableFiltering: true }
]
}
tony's approach does work for me but when do a console.log, the function getTableHeight get called too many time(sort, menu click...)
I modify it so the height is recalculated only when i add/remove rows. Note: tableData is the array of rows
$scope.getTableHeight = function() {
var rowHeight = 30; // your row height
var headerHeight = 30; // your header height
return {
height: ($scope.gridData.data.length * rowHeight + headerHeight) + "px"
};
};
$scope.$watchCollection('tableData', function (newValue, oldValue) {
angular.element(element[0].querySelector('.grid')).css($scope.getTableHeight());
});
Html
<div id="grid1" ui-grid="gridData" class="grid" ui-grid-auto-resize"></div>
I am late to the game but I found a nice solution. I created a custom attribute directive all you need to do is pass in the gridApi and it will automatically calculate the height. It also subscribes to the pagination change event so if the user changes page size it will resize.
class UIGridAutoResize implements ng.IDirective {
link: (scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes) => void;
scope: { gridApi: "=" };
restrict = "A";
private previousValue: string;
private isValid: boolean = true;
private watch: any;
constructor($timeout: ng.ITimeoutService) {
UIGridAutoResize.prototype.link = (scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes) => {
const gridOptions = scope.$eval(attrs.uiGrid) as any;
const gridApi = scope.$eval(attrs.gridResize) as any;
gridApi.core.on.rowsRendered(scope, () => {
$timeout(() => {
this.autoSizeGrid(element, attrs, gridOptions, gridApi, false);
}, 100);
});
gridApi.core.on.filterChanged(scope, () => {
this.autoSizeGrid(element, attrs, gridOptions, gridApi, false);
});
if (attrs.uiGridPagination === "") {
gridApi.pagination.on.paginationChanged(null, () => {
this.autoSizeGrid(element, attrs, gridOptions, gridApi, true);
});
}
angular.element(window).resize(() => {
$timeout(() => {
this.autoSizeGrid(element, attrs, gridOptions, gridApi, false);
}, 100);
});
};
}
static Factory(): ng.IDirectiveFactory {
const directive = ($timeout: ng.ITimeoutService) => {
return new UIGridAutoResize($timeout);
};
directive["$inject"] = ["$timeout"];
return directive;
}
private autoSizeGrid(element: ng.IAugmentedJQuery, attrs: ng.IAttributes, gridOptions: any, gridApi: any, isPaginationChanged: boolean) {
gridApi.core.handleWindowResize();
// Clear empty grid message
angular.element(element.parent()).find("#emptyGridMessage").remove();
element.find(".ui-grid-viewport").css("display", "");
if (attrs.hidePageSize === "") {
element.find(".ui-grid-pager-row-count-picker").css("display", "none");
}
let rowCount = gridApi.core.getVisibleRows().length;
const headerElements = element.find(".ui-grid-header");
let headerHeight = 2;
if (headerElements.length > 1) { // If we have more than one header element the grid is using grouping
const headerElement = angular.element(headerElements[1]);
headerHeight += headerElement.height();
} else {
headerHeight += headerElements.height();
}
if (attrs.uiGridPagination === "") {
if (rowCount < 1) {
gridOptions.enablePagination = false;
gridOptions.enablePaginationControls = false;
element.css("height", (rowCount * 30) + headerHeight - 2);
element.find(".ui-grid-viewport").css("display", "none");
angular.element("<div id='emptyGridMessage' style='font-size: 1em; width: 100%; background-color: white; border: 1px solid #d4d4d4; padding: 7px 12px; color: #707070;'><span style='opacity: 0.95;'>There are no records.</span></div>").insertAfter(element);
} else if (gridApi.core.getVisibleRows().length < gridOptions.paginationPageSize && !isPaginationChanged) {
gridOptions.enablePagination = false;
gridOptions.enablePaginationControls = false;
element.css("height", (rowCount * 30) + headerHeight);
} else {
gridOptions.enablePagination = true;
gridOptions.enablePaginationControls = true;
element.css("height", (rowCount * 30) + headerHeight);
}
} else {
if (rowCount < 1) {
element.css("height", (rowCount * 30) + headerHeight - 2);
element.find(".ui-grid-viewport").css("display", "none");
angular.element("<div id='emptyGridMessage' style='font-size: 1em; width: 100%; background-color: white; border: 1px solid #d4d4d4; padding: 7px 12px; color: #707070;'><span style='opacity: 0.95;'>There are no records.</span></div>").insertAfter(element);
} else {
element.css("height", (rowCount * 30) + headerHeight);
}
}
// Add extra margin to prevent scroll bar and pager from overlapping content underneath
const pagerHeight = element.find(".ui-grid-pager-panel").height();
if (rowCount > 0) {
if (pagerHeight > 0)
element.css("margin-bottom", pagerHeight);
else
element.css("margin-bottom", 10);
} else {
if (pagerHeight > 0)
angular.element(element.parent()).find("#emptyGridMessage").css("margin-bottom", pagerHeight);
else
angular.element(element.parent()).find("#emptyGridMessage").css("margin-bottom", 10);
}
if (rowCount > gridOptions.paginationPageSize) // Sometimes paging shows all rows this fixes that
gridApi.core.refresh();
}
}
<div ui-grid="vm.gridOptions" grid-resize="vm.gridApi" ui-grid-resize-columns ui-grid-pagination></div>
following #tony's approach, changed the getTableHeight() function to
<div id="grid1" ui-grid="$ctrl.gridOptions" class="grid" ui-grid-auto-resize style="{{$ctrl.getTableHeight()}}"></div>
getTableHeight() {
var offsetValue = 365;
return "height: " + parseInt(window.innerHeight - offsetValue ) + "px!important";
}
the grid would have a dynamic height with regards to window height as well.
Is there a way to make a Fabric.js canvas resize with the browser to enable the same result on any device? I'm talking about responsive design.
Has anyone a code example?
This jsFiddle is a working solution. It is inspired by this github issue.
These are the required things:
A div that surrounds the canvas that is controlled by fabric.
<div class="fabric-canvas-wrapper">
<canvas id="theCanvas"></canvas>
</div>
And a window resize handler that triggers the calculation and setting of the new canvas dimension and the zoom.
window.onresize = resizeCanvas() {
const outerCanvasContainer = document.getElementById('fabric-canvas-wrapper');
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = outerCanvasContainer.clientWidth;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
}
That's all. It seems to work perfectly. Please let me know if any issues come up with this solution.
I have used fabric.js in version 3.6.2.
Basically you need to get the device screen's width and height. Afterwards just resize the canvas accordingly in your Javascript. Example:
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
var height = (window.innerHeight > 0) ? window.innerHeight : screen.height;
var canvas = document.getElementById("canvas");
canvas.width = width;
canvas.height = height;
You might have screens with varying resolution ratios though, what I usually do in this case is calculate your original width's and the device's width ratio and then adjust both width and height accordingly with that value. Example:
var originalWidth = 960; //Example value
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
var widthRatio = originalWidth / width;
canvas.width *= widthRatio;
canvas.height *= widthRatio;
This usually works fine for me on any device, hope this helps.
I know it's been a while but i found an easier way to do it using the zoom feature.
This code is triggered when the window resize is completed. It allows me to determine based on the new dimension, the zoom factor needed to resize everything in the canvas.
function rescale_canvas_if_needed()
{
var optimal_dimensions = get_optimal_canvas_dimensions();
var scaleFactor=optimal_dimensions[0]/wpd.canvas_w;
if(scaleFactor != 1) {
wpd_editor.canvas.setWidth(optimal_dimensions[0]);
wpd_editor.canvas.setHeight(optimal_dimensions[1]);
wpd_editor.canvas.setZoom(scaleFactor);
wpd_editor.canvas.calcOffset();
wpd_editor.canvas.renderAll();
}
}
$( window ).resize(function() {
clearTimeout(resizeId);
resizeId = setTimeout(handle_resize, 500);
});
function handle_resize()
{
$(".canvas-container").hide();
rescale_canvas_if_needed();
$(".canvas-container").show();
}
i thought this one was the answer I needed https://stackoverflow.com/a/29445765/1815624
it seemed so close but after some adjustments I got what I wanted it down scales when needed and maxes out at a scale of 1.
The canvas size you desire should be set as width/height var optimal_dimensions = [1000,1000];
this needs some more changes to handle height as well so when a user rotates there phone to landscape it may become to big to see it all on the screen
the new edited code will be at 1000 pixels in width and height for this demo
update: added detection for height and width to scale to window...
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="1000" height="1000"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.0.0/fabric.min.js"></script>
<script>
var canvas = new fabric.Canvas('canvas');
canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
canvas.item(0).set({
borderColor: 'gray',
cornerColor: 'black',
cornerSize: 12,
transparentCorners: true
});
canvas.setActiveObject(canvas.item(0));
canvas.renderAll();
function rescale_canvas_if_needed(){
var optimal_dimensions = [400,400];
var scaleFactorX=window.innerWidth/optimal_dimensions[0];
var scaleFactorY=window.innerHeight/optimal_dimensions[1];
if(scaleFactorX < scaleFactorY && scaleFactorX < 1) {
canvas.setWidth(optimal_dimensions[0] *scaleFactorX);
canvas.setHeight(optimal_dimensions[1] *scaleFactorX);
canvas.setZoom(scaleFactorX);
} else if(scaleFactorX > scaleFactorY && scaleFactorY < 1){
canvas.setWidth(optimal_dimensions[0] *scaleFactorY);
canvas.setHeight(optimal_dimensions[1] *scaleFactorY);
canvas.setZoom(scaleFactorY);
}else {
canvas.setWidth(optimal_dimensions[0] );
canvas.setHeight(optimal_dimensions[1] );
canvas.setZoom(1);
}
canvas.calcOffset();
canvas.renderAll();
}
function handle_resize(){
$(".canvas-container").hide();
rescale_canvas_if_needed();
$(".canvas-container").show();
}
var resizeId = null;
$(function() {
$(window).resize(function() {
if(resizeId != null)
clearTimeout(resizeId);
resizeId = setTimeout(handle_resize, 500);
});
console.log( "ready!" );
/* auto size it right away... */
resizeId = setTimeout(handle_resize, 500);
});
</script>
hope this helps someone...good day.
Resize the canvas depending on the size of an element with jQuery.
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.setHeight(jQuery('#image').height());
canvas.setWidth(jQuery('#image').width());
canvas.renderAll();
}
resizeCanvas();