Skip to content

Commit

Permalink
Renamed shield image names based on structured route properties
Browse files Browse the repository at this point in the history
The name of each shield image in the style is now based on structured route properties and can includes the route name and color.
  • Loading branch information
1ec5 committed Jan 27, 2024
1 parent d79a6d1 commit acdb10d
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 65 deletions.
14 changes: 4 additions & 10 deletions src/js/shield_format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type {
RouteParser,
} from "@americana/maplibre-shield-generator";

import { parseImageName } from "../layer/highway_shield.js";

export const shieldPredicate: StringPredicate = (imageID: string) =>
imageID && imageID.startsWith("shield");

Expand All @@ -14,16 +16,8 @@ export const networkPredicate: StringPredicate = (network: string) =>

export const routeParser: RouteParser = {
parse: (id: string) => {
//Americana format is `${shield}\n${network}=${ref}\n${name}`
let id_parts: string[] = id.split("\n");
let network_ref = id_parts[1].split("=");

return {
network: network_ref[0],
ref: network_ref[1],
name: id_parts[2],
};
return parseImageName(id);
},
format: (network: string, ref: string, name: string) =>
`shield\n${network}=${ref}\n${name}`,
`shield\n${network}\n${ref}\n${name}\n`,
};
47 changes: 17 additions & 30 deletions src/layer/highway_shield.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
"use strict";

export const namedRouteNetworks = [
"US:CT:Parkway",
"US:KY:Parkway",
"US:NH:Turnpike",
"US:NY:Parkway",
"US:TX:Fort_Bend:FBCTRA",
"US:TX:Harris:HCTRA",
];
const orderedRouteAttributes = ["network", "ref", "name", "color"];

export function getImageNameExpression(routeIndex) {
return [
"concat",
"shield\n",
["get", "route_" + routeIndex],
[
"match",
["get", "route_" + routeIndex],
namedRouteNetworks.map((n) => n + "="),
["concat", "\n", ["get", "name"]],
"",
],
];
let concat = ["concat", "shield"];
for (let attr of orderedRouteAttributes) {
concat.push("\n");
concat.push(["coalesce", ["get", `route_${routeIndex}_${attr}`], ""]);
}
return concat;
}

function routeConcurrency(routeIndex) {
return [
"case",
["!=", ["get", "route_" + routeIndex], null],
[
"any",
...orderedRouteAttributes.map(a => ["has", `route_${routeIndex}_${a}`]),
],
["image", getImageNameExpression(routeIndex)],
["literal", ""],
];
Expand All @@ -37,12 +27,14 @@ function routeConcurrency(routeIndex) {
* Returns a structured representation of the given image name.
*
* @param name An image name in the format returned by `routeConcurrency`.
* @return An object with the keys in `orderedRouteAttributes` plus the full image name in `imageName`.
*/
export function parseImageName(imageName) {
let lines = imageName.split("\n");
let [, network, ref] = lines[1].match(/^(.*?)=(.*)/) || [];
let name = lines[2];
return { imageName, network, ref, name };
lines.shift(); // "shield"
let parsed = Object.fromEntries(orderedRouteAttributes.map((a, i) => [a, lines[i]]));
parsed.imageName = imageName;
return parsed;
}

let shieldTextField = ["format"];
Expand Down Expand Up @@ -113,11 +105,6 @@ export const shield = {
},
filter: [
"any",
["has", "route_1"],
["has", "route_2"],
["has", "route_3"],
["has", "route_4"],
["has", "route_5"],
["has", "route_6"],
...orderedRouteAttributes.map(a => ["has", `route_1_${a}`]),
],
};
4 changes: 3 additions & 1 deletion test/shield_format/shield_format.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { expect } from "chai";
import { shieldPredicate, routeParser } from "../../src/js/shield_format.js";

const image_id_I95 = "shield\nUS:I=95";
const image_id_I95 = "shield\nUS:I\n95\nEye Ninety-Five";
const route_def_I95 = {
network: "US:I",
ref: "95",
name: "Eye Ninety-Five",
};

describe("shield_format", function () {
Expand All @@ -19,6 +20,7 @@ describe("shield_format", function () {
let extractedDef = routeParser.parse(image_id_I95);
expect(extractedDef.network).to.be.equal(route_def_I95.network);
expect(extractedDef.ref).to.be.equal(route_def_I95.ref);
expect(extractedDef.name).to.be.equal(route_def_I95.name);
});
});
});
28 changes: 15 additions & 13 deletions test/spec/highway_shield.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,51 @@ describe("highway_shield", function () {
.createExpression(HighwayShieldLayers.getImageNameExpression(1))
.value.expression.evaluate(expressionContext(properties));

let expectImageName = (network, ref, name, expectedImageName) => {
let expectImageName = (network, ref, name, color, expectedImageName) => {
let properties = {
route_1: `${network || ""}=${ref || ""}`,
name: name || null,
route_1_network: network || "",
route_1_ref: ref || "",
route_1_name: name || "",
route_1_color: color || "",
};
let evaluated = evaluatedExpression(properties);
let expectedProperties = {
imageName: expectedImageName,
network: network || "",
ref: ref || "",
name:
!ref && HighwayShieldLayers.namedRouteNetworks.includes(network)
? name
: undefined,
name: name || "",
color: color || "",
};
expect(HighwayShieldLayers.parseImageName(evaluated)).to.be.deep.equal(
expectedProperties
);
};

it("parses an image name for a numbered route", function () {
expectImageName("NET", "REF", undefined, "shield\nNET=REF");
expectImageName("NET", "REF", "NAME", "shield\nNET=REF");
expectImageName("NET", "REF", undefined, undefined, "shield\nNET\nREF\n\n");
expectImageName("NET", "REF", "NAME", undefined, "shield\nNET\nREF\nNAME\n");
});
it("parses an image name for an unnumbered route", function () {
expectImageName("NET", undefined, undefined, "shield\nNET=");
expectImageName("NET", undefined, undefined, undefined, "shield\nNET\n\n\n");
});
it("parses an image name for a named route", function () {
expectImageName(
"US:KY:Parkway",
undefined,
"NAME",
"shield\nUS:KY:Parkway=\nNAME"
undefined,
"shield\nUS:KY:Parkway\n\nNAME\n"
);
expectImageName(
"US:KY:Parkway",
"REF",
"NAME",
"shield\nUS:KY:Parkway=REF"
undefined,
"shield\nUS:KY:Parkway\nREF\nNAME\n"
);
});
it("parses an image name for a network-independent route", function () {
expectImageName(undefined, "REF", "NAME", "shield\n=REF");
expectImageName(undefined, "REF", "NAME", undefined, "shield\n\nREF\nNAME\n");
});
});
});
22 changes: 11 additions & 11 deletions test/spec/shield.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ const shieldRenderer = new ShieldRenderer(shields, routeParser)

const handler = shieldRenderer.getStyleImageMissingHandler();

handler({ id: "shield\nBAB=5" });
handler({ id: "shield\nUS:RI=" });
handler({ id: "shield\nUS:RI=ABC123" });
handler({ id: "shield\nUS:RI=Equator" });
handler({ id: "shield\nrwn=" });
handler({ id: "shield\nBAB\n5\n\n" });
handler({ id: "shield\nUS:RI\n\n\n" });
handler({ id: "shield\nUS:RI\nABC123\n\n" });
handler({ id: "shield\nUS:RI\nEquator\n\n" });
handler({ id: "shield\nrwn\n\n\n" });
handler({ id: "foo" });

function isBlankSprite(id) {
Expand All @@ -39,21 +39,21 @@ function isBlankSprite(id) {
describe("shield", function () {
describe("#isValidNetwork", function () {
it("rejects a recreational network", function () {
expect(isBlankSprite("shield\nBAB=5")).to.be.false;
expect(isBlankSprite("shield\nrwn=")).to.be.true;
expect(isBlankSprite("shield\nBAB\n5\n\n")).to.be.false;
expect(isBlankSprite("shield\nrwn\n\n\n")).to.be.true;
});
it("rejects other missing image prefixes", function () {
expect(mockRepo.hasSprite("foo")).to.be.false;
});
});
describe("#isValidRef", function () {
it("rejects an empty ref", function () {
expect(isBlankSprite("shield\nUS:RI=")).to.be.true;
expect(isBlankSprite("shield\nUS:RI\n\n")).to.be.true;
});
it("rejects a long ref", function () {
expect(mockRepo.hasSprite("shield\nUS:RI=ABC123")).to.be.true;
expect(isBlankSprite("shield\nUS:RI=ABC123")).to.be.false;
expect(isBlankSprite("shield\nUS:RI=Equator")).to.be.true;
expect(mockRepo.hasSprite("shield\nUS:RI\nABC123\n\n")).to.be.true;
expect(isBlankSprite("shield\nUS:RI\nABC123\n\n")).to.be.false;
expect(isBlankSprite("shield\nUS:RI\nEquator\n\n")).to.be.true;
});
});
});

0 comments on commit acdb10d

Please sign in to comment.