@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 11.8 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.8/LICENSE.txt */
import{createUniqueColors as e}from"../../core/colorUtils.js";import i from"../../core/Error.js";import{clone as a}from"../../core/lang.js";import{fetchMessageBundle as n}from"../../intl/messages.js";import l from"../../renderers/support/AuthoringInfo.js";import r from"../../renderers/support/AuthoringInfoClassBreakInfo.js";import s from"../../renderers/support/AuthoringInfoFieldInfo.js";import o from"../heuristics/outline.js";import t from"../heuristics/sizeRange.js";import{createRenderer as d}from"./type.js";import{spliceVisualVariables as m,processRegenerateParams as u,getRendererToUpdate as f,getStyleType as p,hasOutlineVV as c,hasScaleDependentSizeVV as h,findOutlineVVIndex as y,findScaleDependentSizeVVIndex as w}from"./support/regenerateUtils.js";import{errorCallback as b,verifyBasicFieldValidity as v,getClassBreaks as g,getBasemapInfo as I}from"./support/utils.js";import{verifyBinningParams as z}from"../support/binningUtils.js";import{binningCapableLayerTypes as M,featureCapableLayerTypes as F,createLayerAdapter as V,getLayerTypeLabels as T}from"../support/adapters/support/layerUtils.js";import{getColors as k,cloneScheme as H,getSchemes as L,flatten2DArray as C}from"../symbology/relationship.js";import{applyColorToSymbol as E}from"../../symbols/support/utils.js";const B=new Set(["equal-interval","natural-breaks","quantile"]),x=new Set(["HH","HL","LH","LL"]),$={2:[["HL","HH"],["LL","LH"]],3:[["HL","HM","HH"],["ML","MM","MH"],["LL","LM","LH"]],4:[["HL","HM1","HM2","HH"],["M2L","M2M1","M2M2","M2H"],["M1L","M1M1","M1M2","M1H"],["LL","LM1","LM2","LH"]]},O={2:["L","H"],3:["L","M","H"],4:["L","M1","M2","H"]},S=e=>({minValue:e.minValue,maxValue:e.maxValue});async function j(e){if(!(e?.layer&&e.view&&e.field1&&e.field2))throw new i("relationship-renderer:missing-parameters","'layer', 'view', 'field1' and 'field2' parameters are required");e.forBinning&&z(e,"relationship-renderer");const a={...e,layer:e.layer,field1:e.field1,field2:e.field2};if(a.symbolType??="2d",a.defaultSymbolEnabled??=!0,a.classificationMethod??="quantile",a.numClasses??=3,a.focus??=null,!B.has(a.classificationMethod))throw new i("relationship-renderer:invalid-parameters",`classification method ${a.classificationMethod} is not supported`);if(a.numClasses<2||a.numClasses>4)throw new i("relationship-renderer:invalid-parameters","'numClasses' must be 2, 3 or 4");if(e.focus&&!x.has(e.focus))throw new i("relationship-renderer:invalid-parameters","'focus' must be 'HH', 'HL', 'LH', 'LL' or null");const n=e.forBinning?M:F,l=V(a.layer,n,e.forBinning);if(!l)throw new i("relationship-renderer:invalid-parameters","'layer' must be one of these types: "+T(n).join(", "));const r=null!=a.signal?{signal:a.signal}:null;await l.load(r);const s=l.geometryType,o=a.symbolType.includes("3d");a.outlineOptimizationEnabled="polygon"===s&&a.outlineOptimizationEnabled;const t="featureReduction"in e.layer&&"cluster"===e.layer.featureReduction?.type;if(a.sizeOptimizationEnabled=!("point"!==s&&"multipoint"!==s&&"polyline"!==s||t)&&a.sizeOptimizationEnabled,"mesh"===s)a.symbolType="3d-volumetric",a.colorMixMode=a.colorMixMode||"replace",a.edgesType=a.edgesType||"none";else{if("3d-volumetric-uniform"===a.symbolType&&"point"!==s)throw new i("relationship-renderer:not-supported","3d-volumetric-uniform symbols are supported for point layers only");if(o&&"polygon"===s)throw new i("relationship-renderer:not-supported","3d symbols are not supported for polygon layers");if(a.symbolType.includes("3d-volumetric")&&"3d"!==a.view?.type)throw new i("relationship-renderer:invalid-parameters","'view' parameter should be an instance of SceneView when 'symbolType' parameter is '3d-volumetric' or '3d-volumetric-uniform'")}const{field1:d,field2:m}=a,u=[d.field,m.field];d.normalizationField&&u.push(d.normalizationField),m.normalizationField&&u.push(m.normalizationField);const f=v(l,u,"relationship-renderer:invalid-parameters");if(f)throw f;return{...a,layer:l}}async function q(e){const a="regenerate-relationship-renderer";await u(e,a);const n=await f(e),l=p(n);if(!l||!["relationship","relationship-size"].includes(l))throw new i(`${a}:invalid-parameters`,"Renderer is invalid");const{layer:r,forBinning:s,filter:o,view:t,signal:d}=e,m=c(n),y=h(n),{field1:w,field2:b,classificationMethod:v,focus:g,numClasses:I}=n.authoringInfo,z={field:w.field,normalizationField:w.normalizationField,label:w.label},M={field:b.field,normalizationField:b.normalizationField,label:b.label},F=await j({layer:r,field1:z,field2:M,classificationMethod:v,numClasses:I,focus:g,outlineOptimizationEnabled:m,sizeOptimizationEnabled:y,forBinning:s,filter:o,view:t,signal:d});return{...e,creatorParameters:F,renderer:n}}async function N(e){if(!e?.renderer||!e.numClasses)throw new i("update-relationship-renderer:missing-parameters","'renderer' and 'numClasses' parameters are required");const{field1:a,field2:n,renderer:l,numClasses:r,colors:s}=e,o=r**2;if((a||n)&&!(a&&n&&a.field&&n.field))throw new i("update-relationship-renderer:missing-parameters","'field1' and 'field2' parameters are required");if(a&&!a.classBreakInfos||n&&!n.classBreakInfos)throw new i("update-relationship-renderer:missing-parameters","'field1.classBreakInfos' and 'field2.classBreakInfos' are required");if(!l.authoringInfo)throw new i("update-relationship-renderer:missing-parameters","'renderer.authoringInfo' is required");if(l.uniqueValueInfos?.length!==o)throw new i("update-relationship-renderer:invalid-parameters",`Renderer must have ${o} unique value infos to support ${r} classes`);if(s&&s.length!==o)throw new i("update-relationship-renderer:invalid-parameters",`The scheme must have ${o} colors`);return e}async function R(e){let i=e.relationshipScheme,a=null,n=null;const l=await I(e.basemap,e.view);if(a=null!=l.basemapId?l.basemapId:null,n=null!=l.basemapTheme?l.basemapTheme:null,i)return{scheme:H(i),basemapId:a,basemapTheme:n};const r=L({basemapTheme:n,geometryType:e.geometryType,theme:e.theme,worldScale:e.worldScale,view:e.view});return r&&(i=r.primaryScheme,a=r.basemapId,n=r.basemapTheme),{scheme:i,basemapId:a,basemapTheme:n}}function P(e,i){const n=a($[e]);return C(n,i)}function U(e,i){return P(e,i).map(e=>({value:e,count:0}))}function A(e,i,a,n){const{field:l,normalizationField:r}=e,{field:s,normalizationField:o}=i,t=a.map(e=>[e.minValue,e.maxValue]),d=n.map(e=>[e.minValue,e.maxValue]),m=t.length,u=O[m];return`\n var field1 = $feature['${l}'];\n var field2 = $feature['${s}'];\n var hasNormField1 = ${r?"true":"false"};\n var hasNormField2 = ${o?"true":"false"};\n var normField1 = ${r?`$feature['${r}']`:"null"};\n var normField2 = ${o?`$feature['${o}']`:"null"};\n\n if (\n IsEmpty(field1) ||\n IsEmpty(field2) ||\n (hasNormField1 && (IsEmpty(normField1) || normField1 == 0)) ||\n (hasNormField2 && (IsEmpty(normField2) || normField2 == 0))\n ) {\n return null;\n }\n\n var value1 = IIf(hasNormField1, (field1 / normField1), field1);\n var value2 = IIf(hasNormField2, (field2 / normField2), field2);\n\n var breaks1 = ${JSON.stringify(t)};\n var breaks2 = ${JSON.stringify(d)};\n var classCodes = ${JSON.stringify(u)};\n\n function getClassCode(value, breaks) {\n var code = null;\n\n for (var i in breaks) {\n var info = breaks[i];\n if (value >= info[0] && value <= info[1]) {\n code = classCodes[i];\n break;\n }\n }\n\n return code;\n }\n\n var code1 = getClassCode(value1, breaks1);\n var code2 = getClassCode(value2, breaks2);\n\n var classValue = IIf(IsEmpty(code1) || IsEmpty(code2), null, code1 + code2);\n return classValue;\n `}async function J(e,a,o){const t=await n("esri/smartMapping/t9n/smartMapping"),{basemap:m,classificationMethod:u,field1:f,field2:p,focus:c,numClasses:h,signal:y}=e,w=e.layer,b=a.classBreakInfos,v=o.classBreakInfos;if(h!==b.length||b.length!==v.length)throw new i("relationship-renderer:error","incompatible class breaks");const g=U(h,c),I=A(e.field1,e.field2,b,v),z=(await R({basemap:m,geometryType:w.geometryType,theme:"default",relationshipScheme:e.relationshipScheme,worldScale:!!e.symbolType?.includes("3d-volumetric"),view:e.view})).scheme,M=await d({layer:w,basemap:m,valueExpression:I,valueExpressionTitle:t.relationship.legendTitle,numTypes:-1,sortEnabled:!1,defaultSymbolEnabled:e.defaultSymbolEnabled,typeScheme:{colors:k(z,h,c),...z},statistics:{uniqueValueInfos:g},legendOptions:e.legendOptions,outlineOptimizationEnabled:e.outlineOptimizationEnabled,sizeOptimizationEnabled:e.sizeOptimizationEnabled,symbolType:e.symbolType,colorMixMode:e.colorMixMode,edgesType:e.edgesType,filter:e.filter,view:e.view,signal:y}),F=M.renderer,V=F.uniqueValueInfos,T=t.relationship;for(const i of V??[])i.label=T[i.value];const H=new l({type:"relationship",classificationMethod:u,numClasses:h,focus:c,field1:new s({field:f.field,normalizationField:f.normalizationField,label:f.label,classBreakInfos:b.map(({minValue:e,maxValue:i})=>new r({minValue:e,maxValue:i}))}),field2:new s({field:p.field,normalizationField:p.normalizationField,label:p.label,classBreakInfos:v.map(({minValue:e,maxValue:i})=>new r({minValue:e,maxValue:i}))})});return F.authoringInfo=H,{renderer:F,classBreaks:{field1:a,field2:o},uniqueValueInfos:M.uniqueValueInfos,relationshipScheme:z,basemapId:M.basemapId,basemapTheme:M.basemapTheme}}function D(e,i,a){const n=P(i,a);e.sort((e,i)=>{const a=n.indexOf(e.value),l=n.indexOf(i.value);let r=0;return a<l?r=-1:a>l&&(r=1),r})}function G(e,i){e.authoringInfo??=new l;const a=e.authoringInfo;a.numClasses=i.numClasses,a.focus=i.focus||null,a.focus||delete a.focus;const{field1:n,field2:o}=i;a.field1=new s({field:n.field,normalizationField:n.normalizationField,label:n.label,classBreakInfos:n.classBreakInfos.map(e=>new r(S(e)))}),a.field2=new s({field:o.field,normalizationField:o.normalizationField,label:o.label,classBreakInfos:o.classBreakInfos.map(e=>new r(S(e)))}),e.authoringInfo=a}async function K(e){const{layer:a,classificationMethod:n,field1:l,field2:r,numClasses:s,filter:o,view:t,signal:d}=e,m={layer:a,classificationMethod:n,field:l.field,normalizationField:l.normalizationField,normalizationType:l.normalizationField?"field":null,minValue:l.minValue,maxValue:l.maxValue,analyzeData:!(null!=l.minValue&&null!=l.maxValue),numClasses:s,filter:o,view:t,signal:d},u={layer:a,classificationMethod:n,field:r.field,normalizationField:r.normalizationField,normalizationType:r.normalizationField?"field":null,minValue:r.minValue,maxValue:r.maxValue,analyzeData:!(null!=r.minValue&&null!=r.maxValue),numClasses:s,filter:o,view:t,signal:d},[f,p]=await Promise.all([g(m),g(u)]);if(!f||!p)throw new i("relationship-renderer:error","error when calculating class breaks");return{field1:f.result,field2:p.result}}async function Q(i){const a=await N(i),{field1:n,field2:l,renderer:r,numClasses:s,focus:o,colors:t}=a,d=r.clone();d.valueExpression=A(n,l,n.classBreakInfos,l.classBreakInfos);const m=d.uniqueValueInfos??[];if(D(m,s,o),t){const i=e(t,t.length);m.forEach((e,a)=>E(e.symbol,i[a]))}return G(d,a),d}async function W(e){const i=await j(e),{field1:a,field2:n}=await K(i);return J(i,a,n)}async function X(e){const{creatorParameters:i,view:a,signal:n,filter:l,renderer:r}=await q(e),{layer:s,field1:d,field2:u,numClasses:f,focus:p,outlineOptimizationEnabled:c,sizeOptimizationEnabled:h}=i,{field1:v,field2:g}=await K(i),[I,z,M]=await Promise.all([Q({field1:{...d,classBreakInfos:v.classBreakInfos},field2:{...u,classBreakInfos:g.classBreakInfos},renderer:r,numClasses:f,focus:p}),c?o({layer:s,view:a,signal:n,filter:l}).catch(b):null,h?t({layer:s,view:a,signal:n,filter:l}).catch(b):null]);return m(I,z?.visualVariables,y),m(I,M?.minSize,w),{renderer:I}}export{W as createRenderer,X as regenerateRenderer,Q as updateRenderer};