Canvas только отображает пользовательский webfont в событии click с помощью файла fabric.js

У меня проблема с пользовательскими webfonts и fabric.js. В моем приложении много настраиваемых веб-сайтов, и я запускаю их при добавлении iText к моему холсту:

var text = new fabric.IText("My Text", {
    fontFamily: "Some Custom Font Family",
    fontSize: 50,
    top: 0,
    left: 0,
    fill: "#000000"
  });

  canvas.add(text);
  canvas.bringToFront(text);
  canvas.setActiveObject(text);

  canvas.renderAll();

Это работает, но только если я нажимаю на iText на своем холсте и взаимодействую с ним. Затем, как только шрифт загрузится, это уже не проблема. Проблема изначально и первый раз, когда iText добавлен.

Я много исследовал и пришел к этой теме:

Инициализировать загруженный текст удаленным веб-шрифтом в Fabric.js

но это не помогло мне. Jsfiddle при условии, что имеет такую ​​же проблему:

http://jsfiddle.net/vvL6f/6/

Просто откройте эту скрипту новым браузером (например, Chrome CMD + Shift + R) с очищенным кешем. Вы увидите, как только вы откроете скрипку, пользовательский webfont не будет загружен, но сразу загрузится, когда вы нажмете iText справа.

Теперь, как мы можем это решить?

Предполагаемый подход состоял в том, чтобы установить useNative в false и позволить Cufon отображать текст, но это не сработало.

Я загружаю свои веб-сайты в файл CSS следующим образом:

@font-face {
    font-family: 'ApolloASM';
    src: url('ApolloASM-webfont.eot');
    src: url('ApolloASM-webfont.eot?#iefix') format('embedded-opentype'),
         url('ApolloASM-webfont.woff2') format('woff2'),
         url('ApolloASM-webfont.woff') format('woff'),
         url('ApolloASM-webfont.ttf') format('truetype'),
         url('ApolloASM-webfont.svg#apollo_asmregular') format('svg');
    font-weight: normal;
    font-style: normal;
}

Ответ 1

@Промитный ответ почти есть. У меня также есть приложение canvas, которое использует пользовательские шрифты с Fabric. Я загружаю все шрифты в CSS так же, как и вы. Улов есть, только объявление @font-face в вашей таблице стилей недостаточно. Браузер не будет запрашивать файл шрифта, если он не используется в документе. И, вы должны обязательно загрузить и применить webfont до инициализации холста. Это может быть достигнуто с небольшой работой, о чем я расскажу ниже. Недостатком является то, что вам может потребоваться предварительно загрузить все шрифты, которые ваше приложение будет доступно вашим пользователям.


  • Объявление вашего веб-сайта

    Добавьте инструкцию @font-face в таблицу стилей. Просто убедитесь, что он загружен в разделе <head>. Позвольте использовать ваш пример:
 @font-face {
    font-family: 'ApolloASM';
    src: url('ApolloASM-webfont.eot');
    src: url('ApolloASM-webfont.eot?#iefix') format('embedded-opentype'),
         url('ApolloASM-webfont.woff2') format('woff2'),
         url('ApolloASM-webfont.woff') format('woff'),
         url('ApolloASM-webfont.ttf') format('truetype'),
         url('ApolloASM-webfont.svg#apollo_asmregular') format('svg');
    font-weight: normal;
    font-style: normal;
}

Бонус-подсказка. Если вы используете курсив и/или полужирный шрифт в своем приложении, рекомендуется добавить шрифты для этих стилей, как weel, если вы хотите получить согласованные результаты в разных браузерах. Например, Android Browser 4.2 не может вычислить курсив шрифта и отобразит его как обычно.

  • Принудительно выполнить запрос для файла шрифта

Как я уже говорил выше, вам нужно будет использовать шрифт в DOM, чтобы заставить шрифт загружаться. Просто добавление div с некоторым текстом и стилизация его с вашим шрифтом будет достаточно:

<div style="font-family:'ApolloASM'">&nbsp;</div>

Бонусный совет. Не забудьте добавить курсивные и жирные варианты, а также

  • Инициируйте FabricJS Canvas после события DOM load

Вам нужно будет синхронизировать инициализацию canvas (или, по крайней мере, добавление текста) после того, как шрифт загружен браузером, иначе вы можете увидеть эффект FOUT (Flash of Unstyled Text). К счастью для нас браузер не запускает событие load, пока не будут загружены все файлы шрифтов, которые можно использовать для безопасного добавления стилизованного текста в холст:

window.addEventListener('load', function onLoad() {
    var canvas = new Fabric.Canvas({...});
    var text = new fabric.Text("Web Font Example", {
        left: 200,
        top: 30,
        fontFamily: 'ApolloASM',
        fill: '#000',
        fontSize: 60
    });

    canvas.add(text);
    canvas.renderAll();
})

Бонусный совет. Вы можете обернуть эти шрифты <div> в другом и удалить его после события DOM load, чтобы избежать нарушения любого макета, который у вас может быть.

Ответ 2

Вы можете использовать загрузчик веб-шрифтов.

    <script src="//ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js">    </script>
    <script>
    var c = new fabric.Canvas('canvas');
    WebFont.load({
    	google: {
    		families: ['Fredoka One']
    	},
    	active: function() {
            var text = new fabric.IText('Hello world !', {
                fontFamily: 'Fredoka One',
                top: 100,
                left: 100,
                fontSize: 20
            });
    	    c.add(text);
    	},
    });
    </script>

Ответ 3

Что происходит, webfont еще не загружен, когда ваш script сначала отображает холст.

Я бы сказал, что лучший способ выполнить это - загрузить webfont с помощью тега HTML в. Это загрузит шрифт в верхней части DOM, чтобы шрифт был готов для ваших сценариев canvas, когда браузеры его отображают. Вот пример.

https://jsfiddle.net/j47k79e8/1/

<link href='http://fonts.googleapis.com/css?family=Ranchers' rel='stylesheet' type='text/css'>

Хотя, если вы все еще хотите использовать Javascript-метод для загрузки webfont, вы можете дождаться загрузки документа до запуска ваших сценариев FabricJS. Просто заверните его в документ, готовый к заявлению.

$(document).ready(function(){
  // FabricJS scripts
});

https://jsfiddle.net/ahxpeu0v/3/

Ответ 4

Вам нужно только поместить команду canvas.renderAll(); после вставки текста, например:

canvas = new fabric.Canvas('c'); 
var text = new fabric.Text("Web Font Example", {
    left: 200,
    top: 30,
    fontFamily: 'Ranchers',
    fill: '#000',
    fontSize: 60
});

canvas.add(text);
canvas.renderAll();

Fiddle: http://jsfiddle.net/vvL6f/107/

Ответ 5

Ответа на этот вопрос @Bernardo Domingues не понравился, потому что у меня <select> более 500 шрифтов, и я не хочу предварительно загружать их из-за ограничений трафика.

Итак, я решил эту проблему, неоднократно называя метод Canvas.renderAll() каждые 500 мс. Опять и опять. Таким образом, после изменения шрифта на новый (который еще не загружен браузером) - сначала он будет загружен браузером (я не знаю, и мне все равно, сколько времени потребуется). Как только будет загружен новый шрифт - мой код обновит весь холст в 500 мс и вуаля! мои шрифты также обновляются:)