vega-selections
Advanced tools
Comparing version 5.3.1 to 5.4.0
@@ -5,25 +5,29 @@ (function (global, factory) { | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vega = {}, global.vega, global.vega)); | ||
}(this, (function (exports, vegaUtil, vegaExpression) { 'use strict'; | ||
})(this, (function (exports, vegaUtil, vegaExpression) { 'use strict'; | ||
function ascending (a, b) { | ||
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; | ||
function ascending(a, b) { | ||
return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; | ||
} | ||
function bisector (f) { | ||
function bisector(f) { | ||
let delta = f; | ||
let compare = f; | ||
let compare1 = f; | ||
let compare2 = f; | ||
if (f.length === 1) { | ||
if (f.length !== 2) { | ||
delta = (d, x) => f(d) - x; | ||
compare = ascendingComparator(f); | ||
compare1 = ascending; | ||
compare2 = (d, x) => ascending(f(d), x); | ||
} | ||
function left(a, x, lo, hi) { | ||
if (lo == null) lo = 0; | ||
if (hi == null) hi = a.length; | ||
function left(a, x, lo = 0, hi = a.length) { | ||
if (lo < hi) { | ||
if (compare1(x, x) !== 0) return hi; | ||
while (lo < hi) { | ||
const mid = lo + hi >>> 1; | ||
if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid; | ||
do { | ||
const mid = lo + hi >>> 1; | ||
if (compare2(a[mid], x) < 0) lo = mid + 1;else hi = mid; | ||
} while (lo < hi); | ||
} | ||
@@ -34,9 +38,10 @@ | ||
function right(a, x, lo, hi) { | ||
if (lo == null) lo = 0; | ||
if (hi == null) hi = a.length; | ||
function right(a, x, lo = 0, hi = a.length) { | ||
if (lo < hi) { | ||
if (compare1(x, x) !== 0) return hi; | ||
while (lo < hi) { | ||
const mid = lo + hi >>> 1; | ||
if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1; | ||
do { | ||
const mid = lo + hi >>> 1; | ||
if (compare2(a[mid], x) <= 0) lo = mid + 1;else hi = mid; | ||
} while (lo < hi); | ||
} | ||
@@ -47,5 +52,3 @@ | ||
function center(a, x, lo, hi) { | ||
if (lo == null) lo = 0; | ||
if (hi == null) hi = a.length; | ||
function center(a, x, lo = 0, hi = a.length) { | ||
const i = left(a, x, lo, hi - 1); | ||
@@ -62,6 +65,103 @@ return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i; | ||
function ascendingComparator(f) { | ||
return (d, x) => ascending(f(d), x); | ||
class InternSet extends Set { | ||
constructor(values, key = keyof) { | ||
super(); | ||
Object.defineProperties(this, { | ||
_intern: { | ||
value: new Map() | ||
}, | ||
_key: { | ||
value: key | ||
} | ||
}); | ||
if (values != null) for (const value of values) this.add(value); | ||
} | ||
has(value) { | ||
return super.has(intern_get(this, value)); | ||
} | ||
add(value) { | ||
return super.add(intern_set(this, value)); | ||
} | ||
delete(value) { | ||
return super.delete(intern_delete(this, value)); | ||
} | ||
} | ||
function intern_get({ | ||
_intern, | ||
_key | ||
}, value) { | ||
const key = _key(value); | ||
return _intern.has(key) ? _intern.get(key) : value; | ||
} | ||
function intern_set({ | ||
_intern, | ||
_key | ||
}, value) { | ||
const key = _key(value); | ||
if (_intern.has(key)) return _intern.get(key); | ||
_intern.set(key, value); | ||
return value; | ||
} | ||
function intern_delete({ | ||
_intern, | ||
_key | ||
}, value) { | ||
const key = _key(value); | ||
if (_intern.has(key)) { | ||
value = _intern.get(key); | ||
_intern.delete(key); | ||
} | ||
return value; | ||
} | ||
function keyof(value) { | ||
return value !== null && typeof value === "object" ? value.valueOf() : value; | ||
} | ||
function intersection(values, ...others) { | ||
values = new InternSet(values); | ||
others = others.map(set); | ||
out: for (const value of values) { | ||
for (const other of others) { | ||
if (!other.has(value)) { | ||
values.delete(value); | ||
continue out; | ||
} | ||
} | ||
} | ||
return values; | ||
} | ||
function set(values) { | ||
return values instanceof InternSet ? values : new InternSet(values); | ||
} | ||
function union(...others) { | ||
const set = new InternSet(); | ||
for (const other of others) { | ||
for (const o of other) { | ||
set.add(o); | ||
} | ||
} | ||
return set; | ||
} | ||
const Intersect = 'intersect'; | ||
@@ -73,5 +173,6 @@ const Union = 'union'; | ||
const And = 'and'; | ||
const SelectionId = '_vgsid_'; | ||
const $selectionId = vegaUtil.field(SelectionId); | ||
const SELECTION_ID = '_vgsid_', | ||
TYPE_ENUM = 'E', | ||
const TYPE_ENUM = 'E', | ||
TYPE_RANGE_INC = 'R', | ||
@@ -179,4 +280,3 @@ TYPE_RANGE_EXC = 'R-E', | ||
} | ||
const selectionId = vegaUtil.field(SELECTION_ID), | ||
bisect = bisector(selectionId), | ||
const bisect = bisector($selectionId), | ||
bisectLeft = bisect.left, | ||
@@ -189,6 +289,6 @@ bisectRight = bisect.right; | ||
intersect = op === Intersect, | ||
value = selectionId(datum), | ||
value = $selectionId(datum), | ||
index = bisectLeft(entries, value); | ||
if (index === entries.length) return false; | ||
if (selectionId(entries[index]) !== value) return false; | ||
if ($selectionId(entries[index]) !== value) return false; | ||
@@ -206,3 +306,3 @@ if (unitIdx && intersect) { | ||
* @param {string} name - The name of the dataset representing the selection. | ||
* @param {string} unit - The name of the unit view. | ||
* @param {string} base - The base object that generated tuples extend. | ||
* | ||
@@ -213,4 +313,6 @@ * @returns {array} An array of selection entries for the given unit. | ||
function selectionTuples(array, base) { | ||
return array.map(x => vegaUtil.extend({ | ||
return array.map(x => vegaUtil.extend(base.fields ? { | ||
values: base.fields.map(f => (f.getter || (f.getter = vegaUtil.field(f.field)))(x.datum)) | ||
} : { | ||
[SelectionId]: $selectionId(x.datum) | ||
}, base)); | ||
@@ -244,2 +346,3 @@ } | ||
field, | ||
value, | ||
res, | ||
@@ -260,20 +363,37 @@ resUnit, | ||
for (j = 0, m = fields.length; j < m; ++j) { | ||
field = fields[j]; | ||
res = resolved[field.field] || (resolved[field.field] = {}); | ||
if (fields && values) { | ||
// Intentional selection stores | ||
for (j = 0, m = fields.length; j < m; ++j) { | ||
field = fields[j]; | ||
res = resolved[field.field] || (resolved[field.field] = {}); | ||
resUnit = res[unit] || (res[unit] = []); | ||
types[field.field] = type = field.type.charAt(0); | ||
union = ops[`${type}_union`]; | ||
res[unit] = union(resUnit, vegaUtil.array(values[j])); | ||
} // If the same multi-selection is repeated over views and projected over | ||
// an encoding, it may operate over different fields making it especially | ||
// tricky to reliably resolve it. At best, we can de-dupe identical entries | ||
// but doing so may be more computationally expensive than it is worth. | ||
// Instead, for now, we simply transform our store representation into | ||
// a more human-friendly one. | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push(vegaUtil.array(values).reduce((obj, curr, j) => (obj[fields[j].field] = curr, obj), {})); | ||
} | ||
} else { | ||
// Short circuit extensional selectionId stores which hold sorted IDs unique to each unit. | ||
field = SelectionId; | ||
value = $selectionId(entry); | ||
res = resolved[field] || (resolved[field] = {}); | ||
resUnit = res[unit] || (res[unit] = []); | ||
types[field.field] = type = field.type.charAt(0); | ||
union = ops[type + '_union']; | ||
res[unit] = union(resUnit, vegaUtil.array(values[j])); | ||
} // If the same multi-selection is repeated over views and projected over | ||
// an encoding, it may operate over different fields making it especially | ||
// tricky to reliably resolve it. At best, we can de-dupe identical entries | ||
// but doing so may be more computationally expensive than it is worth. | ||
// Instead, for now, we simply transform our store representation into | ||
// a more human-friendly one. | ||
resUnit.push(value); | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push(vegaUtil.array(values).reduce((obj, curr, j) => (obj[fields[j].field] = curr, obj), {})); | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push({ | ||
[SelectionId]: value | ||
}); | ||
} | ||
} | ||
@@ -284,5 +404,11 @@ } // Then resolve fields across units as per the op. | ||
op = op || Union; | ||
Object.keys(resolved).forEach(field => { | ||
resolved[field] = Object.keys(resolved[field]).map(unit => resolved[field][unit]).reduce((acc, curr) => acc === undefined ? curr : ops[types[field] + '_' + op](acc, curr)); | ||
}); | ||
if (resolved[SelectionId]) { | ||
resolved[SelectionId] = ops[`${SelectionId}_${op}`](...Object.values(resolved[SelectionId])); | ||
} else { | ||
Object.keys(resolved).forEach(field => { | ||
resolved[field] = Object.keys(resolved[field]).map(unit => resolved[field][unit]).reduce((acc, curr) => acc === undefined ? curr : ops[`${types[field]}_${op}`](acc, curr)); | ||
}); | ||
} | ||
entries = Object.keys(multiRes); | ||
@@ -304,2 +430,4 @@ | ||
var ops = { | ||
[`${SelectionId}_union`]: union, | ||
[`${SelectionId}_intersect`]: intersection, | ||
E_union: function (base, value) { | ||
@@ -381,2 +509,2 @@ if (!base.length) return value; | ||
}))); | ||
})); |
@@ -1,2 +0,2 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vega-util"),require("vega-expression")):"function"==typeof define&&define.amd?define(["exports","vega-util","vega-expression"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).vega={},e.vega,e.vega)}(this,(function(e,t,n){"use strict";const r="intersect",i="union",u="index:unit";function l(e,n){for(var r,i,u=n.fields,l=n.values,o=u.length,f=0;f<o;++f)if((i=u[f]).getter=t.field.getter||t.field(i.field),r=i.getter(e),t.isDate(r)&&(r=t.toNumber(r)),t.isDate(l[f])&&(l[f]=t.toNumber(l[f])),t.isDate(l[f][0])&&(l[f]=l[f].map(t.toNumber)),"E"===i.type){if(t.isArray(l[f])?l[f].indexOf(r)<0:r!==l[f])return!1}else if("R"===i.type){if(!t.inrange(r,l[f]))return!1}else if("R-RE"===i.type){if(!t.inrange(r,l[f],!0,!1))return!1}else if("R-E"===i.type){if(!t.inrange(r,l[f],!1,!1))return!1}else if("R-LE"===i.type&&!t.inrange(r,l[f],!1,!0))return!1;return!0}const o=t.field("_vgsid_"),f=function(e){let t=e,n=e;function r(e,t,r,i){for(null==r&&(r=0),null==i&&(i=e.length);r<i;){const u=r+i>>>1;n(e[u],t)<0?r=u+1:i=u}return r}return 1===e.length&&(t=(t,n)=>e(t)-n,n=function(e){return(t,n)=>{return(r=e(t))<(i=n)?-1:r>i?1:r>=i?0:NaN;var r,i}}(e)),{left:r,center:function(e,n,i,u){null==i&&(i=0),null==u&&(u=e.length);const l=r(e,n,i,u-1);return l>i&&t(e[l-1],n)>-t(e[l],n)?l-1:l},right:function(e,t,r,i){for(null==r&&(r=0),null==i&&(i=e.length);r<i;){const u=r+i>>>1;n(e[u],t)>0?i=u:r=u+1}return r}}}(o),s=f.left,a=f.right;var c={E_union:function(e,t){if(!e.length)return t;for(var n=0,r=t.length;n<r;++n)e.indexOf(t[n])<0&&e.push(t[n]);return e},E_intersect:function(e,t){return e.length?e.filter((e=>t.indexOf(e)>=0)):t},R_union:function(e,n){var r=t.toNumber(n[0]),i=t.toNumber(n[1]);return r>i&&(r=n[1],i=n[0]),e.length?(e[0]>r&&(e[0]=r),e[1]<i&&(e[1]=i),e):[r,i]},R_intersect:function(e,n){var r=t.toNumber(n[0]),i=t.toNumber(n[1]);return r>i&&(r=n[1],i=n[0]),e.length?i<e[0]||e[1]<r?[]:(e[0]<r&&(e[0]=r),e[1]>i&&(e[1]=i),e):[r,i]}};e.selectionIdTest=function(e,t,n){const i=this.context.data[e],l=i?i.values.value:[],f=i?i[u]&&i[u].value:void 0,c=n===r,d=o(t),g=s(l,d);if(g===l.length)return!1;if(o(l[g])!==d)return!1;if(f&&c){if(1===f.size)return!0;if(a(l,d)-g<f.size)return!1}return!0},e.selectionResolve=function(e,n,r,u){for(var l,o,f,s,a,d,g,v,h,p,y,m=this.context.data[e],b=m?m.values.value:[],x={},R={},_={},N=b.length,O=0;O<N;++O){for(s=(l=b[O]).unit,o=l.fields,f=l.values,p=0,y=o.length;p<y;++p)a=o[p],g=(d=x[a.field]||(x[a.field]={}))[s]||(d[s]=[]),_[a.field]=v=a.type.charAt(0),h=c[v+"_union"],d[s]=h(g,t.array(f[p]));r&&(g=R[s]||(R[s]=[])).push(t.array(f).reduce(((e,t,n)=>(e[o[n].field]=t,e)),{}))}if(n=n||i,Object.keys(x).forEach((e=>{x[e]=Object.keys(x[e]).map((t=>x[e][t])).reduce(((t,r)=>void 0===t?r:c[_[e]+"_"+n](t,r)))})),b=Object.keys(R),r&&b.length){x[u?"vlPoint":"vlMulti"]=n===i?{or:b.reduce(((e,t)=>(e.push(...R[t]),e)),[])}:{and:b.map((e=>({or:R[e]})))}}return x},e.selectionTest=function(e,t,n){for(var i,o,f,s,a,c=this.context.data[e],d=c?c.values.value:[],g=c?c[u]&&c[u].value:void 0,v=n===r,h=d.length,p=0;p<h;++p)if(i=d[p],g&&v){if(-1===(f=(o=o||{})[s=i.unit]||0))continue;if(a=l(t,i),o[s]=a?-1:++f,a&&1===g.size)return!0;if(!a&&f===g.get(s).count)return!1}else if(v^(a=l(t,i)))return a;return h&&v},e.selectionTuples=function(e,n){return e.map((e=>t.extend({values:n.fields.map((n=>(n.getter||(n.getter=t.field(n.field)))(e.datum)))},n)))},e.selectionVisitor=function(e,i,u,l){i[0].type!==n.Literal&&t.error("First argument to selection functions must be a string literal.");const o=i[0].value,f="unit",s="@unit",a=":"+o;(i.length>=2&&t.peek(i).value)!==r||t.hasOwnProperty(l,s)||(l["@unit"]=u.getData(o).indataRef(u,f)),t.hasOwnProperty(l,a)||(l[a]=u.getData(o).tuplesRef())},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vega-util"),require("vega-expression")):"function"==typeof define&&define.amd?define(["exports","vega-util","vega-expression"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).vega={},e.vega,e.vega)}(this,(function(e,t,n){"use strict";function r(e,t){return null==e||null==t?NaN:e<t?-1:e>t?1:e>=t?0:NaN}class i extends Set{constructor(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:u;if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:t}}),null!=e)for(const t of e)this.add(t)}has(e){return super.has(function(e,t){let{_intern:n,_key:r}=e;const i=r(t);return n.has(i)?n.get(i):t}(this,e))}add(e){return super.add(function(e,t){let{_intern:n,_key:r}=e;const i=r(t);return n.has(i)?n.get(i):(n.set(i,t),t)}(this,e))}delete(e){return super.delete(function(e,t){let{_intern:n,_key:r}=e;const i=r(t);n.has(i)&&(t=n.get(i),n.delete(i));return t}(this,e))}}function u(e){return null!==e&&"object"==typeof e?e.valueOf():e}function o(e){return e instanceof i?e:new i(e)}const l="intersect",s="union",f="_vgsid_",a=t.field(f),c="index:unit";function d(e,n){for(var r,i,u=n.fields,o=n.values,l=u.length,s=0;s<l;++s)if((i=u[s]).getter=t.field.getter||t.field(i.field),r=i.getter(e),t.isDate(r)&&(r=t.toNumber(r)),t.isDate(o[s])&&(o[s]=t.toNumber(o[s])),t.isDate(o[s][0])&&(o[s]=o[s].map(t.toNumber)),"E"===i.type){if(t.isArray(o[s])?o[s].indexOf(r)<0:r!==o[s])return!1}else if("R"===i.type){if(!t.inrange(r,o[s]))return!1}else if("R-RE"===i.type){if(!t.inrange(r,o[s],!0,!1))return!1}else if("R-E"===i.type){if(!t.inrange(r,o[s],!1,!1))return!1}else if("R-LE"===i.type&&!t.inrange(r,o[s],!1,!0))return!1;return!0}const g=function(e){let t=e,n=e,i=e;function u(e,t){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,u=arguments.length>3&&void 0!==arguments[3]?arguments[3]:e.length;if(r<u){if(0!==n(t,t))return u;do{const n=r+u>>>1;i(e[n],t)<0?r=n+1:u=n}while(r<u)}return r}return 2!==e.length&&(t=(t,n)=>e(t)-n,n=r,i=(t,n)=>r(e(t),n)),{left:u,center:function(e,n){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:e.length;const o=u(e,n,r,i-1);return o>r&&t(e[o-1],n)>-t(e[o],n)?o-1:o},right:function(e,t){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,u=arguments.length>3&&void 0!==arguments[3]?arguments[3]:e.length;if(r<u){if(0!==n(t,t))return u;do{const n=r+u>>>1;i(e[n],t)<=0?r=n+1:u=n}while(r<u)}return r}}}(a),h=g.left,v=g.right;var p={["".concat(f,"_union")]:function(){const e=new i;for(var t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];for(const t of n)for(const n of t)e.add(n);return e},["".concat(f,"_intersect")]:function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];e=new i(e),n=n.map(o);e:for(const t of e)for(const r of n)if(!r.has(t)){e.delete(t);continue e}return e},E_union:function(e,t){if(!e.length)return t;for(var n=0,r=t.length;n<r;++n)e.indexOf(t[n])<0&&e.push(t[n]);return e},E_intersect:function(e,t){return e.length?e.filter((e=>t.indexOf(e)>=0)):t},R_union:function(e,n){var r=t.toNumber(n[0]),i=t.toNumber(n[1]);return r>i&&(r=n[1],i=n[0]),e.length?(e[0]>r&&(e[0]=r),e[1]<i&&(e[1]=i),e):[r,i]},R_intersect:function(e,n){var r=t.toNumber(n[0]),i=t.toNumber(n[1]);return r>i&&(r=n[1],i=n[0]),e.length?i<e[0]||e[1]<r?[]:(e[0]<r&&(e[0]=r),e[1]>i&&(e[1]=i),e):[r,i]}};e.selectionIdTest=function(e,t,n){const r=this.context.data[e],i=r?r.values.value:[],u=r?r[c]&&r[c].value:void 0,o=n===l,s=a(t),f=h(i,s);if(f===i.length)return!1;if(a(i[f])!==s)return!1;if(u&&o){if(1===u.size)return!0;if(v(i,s)-f<u.size)return!1}return!0},e.selectionResolve=function(e,n,r,i){for(var u,o,l,c,d,g,h,v,y,_,m,b,x=this.context.data[e],O=x?x.values.value:[],N={},w={},R={},j=O.length,k=0;k<j;++k)if(c=(u=O[k]).unit,o=u.fields,l=u.values,o&&l){for(m=0,b=o.length;m<b;++m)d=o[m],v=(h=N[d.field]||(N[d.field]={}))[c]||(h[c]=[]),R[d.field]=y=d.type.charAt(0),_=p["".concat(y,"_union")],h[c]=_(v,t.array(l[m]));r&&(v=w[c]||(w[c]=[])).push(t.array(l).reduce(((e,t,n)=>(e[o[n].field]=t,e)),{}))}else d=f,g=a(u),(v=(h=N[d]||(N[d]={}))[c]||(h[c]=[])).push(g),r&&(v=w[c]||(w[c]=[])).push({[f]:g});if(n=n||s,N._vgsid_?N._vgsid_=p["".concat(f,"_").concat(n)](...Object.values(N._vgsid_)):Object.keys(N).forEach((e=>{N[e]=Object.keys(N[e]).map((t=>N[e][t])).reduce(((t,r)=>void 0===t?r:p["".concat(R[e],"_").concat(n)](t,r)))})),O=Object.keys(w),r&&O.length){N[i?"vlPoint":"vlMulti"]=n===s?{or:O.reduce(((e,t)=>(e.push(...w[t]),e)),[])}:{and:O.map((e=>({or:w[e]})))}}return N},e.selectionTest=function(e,t,n){for(var r,i,u,o,s,f=this.context.data[e],a=f?f.values.value:[],g=f?f[c]&&f[c].value:void 0,h=n===l,v=a.length,p=0;p<v;++p)if(r=a[p],g&&h){if(-1===(u=(i=i||{})[o=r.unit]||0))continue;if(s=d(t,r),i[o]=s?-1:++u,s&&1===g.size)return!0;if(!s&&u===g.get(o).count)return!1}else if(h^(s=d(t,r)))return s;return v&&h},e.selectionTuples=function(e,n){return e.map((e=>t.extend(n.fields?{values:n.fields.map((n=>(n.getter||(n.getter=t.field(n.field)))(e.datum)))}:{[f]:a(e.datum)},n)))},e.selectionVisitor=function(e,r,i,u){r[0].type!==n.Literal&&t.error("First argument to selection functions must be a string literal.");const o=r[0].value,s="unit",f="@unit",a=":"+o;(r.length>=2&&t.peek(r).value)!==l||t.hasOwnProperty(u,f)||(u["@unit"]=i.getData(o).indataRef(i,s)),t.hasOwnProperty(u,a)||(u[a]=i.getData(o).tuplesRef())},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=vega-selection.min.js.map |
@@ -0,60 +1,5 @@ | ||
import { bisector, union, intersection } from 'd3-array'; | ||
import { field, isDate, toNumber, isArray, inrange, extend, array, error, peek, hasOwnProperty } from 'vega-util'; | ||
import { Literal } from 'vega-expression'; | ||
function ascending (a, b) { | ||
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; | ||
} | ||
function bisector (f) { | ||
let delta = f; | ||
let compare = f; | ||
if (f.length === 1) { | ||
delta = (d, x) => f(d) - x; | ||
compare = ascendingComparator(f); | ||
} | ||
function left(a, x, lo, hi) { | ||
if (lo == null) lo = 0; | ||
if (hi == null) hi = a.length; | ||
while (lo < hi) { | ||
const mid = lo + hi >>> 1; | ||
if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid; | ||
} | ||
return lo; | ||
} | ||
function right(a, x, lo, hi) { | ||
if (lo == null) lo = 0; | ||
if (hi == null) hi = a.length; | ||
while (lo < hi) { | ||
const mid = lo + hi >>> 1; | ||
if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1; | ||
} | ||
return lo; | ||
} | ||
function center(a, x, lo, hi) { | ||
if (lo == null) lo = 0; | ||
if (hi == null) hi = a.length; | ||
const i = left(a, x, lo, hi - 1); | ||
return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i; | ||
} | ||
return { | ||
left, | ||
center, | ||
right | ||
}; | ||
} | ||
function ascendingComparator(f) { | ||
return (d, x) => ascending(f(d), x); | ||
} | ||
const Intersect = 'intersect'; | ||
@@ -66,5 +11,6 @@ const Union = 'union'; | ||
const And = 'and'; | ||
const SelectionId = '_vgsid_'; | ||
const $selectionId = field(SelectionId); | ||
const SELECTION_ID = '_vgsid_', | ||
TYPE_ENUM = 'E', | ||
const TYPE_ENUM = 'E', | ||
TYPE_RANGE_INC = 'R', | ||
@@ -172,4 +118,3 @@ TYPE_RANGE_EXC = 'R-E', | ||
} | ||
const selectionId = field(SELECTION_ID), | ||
bisect = bisector(selectionId), | ||
const bisect = bisector($selectionId), | ||
bisectLeft = bisect.left, | ||
@@ -182,6 +127,6 @@ bisectRight = bisect.right; | ||
intersect = op === Intersect, | ||
value = selectionId(datum), | ||
value = $selectionId(datum), | ||
index = bisectLeft(entries, value); | ||
if (index === entries.length) return false; | ||
if (selectionId(entries[index]) !== value) return false; | ||
if ($selectionId(entries[index]) !== value) return false; | ||
@@ -199,3 +144,3 @@ if (unitIdx && intersect) { | ||
* @param {string} name - The name of the dataset representing the selection. | ||
* @param {string} unit - The name of the unit view. | ||
* @param {string} base - The base object that generated tuples extend. | ||
* | ||
@@ -206,4 +151,6 @@ * @returns {array} An array of selection entries for the given unit. | ||
function selectionTuples(array, base) { | ||
return array.map(x => extend({ | ||
return array.map(x => extend(base.fields ? { | ||
values: base.fields.map(f => (f.getter || (f.getter = field(f.field)))(x.datum)) | ||
} : { | ||
[SelectionId]: $selectionId(x.datum) | ||
}, base)); | ||
@@ -237,2 +184,3 @@ } | ||
field, | ||
value, | ||
res, | ||
@@ -253,20 +201,37 @@ resUnit, | ||
for (j = 0, m = fields.length; j < m; ++j) { | ||
field = fields[j]; | ||
res = resolved[field.field] || (resolved[field.field] = {}); | ||
if (fields && values) { | ||
// Intentional selection stores | ||
for (j = 0, m = fields.length; j < m; ++j) { | ||
field = fields[j]; | ||
res = resolved[field.field] || (resolved[field.field] = {}); | ||
resUnit = res[unit] || (res[unit] = []); | ||
types[field.field] = type = field.type.charAt(0); | ||
union = ops["".concat(type, "_union")]; | ||
res[unit] = union(resUnit, array(values[j])); | ||
} // If the same multi-selection is repeated over views and projected over | ||
// an encoding, it may operate over different fields making it especially | ||
// tricky to reliably resolve it. At best, we can de-dupe identical entries | ||
// but doing so may be more computationally expensive than it is worth. | ||
// Instead, for now, we simply transform our store representation into | ||
// a more human-friendly one. | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push(array(values).reduce((obj, curr, j) => (obj[fields[j].field] = curr, obj), {})); | ||
} | ||
} else { | ||
// Short circuit extensional selectionId stores which hold sorted IDs unique to each unit. | ||
field = SelectionId; | ||
value = $selectionId(entry); | ||
res = resolved[field] || (resolved[field] = {}); | ||
resUnit = res[unit] || (res[unit] = []); | ||
types[field.field] = type = field.type.charAt(0); | ||
union = ops[type + '_union']; | ||
res[unit] = union(resUnit, array(values[j])); | ||
} // If the same multi-selection is repeated over views and projected over | ||
// an encoding, it may operate over different fields making it especially | ||
// tricky to reliably resolve it. At best, we can de-dupe identical entries | ||
// but doing so may be more computationally expensive than it is worth. | ||
// Instead, for now, we simply transform our store representation into | ||
// a more human-friendly one. | ||
resUnit.push(value); | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push(array(values).reduce((obj, curr, j) => (obj[fields[j].field] = curr, obj), {})); | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push({ | ||
[SelectionId]: value | ||
}); | ||
} | ||
} | ||
@@ -277,5 +242,11 @@ } // Then resolve fields across units as per the op. | ||
op = op || Union; | ||
Object.keys(resolved).forEach(field => { | ||
resolved[field] = Object.keys(resolved[field]).map(unit => resolved[field][unit]).reduce((acc, curr) => acc === undefined ? curr : ops[types[field] + '_' + op](acc, curr)); | ||
}); | ||
if (resolved[SelectionId]) { | ||
resolved[SelectionId] = ops["".concat(SelectionId, "_").concat(op)](...Object.values(resolved[SelectionId])); | ||
} else { | ||
Object.keys(resolved).forEach(field => { | ||
resolved[field] = Object.keys(resolved[field]).map(unit => resolved[field][unit]).reduce((acc, curr) => acc === undefined ? curr : ops["".concat(types[field], "_").concat(op)](acc, curr)); | ||
}); | ||
} | ||
entries = Object.keys(multiRes); | ||
@@ -297,2 +268,4 @@ | ||
var ops = { | ||
["".concat(SelectionId, "_union")]: union, | ||
["".concat(SelectionId, "_intersect")]: intersection, | ||
E_union: function (base, value) { | ||
@@ -299,0 +272,0 @@ if (!base.length) return value; |
{ | ||
"name": "vega-selections", | ||
"version": "5.3.1", | ||
"version": "5.4.0", | ||
"description": "Vega expression functions for Vega-Lite selections.", | ||
@@ -24,6 +24,7 @@ "keywords": [ | ||
"dependencies": { | ||
"d3-array": "3.1.1", | ||
"vega-expression": "^5.0.0", | ||
"vega-util": "^1.16.0" | ||
}, | ||
"gitHead": "774165e29850b66ec8b79ba52a7955f1ab936ea6" | ||
"gitHead": "9a3faca4395cade9ecdfde90af98f1c53e9916b2" | ||
} |
@@ -0,1 +1,3 @@ | ||
import {field} from 'vega-util'; | ||
export const Intersect = 'intersect'; | ||
@@ -7,1 +9,4 @@ export const Union = 'union'; | ||
export const And = 'and'; | ||
export const SelectionId = '_vgsid_'; | ||
export const $selectionId = field(SelectionId); |
@@ -1,3 +0,4 @@ | ||
import {And, Or, Union, VlMulti, VlPoint} from './constants'; | ||
import {intersection, union} from 'd3-array'; | ||
import {array, toNumber} from 'vega-util'; | ||
import {$selectionId, And, Or, SelectionId, Union, VlMulti, VlPoint} from './constants'; | ||
@@ -21,3 +22,3 @@ /** | ||
resolved = {}, multiRes = {}, types = {}, | ||
entry, fields, values, unit, field, res, resUnit, type, union, | ||
entry, fields, values, unit, field, value, res, resUnit, type, union, | ||
n = entries.length, i = 0, j, m; | ||
@@ -32,20 +33,33 @@ | ||
for (j = 0, m = fields.length; j < m; ++j) { | ||
field = fields[j]; | ||
res = resolved[field.field] || (resolved[field.field] = {}); | ||
if (fields && values) { // Intentional selection stores | ||
for (j = 0, m = fields.length; j < m; ++j) { | ||
field = fields[j]; | ||
res = resolved[field.field] || (resolved[field.field] = {}); | ||
resUnit = res[unit] || (res[unit] = []); | ||
types[field.field] = type = field.type.charAt(0); | ||
union = ops[`${type}_union`]; | ||
res[unit] = union(resUnit, array(values[j])); | ||
} | ||
// If the same multi-selection is repeated over views and projected over | ||
// an encoding, it may operate over different fields making it especially | ||
// tricky to reliably resolve it. At best, we can de-dupe identical entries | ||
// but doing so may be more computationally expensive than it is worth. | ||
// Instead, for now, we simply transform our store representation into | ||
// a more human-friendly one. | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push(array(values).reduce((obj, curr, j) => (obj[fields[j].field] = curr, obj), {})); | ||
} | ||
} else { // Short circuit extensional selectionId stores which hold sorted IDs unique to each unit. | ||
field = SelectionId; | ||
value = $selectionId(entry); | ||
res = resolved[field] || (resolved[field] = {}); | ||
resUnit = res[unit] || (res[unit] = []); | ||
types[field.field] = type = field.type.charAt(0); | ||
union = ops[type + '_union']; | ||
res[unit] = union(resUnit, array(values[j])); | ||
} | ||
resUnit.push(value); | ||
// If the same multi-selection is repeated over views and projected over | ||
// an encoding, it may operate over different fields making it especially | ||
// tricky to reliably resolve it. At best, we can de-dupe identical entries | ||
// but doing so may be more computationally expensive than it is worth. | ||
// Instead, for now, we simply transform our store representation into | ||
// a more human-friendly one. | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push(array(values).reduce((obj, curr, j) => (obj[fields[j].field] = curr, obj), {})); | ||
if (isMulti) { | ||
resUnit = multiRes[unit] || (multiRes[unit] = []); | ||
resUnit.push({[SelectionId]: value}); | ||
} | ||
} | ||
@@ -56,7 +70,11 @@ } | ||
op = op || Union; | ||
Object.keys(resolved).forEach(field => { | ||
resolved[field] = Object.keys(resolved[field]) | ||
.map(unit => resolved[field][unit]) | ||
.reduce((acc, curr) => acc === undefined ? curr : ops[types[field] + '_' + op](acc, curr)); | ||
}); | ||
if (resolved[SelectionId]) { | ||
resolved[SelectionId] = ops[`${SelectionId}_${op}`](...Object.values(resolved[SelectionId])); | ||
} else { | ||
Object.keys(resolved).forEach(field => { | ||
resolved[field] = Object.keys(resolved[field]) | ||
.map(unit => resolved[field][unit]) | ||
.reduce((acc, curr) => acc === undefined ? curr : ops[`${types[field]}_${op}`](acc, curr)); | ||
}); | ||
} | ||
@@ -75,2 +93,5 @@ entries = Object.keys(multiRes); | ||
var ops = { | ||
[`${SelectionId}_union`]: union, | ||
[`${SelectionId}_intersect`]: intersection, | ||
E_union: function(base, value) { | ||
@@ -77,0 +98,0 @@ if (!base.length) return value; |
import {bisector} from 'd3-array'; | ||
import {Intersect} from './constants'; | ||
import {$selectionId, Intersect} from './constants'; | ||
import {field, inrange, isArray, isDate, toNumber} from 'vega-util'; | ||
const SELECTION_ID = '_vgsid_', | ||
TYPE_ENUM = 'E', | ||
const TYPE_ENUM = 'E', | ||
TYPE_RANGE_INC = 'R', | ||
@@ -108,4 +107,3 @@ TYPE_RANGE_EXC = 'R-E', | ||
const selectionId = field(SELECTION_ID), | ||
bisect = bisector(selectionId), | ||
const bisect = bisector($selectionId), | ||
bisectLeft = bisect.left, | ||
@@ -119,7 +117,7 @@ bisectRight = bisect.right; | ||
intersect = op === Intersect, | ||
value = selectionId(datum), | ||
value = $selectionId(datum), | ||
index = bisectLeft(entries, value); | ||
if (index === entries.length) return false; | ||
if (selectionId(entries[index]) !== value) return false; | ||
if ($selectionId(entries[index]) !== value) return false; | ||
@@ -126,0 +124,0 @@ if (unitIdx && intersect) { |
import {extend, field} from 'vega-util'; | ||
import {$selectionId, SelectionId} from './constants'; | ||
@@ -6,3 +7,3 @@ /** | ||
* @param {string} name - The name of the dataset representing the selection. | ||
* @param {string} unit - The name of the unit view. | ||
* @param {string} base - The base object that generated tuples extend. | ||
* | ||
@@ -12,5 +13,8 @@ * @returns {array} An array of selection entries for the given unit. | ||
export function selectionTuples(array, base) { | ||
return array.map(x => extend({ | ||
values: base.fields.map(f => (f.getter || (f.getter = field(f.field)))(x.datum)) | ||
}, base)); | ||
return array.map(x => extend( | ||
base.fields ? { | ||
values: base.fields.map(f => (f.getter || (f.getter = field(f.field)))(x.datum)) | ||
} : { | ||
[SelectionId]: $selectionId(x.datum) | ||
}, base)); | ||
} |
@@ -26,2 +26,2 @@ import {Intersect} from './constants'; | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
70173
1000
3
+ Addedd3-array@3.1.1
+ Addedd3-array@3.1.1(transitive)
+ Addedinternmap@2.0.3(transitive)