public static converter()

in src/StrippetsVisual.ts [246:503]


    public static converter(dataView: DataView, updateIconMap: boolean = false, appendTo?: any, lastDataViewLength: number = 0, defaultColors = []) {
        const categoricalDV = dataView.categorical;
        const categoriesDV = categoricalDV.categories;
        const valuesDV = categoricalDV.values;
        const categories = <any>{};
        const colors = COLOR_PALETTE.slice().concat(defaultColors.map((color: IColorInfo) => color.value));

        categoriesDV.forEach((category, index) => {
            Object.keys(category.source.roles).forEach(categoryName => categories[categoryName] = index);
        });

        const updateIM = updateIconMap && categories['entityType'];

        const strippetsData = (appendTo && appendTo.items) ? appendTo.items.reduce((memo, i) => {
            memo[i.id] = i;
            memo[i.id].order = Object.keys(memo).length + 1;
            return memo;
        }, {}) : <any>{};

        const iconMap = (appendTo && appendTo.iconMap) ? appendTo.iconMap.reduce((memo, im) => {
            const entityTypeId = im.type + '_' + im.name;
            memo[entityTypeId] = {
                class: im.class,
                color: im.color,
                type: im.type,
                name: im.name,
                isDefault: im.isDefault
            };
            return memo;
        }, {}) : <any>{};

        const highlightedEntities = (appendTo && appendTo.highlights && appendTo.highlights.entities) ? appendTo.highlights.entities.reduce((memo, im) => {
            const entityTypeId = im.type + '_' + im.name;
            memo[entityTypeId] = im;
            return memo;
        }, {}) : <any>{};

        const getCategoryValue = (fieldName: string, itemIndex: number) => {
            return categories[fieldName] !== undefined ? categoriesDV[categories[fieldName]].values[itemIndex] : null;
        };
        const isHighlightingOn = valuesDV && valuesDV[0].highlights && valuesDV[0].highlights.length > 0;

        const getHighlightValue = (itemIndex: number) => {
            return isHighlightingOn ? valuesDV[0].highlights[itemIndex] : false;
        };

        const bucketMap = {};
        const getBucket = (bucketValue: any) => {
            if (bucketValue) {
                if (!bucketMap[bucketValue]) {
                    let bucket: Bucket = {
                        key: bucketValue,
                        value: 0,
                    };
                    // store the bucket value (which is probably a string) for later sorting and value generation
                    bucketMap[bucketValue] = bucket;
                }
                return bucketMap[bucketValue];
            }

            return null;
        };

        const populateUncertaintyFields = function (entity, entityIds, buckets, index) {
            if (entityIds.length > index && (entityIds[index] || entityIds[index] === 0)) {
                entity.id = entityIds[index];
                if (buckets.length > index) {
                    entity.bucket = getBucket(buckets[index]);
                }
            }
        };

        const populateUncertaintyFieldsCompressed = function (entity, parsedEntity) {
            if (parsedEntity.hasOwnProperty('entityId') && (parsedEntity.entityId || parsedEntity.entityId === 0)) {
                entity.id = parsedEntity.entityId;
                if (parsedEntity.hasOwnProperty('bucket')) {
                    entity.bucket = getBucket(parsedEntity.bucket);
                }
            }
        };

        const adjustIconColor = function (iconMapEntity, bucket, dataColor, isHighlight) {
            if (bucket) {
                if (dataColor) {
                    iconMapEntity.color = getSegmentColor(dataColor, 100, 0, 1, isHighlight);
                }
                else {
                    iconMapEntity.color = BUCKET_DEFAULT_GREY;
                }
            }
        };

        const highlightEntityAndMapIcon = function (entity, entityClass, entityColor, isHighlighted) {
            let highlighted = false;

            if (entity.type && entity.name) {
                const entityTypeId = entity.type + '_' + entity.name;
                if (isHighlighted && !highlightedEntities[entityTypeId]) {
                    highlightedEntities[entityTypeId] = {
                        id: entity.id,
                        type: entity.type,
                        name: entity.name,
                        bucket: entity.bucket
                    };
                    adjustIconColor(highlightedEntities[entityTypeId], entity.bucket, entityColor, true);
                    highlighted = true;
                }
                if (updateIM && !iconMap[entityTypeId]) {
                    iconMap[entityTypeId] = {
                        class: entityClass || 'fa fa-circle',
                        color: entityColor === null ? colors.shift() : entityColor,
                        type: entity.type,
                        name: entity.name,
                        isDefault: false
                    };

                    adjustIconColor(iconMap[entityTypeId], entity.bucket, entityColor, false);
                }
            }

            return highlighted;
        };

        categoriesDV[categories['id']] && categoriesDV[categories['id']].values.slice(lastDataViewLength).forEach((id: any, adjustedIndex) => {
            // highlight table is not compensated. Since we slice the values, we need to compensate for the slice. Slicing at the highlights level
            // will result in slower performance.
            const index = adjustedIndex + lastDataViewLength;
            const isHighlighted = getHighlightValue(index);
            if (!strippetsData[id]) {
                const title = getCategoryValue('title', index);
                const summary = getCategoryValue('summary', index);
                let articleDate = getCategoryValue('articleDate', index);
                if (articleDate) {
                    articleDate = StrippetBrowser16424341054522.cleanString(articleDate);
                }

                strippetsData[id] = {
                    id: id,
                    title: StrippetBrowser16424341054522.asUtf8(title ? StrippetBrowser16424341054522.cleanString(String(title)) : ''),
                    summary: summary ? StrippetBrowser16424341054522.sanitizeHTML(String(summary), StrippetBrowser16424341054522.HTML_WHITELIST_SUMMARY) : '',
                    content: getCategoryValue('content', index),
                    imageUrl: StrippetBrowser16424341054522.cleanImageUrl(getCategoryValue('imageUrl', index)),
                    author: StrippetBrowser16424341054522.cleanString(getCategoryValue('author', index)),
                    source: StrippetBrowser16424341054522.cleanString(String(getCategoryValue('source', index) || '')),
                    sourceUrl: StrippetBrowser16424341054522.cleanString(String(getCategoryValue('sourceUrl', index) || '')),
                    sourceimage: StrippetBrowser16424341054522.cleanImageUrl(getCategoryValue('sourceImage', index)),
                    articleDate: articleDate,
                    articledate: articleDate, // thumbnails data model has 'articledate' instead of 'articleDate'
                    entities: [],
                    readerUrl: id,
                    isHighlighted: isHighlighted,
                    order: Object.keys(strippetsData).length + 1
                };
            }

            const entityTypesString = String((categories['entityType'] && categoriesDV[categories['entityType']].values[index]) || '');
            const parsedEntityType = (toParse => {
                try {
                    return JSON.parse(toParse);
                } catch (err) {
                    return null;
                }
            })(entityTypesString);

            if (parsedEntityType instanceof Array &&
                parsedEntityType.length > 0 &&
                'entityType' in parsedEntityType[0] &&
                'entityValue' in parsedEntityType[0] &&
                'offsetPercentage' in parsedEntityType[0]) {
                // generate the instances based on the data in the JSON

                for (let i = 0, n = parsedEntityType.length; i < n; ++i) {
                    const parsedEntity = parsedEntityType[i];
                    const entityFirstPosition = parseFloat(parsedEntity.offsetPercentage);
                    const entity: any = {
                        name: parsedEntity.entityValue || '',
                        type: parsedEntity.entityType || '',
                        firstPosition: isNaN(entityFirstPosition) ? null : entityFirstPosition,
                        bucket: getBucket(parsedEntity.bucket)
                    };

                    populateUncertaintyFieldsCompressed(entity, parsedEntity);

                    if (highlightEntityAndMapIcon(entity, parsedEntity.cssClass, parsedEntity.cssColor, isHighlighted)) {
                        populateUncertaintyFieldsCompressed(entity, parsedEntity);
                    }

                    strippetsData[id].entities.push(entity);
                }
            } else {
                // fallback to reading one entity from each data field
                const entityTypes = entityTypesString.split('||');
                const entityIds = String((categories['entityId'] && categoriesDV[categories['entityId']].values[index]) || '').split('||');
                const entityNames = String((categories['entityName'] && categoriesDV[categories['entityName']].values[index]) || '').split('||');
                const entityPositions = String((categories['entityPosition'] && categoriesDV[categories['entityPosition']].values[index]) || '').split('||');
                const entityColors = String((categories['entityTypeColor'] && categoriesDV[categories['entityTypeColor']].values[index]) || '').split('||');
                const entityClasses = String((categories['entityTypeClass'] && categoriesDV[categories['entityTypeClass']].values[index]) || '').split('||');
                const buckets = String((categories['bucket'] && categoriesDV[categories['bucket']].values[index]) || '').split('||');

                const propertiesLength = Math.max(entityTypes.length, entityIds.length, entityNames.length, entityPositions.length);

                if (propertiesLength) {
                    for (let i = 0; i < propertiesLength; ++i) {
                        const entityColor = entityColors.length > i ? entityColors[i] : null;
                        const entityClass = entityClasses.length > i ? entityClasses[i] : null;
                        let bucket: Bucket = null;

                        let entity: any = {
                            name: entityNames.length > i ? entityNames[i] : '',
                            type: entityTypes.length > i ? entityTypes[i] : '',
                            firstPosition: entityPositions.length > i ? parseFloat(entityPositions[i]) : null,
                            bucket: getBucket(buckets[i]),
                        };

                        populateUncertaintyFields(entity, entityIds, buckets, i);
                        highlightEntityAndMapIcon(entity, entityClass, entityColor, isHighlighted);
                        strippetsData[id].entities.push(entity);
                    }
                }
            }

            // Set highlighted state only if strippets contains a highlighted entity.
            if (!strippetsData[id].isHighlighted && isHighlighted) {
                strippetsData[id].isHighlighted = isHighlighted;
            }
        });
        const items = Object.keys(strippetsData).reduce((memo, key) => {
            memo.push(strippetsData[key]);
            return memo;
        }, []).sort((a, b) => {
            return a.order - b.order;
        });

        const bucketList = _.sortBy(bucketMap, (bucket: Bucket) => bucket.key);
        const numBuckets: number = Math.max(1, bucketList.length);
        bucketList.map(function (bucket: Bucket, index) {
            bucket.value = index / numBuckets;
        });

        return {
            items: items,
            iconMap: updateIM ? Object.keys(iconMap).map(key => {
                return iconMap[key];
            }) : [],
            highlights: isHighlightingOn ? {
                entities: Object.keys(highlightedEntities).reduce((memo, key) => {
                    memo.push(highlightedEntities[key]);
                    return memo;
                }, []),
                itemIds: items.reduce((memo, item) => {
                    if (item.isHighlighted) {
                        memo.push(item.id);
                    }
                    return memo;
                }, []),
            } : null,
        };
    }