diff --git a/src/assets/scss/colorize.scss b/src/assets/scss/colorize.scss index 055d7477cf909ec7c362f2fb4c7be5993f9a44ac..8016148aa8635616451f939e474a685fd342471a 100644 --- a/src/assets/scss/colorize.scss +++ b/src/assets/scss/colorize.scss @@ -14,6 +14,19 @@ border: none !important; } +.table-row-font { + @extend .MuiTableCell-root; + color: rgba(0, 0, 0, 0.87); +} + +.MuiSwitch-colorSecondary.Mui-checked { + color: $primary-color !important; +} + +.MuiSwitch-colorSecondary.Mui-checked + .MuiSwitch-track{ + background-color: $primary-color-focus !important; +} + .colorbutton { background-color: white; padding: 10px; diff --git a/src/components/tools/colorize/colorize.component.js b/src/components/tools/colorize/colorize.component.js index 89aa708e3f2f227b03c825354a0af5c9d8525457..37fcb1bc091cc56d9504087d020adefdbf801917 100644 --- a/src/components/tools/colorize/colorize.component.js +++ b/src/components/tools/colorize/colorize.component.js @@ -10,7 +10,7 @@ import { GRADUATED, RASTER, SINGLE_COLOR, VECTOR, import ToolFooter from "../../shared/tool-footer"; import MultiBandComponent from "./multi-band.component"; import Select from "react-select"; -import {Table, TableBody, TableCell, TableRow } from '@material-ui/core'; +import {FormControlLabel, Switch, Table, TableBody, TableCell, TableRow} from '@material-ui/core'; import {customSelectStyle} from "../../shared/tool-content/tool-content.component"; const mapColors = (color) => { @@ -25,6 +25,7 @@ const ColorizeComponent = ({ selectedLayer, layoutProperties, selectLayer, lay classificationMode, classificationOptions, numberOfClasses, changeNumberOfClasses, featureAttributes, changeColorAttributes, colorAttribute, applyVectorColors, currentColor, colorPickerOpen, toggleColorPicker, changeColor, message, isSingleBand, updateRed, updateGreen, updateBlue, bands, redBand, blueBand, greenBand, + removeNoData, toggleRemoveNoData, opacity, }) => ( <div id='colorize-tool' className='tool'> <ToolHeader @@ -70,16 +71,16 @@ const ColorizeComponent = ({ selectedLayer, layoutProperties, selectLayer, lay <Table> <TableBody> <TableRow> - <TableCell className="smaller-text "><strong>Minimum pixel value:</strong></TableCell> - <TableCell className="smaller-text ">{rasterMin.toFixed(2)}</TableCell> + <TableCell className="smaller-text"><strong>Minimum pixel value:</strong></TableCell> + <TableCell className="smaller-text">{rasterMin.toFixed(2)}</TableCell> </TableRow> <TableRow> - <TableCell className="smaller-text "><strong>Maximum pixel value:</strong></TableCell> - <TableCell className="smaller-text ">{rasterMax.toFixed(2)}</TableCell> + <TableCell className="smaller-text"><strong>Maximum pixel value:</strong></TableCell> + <TableCell className="smaller-text">{rasterMax.toFixed(2)}</TableCell> </TableRow> <TableRow> - <TableCell className="smaller-text "><strong>No Data value:</strong></TableCell> - <TableCell className="smaller-text ">{noDataValue}</TableCell> + <TableCell className="smaller-text"><strong>No Data value:</strong></TableCell> + <TableCell className="smaller-text">{noDataValue}</TableCell> </TableRow> </TableBody> </Table> @@ -101,13 +102,24 @@ const ColorizeComponent = ({ selectedLayer, layoutProperties, selectLayer, lay <div> <br/> - <TableCell className="smaller-text no-border"><strong>Opacity:</strong></TableCell> + <div className="table-row-font smaller-text no-border"><strong>Opacity:</strong></div> <Slider defaultValue={0.8} + value={opacity} max={1} step={0.1} valueLabelDisplay="on" onChangeCommitted={updateOpacity} /> + <FormControlLabel + control={ + <Switch + checked={removeNoData || false} + onChange={toggleRemoveNoData} + inputProps={{ 'aria-label': 'controlled' }} + /> + } + label="Hide empty values" /> + <div className='content-row submit-row'> <button className='gt-button-accent full' diff --git a/src/components/tools/colorize/colorize.container.js b/src/components/tools/colorize/colorize.container.js index 4a4654e97c9ebdce622269fac31dd419afd63b13..37d00117c8651bf4b42d00255e72495e931f7c96 100644 --- a/src/components/tools/colorize/colorize.container.js +++ b/src/components/tools/colorize/colorize.container.js @@ -49,14 +49,17 @@ const getColorBars = (type) => { return colorBars; }; -const colorizeRaster = (layers, id, colorScaleType, opacity, rasterMin, rasterMax, redBand, greenBand, blueBand) => { +const colorizeRaster = (layers, id, colorScaleType, opacity, rasterMin, rasterMax, redBand, greenBand, blueBand, removeNoData) => { const raster = getLayerById(layers, id); const isSingleBand = raster.options.georaster.numberOfRasters < 3; let pixelValuesToColorFn; if (isSingleBand){ if (colorScaleType === 'Default') { - pixelValuesToColorFn = null; //reset to default + if (raster.palette) { + pixelValuesToColorFn = + RasterService.applyColorPalette(raster, removeNoData); + } else pixelValuesToColorFn = null; //reset to default } else { let scaleType = getChromaScaleType(colorScaleType); let scale = chroma.scale(scaleType).domain([0, 1]); @@ -72,9 +75,10 @@ const colorizeRaster = (layers, id, colorScaleType, opacity, rasterMin, rasterMa } } else { pixelValuesToColorFn = - RasterService.createMultiBandColors(raster, redBand-1, greenBand-1, blueBand-1); + RasterService.createMultiBandColors(raster, redBand-1, greenBand-1, blueBand-1, removeNoData); } raster.options.opacity = opacity; + raster.options.removeNoData = removeNoData; raster.options.colorScaleType = colorScaleType; raster.options.pixelValuesToColorFn = pixelValuesToColorFn; @@ -85,13 +89,15 @@ const colorizeRaster = (layers, id, colorScaleType, opacity, rasterMin, rasterMa const getRasterProperties = rasterLayer => { if (!rasterLayer.options.colorScaleType) rasterLayer.options.colorScaleType = 'Default'; if (!rasterLayer.options.opacity) rasterLayer.options.opacity = 0.8; + if (!rasterLayer.options.removeNoData) rasterLayer.options.removeNoData = false; const numberOfBands = rasterLayer.options.georaster.numberOfRasters; const noDataValue = String(rasterLayer.options.georaster.noDataValue); const colorScaleType = rasterLayer.options.colorScaleType; const opacity = rasterLayer.options.opacity; + const removeNoData = rasterLayer.options.removeNoData; const min = rasterLayer.options.georaster.mins ? parseFloat(rasterLayer.options.georaster.mins[0]) : 0; const max = rasterLayer.options.georaster.maxs ? parseFloat(rasterLayer.options.georaster.maxs[0]) : 100; - return {'min': min, 'max': max, 'noDataValue': noDataValue, 'numberOfBands': numberOfBands, 'colorScaleType': colorScaleType, 'opacity': opacity}; + return {'min': min, 'max': max, 'noDataValue': noDataValue, 'numberOfBands': numberOfBands, 'colorScaleType': colorScaleType, 'opacity': opacity, 'removeNoData': removeNoData}; }; const getLayerDropDownList = (layers) => { @@ -206,6 +212,7 @@ const ColorizeContainer = () => { const [bands, setBandOptions] = useState([]); const [isSingleBand, setSingleBandProperties] = useState(true); const [message, setMessage] = useState(''); + const [removeNoData, setremoveNoData] = useState(false); useEffect(() => { const dropDownLayers = getLayerDropDownList(layers); @@ -222,7 +229,6 @@ const ColorizeContainer = () => { } }, [currentLayerId]); - const updateRed = selected => { return setRed(selected.value); }; @@ -240,6 +246,8 @@ const ColorizeContainer = () => { setRasterMin(properties['min']); setRasterMax(properties['max']); setNoDataValue(properties['noDataValue']); + setremoveNoData(properties['removeNoData']); + setOpacity(properties['opacity']); if (properties['numberOfBands'] > 2){ setSingleBandProperties(false); setBandOptions(getListOfBands(properties['numberOfBands'])); @@ -251,7 +259,6 @@ const ColorizeContainer = () => { } } setColorBars(getColorBars(RASTER)); - //p.setOpacity(properties['opacity']); showLayoutProperties(RASTER); } else { if (!currentLayer.color) currentLayer.color = 'rgba(245,166,35,1)'; @@ -426,8 +433,11 @@ const ColorizeContainer = () => { return setOpacity(value); }; + const toggleRemoveNoData = () => { + return setremoveNoData(!removeNoData); + }; const colorize = () => { - return colorizeRaster(layers, currentLayerId, colorScaleType, opacity, rasterMin, rasterMax, redBand, greenBand, blueBand); + return colorizeRaster(layers, currentLayerId, colorScaleType, opacity, rasterMin, rasterMax, redBand, greenBand, blueBand, removeNoData); }; const toggleColorPicker = () => { return displayColorPicker(!colorPickerOpen); @@ -444,6 +454,7 @@ const ColorizeContainer = () => { classificationMode, classificationOptions, numberOfClasses, changeNumberOfClasses, featureAttributes, changeColorAttributes, colorAttribute, applyVectorColors, currentColor, colorPickerOpen, toggleColorPicker, changeColor, message, isSingleBand, updateRed, updateGreen, updateBlue, bands, redBand, blueBand, greenBand, + removeNoData, toggleRemoveNoData, opacity, }); }; diff --git a/src/map/Map.js b/src/map/Map.js index bf6b56dfb71a584f37c76c260296ff6f0853152e..d916f485e14bf5c52671014c25b2559038eae18a 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -188,6 +188,15 @@ const Map = { }; }, + getTransparentPolygonStyle(color){ + return { + color: '#000', + weight: 8, + fillColor: color, + fillOpacity: 0.5, + }; + }, + zoomToLayer(layer) { const bounds = layer.getBounds(); @@ -220,7 +229,10 @@ const Map = { addVectorLayer(geojson) { let color = '#F5A623'; if (geojson.color) color = geojson.color; - const defaultStyle = this.getVectorStyle(color); + let defaultStyle = this.getVectorStyle(color); + if (geojson.geometry === 'Polygon' && geojson.attributes.includes('Dataverse')){ + defaultStyle = this.getTransparentPolygonStyle(color); + } const bindPopup = this.bindPopup; const geojsonLayer = L.geoJson(geojson, { pointToLayer: function (feature, latlng) { diff --git a/src/services/RasterService.js b/src/services/RasterService.js index d4b27cb8450c8740fb90228cb5563d4875dc77da..6b2aa8d836f92073a263c2f9ca1fbaf97a6c5ff0 100644 --- a/src/services/RasterService.js +++ b/src/services/RasterService.js @@ -22,22 +22,37 @@ const RasterService = { } }, - createMultiBandColors(georaster, band1Index, band2Index, band3Index) { + createMultiBandColors(georaster, band1Index, band2Index, band3Index, removeNoData) { return pixelValues => { let band1 = pixelValues[band1Index]; let band2 = pixelValues[band2Index]; let band3 = pixelValues[band3Index]; - if (!band1 || band1 === georaster.noDataValue) band1 = 0; - if (!band2 || band2 === georaster.noDataValue) band2 = 0; - if (!band3 || band3 === georaster.noDataValue) band3 = 0; + if (!band1 || band1 === georaster.noDataValue) band1 = -1; + if (!band2 || band2 === georaster.noDataValue) band2 = -1; + if (!band3 || band3 === georaster.noDataValue) band3 = -1; if (band1 > 255) band1 = Math.round(band1 / 65536 * 255 * 2.55); if (band2 > 255) band2 = Math.round(band2 / 65536 * 255 * 2.55); if (band3 > 255) band3 = Math.round(band3 / 65536 * 255 * 2.55); - return `rgba(${band1},${band2},${band3}, 1)`; + let opacity = 1; + if (removeNoData && band1 === -1 && band2 === -1 && band3 === -1) opacity = 0; + return `rgba(${band1},${band2},${band3}, ${opacity})`; }; }, + applyColorPalette(georaster, removeNoData){ + return pixelValues => { + let opacity = 1; + let singleBand = pixelValues[0]; + if (removeNoData && singleBand === georaster.noDataValue){ + opacity = 0; + } + let color = georaster.palette[singleBand]; + if (removeNoData && color[0] === 0 && color[1] === 0 && color[2] === 0) opacity = 0; + return `rgba(${color[0]},${color[1]},${color[2]}, ${opacity})`; + }; + }, + createRaster(input) { /* check for Github URL and switch to cors-enabled version */ @@ -63,7 +78,10 @@ const RasterService = { }; if (georaster.numberOfRasters > 2){ options.pixelValuesToColorFn = - this.createMultiBandColors(georaster, 0, 1,2); + this.createMultiBandColors(georaster,0, 1,2, false); + } else if (georaster.palette){ + options.pixelValuesToColorFn = + this.applyColorPalette(georaster, false); } const raster = new GeoRasterLayer(options); resolve(raster);