Source: FactoryPatterns/Chloropleth.js

/**
 * A class to create choropleth maps.
 *
 * @class      choroplethCreator (choroplethCreator)
 */

function chloroplethCreator() {
};

//UPDATED and not synced

chloroplethCreator.prototype = Object.create(MapCreator.prototype);
chloroplethCreator.prototype.constructor = chloroplethCreator;

/**
 * Creates a choropleth layer and adds it to the map
 *
 * @param      {ol.map}           map                     The map
 * @param      {ol.source}           vectorSource            The vector source
 * @param      {ol.source}           wardsSource             The wards source
 * @param      {string}           colorPerClass           The color per class
 * @param      {number}  amountOfColorClasses    The amount of color classes
 * @param      {string}           featureToDisplay        The feature to display
 * @param      {string}           selectedValue           The selected value
 * @param      {ol.layer}           wardsVectorLayer        The wards vector layer
 * @param      {ol.layer}           featureLayer            The feature layer
 * @param      {number[]}           classArray              The class of each feature
 * @param      {string}           featurePropertyKeyName  The feature property key name
 * @param      {boolean}          isDiscrete              Indicates if discrete
 */
chloroplethCreator.prototype.createMap = function(map, vectorSource, wardsSource, colorPerClass, amountOfColorClasses, featureToDisplay, selectedValue, wardsVectorLayer, featureLayer, classArray, featurePropertyKeyName, isDiscrete) {
    if (wardsSource.getFeatures().length <= 0) {
        console.log("WardsSource not ready");
        return;
    }

    wardsVectorLayer.layer = new ol.layer.Vector({
        source: wardsSource,
        style: new ol.style.Style({
            // fill: new ol.style.Fill({
            //     color: 'rgba(0, 0, 150, 1)'
            // }),
            // stroke: new ol.style.Stroke({
            //     color: 'rgba(0, 0, 0, 0.6)',
            //     width: 1
            // }),
            visible: true
        })
    });

    // map.addLayer(wardsVectorLayer.layer);
    // wardsVectorLayer.layer = new ol.layer.Vector({
    //     source: wardsSource
    // });

    // map.addLayer(wardsVectorLayer.layer)

    featureLayer.layer = new ol.layer.Vector({
        source: vectorSource,
        style: new ol.style.Style({
            visible: true
        })
    });
    map.addLayer(featureLayer.layer);
    //This is the amount of class ranges for the count of the features win a ward. 
    var amountOfColorClasses = colorPerClass.length; // This is specified by the user or AI
    if (isDiscrete) {
        var pointFeatures = vectorSource.getFeatures();
        var boundriesGeometry = wardsSource.getFeatures();
        var countOfClassPerWard;
        var countPerWard = [];
        var colorsPerWard = []; //hue per ward that determines color. Range 0-360
        for (var k = 0; k < amountOfColorClasses; k++) {
            colorsPerWard.push(0);
            countPerWard.push(0);
        }

        var maxClassCountOfWard = -1;
        var minClassCountOfWard = Number.POSITIVE_INFINITY;
        for (var i = 0; i < boundriesGeometry.length; i++) {
            countOfClassPerWard = 0;
            for (var j = 0; j < pointFeatures.length; j++) {
                // if(boundriesGeometry[i].getGeometry().intersects(pointFeatures[j].getGeometry())){
                if (ol.extent.intersects(pointFeatures[j].getGeometry().getExtent(), boundriesGeometry[i].getGeometry().getExtent())) { // Cite:B
                    // console.log("featureToDisplay" + featureToDisplay);
                    // console.log((pointFeatures[j].get(featureToDisplay)));
                    // console.log("selectedValue" + selectedValue);
                    if (pointFeatures[j].get(featureToDisplay) != null) {
                        if ((pointFeatures[j].get(featureToDisplay)).localeCompare(selectedValue) == 0) { //////////////////////////////
                            countOfClassPerWard = countOfClassPerWard + 1;
                        }
                    } else {
                        console.log("Undefined pointfeature, in choropleth");
                    }
                }
            }
            // console.log("ward " + i + " " + countOfClassPerWard);
            if (countOfClassPerWard < minClassCountOfWard) {
                minClassCountOfWard = countOfClassPerWard;
            }
            if (countOfClassPerWard > maxClassCountOfWard) {
                maxClassCountOfWard = countOfClassPerWard;
            }
            countPerWard[i] = countOfClassPerWard;
        }
        if (maxClassCountOfWard > 0) {
            var currentColorFraction = 0;

            //Upper limit for each class, where class 0's minimum = minClassCountOfWard;
            var classRangeMax = [];
            var currentHue = 0;
            for (var i = 0; i < amountOfColorClasses; i++) {
                //
                classRangeMax.push(minClassCountOfWard + ((i + 1) / amountOfColorClasses * (maxClassCountOfWard - minClassCountOfWard)));
                // currentColorFraction += 1 / amountOfColorClasses;
                // colorsPerWard[i] = i / amountOfColorClasses * 360;
                //Key for map
                // document.getElementById("mapKey").innerHTML += "<svg height=\"50\" width=\"200\">" +
                //     "<rect x=\"0\" y=\"25\" width=\"25\" height=\"25\" fill=\"hsla(" + colorsPerWard[i] + ", 100%, 47%, 0.6)\" />" +
                //     "<text x=\"35\" y=\"40\" fill=\"black\" font-size=\"14\">" + "Class #" + i + " 's max is " + classRangeMax[i] + "</text> </svg><hr>";
                // console.log("Class #" + i + " 's max is " + classRangeMax[i]);
            }


            var choroIndex = 0; // Number of current choropleth, to distinguish from others 
            var sourceProperty = sourceProperty + choroIndex; // This needs to differ to display various choropleths at the same time.
            var isClassified = false;
            for (var i = 0; i < boundriesGeometry.length; i++) {
                // See within which class the ward is:
                isClassified = false;
                for (var j = 0; j < amountOfColorClasses; j++) {
                    if (isClassified == false && countPerWard[i] <= classRangeMax[j]) {
                        // console.log(countPerWard[i] + "<=" + classRangeMax[j] + "::class " + j);
                        boundriesGeometry[i].set(sourceProperty, j); // test value j
                        isClassified = true;
                    }
                }
            }

            function wardStyleF(feature) {
                // var index = feature.get('index');
                if (feature.get(sourceProperty) != null && feature.get(sourceProperty) != undefined && colorPerClass[feature.get(sourceProperty)]
                    &&  colorPerClass[feature.get(sourceProperty)][0] != undefined) {
                    // console.log("SP=" + feature.get(sourceProperty));
                    var fill = new ol.style.Fill({
                        color: 'hsla(' + colorPerClass[feature.get(sourceProperty)][0] + ', ' + colorPerClass[feature.get(sourceProperty)][1] +
                            '%, ' + colorPerClass[feature.get(sourceProperty)][2] + '%, 0.6)'
                    });
                    var style = new ol.style.Style({
                        fill: fill
                    });
                    return [style];
                } else {
                    var style = new ol.style.Style({});
                    return [style];
                }
            }


            boundriesGeometry[0].changed(); // explicitly dispatches change event to re-render layer with changed source
            wardsVectorLayer.layer = new ol.layer.Vector({
                source: wardsSource,
                style: wardStyleF
            });
            map.addLayer(wardsVectorLayer.layer);
        } else {
            console.log("No classes found");
        }
    } else {
        var boundriesGeometry = wardsSource.getFeatures();
        var featureCount = boundriesGeometry.length;
        for (var i = 0; i < featureCount; i++) {
            boundriesGeometry[i].set('index', i);
        };
        // var featureClassProperty = ""; // coming from parameter, here for testing

        
        console.log("CLASSES : " + amountOfColorClasses);
        if(amountOfColorClasses == 7)
        {
            console.log(classArray);
        }

        function wardStyleF2(feature) {
            // var index = feature.get('index');
            // console.log("Choro func fpkn " + featurePropertyKeyName);
            // console.log("Choro func feature value " + feature.get(featurePropertyKeyName));
            //TODO
            // console.log(feature.get("index") + " Class=" + classArray[feature.get("index")]);
            // console.log("Value=" +  feature.get(featurePropertyKeyName));


            if (colorPerClass[classArray[feature.get('index')]] == undefined) {
                var style = new ol.style.Style({});
                return [style];
            } else {
                var fill = new ol.style.Fill({
                    color: 'hsla(' + colorPerClass[classArray[feature.get('index')]][0] + ', ' + colorPerClass[classArray[feature.get('index')]][1] +
                        '%, ' + colorPerClass[classArray[feature.get('index')]][2] + '%, 0.6)'
                });
                var style = new ol.style.Style({
                    fill: fill
                });
                return [style];
            }
        }
        wardsVectorLayer.layer = new ol.layer.Vector({
            source: wardsSource,
            style: wardStyleF2
        });
        map.addLayer(wardsVectorLayer.layer);
    }
};

/**
 * A concrete product of a choropleth map creator.
 *
 * @class      choroplethConcrete
 */
function choroplethConcrete(map) {
    this.map = map;
};

choroplethConcrete.prototype = Object.create(MapProduct.prototype);
choroplethConcrete.prototype.constructor = choroplethConcrete;