<commit_before>iD.svg.Areas = function(projection) {
    // Patterns only work in Firefox when set directly on element
    var patterns = {
        wetland: 'wetland',
        beach: 'beach',
        scrub: 'scrub',
        construction: 'construction',
        cemetery: 'cemetery',
        grave_yard: 'cemetery',
        meadow: 'meadow',
        farm: 'farmland',
        farmland: 'farmland',
        orchard: 'orchard'
    };

    var patternKeys = ['landuse', 'natural', 'amenity'];

    function setPattern(selection) {
        selection.each(function(d) {
            for (var i = 0; i < patternKeys.length; i++) {
                if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
                    this.style.fill = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
                    return;
                }
            }
            this.style.fill = '';
        });
    }

    return function drawAreas(surface, graph, entities, filter) {
        var path = iD.svg.Path(projection, graph),
            areas = {},
            multipolygon;

        for (var i = 0; i < entities.length; i++) {
            var entity = entities[i];
            if (entity.geometry(graph) !== 'area') continue;

            if (multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph)) {
                areas[multipolygon.id] = {
                    entity: multipolygon.mergeTags(entity.tags),
                    area: Math.abs(path.area(entity))
                };
            } else if (!areas[entity.id]) {
                areas[entity.id] = {
                    entity: entity,
                    area: Math.abs(path.area(entity))
                };
            }
        }

        areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
        areas.sort(function areaSort(a, b) { return b.area - a.area; });
        areas = _.pluck(areas, 'entity');

        var strokes = areas.filter(function isWay(area) {
            return area.type === 'way';
        });

        function drawPaths(areas, klass, path) {
            var paths = surface.select('.layer-' + klass)
                .selectAll('path.area')
                .filter(filter)
                .data(areas, iD.Entity.key);

            var enter = paths.enter()
                .append('path')
                .attr('class', function(d) { return d.type + ' area ' + klass + ' ' + d.id; })
                .call(iD.svg.TagClasses());

            if (klass === 'fill') enter.call(setPattern);

            paths
                .order()
                .attr('d', path);

            paths.exit()
                .remove();

            return paths;
        }

        drawPaths(strokes, 'shadow', path);
        drawPaths(strokes, 'stroke', path);
        drawPaths(areas, 'fill', path);
    };
};<commit_msg>Render areas in one pass<commit_after>iD.svg.Areas = function(projection) {
    // Patterns only work in Firefox when set directly on element
    var patterns = {
        wetland: 'wetland',
        beach: 'beach',
        scrub: 'scrub',
        construction: 'construction',
        cemetery: 'cemetery',
        grave_yard: 'cemetery',
        meadow: 'meadow',
        farm: 'farmland',
        farmland: 'farmland',
        orchard: 'orchard'
    };

    var patternKeys = ['landuse', 'natural', 'amenity'];

    function setPattern(d) {
        for (var i = 0; i < patternKeys.length; i++) {
            if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
                this.style.fill = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
                return;
            }
        }
        this.style.fill = '';
    }

    return function drawAreas(surface, graph, entities, filter) {
        var path = iD.svg.Path(projection, graph),
            areas = {},
            multipolygon;

        for (var i = 0; i < entities.length; i++) {
            var entity = entities[i];
            if (entity.geometry(graph) !== 'area') continue;

            if (multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph)) {
                areas[multipolygon.id] = {
                    entity: multipolygon.mergeTags(entity.tags),
                    area: Math.abs(path.area(entity))
                };
            } else if (!areas[entity.id]) {
                areas[entity.id] = {
                    entity: entity,
                    area: Math.abs(path.area(entity))
                };
            }
        }

        areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
        areas.sort(function areaSort(a, b) { return b.area - a.area; });
        areas = _.pluck(areas, 'entity');

        var strokes = areas.filter(function(area) {
            return area.type === 'way';
        });

        var data = {
            shadow: strokes,
            stroke: strokes,
            fill: areas
        };

        var paths = surface.selectAll('.layer-shadow, .layer-stroke, .layer-fill')
            .selectAll('path.area')
            .filter(filter)
            .data(function(layer) { return data[layer]; }, iD.Entity.key);

        paths.enter()
            .append('path')
            .each(function(entity) {
                var layer = this.parentNode.__data__;

                this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);

                if (layer === 'fill') {
                    setPattern.apply(this, arguments);
                }
            })
            .call(iD.svg.TagClasses());

        paths
            .order()
            .attr('d', path);

        paths.exit()
            .remove();
    };
};
{'fraction_non_alphanumeric': 0.1420996818663839, 'fraction_numerical': 0.0010604453870625664, 'mean_word_length': 1.5583182640144666, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5678589', 'n_tokens_mistral': 1670, 'n_tokens_neox': 1621, 'n_words': 329}