Resize canvas
Question
Is there a way to have a dynamic resizing of the canvas? i.e not using the Device Manager, but having a drag and drop of the width, similar to what you can do with panels or components?
Thanks
Answers (3)
@artf and @shlomoko, I will explain the step little by little. Firstly, I need to use Jquery but you can use other library or integrate inside the GrapesJS engine. In my case I wanted to do it transparent to the engine.
- I have two hidden div element in the main index HTML outside of the iframe that grapesJS is generated in runtime:
<!-- DEVICE RESOLUTION HINTS-->
<div class="device-resolution hidden">
<div class="dr-type">Phone - Landscape</div>
<div class="dr-measure">Affects 767px and below"</div>
</div>
<div class="iframe-handle-container hidden">
<div class="handle right-handle">
<div class="gutter-handle"></div>
<div class="tab-handle"></div>
<div class="dim-indicator"></div>
<div class="js-mobile-list mobile-wrapper">
.....
</div>
</div>
<div class="handle left-handle"></div>
</div>
- The first div called "device-resolution" will show the device resolution compatible with this screen size.
- The second div contains: -- The gutter -- The left and right vertical bar that wrap the body when the gutter is pressed
The following piece of code is the stylesheet used:
/* RESEZING GLUTTER */
.iframe-handle-container .handle {
position: absolute;
top: 0;
bottom: 0;
z-index: 14;
}
.iframe-handle-container .handle:before {
content: "";
position: absolute;
top: 0;
left: -3px;
width: 4px;
height: 100%;
background: #178df7;
display: none;
}
.iframe-handle-container .right-handle {
left: -1px;
width: 14px;
}
.iframe-handle-container .left-handle {
left: -1px;
width: 3px;
pointer-events: all;
cursor: col-resize;
}
.iframe-handle-container .tab-handle {
position: absolute;
top: 50%;
width: 14px;
height: 38px;
margin-top: -19px;
background: #808080;
cursor: col-resize;
pointer-events: all;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.iframe-handle-container .tab-handle:before,
.iframe-handle-container .tab-handle:after {
content: "";
position: absolute;
top: 8px;
bottom: 8px;
width: 1px;
background: #a6a6a6;
}
.iframe-handle-container .tab-handle:before {
left: 5px;
}
.iframe-handle-container .tab-handle:after {
left: 8px;
}
.iframe-handle-container .tab-handle:hover {
background: #178df7;
}
.iframe-handle-container .tab-handle:hover:before,
.iframe-handle-container .tab-handle:hover:after {
background: #48a5f9;
}
.iframe-handle-container .gutter-handle {
position: absolute;
top: 0;
left: -3px;
width: 4px;
height: 100%;
cursor: col-resize;
pointer-events: all;
}
.iframe-handle-container:hover .handle:before {
display: block;
}
.iframe-handle-container:hover .tab-handle {
background: #178df7;
border-color: #178df7;
}
.iframe-handle-container:hover .tab-handle:before,
.iframe-handle-container:hover .tab-handle:after {
background: #48a5f9;
}
.dim-indicator {
position: absolute;
top: 10%;
height: 24px;
margin-left: 22px;
pointer-events: all;
font-size: 14px;
display: none;
padding: 2px 9px;
border-radius: 4px !important;
color: #ffffff;
/* font-weight: bold; */
width: 156px;
background-color: rgb(0, 0, 0);
}
.mobile-wrapper{
position: absolute;
top: 15%;
margin-left: -30px;
pointer-events: all;
color: #ffffff;
width: 340px;
padding: 14px;
}
.mobile-list li{
background: #808080;
padding: 3px;
border-radius: 4px !important;
margin-bottom: 5px;
list-style-type: none;
padding-left: 11px;
}
- When the user clicks on a device screen icon I'm showing the handler to resize the canvas. --- To do that I created a method called "initDeviceEventHandle" that is in charge of initialising the gutter handler and another method called "showDeviceResolution" that create a clone copy of the two DIV that we explained above.
editor.Commands.add('set-device-tablet', {
run: function(editor, sender)
{
.....
},
stop: function stop(editor, sender) {
var device = deviceManager.get('Tablet High Resolution');
showDeviceResolution("tablet_portrait", device);
initDeviceEventHandle(device);
}
});
/**
* This function will receive a screen type and it will prompt the description on the left side of the canvas.
*
* @param type
* @param device
*/
var showDeviceResolution = function (type, device){
var name, description;
var width = device.attributes.widthMedia;
// To reduce a little bit the width so we can move the handle until this size
var reduceWidth = width - maxReduceScreenPreviewSize;
$(".gjs-frame").width(reduceWidth);
switch (type) {
case "mobile_portrait":
name = "Phone - Portrait";
description = "Affects - " + width + " and below";
break;
case "mobile_landscape":
name = "Phone - Landscape";
description = "Affects - " + width +" and below";
break;
case "tablet_portrait":
name = "Tablet - Portrait";
description = "Affects - " + width +" and below";
}
const deviceResolution = $(document).find(".gjs-cv-canvas").find(".device-resolution");
if (deviceResolution.length > 0){
deviceResolution.addClass("hidden");
deviceResolution.find(".dr-type").html(name);
deviceResolution.find(".dr-measure").html(description);
} else {
var copyDeviceResolution = $(document).find(".device-resolution").clone(true,true);
copyDeviceResolution.find(".dr-type").html(name);
copyDeviceResolution.find(".dr-measure").html(description);
$(document).find(".gjs-cv-canvas").prepend(copyDeviceResolution);
}
const glutterResize = $(document).find(".gjs-cv-canvas").find(".iframe-handle-container");
if (glutterResize.length > 0){
glutterResize.addClass("hidden");
} else {
// If the div is not created yet inside the iframe then we include it.
var copyGlutterResize = $(document).find(".iframe-handle-container").clone(true,true);
$(".gjs-frame").before(copyGlutterResize);
}
// We force to refresh the screen because then we will update all dimensions
setTimeout(function () {
$(window).trigger('resize');
}, 600);
};
/**
* This function initializes device glutter handle
*
*/
var initDeviceEventHandle = function (device) {
try {
var maxDeviceSize = parseInt(device.attributes.widthMedia,10);
// To reduce a little bit the width so we can move the handle until this size
var reduceWidth = maxDeviceSize - maxReduceScreenPreviewSize;
$(".gjs-frame").width(reduceWidth);
var widthIframe = 0; // Current iframe Width
var maxLeftPos = 0;
var finalwidth = 0;
$(".right-handle").draggable({
axis: "x",
start: function(event, ui) {
widthIframe = $(".gjs-frame").width();
},
drag: function(event, ui) {
try {
if ( $(".gjs-cv-canvas").find(".handle-mask").length == 0 ){
// We need to create a mask to avoid in the moment that we are dragging to move the pointer over the iframe and losing then the control of the resizing.
$(".gjs-cv-canvas").append('<div class="handle-mask" style="position: absolute; z-index: 2; left: 0; top: 0; right: 0; bottom: 0;"></div>');
}
// We need to change the iframe width dynamically
const total = ui.position.left - ui.originalPosition.left;
var width = widthIframe + 2*total;
$('.js-mobile-list').find(".mobile-item").addClass("hidden");
if(width > maxDeviceSize || width < minReduceScreenPreviewSize){
ui.position.left = maxLeftPos;
} else {
// Set the iframe width
maxLeftPos = ui.position.left;
$(".gjs-frame").width(width);
finalwidth = width;
// Set the position left of the left handle
var left = $(".gjs-frame")[0].offsetLeft;
$(".left-handle").css("left", left);
var leftDesc = left - 162; // 162 = the right panel width
$(".device-resolution").css("left", leftDesc);
$('.dim-indicator').html('Screen size ' + width + 'px').fadeIn('slow');
}
// After dragging we need to refresh the editor to re-calculate the highlight border in the element selected.
editor.refresh();
} catch (err) {
console.error(err);
}
},
stop: function(event, ui) {
try {
$(".handle-mask").remove();
} catch (err) {
console.error(err);
}
}
});
} catch (err) {
console.error(err);
}
};
- This point is important to do it because when we are resizing the screen then we need also to control as well the gutter. So in the editor "load" method, I'm including a new function to check if the user is resizing the canvas or the screen size. This is called "getWindowDims".
editor.on('load', function() {
// Control that the screen size is not too small
getWindowDims();
}
/**
* Function to determine Viewport Size
*/
var getWindowDims = function() {
var doc = document, w = window;
var docEl = (doc.compatMode && doc.compatMode === 'CSS1Compat')?
doc.documentElement: doc.body;
var width = docEl.clientWidth;
var height = docEl.clientHeight;
// mobile zoomed in?
if ( w.innerWidth && width > w.innerWidth ) {
width = w.innerWidth;
height = w.innerHeight;
}
// IMPORTANT!!!!
// Glutter Handle information
var glutterHandleObj = $(document).find(".gjs-cv-canvas").find(".iframe-handle-container");
if (glutterHandleObj.length > 0){
var leftGlutterHandleBar = glutterHandleObj.find(".left-handle");
var rightGlutterHandleBar = glutterHandleObj.find(".right-handle");
var leftOffset = $('.gjs-frame')[0].offsetLeft;
var rightOffset = $('.gjs-frame')[0].offsetLeft + $('.gjs-frame').width();
leftGlutterHandleBar.css("cssText", "left: " + leftOffset + "px !important");
rightGlutterHandleBar.css("cssText", "left: " + rightOffset + "px !important");
glutterHandleObj.removeClass("hidden");
}
return {width: width, height: height};
};
I hope this will be useful. Don't hesite to ask me any doubts. Demo link: http://recordit.co/RTEaUphDZ6
No @shlomoko, canvas is not resizable but I'd be glad to see a PR for that (possibly with the same logic used in panels)
Hi @artf, I've just implemented a resizing canvas bar but I don't know if exist a way to refresh the position of the highlight borders. Take a look in the video please: http://recordit.co/jKlppYg2dD gjs-badge gjs-toolbar Best regards.
Related Questions and Answers
Continue research with similar issue discussions.
Issue #1791
Name of the destination
@artf, Is there any way to show the name of the destination element ?
Issue #2002
Images won't resize to full width
When an image is resized with the mouse, it won't stretch all the way to the edge of the canvas, leaving a white space on the right side. I...
Issue #1486
How to add/remove class undo manager
Hi @artf, Can you please provide the way to add/remove class in undo manager. Also,on live demo when we drag countdown and click on undo bu...
Issue #1936
Absolute/Designer mode
Hi guys, this issue is an overview of what is it, what is done, what to do and nice-to-have to complete the Designer Mode feature.Preface S...
Paid Plugins That Match This Issue
Curated by issue keywords and label relevance to help you ship faster.
Loading paid plugin recommendations...
Browse Plugin Categories
Jump directly to plugin category pages on the marketplace.