I have made photo editing web page and have this issue, serious.
I have made undo/redo code as follows.
state = Stack.pop();
canvas.fabric.loadFromJSON(state, function() {
canvas.fabric.renderAll();
});
And clearing the full screen with white color process is shown and that will push away lots of people.
I can remove this making another canvas but if then have to change whole structure of the webpage.
Is there any function in fabric.js to make it easily?
ex) display-previous-while-rendering?
In the latest version fabricjs makes possible to do not make the canvas flash.
If you cannot use latest ( 2.0.0beta5 ) do the following:
fabric.StaticCanvas.prototype.clear = function () {
this._objects.length = 0;
this.backgroundImage = null;
this.overlayImage = null;
this.backgroundColor = '';
this.overlayColor = '';
if (this._hasITextHandlers) {
this.off('mouse:up', this._mouseUpITextHandler);
this._iTextInstances = null;
this._hasITextHandlers = false;
}
this.clearContext(this.contextContainer);
this.fire('canvas:cleared');
this.renderOnAddRemove && this.requestRenderAll();
return this;
};
Having the renderAll under this.renderOnAddRemove bool condition, will not make the canvas flash since the loadFromJson process set that boolean to false.
In our Angular app we're using highcarts-ng for our HighCharts implementation.
Here is the Chart Maximize and Minimize function, which works:
function expandChartPanel() {
vm.chartMaxed = !vm.chartMaxed;
viewHeader = ScopeFactory.getScope('viewHeader');
highChart = ScopeFactory.getScope('highChart');
var chart = highChart.chartObject;
var highChartContainer = document.getElementById("highchart-container");
var highChartContainerWidth = document.getElementById('highchart-container').clientWidth;
var highChartContainerHeight = document.getElementById('highchart-container').clientHeight;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
if (vm.chartMaxed) {
vs.savedWidth = highChartContainerWidth;
vs.savedHeight = highChartContainerHeight;
console.log('savedWidth = ', vs.savedWidth);
console.log('savedHeight = ', vs.savedHeight);
root.chartExpanded = true;
viewHeader.vh.chartExpanded = true;
highChart.highChartMax = true;
highChartContainerHeight = document.getElementById('highchart-container').clientHeight;
windowWidth = window.innerWidth;
windowHeight = window.innerHeight;
highChart.chartConfig.size.width = windowWidth;
highChart.chartConfig.size.height = windowHeight - 220;
chart.setSize(windowWidth, windowHeight - 220);
}
else {
root.chartExpanded = false;
viewHeader.vh.chartExpanded = false;
highChart.highChartMax = false;
highChart.chartConfig.size.width = vs.savedWidth;
highChart.chartConfig.size.height = vs.savedHeight;
chart.setSize(vs.savedWidth, vs.savedHeight);
}
highChart.restoreChartSize();
}
Here is the reflow function:
function restoreChartSize() {
console.log('restoreChartSize');
if (!vs.chartObject.reflowNow) {
vs.chartObject.reflowNow = vs.chartObject.reflowNow = function() {
this.containerHeight = this.options.chart.height || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'height');
this.containerWidth = this.options.chart.width || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'width');
this.setSize(this.containerWidth, this.containerHeight, true);
this.hasUserSize = null;
}
}
vs.chartObject.reflowNow();
}
This reflow function above, works perfectly in this jsFiddle, but not in our app.
The full Gist file of our HighChartsDirective file.
After clicking Maximize, the chart will expand to the full size of the browser window, but then after dragging to resize the browser window, I call the restoreChartSize function, which activates the reflow.
However the size of the chart does not go to auto-size 100% 100%, it goes back to the previous size of the chart :(
Before Maximize:
After the Maximize function:
Now after resizing the browser window:
window.onresize = function(event) {
console.log('window resizing...');
highChart = ScopeFactory.getScope('highChart');
highChart.restoreChartSize();
console.log('highChart.chartConfig = ', highChart.chartConfig);
};
^ back to the smaller static sizes, not auto-size 100%
You can do this by adding a new method to chart that will manually trigger the reflow like so:
chart.reflowNow = function(){
this.containerHeight = this.options.chart.height || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'height');
this.containerWidth = this.options.chart.width || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'width');
this.setSize(this.containerWidth, this.containerHeight, false);
this.hasUserSize = null;
}
Then whenever you want to get away from manual resizing using setSize() just call chart.reflow()
Here's an working example: jsFiddle
Reference taken from: github-issue
UPDATE for ng-highcharts users
For doing this when using ng-highcharts library, you can simply pull out the chart object in the controller that has highcharts-ng dependency and add the reflowNow function, like so:
var chart = this.chartConfig.getHighcharts();
chart.reflowreflowNow = function (){ ... }
This is also the recommended way to pull out chart to do custom jobs by author of ng-highcharts as noted here and this fiddle.
I ended up finding an alternative solution to be the only thing I could get working, and it actually was pretty simple and straight forward to do. In case anyone else is looking for a fix for this, here's links to the resources that were useful and solved the issue for me.
You can simply add this to your chart config object, at the same level as the config.series or config.options. The comment references info but the actual solution that worked for me uses $timeout with 0 seconds, here
*For using highcharts-ng obviously
http://plnkr.co/edit/14x7gfQAlHw12XZVhWm0?p=preview
$scope.chartConfigObject = {
// function to trigger reflow in bootstrap containers
// see: http://jsfiddle.net/pgbc988d/ and https://github.com/pablojim/highcharts-ng/issues/211
func: function(chart) {
$timeout(function() {
chart.reflow();
//The below is an event that will trigger all instances of charts to reflow
//$scope.$broadcast('highchartsng.reflow');
}, 0);
}
};
I'm using this solution, http://daverupert.com/2012/05/making-video-js-fluid-for-rwd/, to make the videojs player fluid. My problem is when I have multiple videos (each with a unique id), I'm not sure how to make this work.
Here is my dev site I have 3 videos on, http://tweedee.e-mediaresources.info/
Here is the code I have for the player (from Dave Rupert's solution above):
<script type="text/javascript">
// Once the video is ready
_V_('#my_video_1').ready(function(){
var myPlayer = this; // Store the video object
var aspectRatio = 9/16; // Make up an aspect ratio
function resizeVideoJS(){
// Get the parent element's actual width
var width = document.getElementById(myPlayer.id).parentElement.offsetWidth;
// Set width to fill parent element, Set height
myPlayer.width(width).height( width * aspectRatio );
}
resizeVideoJS(); // Initialize the function
window.onresize = resizeVideoJS; // Call the function on resize
});
</script>
This code works fine for one video, but how do I do multiple ids??? As you can see in my dev site, I just replicated the script above three times (each with a different id) and that only causes the last video to be fluid.
you overwrite window.onresize() each time, so only the last one is used.
replace
window.onresize = resizeVideoJS
with :
window.addEventListener("resize", resizeVideoJS, false); // all browsers except IE before version 9
The following works. It does involve a bit of repetition, which I think you might be able to avoid if you used something like jQuery's deferred object to wait until the ready event is fired for all of the video players, but it's a lot neater than duplicating the resize method as you're currently doing:
<script type="text/javascript">
var players = ['my_video_1', 'my_video_2', 'my_video_3'];
var aspectRatio = 9/16;
// Catch each of the player's ready events and resize them individually
// jQuery deferred might be a neater way to wait for ready on all components to load and avoid a bit of repetition
for (var i = 0; i < players.length; i ++) {
_V_('#' + players[i]).ready(function() {
resizeVideoJS(this);
});
}
// Loop through all the players and resize them
function resizeVideos() {
for (var i = 0; i < players.length; i ++) {
var player = _V_('#' + players[i]);
resizeVideoJS(player);
}
}
// Resize a single player
function resizeVideoJS(player){
// Get the parent element's actual width
var width = document.getElementById(player.id).parentElement.offsetWidth;
// Set width to fill parent element, Set height
player.width(width).height( width * aspectRatio );
}
window.onresize = resizeVideos;
</script>
// jQuery deferred might be a neater way to wait for ready
// on all components to load and avoid a bit of repetition
for (var i = 0; i < players.length; i ++) {
_V_('#' + players[i]).ready(function() {
resizeVideoJS(this);
});
}
// Loop through all the players and resize them
function resizeVideos() {
for (var i = 0; i < players.length; i ++) {
var player = _V_('#' + players[i]);
resizeVideoJS(player);
}
}
// Resize a single player
function resizeVideoJS(player){
// Get the parent element's actual width
var width = document.getElementById(player.id).parentElement.offsetWidth;
// Set width to fill parent element, Set height
player.width(width).height( width * aspectRatio );
}
window.onresize = resizeVideos;
I have slightly modified net.uk.sweet's very helpful answer above into a working script which deals with multiple video players using video js - which are also responsive. You can find my article (which also shows an example) here = http://www.andy-howard.com/videojsmultipleresponsivevideos/index.html
This also includes a provided callback function if you require it.
you can use css rather than javascript :
.wrapper {
width: 100%;
}
.video-js {
padding-top: 55.25%;
}
<div class="wrapper">
<video id="video-player" width="auto" height="auto" class="video-js vjs-default-skin vjs-big-play-centered" data-setup="{}">
</video>
</div>
I'm using Font-Awesome, but while the font files are not loaded, the icons appear with .
So, I want these icons to have display:none while files are not loaded.
#font-face {
font-family: "FontAwesome";
src: url('../font/fontawesome-webfont.eot');
src: url('../font/fontawesome-webfont.eot?#iefix') format('eot'), url('../font/fontawesome-webfont.woff') format('woff'), url('../font/fontawesome-webfont.ttf') format('truetype'), url('../font/fontawesome-webfont.svg#FontAwesome') format('svg');
font-weight: normal;
font-style: normal;
}
How do I know that these files have been loaded and I'm finally able to show the icons?
Edit:
I'm not talking when the page is loaded (onload), because the font could be loaded before the whole page.
Now on GitHub: https://github.com/patrickmarabeas/jQuery-FontSpy.js
Essentially the method works by comparing the width of a string in two different fonts. We are using Comic Sans as the font to test against, because it is the most different of the web safe fonts and hopefully different enough to any custom font you will be using. Additionally we are using a very large font-size so even small differences will be apparent. When the width of the Comic Sans string has been calculated, the font-family is changed to your custom font, with a fallback to Comic Sans. When checked, if the string element width is the same, the fallback font of Comic Sans is still in use. If not, your font should be operational.
I rewrote the method of font load detection into a jQuery plugin designed to give the developer the ability to style elements based upon whether the font has been loaded or not. A fail safe timer has been added so the user isn’t left without content if the custom font fails to load. That’s just bad usability.
I have also added greater control over what happens during font loading and on fail with the inclusion of classes addition and removal. You can now do whatever you like to the font. I would only recommend modifying the fonts size, line spacing, etc to get your fall back font as close to the custom as possible so your layout stays intact, and users get an expected experience.
Here's a demo: http://patrickmarabeas.github.io/jQuery-FontSpy.js
Throw the following into a .js file and reference it.
(function($) {
$.fontSpy = function( element, conf ) {
var $element = $(element);
var defaults = {
font: $element.css("font-family"),
onLoad: '',
onFail: '',
testFont: 'Comic Sans MS',
testString: 'QW#HhsXJ',
delay: 50,
timeOut: 2500
};
var config = $.extend( defaults, conf );
var tester = document.createElement('span');
tester.style.position = 'absolute';
tester.style.top = '-9999px';
tester.style.left = '-9999px';
tester.style.visibility = 'hidden';
tester.style.fontFamily = config.testFont;
tester.style.fontSize = '250px';
tester.innerHTML = config.testString;
document.body.appendChild(tester);
var fallbackFontWidth = tester.offsetWidth;
tester.style.fontFamily = config.font + ',' + config.testFont;
function checkFont() {
var loadedFontWidth = tester.offsetWidth;
if (fallbackFontWidth === loadedFontWidth){
if(config.timeOut < 0) {
$element.removeClass(config.onLoad);
$element.addClass(config.onFail);
console.log('failure');
}
else {
$element.addClass(config.onLoad);
setTimeout(checkFont, config.delay);
config.timeOut = config.timeOut - config.delay;
}
}
else {
$element.removeClass(config.onLoad);
}
}
checkFont();
};
$.fn.fontSpy = function(config) {
return this.each(function() {
if (undefined == $(this).data('fontSpy')) {
var plugin = new $.fontSpy(this, config);
$(this).data('fontSpy', plugin);
}
});
};
})(jQuery);
Apply it to your project
.bannerTextChecked {
font-family: "Lobster";
/* don't specify fallback font here, do this in onFail class */
}
$(document).ready(function() {
$('.bannerTextChecked').fontSpy({
onLoad: 'hideMe',
onFail: 'fontFail anotherClass'
});
});
Remove that FOUC!
.hideMe {
visibility: hidden !important;
}
.fontFail {
visibility: visible !important;
/* fall back font */
/* necessary styling so fallback font doesn't break your layout */
}
EDIT: FontAwesome compatibility removed as it didn't work properly and ran into issues with different versions. A hacky fix can be found here: https://github.com/patrickmarabeas/jQuery-FontFaceSpy.js/issues/1
Try WebFont Loader (github repo), developed by Google and Typekit.
This example first displays the text in the default serif font; then after the fonts have loaded it displays the text in the specified font. (This code reproduces Firefox's default behavior in all other modern browsers.)
Actually, there is a good way to understand all fonts begin to download or loaded completely or not and fall into some errors, but it is not just for a specific font, pay attention to the following code:
document.fonts.onloading = () => {
// do someting when fonts begin to download
};
document.fonts.onloadingdone = () => {
// do someting when fonts are loaded completely
};
document.fonts.onloading = () => {
// do someting when fonts fall into some error
};
And also there is an option that returns Promise and it could handle with .then function:
document.fonts.ready
.then(() => console.log('do someting at the final with each status'))
Here is a different approach to the solutions from others.
I'm using FontAwesome 4.1.0 to build WebGL textures. That gave me the idea to use a tiny canvas to render a fa-square to, then check a pixel in that canvas to test whether it has loaded:
function waitForFontAwesome( callback ) {
var retries = 5;
var checkReady = function() {
var canvas, context;
retries -= 1;
canvas = document.createElement('canvas');
canvas.width = 20;
canvas.height = 20;
context = canvas.getContext('2d');
context.fillStyle = 'rgba(0,0,0,1.0)';
context.fillRect( 0, 0, 20, 20 );
context.font = '16pt FontAwesome';
context.textAlign = 'center';
context.fillStyle = 'rgba(255,255,255,1.0)';
context.fillText( '\uf0c8', 10, 18 );
var data = context.getImageData( 2, 10, 1, 1 ).data;
if ( data[0] !== 255 && data[1] !== 255 && data[2] !== 255 ) {
console.log( "FontAwesome is not yet available, retrying ..." );
if ( retries > 0 ) {
setTimeout( checkReady, 200 );
}
} else {
console.log( "FontAwesome is loaded" );
if ( typeof callback === 'function' ) {
callback();
}
}
}
checkReady();
};
As it uses a canvas it requires a fairly modern browser, but it might work on IE8 as well with the polyfill.
Here's another way of knowing if a #font-face has already been loaded without having to use timers at all: utilize a "scroll" event to receive an instantaneous event when the size of a carefully crafted element is changed.
I wrote a blog post about how it's done and have published the library on Github.
Try something like
$(window).bind("load", function() {
$('#text').addClass('shown');
});
and then do
#text {visibility: hidden;}
#text.shown {visibility: visible;}
The load event should fire after the fonts are loaded.
alternatively, you could add font-display: block to your #font-face declaration.
this instructs browsers to render the fallback font as invisible until your font is loaded, no need for display: none or any javascript load font detection
Solution for Typescript, Angular.
If you are working with Angular, you can use this module in order to do a font check.
// document.fonts.check extension
import type {} from 'css-font-loading-module';
ngOnInit() {
this.onFontLoad();
}
public onFontLoad() {
let myTimer = setInterval(() => {
if (document.fonts.check('14px MyFont')) {
console.log('Font is loaded!');
clearInterval(myTimer);
} else {
console.log('Font is loading');
}
}, 1);
}
Also, some fonts are extremely heavy. Therefore, you can add a loading screen while the font is loading and remove the loading screen when the font is loaded. I believe this is a better approach rather than changing your CSS class to display: none, merely because it might take 3-4+ seconds to download some fonts if the user has slow internet.
This is an alternate approach that will at least ensure that font-awesome is loaded, NOT a complete solution to the OP. Original code found in the wordpress forums here https://wordpress.stackexchange.com/a/165358/40636.
It's agnostic and will work with any font style resource like font-awesome where a font-family can be checked. With a little more thought I bet this could be applied to much more...
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script>
(function($){
var faSpan = $('<span class="fa" style="display:none"></span>').appendTo('body');
if (faSpan .css('fontFamily') !== 'FontAwesome' ) {
// Fallback Link
$('head').append('<link href="/css/font-awesome.min.css" rel="stylesheet">');
}
faSpan.remove();
})(jQuery);
</script>
Use the below code:
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<canvas id="canvasFont" width="40px" height="40px" style="position: absolute; display: none;"></canvas>
<script>
function IsLoadedFonts()
{
var Args = arguments;
var obj = document.getElementById('canvasFont');
var ctx = obj.getContext("2d");
var baseFont = (/chrome/i.test(navigator.userAgent))?'tims new roman':'arial';
//................
function getImg(fon)
{
ctx.clearRect(0, 0, (obj).width, (obj).height);
ctx.fillStyle = 'rgba(0,0,0,1.0)';
ctx.fillRect( 0, 0, 40, 40 );
ctx.font = '20px '+ fon;
ctx.textBaseline = "top";
ctx.fillStyle = 'rgba(255,255,255,1.0)';
ctx.fillText( '\u0630', 18, 5 );
return ctx.getImageData( 0, 0, 40, 40 );
};
//..............
for(var i1=0; i1<Args.length; i1++)
{
data1 = getImg(Args[i1]);
data2 = getImg(baseFont);
var isLoaded = false;
//...........
for (var i=0; i<data1.data.length; i++)
{
if(data1.data[i] != data2.data[i])
{isLoaded = true; break;}
}
//..........
if(!isLoaded)
return false;
}
return true;
};
setTimeout(function(){alert(IsLoadedFonts('myfont'));},100);
</script>
</body>
Can check many fonts:
setTimeout(function(){alert(IsLoadedFonts('font1','font2','font3'));},100);
The below code works in opera only but is easy:
if(!document.defaultView.getComputedStyle(document.getElementById('mydiv'))['fontFamily'].match(/myfont/i))
alert("font do not loaded ");
When you resize a div using jquery resize plugin, if you hold the shift key the aspect ratio is kept.
Well it is possible to {aspectRatio: true} to option list and if i hold the shift key to disable the aspect ratio ?
Thanks.
Well i managed by modifying the widget:
replaced
if (this._aspectRatio || b.shiftKey)
with
if (this._aspectRatio && !b.shiftKey)
You can monkey-patch the jquery resizable code for that without touching the source file, so you could still use its CDN.
var mouseDrag = $.ui.resizable.prototype._mouseDrag;
$.ui.resizable.prototype._mouseDrag = function (event) {
event.shiftKey = !event.shiftKey;
var aspectRatio = this._aspectRatio;
this._aspectRatio = aspectRatio && event.shiftKey;
mouseDrag.apply(this, arguments);
this._aspectRatio = aspectRatio;
};