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,
};
}