mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-03-23 07:37:24 +01:00
refactor: fonts (#1323)
Some checks failed
Deploy static content to Pages / deploy (push) Has been cancelled
Code quality / quality (push) Has been cancelled
Some checks failed
Deploy static content to Pages / deploy (push) Has been cancelled
Code quality / quality (push) Has been cancelled
* refactor: add font management module and update global types * fix: declare global declareFont * test: all map loading test
This commit is contained in:
parent
cff57dc4c8
commit
bce65ce2b3
7 changed files with 578 additions and 146 deletions
|
|
@ -8501,7 +8501,6 @@
|
||||||
<script defer src="libs/polylabel.min.js?v1.105.0"></script>
|
<script defer src="libs/polylabel.min.js?v1.105.0"></script>
|
||||||
<script defer src="libs/lineclip.min.js?v1.105.0"></script>
|
<script defer src="libs/lineclip.min.js?v1.105.0"></script>
|
||||||
<script defer src="libs/simplify.js?v1.105.6"></script>
|
<script defer src="libs/simplify.js?v1.105.6"></script>
|
||||||
<script defer src="modules/fonts.js?v=1.99.03"></script>
|
|
||||||
<script defer src="modules/ui/layers.js?v=1.111.0"></script>
|
<script defer src="modules/ui/layers.js?v=1.111.0"></script>
|
||||||
<script defer src="modules/ui/measurers.js?v=1.99.00"></script>
|
<script defer src="modules/ui/measurers.js?v=1.99.00"></script>
|
||||||
<script defer src="modules/ui/style-presets.js?v=1.100.00"></script>
|
<script defer src="modules/ui/style-presets.js?v=1.100.00"></script>
|
||||||
|
|
|
||||||
|
|
@ -1,272 +1,351 @@
|
||||||
"use strict";
|
import { byId } from "../utils";
|
||||||
|
|
||||||
const fonts = [
|
declare global {
|
||||||
{family: "Arial"},
|
var declareFont: (font: FontDefinition) => void;
|
||||||
{family: "Brush Script MT"},
|
var getUsedFonts: (svg: SVGSVGElement) => FontDefinition[];
|
||||||
{family: "Century Gothic"},
|
var loadFontsAsDataURI: (
|
||||||
{family: "Comic Sans MS"},
|
fonts: FontDefinition[],
|
||||||
{family: "Copperplate"},
|
) => Promise<FontDefinition[]>;
|
||||||
{family: "Courier New"},
|
var addGoogleFont: (family: string) => Promise<void>;
|
||||||
{family: "Garamond"},
|
var addLocalFont: (family: string) => void;
|
||||||
{family: "Georgia"},
|
var addWebFont: (family: string, src: string) => void;
|
||||||
{family: "Herculanum"},
|
var fonts: FontDefinition[];
|
||||||
{family: "Impact"},
|
}
|
||||||
{family: "Papyrus"},
|
|
||||||
{family: "Party LET"},
|
type FontDefinition = {
|
||||||
{family: "Times New Roman"},
|
family: string;
|
||||||
{family: "Verdana"},
|
src?: string;
|
||||||
|
unicodeRange?: string;
|
||||||
|
variant?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.fonts = [
|
||||||
|
{ family: "Arial" },
|
||||||
|
{ family: "Brush Script MT" },
|
||||||
|
{ family: "Century Gothic" },
|
||||||
|
{ family: "Comic Sans MS" },
|
||||||
|
{ family: "Copperplate" },
|
||||||
|
{ family: "Courier New" },
|
||||||
|
{ family: "Garamond" },
|
||||||
|
{ family: "Georgia" },
|
||||||
|
{ family: "Herculanum" },
|
||||||
|
{ family: "Impact" },
|
||||||
|
{ family: "Papyrus" },
|
||||||
|
{ family: "Party LET" },
|
||||||
|
{ family: "Times New Roman" },
|
||||||
|
{ family: "Verdana" },
|
||||||
{
|
{
|
||||||
family: "Almendra SC",
|
family: "Almendra SC",
|
||||||
src: "url(https://fonts.gstatic.com/s/almendrasc/v13/Iure6Yx284eebowr7hbyTaZOrLQ.woff2)",
|
src: "url(https://fonts.gstatic.com/s/almendrasc/v13/Iure6Yx284eebowr7hbyTaZOrLQ.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Amarante",
|
family: "Amarante",
|
||||||
src: "url(https://fonts.gstatic.com/s/amarante/v22/xMQXuF1KTa6EvGx9bp-wAXs.woff2)",
|
src: "url(https://fonts.gstatic.com/s/amarante/v22/xMQXuF1KTa6EvGx9bp-wAXs.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Amatic SC",
|
family: "Amatic SC",
|
||||||
src: "url(https://fonts.gstatic.com/s/amaticsc/v11/TUZ3zwprpvBS1izr_vOMscGKfrUC.woff2)",
|
src: "url(https://fonts.gstatic.com/s/amaticsc/v11/TUZ3zwprpvBS1izr_vOMscGKfrUC.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Arima Madurai",
|
family: "Arima Madurai",
|
||||||
src: "url(https://fonts.gstatic.com/s/arimamadurai/v14/t5tmIRoeKYORG0WNMgnC3seB3T7Prw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/arimamadurai/v14/t5tmIRoeKYORG0WNMgnC3seB3T7Prw.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Architects Daughter",
|
family: "Architects Daughter",
|
||||||
src: "url(https://fonts.gstatic.com/s/architectsdaughter/v8/RXTgOOQ9AAtaVOHxx0IUBM3t7GjCYufj5TXV5VnA2p8.woff2)",
|
src: "url(https://fonts.gstatic.com/s/architectsdaughter/v8/RXTgOOQ9AAtaVOHxx0IUBM3t7GjCYufj5TXV5VnA2p8.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Bitter",
|
family: "Bitter",
|
||||||
src: "url(https://fonts.gstatic.com/s/bitter/v12/zfs6I-5mjWQ3nxqccMoL2A.woff2)",
|
src: "url(https://fonts.gstatic.com/s/bitter/v12/zfs6I-5mjWQ3nxqccMoL2A.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Caesar Dressing",
|
family: "Caesar Dressing",
|
||||||
src: "url(https://fonts.gstatic.com/s/caesardressing/v6/yYLx0hLa3vawqtwdswbotmK4vrRHdrz7.woff2)",
|
src: "url(https://fonts.gstatic.com/s/caesardressing/v6/yYLx0hLa3vawqtwdswbotmK4vrRHdrz7.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Cinzel",
|
family: "Cinzel",
|
||||||
src: "url(https://fonts.gstatic.com/s/cinzel/v7/zOdksD_UUTk1LJF9z4tURA.woff2)",
|
src: "url(https://fonts.gstatic.com/s/cinzel/v7/zOdksD_UUTk1LJF9z4tURA.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Dancing Script",
|
family: "Dancing Script",
|
||||||
src: "url(https://fonts.gstatic.com/s/dancingscript/v9/KGBfwabt0ZRLA5W1ywjowUHdOuSHeh0r6jGTOGdAKHA.woff2)",
|
src: "url(https://fonts.gstatic.com/s/dancingscript/v9/KGBfwabt0ZRLA5W1ywjowUHdOuSHeh0r6jGTOGdAKHA.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Eagle Lake",
|
family: "Eagle Lake",
|
||||||
src: "url(https://fonts.gstatic.com/s/eaglelake/v24/ptRMTiqbbuNJDOiKj9wG1On4KCFtpe4.woff2)",
|
src: "url(https://fonts.gstatic.com/s/eaglelake/v24/ptRMTiqbbuNJDOiKj9wG1On4KCFtpe4.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Faster One",
|
family: "Faster One",
|
||||||
src: "url(https://fonts.gstatic.com/s/fasterone/v17/H4ciBXCHmdfClFb-vWhf-LyYhw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/fasterone/v17/H4ciBXCHmdfClFb-vWhf-LyYhw.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Forum",
|
family: "Forum",
|
||||||
src: "url(https://fonts.gstatic.com/s/forum/v16/6aey4Ky-Vb8Ew8IROpI.woff2)",
|
src: "url(https://fonts.gstatic.com/s/forum/v16/6aey4Ky-Vb8Ew8IROpI.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Fredericka the Great",
|
family: "Fredericka the Great",
|
||||||
src: "url(https://fonts.gstatic.com/s/frederickathegreat/v6/9Bt33CxNwt7aOctW2xjbCstzwVKsIBVV--Sjxbc.woff2)",
|
src: "url(https://fonts.gstatic.com/s/frederickathegreat/v6/9Bt33CxNwt7aOctW2xjbCstzwVKsIBVV--Sjxbc.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Gloria Hallelujah",
|
family: "Gloria Hallelujah",
|
||||||
src: "url(https://fonts.gstatic.com/s/gloriahallelujah/v9/CA1k7SlXcY5kvI81M_R28cNDay8z-hHR7F16xrcXsJw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/gloriahallelujah/v9/CA1k7SlXcY5kvI81M_R28cNDay8z-hHR7F16xrcXsJw.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Great Vibes",
|
family: "Great Vibes",
|
||||||
src: "url(https://fonts.gstatic.com/s/greatvibes/v5/6q1c0ofG6NKsEhAc2eh-3Y4P5ICox8Kq3LLUNMylGO4.woff2)",
|
src: "url(https://fonts.gstatic.com/s/greatvibes/v5/6q1c0ofG6NKsEhAc2eh-3Y4P5ICox8Kq3LLUNMylGO4.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Henny Penny",
|
family: "Henny Penny",
|
||||||
src: "url(https://fonts.gstatic.com/s/hennypenny/v17/wXKvE3UZookzsxz_kjGSfPQtvXI.woff2)",
|
src: "url(https://fonts.gstatic.com/s/hennypenny/v17/wXKvE3UZookzsxz_kjGSfPQtvXI.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "IM Fell English",
|
family: "IM Fell English",
|
||||||
src: "url(https://fonts.gstatic.com/s/imfellenglish/v7/xwIisCqGFi8pff-oa9uSVAkYLEKE0CJQa8tfZYc_plY.woff2)",
|
src: "url(https://fonts.gstatic.com/s/imfellenglish/v7/xwIisCqGFi8pff-oa9uSVAkYLEKE0CJQa8tfZYc_plY.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Kelly Slab",
|
family: "Kelly Slab",
|
||||||
src: "url(https://fonts.gstatic.com/s/kellyslab/v15/-W_7XJX0Rz3cxUnJC5t6fkQLfg.woff2)",
|
src: "url(https://fonts.gstatic.com/s/kellyslab/v15/-W_7XJX0Rz3cxUnJC5t6fkQLfg.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Kranky",
|
family: "Kranky",
|
||||||
src: "url(https://fonts.gstatic.com/s/kranky/v24/hESw6XVgJzlPsFn8oR2F.woff2)",
|
src: "url(https://fonts.gstatic.com/s/kranky/v24/hESw6XVgJzlPsFn8oR2F.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Lobster Two",
|
family: "Lobster Two",
|
||||||
src: "url(https://fonts.gstatic.com/s/lobstertwo/v18/BngMUXZGTXPUvIoyV6yN5-fN5qU.woff2)",
|
src: "url(https://fonts.gstatic.com/s/lobstertwo/v18/BngMUXZGTXPUvIoyV6yN5-fN5qU.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Lugrasimo",
|
family: "Lugrasimo",
|
||||||
src: "url(https://fonts.gstatic.com/s/lugrasimo/v4/qkBXXvoF_s_eT9c7Y7au455KsgbLMA.woff2)",
|
src: "url(https://fonts.gstatic.com/s/lugrasimo/v4/qkBXXvoF_s_eT9c7Y7au455KsgbLMA.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Kaushan Script",
|
family: "Kaushan Script",
|
||||||
src: "url(https://fonts.gstatic.com/s/kaushanscript/v6/qx1LSqts-NtiKcLw4N03IEd0sm1ffa_JvZxsF_BEwQk.woff2)",
|
src: "url(https://fonts.gstatic.com/s/kaushanscript/v6/qx1LSqts-NtiKcLw4N03IEd0sm1ffa_JvZxsF_BEwQk.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Macondo",
|
family: "Macondo",
|
||||||
src: "url(https://fonts.gstatic.com/s/macondo/v21/RrQQboN9-iB1IXmOe2LE0Q.woff2)",
|
src: "url(https://fonts.gstatic.com/s/macondo/v21/RrQQboN9-iB1IXmOe2LE0Q.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "MedievalSharp",
|
family: "MedievalSharp",
|
||||||
src: "url(https://fonts.gstatic.com/s/medievalsharp/v9/EvOJzAlL3oU5AQl2mP5KdgptMqhwMg.woff2)",
|
src: "url(https://fonts.gstatic.com/s/medievalsharp/v9/EvOJzAlL3oU5AQl2mP5KdgptMqhwMg.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Metal Mania",
|
family: "Metal Mania",
|
||||||
src: "url(https://fonts.gstatic.com/s/metalmania/v22/RWmMoKWb4e8kqMfBUdPFJdXFiaQ.woff2)",
|
src: "url(https://fonts.gstatic.com/s/metalmania/v22/RWmMoKWb4e8kqMfBUdPFJdXFiaQ.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Metamorphous",
|
family: "Metamorphous",
|
||||||
src: "url(https://fonts.gstatic.com/s/metamorphous/v7/Wnz8HA03aAXcC39ZEX5y133EOyqs.woff2)",
|
src: "url(https://fonts.gstatic.com/s/metamorphous/v7/Wnz8HA03aAXcC39ZEX5y133EOyqs.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Montez",
|
family: "Montez",
|
||||||
src: "url(https://fonts.gstatic.com/s/montez/v8/aq8el3-0osHIcFK6bXAPkw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/montez/v8/aq8el3-0osHIcFK6bXAPkw.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Nova Script",
|
family: "Nova Script",
|
||||||
src: "url(https://fonts.gstatic.com/s/novascript/v10/7Au7p_IpkSWSTWaFWkumvlQKGFw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/novascript/v10/7Au7p_IpkSWSTWaFWkumvlQKGFw.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Orbitron",
|
family: "Orbitron",
|
||||||
src: "url(https://fonts.gstatic.com/s/orbitron/v9/HmnHiRzvcnQr8CjBje6GQvesZW2xOQ-xsNqO47m55DA.woff2)",
|
src: "url(https://fonts.gstatic.com/s/orbitron/v9/HmnHiRzvcnQr8CjBje6GQvesZW2xOQ-xsNqO47m55DA.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Oregano",
|
family: "Oregano",
|
||||||
src: "url(https://fonts.gstatic.com/s/oregano/v13/If2IXTPxciS3H4S2oZDVPg.woff2)",
|
src: "url(https://fonts.gstatic.com/s/oregano/v13/If2IXTPxciS3H4S2oZDVPg.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Pirata One",
|
family: "Pirata One",
|
||||||
src: "url(https://fonts.gstatic.com/s/pirataone/v22/I_urMpiDvgLdLh0fAtofhi-Org.woff2)",
|
src: "url(https://fonts.gstatic.com/s/pirataone/v22/I_urMpiDvgLdLh0fAtofhi-Org.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Sail",
|
family: "Sail",
|
||||||
src: "url(https://fonts.gstatic.com/s/sail/v16/DPEjYwiBxwYJJBPJAQ.woff2)",
|
src: "url(https://fonts.gstatic.com/s/sail/v16/DPEjYwiBxwYJJBPJAQ.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Satisfy",
|
family: "Satisfy",
|
||||||
src: "url(https://fonts.gstatic.com/s/satisfy/v8/2OzALGYfHwQjkPYWELy-cw.woff2)",
|
src: "url(https://fonts.gstatic.com/s/satisfy/v8/2OzALGYfHwQjkPYWELy-cw.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Shadows Into Light",
|
family: "Shadows Into Light",
|
||||||
src: "url(https://fonts.gstatic.com/s/shadowsintolight/v7/clhLqOv7MXn459PTh0gXYFK2TSYBz0eNcHnp4YqE4Ts.woff2)",
|
src: "url(https://fonts.gstatic.com/s/shadowsintolight/v7/clhLqOv7MXn459PTh0gXYFK2TSYBz0eNcHnp4YqE4Ts.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Tapestry",
|
family: "Tapestry",
|
||||||
src: "url(https://fonts.gstatic.com/s/macondo/v21/RrQQboN9-iB1IXmOe2LE0Q.woff2)",
|
src: "url(https://fonts.gstatic.com/s/macondo/v21/RrQQboN9-iB1IXmOe2LE0Q.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Uncial Antiqua",
|
family: "Uncial Antiqua",
|
||||||
src: "url(https://fonts.gstatic.com/s/uncialantiqua/v5/N0bM2S5WOex4OUbESzoESK-i-MfWQZQ.woff2)",
|
src: "url(https://fonts.gstatic.com/s/uncialantiqua/v5/N0bM2S5WOex4OUbESzoESK-i-MfWQZQ.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Underdog",
|
family: "Underdog",
|
||||||
src: "url(https://fonts.gstatic.com/s/underdog/v6/CHygV-jCElj7diMroWSlWV8.woff2)",
|
src: "url(https://fonts.gstatic.com/s/underdog/v6/CHygV-jCElj7diMroWSlWV8.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "UnifrakturMaguntia",
|
family: "UnifrakturMaguntia",
|
||||||
src: "url(https://fonts.gstatic.com/s/unifrakturmaguntia/v16/WWXPlieVYwiGNomYU-ciRLRvEmK7oaVemGZM.woff2)",
|
src: "url(https://fonts.gstatic.com/s/unifrakturmaguntia/v16/WWXPlieVYwiGNomYU-ciRLRvEmK7oaVemGZM.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
family: "Yellowtail",
|
family: "Yellowtail",
|
||||||
src: "url(https://fonts.gstatic.com/s/yellowtail/v8/GcIHC9QEwVkrA19LJU1qlPk_vArhqVIZ0nv9q090hN8.woff2)",
|
src: "url(https://fonts.gstatic.com/s/yellowtail/v8/GcIHC9QEwVkrA19LJU1qlPk_vArhqVIZ0nv9q090hN8.woff2)",
|
||||||
unicodeRange:
|
unicodeRange:
|
||||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
declareDefaultFonts(); // execute once on load
|
window.declareFont = (font: FontDefinition) => {
|
||||||
|
const { family, src, ...rest } = font;
|
||||||
function declareFont(font) {
|
|
||||||
const {family, src, ...rest} = font;
|
|
||||||
addFontOption(family);
|
addFontOption(family);
|
||||||
|
|
||||||
if (!src) return;
|
if (!src) return;
|
||||||
const fontFace = new FontFace(family, src, {...rest, display: "block"});
|
const fontFace = new FontFace(family, src, { ...rest, display: "block" });
|
||||||
document.fonts.add(fontFace);
|
document.fonts.add(fontFace);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
declareDefaultFonts(); // execute once on load
|
||||||
|
|
||||||
function declareDefaultFonts() {
|
function declareDefaultFonts() {
|
||||||
fonts.forEach(font => declareFont(font));
|
fonts.forEach((font) => {
|
||||||
|
declareFont(font);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUsedFonts(svg) {
|
function addFontOption(family: string) {
|
||||||
|
const options = document.getElementById("styleSelectFont")!;
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = family;
|
||||||
|
option.innerText = family;
|
||||||
|
option.style.fontFamily = family;
|
||||||
|
options.append(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchGoogleFont(family: string) {
|
||||||
|
const url = `https://fonts.googleapis.com/css2?family=${family.replace(/ /g, "+")}`;
|
||||||
|
try {
|
||||||
|
const resp = await fetch(url);
|
||||||
|
const text = await resp.text();
|
||||||
|
|
||||||
|
const fontFaceRules = text.match(/font-face\s*{[^}]+}/g);
|
||||||
|
const fonts = fontFaceRules!.map((fontFace) => {
|
||||||
|
const srcURL = fontFace.match(/url\(['"]?(.+?)['"]?\)/)?.[1];
|
||||||
|
const src = `url(${srcURL})`;
|
||||||
|
const unicodeRange = fontFace.match(/unicode-range: (.*?);/)?.[1];
|
||||||
|
const variant = fontFace.match(/font-style: (.*?);/)?.[1];
|
||||||
|
|
||||||
|
const font: FontDefinition = { family, src };
|
||||||
|
if (unicodeRange) font.unicodeRange = unicodeRange;
|
||||||
|
if (variant && variant !== "normal") font.variant = variant;
|
||||||
|
return font;
|
||||||
|
});
|
||||||
|
|
||||||
|
return fonts;
|
||||||
|
} catch (err) {
|
||||||
|
ERROR && console.error(err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readBlobAsDataURL(blob: Blob) {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onloadend = () => resolve(reader.result as string);
|
||||||
|
reader.onerror = reject;
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.loadFontsAsDataURI = async (fonts: FontDefinition[]) => {
|
||||||
|
const promises = fonts.map(async (font) => {
|
||||||
|
const url = font.src?.match(/url\(['"]?(.+?)['"]?\)/)?.[1];
|
||||||
|
if (!url) return font;
|
||||||
|
const resp = await fetch(url);
|
||||||
|
const blob = await resp.blob();
|
||||||
|
const dataURL = await readBlobAsDataURL(blob);
|
||||||
|
|
||||||
|
return { ...font, src: `url('${dataURL}')` };
|
||||||
|
});
|
||||||
|
|
||||||
|
return await Promise.all(promises);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.getUsedFonts = (svg: SVGSVGElement) => {
|
||||||
const usedFontFamilies = new Set();
|
const usedFontFamilies = new Set();
|
||||||
|
|
||||||
const labelGroups = svg.querySelectorAll("#labels g");
|
const labelGroups = svg.querySelectorAll("#labels g");
|
||||||
|
|
@ -282,112 +361,66 @@ function getUsedFonts(svg) {
|
||||||
const legendFont = legend?.getAttribute("font-family");
|
const legendFont = legend?.getAttribute("font-family");
|
||||||
if (legendFont) usedFontFamilies.add(legendFont);
|
if (legendFont) usedFontFamilies.add(legendFont);
|
||||||
|
|
||||||
const usedFonts = fonts.filter(font => usedFontFamilies.has(font.family));
|
const usedFonts = fonts.filter((font) => usedFontFamilies.has(font.family));
|
||||||
return usedFonts;
|
return usedFonts;
|
||||||
}
|
};
|
||||||
|
|
||||||
function addFontOption(family) {
|
window.addGoogleFont = async (family: string) => {
|
||||||
const options = document.getElementById("styleSelectFont");
|
|
||||||
const option = document.createElement("option");
|
|
||||||
option.value = family;
|
|
||||||
option.innerText = family;
|
|
||||||
option.style.fontFamily = family;
|
|
||||||
options.add(option);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchGoogleFont(family) {
|
|
||||||
const url = `https://fonts.googleapis.com/css2?family=${family.replace(/ /g, "+")}`;
|
|
||||||
try {
|
|
||||||
const resp = await fetch(url);
|
|
||||||
const text = await resp.text();
|
|
||||||
|
|
||||||
const fontFaceRules = text.match(/font-face\s*{[^}]+}/g);
|
|
||||||
const fonts = fontFaceRules.map(fontFace => {
|
|
||||||
const srcURL = fontFace.match(/url\(['"]?(.+?)['"]?\)/)[1];
|
|
||||||
const src = `url(${srcURL})`;
|
|
||||||
const unicodeRange = fontFace.match(/unicode-range: (.*?);/)?.[1];
|
|
||||||
const variant = fontFace.match(/font-style: (.*?);/)?.[1];
|
|
||||||
|
|
||||||
const font = {family, src};
|
|
||||||
if (unicodeRange) font.unicodeRange = unicodeRange;
|
|
||||||
if (variant && variant !== "normal") font.variant = variant;
|
|
||||||
return font;
|
|
||||||
});
|
|
||||||
|
|
||||||
return fonts;
|
|
||||||
} catch (err) {
|
|
||||||
ERROR && console.error(err);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function readBlobAsDataURL(blob) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onloadend = () => resolve(reader.result);
|
|
||||||
reader.onerror = reject;
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadFontsAsDataURI(fonts) {
|
|
||||||
const promises = fonts.map(async font => {
|
|
||||||
const url = font.src.match(/url\(['"]?(.+?)['"]?\)/)[1];
|
|
||||||
const resp = await fetch(url);
|
|
||||||
const blob = await resp.blob();
|
|
||||||
const dataURL = await readBlobAsDataURL(blob);
|
|
||||||
|
|
||||||
return {...font, src: `url('${dataURL}')`};
|
|
||||||
});
|
|
||||||
|
|
||||||
return await Promise.all(promises);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addGoogleFont(family) {
|
|
||||||
const fontRanges = await fetchGoogleFont(family);
|
const fontRanges = await fetchGoogleFont(family);
|
||||||
if (!fontRanges) return tip("Cannot fetch Google font for this value", true, "error", 4000);
|
if (!fontRanges)
|
||||||
|
return tip("Cannot fetch Google font for this value", true, "error", 4000);
|
||||||
tip(`Google font ${family} is loading...`, true, "warn", 4000);
|
tip(`Google font ${family} is loading...`, true, "warn", 4000);
|
||||||
|
|
||||||
const promises = fontRanges.map(range => {
|
const promises = fontRanges.map((range) => {
|
||||||
const {src, unicodeRange, variant} = range;
|
const { src, unicodeRange } = range;
|
||||||
const fontFace = new FontFace(family, src, {unicodeRange, variant, display: "block"});
|
const fontFace = new FontFace(family, src!, {
|
||||||
|
unicodeRange,
|
||||||
|
display: "block",
|
||||||
|
});
|
||||||
return fontFace.load();
|
return fontFace.load();
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all(promises)
|
Promise.all(promises)
|
||||||
.then(fontFaces => {
|
.then((fontFaces) => {
|
||||||
fontFaces.forEach(fontFace => document.fonts.add(fontFace));
|
fontFaces.forEach((fontFace) => {
|
||||||
|
document.fonts.add(fontFace);
|
||||||
|
});
|
||||||
fonts.push(...fontRanges);
|
fonts.push(...fontRanges);
|
||||||
tip(`Google font ${family} is added to the list`, true, "success", 4000);
|
tip(`Google font ${family} is added to the list`, true, "success", 4000);
|
||||||
addFontOption(family);
|
addFontOption(family);
|
||||||
document.getElementById("styleSelectFont").value = family;
|
const select = byId<HTMLSelectElement>("styleSelectFont");
|
||||||
|
if (select) select.value = family;
|
||||||
changeFont();
|
changeFont();
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch((err) => {
|
||||||
tip(`Failed to load Google font ${family}`, true, "error", 4000);
|
tip(`Failed to load Google font ${family}`, true, "error", 4000);
|
||||||
ERROR && console.error(err);
|
ERROR && console.error(err);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function addLocalFont(family) {
|
window.addLocalFont = (family: string) => {
|
||||||
fonts.push({family});
|
fonts.push({ family });
|
||||||
|
|
||||||
const fontFace = new FontFace(family, `local(${family})`, {display: "block"});
|
const fontFace = new FontFace(family, `local(${family})`, {
|
||||||
|
display: "block",
|
||||||
|
});
|
||||||
document.fonts.add(fontFace);
|
document.fonts.add(fontFace);
|
||||||
tip(`Local font ${family} is added to the fonts list`, true, "success", 4000);
|
tip(`Local font ${family} is added to the fonts list`, true, "success", 4000);
|
||||||
addFontOption(family);
|
addFontOption(family);
|
||||||
document.getElementById("styleSelectFont").value = family;
|
const select = byId<HTMLSelectElement>("styleSelectFont");
|
||||||
|
if (select) select.value = family;
|
||||||
changeFont();
|
changeFont();
|
||||||
}
|
};
|
||||||
|
|
||||||
function addWebFont(family, url) {
|
window.addWebFont = (family: string, url: string) => {
|
||||||
const src = `url('${url}')`;
|
const src = `url('${url}')`;
|
||||||
fonts.push({family, src});
|
fonts.push({ family, src });
|
||||||
|
|
||||||
const fontFace = new FontFace(family, src, {display: "block"});
|
const fontFace = new FontFace(family, src, { display: "block" });
|
||||||
document.fonts.add(fontFace);
|
document.fonts.add(fontFace);
|
||||||
tip(`Font ${family} is added to the list`, true, "success", 4000);
|
tip(`Font ${family} is added to the list`, true, "success", 4000);
|
||||||
addFontOption(family);
|
addFontOption(family);
|
||||||
document.getElementById("styleSelectFont").value = family;
|
const select = byId<HTMLSelectElement>("styleSelectFont");
|
||||||
|
if (select) select.value = family;
|
||||||
changeFont();
|
changeFont();
|
||||||
}
|
};
|
||||||
|
|
@ -15,3 +15,4 @@ import "./religions-generator";
|
||||||
import "./provinces-generator";
|
import "./provinces-generator";
|
||||||
import "./emblem";
|
import "./emblem";
|
||||||
import "./ice";
|
import "./ice";
|
||||||
|
import "./fonts";
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ declare global {
|
||||||
var defs: Selection<SVGDefsElement, unknown, null, undefined>;
|
var defs: Selection<SVGDefsElement, unknown, null, undefined>;
|
||||||
var coastline: Selection<SVGGElement, unknown, null, undefined>;
|
var coastline: Selection<SVGGElement, unknown, null, undefined>;
|
||||||
var lakes: Selection<SVGGElement, unknown, null, undefined>;
|
var lakes: Selection<SVGGElement, unknown, null, undefined>;
|
||||||
|
var provs: Selection<SVGGElement, unknown, null, undefined>;
|
||||||
var getColorScheme: (scheme: string | null) => (t: number) => string;
|
var getColorScheme: (scheme: string | null) => (t: number) => string;
|
||||||
var getColor: (height: number, scheme: (t: number) => string) => string;
|
var getColor: (height: number, scheme: (t: number) => string) => string;
|
||||||
var svgWidth: number;
|
var svgWidth: number;
|
||||||
|
|
@ -78,10 +79,12 @@ declare global {
|
||||||
var tip: (
|
var tip: (
|
||||||
message: string,
|
message: string,
|
||||||
autoHide?: boolean,
|
autoHide?: boolean,
|
||||||
type?: "info" | "warning" | "error",
|
type?: "info" | "warn" | "error" | "success",
|
||||||
|
timeout?: number,
|
||||||
) => void;
|
) => void;
|
||||||
var locked: (settingId: string) => boolean;
|
var locked: (settingId: string) => boolean;
|
||||||
var unlock: (settingId: string) => void;
|
var unlock: (settingId: string) => void;
|
||||||
var $: (selector: any) => any;
|
var $: (selector: any) => any;
|
||||||
var scale: number;
|
var scale: number;
|
||||||
|
var changeFont: () => void;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
export const byId = document.getElementById.bind(document);
|
export const byId = <T extends HTMLElement>(id: string): T | undefined =>
|
||||||
|
document.getElementById(id) as T;
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
|
||||||
221
tests/e2e/load-map.spec.ts
Normal file
221
tests/e2e/load-map.spec.ts
Normal file
|
|
@ -0,0 +1,221 @@
|
||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
test.describe("Map loading", () => {
|
||||||
|
test.beforeEach(async ({ context, page }) => {
|
||||||
|
await context.clearCookies();
|
||||||
|
|
||||||
|
await page.goto("/");
|
||||||
|
await page.evaluate(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
sessionStorage.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the hidden file input to be available
|
||||||
|
await page.waitForSelector("#mapToLoad", { state: "attached" });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should load a saved map file", async ({ page }) => {
|
||||||
|
// Track errors during map loading
|
||||||
|
const errors: string[] = [];
|
||||||
|
page.on("pageerror", (error) => errors.push(`pageerror: ${error.message}`));
|
||||||
|
page.on("console", (msg) => {
|
||||||
|
if (msg.type() === "error") {
|
||||||
|
errors.push(`console.error: ${msg.text()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get the file input element and upload the map file
|
||||||
|
const fileInput = page.locator("#mapToLoad");
|
||||||
|
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
|
||||||
|
await fileInput.setInputFiles(mapFilePath);
|
||||||
|
|
||||||
|
// Wait for map to be fully loaded
|
||||||
|
// mapId is set at the very end of map loading in showStatistics()
|
||||||
|
await page.waitForFunction(() => (window as any).mapId !== undefined, {
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Additional wait for rendering to settle
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// Verify map data is loaded
|
||||||
|
const mapData = await page.evaluate(() => {
|
||||||
|
const pack = (window as any).pack;
|
||||||
|
return {
|
||||||
|
hasStates: pack.states && pack.states.length > 1,
|
||||||
|
hasBurgs: pack.burgs && pack.burgs.length > 1,
|
||||||
|
hasCells: pack.cells && pack.cells.i && pack.cells.i.length > 0,
|
||||||
|
hasRivers: pack.rivers && pack.rivers.length > 0,
|
||||||
|
mapId: (window as any).mapId,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mapData.hasStates).toBe(true);
|
||||||
|
expect(mapData.hasBurgs).toBe(true);
|
||||||
|
expect(mapData.hasCells).toBe(true);
|
||||||
|
expect(mapData.hasRivers).toBe(true);
|
||||||
|
expect(mapData.mapId).toBeDefined();
|
||||||
|
|
||||||
|
// Ensure no JavaScript errors occurred during loading
|
||||||
|
// Filter out expected errors (external resources like Google Analytics, fonts)
|
||||||
|
const criticalErrors = errors.filter(
|
||||||
|
(e) =>
|
||||||
|
!e.includes("fonts.googleapis.com") &&
|
||||||
|
!e.includes("google-analytics") &&
|
||||||
|
!e.includes("googletagmanager") &&
|
||||||
|
!e.includes("Failed to load resource")
|
||||||
|
);
|
||||||
|
expect(criticalErrors).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("loaded map should have correct SVG structure", async ({ page }) => {
|
||||||
|
const errors: string[] = [];
|
||||||
|
page.on("pageerror", (error) => errors.push(`pageerror: ${error.message}`));
|
||||||
|
page.on("console", (msg) => {
|
||||||
|
if (msg.type() === "error") {
|
||||||
|
errors.push(`console.error: ${msg.text()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileInput = page.locator("#mapToLoad");
|
||||||
|
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
|
||||||
|
await fileInput.setInputFiles(mapFilePath);
|
||||||
|
|
||||||
|
await page.waitForFunction(() => (window as any).mapId !== undefined, {
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// Check essential SVG layers exist
|
||||||
|
const layers = await page.evaluate(() => {
|
||||||
|
return {
|
||||||
|
ocean: !!document.getElementById("ocean"),
|
||||||
|
lakes: !!document.getElementById("lakes"),
|
||||||
|
coastline: !!document.getElementById("coastline"),
|
||||||
|
rivers: !!document.getElementById("rivers"),
|
||||||
|
borders: !!document.getElementById("borders"),
|
||||||
|
burgs: !!document.getElementById("burgIcons"),
|
||||||
|
labels: !!document.getElementById("labels"),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(layers.ocean).toBe(true);
|
||||||
|
expect(layers.lakes).toBe(true);
|
||||||
|
expect(layers.coastline).toBe(true);
|
||||||
|
expect(layers.rivers).toBe(true);
|
||||||
|
expect(layers.borders).toBe(true);
|
||||||
|
expect(layers.burgs).toBe(true);
|
||||||
|
expect(layers.labels).toBe(true);
|
||||||
|
|
||||||
|
const criticalErrors = errors.filter(
|
||||||
|
(e) =>
|
||||||
|
!e.includes("fonts.googleapis.com") &&
|
||||||
|
!e.includes("google-analytics") &&
|
||||||
|
!e.includes("googletagmanager") &&
|
||||||
|
!e.includes("Failed to load resource")
|
||||||
|
);
|
||||||
|
expect(criticalErrors).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("loaded map should preserve state data", async ({ page }) => {
|
||||||
|
const errors: string[] = [];
|
||||||
|
page.on("pageerror", (error) => errors.push(`pageerror: ${error.message}`));
|
||||||
|
page.on("console", (msg) => {
|
||||||
|
if (msg.type() === "error") {
|
||||||
|
errors.push(`console.error: ${msg.text()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileInput = page.locator("#mapToLoad");
|
||||||
|
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
|
||||||
|
await fileInput.setInputFiles(mapFilePath);
|
||||||
|
|
||||||
|
await page.waitForFunction(() => (window as any).mapId !== undefined, {
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// Verify states have proper structure
|
||||||
|
const statesData = await page.evaluate(() => {
|
||||||
|
const pack = (window as any).pack;
|
||||||
|
const states = pack.states.filter((s: any) => s.i !== 0); // exclude neutral
|
||||||
|
|
||||||
|
return {
|
||||||
|
count: states.length,
|
||||||
|
allHaveNames: states.every((s: any) => s.name && s.name.length > 0),
|
||||||
|
allHaveCells: states.every((s: any) => s.cells > 0),
|
||||||
|
allHaveArea: states.every((s: any) => s.area > 0),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(statesData.count).toBeGreaterThan(0);
|
||||||
|
expect(statesData.allHaveNames).toBe(true);
|
||||||
|
expect(statesData.allHaveCells).toBe(true);
|
||||||
|
expect(statesData.allHaveArea).toBe(true);
|
||||||
|
|
||||||
|
const criticalErrors = errors.filter(
|
||||||
|
(e) =>
|
||||||
|
!e.includes("fonts.googleapis.com") &&
|
||||||
|
!e.includes("google-analytics") &&
|
||||||
|
!e.includes("googletagmanager") &&
|
||||||
|
!e.includes("Failed to load resource")
|
||||||
|
);
|
||||||
|
expect(criticalErrors).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("loaded map should preserve burg data", async ({ page }) => {
|
||||||
|
const errors: string[] = [];
|
||||||
|
page.on("pageerror", (error) => errors.push(`pageerror: ${error.message}`));
|
||||||
|
page.on("console", (msg) => {
|
||||||
|
if (msg.type() === "error") {
|
||||||
|
errors.push(`console.error: ${msg.text()}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileInput = page.locator("#mapToLoad");
|
||||||
|
const mapFilePath = path.join(__dirname, "../fixtures/demo.map");
|
||||||
|
await fileInput.setInputFiles(mapFilePath);
|
||||||
|
|
||||||
|
await page.waitForFunction(() => (window as any).mapId !== undefined, {
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// Verify burgs have proper structure
|
||||||
|
const burgsData = await page.evaluate(() => {
|
||||||
|
const pack = (window as any).pack;
|
||||||
|
// Filter out placeholder (i=0) and removed burgs (removed=true or no name)
|
||||||
|
const activeBurgs = pack.burgs.filter(
|
||||||
|
(b: any) => b.i !== 0 && !b.removed && b.name
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
count: activeBurgs.length,
|
||||||
|
allHaveNames: activeBurgs.every(
|
||||||
|
(b: any) => b.name && b.name.length > 0
|
||||||
|
),
|
||||||
|
allHaveCoords: activeBurgs.every(
|
||||||
|
(b: any) => typeof b.x === "number" && typeof b.y === "number"
|
||||||
|
),
|
||||||
|
allHaveCells: activeBurgs.every(
|
||||||
|
(b: any) => typeof b.cell === "number"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(burgsData.count).toBeGreaterThan(0);
|
||||||
|
expect(burgsData.allHaveNames).toBe(true);
|
||||||
|
expect(burgsData.allHaveCoords).toBe(true);
|
||||||
|
expect(burgsData.allHaveCells).toBe(true);
|
||||||
|
|
||||||
|
const criticalErrors = errors.filter(
|
||||||
|
(e) =>
|
||||||
|
!e.includes("fonts.googleapis.com") &&
|
||||||
|
!e.includes("google-analytics") &&
|
||||||
|
!e.includes("googletagmanager") &&
|
||||||
|
!e.includes("Failed to load resource")
|
||||||
|
);
|
||||||
|
expect(criticalErrors).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
174
tests/fixtures/demo.map
vendored
Normal file
174
tests/fixtures/demo.map
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue