@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 14.5 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.8/LICENSE.txt */
import{__decorate as e}from"tslib";import{JSONSupport as t}from"../../core/JSONSupport.js";import r from"../../core/Logger.js";import{property as s,subclass as a}from"../../core/accessorSupport/decorators.js";import{getPixelValueRange as o}from"../../layers/raster/formats/pixelRangeUtils.js";import{colorize as n,remapColor as i,lookupPixels as l,createColormapLUT as u,isValidPixelBlock as c}from"../../layers/raster/functions/pixelUtils.js";import{stretch as p,getStretchCutoff as d,isStandardU8Histogram as m,createStretchLUT as h,computeGammaValues as f,createHistogramEqualizationLUT as b}from"../../layers/raster/functions/stretchUtils.js";import{hillshade as g,tintHillshade as y,calculateHillshadeParams as x}from"../../layers/raster/functions/surfaceUtils.js";import S from"../../layers/support/RasterInfo.js";import{convertColorRampToColormap as R,createHsvMap as I}from"./colorRampUtils.js";import{isUVRendererSupported as C,isColormapSupportedByWebGL as k,isColormapRendererSupported as L,isShadedReliefRendererSupported as _}from"./rasterRendererChecks.js";let O=class extends t{constructor(e){super(e),this.lookup={rendererJSON:{}},this.canRenderInWebGL=!1}bind(){const{rendererJSON:e}=this;if(!e)return{success:!1};let t;switch(this.lookup={rendererJSON:{}},e.type){case"uniqueValue":t=this._updateUVRenderer(e);break;case"rasterColormap":t=this._updateColormapRenderer(e);break;case"rasterStretch":t=this._updateStretchRenderer(e);break;case"classBreaks":t=this._updateClassBreaksRenderer(e);break;case"rasterShadedRelief":t=this._updateShadedReliefRenderer(e);break;case"vectorField":t=this._updateVectorFieldRenderer();break;case"flowRenderer":t=this._updateFlowRenderer()}return t}symbolize(e){let t=e?.pixelBlock;if(!T(t))return t;if(e.simpleStretchParams&&"rasterStretch"===this.rendererJSON.type)return this.simpleStretch(t,e.simpleStretchParams);try{let r;switch(t.pixels.length>3&&(t=t.extractBands(e.bandIds??[0,1,2])),this.rendererJSON.type){case"uniqueValue":case"rasterColormap":r=this._symbolizeColormap(t);break;case"classBreaks":r=this._symbolizeClassBreaks(t);break;case"rasterStretch":r=this._symbolizeStretch(t,e.bandIds);break;case"rasterShadedRelief":{const s=e.extent,a=s.spatialReference.isGeographic,o={x:(s.xmax-s.xmin)/t.width,y:(s.ymax-s.ymin)/t.height};r=this._symbolizeShadedRelief(t,{isGCS:a,resolution:o});break}}return r}catch(s){return r.getLogger(this).error("symbolize",s.message),t}}simpleStretch(e,t){if(!T(e))return e;try{return e.pixels.length>3&&(e=e.extractBands([0,1,2])),p(e,{...t,isRenderer:!0})}catch(s){return r.getLogger(this).error("symbolize",s.message),e}}generateWebGLParameters(e){const{rendererJSON:t}=this;switch(t.type){case"uniqueValue":case"rasterColormap":case"classBreaks":return this._generateColormapWebGLParams("classBreaks"===t.type);case"rasterStretch":return this._generateStretchWebGLParams(e.pixelBlock,t,e.bandIds);case"rasterShadedRelief":return this._generateShadedReliefWebGLParams(t,e.isGCS,e.resolution??void 0);case"vectorField":return this._generateVectorFieldWebGLParams(t);default:return null}}_isLUTChanged(e){const t=this.lookup.rendererJSON;if(!t)return!0;const{rendererJSON:r}=this;if("colorRamp"in r&&r.colorRamp){const s=r.colorRamp;if(e)return JSON.stringify(s)!==JSON.stringify(t.colorRamp)}return JSON.stringify(r)!==JSON.stringify(t)}_symbolizeColormap(e){if(this._isLUTChanged()){if(!this.bind().success)return e}return n(e,this.lookup.colormapLut)}_symbolizeClassBreaks(e){const{canUseIndexedLUT:t}=this._analyzeClassBreaks(this.rendererJSON);if(this._isLUTChanged()){if(!this.bind().success)return e}return t?n(e,this.lookup.colormapLut):i(e,this.lookup.remapLut??[])}_symbolizeStretch(e,t){if(!e)return null;const{rasterInfo:r,lookup:s}=this,{pixelType:a,bandCount:o}=r,i=this.rendererJSON,u=["u8","u16","s8","s16"].includes(a);let c;const{dra:f}=i,{gamma:b}=s;if(f&&(t=null),"histogramEqualization"===i.stretchType){const a=f?null:s.histogramLut,o=d(i,{rasterInfo:r,pixelBlock:e,bandIds:t,returnHistogramLut:!a}),n="u8"===r.pixelType&&!f&&m(r.histograms?.[0])?e:p(e,{...o,gamma:b,isRenderer:!0});c=l(n,{lut:f?o.histogramLut:t?.length?t.map(e=>a[e]):a,offset:0})}else if(u){let n;if(f){const s=d(i,{rasterInfo:r,pixelBlock:e,bandIds:t});n=h({pixelType:a,...s,gamma:b,rounding:"floor"})}else{if(this._isLUTChanged()){if(!this.bind().success)return e}n=s.stretchLut}if(!n)return e;o>1&&null!=t&&t.length===e?.pixels.length&&n.lut.length===o&&(n={lut:t.map(e=>n.lut[e]),offset:n.offset}),c=l(e,n)}else{const s=d(i,{rasterInfo:r,pixelBlock:e,bandIds:t});c=p(e,{...s,gamma:b,isRenderer:!0})}if(i.colorRamp){if(this._isLUTChanged(!0)){if(!this.bind().success)return e}c=n(c,s.colormapLut)}return c}_symbolizeShadedRelief(e,t){const r=this.rendererJSON,s={...r,...t},a=g(e,s);if(!r.colorRamp)return a;if(this._isLUTChanged(!0)){if(!this.bind().success)return a}const{hsvMap:o}=this.lookup;if(!o)return a;const n=this.rasterInfo.statistics?.[0]??{min:0,max:8e3};return y(a,e,o,n),a}_isVectorFieldData(){const{bandCount:e,dataType:t}=this.rasterInfo;return 2===e&&("vector-magdir"===t||"vector-uv"===t)}_updateVectorFieldRenderer(){return this._isVectorFieldData()?{success:!0}:{success:!1,error:`Unsupported data type "${this.rasterInfo.dataType}"; VectorFieldRenderer only supports "vector-magdir" and "vector-uv".`}}_updateFlowRenderer(){return this._isVectorFieldData()?{success:!0}:{success:!1,error:`Unsupported data type "${this.rasterInfo.dataType}"; FlowRenderer only supports "vector-magdir" and "vector-uv".`}}_updateUVRenderer(e){const{bandCount:t,attributeTable:r,pixelType:s}=this.rasterInfo,a=e.field1;if(!a)return{success:!1,error:"Unsupported renderer; missing UniqueValueRenderer.field."};const o=e.defaultSymbol,n=1===t&&["u8","s8"].includes(s);if(!C(this.rasterInfo,a)&&!n)return{success:!1,error:"Unsupported data; UniqueValueRenderer is only supported on single band data with a valid raster attribute table."};const i=[];if(null!=r){const t=r.fields.find(e=>"value"===e.name.toLowerCase());if(!t)return{success:!1,error:"Unsupported data; the data's raster attribute table does not have a value field."};r.features.forEach(r=>{const s=e.uniqueValueInfos?.find(e=>String(e.value)===String(r.attributes[a])),n=s?.symbol?.color;n?i.push([r.attributes[t.name]].concat(n)):o&&i.push([r.attributes[t.name]].concat(o.color))})}else{if("value"!==a.toLowerCase())return{success:!1,error:'Unsupported renderer; UniqueValueRenderer.field must be "Value" when raster attribute table is not available.'};e.uniqueValueInfos?.forEach(e=>{const t=e?.symbol?.color;t?i.push([parseInt(""+e.value,10)].concat(t)):o&&i.push([parseInt(""+e.value,10)].concat(o?.color))})}if(0===i.length)return{success:!1,error:"Invalid UniqueValueRenderer. Cannot find matching records in the raster attribute table."};const l=u({colormap:i});return this.lookup={rendererJSON:e,colormapLut:l},this.canRenderInWebGL=k(l?.indexedColormap),{success:!0}}_updateColormapRenderer(e){if(!L(this.rasterInfo))return{success:!1,error:"Unsupported data; the data source does not have a colormap."};const t=e.colormapInfos.map(e=>[e.value].concat(e.color)).sort((e,t)=>e[0]-t[0]);if(!t||0===t.length)return{success:!1,error:"Unsupported renderer; ColormapRenderer must have meaningful colormapInfos."};const r=u({colormap:t});return this.lookup={rendererJSON:e,colormapLut:r},this.canRenderInWebGL=k(r?.indexedColormap),{success:!0}}_updateShadedReliefRenderer(e){if(!_(this.rasterInfo))return{success:!1,error:`Unsupported data type "${this.rasterInfo.dataType}"; ShadedReliefRenderer only supports "elevation", or single band float/s16 data.`};if(e.colorRamp){const t=R(e.colorRamp,{interpolateAlpha:!0}),r=u({colormap:t}),s=I(r.indexedColormap);this.lookup={rendererJSON:e,colormapLut:r,hsvMap:s}}else this.lookup={rendererJSON:e};return this.canRenderInWebGL=!0,{success:!0}}_analyzeClassBreaks(e){const{attributeTable:t,pixelType:r}=this.rasterInfo,s=t?.fields.find(e=>"value"===e.name.toLowerCase()),a=t?.fields.find(t=>t.name.toLowerCase()===e.field.toLowerCase()),o=null!=s&&null!==a;return{canUseIndexedLUT:["u8","u16","s8","s16"].includes(r)||o,tableValueField:s,tableBreakField:a}}_updateClassBreaksRenderer(e){const{attributeTable:t}=this.rasterInfo,{canUseIndexedLUT:r,tableValueField:s,tableBreakField:a}=this._analyzeClassBreaks(e),n=e.classBreakInfos;if(!n?.length)return{success:!1,error:"Unsupported renderer; missing or invalid ClassBreaksRenderer.classBreakInfos."};const i=n.sort((e,t)=>e.classMaxValue-t.classMaxValue),l=i[i.length-1];let c=e.minValue;if(!r){const t=[];for(let e=0;e<i.length;e++)t.push({value:i[e].classMinValue??c,mappedColor:i[e].symbol.color}),c=i[e].classMaxValue;return t.push({value:l.classMaxValue,mappedColor:l.symbol.color}),this.lookup={rendererJSON:e,remapLut:t},this.canRenderInWebGL=!1,{success:!0}}const p=[];if(null!=t&&null!=s&&null!==a&&s!==a){const r=s.name,o=a.name,n=i[i.length-1],{classMaxValue:l}=n;c=e.minValue;for(const e of t.features){const t=e.attributes[r],s=e.attributes[o],a=s===l?n:s<c?null:i.find(({classMaxValue:e})=>e>s);a&&p.push([t].concat(a.symbol.color))}}else{const[t,r]=o(this.rasterInfo.pixelType);c=Math.max(t,Math.floor(e.minValue));for(let e=0;e<i.length;e++){const t=i[e],s=Math.min(r,Math.ceil(t.classMaxValue));for(let e=c;e<s;e++)p.push([e].concat(t.symbol.color));c=s}l.classMaxValue!==c&&c!==r||p.push([c].concat(l.symbol.color))}const d=u({colormap:p,fillUnspecified:!1});return this.lookup={rendererJSON:e,colormapLut:d},this.canRenderInWebGL=k(d?.indexedColormap),{success:!0}}_updateStretchRenderer(e){let{stretchType:t,dra:r}=e;if(!("none"===t||e.statistics?.length||v(this.rasterInfo.statistics)||r))return{success:!1,error:"Unsupported renderer; StretchRenderer.customStatistics is required when dynamic range adjustment is not used."};const s=e.histograms||this.rasterInfo.histograms;!V(e.stretchType)||s?.length||r||(t="minMax");const{computeGamma:a,useGamma:o,colorRamp:n}=e;let{gamma:i}=e;if(o&&a&&!i?.length){const t=e.statistics?.length?e.statistics:this.rasterInfo.statistics;i=f(this.rasterInfo.pixelType,t)}const l=this.rasterInfo.pixelType,c=!r&&["u8","u16","s8","s16"].includes(l);if("histogramEqualization"===t){const t=s.map(e=>b(e));this.lookup={rendererJSON:e,histogramLut:t}}else if(c){const t=d(e,{rasterInfo:this.rasterInfo}),r=h({pixelType:l,...t,gamma:o?i:null,rounding:"floor"});this.lookup={rendererJSON:e,stretchLut:r}}else this.lookup={rendererJSON:e};if(n&&!U(n)){const t=R(n,{interpolateAlpha:!0});this.lookup.colormapLut=u({colormap:t}),this.lookup.rendererJSON=e}return this.lookup.gamma=o&&i?.length?i:null,this.canRenderInWebGL="histogramEqualization"!==t,{success:!0}}_generateColormapWebGLParams(e){const{indexedColormap:t,offset:r}=this.lookup.colormapLut||{};return{colormap:t,colormapOffset:r,isClassBreaks:e,type:"lut"}}_generateStretchWebGLParams(e,t,r){const{colormapLut:s}=this.lookup,a=t.colorRamp?s?.indexedColormap:null,o=t.colorRamp?s?.offset:null;"histogramEqualization"===t.stretchType&&(t={...t,stretchType:"minMax"});const{gamma:n}=this.lookup,i=!(!t.useGamma||!n?.some(e=>1!==e));let l=0;null!=e&&(l=e.getPlaneCount(),2===l&&((e=e.clone()).statistics=[e.statistics[0]],e.pixels=[e.pixels[0]]));const{bandCount:u}=this.rasterInfo,c=Math.min(3,r?.length||l||u,u),p=a||i?1:255,m=new Float32Array(c);if(i&&n)for(let d=0;d<c;d++)n[d]>1?n[d]>2?m[d]=6.5+(n[d]-2)**2.5:m[d]=6.5+100*(2-n[d])**4:m[d]=1;const h=i&&n?[n[0],n[1]??n[0],n[2]??n[0]]:[1,1,1],f=i?[m[0],m[1]??m[0],m[2]??m[0]]:[1,1,1];if(t.dra&&null==e&&("minMax"===t.stretchType||"standardDeviation"===t.stretchType))return{bandCount:c,minOutput:(t.min??0)/p,maxOutput:(t.max??255)/p,minCutOff:[0,0,0],maxCutOff:[1,1,1],factor:[1,1,1],useGamma:i,gamma:h,gammaCorrection:f,colormap:a,colormapOffset:o,stretchType:t.stretchType,dynamicRangeAdjustment:t.dra,numberOfStandardDeviations:t.numberOfStandardDeviations??2,type:"stretch"};const{minCutOff:b,maxCutOff:g,minOutput:y,maxOutput:x}=d(t,{rasterInfo:this.rasterInfo,pixelBlock:e,bandIds:r});1===b.length&&(b[2]=b[1]=b[0]),1===g.length&&(g[2]=g[1]=g[0]);const S=g.map((e,t)=>g[t]===b[t]?0:(x-y)/(g[t]-b[t])/p);return{bandCount:c,minOutput:y/p,maxOutput:x/p,minCutOff:b,maxCutOff:g,factor:S,useGamma:i,gamma:h,gammaCorrection:f,colormap:a,colormapOffset:o,stretchType:t.stretchType,type:"stretch"}}_generateShadedReliefWebGLParams(e,t=!1,r={x:0,y:0}){const{colormapLut:s}=this.lookup,a=e.colorRamp?s?.indexedColormap:null,o=e.colorRamp?s?.offset:null,n={...e,isGCS:t,resolution:r},i=x(n),l=this.rasterInfo.statistics?.[0];return{...i,minValue:l?.min??0,maxValue:l?.max??8e3,hillshadeType:"traditional"===e.hillshadeType?0:1,type:"hillshade",colormap:a,colormapOffset:o}}_generateVectorFieldWebGLParams(e){const{style:t,inputUnit:r,outputUnit:s,visualVariables:a,symbolTileSize:o,flowRepresentation:n}=e,i=this.rasterInfo.statistics?.[0].min??0,l=this.rasterInfo.statistics?.[0].max??50,u=a?.find(e=>"sizeInfo"===e.type)??{maxDataValue:l,maxSize:.8*o,minDataValue:i,minSize:.2*o},c=u.minDataValue??i,p=u.maxDataValue??l,d=null!=u.maxSize&&null!=u.minSize?[u.minSize/o,u.maxSize/o]:[.2,.8];if("wind_speed"===t){const e=(d[0]+d[1])/2;d[0]=d[1]=e}const m=null!=c&&null!=p?[c,p]:null;let h=null;if("classified_arrow"===t)if(null!=c&&null!=p&&null!=u){h=[];const e=(u.maxDataValue-u.minDataValue)/5;for(let t=0;t<6;t++)h.push(u.minDataValue+e*t)}else h=[0,1e-6,3.5,7,10.5,14];const f="flow_to"===n===("ocean_current_kn"===t||"ocean_current_m"===t)?0:Math.PI,b=a?.find(e=>"rotationInfo"===e.type);return{breakValues:h,dataRange:m,inputUnit:r,outputUnit:s,symbolTileSize:o,symbolPercentRange:d,style:t||"single_arrow",rotation:f,rotationType:this.rasterInfo.storageInfo?.tileInfo&&"vector-uv"===this.rasterInfo.dataType?"geographic":b?.rotationType||e.rotationType,type:"vectorField"}}};function V(e){return"percentClip"===e||"histogramEqualization"===e}function v(e){return null!=e&&e.length>0&&null!=e[0].min&&null!=e[0].max}function T(e){return c(e)&&0!==e.validPixelCount}function U(e){return"algorithmic"===e.type&&["0,0,0,255","0,0,0"].includes(e.fromColor.join(","))&&["255,255,255,255","255,255,255"].includes(e.toColor.join(","))}e([s({json:{write:!0}})],O.prototype,"rendererJSON",void 0),e([s({type:S,json:{write:!0}})],O.prototype,"rasterInfo",void 0),e([s({json:{write:!0}})],O.prototype,"lookup",void 0),e([s()],O.prototype,"canRenderInWebGL",void 0),O=e([a("esri.renderers.support.RasterSymbolizer")],O);export{O as default};