const MAX_PAGE_MATERIALS = 16 const MATERIALS_PER_ROW = 4 const MAX_BLOCK_SIZE = 3 function chunkify(array, size) { let chunks = [] for (let i = 0, j = array.length; i < j; i += size) { let slice = array.slice(i, i + size) chunks.push(slice) } return chunks } function copyModel(model) { if (model) { return JSON.parse(JSON.stringify(model)) } else { console.error('no model to copy') } } function copyModels(models) { let copies = [] if (models) { for (let model of models) { let copy = copyModel(model) copies.push(copy) } } return copies } // split models with too many materials function splitModels(models) { let splits = [] for (let model of models) { if (model.size > MAX_BLOCK_SIZE) { let chunks = chunkify(model.ids, MAX_PAGE_MATERIALS) for (let chunk of chunks) { let splitModel = copyModel(model) splitModel.ids = chunk splits.push(splitModel) } } else { splits.push(copyModel(model)) } } return splits } // join adjacent models with the same model number function joinModels(models) { let joins = [] let lastModel = null for (let model of models) { model = copyModel(model) if (lastModel) { if (lastModel.model === model.model) { // match - join lastModel.ids.push(...model.ids) // uniquify lastModel.ids = lastModel.ids.filter((v, i, a) => a.indexOf(v) === i) } else { // no match - add joins.push(model) lastModel = model } } else { // first - add joins.push(model) lastModel = model } } return joins } export function paginateModels(models) { models = joinModels(models) for (let model of models) { model.size = modelBlockSize(model) } models = splitModels(models) for (let model of models) { model.size = modelBlockSize(model) } models = copyModels(models) let pages = [] let currentSize = 0 let currentPage = [] for (let model of models) { if (model.size < 1) { // skip empty models continue } currentSize += model.size if (currentSize > 3) { pages.push(currentPage) currentPage = [model] currentSize = model.size } else { currentPage.push(model) } } if (currentPage.length > 0) { pages.push(currentPage) } return pages } export function modelBlockSize(model) { if (!model || !model.ids) return 0 if (model.ids.length <= MATERIALS_PER_ROW) return 1 if (model.ids.length <= MATERIALS_PER_ROW * 2) return 2 if (model.ids.length <= MATERIALS_PER_ROW * 4) return 3 return MAX_BLOCK_SIZE + 1 // generic "too big" } // de-paginate, essentially export function modelsFromSection(section, getters) { // remove pages, return models (blocks) in order. // combine blocks with the same model number. let models = [] if (section && section.pages) { for (let page of section.pages) { for (let model of page) { model = copyModel(model) if (model.ids && model.ids.length > 0) { // add extra info from a material let material = getters.material(model.ids[0]) if (material) { model = extendModelFromMaterial(material, model) } else { console.log('no material found for id', model.ids[0]) } models.push(model) } } } } return joinModels(models) } export function sectionTitle(material) { // "Trailhead (Men)" if (material) { return `${material.category} (${material.gender})` } else { return '(unknown)' } } // add properties from the material to the model, // creating it if necessary. export function extendModelFromMaterial(material, model = {}) { if (material) { if (!model['name']) { // don't overwrite possibly overridden value model['name'] = material.name } model['model'] = material.model model['family'] = material.family model['gender'] = material.gender model['category'] = material.category // make sure the material id is in the list let ids = model['ids'] || [] if (!ids.includes(material.id)) { ids.push(material.id) model['ids'] = ids } } return model }