Skip to content

Commit

Permalink
fix: fix text style kml parsing as richt text (#727)
Browse files Browse the repository at this point in the history
  • Loading branch information
oterral authored Jul 11, 2024
1 parent 4bd3580 commit e5bc676
Show file tree
Hide file tree
Showing 3 changed files with 214 additions and 12 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "react-spatial",
"license": "MIT",
"description": "Components to build React map apps.",
"version": "1.11.4",
"version": "1.11.5-beta.7",
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
Expand Down
31 changes: 27 additions & 4 deletions src/utils/KML.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,30 @@ const sanitizeFeature = (feature, doNotRevert32pxScaling = false) => {
feature.set("name", name);
}

// For backward compatibility we translate the bold and italic textFont property to a textArray prop
const font = feature.get("textFont") || "normal 16px Helvetica";

// Since we use rich text in mapset editor we use a text array instead,
// it's only necessary when there is new lines in the text
// Manage new lines
if (/\n/.test(name)) {
const array = [];
const split = name.split("\n");
split.forEach((txt, idx) => {
array.push(txt || "\u200B", txt ? font : "");

if (idx < split.length - 1) {
array.push("\n", "");
}
});
name = array;
} else {
name = [name, font];
}

text = new Text({
font: feature.get("textFont") || "normal 16px Helvetica",
text: feature.get("name"),
font: font.replace(/bold/g, "normal"), // We manage bold in textArray
text: name,
fill: style.getText().getFill(),
// rotation unsupported by KML, taken instead from custom field.
rotation: feature.get("textRotation") || 0,
Expand Down Expand Up @@ -483,14 +504,16 @@ const writeFeatures = (layer, featureProjection, mapResolution) => {
.map((t, idx) => {
return idx % 2 === 0 ? t : "";
})
.join("");

.join("")
.replaceAll("\u200B", "");
}

// We add the current text as features's name so it will be added as Placemark's name in the kml
if (kmlText) {
// If we see spaces at the beginning or at the end we add a empty
// white space at the beginning and at the end.
if (/^\s|\s$/g.test(kmlText)) {
if (/^(\s|\n)|(\n|\s)$/g.test(kmlText)) {
clone.set("name", `\u200B${kmlText}\u200B`);
} else {
clone.set("name", kmlText);
Expand Down
193 changes: 186 additions & 7 deletions src/utils/KML.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,16 @@ describe("KML", () => {
<Data name="textAlign">
<value>right</value>
</Data>
<Data name="textArray">
<value>
["bar","normal 16px arial"]
</value>
</Data>
<Data name="textBackgroundFillColor">
<value>rgba(255,255,255,0.01)</value>
</Data>
<Data name="textFont">
<value>bold 16px arial</value>
<value>normal 16px arial</value>
</Data>
<Data name="textOffsetX">
<value>-90</value>
Expand Down Expand Up @@ -203,8 +208,8 @@ describe("KML", () => {

// Text
const styleText = style.getText();
expect(styleText.getText()).toBe("bar");
expect(styleText.getFont()).toEqual("bold 16px arial");
expect(styleText.getText()).toEqual(["bar", "normal 16px arial"]);
expect(styleText.getFont()).toEqual("normal 16px arial");
expect(styleText.getFill()).toEqual({
color_: [32, 52, 126, 1],
patternImage_: null,
Expand Down Expand Up @@ -248,8 +253,13 @@ describe("KML", () => {
</LabelStyle>
</Style>
<ExtendedData>
<Data name="textArray">
<value>
[" bar ","normal 16px arial"]
</value>
</Data>
<Data name="textFont">
<value>bold 16px arial</value>
<value>normal 16px arial</value>
</Data>
</ExtendedData>
<Point>
Expand All @@ -266,7 +276,7 @@ describe("KML", () => {

// Text
const styleText = style.getText();
expect(styleText.getText()).toBe(" bar "); // Avoid trim spaces using unicode \u200B
expect(styleText.getText()).toEqual([" bar ", "normal 16px arial"]); // Avoid trim spaces using unicode \u200B
expectWriteResult(feats, str);
});

Expand All @@ -291,7 +301,7 @@ describe("KML", () => {
<value>["\\n",""," ","","foo","bold 16px arial"," ","","\\n",""]</value>
</Data>
<Data name="textFont">
<value>bold 16px arial</value>
<value>normal 16px arial</value>
</Data>
</ExtendedData>
<Point>
Expand Down Expand Up @@ -323,10 +333,179 @@ describe("KML", () => {
"\n",
"",
]);
expect(styleText.getFont()).toEqual("bold 16px arial");
expect(styleText.getFont()).toEqual("normal 16px arial");
expectWriteResult(feats, str);
});

test("should read/rewrite old TextStyle as textArray as ExtendedData.", () => {
const str = `
<kml ${xmlns}>
<Document>
<name>lala</name>
<Placemark>
<name>\u200B bar \u200B</name>
<Style>
<IconStyle>
<scale>0</scale>
</IconStyle>
<LabelStyle>
<color>ff7e3420</color>
<scale>2</scale>
</LabelStyle>
</Style>
<ExtendedData>
<Data name="textFont">
<value>normal 16px arial</value>
</Data>
</ExtendedData>
<Point>
<coordinates>0,0,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
`;
const feats = KML.readFeatures(str);
const style = feats[0].getStyleFunction()(feats[0], 1);
expect(feats.length).toBe(1);
expect(style instanceof Style).toBe(true);

// Text
const styleText = style.getText();

// Make sure it is an array, the toEqual on nextline is not working properly because the array is converted to a string for comparaison.
expect(Array.isArray(styleText.getText())).toBe(true);
expect(styleText.getText()).toEqual([" bar ", "normal 16px arial"]);
expect(styleText.getFont()).toEqual("normal 16px arial");

const strAfter = `
<kml ${xmlns}>
<Document>
<name>lala</name>
<Placemark>
<name>\u200B bar \u200B</name>
<Style>
<IconStyle>
<scale>0</scale>
</IconStyle>
<LabelStyle>
<color>ff7e3420</color>
<scale>2</scale>
</LabelStyle>
</Style>
<ExtendedData>
<Data name="textArray">
<value>
[" bar ","normal 16px arial"]
</value>
</Data>
<Data name="textFont">
<value>normal 16px arial</value>
</Data>
</ExtendedData>
<Point>
<coordinates>0,0,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
`;
expectWriteResult(feats, strAfter);
});

test("should read/write old bold TextStyle as textArray as ExtendedData.", () => {
const str = `
<kml ${xmlns}>
<Document>
<name>lala</name>
<Placemark>
<name>\u200B\n foo \n\n \n\u200B</name>
<Style>
<IconStyle>
<scale>0</scale>
</IconStyle>
<LabelStyle>
<color>ff7e3420</color>
<scale>2</scale>
</LabelStyle>
</Style>
<ExtendedData>
<Data name="textFont">
<value>bold 16px arial</value>
</Data>
</ExtendedData>
<Point>
<coordinates>0,0,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
`;
const feats = KML.readFeatures(str);
const style = feats[0].getStyleFunction()(feats[0], 1);
expect(feats.length).toBe(1);
expect(style instanceof Style).toBe(true);

// Text
const styleText = style.getText();

// Make sure it is an array, the toEqual on nextline is not working properly because the array is converted to a string for comparaison.
expect(Array.isArray(styleText.getText())).toBe(true);
expect(styleText.getText()).toEqual([
"\u200B",
"",
"\n",
"",
" foo ",
"bold 16px arial",
"\n",
"",
"\u200B",
"",
"\n",
"",
" ",
"bold 16px arial",
"\n",
"",
"\u200B",
"",
]);
expect(styleText.getFont()).toEqual("normal 16px arial");

const strAfter = `
<kml ${xmlns}>
<Document>
<name>lala</name>
<Placemark>
<name>\u200B\n foo \n\n \n\u200B</name>
<Style>
<IconStyle>
<scale>0</scale>
</IconStyle>
<LabelStyle>
<color>ff7e3420</color>
<scale>2</scale>
</LabelStyle>
</Style>
<ExtendedData>
<Data name="textArray">
<value>["\u200B","","\\n",""," foo ","bold 16px arial","\\n","","\u200B","","\\n",""," ","bold 16px arial","\\n","","\u200B",""]</value>
</Data>
<Data name="textFont">
<value>normal 16px arial</value>
</Data>
</ExtendedData>
<Point>
<coordinates>0,0,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>
`;
expectWriteResult(feats, strAfter);
});

test("should read and write lineDash and fillPattern style for polygon", () => {
const str = `
<kml ${xmlns}>
Expand Down

0 comments on commit e5bc676

Please sign in to comment.