diff --git a/docs/developer-guide/mapstore-migration-guide.md b/docs/developer-guide/mapstore-migration-guide.md
index 85cf9b5455..b7592d8ccb 100644
--- a/docs/developer-guide/mapstore-migration-guide.md
+++ b/docs/developer-guide/mapstore-migration-guide.md
@@ -22,6 +22,16 @@ This is a list of things to check if you want to update from a previous version
## Migration from 2023.02.xx to 2024.01.00
+### Removing possibility to add custom fonts to the Map
+
+From this version we limited the load of the font to FontAwesome.
+
+If you have changed the property **fonts** inside Map plugin it will not longer load the font. A possible fix would be to add the font to the `*.html` files in your application.
+
+- make sure that the `localConfig.json` does not have **fonts** property in **Map** plugin
+
+The following css is added automatically if needed `` inside the *head* tag.
+
### Fixing background config
From this version in order to fix default 3d background config a change is needed here:
diff --git a/project/standard/templates/index.html b/project/standard/templates/index.html
index c643e11b3e..de360edd75 100644
--- a/project/standard/templates/index.html
+++ b/project/standard/templates/index.html
@@ -84,7 +84,6 @@
-
diff --git a/project/standard/templates/indexTemplate.html b/project/standard/templates/indexTemplate.html
index 3d12542e2d..790ed2e814 100644
--- a/project/standard/templates/indexTemplate.html
+++ b/project/standard/templates/indexTemplate.html
@@ -84,7 +84,6 @@
-
diff --git a/web/client/index.html b/web/client/index.html
index 5cd64af541..d7f952eaf2 100644
--- a/web/client/index.html
+++ b/web/client/index.html
@@ -84,7 +84,6 @@
-
diff --git a/web/client/indexTemplate.html b/web/client/indexTemplate.html
index 4d71ff0a81..56155c619e 100644
--- a/web/client/indexTemplate.html
+++ b/web/client/indexTemplate.html
@@ -84,7 +84,6 @@
-
diff --git a/web/client/plugins/Map.jsx b/web/client/plugins/Map.jsx
index f8795a8c32..2ff9619fd6 100644
--- a/web/client/plugins/Map.jsx
+++ b/web/client/plugins/Map.jsx
@@ -9,7 +9,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import { connect, createPlugin } from '../utils/PluginsUtils';
-import { loadFont } from '../utils/AgentUtils';
import Spinner from 'react-spinkit';
import './map/css/map.css';
import Message from '../components/I18N/Message';
@@ -108,8 +107,6 @@ import {getHighlightLayerOptions} from "../utils/HighlightUtils";
* {
* "name": "Map",
* "cfg": {
- * "shouldLoadFont": true,
- * "fonts": ['FontAwesome'],
* "tools": ["overview", "scalebar", "draw", {
* "leaflet": {
* "name": "test",
@@ -128,20 +125,8 @@ import {getHighlightLayerOptions} from "../utils/HighlightUtils";
* - name is a unique name for the tool
* - impl is a placeholder (“{context.ToolName}”) where ToolName is the name you gave the tool in plugins.js (TestSupportLeaflet in our example)
*
- * You can also specify a list of fonts that have to be loaded before map rendering
- * if the shouldLoadFont is true
- * This font pre-load list is required if you're using canvas based mapping libraries (e.g. OpenLayers) and you need to show markers with symbols (e.g. Annotations).
- * For each font you must specify the font name used in the `@font-face` inside the "fonts" array property. Note: the `@font-face` declaration must be present in css of the page, otherwise the font can not be loaded anyway.
- * ```
- * {
- * "name": "Map",
- * "cfg": {
- * "shouldLoadFont": true,
- * "fonts": ['FontAwesome']
- * }
- * }
- * ```
- * For more info on metadata visit [fontfaceobserver](https://github.com/bramstein/fontfaceobserver)
+ * You can no longer specify a list of fonts that have to be loaded before map rendering, we are now only loading FontAwesome for the icons
+ * We will pre-load FontAwesome only if needed, i.e you need to show markers with symbols (e.g. Annotations).
*
* An additional feature to is limit the area and/or the minimum level of zoom in the localConfig.json file using "mapConstraints" property
*
@@ -210,7 +195,6 @@ class MapPlugin extends React.Component {
loadingSpinner: PropTypes.bool,
loadingError: PropTypes.string,
tools: PropTypes.array,
- fonts: PropTypes.array,
options: PropTypes.object,
mapOptions: PropTypes.object,
projectionDefs: PropTypes.array,
@@ -219,7 +203,6 @@ class MapPlugin extends React.Component {
actions: PropTypes.object,
features: PropTypes.array,
securityToken: PropTypes.string,
- shouldLoadFont: PropTypes.bool,
elevationEnabled: PropTypes.bool,
isLocalizedLayerStylesEnabled: PropTypes.bool,
localizedLayerStylesName: PropTypes.string,
@@ -239,7 +222,6 @@ class MapPlugin extends React.Component {
tools: ["scalebar", "draw", "highlight", "popup", "box"],
options: {},
mapOptions: {},
- fonts: ['FontAwesome'],
toolsOptions: {
measurement: {},
locate: {},
@@ -261,7 +243,6 @@ class MapPlugin extends React.Component {
},
securityToken: '',
additionalLayers: [],
- shouldLoadFont: false,
elevationEnabled: false,
onResolutionsChange: () => {},
items: [],
@@ -274,25 +255,7 @@ class MapPlugin extends React.Component {
};
UNSAFE_componentWillMount() {
- const {shouldLoadFont, fonts} = this.props;
-
- // load each font before rendering (see issue #3155)
- if (shouldLoadFont && fonts) {
- this.setState({canRender: false});
-
- Promise.all(
- fonts.map(f =>
- loadFont(f, {
- timeoutAfter: 5000 // 5 seconds in milliseconds
- }).catch((error) => {
- console.warn("Fonts loading check for map style responded slowly or with an error. Fonts in map may not be rendered correctly. This is not necessarily an issue.", error); // eslint-disable-line no-console
- }
- ))
- ).then(() => {
- this.setState({canRender: true});
- });
-
- }
+ // moved the font load of FontAwesome only to styleParseUtils (#9653)
this.updatePlugins(this.props);
this._isMounted = true;
}
diff --git a/web/client/plugins/map/selector.js b/web/client/plugins/map/selector.js
index 9ac8043939..585c125c52 100644
--- a/web/client/plugins/map/selector.js
+++ b/web/client/plugins/map/selector.js
@@ -1,5 +1,5 @@
import { mapSelector, projectionDefsSelector, isMouseMoveCoordinatesActiveSelector } from '../../selectors/map';
-import { mapTypeSelector, isOpenlayers } from '../../selectors/maptype';
+import { mapTypeSelector } from '../../selectors/maptype';
import { layerSelectorWithMarkers } from '../../selectors/layers';
import { highlighedFeatures } from '../../selectors/highlight';
import { securityTokenSelector } from '../../selectors/security';
@@ -21,11 +21,10 @@ export default createShallowSelectorCreator(isEqual)(
state => state.mapInitialConfig && state.mapInitialConfig.loadingError && state.mapInitialConfig.loadingError.data,
securityTokenSelector,
isMouseMoveCoordinatesActiveSelector,
- isOpenlayers,
isLocalizedLayerStylesEnabledSelector,
localizedLayerStylesNameSelector,
currentLocaleLanguageSelector,
- (projectionDefs, map, mapType, layers, features, loadingError, securityToken, elevationEnabled, shouldLoadFont, isLocalizedLayerStylesEnabled, localizedLayerStylesName, currentLocaleLanguage) => ({
+ (projectionDefs, map, mapType, layers, features, loadingError, securityToken, elevationEnabled, isLocalizedLayerStylesEnabled, localizedLayerStylesName, currentLocaleLanguage) => ({
projectionDefs,
map,
mapType,
@@ -34,7 +33,6 @@ export default createShallowSelectorCreator(isEqual)(
loadingError,
securityToken,
elevationEnabled,
- shouldLoadFont,
isLocalizedLayerStylesEnabled,
localizedLayerStylesName,
currentLocaleLanguage
diff --git a/web/client/utils/AgentUtils.js b/web/client/utils/AgentUtils.js
index 5b6022163d..ccd0777498 100644
--- a/web/client/utils/AgentUtils.js
+++ b/web/client/utils/AgentUtils.js
@@ -18,328 +18,3 @@ export const getWindowSize = () => {
return {maxWidth: width, maxHeight: height};
};
- /**
- * This has been cloned from https://github.com/dwighthouse/onfontready
- * because it was throwing a syntax error with IE11
- *
- * fontName : Font name used in the `@font-face` declaration
- * onReady : Function called upon successful font load and parse detection
- * options : Optional parameters
- * options.timeoutAfter : Milliseconds to wait before giving up Triggers options.onTimeout call Unset or 0 will result in an indefinite wait
- * options.onTimeout : Called after options.timeoutAfter milliseconds have elapsed without an onReady call
- * options.sampleText : Text string used to test font loading Defaults to " " (space character)
- * options.generic : Boolean set to true if attempting to detect generic family font
- * root : Undefined variable used by function
- * tryFinish : Undefined variable used by function
- */
-export const onfontready = (fontNameNew, onReady, options = {}, rootNew, tryFinishNew) => {
- let fontName = fontNameNew;
- let root = rootNew;
- let tryFinish = tryFinishNew;
- // root and tryFinish parameters prevent the need for var statement
- let fontNameCopy = fontName;
- if (process.env.isTest) {
- // Store a copy because later code will reuse the fontName variable
- // Use var to pull it out of the if block's scope
-
- const tests = {};
-
- const tryCreate = (name) => {
- tests[name] = tests[name] || {
- rootCount: 0,
- iframesCreated: false,
- timedOut: false,
- fontLoaded: false,
- requiredExtraTimeout: false
- };
- return tests[name];
- };
-
- // A helper function tracks info about internal processes for testing
- window.reporter = window.reporter || {
- modifyRootCount(name, increment) {
- tryCreate(name).rootCount += increment;
- },
- iframesCreated(name) {
- tryCreate(name).iframesCreated = true;
- },
- timedOut(name) {
- tryCreate(name).timedOut = true;
- },
- fontLoaded(name) {
- tryCreate(name).fontLoaded = true;
- },
- requiredExtraTimeout(name) {
- tryCreate(name).requiredExtraTimeout = true;
- },
- getTests() {
- return tests;
- }
- };
- }
-
- // Ensure options is defined to prevent access errors
-
- // A 0 timeoutAfter will prevent the timeout functionality
- if (options.timeoutAfter) {
- setTimeout(() => {
- // Prevent onTimeout call after shutdown
- if (root) {
- if (process.env.isTest) {
- window.reporter.modifyRootCount(fontNameCopy, -1);
- }
-
- // Shutdown should occur even if onTimeout is not defined
- document.body.removeChild(root);
-
- // Break the reference to the DOM element to allow GC to run
- // Assigning to 0 also results in falsy root tests elsewhere
- root = 0;
-
- // This won't prevent TypeError if onTimeout is not a function
- if (options.onTimeout) {
- if (process.env.isTest) {
- window.reporter.timedOut(fontNameCopy);
- }
- options.onTimeout();
- }
- }
- }, options.timeoutAfter);
- }
-
- // Measures the test elements to determine if the font has loaded
- // Always safe to call, even after shutdown
- // Using function assignment compresses better than function declaration
- tryFinish = () => {
- // Prevent test or onReady call after shutdown
- // The width of the parent elements are influenced by the children,
- // so it is sufficient to measure the parents
- // clientWidth only measures to integer accuracy
- // This is sufficient for such large font sizes (999px)
- // Both compared values are integers, so double equality is sufficient
- if (root && root.firstChild.clientWidth === root.lastChild.clientWidth) {
- if (process.env.isTest) {
- window.reporter.modifyRootCount(fontNameCopy, -1);
- }
-
- document.body.removeChild(root);
-
- // Break the reference to the DOM element to allow GC to run
- // Assigning to 0 also results in falsy root tests elsewhere
- root = 0;
-
- if (process.env.isTest) {
- window.reporter.fontLoaded(fontNameCopy);
- }
-
- onReady();
- }
- };
-
- if (process.env.isTest) {
- window.reporter.modifyRootCount(fontNameCopy, 1);
- }
-
- if (!process.env.isLegacy) {
- // Attempt to finish early if the font is already loaded
- // The tryFinish call happens after the test elements are added
- tryFinish(
- // Save bytes by creating and assigning the root div inside call
- // appendChild returns the root, allowing innerHTML usage inline
- document.body.appendChild(root = document.createElement('div')).innerHTML =
- // position:fixed breaks the element out of page flow
- // Being out of flow makes the div size to the text
- // white-space:pre ensures no text wrapping will occur
- // Out of bounds percentage bottom/right prevents scrollbars
- // font combines font-size and font-family
- // Font size 999px differentiates fallback fonts
- // Using font size in pixels prevents possible
- // failure due to zero-sized default page fonts
- // Using a
instead of a
tag might be smaller, but
- // it is more likely to interfere with page styles
- '
' +
- // A single space is the text default
- (options.sampleText || ' ') +
- '
' +
- '
' +
- (options.sampleText || ' ') +
- '
'
- );
- }
-
- if (process.env.isLegacy) {
- // Attempt to finish early if the font is already loaded
- // The tryFinish call happens after the test elements are added
- tryFinish(
- // Save bytes by creating and assigning the root div inside call
- // appendChild returns the root, allowing innerHTML usage inline
- document.body.appendChild(root = document.createElement('div')).innerHTML =
- // IE6 cannot create automatically sized divs that will
- // contain an absolutely positioned element
- // Such elements will instead break out of their bounds
- // The only other method to associate the width of one
- // element's natural size with the size of another is table
- // Style value with no spaces does not require quotes
- // position:absolute breaks the element out of page flow
- // IE6 does not support position:fixed
- // Out of bounds percentage bottom/right prevents scrollbars
- // width:auto prevents interference from width:100% styles
- // which are commonly added
- '
' +
- // tag is implied
- '
' +
- // position:relative allows the iframe's absolute
- // positioning to be relative to the
- '
' +
- //
is implied
- //
is implied
- '
' +
- // Inner needs surrounding, equal-sized periods
- // to prevent some older browsers from collapsing the
- // whitespace character (space) at insertion time
- // Monospace font compresses better than serif here
- // white-space:pre ensures no text wrapping will occur
- '
' +
- // font combines font-size and font-family
- // Font size 999px differentiates fallback fonts
- // Using font size in pixels prevents possible
- // failure due to zero-sized default page fonts
- '.' +
- // A single space is the text default
- (options.sampleText || ' ') +
- '.' +
- // Closing tags for
'
- );
- }
-
- // If the font is already loaded, tryFinish will have already destroyed
- // the root reference, so the iframes will never be inserted
- if (root) {
- if (process.env.isTest) {
- window.reporter.iframesCreated(fontNameCopy);
- }
-
- if (!process.env.isLegacy) {
- // The fontName value has already been used, reuse for reference
- // Save bytes by creating and assigning the iframe inside call
- // appendChild returns the iframe, allowing style usage inline
- // The iframe's width only needs to be relative to the parent's
- root.firstChild.appendChild(
- fontName = document.createElement('iframe')
- ).style.width = '999%';
-
- // contentWindow becomes available upon DOM insertion
- // Assigning a non-closure function to onresize prevents the
- // possibility of memory leaks through event handlers
- fontName.contentWindow.onresize = tryFinish;
-
- // By reusing the fontName (via reassignment), the DOM reference
- // to the first iframe is broken, reducing memory leak potential
- root.lastChild.appendChild(
- fontName = document.createElement('iframe')
- ).style.width = '999%';
-
- fontName.contentWindow.onresize = tryFinish;
- }
-
- if (process.env.isLegacy) {
- // The fontName value has already been used, reuse for reference
- // Save bytes by creating and assigning the iframe inside call
- // Save bytes by duplicating the deeply nested DOM insertion
- // appendChild returns the iframe, allowing style usage inline
- // position:absolute prevents the iframe from influencing the
- // table's width
- // Some IE browsers will generate scrollbars if the iframe
- // isn't positioned to the top-left
- // The iframe's width only needs to be relative to the parent's
- root.firstChild.firstChild.firstChild.firstChild.appendChild(
- fontName = document.createElement('iframe')
- ).style.cssText = 'position:absolute;bottom:999%;right:999%;width:999%';
-
- // contentWindow becomes available upon DOM insertion
- // Assigning a non-closure function to onresize prevents the
- // possibility of memory leaks through event handlers
- // Older IE browsers require iframe onresize event handlers
- // to be attached via attachEvent
- if (fontName.attachEvent) {
- fontName.contentWindow.attachEvent('onresize', tryFinish);
- } else {
- fontName.contentWindow.onresize = tryFinish;
- }
-
- // By reusing the fontName (via reassignment), the DOM reference
- // to the first iframe is broken, reducing memory leak potential
- root.lastChild.firstChild.firstChild.firstChild.appendChild(
- fontName = document.createElement('iframe')
- ).style.cssText = 'position:absolute;bottom:999%;right:999%;width:999%';
-
- if (fontName.attachEvent) {
- fontName.contentWindow.attachEvent('onresize', tryFinish);
- } else {
- fontName.contentWindow.onresize = tryFinish;
- }
- }
-
- if (!process.env.isTest) {
- // Because of iframe loading nuances, sometimes the font can finish
- // loading after the root is inserted, but before the onresize
- // event handler can be added to an iframe, creating a potential
- // for a missed resize event
- // This setTimeout gives the browser an additional chance to catch
- // a font load after returning control to the browser
- // By assigning the result of setTimeout (a timeout ID) to the
- // fontName, the DOM reference to the second iframe is broken,
- // further reducing the possibility of memory leaks
- fontName = setTimeout(tryFinish);
- }
-
- if (process.env.isTest) {
- // When testing, report that this timeout was used
- fontName = setTimeout(function() {
- if (root) {
- window.reporter.requiredExtraTimeout(fontNameCopy);
- tryFinish();
- }
- });
- }
- }
-};
-/**
- uses the onfontready function in a Promise throwing an error it the promise rejects (after 3000ms)
-*/
-export const loadFont = (fontName, options = {}) =>
- new Promise((resolve, reject) => {
- onfontready(fontName, resolve, {
- timeoutAfter: options.timeoutAfter,
-
- // Catch should only occur if onTimeout would normally be called
- onTimeout: reject,
- sampleText: options.sampleText,
- generic: options.generic
- });
- });
diff --git a/web/client/utils/styleparser/StyleParserUtils.js b/web/client/utils/styleparser/StyleParserUtils.js
index 21252393cb..b77a911df6 100644
--- a/web/client/utils/styleparser/StyleParserUtils.js
+++ b/web/client/utils/styleparser/StyleParserUtils.js
@@ -853,6 +853,26 @@ export const parseSymbolizerExpressions = (symbolizer, feature) => {
};
+const loadFontAwesome = () => {
+ return new Promise((resolve) => {
+ const fontAwesomeHref = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css';
+ if (!document.querySelector(`link[href='${fontAwesomeHref}']`)) {
+ const fontAwesome = document.createElement('link');
+ fontAwesome.setAttribute('rel', 'stylesheet');
+ fontAwesome.setAttribute('href', fontAwesomeHref);
+ document.head.appendChild(fontAwesome);
+ fontAwesome.onload = () => {
+ resolve();
+ };
+ fontAwesome.onerror = () => {
+ resolve();
+ };
+ } else {
+ resolve();
+ }
+ });
+};
+
/**
* prefetch all image or mark symbol in a geostyler style
* @param {object} geoStylerStyle geostyler style
@@ -886,16 +906,19 @@ export const drawIcons = (geoStylerStyle, options) => {
}, []);
const marks = symbolizers.filter(({ kind }) => kind === 'Mark');
const icons = symbolizers.filter(({ kind }) => kind === 'Icon');
- return new Promise((resolve) => {
- if (marks.length > 0 || icons.length > 0) {
- Promise.all([
- ...marks.map(getWellKnownNameImageFromSymbolizer),
- ...icons.map(getImageFromSymbolizer)
- ]).then((images) => {
- resolve(images);
- });
- } else {
- resolve([]);
- }
- });
+ return loadFontAwesome()
+ .then(
+ () => new Promise((resolve) => {
+ if (marks.length > 0 || icons.length > 0) {
+ Promise.all([
+ ...marks.map(getWellKnownNameImageFromSymbolizer),
+ ...icons.map(getImageFromSymbolizer)
+ ]).then((images) => {
+ resolve(images);
+ });
+ } else {
+ resolve([]);
+ }
+ })
+ );
};