33#ifndef DRAIN_IMAGE_MOUSEXML_H_
34#define DRAIN_IMAGE_MOUSEXML_H_
36#include "drain/Enum.h"
37#include "drain/util/EnumFlagger.h"
39#include "drain/StringBuilder.h"
40#include "drain/util/TreeXML.h"
41#include "drain/util/UtilsXML.h"
42#include "drain/util/JavaScriptXML.h"
43#include "drain/js/coords.h"
104 const std::string & mouseEventOn =
"onmouseenter",
105 const std::string & mouseEventOff =
"onmouseleave");
109 enum CoordinateProcessing {
114 GEOGRAPHIC_COORDS = 7,
132 std::string getHandlerFunctionName(MouseXML::EventClass eventKey);
135 std::string getInitialiserFunctionName(MouseXML::EventClass eventKey);
143 void adjustListenerGeoRef(
DRAIN_XML_TREE(N) & handlerScopeJS, CoordFlagger::ivalue_t coords)
const ;
164 void attachListener(
XML & elem,
const std::string & eventName,
const std::string & handlerName){
170 DRAIN_XML_TREE(N) & ensureListenerHandler(DRAIN_XML_TREE(N) & root,
const std::string & handlerName);
180 const std::string COORD_INIT_SCOPE;
187DRAIN_ENUM_DICT(image::MouseXML::EventClass);
188DRAIN_ENUM_DICT(image::MouseXML::CoordinateProcessing);
196DRAIN_ENUM_OSTREAM(image::MouseXML::EventClass)
200void MouseXML::adjustListenerGeoRef(DRAIN_XML_TREE(N) & handlerScopeJS, CoordFlagger::ivalue_t coords)
const {
202 const CoordFlagger flags(coords);
204 DRAIN_XML_TREE(N) & coordScopeJS = handlerScopeJS(COORD_INIT_SCOPE);
206 if (flags.isSet(IMAGE_COORDS)){
207 coordScopeJS[flags.str()] -> setProgramComment(
"Coord request: ", flags.str());
209 coordScopeJS[
"ctx.bbox"] =
"ctx.bbox = evt.target.getBoundingClientRect();";
210 coordScopeJS[
"COORDS"] -> setProgramComment(
"Image coordinates");
211 coordScopeJS[
"ctx.x"] =
"ctx.x = Math.floor(evt.clientX - ctx.bbox.left);";
212 coordScopeJS[
"ctx.y"] =
"ctx.y = Math.floor(evt.clientY - ctx.bbox.top);";
213 if (flags.isSet(RELATIVE_COORDS)){
214 coordScopeJS[
"RELATIVE_COORDS"] -> setProgramComment(
"Relative coordinates");
215 coordScopeJS[
"ctx.rx"] =
"ctx.rx = ctx.x / ctx.bbox.width;";
216 coordScopeJS[
"ctx.ry"] =
"ctx.ry = ctx.y / ctx.bbox.height;";
217 if (flags.isSet(GEOGRAPHIC_COORDS)){
218 coordScopeJS[
"GEOGRAPHIC_COORDS"] -> setProgramComment(
"Geographic coordinates");
220 coordScopeJS[
"ctx.gx"] =
"ctx.gx = ctx.georef.bbox.left + ctx.rx*ctx.georef.bbox.width;";
221 coordScopeJS[
"ctx.gy"] =
"ctx.gy = ctx.georef.bbox.top + ctx.ry*ctx.georef.bbox.height;";
230DRAIN_XML_TREE(N) & MouseXML::ensureListenerUNUSED(DRAIN_XML_TREE(N) & root,
XML & elem,
const EventClass & eventKey){
234 std::string handlerName = getHandlerFunctionName(eventKey);
235 ensureListenerHandler(root, handlerName);
238 attachListener(elem, eventName, handlerName);
249DRAIN_XML_TREE(N) & MouseXML::ensureListenerHandler(DRAIN_XML_TREE(N) & root,
const std::string & handlerName){
254 DRAIN_XML_TREE(N) & handlerFunctionScope = JavaScriptXML::ensureJavaScriptFunction(root, handlerName,
"evt");
256 if (!handlerFunctionScope.hasChild(__FUNCTION__)){
257 handlerFunctionScope[__FUNCTION__]->setProgramComment(
"Std init by ", __FUNCTION__);
258 handlerFunctionScope[
"const_ctx"] =
"const ctx = evt.target.ctx;";
259 DRAIN_XML_TREE(N) & coordInitSubScope = handlerFunctionScope[COORD_INIT_SCOPE];
260 coordInitSubScope->setType(N::SCOPE_CURLY);
261 coordInitSubScope->setText(
"if (true)");
262 coordInitSubScope.addChild()->setProgramComment(
"Reserved for coordinates by ", __FUNCTION__);
264 return handlerFunctionScope;
308DRAIN_XML_TREE(N) & MouseXML::getListenerScope(DRAIN_XML_TREE(N) & root,
const std::string & handlerName){
313 DRAIN_XML_TREE(N) & scopeJS = ensureListenerHandler(root, handlerName);
316 subScopeJS->setType(XML::SCOPE_CURLY);
318 subScopeJS->setText(
"with(ctx)");
328DRAIN_XML_TREE(N) & MouseXML::ensureListenerInit(DRAIN_XML_TREE(N) & root,
329 const std::string & initFnctName){
336 DRAIN_XML_TREE(N) & scopeJS = JavaScriptXML::ensureJavaScriptFunction(root, initFnctName);
337 scopeJS->setId(initFnctName);
338 if (!scopeJS.hasChildren()){
339 scopeJS.addChild()->setText(
"/* Added by ", __FUNCTION__,
"*/");
340 scopeJS.addChild()->setText(
"console.info('", __FUNCTION__,
':', initFnctName,
"')");
351 DRAIN_XML_TREE(N) & onLoadScope = JavaScriptXML::getOnLoadScript(root);
352 onLoadScope[initFnctName]->setText(initFnctName,
"();");
362DRAIN_XML_TREE(N) & MouseXML::getListenerInitScope(DRAIN_XML_TREE(N) & root,
const std::string & initFnctName) {
364 DRAIN_XML_TREE(N) & mouseInit = ensureListenerInit(root, initFnctName);
367 std::string installerKey = initFnctName+
"Installer";
370 installer->setText(
"document.querySelectorAll('.", MouseXML::MOUSE,
"').forEach(\n");
372 DRAIN_XML_TREE(N) & scope = installer[N::tag_t::SCOPE_CURLY](N::tag_t::SCOPE_CURLY);
374 scope->setText(
"group =>");
375 scope.addChild()->setProgramComment(
"MouseXML");
376 scope.addChild()->setText(
"var listener = group.querySelector('.", MouseXML::MOUSE_LISTENER,
"');");
378 installer[
"end-foreach"]->setText(
")");
381 if (initScope.empty()){
382 initScope->setType(N::tag_t::SCOPE_CURLY);
383 initScope->setText(
"if (listener)");
384 initScope[
"ensure_CTX"] =
"if (!('ctx' in listener)) listener.ctx = {};";
388 if (!initScope.hasChild(
"georef")){
389 initScope[
"georef_comment"]->setProgramComment(
"Georeference added by ", __FUNCTION__,
" (unconditional for now)");
390 initScope[
"georef"]->setText(
"if (!('georef' in listener.ctx)){ listener.ctx.georef = {}; }");
391 initScope[
"georef_bbox"]->setText(
"if (listener.hasAttribute('data-bbox')){ listener.ctx.georef.bbox = new BBox(listener.getAttribute('data-bbox'))};");
393 initScope[
"georef_epsg"]->setText(
"if (listener.hasAttribute('data-epsg')){ listener.ctx.georef.epsg = listener.getAttribute('data-epsg') };");
Flagger accepting values of enum type E.
Definition EnumFlagger.h:56
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:326
Base class for XML "nodes", to be data elements T for drain::Tree<T>
Definition XML.h:69
virtual void setAttribute(const std::string &key, const std::string &value)
Default implementation. Needed for handling units in strings, like "50%" or "640px".
Definition XML.h:556
ElemClass
Definition MouseXML.h:73
static DRAIN_XML_TREE(N) &getListenerInitScope(DRAIN_XML_TREE(N) &root
Return ("top-level") initialisation script scope for a mouse event. The routine calls subroutine (tha...
static std::string getEventFunctionName(MouseXML::EventClass eventKey)
Modifies short mouse event name like "click" to "onmouseclick", or prefixed form "handleClick".
Definition MouseXML.cpp:73
static DRAIN_XML_TREE(N) &ensureListenerInit(DRAIN_XML_TREE(N) &root
Create internal ("top-level") initialisation script scope for mouse event, if it does not exist.
static DRAIN_XML_TREE(N) &ensureListenerUNUSED(DRAIN_XML_TREE(N) &root
Create internal ("top-level") routine for mouse event, if it does not exist.
static DRAIN_XML_TREE(N) &getListenerScope(DRAIN_XML_TREE(N) &root
Return internal ("top-level") routine for mouse event. The routine calls subroutine (that has a sub s...
static void addVisibilitySwitch(XML &dstElem, XML &listenerElem, const std::string &scope="document", const std::string &mouseEventOn="onmouseenter", const std::string &mouseEventOff="onmouseleave")
Show an element only if the mouse is on another specified element (listenerElem).
Definition MouseXML.cpp:93