Skip to content
Snippets Groups Projects
Commit 6922265f authored by Xiao Gui's avatar Xiao Gui
Browse files

feat: encodding region selected as b64, greatly reduce url lengtth

comparison allen v3, ~580 regions selected:
- pre 2019 May release: 2854 char
- post 2019 May release: 7390 char
- this patch: 1997 char

maintaining backwards compat
parent 341c1e25
No related branches found
No related tags found
No related merge requests found
......@@ -290,4 +290,55 @@ export const SUPPORT_LIBRARY_MAP : Map<string,HTMLElement> = new Map([
['vue@2.5.16',parseURLToElement('https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js')],
['preact@8.4.2',parseURLToElement('https://cdn.jsdelivr.net/npm/preact@8.4.2/dist/preact.min.js')],
['d3@5.7.0',parseURLToElement('https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js')]
])
\ No newline at end of file
])
/**
* First attempt at encoding int (e.g. selected region, navigation location) from number (loc info density) to b64 (higher info density)
* The constraint is that the cipher needs to be commpatible with URI encoding
* and a URI compatible separator is required.
*
* The implementation below came from
* https://stackoverflow.com/a/6573119/6059235
*
* While a faster solution exist in the same post, this operation is expected to be done:
* - once per 1 sec frequency
* - on < 1000 numbers
*
* So performance is not really that important (Also, need to learn bitwise operation)
*/
const cipher = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-"
export const separator = "."
export const encodeNumber = (number: number) => {
if (isNaN(Number(number)) || number === null ||
number === Number.POSITIVE_INFINITY)
throw "The input is not valid"
if (number < 0)
throw "Can't represent negative numbers now"
let rixit // like 'digit', only in some non-decimal radix
let residual = Math.floor(number)
let result = ''
while (true) {
rixit = residual % 64
// console.log("rixit : " + rixit)
// console.log("result before : " + result)
result = cipher.charAt(rixit) + result
// console.log("result after : " + result)
// console.log("residual before : " + residual)
residual = Math.floor(residual / 64)
// console.log("residual after : " + residual)
if (residual == 0)
break;
}
return result
}
export const decodeToNumber = (encodedString: string) => {
return [...encodedString].reduce((acc,curr) => {
return acc * 64 + cipher.indexOf(curr)
}, 0)
}
\ No newline at end of file
import { Injectable } from "@angular/core";
import { Store, select } from "@ngrx/store";
import { ViewerStateInterface, isDefined, NEWVIEWER, CHANGE_NAVIGATION, ADD_NG_LAYER, generateLabelIndexId } from "../services/stateStore.service";
import { ViewerStateInterface, isDefined, NEWVIEWER, CHANGE_NAVIGATION, ADD_NG_LAYER } from "../services/stateStore.service";
import { PluginInitManifestInterface } from 'src/services/state/pluginState.store'
import { Observable,combineLatest } from "rxjs";
import { filter, map, scan, distinctUntilChanged, skipWhile, take } from "rxjs/operators";
import { PluginServices } from "./atlasViewer.pluginService.service";
import { AtlasViewerConstantsServices } from "./atlasViewer.constantService.service";
import { AtlasViewerConstantsServices, encodeNumber, separator, decodeToNumber } from "./atlasViewer.constantService.service";
import { ToastService } from "src/services/toastService.service";
import { SELECT_REGIONS_WITH_ID } from "src/services/state/viewerState.store";
......@@ -157,6 +157,34 @@ export class AtlasViewerURLService{
selectRegionIds: ids
})
}
const cRegionsSelectedParam = searchparams.get('cRegionsSelected')
if (cRegionsSelectedParam) {
try {
const json = JSON.parse(cRegionsSelectedParam)
const selectRegionIds = []
for (let ngId in json) {
const val = json[ngId]
const labelIndicies = val.split(separator).map(decodeToNumber)
for (let labelIndex of labelIndicies) {
selectRegionIds.push(`${ngId}#${labelIndex}`)
}
}
this.store.dispatch({
type: SELECT_REGIONS_WITH_ID,
selectRegionIds
})
} catch (e) {
/**
* parsing cRegionSelected error
*/
console.log('parsing cRegionSelected error', e)
}
}
}
/* now that the parcellation is loaded, load the navigation state */
......@@ -222,9 +250,37 @@ export class AtlasViewerURLService{
].join('__')
}
break;
case 'regionsSelected':
_[key] = state[key].map(({ ngId, labelIndex })=> generateLabelIndexId({ ngId,labelIndex })).join('_')
case 'regionsSelected': {
// _[key] = state[key].map(({ ngId, labelIndex })=> generateLabelIndexId({ ngId,labelIndex })).join('_')
const ngIdLabelIndexMap : Map<string, number[]> = state[key].reduce((acc, curr) => {
const returnMap = new Map(acc)
const { ngId, labelIndex } = curr
const existingArr = (returnMap as Map<string, number[]>).get(ngId)
if (existingArr) {
existingArr.push(labelIndex)
} else {
returnMap.set(ngId, [labelIndex])
}
return returnMap
}, new Map())
if (ngIdLabelIndexMap.size === 0) {
_['cRegionsSelected'] = null
_[key] = null
break;
}
const returnObj = {}
for (let entry of ngIdLabelIndexMap) {
const [ ngId, labelIndicies ] = entry
returnObj[ngId] = labelIndicies.map(encodeNumber).join(separator)
}
_['cRegionsSelected'] = JSON.stringify(returnObj)
_[key] = null
break;
}
case 'templateSelected':
case 'parcellationSelected':
_[key] = state[key].name
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment