17 changed files with 1321 additions and 0 deletions
-
5BSR_Filter/config.json
-
25BSR_Filter/dist/runtime/assets/zoom-in.svg
-
2BSR_Filter/dist/runtime/widget.js
-
311BSR_Filter/dist/runtime/widget.js.LICENSE.txt
-
1BSR_Filter/dist/setting/setting.js
-
16BSR_Filter/icon.svg
-
19BSR_Filter/manifest.json
-
7BSR_Filter/src/config.ts
-
25BSR_Filter/src/runtime/assets/zoom-in.svg
-
45BSR_Filter/src/runtime/components/LoadingPopup.css
-
23BSR_Filter/src/runtime/components/LoadingPopup.tsx
-
23BSR_Filter/src/runtime/components/LoadingSpinner.jsx
-
123BSR_Filter/src/runtime/simple_widget.css
-
662BSR_Filter/src/runtime/widget.tsx
-
20BSR_Filter/src/setting/setting.tsx
-
BINBSR_Filter/src/zoom-in.png
-
14BSR_Filter/tests/simple-widget.test.tsx
@ -0,0 +1,5 @@ |
|||||
|
{ |
||||
|
"exampleConfigProperty": "test", |
||||
|
"useMapWidget": true |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
<?xml version="1.0" encoding="iso-8859-1"?> |
||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> |
||||
|
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" |
||||
|
viewBox="0 0 488.409 488.409" xml:space="preserve"> |
||||
|
<circle style="fill:#91C7C9;" cx="160.296" cy="328.409" r="136.8"/> |
||||
|
<circle style="fill:#B3DEE0;" cx="177.896" cy="346.009" r="119.2"/> |
||||
|
<path style="fill:#13BCCE;" d="M478.696,10.009c16,16.8,16,43.2-35.2,94.4s-168.8,142.4-184.8,125.6s74.4-133.6,125.6-185.6 |
||||
|
C435.496-6.791,462.696-6.791,478.696,10.009z"/> |
||||
|
<path style="fill:#0E94AA;" d="M478.696,10.009c16,16.8,16,43.2-35.2,94.4s-168.8,142.4-184.8,125.6s80.8-124.8,132.8-176.8 |
||||
|
C442.696,2.009,462.696-6.791,478.696,10.009z"/> |
||||
|
<path style="fill:#096E89;" d="M478.696,10.009c16,16.8,16,43.2-35.2,94.4s-168.8,142.4-184.8,125.6"/> |
||||
|
<path style="fill:#F98AC1;" d="M164.296,488.409c-91.2,0-164-72.8-164-164c0-90.4,73.6-164,164-164s164,73.6,164,164 |
||||
|
C328.296,415.609,254.696,488.409,164.296,488.409z M164.296,200.409c-68,0-124,56-124,124s56,124,124,124s124-56,124-124 |
||||
|
S232.296,200.409,164.296,200.409z"/> |
||||
|
<path style="fill:#EF3388;" d="M164.296,488.409c-90.4,0-156-69.6-156-160s72.8-163.2,163.2-163.2s156.8,68.8,156.8,159.2 |
||||
|
C328.296,415.609,254.696,488.409,164.296,488.409z M164.296,200.409c-68,0-124,56-124,124s56,124,124,124s124-56,124-124 |
||||
|
S232.296,200.409,164.296,200.409z"/> |
||||
|
<path style="fill:#BC086B;" d="M306.696,240.409c-3.2,21.6-11.2,43.2-20.8,62.4c1.6,7.2,1.6,14.4,1.6,21.6c0,68-56,124-124,124 |
||||
|
c-20.8,0-40-4.8-57.6-14.4c-11.2,1.6-22.4,2.4-33.6,2.4c-10.4,0-20-0.8-30.4-1.6c30.4,32.8,72.8,53.6,120.8,53.6 |
||||
|
c90.4,0,165.6-73.6,165.6-164C329.896,294.009,321.096,265.209,306.696,240.409z"/> |
||||
|
<path style="fill:#EF3388;" d="M229.096,308.409h-48.8v-48.8c0-8-8-13.6-16-13.6s-16,6.4-16,13.6v48.8h-49.6c-8,0-14.4,8-14.4,16 |
||||
|
s6.4,16,14.4,16h49.6v49.6c0,8,8,14.4,16,14.4s16-6.4,16-14.4v-49.6h48.8c8,0,14.4-8,14.4-16S237.096,308.409,229.096,308.409z"/> |
||||
|
<path style="fill:#BC086B;" d="M229.096,308.409h-48.8l0,0l-32,32l0,0v49.6c0,8,8,14.4,16,14.4s16-6.4,16-14.4v-49.6h48.8 |
||||
|
c8,0,14.4-8,14.4-16S237.096,308.409,229.096,308.409z"/> |
||||
|
</svg> |
||||
2
BSR_Filter/dist/runtime/widget.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,311 @@ |
|||||
|
/** |
||||
|
* @license |
||||
|
Copyright (c) 2008, Adobe Systems Incorporated |
||||
|
All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are |
||||
|
met: |
||||
|
|
||||
|
* Redistributions of source code must retain the above copyright notice, |
||||
|
this list of conditions and the following disclaimer. |
||||
|
|
||||
|
* Redistributions in binary form must reproduce the above copyright |
||||
|
notice, this list of conditions and the following disclaimer in the |
||||
|
documentation and/or other materials provided with the distribution. |
||||
|
|
||||
|
* Neither the name of Adobe Systems Incorporated nor the names of its |
||||
|
contributors may be used to endorse or promote products derived from |
||||
|
this software without specific prior written permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* |
||||
|
* Copyright (c) 2014 James Robb, https://github.com/jamesbrobb |
||||
|
* |
||||
|
* Permission is hereby granted, free of charge, to any person obtaining |
||||
|
* a copy of this software and associated documentation files (the |
||||
|
* "Software"), to deal in the Software without restriction, including |
||||
|
* without limitation the rights to use, copy, modify, merge, publish, |
||||
|
* distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
* permit persons to whom the Software is furnished to do so, subject to |
||||
|
* the following conditions: |
||||
|
* |
||||
|
* The above copyright notice and this permission notice shall be |
||||
|
* included in all copies or substantial portions of the Software. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
* ==================================================================== |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* (c) Dean McNamee <dean@gmail.com>, 2013. |
||||
|
* |
||||
|
* https://github.com/deanm/omggif |
||||
|
* |
||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
* of this software and associated documentation files (the "Software"), to |
||||
|
* deal in the Software without restriction, including without limitation the |
||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
||||
|
* sell copies of the Software, and to permit persons to whom the Software is |
||||
|
* furnished to do so, subject to the following conditions: |
||||
|
* |
||||
|
* The above copyright notice and this permission notice shall be included in |
||||
|
* all copies or substantial portions of the Software. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
* IN THE SOFTWARE. |
||||
|
* |
||||
|
* omggif is a JavaScript implementation of a GIF 89a encoder and decoder, |
||||
|
* including animation and compression. It does not rely on any specific |
||||
|
* underlying system, so should run in the browser, Node, or Plask. |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* Copyright (c) 2014 Steven Spungin (TwelveTone LLC) steven@twelvetone.tv |
||||
|
* |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* Copyright (c) 2017 Aras Abbasi |
||||
|
* |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* Copyright (c) 2018 Aras Abbasi |
||||
|
* |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* Copyright (c) 2019 Aras Abbasi |
||||
|
* |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* FPDF is released under a permissive license: there is no usage restriction. |
||||
|
* You may embed it freely in your application (commercial or not), with or |
||||
|
* without modifications. |
||||
|
* |
||||
|
* Reference: http://www.fpdf.org/en/script/script37.php |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* Joseph Myers does not specify a particular license for his work. |
||||
|
* |
||||
|
* Author: Joseph Myers |
||||
|
* Accessed from: http://www.myersdaily.org/joseph/javascript/md5.js |
||||
|
* |
||||
|
* Modified by: Owen Leong |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
* Author: Owen Leong (@owenl131) |
||||
|
* Date: 15 Oct 2020 |
||||
|
* References: |
||||
|
* https://www.cs.cmu.edu/~dst/Adobe/Gallery/anon21jul01-pdf-encryption.txt |
||||
|
* https://github.com/foliojs/pdfkit/blob/master/lib/security.js |
||||
|
* http://www.fpdf.org/en/script/script37.php |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* Unicode Bidi Engine based on the work of Alex Shensis (@asthensis) |
||||
|
* MIT License |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* jsPDF fileloading PlugIn |
||||
|
* Copyright (c) 2018 Aras Abbasi (aras.abbasi@gmail.com) |
||||
|
* |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* jsPDF filters PlugIn |
||||
|
* Copyright (c) 2014 Aras Abbasi |
||||
|
* |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* @license |
||||
|
* jsPDF virtual FileSystem functionality |
||||
|
* |
||||
|
* Licensed under the MIT License. |
||||
|
* http://opensource.org/licenses/mit-license |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* A class to parse color values |
||||
|
* @author Stoyan Stefanov <sstoo@gmail.com> |
||||
|
* {@link http://www.phpied.com/rgb-color-parser-in-javascript/} |
||||
|
* @license Use it if you like it |
||||
|
*/ |
||||
|
|
||||
|
/** ==================================================================== |
||||
|
* @license |
||||
|
* jsPDF XMP metadata plugin |
||||
|
* Copyright (c) 2016 Jussi Utunen, u-jussi@suomi24.fi |
||||
|
* |
||||
|
* Permission is hereby granted, free of charge, to any person obtaining |
||||
|
* a copy of this software and associated documentation files (the |
||||
|
* "Software"), to deal in the Software without restriction, including |
||||
|
* without limitation the rights to use, copy, modify, merge, publish, |
||||
|
* distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
* permit persons to whom the Software is furnished to do so, subject to |
||||
|
* the following conditions: |
||||
|
* |
||||
|
* The above copyright notice and this permission notice shall be |
||||
|
* included in all copies or substantial portions of the Software. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
* ==================================================================== |
||||
|
*/ |
||||
|
|
||||
|
/** @license |
||||
|
* Copyright (c) 2017 Dominik Homberger |
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
https://webpjs.appspot.com |
||||
|
WebPRiffParser dominikhlbg@gmail.com |
||||
|
*/ |
||||
|
|
||||
|
/** @license |
||||
|
* |
||||
|
* jsPDF - PDF Document creation from JavaScript |
||||
|
* Version 3.0.1 Built on 2025-03-17T14:19:36.873Z |
||||
|
* CommitID 00000000 |
||||
|
* |
||||
|
* Copyright (c) 2010-2021 James Hall <james@parall.ax>, https://github.com/MrRio/jsPDF |
||||
|
* 2015-2021 yWorks GmbH, http://www.yworks.com |
||||
|
* 2015-2021 Lukas Holländer <lukas.hollaender@yworks.com>, https://github.com/HackbrettXXX |
||||
|
* 2016-2018 Aras Abbasi <aras.abbasi@gmail.com> |
||||
|
* 2010 Aaron Spike, https://github.com/acspike |
||||
|
* 2012 Willow Systems Corporation, https://github.com/willowsystems |
||||
|
* 2012 Pablo Hess, https://github.com/pablohess |
||||
|
* 2012 Florian Jenett, https://github.com/fjenett |
||||
|
* 2013 Warren Weckesser, https://github.com/warrenweckesser |
||||
|
* 2013 Youssef Beddad, https://github.com/lifof |
||||
|
* 2013 Lee Driscoll, https://github.com/lsdriscoll |
||||
|
* 2013 Stefan Slonevskiy, https://github.com/stefslon |
||||
|
* 2013 Jeremy Morel, https://github.com/jmorel |
||||
|
* 2013 Christoph Hartmann, https://github.com/chris-rock |
||||
|
* 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria |
||||
|
* 2014 James Makes, https://github.com/dollaruw |
||||
|
* 2014 Diego Casorran, https://github.com/diegocr |
||||
|
* 2014 Steven Spungin, https://github.com/Flamenco |
||||
|
* 2014 Kenneth Glassey, https://github.com/Gavvers |
||||
|
* |
||||
|
* Permission is hereby granted, free of charge, to any person obtaining |
||||
|
* a copy of this software and associated documentation files (the |
||||
|
* "Software"), to deal in the Software without restriction, including |
||||
|
* without limitation the rights to use, copy, modify, merge, publish, |
||||
|
* distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
* permit persons to whom the Software is furnished to do so, subject to |
||||
|
* the following conditions: |
||||
|
* |
||||
|
* The above copyright notice and this permission notice shall be |
||||
|
* included in all copies or substantial portions of the Software. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
* |
||||
|
* Contributor(s): |
||||
|
* siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango, |
||||
|
* kim3er, mfo, alnorth, Flamenco |
||||
|
*/ |
||||
|
|
||||
|
/** @license |
||||
|
* Copyright (c) 2012 Willow Systems Corporation, https://github.com/willowsystems |
||||
|
* |
||||
|
* Permission is hereby granted, free of charge, to any person obtaining |
||||
|
* a copy of this software and associated documentation files (the |
||||
|
* "Software"), to deal in the Software without restriction, including |
||||
|
* without limitation the rights to use, copy, modify, merge, publish, |
||||
|
* distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
* permit persons to whom the Software is furnished to do so, subject to |
||||
|
* the following conditions: |
||||
|
* |
||||
|
* The above copyright notice and this permission notice shall be |
||||
|
* included in all copies or substantial portions of the Software. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
* ==================================================================== |
||||
|
*/ |
||||
@ -0,0 +1 @@ |
|||||
|
System.register(["jimu-core","jimu-ui/advanced/setting-components"],(function(e,t){var r={},o={};return{setters:[function(e){r.React=e.React},function(e){o.MapWidgetSelector=e.MapWidgetSelector}],execute:function(){e((()=>{var e={79244:e=>{"use strict";e.exports=r},79298:e=>{"use strict";e.exports=o}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={exports:{}};return e[r](i,i.exports,n),i.exports}n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="";var i={};return n.p=window.jimuConfig.baseUrl,(()=>{"use strict";n.r(i),n.d(i,{__set_webpack_public_path__:()=>o,default:()=>r});var e=n(79244),t=n(79298);const r=r=>e.React.createElement("div",{className:"widget-setting-demo"},e.React.createElement(t.MapWidgetSelector,{useMapWidgetIds:r.useMapWidgetIds,onSelect:e=>{console.log("Selected Map Widget IDs:",e),r.onSettingChange({id:r.id,useMapWidgetIds:e})}}));function o(e){n.p=e}})(),i})())}}})); |
||||
@ -0,0 +1,16 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
|
||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> |
||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> |
||||
|
<svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" |
||||
|
viewBox="0 0 512 512" xml:space="preserve"> |
||||
|
<style type="text/css"> |
||||
|
.st0{fill:#000000;} |
||||
|
</style> |
||||
|
<g> |
||||
|
<path class="st0" d="M272,48h-32V0H112v512h128v-48h32v48h128V0H272V48z M272,380.797h-32v-83.203h32V380.797z M272,214.398h-32 |
||||
|
v-83.203h32V214.398z"/> |
||||
|
<rect class="st0" width="64" height="512"/> |
||||
|
<rect x="448" class="st0" width="64" height="512"/> |
||||
|
</g> |
||||
|
</svg> |
||||
@ -0,0 +1,19 @@ |
|||||
|
{ |
||||
|
"name": "BSR_Filter", |
||||
|
"label": "BSR_Filter", |
||||
|
"type": "widget", |
||||
|
"version": "1.16.0", |
||||
|
"exbVersion": "1.16.0", |
||||
|
"author": "Esri R&D Center Beijing", |
||||
|
"description": "This is a barebones, simple widget. It includes an example of how to use the config file, and it includes a placeholder SVG icon. It intentionally does not include the following so you can use this to start from scratch: i18n translations, a Settings panel, unit tests. See the documentation for more information on how to implement these features.", |
||||
|
"copyright": "", |
||||
|
"license": "http://www.apache.org/licenses/LICENSE-2.0", |
||||
|
"properties": {}, |
||||
|
"translatedLocales": [ |
||||
|
"en" |
||||
|
], |
||||
|
"defaultSize": { |
||||
|
"width": 800, |
||||
|
"height": 500 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
import { type ImmutableObject } from 'seamless-immutable' |
||||
|
|
||||
|
export interface Config { |
||||
|
exampleConfigProperty: string |
||||
|
} |
||||
|
|
||||
|
export type IMConfig = ImmutableObject<Config> |
||||
@ -0,0 +1,25 @@ |
|||||
|
<?xml version="1.0" encoding="iso-8859-1"?> |
||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> |
||||
|
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" |
||||
|
viewBox="0 0 488.409 488.409" xml:space="preserve"> |
||||
|
<circle style="fill:#91C7C9;" cx="160.296" cy="328.409" r="136.8"/> |
||||
|
<circle style="fill:#B3DEE0;" cx="177.896" cy="346.009" r="119.2"/> |
||||
|
<path style="fill:#13BCCE;" d="M478.696,10.009c16,16.8,16,43.2-35.2,94.4s-168.8,142.4-184.8,125.6s74.4-133.6,125.6-185.6 |
||||
|
C435.496-6.791,462.696-6.791,478.696,10.009z"/> |
||||
|
<path style="fill:#0E94AA;" d="M478.696,10.009c16,16.8,16,43.2-35.2,94.4s-168.8,142.4-184.8,125.6s80.8-124.8,132.8-176.8 |
||||
|
C442.696,2.009,462.696-6.791,478.696,10.009z"/> |
||||
|
<path style="fill:#096E89;" d="M478.696,10.009c16,16.8,16,43.2-35.2,94.4s-168.8,142.4-184.8,125.6"/> |
||||
|
<path style="fill:#F98AC1;" d="M164.296,488.409c-91.2,0-164-72.8-164-164c0-90.4,73.6-164,164-164s164,73.6,164,164 |
||||
|
C328.296,415.609,254.696,488.409,164.296,488.409z M164.296,200.409c-68,0-124,56-124,124s56,124,124,124s124-56,124-124 |
||||
|
S232.296,200.409,164.296,200.409z"/> |
||||
|
<path style="fill:#EF3388;" d="M164.296,488.409c-90.4,0-156-69.6-156-160s72.8-163.2,163.2-163.2s156.8,68.8,156.8,159.2 |
||||
|
C328.296,415.609,254.696,488.409,164.296,488.409z M164.296,200.409c-68,0-124,56-124,124s56,124,124,124s124-56,124-124 |
||||
|
S232.296,200.409,164.296,200.409z"/> |
||||
|
<path style="fill:#BC086B;" d="M306.696,240.409c-3.2,21.6-11.2,43.2-20.8,62.4c1.6,7.2,1.6,14.4,1.6,21.6c0,68-56,124-124,124 |
||||
|
c-20.8,0-40-4.8-57.6-14.4c-11.2,1.6-22.4,2.4-33.6,2.4c-10.4,0-20-0.8-30.4-1.6c30.4,32.8,72.8,53.6,120.8,53.6 |
||||
|
c90.4,0,165.6-73.6,165.6-164C329.896,294.009,321.096,265.209,306.696,240.409z"/> |
||||
|
<path style="fill:#EF3388;" d="M229.096,308.409h-48.8v-48.8c0-8-8-13.6-16-13.6s-16,6.4-16,13.6v48.8h-49.6c-8,0-14.4,8-14.4,16 |
||||
|
s6.4,16,14.4,16h49.6v49.6c0,8,8,14.4,16,14.4s16-6.4,16-14.4v-49.6h48.8c8,0,14.4-8,14.4-16S237.096,308.409,229.096,308.409z"/> |
||||
|
<path style="fill:#BC086B;" d="M229.096,308.409h-48.8l0,0l-32,32l0,0v49.6c0,8,8,14.4,16,14.4s16-6.4,16-14.4v-49.6h48.8 |
||||
|
c8,0,14.4-8,14.4-16S237.096,308.409,229.096,308.409z"/> |
||||
|
</svg> |
||||
@ -0,0 +1,45 @@ |
|||||
|
.loading-overlay { |
||||
|
position: fixed; |
||||
|
inset: 0; |
||||
|
background: rgba(0, 0, 0, 0.5); |
||||
|
z-index: 1000; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.loading-box { |
||||
|
background: #fff; |
||||
|
padding: 24px; |
||||
|
border-radius: 8px; |
||||
|
width: 280px; |
||||
|
text-align: center; |
||||
|
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3); |
||||
|
} |
||||
|
|
||||
|
.loading-title { |
||||
|
font-size: 1.2rem; |
||||
|
font-weight: bold; |
||||
|
margin-bottom: 16px; |
||||
|
} |
||||
|
|
||||
|
.spinner { |
||||
|
border: 4px solid #e0e0e0; |
||||
|
border-top: 4px solid #009688; |
||||
|
border-radius: 50%; |
||||
|
width: 32px; |
||||
|
height: 32px; |
||||
|
animation: spin 1s linear infinite; |
||||
|
margin: 0 auto 12px auto; |
||||
|
} |
||||
|
|
||||
|
@keyframes spin { |
||||
|
to { |
||||
|
transform: rotate(360deg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.loading-message { |
||||
|
color: #555; |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,23 @@ |
|||||
|
import React from 'react'; |
||||
|
import './LoadingPopup.css'; |
||||
|
|
||||
|
interface LoadingPopupProps { |
||||
|
show: boolean; |
||||
|
message?: string; |
||||
|
} |
||||
|
|
||||
|
const LoadingPopup: React.FC<LoadingPopupProps> = ({ show, message = "Preparing to download ..." }) => { |
||||
|
if (!show) return null; |
||||
|
|
||||
|
return ( |
||||
|
<div className="loading-overlay"> |
||||
|
<div className="loading-box"> |
||||
|
<h2 className="loading-title">Please Wait..</h2> |
||||
|
<div className="spinner" /> |
||||
|
<p className="loading-message">{message}</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default LoadingPopup; |
||||
@ -0,0 +1,23 @@ |
|||||
|
import React from 'react'; |
||||
|
import './LoadingPopup.css'; |
||||
|
|
||||
|
interface LoadingPopupProps { |
||||
|
show: boolean; |
||||
|
message?: string; |
||||
|
} |
||||
|
|
||||
|
const LoadingPopup: React.FC<LoadingPopupProps> = ({ show, message = "Preparing to download ..." }) => { |
||||
|
if (!show) return null; |
||||
|
|
||||
|
return ( |
||||
|
<div className="loading-overlay"> |
||||
|
<div className="loading-box"> |
||||
|
<h2 className="loading-title">Please Wait..</h2> |
||||
|
<div className="spinner" /> |
||||
|
<p className="loading-message">{message}</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default LoadingPopup; |
||||
@ -0,0 +1,123 @@ |
|||||
|
.property-widget-parent { |
||||
|
padding: 0.7rem; |
||||
|
font-family: "Arial", sans-serif; |
||||
|
height: 100%; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.property-widget { |
||||
|
background: #fff; |
||||
|
border-radius: 6px; |
||||
|
padding: 0.7rem; |
||||
|
box-shadow: 0 0 3px rgba(0, 0, 0, 0.08); |
||||
|
height: 100%; |
||||
|
max-height: 100%; |
||||
|
overflow-y: auto; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
.widget-title { |
||||
|
font-size: 1rem; |
||||
|
font-weight: bold; |
||||
|
margin-bottom: 0.7rem; |
||||
|
} |
||||
|
|
||||
|
#countDiv { |
||||
|
background: #f7f7f7; |
||||
|
border-radius: 4px; |
||||
|
padding: 4px 8px; /* less padding */ |
||||
|
margin-bottom: 0.3rem; |
||||
|
font-size: 0.75rem; /* smaller text */ |
||||
|
color: #333; |
||||
|
line-height: 1.2; |
||||
|
display: inline-block; /* shrink width to content */ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
.property_form { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
margin-bottom: 0.7rem; |
||||
|
} |
||||
|
|
||||
|
.property_form label { |
||||
|
font-weight: 600; |
||||
|
margin-bottom: 2px; |
||||
|
font-size: 0.7rem; |
||||
|
} |
||||
|
|
||||
|
.property_form select { |
||||
|
padding: 4px 6px; |
||||
|
border: 1px solid #ccc; |
||||
|
border-radius: 4px; |
||||
|
font-size: 0.7rem; |
||||
|
} |
||||
|
|
||||
|
button { |
||||
|
width: 100%; |
||||
|
padding: 6px 8px; |
||||
|
margin-top: 0.3rem; |
||||
|
border-radius: 4px; |
||||
|
font-weight: bold; |
||||
|
font-size: 0.7rem; |
||||
|
border: none; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
button.property_form { |
||||
|
background-color: #0078d4; |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
button[property_form]:hover { |
||||
|
background-color: #005ea0; |
||||
|
} |
||||
|
|
||||
|
button[variant="outlined"] { |
||||
|
background-color: white; |
||||
|
color: #0078d4; |
||||
|
border: 1px solid #0078d4; |
||||
|
} |
||||
|
|
||||
|
button[variant="outlined"]:hover { |
||||
|
background-color: #f0f0f0; |
||||
|
} |
||||
|
|
||||
|
.attribute-table { |
||||
|
margin-top: 0.7rem; |
||||
|
overflow-x: auto; |
||||
|
} |
||||
|
|
||||
|
.attribute-table table { |
||||
|
table-layout: fixed; |
||||
|
width: 100%; |
||||
|
border-collapse: collapse; |
||||
|
} |
||||
|
|
||||
|
.attribute-table th, |
||||
|
.attribute-table td { |
||||
|
max-width: 150px; |
||||
|
padding: 6px; |
||||
|
border: 1px solid #ddd; |
||||
|
word-wrap: break-word; |
||||
|
overflow-wrap: break-word; |
||||
|
white-space: normal; |
||||
|
font-size: 0.7rem; |
||||
|
} |
||||
|
|
||||
|
.attribute-table th { |
||||
|
background-color: #f2f2f2; |
||||
|
font-weight: bold; |
||||
|
position: sticky; |
||||
|
top: 0; |
||||
|
z-index: 10; |
||||
|
text-align: left; |
||||
|
border-bottom: 1px solid #ccc; |
||||
|
box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
.attribute-table tr:hover { |
||||
|
background-color: #f9f9f9; |
||||
|
cursor: pointer; |
||||
|
} |
||||
@ -0,0 +1,662 @@ |
|||||
|
import React, { useEffect, useMemo, useState } from "react"; |
||||
|
import FeatureLayer from "@arcgis/core/layers/FeatureLayer"; |
||||
|
import GroupLayer from "@arcgis/core/layers/GroupLayer"; |
||||
|
import { type AllWidgetProps } from "jimu-core"; |
||||
|
import { JimuMapViewComponent, type JimuMapView } from "jimu-arcgis"; |
||||
|
import { mapViewManager } from "../../../utils/mapview"; |
||||
|
import "./simple_widget.css"; |
||||
|
import zoomInIcon from "./assets/zoom-in.svg"; |
||||
|
|
||||
|
// Export libraries
|
||||
|
import * as XLSX from "xlsx"; |
||||
|
import jsPDF from "jspdf"; |
||||
|
import autoTable from "jspdf-autotable"; |
||||
|
|
||||
|
const ZONE_LAYER_URL = |
||||
|
"https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/GCC_Administration_Boundaries/FeatureServer/3"; |
||||
|
const WARD_LAYER_URL = |
||||
|
"https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/GCC_Administration_Boundaries/FeatureServer/4"; |
||||
|
const ROAD_LAYER_URL = |
||||
|
"https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/Transporations/FeatureServer/0"; |
||||
|
|
||||
|
const FIELD_ALIASES: Record<string, string> = { |
||||
|
zone: "Zone", |
||||
|
ward: "Ward", |
||||
|
road_id: "Road ID", |
||||
|
road_name: "Road Name", |
||||
|
interior_brr: "Directions", |
||||
|
res_b600: "Res Below 600", |
||||
|
res_600: "Res 601 - 1200", |
||||
|
res_1200: "Res 1201 - 1800", |
||||
|
res_1800: "Res Above 1800", |
||||
|
non_res: "Non Residential", |
||||
|
education: "Education", |
||||
|
vac_res: "Vacant Residential", |
||||
|
vac_non_res: "Vacant Non Residential", |
||||
|
bsr_slab: "BSR Slab", |
||||
|
}; |
||||
|
|
||||
|
const ROAD_TABLE_FIELDS = [ |
||||
|
"zone", |
||||
|
"ward", |
||||
|
"road_id", |
||||
|
"road_name", |
||||
|
"interior_brr", |
||||
|
"res_b600", |
||||
|
"res_600", |
||||
|
"res_1200", |
||||
|
"res_1800", |
||||
|
"non_res", |
||||
|
"education", |
||||
|
"vac_res", |
||||
|
"vac_non_res", |
||||
|
"bsr_slab", |
||||
|
] as const; |
||||
|
|
||||
|
const RoadAssetFilter = (props: AllWidgetProps<any>) => { |
||||
|
const [jimuMapView, setJimuMapView] = useState<JimuMapView>(); |
||||
|
const [highlightHandle, setHighlightHandle] = useState<any>(null); |
||||
|
|
||||
|
const [selectedZone, setSelectedZone] = useState<string>(""); |
||||
|
const [selectedWard, setSelectedWard] = useState<string>(""); |
||||
|
const [selectedRoadName, setSelectedRoadName] = useState<string>("All"); |
||||
|
|
||||
|
const [zoneOptions, setZoneOptions] = useState<string[]>([]); |
||||
|
const [wardOptions, setWardOptions] = useState<string[]>([]); |
||||
|
const [roadNameOptions, setRoadNameOptions] = useState<string[]>([]); |
||||
|
|
||||
|
const [roadCount, setRoadCount] = useState<number | null>(null); |
||||
|
const [tableData, setTableData] = useState<any[]>([]); |
||||
|
|
||||
|
const safe = (val: any) => String(val ?? "").replace(/'/g, "''"); |
||||
|
|
||||
|
const roadLayer = useMemo(() => new FeatureLayer({ url: ROAD_LAYER_URL }), []); |
||||
|
|
||||
|
const getRoadLayersFromMap = async () => { |
||||
|
const view = jimuMapView?.view; |
||||
|
if (!view) return []; |
||||
|
|
||||
|
const found: any[] = []; |
||||
|
|
||||
|
for (const layer of view.map.layers.toArray()) { |
||||
|
try { |
||||
|
await layer.load(); |
||||
|
|
||||
|
if (layer.type === "group") { |
||||
|
const group = layer as GroupLayer; |
||||
|
for (const sub of group.layers.toArray()) { |
||||
|
try { |
||||
|
await sub.load(); |
||||
|
if ( |
||||
|
sub.url === ROAD_LAYER_URL || |
||||
|
sub.title === "Road" || |
||||
|
sub.title === "CarraigeWay" |
||||
|
) { |
||||
|
found.push(sub); |
||||
|
} |
||||
|
} catch { |
||||
|
// ignore sublayer load errors
|
||||
|
} |
||||
|
} |
||||
|
} else if (layer.url === ROAD_LAYER_URL || layer.title === "Road") { |
||||
|
found.push(layer); |
||||
|
} |
||||
|
} catch { |
||||
|
// ignore layer load errors
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return found; |
||||
|
}; |
||||
|
|
||||
|
const getBoundaryLayer = async (url: string) => { |
||||
|
const layer = new FeatureLayer({ url }); |
||||
|
await layer.load(); |
||||
|
return layer; |
||||
|
}; |
||||
|
|
||||
|
const zoomToZoneGeometry = async (zoneValue: string) => { |
||||
|
if (!jimuMapView?.view || !zoneValue || zoneValue === "All") return; |
||||
|
|
||||
|
try { |
||||
|
const view = jimuMapView.view; |
||||
|
const zoneLayer = await getBoundaryLayer(ZONE_LAYER_URL); |
||||
|
|
||||
|
const query = zoneLayer.createQuery(); |
||||
|
query.where = `zone = '${safe(zoneValue)}'`; |
||||
|
query.outFields = ["zone"]; |
||||
|
query.returnGeometry = true; |
||||
|
|
||||
|
const result = await zoneLayer.queryFeatures(query); |
||||
|
if (result.features.length > 0) { |
||||
|
await view.goTo({ |
||||
|
target: result.features[0].geometry, |
||||
|
padding: { top: 50, bottom: 50, left: 50, right: 50 }, |
||||
|
duration: 1000, |
||||
|
}); |
||||
|
} |
||||
|
} catch (err) { |
||||
|
console.error("Error zooming to zone:", err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const zoomToWardGeometry = async (wardValue: string) => { |
||||
|
if (!jimuMapView?.view || !wardValue || wardValue === "All") return; |
||||
|
|
||||
|
try { |
||||
|
const view = jimuMapView.view; |
||||
|
const wardLayer = await getBoundaryLayer(WARD_LAYER_URL); |
||||
|
|
||||
|
const query = wardLayer.createQuery(); |
||||
|
query.where = `ward_no = '${safe(wardValue)}'`; |
||||
|
query.outFields = ["ward_no"]; |
||||
|
query.returnGeometry = true; |
||||
|
|
||||
|
const result = await wardLayer.queryFeatures(query); |
||||
|
if (result.features.length > 0) { |
||||
|
const geometry = result.features[0].geometry; |
||||
|
sessionStorage.setItem("wardgeometry", JSON.stringify(geometry.toJSON?.() ?? geometry)); |
||||
|
await view.goTo({ |
||||
|
target: geometry, |
||||
|
padding: { top: 50, bottom: 50, left: 50, right: 50 }, |
||||
|
duration: 1000, |
||||
|
}); |
||||
|
} |
||||
|
} catch (err) { |
||||
|
console.error("Error zooming to ward:", err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const fetchDistinctValues = async (fieldName: string, whereClause: string) => { |
||||
|
try { |
||||
|
const layer = new FeatureLayer({ url: ROAD_LAYER_URL }); |
||||
|
await layer.load(); |
||||
|
|
||||
|
const query = layer.createQuery(); |
||||
|
query.where = whereClause; |
||||
|
query.outFields = [fieldName]; |
||||
|
query.returnDistinctValues = true; |
||||
|
query.returnGeometry = false; |
||||
|
|
||||
|
const result = await layer.queryFeatures(query); |
||||
|
return Array.from( |
||||
|
new Set(result.features.map((f) => f.attributes[fieldName]).filter((v) => v != null && v !== "")) |
||||
|
) as string[]; |
||||
|
} catch (err) { |
||||
|
console.error(`Error fetching distinct ${fieldName}:`, err); |
||||
|
return []; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const populateZone = async () => { |
||||
|
const zones = await fetchDistinctValues("zone", "1=1"); |
||||
|
zones.sort((a, b) => String(a).localeCompare(String(b), undefined, { numeric: true })); |
||||
|
setZoneOptions(["All", ...zones]); |
||||
|
}; |
||||
|
|
||||
|
const populateWard = async () => { |
||||
|
let where = "1=1"; |
||||
|
if (selectedZone && selectedZone !== "All") { |
||||
|
where = `zone = '${safe(selectedZone)}'`; |
||||
|
} |
||||
|
const wards = await fetchDistinctValues("ward", where); |
||||
|
wards.sort((a, b) => String(a).localeCompare(String(b), undefined, { numeric: true })); |
||||
|
setWardOptions(["All", ...wards]); |
||||
|
}; |
||||
|
|
||||
|
const populateRoadNames = async () => { |
||||
|
let where = "1=1"; |
||||
|
if (selectedZone && selectedZone !== "All") { |
||||
|
where += ` AND zone = '${safe(selectedZone)}'`; |
||||
|
} |
||||
|
if (selectedWard && selectedWard !== "All") { |
||||
|
where += ` AND ward = '${safe(selectedWard)}'`; |
||||
|
} |
||||
|
const roads = await fetchDistinctValues("road_name", where); |
||||
|
roads.sort((a, b) => String(a).localeCompare(String(b), undefined, { numeric: true })); |
||||
|
setRoadNameOptions(["All", ...roads]); |
||||
|
setSelectedRoadName("All"); |
||||
|
}; |
||||
|
|
||||
|
useEffect(() => { |
||||
|
populateZone(); |
||||
|
}, []); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
populateWard(); |
||||
|
setSelectedWard(""); |
||||
|
setSelectedRoadName("All"); |
||||
|
}, [selectedZone]); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
populateRoadNames(); |
||||
|
}, [selectedZone, selectedWard]); |
||||
|
|
||||
|
const buildWhereClause = () => { |
||||
|
let where = "1=1"; |
||||
|
|
||||
|
if (selectedZone && selectedZone !== "All") { |
||||
|
where += ` AND zone='${safe(selectedZone)}'`; |
||||
|
} |
||||
|
if (selectedWard && selectedWard !== "All") { |
||||
|
where += ` AND ward='${safe(selectedWard)}'`; |
||||
|
} |
||||
|
if (selectedRoadName && selectedRoadName !== "All") { |
||||
|
where += ` AND road_name='${safe(selectedRoadName)}'`; |
||||
|
} |
||||
|
|
||||
|
return where; |
||||
|
}; |
||||
|
|
||||
|
const getRoadCount = async (whereClause: string) => { |
||||
|
try { |
||||
|
const layer = new FeatureLayer({ url: ROAD_LAYER_URL }); |
||||
|
const query = layer.createQuery(); |
||||
|
query.where = whereClause; |
||||
|
query.returnGeometry = false; |
||||
|
return await layer.queryFeatureCount(query); |
||||
|
} catch (err) { |
||||
|
console.error("Error counting roads:", err); |
||||
|
return 0; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const applyDefinitionToRoadLayer = async (whereClause: string) => { |
||||
|
const view = jimuMapView?.view; |
||||
|
if (!view) return; |
||||
|
|
||||
|
const layers = await getRoadLayersFromMap(); |
||||
|
for (const lyr of layers) { |
||||
|
try { |
||||
|
lyr.definitionExpression = whereClause; |
||||
|
const lv = await view.whenLayerView(lyr); |
||||
|
if (lv) { |
||||
|
lv.filter = { where: whereClause } as any; |
||||
|
} |
||||
|
} catch (err) { |
||||
|
console.error("Error applying definition expression:", err); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const zoomToFeatureGeometry = async (feature: any) => { |
||||
|
const view = jimuMapView?.view; |
||||
|
if (!view || !feature?.geometry) return; |
||||
|
|
||||
|
try { |
||||
|
const geom = feature.geometry; |
||||
|
if ((geom as any).extent) { |
||||
|
await view.goTo({ target: (geom as any).extent.expand(0.2), duration: 1000 }); |
||||
|
} else if ((geom as any).longitude !== undefined && (geom as any).latitude !== undefined) { |
||||
|
await view.goTo({ center: geom, zoom: 16, duration: 1000 }); |
||||
|
} else { |
||||
|
await view.goTo({ target: geom, duration: 1000 }); |
||||
|
} |
||||
|
} catch (err) { |
||||
|
console.error("Error zooming to feature:", err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const handleRowZoom = async (feature: any) => { |
||||
|
const view = jimuMapView?.view; |
||||
|
if (!view || !feature) return; |
||||
|
|
||||
|
try { |
||||
|
if (highlightHandle) { |
||||
|
highlightHandle.remove(); |
||||
|
setHighlightHandle(null); |
||||
|
} |
||||
|
|
||||
|
const layers = await getRoadLayersFromMap(); |
||||
|
const layerForHighlight = layers[0] ?? roadLayer; |
||||
|
|
||||
|
await layerForHighlight.load(); |
||||
|
const layerView = await view.whenLayerView(layerForHighlight); |
||||
|
const highlight = layerView.highlight(feature); |
||||
|
setHighlightHandle(highlight); |
||||
|
|
||||
|
await zoomToFeatureGeometry(feature); |
||||
|
} catch (err) { |
||||
|
console.error("Error highlighting/zooming row:", err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const handleSubmit = async (e: React.MouseEvent) => { |
||||
|
e.preventDefault(); |
||||
|
|
||||
|
if (!selectedZone || selectedZone === "") { |
||||
|
alert("Please select Zone"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
const whereClause = buildWhereClause(); |
||||
|
|
||||
|
const query = roadLayer.createQuery(); |
||||
|
query.where = whereClause; |
||||
|
query.outFields = ["*"]; |
||||
|
query.returnGeometry = true; |
||||
|
|
||||
|
const [count, results] = await Promise.all([ |
||||
|
getRoadCount(whereClause), |
||||
|
roadLayer.queryFeatures(query), |
||||
|
]); |
||||
|
|
||||
|
setRoadCount(count); |
||||
|
setTableData(results.features); |
||||
|
await applyDefinitionToRoadLayer(whereClause); |
||||
|
|
||||
|
if (results.features.length > 0) { |
||||
|
const extentResult = await roadLayer.queryExtent({ where: whereClause }); |
||||
|
if (extentResult.extent) { |
||||
|
await jimuMapView?.view.goTo({ |
||||
|
target: extentResult.extent.expand(0.2), |
||||
|
duration: 1000, |
||||
|
}); |
||||
|
} |
||||
|
} else { |
||||
|
alert("No records found for selected filters."); |
||||
|
} |
||||
|
} catch (err) { |
||||
|
console.error("Submit error:", err); |
||||
|
alert("An error occurred while querying roads."); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const clearRoadDefinition = async () => { |
||||
|
const view = jimuMapView?.view; |
||||
|
if (!view) return; |
||||
|
|
||||
|
const layers = await getRoadLayersFromMap(); |
||||
|
for (const lyr of layers) { |
||||
|
try { |
||||
|
lyr.definitionExpression = ""; |
||||
|
const lv = await view.whenLayerView(lyr); |
||||
|
if (lv) { |
||||
|
lv.filter = null; |
||||
|
} |
||||
|
} catch (err) { |
||||
|
console.error("Error clearing definition expression:", err); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const handleReset = async () => { |
||||
|
setSelectedZone(""); |
||||
|
setSelectedWard(""); |
||||
|
setSelectedRoadName("All"); |
||||
|
setWardOptions([]); |
||||
|
setRoadNameOptions([]); |
||||
|
setTableData([]); |
||||
|
setRoadCount(null); |
||||
|
|
||||
|
if (highlightHandle) { |
||||
|
highlightHandle.remove(); |
||||
|
setHighlightHandle(null); |
||||
|
} |
||||
|
|
||||
|
jimuMapView?.view?.graphics.removeAll(); |
||||
|
await clearRoadDefinition(); |
||||
|
}; |
||||
|
|
||||
|
const handleExportExcel = () => { |
||||
|
if (tableData.length === 0) { |
||||
|
alert("No data to export."); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const headers = ROAD_TABLE_FIELDS.map((f) => FIELD_ALIASES[f] || f); |
||||
|
const rows = tableData.map((feature, idx) => { |
||||
|
const a = feature.attributes; |
||||
|
return [ |
||||
|
idx + 1, |
||||
|
a.zone, |
||||
|
a.ward, |
||||
|
a.road_id, |
||||
|
a.road_name, |
||||
|
a.interior_brr, |
||||
|
a.res_b600, |
||||
|
a.res_600, |
||||
|
a.res_1200, |
||||
|
a.res_1800, |
||||
|
a.non_res, |
||||
|
a.education, |
||||
|
a.vac_res, |
||||
|
a.vac_non_res, |
||||
|
a.bsr_slab, |
||||
|
]; |
||||
|
}); |
||||
|
|
||||
|
const ws = XLSX.utils.aoa_to_sheet([["Sl.No", ...headers], ...rows]); |
||||
|
const wb = XLSX.utils.book_new(); |
||||
|
XLSX.utils.book_append_sheet(wb, ws, "Road Data"); |
||||
|
XLSX.writeFile(wb, `Road_Data_${new Date().toISOString().slice(0, 10)}.xlsx`); |
||||
|
}; |
||||
|
|
||||
|
const handleExportPDF = () => { |
||||
|
if (tableData.length === 0) { |
||||
|
alert("No data to export."); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const headers = ["Sl.No", ...ROAD_TABLE_FIELDS.map((f) => FIELD_ALIASES[f] || f)]; |
||||
|
const rows = tableData.map((feature, idx) => { |
||||
|
const a = feature.attributes; |
||||
|
return [ |
||||
|
idx + 1, |
||||
|
a.zone, |
||||
|
a.ward, |
||||
|
a.road_id, |
||||
|
a.road_name, |
||||
|
a.interior_brr, |
||||
|
a.res_b600, |
||||
|
a.res_600, |
||||
|
a.res_1200, |
||||
|
a.res_1800, |
||||
|
a.non_res, |
||||
|
a.education, |
||||
|
a.vac_res, |
||||
|
a.vac_non_res, |
||||
|
a.bsr_slab, |
||||
|
]; |
||||
|
}); |
||||
|
|
||||
|
const doc = new jsPDF({ orientation: "landscape" }); |
||||
|
doc.text(`Road Data - ${new Date().toLocaleDateString()}`, 14, 10); |
||||
|
|
||||
|
autoTable(doc, { |
||||
|
head: [headers], |
||||
|
body: rows, |
||||
|
startY: 18, |
||||
|
theme: "striped", |
||||
|
styles: { fontSize: 7, cellPadding: 2 }, |
||||
|
headStyles: { fillColor: [41, 128, 185], textColor: 255 }, |
||||
|
}); |
||||
|
|
||||
|
doc.save(`Road_Data_${new Date().toISOString().slice(0, 10)}.pdf`); |
||||
|
}; |
||||
|
|
||||
|
useEffect(() => { |
||||
|
const interval = setInterval(() => { |
||||
|
const view = mapViewManager.getMapView(); |
||||
|
if (view && view.view) { |
||||
|
setJimuMapView(view); |
||||
|
clearInterval(interval); |
||||
|
} |
||||
|
}, 500); |
||||
|
return () => clearInterval(interval); |
||||
|
}, []); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
const autoCount = async () => { |
||||
|
if (!selectedZone) { |
||||
|
setRoadCount(null); |
||||
|
return; |
||||
|
} |
||||
|
const whereClause = buildWhereClause(); |
||||
|
const count = await getRoadCount(whereClause); |
||||
|
setRoadCount(count); |
||||
|
}; |
||||
|
autoCount(); |
||||
|
}, [selectedZone, selectedWard, selectedRoadName]); |
||||
|
|
||||
|
return ( |
||||
|
<div className="property-widget-parent"> |
||||
|
<div className="property-widget"> |
||||
|
<JimuMapViewComponent |
||||
|
useMapWidgetId={props.useMapWidgetIds?.[0]} |
||||
|
onActiveViewChange={(jmv: JimuMapView) => { |
||||
|
if (jmv && jmv.view) setJimuMapView(jmv); |
||||
|
}} |
||||
|
/> |
||||
|
|
||||
|
<h3 className="widget-title">Road Search</h3> |
||||
|
|
||||
|
<div id="countDiv"> |
||||
|
<strong>Road Count:</strong>{" "} |
||||
|
<span id="roadCount">{roadCount !== null ? roadCount : "-"}</span> |
||||
|
</div> |
||||
|
|
||||
|
<div className="property_form"> |
||||
|
<label> |
||||
|
Zone:<span style={{ color: "red" }}>*</span> |
||||
|
</label> |
||||
|
<select |
||||
|
value={selectedZone} |
||||
|
onChange={(e) => { |
||||
|
const v = e.target.value; |
||||
|
setSelectedZone(v); |
||||
|
zoomToZoneGeometry(v); |
||||
|
}} |
||||
|
required |
||||
|
> |
||||
|
<option value="">--Select Zone--</option> |
||||
|
{zoneOptions.map((zone) => ( |
||||
|
<option key={zone} value={zone}> |
||||
|
{zone} |
||||
|
</option> |
||||
|
))} |
||||
|
</select> |
||||
|
</div> |
||||
|
|
||||
|
<div className="property_form"> |
||||
|
<label>Ward:</label> |
||||
|
<select |
||||
|
value={selectedWard} |
||||
|
onChange={(e) => { |
||||
|
const v = e.target.value; |
||||
|
setSelectedWard(v); |
||||
|
zoomToWardGeometry(v); |
||||
|
}} |
||||
|
> |
||||
|
<option value="">--Select Ward--</option> |
||||
|
{wardOptions.map((ward) => ( |
||||
|
<option key={ward} value={ward}> |
||||
|
{ward} |
||||
|
</option> |
||||
|
))} |
||||
|
</select> |
||||
|
</div> |
||||
|
|
||||
|
<div className="property_form"> |
||||
|
<label>Road Name:</label> |
||||
|
<select |
||||
|
value={selectedRoadName} |
||||
|
onChange={(e) => setSelectedRoadName(e.target.value)} |
||||
|
> |
||||
|
{roadNameOptions.map((name) => ( |
||||
|
<option key={name} value={name}> |
||||
|
{name} |
||||
|
</option> |
||||
|
))} |
||||
|
</select> |
||||
|
</div> |
||||
|
|
||||
|
<button className="property_form" onClick={handleSubmit}> |
||||
|
Submit |
||||
|
</button> |
||||
|
<button className="property_form outlined" onClick={handleReset}> |
||||
|
Reset |
||||
|
</button> |
||||
|
|
||||
|
{tableData.length > 0 && ( |
||||
|
<div className="attribute-table"> |
||||
|
<div |
||||
|
style={{ |
||||
|
display: "flex", |
||||
|
justifyContent: "space-between", |
||||
|
alignItems: "center", |
||||
|
}} |
||||
|
> |
||||
|
<h4>Feature Details</h4> |
||||
|
<div> |
||||
|
<button onClick={handleExportExcel} style={{ marginRight: "8px" }}> |
||||
|
Export Excel |
||||
|
</button> |
||||
|
<button onClick={handleExportPDF}>Export PDF</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div style={{ maxHeight: "400px", overflowY: "auto" }}> |
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th className="sticky-header">Sl.No</th> |
||||
|
{ROAD_TABLE_FIELDS.map((field) => ( |
||||
|
<th key={field} className="sticky-header"> |
||||
|
{FIELD_ALIASES[field] || field} |
||||
|
</th> |
||||
|
))} |
||||
|
<th className="sticky-header">Action</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{tableData.map((feature, index) => { |
||||
|
const a = feature.attributes; |
||||
|
return ( |
||||
|
<tr key={index}> |
||||
|
<td>{index + 1}</td> |
||||
|
<td>{a.zone}</td> |
||||
|
<td>{a.ward}</td> |
||||
|
<td>{a.road_id}</td> |
||||
|
<td>{a.road_name}</td> |
||||
|
<td>{a.interior_brr}</td> |
||||
|
<td>{a.res_b600}</td> |
||||
|
<td>{a.res_600}</td> |
||||
|
<td>{a.res_1200}</td> |
||||
|
<td>{a.res_1800}</td> |
||||
|
<td>{a.non_res}</td> |
||||
|
<td>{a.education}</td> |
||||
|
<td>{a.vac_res}</td> |
||||
|
<td>{a.vac_non_res}</td> |
||||
|
<td>{a.bsr_slab}</td> |
||||
|
<td> |
||||
|
<button |
||||
|
onClick={(e) => { |
||||
|
e.stopPropagation(); |
||||
|
handleRowZoom(feature); |
||||
|
}} |
||||
|
style={{ background: "none", border: "none", cursor: "pointer" }} |
||||
|
title="Zoom to this feature" |
||||
|
> |
||||
|
<img |
||||
|
src={zoomInIcon} |
||||
|
alt="Zoom" |
||||
|
style={{ width: "16px", height: "16px" }} |
||||
|
/> |
||||
|
</button> |
||||
|
</td> |
||||
|
</tr> |
||||
|
); |
||||
|
})} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
)} |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default RoadAssetFilter; |
||||
@ -0,0 +1,20 @@ |
|||||
|
import { React } from 'jimu-core' |
||||
|
import { type AllWidgetSettingProps } from 'jimu-for-builder' |
||||
|
import { MapWidgetSelector } from 'jimu-ui/advanced/setting-components' |
||||
|
|
||||
|
const Setting = (props: AllWidgetSettingProps<any>) => { |
||||
|
const onMapWidgetSelected = (useMapWidgetIds: string[]) => { |
||||
|
console.log("Selected Map Widget IDs:", useMapWidgetIds); |
||||
|
props.onSettingChange({ |
||||
|
id: props.id, |
||||
|
useMapWidgetIds: useMapWidgetIds |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
return <div className="widget-setting-demo"> |
||||
|
<MapWidgetSelector useMapWidgetIds={props.useMapWidgetIds} onSelect={onMapWidgetSelected} /> |
||||
|
</div> |
||||
|
} |
||||
|
|
||||
|
export default Setting |
||||
|
|
||||
|
After Width: 512 | Height: 512 | Size: 23 KiB |
@ -0,0 +1,14 @@ |
|||||
|
import { React } from 'jimu-core' |
||||
|
import _Widget from '../src/runtime/widget' |
||||
|
import { widgetRender, wrapWidget } from 'jimu-for-test' |
||||
|
|
||||
|
const render = widgetRender() |
||||
|
describe('test simple widget', () => { |
||||
|
it('simple test', () => { |
||||
|
const Widget = wrapWidget(_Widget, { |
||||
|
config: { exampleConfigProperty: 'a' } |
||||
|
}) |
||||
|
const { queryByText } = render(<Widget widgetId="Widget_1" />) |
||||
|
expect(queryByText('exampleConfigProperty: a').tagName).toBe('P') |
||||
|
}) |
||||
|
}) |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue