mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 01:02:58 +00:00
Render area fill patterns in preset icons (close #6900)
This commit is contained in:
@@ -3,135 +3,18 @@ import { bisector as d3_bisector } from 'd3-array';
|
||||
import { osmEntity, osmIsOldMultipolygonOuterMember } from '../osm';
|
||||
import { svgPath, svgSegmentWay } from './helpers';
|
||||
import { svgTagClasses } from './tag_classes';
|
||||
import { svgTagPattern } from './tag_pattern';
|
||||
|
||||
|
||||
export function svgAreas(projection, context) {
|
||||
// Patterns only work in Firefox when set directly on element.
|
||||
// (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
|
||||
var patterns = {
|
||||
// tag - pattern name
|
||||
// -or-
|
||||
// tag - value - pattern name
|
||||
// -or-
|
||||
// tag - value - rules (optional tag-values, pattern name)
|
||||
// (matches earlier rules first, so fallback should be last entry)
|
||||
amenity: {
|
||||
grave_yard: 'cemetery',
|
||||
fountain: 'water_standing'
|
||||
},
|
||||
landuse: {
|
||||
cemetery: [
|
||||
{ religion: 'christian', pattern: 'cemetery_christian' },
|
||||
{ religion: 'buddhist', pattern: 'cemetery_buddhist' },
|
||||
{ religion: 'muslim', pattern: 'cemetery_muslim' },
|
||||
{ religion: 'jewish', pattern: 'cemetery_jewish' },
|
||||
{ pattern: 'cemetery' }
|
||||
],
|
||||
construction: 'construction',
|
||||
farmland: 'farmland',
|
||||
farmyard: 'farmyard',
|
||||
forest: [
|
||||
{ leaf_type: 'broadleaved', pattern: 'forest_broadleaved' },
|
||||
{ leaf_type: 'needleleaved', pattern: 'forest_needleleaved' },
|
||||
{ leaf_type: 'leafless', pattern: 'forest_leafless' },
|
||||
{ pattern: 'forest' } // same as 'leaf_type:mixed'
|
||||
],
|
||||
grave_yard: 'cemetery',
|
||||
grass: 'grass',
|
||||
landfill: 'landfill',
|
||||
meadow: 'meadow',
|
||||
military: 'construction',
|
||||
orchard: 'orchard',
|
||||
quarry: 'quarry',
|
||||
vineyard: 'vineyard'
|
||||
},
|
||||
natural: {
|
||||
beach: 'beach',
|
||||
grassland: 'grass',
|
||||
sand: 'beach',
|
||||
scrub: 'scrub',
|
||||
water: [
|
||||
{ water: 'pond', pattern: 'pond' },
|
||||
{ water: 'reservoir', pattern: 'water_standing' },
|
||||
{ pattern: 'waves' }
|
||||
],
|
||||
wetland: [
|
||||
{ wetland: 'marsh', pattern: 'wetland_marsh' },
|
||||
{ wetland: 'swamp', pattern: 'wetland_swamp' },
|
||||
{ wetland: 'bog', pattern: 'wetland_bog' },
|
||||
{ wetland: 'reedbed', pattern: 'wetland_reedbed' },
|
||||
{ pattern: 'wetland' }
|
||||
],
|
||||
wood: [
|
||||
{ leaf_type: 'broadleaved', pattern: 'forest_broadleaved' },
|
||||
{ leaf_type: 'needleleaved', pattern: 'forest_needleleaved' },
|
||||
{ leaf_type: 'leafless', pattern: 'forest_leafless' },
|
||||
{ pattern: 'forest' } // same as 'leaf_type:mixed'
|
||||
]
|
||||
},
|
||||
traffic_calming: {
|
||||
island: [
|
||||
{ surface: 'grass', pattern: 'grass' },
|
||||
],
|
||||
chicane: [
|
||||
{ surface: 'grass', pattern: 'grass' },
|
||||
],
|
||||
choker: [
|
||||
{ surface: 'grass', pattern: 'grass' },
|
||||
]
|
||||
|
||||
|
||||
function getPatternStyle(tags) {
|
||||
var imageID = svgTagPattern(tags);
|
||||
if (imageID) {
|
||||
return 'url("#' + imageID + '")';
|
||||
}
|
||||
};
|
||||
|
||||
function setPattern(entity) {
|
||||
// Skip pattern filling if this is a building (buildings don't get patterns applied)
|
||||
if (entity.tags.building && entity.tags.building !== 'no') {
|
||||
this.style.fill = this.style.stroke = '';
|
||||
return;
|
||||
}
|
||||
|
||||
for (var tag in patterns) {
|
||||
var entityValue = entity.tags[tag];
|
||||
if (!entityValue) continue;
|
||||
|
||||
if (typeof patterns[tag] === 'string') { // extra short syntax (just tag) - pattern name
|
||||
this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[tag] + '")';
|
||||
return;
|
||||
} else {
|
||||
var values = patterns[tag];
|
||||
for (var value in values) {
|
||||
if (entityValue !== value) continue;
|
||||
|
||||
var rules = values[value];
|
||||
if (typeof rules === 'string') { // short syntax - pattern name
|
||||
this.style.fill = this.style.stroke = 'url("#pattern-' + rules + '")';
|
||||
return;
|
||||
} else { // long syntax - rule array
|
||||
for (var ruleKey in rules) {
|
||||
var rule = rules[ruleKey];
|
||||
|
||||
var pass = true;
|
||||
for (var criterion in rule) {
|
||||
if (criterion !== 'pattern') { // reserved for pattern name
|
||||
// The only rule is a required tag-value pair
|
||||
var v = entity.tags[criterion];
|
||||
if (!v || v !== rule[criterion]) {
|
||||
pass = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pass) {
|
||||
this.style.fill = this.style.stroke = 'url("#pattern-' + rule.pattern + '")';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.style.fill = this.style.stroke = '';
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
@@ -284,7 +167,7 @@ export function svgAreas(projection, context) {
|
||||
|
||||
if (layer === 'fill') {
|
||||
this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
|
||||
setPattern.call(this, entity);
|
||||
this.style.fill = this.style.stroke = getPatternStyle(entity.tags);
|
||||
}
|
||||
})
|
||||
.call(svgTagClasses())
|
||||
|
||||
@@ -23,6 +23,7 @@ export { svgRelationMemberTags } from './helpers.js';
|
||||
export { svgSegmentWay } from './helpers.js';
|
||||
export { svgStreetside } from './streetside.js';
|
||||
export { svgTagClasses } from './tag_classes.js';
|
||||
export { svgTagPattern } from './tag_pattern.js';
|
||||
export { svgTouch } from './touch.js';
|
||||
export { svgTurns } from './turns.js';
|
||||
export { svgVertices } from './vertices.js';
|
||||
|
||||
125
modules/svg/tag_pattern.js
Normal file
125
modules/svg/tag_pattern.js
Normal file
@@ -0,0 +1,125 @@
|
||||
|
||||
// Patterns only work in Firefox when set directly on element.
|
||||
// (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
|
||||
var patterns = {
|
||||
// tag - pattern name
|
||||
// -or-
|
||||
// tag - value - pattern name
|
||||
// -or-
|
||||
// tag - value - rules (optional tag-values, pattern name)
|
||||
// (matches earlier rules first, so fallback should be last entry)
|
||||
amenity: {
|
||||
grave_yard: 'cemetery',
|
||||
fountain: 'water_standing'
|
||||
},
|
||||
landuse: {
|
||||
cemetery: [
|
||||
{ religion: 'christian', pattern: 'cemetery_christian' },
|
||||
{ religion: 'buddhist', pattern: 'cemetery_buddhist' },
|
||||
{ religion: 'muslim', pattern: 'cemetery_muslim' },
|
||||
{ religion: 'jewish', pattern: 'cemetery_jewish' },
|
||||
{ pattern: 'cemetery' }
|
||||
],
|
||||
construction: 'construction',
|
||||
farmland: 'farmland',
|
||||
farmyard: 'farmyard',
|
||||
forest: [
|
||||
{ leaf_type: 'broadleaved', pattern: 'forest_broadleaved' },
|
||||
{ leaf_type: 'needleleaved', pattern: 'forest_needleleaved' },
|
||||
{ leaf_type: 'leafless', pattern: 'forest_leafless' },
|
||||
{ pattern: 'forest' } // same as 'leaf_type:mixed'
|
||||
],
|
||||
grave_yard: 'cemetery',
|
||||
grass: 'grass',
|
||||
landfill: 'landfill',
|
||||
meadow: 'meadow',
|
||||
military: 'construction',
|
||||
orchard: 'orchard',
|
||||
quarry: 'quarry',
|
||||
vineyard: 'vineyard'
|
||||
},
|
||||
natural: {
|
||||
beach: 'beach',
|
||||
grassland: 'grass',
|
||||
sand: 'beach',
|
||||
scrub: 'scrub',
|
||||
water: [
|
||||
{ water: 'pond', pattern: 'pond' },
|
||||
{ water: 'reservoir', pattern: 'water_standing' },
|
||||
{ pattern: 'waves' }
|
||||
],
|
||||
wetland: [
|
||||
{ wetland: 'marsh', pattern: 'wetland_marsh' },
|
||||
{ wetland: 'swamp', pattern: 'wetland_swamp' },
|
||||
{ wetland: 'bog', pattern: 'wetland_bog' },
|
||||
{ wetland: 'reedbed', pattern: 'wetland_reedbed' },
|
||||
{ pattern: 'wetland' }
|
||||
],
|
||||
wood: [
|
||||
{ leaf_type: 'broadleaved', pattern: 'forest_broadleaved' },
|
||||
{ leaf_type: 'needleleaved', pattern: 'forest_needleleaved' },
|
||||
{ leaf_type: 'leafless', pattern: 'forest_leafless' },
|
||||
{ pattern: 'forest' } // same as 'leaf_type:mixed'
|
||||
]
|
||||
},
|
||||
traffic_calming: {
|
||||
island: [
|
||||
{ surface: 'grass', pattern: 'grass' },
|
||||
],
|
||||
chicane: [
|
||||
{ surface: 'grass', pattern: 'grass' },
|
||||
],
|
||||
choker: [
|
||||
{ surface: 'grass', pattern: 'grass' },
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export function svgTagPattern(tags) {
|
||||
// Skip pattern filling if this is a building (buildings don't get patterns applied)
|
||||
if (tags.building && tags.building !== 'no') {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (var tag in patterns) {
|
||||
var entityValue = tags[tag];
|
||||
if (!entityValue) continue;
|
||||
|
||||
if (typeof patterns[tag] === 'string') { // extra short syntax (just tag) - pattern name
|
||||
return 'pattern-' + patterns[tag];
|
||||
} else {
|
||||
var values = patterns[tag];
|
||||
for (var value in values) {
|
||||
if (entityValue !== value) continue;
|
||||
|
||||
var rules = values[value];
|
||||
if (typeof rules === 'string') { // short syntax - pattern name
|
||||
return 'pattern-' + rules;
|
||||
}
|
||||
|
||||
// long syntax - rule array
|
||||
for (var ruleKey in rules) {
|
||||
var rule = rules[ruleKey];
|
||||
|
||||
var pass = true;
|
||||
for (var criterion in rule) {
|
||||
if (criterion !== 'pattern') { // reserved for pattern name
|
||||
// The only rule is a required tag-value pair
|
||||
var v = tags[criterion];
|
||||
if (!v || v !== rule[criterion]) {
|
||||
pass = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pass) {
|
||||
return 'pattern-' + rule.pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import { select as d3_select } from 'd3-selection';
|
||||
|
||||
import { svgIcon, svgTagClasses } from '../svg';
|
||||
import { svgTagClasses } from '../svg/tag_classes';
|
||||
import { svgIcon } from '../svg/icon';
|
||||
import { svgTagPattern } from '../svg/tag_pattern';
|
||||
import { utilFunctor } from '../util';
|
||||
|
||||
export function uiPresetIcon(context) {
|
||||
@@ -282,10 +284,15 @@ export function uiPresetIcon(context) {
|
||||
renderSquareFill(fillEnter);
|
||||
fill = fillEnter.merge(fill);
|
||||
|
||||
var patternID = svgTagPattern(tags);
|
||||
var patternStyle = patternID ? 'url("#' + patternID + '")' : null;
|
||||
|
||||
fill.selectAll('path.stroke')
|
||||
.attr('class', 'area stroke ' + tagClasses);
|
||||
fill.selectAll('path.fill')
|
||||
.attr('class', 'area fill ' + tagClasses);
|
||||
.attr('class', 'area fill ' + tagClasses)
|
||||
.style('fill', patternStyle)
|
||||
.style('stroke', patternStyle);
|
||||
|
||||
|
||||
var line = container.selectAll('.preset-icon-line')
|
||||
|
||||
Reference in New Issue
Block a user