Add support for FontAwesome icons as preset icons

(closes #3025)
This commit is contained in:
Bryan Housel
2018-06-06 02:19:38 -04:00
parent e04b01d886
commit 2dd7bfc849
14 changed files with 90 additions and 30 deletions

View File

@@ -75,11 +75,22 @@ If you want to add in the full history later on, perhaps to run `git blame` or `
For guidance on building a packaged version, running tests, and contributing to
development, see [CONTRIBUTING.md](CONTRIBUTING.md).
## License
iD is available under the [ISC License](https://opensource.org/licenses/ISC).
See the [LICENSE.md](LICENSE.md) file for more details.
iD also bundles portions of the following open source software.
* [D3.js (BSD-3-Clause)](https://github.com/d3/d3)
* [editor-layer-index (CC-BY-SA 3.0)](https://github.com/osmlab/editor-layer-index)
* [Font Awesome (CC-BY 4.0)](https://fontawesome.com/license)
* [Maki (CC0 1.0)](https://github.com/mapbox/maki)
* [Mapillary JS (MIT)](https://github.com/mapillary/mapillary-js)
* [name-suggestion-index (BSD-3-Clause)](https://github.com/osmlab/name-suggestion-index)
* [osm-community-index (ISC)](https://github.com/osmlab/osm-community-index)
## Thank you
Initial development of iD was made possible by a [grant of the Knight Foundation](https://www.mapbox.com/blog/knight-invests-openstreetmap/).

View File

@@ -19,6 +19,11 @@ const fieldSchema = require('./data/presets/schema/field.json');
const presetSchema = require('./data/presets/schema/preset.json');
const suggestions = require('name-suggestion-index/name-suggestions.json');
// fontawesome icons
const fontawesome = require('@fortawesome/fontawesome');
const fas = require('@fortawesome/fontawesome-free-solid').default;
fontawesome.library.add(fas);
module.exports = function buildData() {
var building;
@@ -52,6 +57,9 @@ module.exports = function buildData() {
presets: {}
};
// Font Awesome icons used
var faIcons = {};
// Start clean
shell.rm('-f', [
'data/presets/categories.json',
@@ -59,12 +67,13 @@ module.exports = function buildData() {
'data/presets/presets.json',
'data/presets.yaml',
'data/taginfo.json',
'dist/locales/en.json'
'dist/locales/en.json',
'svg/fontawesome/*',
]);
var categories = generateCategories(tstrings);
var fields = generateFields(tstrings);
var presets = generatePresets(tstrings);
var categories = generateCategories(tstrings, faIcons);
var fields = generateFields(tstrings, faIcons);
var presets = generatePresets(tstrings, faIcons);
var defaults = read('data/presets/defaults.json');
var translations = generateTranslations(fields, presets, tstrings);
var taginfo = generateTaginfo(presets, fields);
@@ -90,7 +99,8 @@ module.exports = function buildData() {
),
writeFileProm('data/presets.yaml', translationsToYAML(translations)),
writeFileProm('data/taginfo.json', JSON.stringify(taginfo, null, 4)),
writeEnJson(tstrings)
writeEnJson(tstrings),
writeFaIcons(faIcons)
];
return Promise.all(tasks)
@@ -127,23 +137,28 @@ function validate(file, instance, schema) {
}
function generateCategories(tstrings) {
function generateCategories(tstrings, faIcons) {
var categories = {};
glob.sync(__dirname + '/data/presets/categories/*.json').forEach(function(file) {
var field = read(file);
var category = read(file);
var id = 'category-' + path.basename(file, '.json');
tstrings.categories[id] = { name: field.name };
categories[id] = field;
tstrings.categories[id] = { name: category.name };
categories[id] = category;
// fontawesome icon, remember for later
if (/^fa-/.test(category.icon)) {
faIcons[category.icon] = {};
}
});
return categories;
}
function generateFields(tstrings) {
function generateFields(tstrings, faIcons) {
var fields = {};
glob.sync(__dirname + '/data/presets/fields/**/*.json').forEach(function(file) {
var field = read(file),
id = stripLeadingUnderscores(file.match(/presets\/fields\/([^.]*)\.json/)[1]);
var field = read(file);
var id = stripLeadingUnderscores(file.match(/presets\/fields\/([^.]*)\.json/)[1]);
validate(file, field, fieldSchema);
@@ -162,10 +177,16 @@ function generateFields(tstrings) {
}
fields[id] = field;
// fontawesome icon, remember for later
if (/^fa-/.test(field.icon)) {
faIcons[field.icon] = {};
}
});
return fields;
}
function suggestionsToPresets(presets) {
var existing = {};
@@ -239,7 +260,7 @@ function stripLeadingUnderscores(str) {
}
function generatePresets(tstrings) {
function generatePresets(tstrings, faIcons) {
var presets = {};
glob.sync(__dirname + '/data/presets/presets/**/*.json').forEach(function(file) {
@@ -254,6 +275,11 @@ function generatePresets(tstrings) {
};
presets[id] = preset;
// fontawesome icon, remember for later
if (/^fa-/.test(preset.icon)) {
faIcons[preset.icon] = {};
}
});
presets = _merge(presets, suggestionsToPresets(presets));
@@ -351,6 +377,9 @@ function generateTaginfo(presets, fields) {
} else if (/^temaki-/.test(preset.icon)) {
tag.icon_url = 'https://raw.githubusercontent.com/bhousel/temaki/master/icons/' +
preset.icon.replace(/^temaki-/, '') + '.svg?sanitize=true';
} else if (/^fa-/.test(preset.icon)) {
tag.icon_url = 'https://raw.githubusercontent.com/openstreetmap/iD/master/svg/fontawesome/' +
preset.icon.replace(/^fa-/, '') + '.svg?sanitize=true';
}
coalesceTags(taginfo, tag);
@@ -484,6 +513,7 @@ function translationsToYAML(translations) {
.replace(/\'.*#\':/g, '#');
}
function writeEnJson(tstrings) {
var readCoreYaml = readFileProm('data/core.yaml', 'utf8');
var readImagery = readFileProm('node_modules/editor-layer-index/i18n/en.yaml', 'utf8');
@@ -503,6 +533,16 @@ function writeEnJson(tstrings) {
});
}
function writeFaIcons(faIcons) {
for (var key in faIcons) {
var name = key.substring(3); // without `fa-`
var def = fontawesome.findIconDefinition({ iconName: name });
writeFileProm('svg/fontawesome/' + name + '.svg', fontawesome.icon(def).html);
}
}
function writeFileProm(path, content) {
return new Promise(function(res, rej) {
fs.writeFile(path, content, function(err) {

View File

@@ -217,6 +217,7 @@ You can use any of the following open source map icon sets as preset icons.
* [Maki](http://www.mapbox.com/maki/) - prefix: `maki-`
* [Temaki](http://bhousel.github.io/temaki/docs/) - prefix: `temaki-`
* [Font Awesome](https://fontawesome.com/icons?d=gallery&s=solid) (free, solid only) - prefix: `fa-`
When specifying an icon, use the prefixed version of the name, for example `"icon": "maki-park"`.

View File

@@ -2021,7 +2021,7 @@
"name": "Monastery Grounds"
},
"amenity/motorcycle_parking": {
"icon": "maki-scooter",
"icon": "fa-motorcycle",
"fields": [
"capacity",
"operator",
@@ -6485,7 +6485,7 @@
"matchScore": 0.01
},
"emergency/ambulance_station": {
"icon": "maki-hospital",
"icon": "fa-ambulance",
"fields": [
"name",
"operator",
@@ -18056,7 +18056,7 @@
"name": "Money Lender"
},
"shop/motorcycle_repair": {
"icon": "maki-scooter",
"icon": "fa-motorcycle",
"fields": [
"name",
"operator",
@@ -18084,7 +18084,7 @@
"name": "Motorcycle Repair Shop"
},
"shop/motorcycle": {
"icon": "maki-scooter",
"icon": "fa-motorcycle",
"fields": [
"name",
"operator",
@@ -83203,7 +83203,7 @@
"shop": "motorcycle"
},
"name": "Harley Davidson",
"icon": "maki-scooter",
"icon": "fa-motorcycle",
"geometry": [
"point",
"area"
@@ -83224,7 +83224,7 @@
"shop": "motorcycle"
},
"name": "Yamaha",
"icon": "maki-scooter",
"icon": "fa-motorcycle",
"geometry": [
"point",
"area"

View File

@@ -1,5 +1,5 @@
{
"icon": "maki-scooter",
"icon": "fa-motorcycle",
"fields": [
"capacity",
"operator",

View File

@@ -1,5 +1,5 @@
{
"icon": "maki-hospital",
"icon": "fa-ambulance",
"fields": [
"name",
"operator",

View File

@@ -1,5 +1,5 @@
{
"icon": "maki-scooter",
"icon": "fa-motorcycle",
"fields": [
"name",
"operator",

View File

@@ -1,5 +1,5 @@
{
"icon": "maki-scooter",
"icon": "fa-motorcycle",
"fields": [
"name",
"operator",

View File

@@ -924,7 +924,7 @@
"node",
"area"
],
"icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/scooter-15.svg?sanitize=true"
"icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/fontawesome/motorcycle.svg?sanitize=true"
},
{
"key": "amenity",
@@ -2946,7 +2946,7 @@
"node",
"area"
],
"icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/hospital-15.svg?sanitize=true"
"icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/fontawesome/ambulance.svg?sanitize=true"
},
{
"key": "emergency",
@@ -7313,7 +7313,7 @@
"node",
"area"
],
"icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/scooter-15.svg?sanitize=true"
"icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/fontawesome/motorcycle.svg?sanitize=true"
},
{
"key": "shop",
@@ -7323,7 +7323,7 @@
"node",
"area"
],
"icon_url": "https://raw.githubusercontent.com/mapbox/maki/master/icons/scooter-15.svg?sanitize=true"
"icon_url": "https://raw.githubusercontent.com/openstreetmap/iD/master/svg/fontawesome/motorcycle.svg?sanitize=true"
},
{
"key": "shop",

View File

@@ -122,6 +122,7 @@ export function svgDefs(context) {
'iD-sprite',
'maki-sprite',
'temaki-sprite',
'fa-sprite',
'community-sprite'
])
.enter()

View File

@@ -21,7 +21,7 @@ export function uiPresetIcon() {
else if (geom === 'vertex')
return p.isFallback() ? '' : 'temaki-vertex';
else
return 'marker-stroked';
return 'maki-marker-stroked';
}
@@ -32,6 +32,8 @@ export function uiPresetIcon() {
var picon = getIcon(p, geom);
var isMaki = /^maki-/.test(picon);
var isTemaki = /^temaki-/.test(picon);
var isFa = /^fa-/.test(picon);
var isPOI = isMaki || isTemaki || isFa;
var isFramed = (geom === 'area' || geom === 'vertex');
@@ -83,12 +85,12 @@ export function uiPresetIcon() {
icon
.attr('class', 'preset-icon preset-icon-' +
((isMaki || isTemaki) ? (isFramed ? '24' : '28') : (isFramed ? '44' : '60'))
(isPOI ? (isFramed ? '24' : '28') : (isFramed ? '44' : '60'))
);
icon.selectAll('svg')
.attr('class', function() {
return 'icon ' + picon + (isMaki || isTemaki ? '' : tag_classes(p));
return 'icon ' + picon + (isPOI ? '' : tag_classes(p));
});
icon.selectAll('use')

View File

@@ -20,6 +20,7 @@
"dist:svg:community": "svg-sprite --symbol --symbol-dest . --shape-id-generator \"community-%s\" --symbol-sprite dist/img/community-sprite.svg node_modules/osm-community-index/dist/img/*.svg",
"dist:svg:maki": "svg-sprite --symbol --symbol-dest . --shape-id-generator \"maki-%s\" --symbol-sprite dist/img/maki-sprite.svg node_modules/@mapbox/maki/icons/*.svg",
"dist:svg:temaki": "svg-sprite --symbol --symbol-dest . --shape-id-generator \"temaki-%s\" --symbol-sprite dist/img/temaki-sprite.svg node_modules/temaki/icons/*.svg",
"dist:svg:fa": "svg-sprite --symbol --symbol-dest . --shape-id-generator \"fa-%s\" --symbol-sprite dist/img/fa-sprite.svg svg/fontawesome/*.svg",
"imagery": "node data/update_imagery",
"lint": "eslint *.js js/id test/spec modules",
"start": "node development_server.js develop",
@@ -40,6 +41,8 @@
"wmf-sitematrix": "0.1.4"
},
"devDependencies": {
"@fortawesome/fontawesome": "^1.1.5",
"@fortawesome/fontawesome-free-solid": "^5.0.9",
"@mapbox/maki": "^4.0.0",
"chai": "^4.1.0",
"colors": "^1.1.2",

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" data-prefix="fa" data-icon="ambulance" class="svg-inline--fa fa-ambulance fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M624 352h-16V243.9c0-12.7-5.1-24.9-14.1-33.9L494 110.1c-9-9-21.2-14.1-33.9-14.1H416V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h16c0 53 43 96 96 96s96-43 96-96h128c0 53 43 96 96 96s96-43 96-96h48c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zM160 464c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm144-248c0 4.4-3.6 8-8 8h-56v56c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-56h-56c-4.4 0-8-3.6-8-8v-48c0-4.4 3.6-8 8-8h56v-56c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v56h56c4.4 0 8 3.6 8 8v48zm176 248c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-208H416V144h44.1l99.9 99.9V256z"></path></svg>

After

Width:  |  Height:  |  Size: 846 B

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" data-prefix="fa" data-icon="motorcycle" class="svg-inline--fa fa-motorcycle fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M512.949 192.003c-14.862-.108-29.14 2.322-42.434 6.874L437.589 144H520c13.255 0 24-10.745 24-24V88c0-13.255-10.745-24-24-24h-45.311a24 24 0 0 0-17.839 7.945l-37.496 41.663-22.774-37.956A24 24 0 0 0 376 64h-80c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h66.411l19.2 32H227.904c-17.727-23.073-44.924-40-99.904-40H72.54c-13.455 0-24.791 11.011-24.536 24.464C48.252 141.505 58.9 152 72 152h56c24.504 0 38.686 10.919 47.787 24.769l-11.291 20.529c-13.006-3.865-26.871-5.736-41.251-5.21C55.857 194.549 1.565 249.605.034 317.021-1.603 389.076 56.317 448 128 448c59.642 0 109.744-40.794 123.953-96h84.236c13.673 0 24.589-11.421 23.976-25.077-2.118-47.12 17.522-93.665 56.185-125.026l12.485 20.808c-27.646 23.654-45.097 58.88-44.831 98.179.47 69.556 57.203 126.452 126.758 127.11 71.629.678 129.839-57.487 129.234-129.099-.588-69.591-57.455-126.386-127.047-126.892zM128 400c-44.112 0-80-35.888-80-80s35.888-80 80-80c4.242 0 8.405.341 12.469.982L98.97 316.434C90.187 332.407 101.762 352 120 352h81.297c-12.37 28.225-40.56 48-73.297 48zm388.351-.116C470.272 402.337 432 365.554 432 320c0-21.363 8.434-40.781 22.125-55.144l49.412 82.352c4.546 7.577 14.375 10.034 21.952 5.488l13.72-8.232c7.577-4.546 10.034-14.375 5.488-21.952l-48.556-80.927A80.005 80.005 0 0 1 512 240c45.554 0 82.338 38.273 79.884 84.352-2.16 40.558-34.974 73.372-75.533 75.532z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB