diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..c043e5f
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,38 @@
+{
+ "parserOptions": {
+ "ecmaVersion": 6,
+ "sourceType": "module"
+ },
+ "env": {
+ "browser": true,
+ "es6": true
+ },
+ "extends": "eslint:recommended",
+ "globals": {
+ "M": true,
+ "ol": true,
+ "CustomEvent": true,
+ "Handlebars": true,
+ "proj4": true,
+ "ActiveXObject": true,
+ "jsts": true,
+ "document": true,
+ "window": true,
+ "DOMParser": true,
+ "XMLHttpRequest": true,
+ "Image": true,
+ "Draggabilly": true,
+ "XMLSerializer": true
+ },
+ "rules": {
+ "import/no-absolute-path": "off",
+ "no-console":"off", //0 = off, 1 = warn, 2 = error
+ "no-unused-vars": [
+ "error",
+ {
+ "vars": "all",
+ "args": "none"
+ }
+ ]
+ }
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6067958
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,274 @@
+European Union Public Licence
+V. 1.2
+
+EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as
+defined below) which is provided under the terms of this Licence. Any use of
+the Work, other than as authorised under this Licence is prohibited (to the
+extent such use is covered by a right of the copyright holder of the Work).
+
+The Work is provided under the terms of this Licence when the Licensor (as
+defined below) has placed the following notice immediately following the
+copyright notice for the Work: “Licensed under the EUPL”, or has expressed by
+any other means his willingness to license under the EUPL.
+
+1. Definitions
+
+In this Licence, the following terms have the following meaning:
+— ‘The Licence’: this Licence.
+— ‘The Original Work’: the work or software distributed or communicated by the
+ ‘Licensor under this Licence, available as Source Code and also as
+ ‘Executable Code as the case may be.
+— ‘Derivative Works’: the works or software that could be created by the
+ ‘Licensee, based upon the Original Work or modifications thereof. This
+ ‘Licence does not define the extent of modification or dependence on the
+ ‘Original Work required in order to classify a work as a Derivative Work;
+ ‘this extent is determined by copyright law applicable in the country
+ ‘mentioned in Article 15.
+— ‘The Work’: the Original Work or its Derivative Works.
+— ‘The Source Code’: the human-readable form of the Work which is the most
+ convenient for people to study and modify.
+
+— ‘The Executable Code’: any code which has generally been compiled and which
+ is meant to be interpreted by a computer as a program.
+— ‘The Licensor’: the natural or legal person that distributes or communicates
+ the Work under the Licence.
+— ‘Contributor(s)’: any natural or legal person who modifies the Work under
+ the Licence, or otherwise contributes to the creation of a Derivative Work.
+— ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
+ the Work under the terms of the Licence.
+— ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
+ renting, distributing, communicating, transmitting, or otherwise making
+ available, online or offline, copies of the Work or providing access to its
+ essential functionalities at the disposal of any other natural or legal
+ person.
+
+2. Scope of the rights granted by the Licence
+
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+sublicensable licence to do the following, for the duration of copyright
+vested in the Original Work:
+
+— use the Work in any circumstance and for all usage,
+— reproduce the Work,
+— modify the Work, and make Derivative Works based upon the Work,
+— communicate to the public, including the right to make available or display
+ the Work or copies thereof to the public and perform publicly, as the case
+ may be, the Work,
+— distribute the Work or copies thereof,
+— lend and rent the Work or copies thereof,
+— sublicense rights in the Work or copies thereof.
+
+Those rights can be exercised on any media, supports and formats, whether now
+known or later invented, as far as the applicable law permits so.
+
+In the countries where moral rights apply, the Licensor waives his right to
+exercise his moral right to the extent allowed by law in order to make
+effective the licence of the economic rights here above listed.
+
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights
+to any patents held by the Licensor, to the extent necessary to make use of
+the rights granted on the Work under this Licence.
+
+3. Communication of the Source Code
+
+The Licensor may provide the Work either in its Source Code form, or as
+Executable Code. If the Work is provided as Executable Code, the Licensor
+provides in addition a machine-readable copy of the Source Code of the Work
+along with each copy of the Work that the Licensor distributes or indicates,
+in a notice following the copyright notice attached to the Work, a repository
+where the Source Code is easily and freely accessible for as long as the
+Licensor continues to distribute or communicate the Work.
+
+4. Limitations on copyright
+
+Nothing in this Licence is intended to deprive the Licensee of the benefits
+from any exception or limitation to the exclusive rights of the rights owners
+in the Work, of the exhaustion of those rights or of other applicable
+limitations thereto.
+
+5. Obligations of the Licensee
+
+The grant of the rights mentioned above is subject to some restrictions and
+obligations imposed on the Licensee. Those obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or
+trademarks notices and all notices that refer to the Licence and to the
+disclaimer of warranties. The Licensee must include a copy of such notices and
+a copy of the Licence with every copy of the Work he/she distributes or
+communicates. The Licensee must cause any Derivative Work to carry prominent
+notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the
+Original Works or Derivative Works, this Distribution or Communication will be
+done under the terms of this Licence or of a later version of this Licence
+unless the Original Work is expressly distributed only under this version of
+the Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
+(becoming Licensor) cannot offer or impose any additional terms or conditions
+on the Work or Derivative Work that alter or restrict the terms of the
+Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative
+Works or copies thereof based upon both the Work and another work licensed
+under a Compatible Licence, this Distribution or Communication can be done
+under the terms of this Compatible Licence. For the sake of this clause,
+‘Compatible Licence’ refers to the licences listed in the appendix attached to
+this Licence. Should the Licensee's obligations under the Compatible Licence
+conflict with his/her obligations under this Licence, the obligations of the
+Compatible Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the
+Work, the Licensee will provide a machine-readable copy of the Source Code or
+indicate a repository where this Source will be easily and freely available
+for as long as the Licensee continues to distribute or communicate the Work.
+
+Legal Protection: This Licence does not grant permission to use the trade
+names, trademarks, service marks, or names of the Licensor, except as required
+for reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6. Chain of Authorship
+
+The original Licensor warrants that the copyright in the Original Work granted
+hereunder is owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each Contributor warrants that the copyright in the modifications he/she
+brings to the Work are owned by him/her or licensed to him/her and that he/she
+has the power and authority to grant the Licence.
+
+Each time You accept the Licence, the original Licensor and subsequent
+Contributors grant You a licence to their contributions to the Work, under the
+terms of this Licence.
+
+7. Disclaimer of Warranty
+
+The Work is a work in progress, which is continuously improved by numerous
+Contributors. It is not a finished work and may therefore contain defects or
+‘bugs’ inherent to this type of development.
+
+For the above reason, the Work is provided under the Licence on an ‘as is’
+basis and without warranties of any kind concerning the Work, including
+without limitation merchantability, fitness for a particular purpose, absence
+of defects or errors, accuracy, non-infringement of intellectual property
+rights other than copyright as stated in Article 6 of this Licence.
+
+This disclaimer of warranty is an essential part of the Licence and a
+condition for the grant of any rights to the Work.
+
+8. Disclaimer of Liability
+
+Except in the cases of wilful misconduct or damages directly caused to natural
+persons, the Licensor will in no event be liable for any direct or indirect,
+material or moral, damages of any kind, arising out of the Licence or of the
+use of the Work, including without limitation, damages for loss of goodwill,
+work stoppage, computer failure or malfunction, loss of data or any commercial
+damage, even if the Licensor has been advised of the possibility of such
+damage. However, the Licensor will be liable under statutory product liability
+laws as far such laws apply to the Work.
+
+9. Additional agreements
+
+While distributing the Work, You may choose to conclude an additional
+agreement, defining obligations or services consistent with this Licence.
+However, if accepting obligations, You may act only on your own behalf and on
+your sole responsibility, not on behalf of the original Licensor or any other
+Contributor, and only if You agree to indemnify, defend, and hold each
+Contributor harmless for any liability incurred by, or claims asserted against
+such Contributor by the fact You have accepted any warranty or additional
+liability.
+
+10. Acceptance of the Licence
+
+The provisions of this Licence can be accepted by clicking on an icon ‘I
+agree’ placed under the bottom of a window displaying the text of this Licence
+or by affirming consent in any other similar way, in accordance with the rules
+of applicable law. Clicking on that icon indicates your clear and irrevocable
+acceptance of this Licence and all of its terms and conditions.
+
+Similarly, you irrevocably accept this Licence and all of its terms and
+conditions by exercising any rights granted to You by Article 2 of this
+Licence, such as the use of the Work, the creation by You of a Derivative Work
+or the Distribution or Communication by You of the Work or copies thereof.
+
+11. Information to the public
+
+In case of any Distribution or Communication of the Work by means of
+electronic communication by You (for example, by offering to download the Work
+from a remote location) the distribution channel or media (for example, a
+website) must at least provide to the public the information requested by the
+applicable law regarding the Licensor, the Licence and the way it may be
+accessible, concluded, stored and reproduced by the Licensee.
+
+12. Termination of the Licence
+
+The Licence and the rights granted hereunder will terminate automatically upon
+any breach by the Licensee of the terms of the Licence. Such a termination
+will not terminate the licences of any person who has received the Work from
+the Licensee under the Licence, provided such persons remain in full
+compliance with the Licence.
+
+13. Miscellaneous
+
+Without prejudice of Article 9 above, the Licence represents the complete
+agreement between the Parties as to the Work.
+
+If any provision of the Licence is invalid or unenforceable under applicable
+law, this will not affect the validity or enforceability of the Licence as a
+whole. Such provision will be construed or reformed so as necessary to make it
+valid and enforceable.
+
+The European Commission may publish other linguistic versions or new versions
+of this Licence or updated versions of the Appendix, so far this is required
+and reasonable, without reducing the scope of the rights granted by the
+Licence. New versions of the Licence will be published with a unique version
+number.
+
+All linguistic versions of this Licence, approved by the European Commission,
+have identical value. Parties can take advantage of the linguistic version of
+their choice.
+
+14. Jurisdiction
+
+Without prejudice to specific agreement between parties,
+— any litigation resulting from the interpretation of this License, arising
+ between the European Union institutions, bodies, offices or agencies, as a
+ Licensor, and any Licensee, will be subject to the jurisdiction of the Court
+ of Justice of the European Union, as laid down in article 272 of the Treaty
+ on the Functioning of the European Union,
+— any litigation arising between other parties and resulting from the
+ interpretation of this License, will be subject to the exclusive
+ jurisdiction of the competent court where the Licensor resides or conducts
+ its primary business.
+
+15. Applicable Law
+
+Without prejudice to specific agreement between parties,
+— this Licence shall be governed by the law of the European Union Member State
+ where the Licensor has his seat, resides or has his registered office,
+— this licence shall be governed by Belgian law if the Licensor has no seat,
+ residence or registered office inside a European Union Member State.
+
+Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+— GNU General Public License (GPL) v. 2, v. 3
+— GNU Affero General Public License (AGPL) v. 3
+— Open Software License (OSL) v. 2.1, v. 3.0
+— Eclipse Public License (EPL) v. 1.0
+— CeCILL v. 2.0, v. 2.1
+— Mozilla Public Licence (MPL) v. 2
+— GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+— Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
+ works other than software
+— European Union Public Licence (EUPL) v. 1.1, v. 1.2
+— Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or
+ Strong Reciprocity (LiLiQ-R+)
+
+— The European Commission may update this Appendix to later versions of the
+ above licences without producing a new version of the EUPL, as long as they
+ provide the rights granted in Article 2 of this Licence and protect the
+ covered Source Code from exclusive appropriation.
+— All other changes or additions to this Appendix require the production of a
+ new EUPL version.
diff --git a/README.md b/README.md
deleted file mode 100644
index 83e0fae..0000000
--- a/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# mirrorpanel
-Mapas sincronizados
diff --git a/dist/api.json b/dist/api.json
new file mode 100644
index 0000000..53c0a1a
--- /dev/null
+++ b/dist/api.json
@@ -0,0 +1,120 @@
+{
+ "url": {
+ "name": "mirrorpanel",
+ "separator": "*!"
+ },
+ "constructor": "M.plugin.Mirrorpanel",
+ "parameters": [
+ {
+ "type": "object",
+ "properties": [
+ {
+ "type": "simple",
+ "name": "position",
+ "possibleValues": [
+ "TL",
+ "TR",
+ "BL",
+ "BR"
+ ],
+ "position": 0
+ },
+ {
+ "type": "boolean",
+ "name": "collapsed",
+ "position": 1
+ },
+ {
+ "type": "boolean",
+ "name": "collapsible",
+ "position": 2
+ },
+ {
+ "type": "simple",
+ "name": "modeViz",
+ "position": 3
+ },
+ {
+ "type": "boolean",
+ "name": "enabledKeyFunctions",
+ "position": 4
+ },
+ {
+ "type": "boolean",
+ "name": "showCursors",
+ "position": 5
+ },
+ {
+ "type": "simple",
+ "name": "mirrorLayers",
+ "position": 6
+ },
+ {
+ "type": "simple",
+ "name": "defaultBaseLyrs",
+ "position": 7
+ },
+ {
+ "type": "boolean",
+ "name": "interface",
+ "position": 8
+ },
+ {
+ "type": "boolean",
+ "name": "showToc",
+ "position": 9
+ }
+ ]
+ }
+ ],
+ "files": {
+ "ol": {
+ "scripts": ["mirrorpanel.ol.min.js"],
+ "styles": ["mirrorpanel.ol.min.css"]
+ }
+ },
+ "metadata": {
+ "uuid_plugin": "",
+ "uuid_version_plugin": "",
+ "version_ficha_metadatos": "",
+ "name": "Mirrorpanel",
+ "description": "Plugin que permite comparar varias capas dividiendo la pantalla en varias partes.",
+ "text": "Plugin que permite comparar varias capas dividiendo la pantalla en varias partes. Los mapas tienen sus vistas sincronizadas, y podemos ver la representación de una misma zona por distintas capas.",
+ "version": "1.0.0",
+ "date": "Julio, 2020",
+ "author": "",
+ "org": "",
+ "tags": "mapea,plugin",
+ "icon": "./facade/assets/icons/icons.svg",
+ "buttons": [
+ {
+ "title": "",
+ "description": "",
+ "querySelector": ""
+ },
+ {
+ "title": "",
+ "description": "",
+ "querySelector": ""
+ }
+ ],
+ "dependencies": {
+ "modules": [
+ "",
+ ""
+ ],
+ "plugins": [
+ {
+ "uuid": "",
+ "name": ""
+ }
+ ],
+ "services": [
+ {
+ "name": "",
+ "description": ""
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/dist/mirrorpanel.ol.min.css b/dist/mirrorpanel.ol.min.css
new file mode 100644
index 0000000..9873d82
--- /dev/null
+++ b/dist/mirrorpanel.ol.min.css
@@ -0,0 +1 @@
+@font-face{font-family:mirrorpanel;src:url(data:application/vnd.ms-fontobject;base64,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);src:url(data:application/vnd.ms-fontobject;base64,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#iefix) format("embedded-opentype"),url(data:font/ttf;base64,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) format("truetype"),url(data:font/woff;base64,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) format("woff"),url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiID4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8bWV0YWRhdGE+R2VuZXJhdGVkIGJ5IEljb01vb248L21ldGFkYXRhPgo8ZGVmcz4KPGZvbnQgaWQ9Im1pcnJvcnBhbmVsIiBob3Jpei1hZHYteD0iMTAyNCI+Cjxmb250LWZhY2UgdW5pdHMtcGVyLWVtPSIxMDI0IiBhc2NlbnQ9Ijg3MC40IiBkZXNjZW50PSItMTUzLjYiIC8+CjxtaXNzaW5nLWdseXBoIGhvcml6LWFkdi14PSIxMDI0IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjA7IiBkPSIiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlODAyOyIgZ2x5cGgtbmFtZT0iaWNvbiIgZD0iTTMyMC41MTIgNTQ0LjUxMmwtMTkyLjUxMi0xOTIuNTEyIDE5Mi41MTItMTkxLjQ4OHYxMjhoMzg0di0xMjhsMTkxLjQ4OCAxOTEuNDg4LTE5MS40ODggMTkyLjUxMnYtMTI4aC0zODR2MTI4ek01MTIgODY0bC01MTItMzE5LjQ4OHYtNzA0LjUxMmw1MTIgMjU2IDUxMi0yNTZ2NzA0LjUxMmwtNTEyIDMxOS40ODh6TTk2MC41MTItMzJsLTM4NCAxOTIuNTEydjYzLjQ4OGgtMTI4di02My40ODhsLTM4NC0xOTIuNTEydjUxMmwzODQgMjU2di0yNTZoMTI4djI1NmwzODQtMjU2di01MTJ6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTgwMzsiIGdseXBoLW5hbWU9Im1vZGV2aXoxIiBkPSJNMTMyLjkxNCA4NjRjLTczLjEwOSAwLTEzMi44OS01OS43NzQtMTMyLjg5LTEzMi44ODJ2LTc1OC4yN2MwLTczLjEwOCA1OS43NzgtMTMyLjg5IDEzMi44OS0xMzIuODloNzU4LjI4NmM3My4xMDggMCAxMzIuODY1IDU5Ljc4IDEzMi44NjUgMTMyLjg5djc1OC4yN2MwIDczLjEwNi01OS43NTcgMTMyLjg4Mi0xMzIuODY1IDEzMi44ODJ6TTEzMi45MTQgNzk0LjgxOWgzNDYuMzU4di04ODUuNjMzaC0zNDYuMzU4Yy0zNi4wMjMgMC02My43MDEgMjcuNjc4LTYzLjcwMSA2My43MDF2NzU4LjI3YzAgMzYuMDIzIDI3LjY3OCA2My43MDEgNjMuNzAxIDYzLjcwMXpNNTQ0LjgxNyA3OTQuODE5aDM0Ni4zODJjMzYuMDIzIDAgNjMuNjg0LTI3LjY3NSA2My42ODQtNjMuNzAxdi03NTguMjdjMC0zNi4wMjYtMjcuNjYxLTYzLjcwMS02My42ODQtNjMuNzAxaC0zNDYuMzgyeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU4MDQ7IiBnbHlwaC1uYW1lPSJtb2Rldml6MCIgZD0iTTEzMi45MTQgODY0Yy03My4xMDkgMC0xMzIuODgyLTU5Ljc3My0xMzIuODgyLTEzMi44ODJ2LTc1OC4yN2MwLTczLjEwOSA1OS43NzMtMTMyLjg4MiAxMzIuODgyLTEzMi44ODJoNzU4LjI4NmM3My4xMDkgMCAxMzIuODY1IDU5Ljc3NiAxMzIuODY1IDEzMi44ODJ2NzU4LjI3YzAgNzMuMTA3LTU5Ljc1NiAxMzIuODgyLTEzMi44NjUgMTMyLjg4MnpNMTMyLjkxNCA3OTQuODE1aDc1OC4yODZjMzYuMDIzIDAgNjMuNjgtMjcuNjcgNjMuNjgtNjMuNjk3di03NTguMjdjMC0zNi4wMjYtMjcuNjU3LTYzLjcwMS02My42OC02My43MDFoLTc1OC4yODZjLTM2LjAyMyAwLTYzLjcwMSAyNy42NzgtNjMuNzAxIDYzLjcwMXY3NTguMjdjMCAzNi4wMjMgMjcuNjc4IDYzLjY5NyA2My43MDEgNjMuNjk3eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGU4MDU7IiBnbHlwaC1uYW1lPSJtb2Rldml6MiIgZD0iTTEzMi45MTQgODY0Yy03My4xMDggMC0xMzIuODgyLTU5Ljc3My0xMzIuODgyLTEzMi44ODJ2LTc1OC4yN2MwLTczLjEwOSA1OS43NzQtMTMyLjg5IDEzMi44ODItMTMyLjg5aDc1OC4yODZjNzMuMTA4IDAgMTMyLjg3MyA1OS43OCAxMzIuODczIDEzMi44OXY3NTguMjdjMCA3My4xMDctNTkuNzYyIDEzMi44ODItMTMyLjg3MyAxMzIuODgyek0xMzIuOTE0IDc5NC44MTloMTg2LjYxN3YtODg1LjYzM2gtMTg2LjYxN2MtMzYuMDIzIDAtNjMuNzAxIDI3LjY3OC02My43MDEgNjMuNzAxdjc1OC4yN2MwIDM2LjAyMyAyNy42NzggNjMuNzAxIDYzLjcwMSA2My43MDF6TTM4NS4wNzYgNzk0LjgxOWgyNTMuOTUzdi04ODUuNjMzaC0yNTMuOTUzek03MDQuNTc1IDc5NC44MTloMTg2LjYyNWMzNi4wMjMgMCA2My42ODQtMjcuNjc1IDYzLjY4NC02My43MDF2LTc1OC4yN2MwLTM2LjAyNi0yNy42NjEtNjMuNzAxLTYzLjY4NC02My43MDFoLTE4Ni42MjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTgwNjsiIGdseXBoLW5hbWU9Im1vZGV2aXozIiBkPSJNMTMyLjkxNCA4NjRjLTczLjEwOSAwLTEzMi44ODItNTkuNzc0LTEzMi44ODItMTMyLjg4MnYtNzU4LjI3YzAtNzMuMTA5IDU5Ljc3My0xMzIuODkgMTMyLjg4Mi0xMzIuODloNzU4LjI4NmM3My4xMDkgMCAxMzIuODY1IDU5Ljc4IDEzMi44NjUgMTMyLjg5djc1OC4yN2MwIDczLjEwNy01OS43NTcgMTMyLjg4Mi0xMzIuODY1IDEzMi44ODJ6TTEzMi45MTQgNzk0LjgxOWgxMDYuNzN2LTg4NS42MzNoLTEwNi43M2MtMzYuMDIyIDAtNjMuNjk3IDI3LjY3OC02My42OTcgNjMuNzAxdjc1OC4yN2MwIDM2LjAyMyAyNy42NzQgNjMuNzAxIDYzLjY5NyA2My43MDF6TTMwNS4xOSA3OTQuODE5aDE3NC4wOTF2LTg4NS42MzNoLTE3NC4wOTF6TTU0NC44MjYgNzk0LjgxOWgxNzQuMDgydi04ODUuNjMzaC0xNzQuMDgyek03ODQuNDU0IDc5NC44MTloMTA2Ljc0NmMzNi4wMjMgMCA2My42ODQtMjcuNjc1IDYzLjY4NC02My43MDF2LTc1OC4yN2MwLTM2LjAyNy0yNy42NjItNjMuNzAxLTYzLjY4NC02My43MDFoLTEwNi43NDZ6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTgwNzsiIGdseXBoLW5hbWU9Im1vZGV2aXo3IiBkPSJNMTMyLjkxNCA4NjRjLTczLjEwOSAwLTEzMi44ODItNTkuNzczLTEzMi44ODItMTMyLjg4MnYtNzU4LjI3YzAtNzMuMTA5IDU5Ljc3NC0xMzIuODgyIDEzMi44ODItMTMyLjg4Mmg3NTguMjg2YzczLjEwOCAwIDEzMi44NjUgNTkuNzc2IDEzMi44NjUgMTMyLjg4MnY3NTguMjdjMCA3My4xMDYtNTkuNzU3IDEzMi44ODItMTMyLjg2NSAxMzIuODgyek0xMzIuOTE0IDc5NC44MTloMzQ2LjM2NnYtODg1LjYzM2gtMzQ2LjM2NmMtMzYuMDIzIDAtNjMuNjk3IDI3LjY3OC02My42OTcgNjMuNzAxdjc1OC4yN2MwIDM2LjAyMyAyNy42NzQgNjMuNzAxIDYzLjY5NyA2My43MDF6TTU0NC44MjYgNzk0LjgxOWgxNzQuMDY2di04ODUuNjMzaC0xNzQuMDY2ek03ODQuNDU0IDc5NC44MTloMTA2Ljc0NmMzNi4wMjMgMCA2My42ODQtMjcuNjc1IDYzLjY4NC02My43MDF2LTc1OC4yN2MwLTM2LjAyNi0yNy42NjEtNjMuNzAxLTYzLjY4NC02My43MDFoLTEwNi43NDZ6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTgwODsiIGdseXBoLW5hbWU9Im1vZGV2aXo1IiBkPSJNMTMyLjkxNCA4NjRjLTczLjEwOSAwLTEzMi44OS01OS43NTctMTMyLjg5LTEzMi44NjV2LTc1OC4yODZjMC03My4xMDkgNTkuNzc3LTEzMi44ODIgMTMyLjg5LTEzMi44ODJoNzU4LjI4NmM3My4xMDkgMCAxMzIuODY1IDU5Ljc3NiAxMzIuODY1IDEzMi44ODJ2NzU4LjI4NmMwIDczLjEwNi01OS43NTcgMTMyLjg2NS0xMzIuODY1IDEzMi44NjV6TTEzMi45MTQgNzk0LjgzMWgzNDYuMzY2di00MDkuODUyaC00MTAuMDY0djM0Ni4xNTRjMCAzNi4wMjMgMjcuNjc4IDYzLjY5NyA2My43MDEgNjMuNjk3ek01NDQuODE3IDc5NC44MzFoMzQ2LjM4MmMzNi4wMjMgMCA2My42ODQtMjcuNjcgNjMuNjg0LTYzLjY5N3YtMzQ2LjE1NGgtNDEwLjA2NHpNNjkuMjA4IDMxOS4wMDJoNDEwLjA2NHYtNDA5Ljg2aC0zNDYuMzU4Yy0zNi4wMjMgMC02My43MDEgMjcuNjc0LTYzLjcwMSA2My42OTd6TTU0NC44MTcgMzE5LjAwMmg0MTAuMDY0di0zNDYuMTYzYzAtMzYuMDI3LTI3LjY2Mi02My42OTctNjMuNjg0LTYzLjY5N2gtMzQ2LjM4MnoiIC8+CjxnbHlwaCB1bmljb2RlPSImI3hlODA5OyIgZ2x5cGgtbmFtZT0ibW9kZXZpejgiIGQ9Ik0xMzIuOTE0IDg2NGMtNzMuMTA5IDAtMTMyLjg4Mi01OS43NzctMTMyLjg4Mi0xMzIuODl2LTc1OC4yN2MwLTczLjEwOSA1OS43NzQtMTMyLjg4MiAxMzIuODgyLTEzMi44ODJoNzU4LjI4NmM3My4xMDggMCAxMzIuODczIDU5Ljc3NiAxMzIuODczIDEzMi44ODJ2NzU4LjI3YzAgNzMuMTA3LTU5Ljc2MSAxMzIuODktMTMyLjg3MyAxMzIuODl6TTEzMi45MTQgNzk0LjgxNWg3NTguMjg2YzM2LjAyMyAwIDYzLjY4NC0yNy42NzQgNjMuNjg0LTYzLjcwMXYtMzQ2LjEzOGgtODg1LjYzM3YzNDYuMTM4YzAgMzYuMDIzIDI3LjY3OCA2My43MDEgNjMuNzAxIDYzLjcwMXpNNjkuMjEzIDMxOS4wMDJoNDEwLjA2NHYtNDA5Ljg2aC0zNDYuMzY2Yy0zNi4wMjMgMC02My43MDEgMjcuNjc4LTYzLjcwMSA2My43MDF6TTU0NC44MjIgMzE5LjAwMmg0MTAuMDY0di0zNDYuMTU0YzAtMzYuMDI2LTI3LjY2MS02My43MDEtNjMuNjg0LTYzLjcwMWgtMzQ2LjM4MnoiIC8+CjwvZm9udD48L2RlZnM+PC9zdmc+#mirrorpanel) format("svg");font-weight:400;font-style:normal;font-display:block}.info{position:absolute;width:60%;padding:5px;top:10px;left:20%;background:hsla(0,0%,96.1%,.8);font-size:large;border-radius:5px;border-style:dashed;border-width:2px;text-align:center}.m-panel-btn.mirrorpanel-icon{color:#718bd3!important}.m-plugin-panelMirrorpanel.hidden{display:none}div.m-plugin-panelMirrorpanel.opened>.m-panel-btn.g-cartografia-flecha-derecha,div.m-plugin-panelMirrorpanel.opened>.m-panel-btn.g-cartografia-flecha-izquierda{color:#e8f5e9!important}.m-plugin-panelMirrorpanel.collapsed>div.m-panel-controls{display:none!important}div.m-plugin-panelMirrorpanel.opened{min-width:max-content}.m-areas>div.m-area.m-right>div.m-plugin-panelMirrorpanel.opened>button.m-panel-btn{position:absolute;left:-2.5rem;background-color:#718bd3}.m-areas>div.m-area.m-left>div.m-plugin-panelMirrorpanel.opened>button.m-panel-btn{position:absolute;right:-2.5rem;left:unset!important;background-color:#718bd3}.div-m-mirrorpanel-panel{padding:.7rem}.m-mirrorpanel-effect-buttoms{padding:.3rem 0;text-align:center}div#m-mirrorpanel-titulo{display:block;font-size:15px;height:40px;line-height:40px;padding:0 .3rem;text-align:center;border-radius:4px 4px 0 0;border-bottom:1.5px solid rgba(0,0,0,.12)}.m-mirrorpanel-container .big-button{font-size:32px;background:none;border:none;cursor:pointer;opacity:.75;transition:all .25s ease;color:#404040;outline:none}.m-mirrorpanel-container .big-button:hover,.m-mirrorpanel-container .buttom-pressed{color:#718bd3}[class*=" mirrorpanel-"],[class^=mirrorpanel-]{font-family:mirrorpanel!important;speak:never;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}[class*=" mirrorpanel-"]:before,[class^=mirrorpanel-]:before{display:block}.mirrorpanel-icon:before{content:"\e802";font-family:mirrorpanel!important}.mirrorpanel-modeviz0:before{content:"\e804"}.mirrorpanel-modeviz1:before{content:"\e803"}.mirrorpanel-modeviz2:before{content:"\e803";transform:rotate(90deg)}.mirrorpanel-modeviz3:before{content:"\e805"}.mirrorpanel-modeviz4:before{content:"\e806"}.mirrorpanel-modeviz5:before{content:"\e808"}.mirrorpanel-modeviz6:before{content:"\e806";transform:rotate(90deg)}.mirrorpanel-modeviz7:before{content:"\e807"}.mirrorpanel-modeviz8:before{content:"\e809"}.mirrorpanel-modeviz9:before{content:"\e809";transform:rotate(180deg)}.mirrorpanel-grid{display:grid;height:100%;width:100%;margin:0;padding:0;grid-template-columns:1fr;grid-template-rows:1fr;gap:1px 1px;grid-template-areas:mirror1}.mirrorpanel-grid .mirror1,.mirrorpanel-grid .mirror2,.mirrorpanel-grid .mirror3,.mirrorpanel-grid .mirror4{display:none;min-height:100%}.mirrorpanel-grid .mirror1,.mirrorpanel-grid.modeViz4 .mirror4,.mirrorpanel-grid.modeViz5 .mirror4,.mirrorpanel-grid.modeViz6 .mirror4,.mirrorpanel-grid:not(.modeViz0) .mirror2,.mirrorpanel-grid:not(.modeViz0):not(.modeViz1):not(.modeViz2) .mirror3{display:block!important}.mirror1{grid-area:mirror1}.mirror2{grid-area:mirror2}.mirror3{grid-area:mirror3}.mirror4{grid-area:mirror4}.mirrorpanel-grid.modeViz0{grid-template-columns:1fr!important;grid-template-rows:1fr!important;grid-template-areas:"mirror1"!important}.mirrorpanel-grid.modeViz1{grid-template-columns:1fr 1fr!important;grid-template-rows:1fr!important;grid-template-areas:"mirror1 mirror2"!important}.mirrorpanel-grid.modeViz2{grid-template-columns:1fr!important;grid-template-rows:1fr 1fr!important;grid-template-areas:"mirror1" "mirror2"!important}.mirrorpanel-grid.modeViz3{grid-template-columns:1fr 1fr 1fr!important;grid-template-rows:1fr!important;grid-template-areas:"mirror1 mirror2 mirror3"!important}.mirrorpanel-grid.modeViz4{grid-template-columns:1fr 1fr 1fr 1fr!important;grid-template-rows:1fr!important;grid-template-areas:"mirror1 mirror2 mirror3 mirror4"!important}.mirrorpanel-grid.modeViz5{grid-template-columns:1fr 1fr!important;grid-template-rows:1fr 1fr!important;grid-template-areas:"mirror1 mirror2" "mirror3 mirror4"!important}.mirrorpanel-grid.modeViz6{grid-template-columns:1fr!important;grid-auto-rows:1fr 1fr 1fr 1fr!important;grid-template-areas:"mirror1" "mirror2" "mirror3" "mirror4"!important}.mirrorpanel-grid.modeViz7{grid-template-columns:2fr 1fr 1fr!important;grid-template-rows:1fr!important;grid-template-areas:"mirror1 mirror2 mirror3"!important}.mirrorpanel-grid.modeViz8{grid-template-areas:"mirror1 mirror1" "mirror2 mirror3"!important}.mirrorpanel-grid.modeViz8,.mirrorpanel-grid.modeViz9{grid-template-columns:1fr 1fr!important;grid-template-rows:1fr 1fr!important}.mirrorpanel-grid.modeViz9{grid-template-areas:"mirror1 mirror2" "mirror3 mirror3"!important}
\ No newline at end of file
diff --git a/dist/mirrorpanel.ol.min.js b/dist/mirrorpanel.ol.min.js
new file mode 100644
index 0000000..54d1fe4
--- /dev/null
+++ b/dist/mirrorpanel.ol.min.js
@@ -0,0 +1,2 @@
+!function(t){var e={};function o(r){if(e[r])return e[r].exports;var n=e[r]={i:r,l:!1,exports:{}};return t[r].call(n.exports,n,n.exports,o),n.l=!0,n.exports}o.m=t,o.c=e,o.d=function(t,e,r){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(o.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)o.d(r,n,function(e){return t[e]}.bind(null,n));return r},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=5)}([function(t,e){t.exports='
\r\n
{{translations.title}}
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n
\r\n \r\n
\r\n\r\n
\r\n'},function(t){t.exports=JSON.parse('{"tooltip":"Mirror Comparison","title":"Mirror Maps","modViz0":"Standard map","modViz1":"Vertical two maps","modViz2":"Horizontal two maps","modViz3":"Vertical three maps","modViz4":"Vertical four maps","modViz5":"Mosaic maps","modViz6":"Horizontal four maps","modViz7":"Vertical 2-1-1 proportional maps","modViz8":"One map above and two below","modViz9":"Two maps above and one below"}')},function(t){t.exports=JSON.parse('{"tooltip":"Comparador de mapas espejo","title":"Mapas espejo","modViz0":"Mapa standard","modViz1":"Dos mapas en vertical","modViz2":"Dos mapas en horizontal","modViz3":"Tres mapas en vertical","modViz4":"Cuatro mapas en vertical","modViz5":"Mosaico de mapas","modViz6":"Cuatro mapas en horizontal","modViz7":"Tres mapas en proporción 2-1-1","modViz8":"Un mapa arriba y dos abajo","modViz9":"Dos mapas arriba y uno abajo"}')},function(t){t.exports=JSON.parse('{"url":{"name":"mirrorpanel","separator":"*!"},"constructor":"M.plugin.Mirrorpanel","parameters":[{"type":"object","properties":[{"type":"simple","name":"position","possibleValues":["TL","TR","BL","BR"],"position":0},{"type":"boolean","name":"collapsed","position":1},{"type":"boolean","name":"collapsible","position":2},{"type":"simple","name":"modeViz","position":3},{"type":"boolean","name":"enabledKeyFunctions","position":4},{"type":"boolean","name":"showCursors","position":5},{"type":"simple","name":"mirrorLayers","position":6},{"type":"simple","name":"defaultBaseLyrs","position":7},{"type":"boolean","name":"interface","position":8},{"type":"boolean","name":"showToc","position":9}]}],"files":{"ol":{"scripts":["mirrorpanel.ol.min.js"],"styles":["mirrorpanel.ol.min.css"]}},"metadata":{"uuid_plugin":"","uuid_version_plugin":"","version_ficha_metadatos":"","name":"Mirrorpanel","description":"Plugin que permite comparar varias capas dividiendo la pantalla en varias partes.","text":"Plugin que permite comparar varias capas dividiendo la pantalla en varias partes. Los mapas tienen sus vistas sincronizadas, y podemos ver la representación de una misma zona por distintas capas.","version":"1.0.0","date":"Julio, 2020","author":"","org":"","tags":"mapea,plugin","icon":"./facade/assets/icons/icons.svg","buttons":[{"title":"","description":"","querySelector":""},{"title":"","description":"","querySelector":""}],"dependencies":{"modules":["",""],"plugins":[{"uuid":"","name":""}],"services":[{"name":"","description":""}]}}}')},function(t,e,o){},function(t,e,o){"use strict";o.r(e);o(4);function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var o=0;o1&&void 0!==arguments[1]?arguments[1]:y(),o=h(e),r="";return M.utils.isNullOrEmpty(o)?console.warn("The translation '".concat(e,"' has not been defined.")):r=t.split(".").reduce((function(t,e){return t[e]}),o),r};function v(t){return(v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function g(t,e){for(var o=0;o0&&(this.mapL.A.addLayers(this.mirrorLayers),this.mapL.A.getLayers().forEach((function(t){0!==t.zindex_&&t.setVisible(!1)}))),this.showCursors&&this.addLayerCursor("A"),new Promise((function(t,o){var r;r={jsonp:!0,vars:{translations:{title:b("title"),modViz0:b("modViz0"),modViz1:b("modViz1"),modViz2:b("modViz2"),modViz3:b("modViz3"),modViz4:b("modViz4"),modViz5:b("modViz5"),modViz6:b("modViz6"),modViz7:b("modViz7"),modViz8:b("modViz8"),modViz9:b("modViz9")}}},e.template=M.template.compileSync(d.a,r),e.template.querySelectorAll('button[id^="set-mirror-"]').forEach((function(t,o){t.addEventListener("click",(function(t){e.manageVisionPanelByCSSGrid(o)}))})),e.manageVisionPanelByCSSGrid(e.modeViz),t(e.template)}))}},{key:"activate",value:function(){L(V(i.prototype),"activate",this).call(this)}},{key:"deactivate",value:function(){L(V(i.prototype),"deactivate",this).call(this)}},{key:"createMapContainers",value:function(){var t=document.createElement("div");t.id="lienzo",t.classList.add("mirrorpanel-grid");var e=document.getElementById("mapjs")||document.getElementById("map");document.body.insertBefore(t,e),e.classList.add("mirror1"),t.appendChild(e);var o=document.createElement("div");o.id="mapjsB",o.classList.add("mirror2"),t.appendChild(o);var r=document.createElement("div");r.id="mapjsC",r.classList.add("mirror3"),t.appendChild(r);var n=document.createElement("div");n.id="mapjsD",n.classList.add("mirror4"),t.appendChild(n)}},{key:"manageVisionPanelByCSSGrid",value:function(t){var e=this.modeViz;(document.getElementById("mapjs")||document.getElementById("map")).style.display="none",document.getElementById("mapjsB").style.display="none",document.getElementById("mapjsC").style.display="none",document.getElementById("mapjsD").style.display="none",this.template.querySelector("#set-mirror-"+e).classList.remove("buttom-pressed");for(var o=0;o<10;o++)document.getElementById("lienzo").classList.remove("modeViz"+o);document.getElementById("lienzo").classList.add("modeViz"+t),[1,2].includes(t)&&null==this.mapL.B&&this.createMapObjects("B"),[3,7,8,9].includes(t)&&(null==this.mapL.B&&this.createMapObjects("B"),null==this.mapL.C&&this.createMapObjects("C")),[4,5,6].includes(t)&&(null==this.mapL.B&&this.createMapObjects("B"),null==this.mapL.C&&this.createMapObjects("C"),null==this.mapL.D&&this.createMapObjects("D")),this.modeViz=t,this.template.querySelector("#set-mirror-"+t).classList.add("buttom-pressed"),this.map_.refresh(),null!==this.mapL.B&&this.mapL.B.refresh(),null!==this.mapL.C&&this.mapL.C.refresh(),null!==this.mapL.D&&this.mapL.D.refresh()}},{key:"createMapObjects",value:function(t){var e=null;switch(t){case"B":this.defaultBaseLyrs[1]&&(e=this.defaultBaseLyrs[0]);break;case"C":this.defaultBaseLyrs[2]&&(e=this.defaultBaseLyrs[1]);break;case"D":this.defaultBaseLyrs[3]&&(e=this.defaultBaseLyrs[2]);break;default:e=this.map_.getLayers()[0].setMap(this)}this.mapL[t]=M.map({container:"mapjs"+t,layers:e,controls:this.showTOC?["layerswitcher"]:"",center:this.map_.getCenter(),projection:this.map_.getProjection().code+"*"+this.map_.getProjection().units,zoom:this.map_.getZoom()}),this.mapL[t].getMapImpl().setView(this.map_.getMapImpl().getView()),this.showCursors&&this.addLayerCursor(t),this.mirrorLayers.length>0&&(this.mapL[t].addLayers(this.mirrorLayers),this.mapL[t].getLayers().forEach((function(t){0!==t.zindex_&&t.setVisible(!1)}))),this.mapL[t].refresh()}},{key:"addLayerCursor",value:function(t){var e=this;this.lyrCursor[t]=new M.layer.Vector({name:"Coordenadas centro "+t},{displayInLayerSwitcher:!1}),this.featureLyrCursor[t]=new M.Feature("Center"+t,{type:"Feature",properties:{},geometry:{type:"Point",coordinates:this.mapL[t].getCenter()}}),this.lyrCursor[t].addFeatures([this.featureLyrCursor[t]]),this.lyrCursor[t].setStyle(this.styleCursor),this.lyrCursor[t].setZIndex(5e3),this.mapL[t].addLayers(this.lyrCursor[t]),this.mapL[t].getMapImpl().on("pointermove",(function(o){e.lyrCursor[t].setVisible(!1),Object.keys(e.featureLyrCursor).forEach((function(r){e.mapL[r]&&e.mapL[r].getMapImpl().setView(e.mapL[t].getMapImpl().getView()),r!=t&&null!==e.featureLyrCursor[r]&&(e.lyrCursor[r].setVisible(!0),e.featureLyrCursor[r].setGeometry({type:"Point",coordinates:o.coordinate}))}))}))}},{key:"removeMaps",value:function(){this.mapL.B=null,this.mapL.C=null,this.mapL.D=null}},{key:"destroyMapsContainer",value:function(){document.getElementById("mapjsB").remove(),document.getElementById("mapjsC").remove(),document.getElementById("mapjsD").remove();var t=document.getElementById("lienzo"),e=document.getElementById("mapjs")||document.getElementById("map");e.style.display="block",e.classList.remove("mirror1"),document.body.insertBefore(e,t),document.getElementById("lienzo").remove()}},{key:"equals",value:function(t){return t instanceof i}}])&&g(e.prototype,o),r&&g(e,r),i}(),O=o(3);function B(t){return(B="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function j(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function S(t,e){for(var o=0;o0&&void 0!==arguments[0]?arguments[0]:{};j(this,i),(t=n.call(this)).name_="mirrorpanel",t.map_=null,t.controls_=[],t.className="m-plugin-mirrorpanel";var o=["TR","TL","BL","BR"];return t.position=o.includes(e.position)?e.position:"TR",t.collapsed=e.collapsed,void 0===t.collapsed&&(t.collapsed=!0),t.collapsible=e.collapsible,void 0===t.collapsible&&(t.collapsible=!0),t.modeViz=e.modeViz,void 0===t.modeViz&&(t.modeViz=0),t.enabledKeyFunctions=e.enabledKeyFunctions,void 0===t.enabledKeyFunctions&&(t.enabledKeyFunctions=!0),t.showCursors=e.showCursors,void 0===t.showCursors&&(t.showCursors=!0),t.mirrorLayers=[],void 0!==e.mirrorLayers&&(Array.isArray(e.mirrorLayers)?t.mirrorLayers=e.mirrorLayers:t.mirrorLayers=e.mirrorLayers.split(",")),t.defaultBaseLyrs=[],void 0!==e.defaultBaseLyrs&&(Array.isArray(e.defaultBaseLyrs)?t.defaultBaseLyrs=e.defaultBaseLyrs:t.defaultBaseLyrs=e.defaultBaseLyrs.split(",")),t.interface=void 0===e.interface||e.interface,t.showTOC=e.showTOC,void 0===t.showTOC&&(t.showTOC=!0),t.tooltip_=e.tooltip||b("tooltip"),t.metadata_=O.metadata,t}return e=i,(o=[{key:"addTo",value:function(t){var e=this,o={pluginOnLeft:!!["TL","BL"].includes(this.position),collapsible:this.collapsible,collapsed:this.collapsed,modeViz:this.modeViz,showCursors:this.showCursors,mirrorLayers:this.mirrorLayers,defaultBaseLyrs:this.defaultBaseLyrs,showTOC:this.showTOC};this.control_=new _(o),this.controls_.push(this.control_),this.map_=t,this.panel_=new M.ui.Panel("panelMirrorpanel",{collapsible:this.collapsible,collapsed:this.collapsed,position:M.ui.position[this.position],modeViz:this.modeViz,showCursors:this.showCursors,className:this.interface?"m-plugin-panelMirrorpanel":"m-plugin-panelMirrorpanel hidden",collapsedButtonClass:"mirrorpanel-icon",tooltip:this.tooltip_}),this.panel_.addControls(this.controls_),t.addPanels(this.panel_),document.addEventListener("keydown",(function(t){if(e.enabledKeyFunctions){for(var o=0;o<10;o++)t.ctrlKey&&t.shiftKey&&t.key==="F"+(o+1)&&e.control_.manageVisionPanelByCSSGrid(o);var r=["Control","Shift","Alt","Meta"].includes(t.key)?"":t.key;"Escape"==(t.ctrlKey?"Control ":"")+(t.shiftKey?"Shift ":"")+(t.altKey?"Alt ":"")+(t.metaKey?"Meta ":"")+r&&e.control_.manageVisionPanelByCSSGrid(0)}}))}},{key:"destroy",value:function(){document.removeEventListener("keydown",(function(t){})),this.control_.removeMaps(),this.control_.destroyMapsContainer(),this.map_.removeControls([this.control_]);var t=[null,null,null,null,null,null,null,null,null,null,null,null];this.control_=t[0],this.panel_=t[1],this.map_=t[2],this.collapsible=t[3],this.collapsed=t[4],this.modeViz=t[5],this.enabledKeyFunctions=t[6],this.showCursors=t[7],this.mirrorLayers=t[8],this.defaultBaseLyrs=t[9],this.interface=t[10],this.showTOC=t[11]}},{key:"getMetadata",value:function(){return this.metadata_}},{key:"getAPIRest",value:function(){return"".concat(this.name,"=").concat(this.position,"*!").concat(this.collapsed,"*!").concat(this.collapsible,"*!").concat(this.modeViz,"*!").concat(this.enabledKeyFunctions,"*!").concat(this.showCursors,"*!").concat(this.mirrorLayers,"*!").concat(this.defaultBaseLyrs,"*!").concat(this.interface,"*!").concat(this.showTOC)}},{key:"activate",value:function(){this.control_.activate()}},{key:"deactivate",value:function(){this.control_.deactivate()}},{key:"name",get:function(){return this.name_}}])&&S(e.prototype,o),r&&S(e,r),i}();window.M.plugin||(window.M.plugin={}),window.M.control||(window.M.control={}),window.M.impl||(window.M.impl={}),window.M.impl.control||(window.M.impl.control={}),window.M.plugin.Mirrorpanel=R,window.M.control.MirrorpanelControl=_,window.M.impl.control.MirrorpanelControl=p}]);
+//# sourceMappingURL=mirrorpanel.ol.min.js.map
\ No newline at end of file
diff --git a/dist/mirrorpanel.ol.min.js.map b/dist/mirrorpanel.ol.min.js.map
new file mode 100644
index 0000000..b18c62d
--- /dev/null
+++ b/dist/mirrorpanel.ol.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./src/templates/mirrorpanel.html","webpack:///./src/impl/ol/js/mirrorpanelcontrol.js","webpack:///./src/facade/js/i18n/language.js","webpack:///./src/facade/js/mirrorpanelcontrol.js","webpack:///./src/facade/js/mirrorpanel.js","webpack:///./src/index.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","MirrorpanelControl","M","impl","Control","map","html","getMapImpl","getInteractions","forEach","interaction","ol","DoubleClickZoom","dblClickInteraction_","translations","en","es","getLang","res","language","getTranslation","lang","getValue","keyPath","translation","utils","isNullOrEmpty","console","warn","split","reduce","prev","current","values","isUndefined","MirrorpanelImplControl","exception","template","modeViz","showCursors","mapL","A","B","C","D","lyrCursor","featureLyrCursor","styleCursor","style","Point","icon","form","CIRCLE","fontsize","radius","rotation","rotate","offset","color","fill","gradientcolor","opacity","defaultBaseLyrs","mirrorLayers","showTOC","createMapContainers","compileSync","string","options","parseToHtml","templateVars","vars","htmlText","Handlebars","compile","templateFn","stringToHtml","this","length","addLayers","getLayers","zindex_","setVisible","addLayerCursor","Promise","success","fail","templateOptions","jsonp","title","getValueTranslate","modViz0","modViz1","modViz2","modViz3","modViz4","modViz5","modViz6","modViz7","modViz8","modViz9","querySelectorAll","button","addEventListener","evt","manageVisionPanelByCSSGrid","bigContainer","document","createElement","id","classList","add","mapjsA","getElementById","body","insertBefore","appendChild","mapjsB","mapjsC","mapjsD","oldModeViz","display","querySelector","remove","includes","createMapObjects","map_","refresh","mapLyr","defLyr","setMap","container","layers","controls","center","getCenter","projection","getProjection","code","units","zoom","getZoom","setView","getView","layer","Vector","displayInLayerSwitcher","Feature","type","properties","geometry","coordinates","addFeatures","setStyle","setZIndex","on","event","keys","k","setGeometry","coordinate","lienzo","control","Mirrorpanel","Plugin","name_","controls_","className","positions","position","collapsed","undefined","collapsible","enabledKeyFunctions","Array","isArray","tooltip_","tooltip","metadata_","api","metadata","pluginOnLeft","control_","push","panel_","ui","Panel","collapsedButtonClass","addControls","addPanels","zEvent","ctrlKey","shiftKey","keyStr","altKey","metaKey","removeEventListener","removeMaps","destroyMapsContainer","removeControls","activate","deactivate","window","plugin","M$plugin$Mirrorpanel","M$control$MirrorpanelControl","M$impl$control$MirrorpanelControl"],"mappings":"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","file":"mirrorpanel.ol.min.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 5);\n","module.exports = \"\\r\\n
{{translations.title}}
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n \\r\\n
\\r\\n\\r\\n
\\r\\n\";","/**\r\n * @module M/impl/control/MirrorpanelControl\r\n */\r\nexport default class MirrorpanelControl extends M.impl.Control {\r\n /**\r\n * This function adds the control to the specified map\r\n *\r\n * @public\r\n * @function\r\n * @param {M.Map} map to add the plugin\r\n * @param {HTMLElement} html of the plugin\r\n * @api stable\r\n */\r\n addTo(map, html) {\r\n // obtengo la interacción por defecto del dblclick para manejarla\r\n const olMap = map.getMapImpl();\r\n olMap.getInteractions().forEach((interaction) => {\r\n if (interaction instanceof ol.interaction.DoubleClickZoom) {\r\n this.dblClickInteraction_ = interaction;\r\n }\r\n });\r\n super.addTo(map, html);\r\n }\r\n}\r\n","import en from './en';\nimport es from './es';\n\n/**\n * Default object with es and en translate.\n *\n * @const\n * @type {object}\n */\nconst translations = {\n en,\n es,\n};\n\nconst getLang = () => {\n let res = 'es';\n if (typeof M.language.getLang === 'function') {\n res = M.language.getLang();\n }\n\n return res;\n};\n\n/**\n * This function sets a new language translate.\n * @param {string} lang\n * @param {JSON} json\n * @public\n * @api\n */\nexport const addTranslation = (lang, json) => {\n translations[lang] = json;\n};\n\n/**\n * This function gets a language translate.\n *\n * @param {string} lang\n * @return {JSON}\n * @public\n * @api\n */\nexport const getTranslation = (lang) => {\n return translations[lang];\n};\n\n/**\n * This function gets a language value from key\n *\n * @public\n * @param {string}\n * @param {string}\n * @return {string}\n * @public\n * @api\n */\n\nexport const getValue = (keyPath, lang = getLang()) => {\n const translation = getTranslation(lang);\n let value = '';\n if (M.utils.isNullOrEmpty(translation)) {\n /* eslint-disable no-console */\n console.warn(`The translation '${lang}' has not been defined.`);\n } else {\n value = keyPath.split('.').reduce((prev, current) => prev[current], translation);\n }\n\n return value;\n};\n","/**\r\n * @module M/control/MirrorpanelControl\r\n */\r\n\r\nimport MirrorpanelImplControl from 'impl/mirrorpanelcontrol';\r\nimport template from 'templates/mirrorpanel';\r\nimport { getValue as getValueTranslate } from './i18n/language';\r\n\r\nexport default class MirrorpanelControl extends M.Control {\r\n /**\r\n * @classdesc\r\n * Main constructor of the class. Creates a PluginControl\r\n * control\r\n *\r\n * @constructor\r\n * @extends {M.Control}\r\n * @api stable\r\n */\r\n constructor(values) {\r\n // 1. checks if the implementation can create PluginControl\r\n if (M.utils.isUndefined(MirrorpanelImplControl)) {\r\n M.exception('La implementación usada no puede crear controles MirrorpanelControl');\r\n }\r\n // 2. implementation of this control\r\n const impl = new MirrorpanelImplControl();\r\n super(impl, 'Mirrorpanel');\r\n\r\n /**\r\n * Template\r\n * @public\r\n * @type { HTMLElement }\r\n */\r\n this.template = null;\r\n\r\n /**\r\n * Visual mode\r\n * @private\r\n * @type {Number}\r\n */\r\n this.modeViz = values.modeViz;\r\n\r\n /**\r\n * Mirror maps with plugins\r\n * @private\r\n * @type {boolean}\r\n */\r\n this.showCursors = values.showCursors;\r\n\r\n /**\r\n * Defining mirror maps variables\r\n */\r\n this.mapL = {\r\n A: null,\r\n B: null,\r\n C: null,\r\n D: null,\r\n }\r\n this.lyrCursor = {\r\n A: null,\r\n B: null,\r\n C: null,\r\n D: null,\r\n }\r\n this.featureLyrCursor = {\r\n A: null,\r\n B: null,\r\n C: null,\r\n D: null,\r\n }\r\n\r\n /**\r\n * Defining cursor style\r\n */\r\n this.styleCursor = new M.style.Point({\r\n icon: {\r\n form: M.style.form.CIRCLE,\r\n fontsize: 0.5,\r\n radius: 5,\r\n rotation: 0,\r\n rotate: false,\r\n offset: [0, 0],\r\n color: 'black',\r\n fill: 'red',\r\n gradientcolor: '#088A85',\r\n opacity: 0.8\r\n }\r\n });\r\n\r\n /**\r\n * Default layers for mirror maps\r\n * @public\r\n * @public {Array}\r\n */\r\n this.defaultBaseLyrs = values.defaultBaseLyrs;\r\n\r\n /**\r\n * All layers\r\n * @public\r\n * @public {Array}\r\n */\r\n this.mirrorLayers = values.mirrorLayers;\r\n\r\n /**\r\n * Enable layerswitcher control\r\n * @public\r\n * @public {Array}\r\n */\r\n this.showTOC = values.showTOC;\r\n\r\n this.createMapContainers();\r\n }\r\n\r\n\r\n /**\r\n * This function creates the view\r\n *\r\n * @public\r\n * @function\r\n * @param {M.Map} map to add the control\r\n * @api stable\r\n */\r\n createView(map) {\r\n if (!M.template.compileSync) {\r\n M.template.compileSync = (string, options) => {\r\n let templateCompiled;\r\n let templateVars = {};\r\n let parseToHtml;\r\n if (!M.utils.isUndefined(options)) {\r\n templateVars = M.utils.extends(templateVars, options.vars);\r\n parseToHtml = options.parseToHtml;\r\n }\r\n const templateFn = Handlebars.compile(string);\r\n const htmlText = templateFn(templateVars);\r\n if (parseToHtml !== false) {\r\n templateCompiled = M.utils.stringToHtml(htmlText);\r\n } else {\r\n templateCompiled = htmlText;\r\n }\r\n return templateCompiled;\r\n };\r\n }\r\n\r\n this.mapL['A'] = map;\r\n if (this.mirrorLayers.length > 0) {\r\n this.mapL['A'].addLayers(this.mirrorLayers);\r\n this.mapL['A'].getLayers().forEach((l) => {\r\n if (l.zindex_ !== 0) { l.setVisible(false); }\r\n });\r\n }\r\n if (this.showCursors) { this.addLayerCursor('A'); }\r\n return new Promise((success, fail) => {\r\n let templateOptions = '';\r\n templateOptions = {\r\n jsonp: true,\r\n vars: {\r\n translations: {\r\n title: getValueTranslate('title'),\r\n modViz0: getValueTranslate('modViz0'),\r\n modViz1: getValueTranslate('modViz1'),\r\n modViz2: getValueTranslate('modViz2'),\r\n modViz3: getValueTranslate('modViz3'),\r\n modViz4: getValueTranslate('modViz4'),\r\n modViz5: getValueTranslate('modViz5'),\r\n modViz6: getValueTranslate('modViz6'),\r\n modViz7: getValueTranslate('modViz7'),\r\n modViz8: getValueTranslate('modViz8'),\r\n modViz9: getValueTranslate('modViz9')\r\n }\r\n }\r\n };\r\n\r\n this.template = M.template.compileSync(template, templateOptions);\r\n\r\n // Button's click events\r\n this.template.querySelectorAll('button[id^=\"set-mirror-\"]')\r\n .forEach((button, modeViz) => {\r\n button.addEventListener('click', evt => {\r\n this.manageVisionPanelByCSSGrid(modeViz);\r\n })\r\n });\r\n\r\n // Apply default vision\r\n this.manageVisionPanelByCSSGrid(this.modeViz);\r\n success(this.template);\r\n });\r\n\r\n }\r\n\r\n /**\r\n * This function is called on the control activation\r\n *\r\n * @public\r\n * @function\r\n * @api stable\r\n */\r\n activate() {\r\n super.activate();\r\n }\r\n /**\r\n * This function is called on the control deactivation\r\n *\r\n * @public\r\n * @function\r\n * @api stable\r\n */\r\n deactivate() {\r\n super.deactivate();\r\n }\r\n\r\n /**\r\n * Initial configurations for applying CSS grid.\r\n * \r\n */\r\n createMapContainers() {\r\n const bigContainer = document.createElement('div');\r\n bigContainer.id = \"lienzo\";\r\n bigContainer.classList.add('mirrorpanel-grid');\r\n\r\n const mapjsA = document.getElementById(\"mapjs\") || document.getElementById(\"map\");\r\n document.body.insertBefore(bigContainer, mapjsA);\r\n mapjsA.classList.add('mirror1');\r\n bigContainer.appendChild(mapjsA);\r\n\r\n const mapjsB = document.createElement('div');\r\n mapjsB.id = \"mapjsB\";\r\n mapjsB.classList.add('mirror2');\r\n bigContainer.appendChild(mapjsB);\r\n\r\n const mapjsC = document.createElement('div');\r\n mapjsC.id = \"mapjsC\";\r\n mapjsC.classList.add('mirror3');\r\n bigContainer.appendChild(mapjsC);\r\n\r\n const mapjsD = document.createElement('div');\r\n mapjsD.id = \"mapjsD\";\r\n mapjsD.classList.add('mirror4');\r\n bigContainer.appendChild(mapjsD);\r\n }\r\n\r\n /**\r\n * This function shows/hides panel for differents viz options.\r\n * The mirror maps are launched from here\r\n * \r\n */\r\n manageVisionPanelByCSSGrid(modeViz) {\r\n let oldModeViz = this.modeViz;\r\n let map0 = document.getElementById('mapjs') || document.getElementById('map');\r\n map0.style.display = 'none';\r\n document.getElementById('mapjsB').style.display = 'none';\r\n document.getElementById('mapjsC').style.display = 'none';\r\n document.getElementById('mapjsD').style.display = 'none';\r\n this.template.querySelector('#set-mirror-' + oldModeViz).classList.remove('buttom-pressed');\r\n\r\n for (let i = 0; i < 10; i++) {\r\n document.getElementById('lienzo').classList.remove('modeViz' + i);\r\n }\r\n document.getElementById('lienzo').classList.add('modeViz' + modeViz);\r\n\r\n //Create map objects by modeviz\r\n if ([1, 2].includes(modeViz)) {\r\n if (this.mapL['B'] == null) {\r\n this.createMapObjects('B');//Create MapB\r\n }\r\n }\r\n if ([3, 7, 8, 9].includes(modeViz)) {\r\n if (this.mapL['B'] == null) {\r\n this.createMapObjects('B');//Create MapB\r\n }\r\n if (this.mapL['C'] == null) {\r\n this.createMapObjects('C');//Create MapC\r\n }\r\n }\r\n if ([4, 5, 6].includes(modeViz)) {\r\n if (this.mapL['B'] == null) {\r\n this.createMapObjects('B');//Create MapB\r\n }\r\n if (this.mapL['C'] == null) {\r\n this.createMapObjects('C');//Create MapC\r\n }\r\n if (this.mapL['D'] == null) {\r\n this.createMapObjects('D');//Create MapD\r\n }\r\n }\r\n\r\n this.modeViz = modeViz;\r\n this.template.querySelector('#set-mirror-' + modeViz).classList.add('buttom-pressed');\r\n this.map_.refresh();\r\n if (this.mapL['B'] !== null) { this.mapL['B'].refresh(); }\r\n if (this.mapL['C'] !== null) { this.mapL['C'].refresh(); }\r\n if (this.mapL['D'] !== null) { this.mapL['D'].refresh(); }\r\n }\r\n\r\n /**\r\n * Create mirror map object synchro with the main map\r\n */\r\n createMapObjects(mapLyr) {\r\n let defLyr = null;\r\n switch (mapLyr) {\r\n case 'B':\r\n if (this.defaultBaseLyrs[1]) defLyr = this.defaultBaseLyrs[0];\r\n break;\r\n case 'C':\r\n if (this.defaultBaseLyrs[2]) defLyr = this.defaultBaseLyrs[1];\r\n break;\r\n case 'D':\r\n if (this.defaultBaseLyrs[3]) defLyr = this.defaultBaseLyrs[2];\r\n break;\r\n default:\r\n defLyr = this.map_.getLayers()[0].setMap(this);\r\n break;\r\n }\r\n this.mapL[mapLyr] = M.map({\r\n container: 'mapjs' + mapLyr,\r\n layers: defLyr,\r\n controls: this.showTOC ? ['layerswitcher'] : '',\r\n center: this.map_.getCenter(),\r\n projection: this.map_.getProjection().code + '*' + this.map_.getProjection().units,\r\n zoom: this.map_.getZoom(),\r\n });\r\n this.mapL[mapLyr].getMapImpl().setView(this.map_.getMapImpl().getView());\r\n\r\n if (this.showCursors) { this.addLayerCursor(mapLyr); }\r\n if (this.mirrorLayers.length > 0) {\r\n this.mapL[mapLyr].addLayers(this.mirrorLayers);\r\n this.mapL[mapLyr].getLayers().forEach((l) => {\r\n if (l.zindex_ !== 0) { l.setVisible(false); }\r\n });\r\n }\r\n this.mapL[mapLyr].refresh();\r\n }\r\n\r\n /**\r\n * Adding a layer for cursor on Map\r\n */\r\n addLayerCursor(mapLyr) {\r\n // Cursor Layer\r\n this.lyrCursor[mapLyr] = new M.layer.Vector({\r\n name: 'Coordenadas centro ' + mapLyr,\r\n }, { displayInLayerSwitcher: false });\r\n\r\n this.featureLyrCursor[mapLyr] = new M.Feature('Center' + mapLyr, {\r\n type: 'Feature',\r\n properties: {},\r\n geometry: {\r\n type: 'Point',\r\n coordinates: this.mapL[mapLyr].getCenter(),\r\n },\r\n });\r\n\r\n this.lyrCursor[mapLyr].addFeatures([this.featureLyrCursor[mapLyr]]);\r\n this.lyrCursor[mapLyr].setStyle(this.styleCursor);\r\n this.lyrCursor[mapLyr].setZIndex(5000);\r\n this.mapL[mapLyr].addLayers(this.lyrCursor[mapLyr]);\r\n\r\n this.mapL[mapLyr].getMapImpl().on('pointermove', (event) => {\r\n this.lyrCursor[mapLyr].setVisible(false);\r\n Object.keys(this.featureLyrCursor).forEach(k => {\r\n if (this.mapL[k]) {\r\n this.mapL[k].getMapImpl().setView(this.mapL[mapLyr].getMapImpl().getView());\r\n }\r\n if (k != mapLyr) {\r\n if (this.featureLyrCursor[k] !== null) {\r\n this.lyrCursor[k].setVisible(true);\r\n this.featureLyrCursor[k].setGeometry({\r\n type: 'Point',\r\n coordinates: event.coordinate,\r\n });\r\n }\r\n }\r\n })\r\n });\r\n\r\n }\r\n\r\n /**\r\n * This function is called to remove the effects\r\n *\r\n * @public\r\n * @function\r\n * @api stable\r\n */\r\n removeMaps() {\r\n this.mapL['B'] = null;\r\n this.mapL['C'] = null;\r\n this.mapL['D'] = null;\r\n }\r\n\r\n destroyMapsContainer() {\r\n // Remove mirrors containers\r\n document.getElementById(\"mapjsB\").remove();\r\n document.getElementById(\"mapjsC\").remove();\r\n document.getElementById(\"mapjsD\").remove();\r\n\r\n // Take the main map out of the container\r\n const lienzo = document.getElementById(\"lienzo\");\r\n const mapjsA = document.getElementById(\"mapjs\") || document.getElementById(\"map\");\r\n mapjsA.style.display = \"block\";\r\n mapjsA.classList.remove('mirror1');\r\n document.body.insertBefore(mapjsA, lienzo);\r\n\r\n // Load the main container\r\n document.getElementById(\"lienzo\").remove();\r\n }\r\n\r\n /**\r\n * This function compares controls\r\n *\r\n * @public\r\n * @function\r\n * @param {M.Control} control to compare\r\n * @api stable\r\n */\r\n equals(control) {\r\n return control instanceof MirrorpanelControl;\r\n }\r\n}\r\n","/**\r\n * @module M/plugin/Mirrorpanel\r\n */\r\nimport 'assets/css/mirrorpanel';\r\nimport MirrorpanelControl from './mirrorpanelcontrol';\r\nimport api from '../../api';\r\nimport { getValue } from './i18n/language'; //e2m: Multilanguage support\r\n\r\nexport default class Mirrorpanel extends M.Plugin {\r\n /**\r\n * @classdesc\r\n * Main facade plugin object. This class creates a plugin\r\n * object which has an implementation Object\r\n *\r\n * @constructor\r\n * @extends {M.Plugin}\r\n * @param {Object} impl implementation object\r\n * @api stable\r\n */\r\n constructor(options = {}) {\r\n super();\r\n\r\n /**\r\n * Name plugin\r\n * @private\r\n * @type {String}\r\n */\r\n this.name_ = 'mirrorpanel';\r\n\r\n /**\r\n * Facade of the map\r\n * @private\r\n * @type {M.Map}\r\n */\r\n this.map_ = null;\r\n\r\n /**\r\n * Array of controls\r\n * @private\r\n * @type {Array}\r\n */\r\n this.controls_ = [];\r\n\r\n /**\r\n * Class name of the html view Plugin\r\n * @public\r\n * @type {string}\r\n */\r\n this.className = 'm-plugin-mirrorpanel';\r\n\r\n /**\r\n * Position of the Plugin\r\n * @public\r\n * Posible values: TR | TL | BL | BR\r\n * @type {String}\r\n */\r\n const positions = ['TR', 'TL', 'BL', 'BR'];\r\n this.position = positions.includes(options.position) ? options.position : 'TR';\r\n\r\n /**\r\n * Collapsed attribute\r\n * @public\r\n * @type {boolean}\r\n */\r\n this.collapsed = options.collapsed;\r\n if (this.collapsed === undefined) this.collapsed = true;\r\n\r\n /**\r\n * Collapsible attribute\r\n * @public\r\n * @type {boolean}\r\n */\r\n this.collapsible = options.collapsible;\r\n if (this.collapsible === undefined) this.collapsible = true;\r\n\r\n /**\r\n * Modo de visualización\r\n * Value: number in range 0 - 9\r\n * @type {number}\r\n * @public\r\n */\r\n this.modeViz = options.modeViz;\r\n if (this.modeViz === undefined) this.modeViz = 0;\r\n\r\n /**\r\n * Enabled key functions\r\n * @type {boolean}\r\n * @public\r\n */\r\n this.enabledKeyFunctions = options.enabledKeyFunctions;\r\n if (this.enabledKeyFunctions === undefined) this.enabledKeyFunctions = true;\r\n\r\n /**\r\n * Enabled synchro cursors\r\n * @type {boolean}\r\n * @public\r\n */\r\n this.showCursors = options.showCursors;\r\n if (this.showCursors === undefined) this.showCursors = true;\r\n\r\n /**\r\n * Layer names that will have effects\r\n * @public\r\n * Value: the names separated with coma\r\n * @type {string}\r\n */\r\n\r\n this.mirrorLayers = [];\r\n if (options.mirrorLayers !== undefined) {\r\n if (Array.isArray(options.mirrorLayers)) {\r\n this.mirrorLayers = options.mirrorLayers;\r\n } else {\r\n this.mirrorLayers = options.mirrorLayers.split(\",\");\r\n }\r\n }\r\n\r\n /**\r\n * Layer base for the three mirror maps\r\n * @public\r\n * Value: the names separated with coma\r\n * @type {string}\r\n */\r\n\r\n this.defaultBaseLyrs = [];\r\n if (options.defaultBaseLyrs !== undefined) {\r\n if (Array.isArray(options.defaultBaseLyrs)) {\r\n this.defaultBaseLyrs = options.defaultBaseLyrs;\r\n } else {\r\n this.defaultBaseLyrs = options.defaultBaseLyrs.split(\",\");\r\n }\r\n }\r\n\r\n /** \r\n * Show interface\r\n *@public\r\n *@type{boolean}\r\n */\r\n this.interface = options.interface === undefined ? true : options.interface;\r\n\r\n /**\r\n * Enabled layerswitcher control on mirrors \r\n * @type {boolean}\r\n * @public\r\n */\r\n this.showTOC = options.showTOC;\r\n if (this.showTOC === undefined) this.showTOC = true;\r\n\r\n\r\n /**\r\n *@private\r\n *@type { string }\r\n */\r\n this.tooltip_ = options.tooltip || getValue('tooltip');\r\n\r\n\r\n /**\r\n * Metadata from api.json\r\n * @private\r\n * @type {Object}\r\n */\r\n this.metadata_ = api.metadata;\r\n }\r\n\r\n /**\r\n * This function adds this plugin into the map\r\n *\r\n * @public\r\n * @function\r\n * @param {M.Map} map the map to add the plugin\r\n * @api stable\r\n */\r\n addTo(map) {\r\n const pluginOnLeft = !!(['TL', 'BL'].includes(this.position));\r\n\r\n const values = {\r\n pluginOnLeft,\r\n collapsible: this.collapsible,\r\n collapsed: this.collapsed,\r\n modeViz: this.modeViz,\r\n showCursors: this.showCursors,\r\n mirrorLayers: this.mirrorLayers,\r\n defaultBaseLyrs: this.defaultBaseLyrs,\r\n showTOC: this.showTOC\r\n };\r\n\r\n this.control_ = new MirrorpanelControl(values);\r\n this.controls_.push(this.control_);\r\n this.map_ = map;\r\n\r\n this.panel_ = new M.ui.Panel('panelMirrorpanel', {\r\n collapsible: this.collapsible,\r\n collapsed: this.collapsed,\r\n position: M.ui.position[this.position],\r\n modeViz: this.modeViz,\r\n showCursors: this.showCursors,\r\n className: this.interface ? 'm-plugin-panelMirrorpanel' : 'm-plugin-panelMirrorpanel hidden',\r\n collapsedButtonClass: 'mirrorpanel-icon',\r\n tooltip: this.tooltip_,\r\n });\r\n this.panel_.addControls(this.controls_);\r\n map.addPanels(this.panel_);\r\n\r\n // Keybindings for Ctrl + Shift + (F1-F8) / ESC\r\n document.addEventListener('keydown', (zEvent) => {\r\n if (!this.enabledKeyFunctions) {\r\n return;\r\n }\r\n for (let i = 0; i < 10; i++) {\r\n if (zEvent.ctrlKey && zEvent.shiftKey && zEvent.key === \"F\" + (i + 1)) { // case sensitive\r\n this.control_.manageVisionPanelByCSSGrid(i);\r\n }\r\n }\r\n var keyStr = [\"Control\", \"Shift\", \"Alt\", \"Meta\"].includes(zEvent.key) ? \"\" : zEvent.key;\r\n\r\n var combinedKeys = (zEvent.ctrlKey ? \"Control \" : \"\") +\r\n (zEvent.shiftKey ? \"Shift \" : \"\") +\r\n (zEvent.altKey ? \"Alt \" : \"\") +\r\n (zEvent.metaKey ? \"Meta \" : \"\") + keyStr;\r\n if (combinedKeys === \"Escape\") {\r\n this.control_.manageVisionPanelByCSSGrid(0);\r\n }\r\n\r\n });\r\n\r\n }\r\n\r\n /**\r\n * This function destroys this plugin\r\n *\r\n * @public\r\n * @function\r\n * @api stable\r\n */\r\n destroy() {\r\n document.removeEventListener('keydown', (zEvent) => { });\r\n this.control_.removeMaps();\r\n this.control_.destroyMapsContainer();\r\n this.map_.removeControls([this.control_]);\r\n [this.control_, this.panel_, this.map_, this.collapsible, this.collapsed, this.modeViz, this.enabledKeyFunctions, this.showCursors, this.mirrorLayers, this.defaultBaseLyrs, this.interface, this.showTOC] = [null, null, null, null, null, null, null, null, null, null, null, null];\r\n }\r\n\r\n /**\r\n * This function gets name plugin\r\n * @getter\r\n * @public\r\n * @returns {string}\r\n * @api stable\r\n */\r\n get name() {\r\n return this.name_;\r\n }\r\n\r\n /**\r\n * This function gets metadata plugin\r\n *\r\n * @public\r\n * @function\r\n * @api stable\r\n */\r\n getMetadata() {\r\n return this.metadata_;\r\n }\r\n\r\n /**\r\n * Get the API REST Parameters of the plugin\r\n *\r\n * @function\r\n * @public\r\n * @api\r\n */\r\n getAPIRest() {\r\n return `${this.name}=${this.position}*!${this.collapsed}*!${this.collapsible}*!${this.modeViz}*!${this.enabledKeyFunctions}*!${this.showCursors}*!${this.mirrorLayers}*!${this.defaultBaseLyrs}*!${this.interface}*!${this.showTOC}`;\r\n }\r\n\r\n /**\r\n * Activate plugin\r\n *\r\n * @function\r\n * @public\r\n * @api\r\n */\r\n activate() {\r\n this.control_.activate();\r\n }\r\n\r\n /**\r\n * Desactivate plugin\r\n *\r\n * @function\r\n * @public\r\n * @api\r\n */\r\n deactivate() {\r\n this.control_.deactivate();\r\n }\r\n\r\n\r\n}\r\n","import M$plugin$Mirrorpanel from '/home/irenevinas/m5/mapea-publico/src/plugins/v5/mirrorpanel/src/facade/js/mirrorpanel';\nimport M$control$MirrorpanelControl from '/home/irenevinas/m5/mapea-publico/src/plugins/v5/mirrorpanel/src/facade/js/mirrorpanelcontrol';\nimport M$impl$control$MirrorpanelControl from '/home/irenevinas/m5/mapea-publico/src/plugins/v5/mirrorpanel/src/impl/ol/js/mirrorpanelcontrol';\n\nif (!window.M.plugin) window.M.plugin = {};\nif (!window.M.control) window.M.control = {};\nif (!window.M.impl) window.M.impl = {};\nif (!window.M.impl.control) window.M.impl.control = {};\nwindow.M.plugin.Mirrorpanel = M$plugin$Mirrorpanel;\nwindow.M.control.MirrorpanelControl = M$control$MirrorpanelControl;\nwindow.M.impl.control.MirrorpanelControl = M$impl$control$MirrorpanelControl;\n"],"sourceRoot":""}
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..326344c
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,116 @@
+# M.plugin.Mirrorpanel
+
+Plugin que permite comparar varias capas dividiendo la pantalla en varias partes. Los mapas tienen sus vistas sincronizadas, y podemos ver la representación de una misma zona por distintas capas.
+
+![Imagen - Cortina Vertical](../img/mirrorpanel_1.png)
+
+
+# Dependencias
+
+- mirrorpanel.ol.min.js
+- mirrorpanel.ol.min.css
+
+
+```html
+
+
+```
+
+# Parámetros
+
+- El constructor se inicializa con un JSON de options con los siguientes atributos:
+
+- **position**. Indica la posición donde se mostrará el plugin.
+ - 'TL':top left
+ - 'TR':top right (default)
+ - 'BL':bottom left
+ - 'BR':bottom right
+
+- **collapsible**. Si es *true*, el botón aparece, y puede desplegarse y contraerse. Si es *false*, el botón no aparece. Por defecto tiene el valor *true*.
+
+- **collapsed**. Si es *true*, el panel aparece cerrado. Si es *false*, el panel aparece abierto. Por defecto tiene el valor *true*.
+
+- **modeViz**. Define el tipo de comparación con la que arranca. Rango 0-9.
+ - 0: mapa simple.
+ - 1: dos mapas en vertical.
+ - 2: dos mapas en horizontal.
+ - 3: tres mapas en vertical.
+ - 4: cuatro mapas en vertical.
+ - 5: mosaico con cuatro mapas.
+ - 6: cuatro mapas en horizontal.
+ - 7: tres mapas en proporción 2-1-1.
+ - 8: un mapa arriba y dos abajo.
+ - 9: dos mapas arriba y uno abajo.
+
+- **enabledKeyFunctions**. Si es *true*, se pueden usar las combinaciones de teclas Ctrl + Shift + [F1-F8] para cambiar entre los distintos modos de visualización. Con la tecla *Escape* se destruye el plugin. Por defecto tiene el valor *true*.
+
+- **showCursors**. Si es *true*, muestra cursores sincronziados en cda unao de los mapas espejo. Por defecto tiene el valor *true*.
+
+- **mirrorLayers**. Es un array de capas para mostrar en los mapas espejo y poder compararlas entre sí.
+
+- **defaultBaseLyrs**. Es un array de capas para mostrar como mapa por defecto.
+
+- **interface**. Define si mostrar o no la interfaz del plugin.
+
+- **showTOC**. si es *true* mostrará el control layerswitcher en las capas espejo.
+
+# Eventos
+
+# Multi idioma
+
+Actualmente viene preparado para español e inglés. Para definir con qué idioma arranca, hay que ir al fichero test.js y modificar
+
+```javascript
+M.language.setLang('es');//Idioma español
+M.language.setLang('en');//Idioma inglés
+```
+Se pueden crear más ficheros de idioma. Basta con copiar la estructura de los ficheros **json** de la carpeta *\src\facade\js\i18n* , renombrar con la abreviatura del nuevo idioma (fr para el fránces), y cambiar los textos, manteniendo las *keywords*.
+
+# Ejemplos de uso
+
+## Ejemplo base
+
+```javascript
+const map = M.map({
+ container: 'mapjs',
+ center: {
+ x: -667143.31,
+ y: 4493011.77,
+ },
+ projection: "EPSG:3857*m",
+ zoom: 8,
+});
+
+const mpMirrorPanel = new M.plugin.Mirrorpanel();
+map.addPlugin(mpMirrorPanel);
+```
+
+## Ejemplo 1
+
+```javascript
+const map = M.map({
+ container: 'mapjs',
+ center: {
+ x: -667143.31,
+ y: 4493011.77,
+ },
+ projection: "EPSG:3857*m",
+ zoom: 8,
+});
+
+const mpMirrorPanel = new M.plugin.Mirrorpanel({
+ position: 'TR',
+ collapsible: true,
+ collapsed: false,
+ modeViz: 0,
+ enabledKeyFunctions: true,
+ showCursors: true,
+ defaultBaseLyrs: [
+ 'WMTS*http://www.ign.es/wmts/mapa-raster?*MTN*GoogleMapsCompatible*MTN',
+ 'WMTS*http://www.ign.es/wmts/pnoa-ma?*OI.OrthoimageCoverage*GoogleMapsCompatible*PNOA',
+ 'WMTS*https://wmts-mapa-lidar.idee.es/lidar?*EL.GridCoverageDSM*GoogleMapsCompatible*LiDAR',
+ ],
+});
+
+map.addPlugin(mpMirrorPanel);
+```
\ No newline at end of file
diff --git a/img/mirrorpanel_1.png b/img/mirrorpanel_1.png
new file mode 100644
index 0000000..65eb85d
Binary files /dev/null and b/img/mirrorpanel_1.png differ
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..c0c4932
--- /dev/null
+++ b/package.json
@@ -0,0 +1,58 @@
+{
+ "name": "Mirrorpanel",
+ "version": "1.0.0",
+ "description": "",
+ "keywords": [
+ "map",
+ "mapping",
+ "tool",
+ "sigcorporativo-ja",
+ "mapea",
+ "plugin"
+ ],
+ "license": "ISC",
+ "scripts": {
+ "start": "webpack-dev-server --config=webpack-config/webpack.development.config.js",
+ "prebuild": "node task/create-entrypoint.js",
+ "build": "webpack --config=webpack-config/webpack.production.config.js",
+ "test-build": "npm run build && live-server --open=test/prod.html",
+ "check": "eslint ./src",
+ "fix": "eslint --fix ./src"
+ },
+ "author": "",
+ "devDependencies": {
+ "@babel/core": "^7.10.3",
+ "@babel/plugin-proposal-export-default-from": "^7.0.0-beta.51",
+ "@babel/preset-env": "^7.10.3",
+ "async": "2.1.4",
+ "babel-eslint": "^10.0.1",
+ "babel-loader": "^8.0.0-beta.4",
+ "copy-webpack-plugin": "^4.5.2",
+ "cross-env": "^5.2.0",
+ "css-loader": "^2.1.1",
+ "derequire": "2.0.6",
+ "eslint": "^4.19.1",
+ "eslint-loader": "^2.0.0",
+ "eslint-plugin-import": "^2.21.2",
+ "eslint-plugin-jsx-a11y": "^6.3.1",
+ "eslint-plugin-react": "^7.7.0",
+ "file-loader": "^1.1.11",
+ "fs-extra": "2.0.0",
+ "handlebars": "^4.0.11",
+ "html-loader": "^0.5.5",
+ "live-server": "^1.2.1",
+ "mini-css-extract-plugin": "^0.4.1",
+ "minimist": "^1.2.0",
+ "optimize-css-assets-webpack-plugin": "^5.0.1",
+ "slash": "^3.0.0",
+ "style-loader": "^0.21.0",
+ "supports-color": "^5.3.0",
+ "terser-webpack-plugin": "^1.4.4",
+ "uglify-js": "^2.6.1",
+ "uglifycss": "0.0.29",
+ "url-loader": "^1.0.1",
+ "webpack": "^4.12.0",
+ "webpack-cli": "^3.3.12",
+ "webpack-dev-server": "^3.1.14"
+ }
+}
diff --git a/src/api.json b/src/api.json
new file mode 100644
index 0000000..53c0a1a
--- /dev/null
+++ b/src/api.json
@@ -0,0 +1,120 @@
+{
+ "url": {
+ "name": "mirrorpanel",
+ "separator": "*!"
+ },
+ "constructor": "M.plugin.Mirrorpanel",
+ "parameters": [
+ {
+ "type": "object",
+ "properties": [
+ {
+ "type": "simple",
+ "name": "position",
+ "possibleValues": [
+ "TL",
+ "TR",
+ "BL",
+ "BR"
+ ],
+ "position": 0
+ },
+ {
+ "type": "boolean",
+ "name": "collapsed",
+ "position": 1
+ },
+ {
+ "type": "boolean",
+ "name": "collapsible",
+ "position": 2
+ },
+ {
+ "type": "simple",
+ "name": "modeViz",
+ "position": 3
+ },
+ {
+ "type": "boolean",
+ "name": "enabledKeyFunctions",
+ "position": 4
+ },
+ {
+ "type": "boolean",
+ "name": "showCursors",
+ "position": 5
+ },
+ {
+ "type": "simple",
+ "name": "mirrorLayers",
+ "position": 6
+ },
+ {
+ "type": "simple",
+ "name": "defaultBaseLyrs",
+ "position": 7
+ },
+ {
+ "type": "boolean",
+ "name": "interface",
+ "position": 8
+ },
+ {
+ "type": "boolean",
+ "name": "showToc",
+ "position": 9
+ }
+ ]
+ }
+ ],
+ "files": {
+ "ol": {
+ "scripts": ["mirrorpanel.ol.min.js"],
+ "styles": ["mirrorpanel.ol.min.css"]
+ }
+ },
+ "metadata": {
+ "uuid_plugin": "",
+ "uuid_version_plugin": "",
+ "version_ficha_metadatos": "",
+ "name": "Mirrorpanel",
+ "description": "Plugin que permite comparar varias capas dividiendo la pantalla en varias partes.",
+ "text": "Plugin que permite comparar varias capas dividiendo la pantalla en varias partes. Los mapas tienen sus vistas sincronizadas, y podemos ver la representación de una misma zona por distintas capas.",
+ "version": "1.0.0",
+ "date": "Julio, 2020",
+ "author": "",
+ "org": "",
+ "tags": "mapea,plugin",
+ "icon": "./facade/assets/icons/icons.svg",
+ "buttons": [
+ {
+ "title": "",
+ "description": "",
+ "querySelector": ""
+ },
+ {
+ "title": "",
+ "description": "",
+ "querySelector": ""
+ }
+ ],
+ "dependencies": {
+ "modules": [
+ "",
+ ""
+ ],
+ "plugins": [
+ {
+ "uuid": "",
+ "name": ""
+ }
+ ],
+ "services": [
+ {
+ "name": "",
+ "description": ""
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/facade/assets/css/mirrorpanel.css b/src/facade/assets/css/mirrorpanel.css
new file mode 100644
index 0000000..64b14e3
--- /dev/null
+++ b/src/facade/assets/css/mirrorpanel.css
@@ -0,0 +1,338 @@
+
+
+/** Estilos sobreescritos */
+
+@font-face {
+ font-family: 'mirrorpanel';
+ src: url('../fonts/mirrorpanel.eot?b6yytp');
+ src: url('../fonts/mirrorpanel.eot?b6yytp#iefix') format('embedded-opentype'), url('../fonts/mirrorpanel.ttf?b6yytp') format('truetype'), url('../fonts/mirrorpanel.woff?b6yytp') format('woff'), url('../fonts/mirrorpanel.svg?b6yytp#mirrorpanel') format('svg');
+ font-weight: normal;
+ font-style: normal;
+ font-display: block;
+}
+
+
+/** Estilos propios*/
+
+.info {
+ position: absolute;
+ width: 60%;
+ padding: 5px;
+ top: 10px;
+ left: 20%;
+ background: rgba(245, 245, 245, 0.8);
+ font-size: large;
+ border-radius: 5px;
+ border-style: dashed;
+ border-width: 2px;
+ text-align: center;
+}
+
+.m-panel-btn.mirrorpanel-icon {
+ /*color: #e8f5e9 !important;*/
+ color: #718bd3 !important;
+}
+
+.m-plugin-panelMirrorpanel.hidden {
+ display: none;
+}
+
+div.m-plugin-panelMirrorpanel.opened>.m-panel-btn.g-cartografia-flecha-derecha,
+div.m-plugin-panelMirrorpanel.opened>.m-panel-btn.g-cartografia-flecha-izquierda {
+ color: #e8f5e9 !important;
+ /*color: #718bd3 !important;*/
+}
+
+.m-plugin-panelMirrorpanel.collapsed>div.m-panel-controls {
+ display: none !important;
+}
+
+div.m-plugin-panelMirrorpanel.opened{
+ min-width: max-content;
+}
+
+/*Rolled button in panels on the right*/
+
+.m-areas>div.m-area.m-right>div.m-plugin-panelMirrorpanel.opened>button.m-panel-btn {
+ position: absolute;
+ left: -2.5rem;
+ background-color: #718bd3;
+ /*background-color: #fff;*/
+}
+
+
+/*Rolled button in panels on the left*/
+
+.m-areas>div.m-area.m-left>div.m-plugin-panelMirrorpanel.opened>button.m-panel-btn {
+ position: absolute;
+ right: -2.5rem;
+ left: unset !important;
+ background-color: #718bd3;
+ /*background-color: #fff;*/
+}
+
+.div-m-mirrorpanel-panel {
+ padding: .7rem;
+}
+
+.m-mirrorpanel-effect-buttoms {
+ padding: 0.3rem 0;
+ text-align: center;
+}
+
+div#m-mirrorpanel-titulo {
+ /*background-color: #718bd3;
+ color: white;*/
+ display: block;
+ font-size: 15px;
+ height: 40px;
+ line-height: 40px;
+ padding: 0 0.3rem;
+ text-align: center;
+ border-radius: 4px 4px 0 0;
+ border-bottom: 1.5px solid rgba(0, 0, 0, .12);
+}
+
+
+/*
+Estilos del botón
+*/
+
+.m-mirrorpanel-container .big-button {
+ font-size: 32px;
+ background: none;
+ border: none;
+ cursor: pointer;
+ opacity: .75;
+ transition: all .25s ease;
+ color: #404040;
+ outline: none;
+}
+
+.m-mirrorpanel-container .big-button:hover {
+ color: #718bd3;
+}
+
+.m-mirrorpanel-container .buttom-pressed {
+ color: #718bd3;
+}
+
+[class^="mirrorpanel-"],
+[class*=" mirrorpanel-"] {
+ font-family: 'mirrorpanel' !important;
+ speak: never;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+[class^="mirrorpanel-"]:before,
+[class*=" mirrorpanel-"]:before {
+ display: block;
+}
+
+.mirrorpanel-icon:before {
+ content: "\e802";
+ font-family: 'mirrorpanel' !important;
+}
+
+.mirrorpanel-modeviz0:before {
+ content: "\e804";
+}
+
+.mirrorpanel-modeviz1:before {
+ content: "\e803";
+}
+
+.mirrorpanel-modeviz2:before {
+ content: "\e803";
+ transform: rotate(90deg);
+}
+
+.mirrorpanel-modeviz3:before {
+ content: "\e805";
+}
+
+.mirrorpanel-modeviz4:before {
+ content: "\e806";
+}
+
+.mirrorpanel-modeviz5:before {
+ content: "\e808";
+}
+
+.mirrorpanel-modeviz6:before {
+ content: "\e806";
+ transform: rotate(90deg);
+}
+
+.mirrorpanel-modeviz7:before {
+ content: "\e807";
+}
+
+.mirrorpanel-modeviz8:before {
+ content: "\e809";
+}
+
+.mirrorpanel-modeviz9:before {
+ content: "\e809";
+ transform: rotate(180deg);
+}
+
+
+/* Grid classes */
+
+.mirrorpanel-grid {
+ display: grid;
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ grid-template-columns: 1fr;
+ grid-template-rows: 1fr;
+ gap: 1px 1px;
+ grid-template-areas: mirror1;
+}
+
+.mirrorpanel-grid .mirror1,
+.mirrorpanel-grid .mirror2,
+.mirrorpanel-grid .mirror3,
+.mirrorpanel-grid .mirror4 {
+ display: none;
+ min-height: 100%;
+}
+
+.mirrorpanel-grid .mirror1,
+.mirrorpanel-grid:not(.modeViz0) .mirror2,
+.mirrorpanel-grid:not(.modeViz0):not(.modeViz1):not(.modeViz2) .mirror3,
+.mirrorpanel-grid.modeViz4 .mirror4,
+.mirrorpanel-grid.modeViz5 .mirror4,
+.mirrorpanel-grid.modeViz6 .mirror4 {
+ display: block !important;
+}
+
+.mirror1 { grid-area: mirror1; }
+.mirror2 { grid-area: mirror2; }
+.mirror3 { grid-area: mirror3; }
+.mirror4 { grid-area: mirror4; }
+
+/**
+ * | A |
+ */
+
+.mirrorpanel-grid.modeViz0 {
+ grid-template-columns: 1fr !important;
+ grid-template-rows: 1fr !important;
+ grid-template-areas: 'mirror1' !important;
+}
+
+
+/**
+ * | A | B |
+ */
+
+.mirrorpanel-grid.modeViz1 {
+ grid-template-columns: 1fr 1fr !important;
+ grid-template-rows: 1fr !important;
+ grid-template-areas: 'mirror1 mirror2' !important;
+}
+
+
+/**
+* | A |
+* | B |
+*/
+
+.mirrorpanel-grid.modeViz2 {
+ grid-template-columns: 1fr !important;
+ grid-template-rows: 1fr 1fr !important;
+ grid-template-areas: 'mirror1' 'mirror2' !important;
+}
+
+
+/**
+* | A | B | C |
+*/
+
+.mirrorpanel-grid.modeViz3 {
+ grid-template-columns: 1fr 1fr 1fr !important;
+ grid-template-rows: 1fr !important;
+ grid-template-areas: 'mirror1 mirror2 mirror3' !important;
+}
+
+
+/**
+* | A | B | C | D |
+*/
+
+.mirrorpanel-grid.modeViz4 {
+ grid-template-columns: 1fr 1fr 1fr 1fr !important;
+ grid-template-rows: 1fr !important;
+ grid-template-areas: 'mirror1 mirror2 mirror3 mirror4' !important;
+}
+
+
+/**
+* | A | B |
+* | C | D |
+*/
+
+.mirrorpanel-grid.modeViz5 {
+ grid-template-columns: 1fr 1fr !important;
+ grid-template-rows: 1fr 1fr !important;
+ grid-template-areas: 'mirror1 mirror2' 'mirror3 mirror4' !important;
+}
+
+
+/**
+* | A |
+* | B |
+* | C |
+* | D |
+*/
+
+.mirrorpanel-grid.modeViz6 {
+ grid-template-columns: 1fr !important;
+ grid-auto-rows: 1fr 1fr 1fr 1fr !important;
+ grid-template-areas: 'mirror1' 'mirror2' 'mirror3' 'mirror4' !important;
+}
+
+
+/**
+* | A | B | C |
+*/
+
+.mirrorpanel-grid.modeViz7 {
+ grid-template-columns: 2fr 1fr 1fr !important;
+ grid-template-rows: 1fr !important;
+ grid-template-areas: 'mirror1 mirror2 mirror3' !important;
+}
+
+
+/**
+* | A |
+* | B | C |
+*/
+
+.mirrorpanel-grid.modeViz8 {
+ grid-template-columns: 1fr 1fr !important;
+ grid-template-rows: 1fr 1fr !important;
+ grid-template-areas: 'mirror1 mirror1' 'mirror2 mirror3' !important;
+}
+
+
+/**
+* | A | B |
+* | C |
+*/
+
+.mirrorpanel-grid.modeViz9 {
+ grid-template-columns: 1fr 1fr !important;
+ grid-template-rows: 1fr 1fr !important;
+ grid-template-areas: 'mirror1 mirror2' 'mirror3 mirror3' !important;
+}
+
diff --git a/src/facade/assets/fonts/mirrorpanel.eot b/src/facade/assets/fonts/mirrorpanel.eot
new file mode 100644
index 0000000..f73cd5b
Binary files /dev/null and b/src/facade/assets/fonts/mirrorpanel.eot differ
diff --git a/src/facade/assets/fonts/mirrorpanel.svg b/src/facade/assets/fonts/mirrorpanel.svg
new file mode 100644
index 0000000..1bd488a
--- /dev/null
+++ b/src/facade/assets/fonts/mirrorpanel.svg
@@ -0,0 +1,18 @@
+
+
+
\ No newline at end of file
diff --git a/src/facade/assets/fonts/mirrorpanel.ttf b/src/facade/assets/fonts/mirrorpanel.ttf
new file mode 100644
index 0000000..2db837c
Binary files /dev/null and b/src/facade/assets/fonts/mirrorpanel.ttf differ
diff --git a/src/facade/assets/fonts/mirrorpanel.woff b/src/facade/assets/fonts/mirrorpanel.woff
new file mode 100644
index 0000000..9590c1a
Binary files /dev/null and b/src/facade/assets/fonts/mirrorpanel.woff differ
diff --git a/src/facade/assets/icons/icon.svg b/src/facade/assets/icons/icon.svg
new file mode 100644
index 0000000..d67d177
--- /dev/null
+++ b/src/facade/assets/icons/icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/facade/js/i18n/en.json b/src/facade/js/i18n/en.json
new file mode 100644
index 0000000..90c2fb8
--- /dev/null
+++ b/src/facade/js/i18n/en.json
@@ -0,0 +1,14 @@
+{
+ "tooltip": "Mirror Comparison",
+ "title": "Mirror Maps",
+ "modViz0": "Standard map",
+ "modViz1": "Vertical two maps",
+ "modViz2": "Horizontal two maps",
+ "modViz3": "Vertical three maps",
+ "modViz4": "Vertical four maps",
+ "modViz5": "Mosaic maps",
+ "modViz6": "Horizontal four maps",
+ "modViz7": "Vertical 2-1-1 proportional maps",
+ "modViz8": "One map above and two below",
+ "modViz9": "Two maps above and one below"
+}
diff --git a/src/facade/js/i18n/es.json b/src/facade/js/i18n/es.json
new file mode 100644
index 0000000..e3b12d6
--- /dev/null
+++ b/src/facade/js/i18n/es.json
@@ -0,0 +1,14 @@
+{
+ "tooltip": "Comparador de mapas espejo",
+ "title": "Mapas espejo",
+ "modViz0": "Mapa standard",
+ "modViz1": "Dos mapas en vertical",
+ "modViz2": "Dos mapas en horizontal",
+ "modViz3": "Tres mapas en vertical",
+ "modViz4": "Cuatro mapas en vertical",
+ "modViz5": "Mosaico de mapas",
+ "modViz6": "Cuatro mapas en horizontal",
+ "modViz7": "Tres mapas en proporción 2-1-1",
+ "modViz8": "Un mapa arriba y dos abajo",
+ "modViz9": "Dos mapas arriba y uno abajo"
+}
diff --git a/src/facade/js/i18n/language.js b/src/facade/js/i18n/language.js
new file mode 100644
index 0000000..682ea35
--- /dev/null
+++ b/src/facade/js/i18n/language.js
@@ -0,0 +1,69 @@
+import en from './en';
+import es from './es';
+
+/**
+ * Default object with es and en translate.
+ *
+ * @const
+ * @type {object}
+ */
+const translations = {
+ en,
+ es,
+};
+
+const getLang = () => {
+ let res = 'es';
+ if (typeof M.language.getLang === 'function') {
+ res = M.language.getLang();
+ }
+
+ return res;
+};
+
+/**
+ * This function sets a new language translate.
+ * @param {string} lang
+ * @param {JSON} json
+ * @public
+ * @api
+ */
+export const addTranslation = (lang, json) => {
+ translations[lang] = json;
+};
+
+/**
+ * This function gets a language translate.
+ *
+ * @param {string} lang
+ * @return {JSON}
+ * @public
+ * @api
+ */
+export const getTranslation = (lang) => {
+ return translations[lang];
+};
+
+/**
+ * This function gets a language value from key
+ *
+ * @public
+ * @param {string}
+ * @param {string}
+ * @return {string}
+ * @public
+ * @api
+ */
+
+export const getValue = (keyPath, lang = getLang()) => {
+ const translation = getTranslation(lang);
+ let value = '';
+ if (M.utils.isNullOrEmpty(translation)) {
+ /* eslint-disable no-console */
+ console.warn(`The translation '${lang}' has not been defined.`);
+ } else {
+ value = keyPath.split('.').reduce((prev, current) => prev[current], translation);
+ }
+
+ return value;
+};
diff --git a/src/facade/js/mirrorpanel.js b/src/facade/js/mirrorpanel.js
new file mode 100644
index 0000000..97199ba
--- /dev/null
+++ b/src/facade/js/mirrorpanel.js
@@ -0,0 +1,298 @@
+/**
+ * @module M/plugin/Mirrorpanel
+ */
+import 'assets/css/mirrorpanel';
+import MirrorpanelControl from './mirrorpanelcontrol';
+import api from '../../api';
+import { getValue } from './i18n/language'; //e2m: Multilanguage support
+
+export default class Mirrorpanel extends M.Plugin {
+ /**
+ * @classdesc
+ * Main facade plugin object. This class creates a plugin
+ * object which has an implementation Object
+ *
+ * @constructor
+ * @extends {M.Plugin}
+ * @param {Object} impl implementation object
+ * @api stable
+ */
+ constructor(options = {}) {
+ super();
+
+ /**
+ * Name plugin
+ * @private
+ * @type {String}
+ */
+ this.name_ = 'mirrorpanel';
+
+ /**
+ * Facade of the map
+ * @private
+ * @type {M.Map}
+ */
+ this.map_ = null;
+
+ /**
+ * Array of controls
+ * @private
+ * @type {Array}
+ */
+ this.controls_ = [];
+
+ /**
+ * Class name of the html view Plugin
+ * @public
+ * @type {string}
+ */
+ this.className = 'm-plugin-mirrorpanel';
+
+ /**
+ * Position of the Plugin
+ * @public
+ * Posible values: TR | TL | BL | BR
+ * @type {String}
+ */
+ const positions = ['TR', 'TL', 'BL', 'BR'];
+ this.position = positions.includes(options.position) ? options.position : 'TR';
+
+ /**
+ * Collapsed attribute
+ * @public
+ * @type {boolean}
+ */
+ this.collapsed = options.collapsed;
+ if (this.collapsed === undefined) this.collapsed = true;
+
+ /**
+ * Collapsible attribute
+ * @public
+ * @type {boolean}
+ */
+ this.collapsible = options.collapsible;
+ if (this.collapsible === undefined) this.collapsible = true;
+
+ /**
+ * Modo de visualización
+ * Value: number in range 0 - 9
+ * @type {number}
+ * @public
+ */
+ this.modeViz = options.modeViz;
+ if (this.modeViz === undefined) this.modeViz = 0;
+
+ /**
+ * Enabled key functions
+ * @type {boolean}
+ * @public
+ */
+ this.enabledKeyFunctions = options.enabledKeyFunctions;
+ if (this.enabledKeyFunctions === undefined) this.enabledKeyFunctions = true;
+
+ /**
+ * Enabled synchro cursors
+ * @type {boolean}
+ * @public
+ */
+ this.showCursors = options.showCursors;
+ if (this.showCursors === undefined) this.showCursors = true;
+
+ /**
+ * Layer names that will have effects
+ * @public
+ * Value: the names separated with coma
+ * @type {string}
+ */
+
+ this.mirrorLayers = [];
+ if (options.mirrorLayers !== undefined) {
+ if (Array.isArray(options.mirrorLayers)) {
+ this.mirrorLayers = options.mirrorLayers;
+ } else {
+ this.mirrorLayers = options.mirrorLayers.split(",");
+ }
+ }
+
+ /**
+ * Layer base for the three mirror maps
+ * @public
+ * Value: the names separated with coma
+ * @type {string}
+ */
+
+ this.defaultBaseLyrs = [];
+ if (options.defaultBaseLyrs !== undefined) {
+ if (Array.isArray(options.defaultBaseLyrs)) {
+ this.defaultBaseLyrs = options.defaultBaseLyrs;
+ } else {
+ this.defaultBaseLyrs = options.defaultBaseLyrs.split(",");
+ }
+ }
+
+ /**
+ * Show interface
+ *@public
+ *@type{boolean}
+ */
+ this.interface = options.interface === undefined ? true : options.interface;
+
+ /**
+ * Enabled layerswitcher control on mirrors
+ * @type {boolean}
+ * @public
+ */
+ this.showTOC = options.showTOC;
+ if (this.showTOC === undefined) this.showTOC = true;
+
+
+ /**
+ *@private
+ *@type { string }
+ */
+ this.tooltip_ = options.tooltip || getValue('tooltip');
+
+
+ /**
+ * Metadata from api.json
+ * @private
+ * @type {Object}
+ */
+ this.metadata_ = api.metadata;
+ }
+
+ /**
+ * This function adds this plugin into the map
+ *
+ * @public
+ * @function
+ * @param {M.Map} map the map to add the plugin
+ * @api stable
+ */
+ addTo(map) {
+ const pluginOnLeft = !!(['TL', 'BL'].includes(this.position));
+
+ const values = {
+ pluginOnLeft,
+ collapsible: this.collapsible,
+ collapsed: this.collapsed,
+ modeViz: this.modeViz,
+ showCursors: this.showCursors,
+ mirrorLayers: this.mirrorLayers,
+ defaultBaseLyrs: this.defaultBaseLyrs,
+ showTOC: this.showTOC
+ };
+
+ this.control_ = new MirrorpanelControl(values);
+ this.controls_.push(this.control_);
+ this.map_ = map;
+
+ this.panel_ = new M.ui.Panel('panelMirrorpanel', {
+ collapsible: this.collapsible,
+ collapsed: this.collapsed,
+ position: M.ui.position[this.position],
+ modeViz: this.modeViz,
+ showCursors: this.showCursors,
+ className: this.interface ? 'm-plugin-panelMirrorpanel' : 'm-plugin-panelMirrorpanel hidden',
+ collapsedButtonClass: 'mirrorpanel-icon',
+ tooltip: this.tooltip_,
+ });
+ this.panel_.addControls(this.controls_);
+ map.addPanels(this.panel_);
+
+ // Keybindings for Ctrl + Shift + (F1-F8) / ESC
+ document.addEventListener('keydown', (zEvent) => {
+ if (!this.enabledKeyFunctions) {
+ return;
+ }
+ for (let i = 0; i < 10; i++) {
+ if (zEvent.ctrlKey && zEvent.shiftKey && zEvent.key === "F" + (i + 1)) { // case sensitive
+ this.control_.manageVisionPanelByCSSGrid(i);
+ }
+ }
+ var keyStr = ["Control", "Shift", "Alt", "Meta"].includes(zEvent.key) ? "" : zEvent.key;
+
+ var combinedKeys = (zEvent.ctrlKey ? "Control " : "") +
+ (zEvent.shiftKey ? "Shift " : "") +
+ (zEvent.altKey ? "Alt " : "") +
+ (zEvent.metaKey ? "Meta " : "") + keyStr;
+ if (combinedKeys === "Escape") {
+ this.control_.manageVisionPanelByCSSGrid(0);
+ }
+
+ });
+
+ }
+
+ /**
+ * This function destroys this plugin
+ *
+ * @public
+ * @function
+ * @api stable
+ */
+ destroy() {
+ document.removeEventListener('keydown', (zEvent) => { });
+ this.control_.removeMaps();
+ this.control_.destroyMapsContainer();
+ this.map_.removeControls([this.control_]);
+ [this.control_, this.panel_, this.map_, this.collapsible, this.collapsed, this.modeViz, this.enabledKeyFunctions, this.showCursors, this.mirrorLayers, this.defaultBaseLyrs, this.interface, this.showTOC] = [null, null, null, null, null, null, null, null, null, null, null, null];
+ }
+
+ /**
+ * This function gets name plugin
+ * @getter
+ * @public
+ * @returns {string}
+ * @api stable
+ */
+ get name() {
+ return this.name_;
+ }
+
+ /**
+ * This function gets metadata plugin
+ *
+ * @public
+ * @function
+ * @api stable
+ */
+ getMetadata() {
+ return this.metadata_;
+ }
+
+ /**
+ * Get the API REST Parameters of the plugin
+ *
+ * @function
+ * @public
+ * @api
+ */
+ getAPIRest() {
+ return `${this.name}=${this.position}*!${this.collapsed}*!${this.collapsible}*!${this.modeViz}*!${this.enabledKeyFunctions}*!${this.showCursors}*!${this.mirrorLayers}*!${this.defaultBaseLyrs}*!${this.interface}*!${this.showTOC}`;
+ }
+
+ /**
+ * Activate plugin
+ *
+ * @function
+ * @public
+ * @api
+ */
+ activate() {
+ this.control_.activate();
+ }
+
+ /**
+ * Desactivate plugin
+ *
+ * @function
+ * @public
+ * @api
+ */
+ deactivate() {
+ this.control_.deactivate();
+ }
+
+
+}
diff --git a/src/facade/js/mirrorpanelcontrol.js b/src/facade/js/mirrorpanelcontrol.js
new file mode 100644
index 0000000..8dc0d9a
--- /dev/null
+++ b/src/facade/js/mirrorpanelcontrol.js
@@ -0,0 +1,401 @@
+/**
+ * @module M/control/MirrorpanelControl
+ */
+
+import MirrorpanelImplControl from 'impl/mirrorpanelcontrol';
+import template from 'templates/mirrorpanel';
+import { getValue as getValueTranslate } from './i18n/language';
+
+export default class MirrorpanelControl extends M.Control {
+ /**
+ * @classdesc
+ * Main constructor of the class. Creates a PluginControl
+ * control
+ *
+ * @constructor
+ * @extends {M.Control}
+ * @api stable
+ */
+ constructor(values) {
+ // 1. checks if the implementation can create PluginControl
+ if (M.utils.isUndefined(MirrorpanelImplControl)) {
+ M.exception('La implementación usada no puede crear controles MirrorpanelControl');
+ }
+ // 2. implementation of this control
+ const impl = new MirrorpanelImplControl();
+ super(impl, 'Mirrorpanel');
+
+ /**
+ * Template
+ * @public
+ * @type { HTMLElement }
+ */
+ this.template = null;
+
+ /**
+ * Visual mode
+ * @private
+ * @type {Number}
+ */
+ this.modeViz = values.modeViz;
+
+ /**
+ * Mirror maps with plugins
+ * @private
+ * @type {boolean}
+ */
+ this.showCursors = values.showCursors;
+
+ /**
+ * Defining mirror maps variables
+ */
+ this.mapL = { A: null, B: null, C: null, D: null, }
+ this.lyrCursor = { A: null, B: null, C: null, D: null, }
+ this.featureLyrCursor = { A: null, B: null, C: null, D: null, }
+
+ /**
+ * Defining cursor style
+ */
+ this.styleCursor = new M.style.Point({
+ icon: {
+ form: M.style.form.CIRCLE,
+ fontsize: 0.5,
+ radius: 5,
+ rotation: 0,
+ rotate: false,
+ offset: [0, 0],
+ color: 'black',
+ fill: 'red',
+ gradientcolor: '#088A85',
+ opacity: 0.8
+ }
+ });
+
+ /**
+ * Default layers for mirror maps
+ * @public
+ * @public {Array}
+ */
+ this.defaultBaseLyrs = values.defaultBaseLyrs;
+
+ /**
+ * All layers
+ * @public
+ * @public {Array}
+ */
+ this.mirrorLayers = values.mirrorLayers;
+
+ /**
+ * Enable layerswitcher control
+ * @public
+ * @public {Array}
+ */
+ this.showTOC = values.showTOC;
+
+ this.createMapContainers();
+ }
+
+
+ /**
+ * This function creates the view
+ *
+ * @public
+ * @function
+ * @param {M.Map} map to add the control
+ * @api stable
+ */
+ createView(map) {
+ if (!M.template.compileSync) {
+ M.template.compileSync = (string, options) => {
+ let templateCompiled;
+ let templateVars = {};
+ let parseToHtml;
+ if (!M.utils.isUndefined(options)) {
+ templateVars = M.utils.extends(templateVars, options.vars);
+ parseToHtml = options.parseToHtml;
+ }
+ const templateFn = Handlebars.compile(string);
+ const htmlText = templateFn(templateVars);
+ if (parseToHtml !== false) {
+ templateCompiled = M.utils.stringToHtml(htmlText);
+ } else {
+ templateCompiled = htmlText;
+ }
+ return templateCompiled;
+ };
+ }
+
+ this.mapL['A'] = map;
+ if (this.mirrorLayers.length > 0) {
+ this.mapL['A'].addLayers(this.mirrorLayers);
+ this.mapL['A'].getLayers().forEach((l) => {
+ if (l.zindex_ !== 0) { l.setVisible(false); }
+ });
+ }
+ if (this.showCursors) { this.addLayerCursor('A'); }
+ return new Promise((success, fail) => {
+ let templateOptions = '';
+ templateOptions = {
+ jsonp: true,
+ vars: {
+ translations: {
+ title: getValueTranslate('title'),
+ modViz0: getValueTranslate('modViz0'),
+ modViz1: getValueTranslate('modViz1'),
+ modViz2: getValueTranslate('modViz2'),
+ modViz3: getValueTranslate('modViz3'),
+ modViz4: getValueTranslate('modViz4'),
+ modViz5: getValueTranslate('modViz5'),
+ modViz6: getValueTranslate('modViz6'),
+ modViz7: getValueTranslate('modViz7'),
+ modViz8: getValueTranslate('modViz8'),
+ modViz9: getValueTranslate('modViz9')
+ }
+ }
+ };
+
+ this.template = M.template.compileSync(template, templateOptions);
+
+ // Button's click events
+ this.template.querySelectorAll('button[id^="set-mirror-"]')
+ .forEach((button, modeViz) => {
+ button.addEventListener('click', evt => {
+ this.manageVisionPanelByCSSGrid(modeViz);
+ })
+ });
+
+ // Apply default vision
+ this.manageVisionPanelByCSSGrid(this.modeViz);
+ success(this.template);
+ });
+
+ }
+
+ /**
+ * This function is called on the control activation
+ *
+ * @public
+ * @function
+ * @api stable
+ */
+ activate() {
+ super.activate();
+ }
+ /**
+ * This function is called on the control deactivation
+ *
+ * @public
+ * @function
+ * @api stable
+ */
+ deactivate() {
+ super.deactivate();
+ }
+
+ /**
+ * Initial configurations for applying CSS grid.
+ *
+ */
+ createMapContainers() {
+ const bigContainer = document.createElement('div');
+ bigContainer.id = "lienzo";
+ bigContainer.classList.add('mirrorpanel-grid');
+
+ const mapjsA = document.getElementById("mapjs") || document.getElementById("map");
+ document.body.insertBefore(bigContainer, mapjsA);
+ mapjsA.classList.add('mirror1');
+ bigContainer.appendChild(mapjsA);
+
+ const mapjsB = document.createElement('div');
+ mapjsB.id = "mapjsB";
+ mapjsB.classList.add('mirror2');
+ bigContainer.appendChild(mapjsB);
+
+ const mapjsC = document.createElement('div');
+ mapjsC.id = "mapjsC";
+ mapjsC.classList.add('mirror3');
+ bigContainer.appendChild(mapjsC);
+
+ const mapjsD = document.createElement('div');
+ mapjsD.id = "mapjsD";
+ mapjsD.classList.add('mirror4');
+ bigContainer.appendChild(mapjsD);
+ }
+
+ /**
+ * This function shows/hides panel for differents viz options.
+ * The mirror maps are launched from here
+ *
+ */
+ manageVisionPanelByCSSGrid(modeViz) {
+ let oldModeViz = this.modeViz;
+ let map0 = document.getElementById('mapjs') || document.getElementById('map');
+ map0.style.display = 'none';
+ document.getElementById('mapjsB').style.display = 'none';
+ document.getElementById('mapjsC').style.display = 'none';
+ document.getElementById('mapjsD').style.display = 'none';
+ this.template.querySelector('#set-mirror-' + oldModeViz).classList.remove('buttom-pressed');
+
+ for (let i = 0; i < 10; i++) {
+ document.getElementById('lienzo').classList.remove('modeViz' + i);
+ }
+ document.getElementById('lienzo').classList.add('modeViz' + modeViz);
+
+ //Create map objects by modeviz
+ if ([1, 2].includes(modeViz)) {
+ if (this.mapL['B'] == null) {
+ this.createMapObjects('B');//Create MapB
+ }
+ }
+ if ([3, 7, 8, 9].includes(modeViz)) {
+ if (this.mapL['B'] == null) {
+ this.createMapObjects('B');//Create MapB
+ }
+ if (this.mapL['C'] == null) {
+ this.createMapObjects('C');//Create MapC
+ }
+ }
+ if ([4, 5, 6].includes(modeViz)) {
+ if (this.mapL['B'] == null) {
+ this.createMapObjects('B');//Create MapB
+ }
+ if (this.mapL['C'] == null) {
+ this.createMapObjects('C');//Create MapC
+ }
+ if (this.mapL['D'] == null) {
+ this.createMapObjects('D');//Create MapD
+ }
+ }
+
+ this.modeViz = modeViz;
+ this.template.querySelector('#set-mirror-' + modeViz).classList.add('buttom-pressed');
+ this.map_.refresh();
+ if (this.mapL['B'] !== null) { this.mapL['B'].refresh(); }
+ if (this.mapL['C'] !== null) { this.mapL['C'].refresh(); }
+ if (this.mapL['D'] !== null) { this.mapL['D'].refresh(); }
+ }
+
+ /**
+ * Create mirror map object synchro with the main map
+ */
+ createMapObjects(mapLyr) {
+ let defLyr = null;
+ switch (mapLyr) {
+ case 'B':
+ if (this.defaultBaseLyrs[1]) defLyr = this.defaultBaseLyrs[0];
+ break;
+ case 'C':
+ if (this.defaultBaseLyrs[2]) defLyr = this.defaultBaseLyrs[1];
+ break;
+ case 'D':
+ if (this.defaultBaseLyrs[3]) defLyr = this.defaultBaseLyrs[2];
+ break;
+ default:
+ defLyr = this.map_.getLayers()[0].setMap(this);
+ break;
+ }
+ this.mapL[mapLyr] = M.map({
+ container: 'mapjs' + mapLyr,
+ layers: defLyr,
+ controls: this.showTOC ? ['layerswitcher'] : '',
+ center: this.map_.getCenter(),
+ projection: this.map_.getProjection().code + '*' + this.map_.getProjection().units,
+ zoom: this.map_.getZoom(),
+ });
+ this.mapL[mapLyr].getMapImpl().setView(this.map_.getMapImpl().getView());
+
+ if (this.showCursors) { this.addLayerCursor(mapLyr); }
+ if (this.mirrorLayers.length > 0) {
+ this.mapL[mapLyr].addLayers(this.mirrorLayers);
+ this.mapL[mapLyr].getLayers().forEach((l) => {
+ if (l.zindex_ !== 0) { l.setVisible(false); }
+ });
+ }
+ this.mapL[mapLyr].refresh();
+ }
+
+ /**
+ * Adding a layer for cursor on Map
+ */
+ addLayerCursor(mapLyr) {
+ // Cursor Layer
+ this.lyrCursor[mapLyr] = new M.layer.Vector({
+ name: 'Coordenadas centro ' + mapLyr,
+ }, { displayInLayerSwitcher: false });
+
+ this.featureLyrCursor[mapLyr] = new M.Feature('Center' + mapLyr, {
+ type: 'Feature',
+ properties: {},
+ geometry: {
+ type: 'Point',
+ coordinates: this.mapL[mapLyr].getCenter(),
+ },
+ });
+
+ this.lyrCursor[mapLyr].addFeatures([this.featureLyrCursor[mapLyr]]);
+ this.lyrCursor[mapLyr].setStyle(this.styleCursor);
+ this.lyrCursor[mapLyr].setZIndex(5000);
+ this.mapL[mapLyr].addLayers(this.lyrCursor[mapLyr]);
+
+ this.mapL[mapLyr].getMapImpl().on('pointermove', (event) => {
+ this.lyrCursor[mapLyr].setVisible(false);
+ Object.keys(this.featureLyrCursor).forEach(k => {
+ if (this.mapL[k]) {
+ this.mapL[k].getMapImpl().setView(this.mapL[mapLyr].getMapImpl().getView());
+ }
+ if (k != mapLyr) {
+ if (this.featureLyrCursor[k] !== null) {
+ this.lyrCursor[k].setVisible(true);
+ this.featureLyrCursor[k].setGeometry({
+ type: 'Point',
+ coordinates: event.coordinate,
+ });
+ }
+ }
+ })
+ });
+
+ }
+
+ /**
+ * This function is called to remove the effects
+ *
+ * @public
+ * @function
+ * @api stable
+ */
+ removeMaps() {
+ this.mapL['B'] = null;
+ this.mapL['C'] = null;
+ this.mapL['D'] = null;
+ }
+
+ destroyMapsContainer() {
+ // Remove mirrors containers
+ document.getElementById("mapjsB").remove();
+ document.getElementById("mapjsC").remove();
+ document.getElementById("mapjsD").remove();
+
+ // Take the main map out of the container
+ const lienzo = document.getElementById("lienzo");
+ const mapjsA = document.getElementById("mapjs") || document.getElementById("map");
+ mapjsA.style.display = "block";
+ mapjsA.classList.remove('mirror1');
+ document.body.insertBefore(mapjsA, lienzo);
+
+ // Load the main container
+ document.getElementById("lienzo").remove();
+ }
+
+ /**
+ * This function compares controls
+ *
+ * @public
+ * @function
+ * @param {M.Control} control to compare
+ * @api stable
+ */
+ equals(control) {
+ return control instanceof MirrorpanelControl;
+ }
+}
diff --git a/src/impl/ol/js/mirrorpanelcontrol.js b/src/impl/ol/js/mirrorpanelcontrol.js
new file mode 100644
index 0000000..99060ff
--- /dev/null
+++ b/src/impl/ol/js/mirrorpanelcontrol.js
@@ -0,0 +1,24 @@
+/**
+ * @module M/impl/control/MirrorpanelControl
+ */
+export default class MirrorpanelControl extends M.impl.Control {
+ /**
+ * This function adds the control to the specified map
+ *
+ * @public
+ * @function
+ * @param {M.Map} map to add the plugin
+ * @param {HTMLElement} html of the plugin
+ * @api stable
+ */
+ addTo(map, html) {
+ // obtengo la interacción por defecto del dblclick para manejarla
+ const olMap = map.getMapImpl();
+ olMap.getInteractions().forEach((interaction) => {
+ if (interaction instanceof ol.interaction.DoubleClickZoom) {
+ this.dblClickInteraction_ = interaction;
+ }
+ });
+ super.addTo(map, html);
+ }
+}
diff --git a/src/templates/mirrorpanel.html b/src/templates/mirrorpanel.html
new file mode 100644
index 0000000..b450878
--- /dev/null
+++ b/src/templates/mirrorpanel.html
@@ -0,0 +1,21 @@
+
+
{{translations.title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/task/create-entrypoint.js b/task/create-entrypoint.js
new file mode 100644
index 0000000..de3cf32
--- /dev/null
+++ b/task/create-entrypoint.js
@@ -0,0 +1,67 @@
+const path = require('path');
+const slash = require('slash');
+const fs = require('fs-extra');
+const SRC_PATH = path.resolve(__dirname, '..', 'src');
+const DIST_PATH = path.resolve(__dirname, '..', 'dist');
+const FACADE_PATH = path.resolve(SRC_PATH, 'facade', 'js');
+const IMPL_PATH = path.resolve(SRC_PATH, 'impl', 'ol', 'js');
+
+const files = [];
+const namespaces = [];
+const uniqueNS = [];
+let imports = '';
+let exportedClasses = '';
+let createNS = '';
+
+const getAbsolutePath = (fileNames, fullPath) => {
+ const absolutePaths = fileNames.map(fileName => path.resolve(fullPath, fileName));
+ absolutePaths.forEach((absolutePath) => {
+ if (fs.lstatSync(absolutePath).isDirectory() === true) {
+ getAbsolutePath(fs.readdirSync(absolutePath), absolutePath);
+ } else if (/.js$/.test(absolutePath)) {
+ files.push(absolutePath);
+ }
+ });
+};
+
+const facadeFiles = fs.readdirSync(FACADE_PATH);
+const implFiles = fs.readdirSync(IMPL_PATH);
+getAbsolutePath(facadeFiles, FACADE_PATH);
+getAbsolutePath(implFiles, IMPL_PATH);
+
+files.forEach((file) => {
+ const match = fs.readFileSync(file, 'utf8').match(/@module.*/);
+ if (match !== null) {
+ const namespace = match[0].replace(/@module (.*)/, '$1');
+ namespaces.push({
+ alias: namespace.replace(/\//g, '$'),
+ namespace: namespace.replace(/\//g, '.'),
+ path: slash(file),
+ });
+ }
+});
+
+namespaces.forEach((namespace) => {
+ const partitions = namespace.namespace.split('.');
+ for (let i = 2; i < partitions.length; i += 1) {
+ const partition = partitions.slice(0, i).join('.');
+ if (uniqueNS.includes(partition) === false) {
+ uniqueNS.push(partition);
+ }
+ }
+});
+
+namespaces.forEach((namespace) => {
+ imports += `import ${namespace.alias} from '${namespace.path.replace(/(.*)\.js/, '$1')}';\n`;
+ exportedClasses += `window.${namespace.namespace} = ${namespace.alias};\n`;
+});
+
+uniqueNS.forEach((ns) => {
+ createNS += `if (!window.${ns}) window.${ns} = {};\n`;
+});
+
+const contentEntryPoint = `${imports}\n${createNS}${exportedClasses}`;
+
+fs.writeFileSync(path.join(SRC_PATH, 'index.js'), contentEntryPoint);
+fs.removeSync(DIST_PATH);
+fs.ensureDirSync(DIST_PATH);
diff --git a/test/dev.html b/test/dev.html
new file mode 100644
index 0000000..a08c477
--- /dev/null
+++ b/test/dev.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+ Mirrorpanel TEST
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/prod.html b/test/prod.html
new file mode 100644
index 0000000..7dd2018
--- /dev/null
+++ b/test/prod.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+ Mirrorpanel TEST
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/test.js b/test/test.js
new file mode 100644
index 0000000..13cd74e
--- /dev/null
+++ b/test/test.js
@@ -0,0 +1,82 @@
+import Mirrorpanel from 'facade/mirrorpanel'; //Importación del plugin que desarrollamos para trabajar
+
+M.language.setLang('es'); //Español
+//M.language.setLang('en');//Inglés
+
+const map = M.map({
+ container: 'mapjs',
+ center: {
+ x: -667143.31,
+ y: 4493011.77,
+ },
+ controls: ['scale', 'location', 'layerswitcher'],
+ projection: "EPSG:3857*m",
+ zoom: 8,
+});
+
+let capasPNOA = [
+ 'WMS*PNOA 2015*https://www.ign.es/wms/pnoa-historico*PNOA2015',
+ 'WMS*PNOA 2016*https://www.ign.es/wms/pnoa-historico*PNOA2016',
+ 'WMS*PNOA 2017*https://www.ign.es/wms/pnoa-historico*PNOA2017',
+ 'WMS*PNOA 2018*https://www.ign.es/wms/pnoa-historico*PNOA2018',
+];
+
+let defaultBaseLyrs = [
+ new M.layer.WMTS({
+ url: 'http://www.ign.es/wmts/ign-base?',
+ name: 'IGNBaseTodo',
+ legend: 'Mapa IGN',
+ matrixSet: 'GoogleMapsCompatible',
+ transparent: false,
+ displayInLayerSwitcher: false,
+ queryable: false,
+ visible: true,
+ format: 'image/jpeg',
+ }),
+ new M.layer.WMTS({
+ url: 'http://www.ign.es/wmts/pnoa-ma?',
+ name: 'OI.OrthoimageCoverage',
+ legend: 'Imagen (PNOA)',
+ matrixSet: 'GoogleMapsCompatible',
+ transparent: false,
+ displayInLayerSwitcher: false,
+ queryable: false,
+ visible: true,
+ format: 'image/jpeg',
+ }),
+ new M.layer.WMTS({
+ url: 'https://wmts-mapa-lidar.idee.es/lidar?',
+ name: 'EL.GridCoverageDSM',
+ legend: 'Modelo Digital de Superficies LiDAR',
+ matrixSet: 'GoogleMapsCompatible',
+ transparent: false,
+ displayInLayerSwitcher: false,
+ queryable: false,
+ visible: true,
+ format: 'image/png',
+ }),
+ new M.layer.WMTS({
+ url: 'http://www.ideandalucia.es/geowebcache/service/wmts?',
+ name: 'orto_2010-11',
+ legend: 'orto_2010-11',
+ matrixSet: 'SIG-C:25830',
+ transparent: false,
+ displayInLayerSwitcher: false,
+ queryable: false,
+ visible: true,
+ format: 'image/png',
+ })
+]
+
+const mpMirrorPanel = new Mirrorpanel({
+ position: 'TR',
+ collapsible: true, // El botón para desplegar/replegar el plugin no aparece (false) o sí aparece(true)
+ collapsed: false, // El panel del plugin se muestra desplegado (false) o replegado (true)
+ modeViz: 0,
+ mirrorLayers: capasPNOA,
+ defaultBaseLyrs: defaultBaseLyrs, // Array de capas para los mapas espejo en formato StringAPICNIG
+ enabledKeyFunctions: true, // Están habilitadas los comandos por teclado
+ showCursors: true, // Se muestran los cursores
+});
+
+map.addPlugin(mpMirrorPanel);
\ No newline at end of file
diff --git a/webpack-config/GenerateVersionPlugin.js b/webpack-config/GenerateVersionPlugin.js
new file mode 100644
index 0000000..e55e424
--- /dev/null
+++ b/webpack-config/GenerateVersionPlugin.js
@@ -0,0 +1,52 @@
+const pathmodule = require('path');
+const fs = require('fs');
+/**
+ * Webpack plugin that allows overwrite functions definitions after import.
+ * This plugin is directly related to the class src/impl/ol/js/patches.js, which is used to
+ * overwrite functions of openlayers that we can not access by inheritance of classes.
+ * @class AllowMutateEsmExports
+ */
+class GenerateVersionPlugin {
+ constructor(opt) {
+ this.version = opt.version;
+ this.regex = opt.regex;
+ this.fileName = opt.fileName;
+ this.aliasRoot = opt.aliasRoot;
+ }
+ /**
+ * This function apply the logic plugin.
+ * @function
+ */
+ apply(compiler) {
+ compiler.hooks.done.tap('GenerateVersionPlugin', (stats) => {
+ const { path } = stats.compilation.options.output;
+ stats.compilation.chunks.forEach((chunk) => {
+ chunk.files.forEach((file, index) => {
+ const basename = pathmodule.basename(file);
+ const version = this.version || this.geExecuteCB(index, stats);
+ let replacePath;
+ if (this.regex instanceof RegExp) {
+ replacePath = basename.replace(this.regex, `$1-${version}$2`);
+ }
+ const realPath = pathmodule.resolve(path, file);
+ const newPath = pathmodule.join(pathmodule.dirname(realPath), replacePath);
+ fs.copyFileSync(realPath, newPath);
+ });
+ });
+ });
+ }
+
+ /**
+ * @function
+ */
+ geExecuteCB(index, stats) {
+ const entry = Object.keys(stats.compilation.options.entry)[index];
+ const name = entry.split('/').slice(-1)[0];
+ const context = stats.compilation.options.resolve.alias[this.aliasRoot];
+ const absolutePath = pathmodule.resolve(context, name, this.fileName);
+ const version = JSON.parse(fs.readFileSync(absolutePath)).version;
+ return version;
+ }
+}
+
+module.exports = GenerateVersionPlugin;
diff --git a/webpack-config/webpack.development.config.js b/webpack-config/webpack.development.config.js
new file mode 100644
index 0000000..8b569e7
--- /dev/null
+++ b/webpack-config/webpack.development.config.js
@@ -0,0 +1,62 @@
+const path = require('path');
+const webpack = require('webpack');
+
+module.exports = {
+ mode: 'development',
+ entry: path.resolve(__dirname, '..', 'test', 'test.js'),
+ resolve: {
+ alias: {
+ templates: path.resolve(__dirname, '../src/templates'),
+ assets: path.resolve(__dirname, '../src/facade/assets'),
+ impl: path.resolve(__dirname, '../src/impl/ol/js'),
+ facade: path.resolve(__dirname, '../src/facade/js'),
+ },
+ extensions: ['.wasm', '.mjs', '.js', '.json', '.css', '.hbs', '.html'],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: /(node_modules\/(?!ol)|bower_components)/,
+ use: {
+ loader: 'babel-loader',
+ options: {
+ presets: ['@babel/preset-env'],
+ },
+ },
+ },
+ {
+ test: /\.js$/,
+ loader: 'eslint-loader',
+ exclude: [/node_modules/, /lib/, /test/, /dist/],
+ },
+ {
+ test: [/\.hbs$/, /\.html$/],
+ loader: 'html-loader',
+ exclude: /node_modules/,
+ },
+ {
+ test: /\.css$/,
+ loader: 'style-loader!css-loader',
+ exclude: [/node_modules/],
+ },
+ {
+ test: /\.(woff|woff2|eot|ttf|svg)$/,
+ exclude: /node_modules/,
+ loader: 'url-loader?name=fonts/[name].[ext]',
+ }],
+ },
+ plugins: [
+ new webpack.HotModuleReplacementPlugin(),
+ ],
+ devServer: {
+ hot: true,
+ open: true,
+ port: 6123,
+ openPage: 'test/dev.html',
+ watchOptions: {
+ poll: 1000,
+ },
+ },
+ devtool: 'eval-source-map',
+};
diff --git a/webpack-config/webpack.production.config.js b/webpack-config/webpack.production.config.js
new file mode 100644
index 0000000..9a8fcf4
--- /dev/null
+++ b/webpack-config/webpack.production.config.js
@@ -0,0 +1,90 @@
+const path = require('path');
+const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
+const TerserPlugin = require('terser-webpack-plugin');
+const GenerateVersionPlugin = require('./GenerateVersionPlugin');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const CopywebpackPlugin = require('copy-webpack-plugin');
+
+const PJSON_PATH = path.resolve(__dirname, '..', 'package.json');
+const pjson = require(PJSON_PATH);
+
+module.exports = {
+ mode: 'production',
+ entry: {
+ 'mirrorpanel.ol.min': path.resolve(__dirname, '..', 'src', 'index.js'),
+ },
+ output: {
+ path: path.resolve(__dirname, '..', 'dist'),
+ filename: '[name].js',
+ },
+ resolve: {
+ alias: {
+ templates: path.resolve(__dirname, '../src/templates'),
+ assets: path.resolve(__dirname, '../src/facade/assets'),
+ impl: path.resolve(__dirname, '../src/impl/ol/js'),
+ facade: path.resolve(__dirname, '../src/facade/js'),
+ },
+ extensions: ['.wasm', '.mjs', '.js', '.json', '.css', '.hbs', '.html'],
+ },
+ module: {
+ rules: [{
+ test: /\.js$/,
+ exclude: /(node_modules\/(?!ol)|bower_components)/,
+ use: {
+ loader: 'babel-loader',
+ options: {
+ presets: ['@babel/preset-env'],
+ },
+ },
+ },
+ {
+ test: /\.js$/,
+ loader: 'eslint-loader',
+ exclude: /node_modules/,
+ },
+ {
+ test: [/\.hbs$/, /\.html$/],
+ loader: 'html-loader',
+ exclude: /node_modules/,
+ },
+ {
+ test: /\.css$/,
+ loader: MiniCssExtractPlugin.loader,
+ exclude: /node_modules/,
+ }, {
+ test: /\.css$/,
+ loader: 'css-loader',
+ exclude: /node_modules/,
+
+ },
+ {
+ test: /\.(woff|woff2|eot|ttf|svg)$/,
+ exclude: /node_modules/,
+ loader: 'url-loader?name=fonts/[name].[ext]',
+ }
+ ],
+ },
+ optimization: {
+ noEmitOnErrors: true,
+ minimizer: [
+ new OptimizeCssAssetsPlugin(),
+ new TerserPlugin({
+ sourceMap: true,
+ }),
+ ],
+ },
+ plugins: [
+ // new GenerateVersionPlugin({
+ // version: pjson.version,
+ // regex: /([A-Za-z]+)(\..*)/,
+ // }),
+ new MiniCssExtractPlugin({
+ filename: '[name].css',
+ }),
+ new CopywebpackPlugin([{
+ from: 'src/api.json',
+ to: 'api.json',
+ }]),
+ ],
+ devtool: 'source-map',
+};