EmbAJAX
Simplistic framework for creating and handling displays and controls on a web page served by an embeddable device (Arduino or other microcontroller with Arduino support).
EmbAJAXJoystick.h
1 
22 #ifndef EMBAJAXJOYSTICK_H
23 #define EMBAJAXJOYSTICK_H
24 
25 #include "EmbAJAX.h"
26 
27 const char EmbAJAXJoystick_SNAP_BACK[] = "if (!pressed) { x = 0; y = 0; }\n";
28 const char EmbAJAXJoystick_NO_SNAP_BACK[] = "";
29 const char EmbAJAXJoystick_FREE_POSITION[] = "";
30 const char EmbAJAXJoystick_POSITION_9_DIRECTIONS[] = "if (pressed) {\n"
31  " if (x < -500) x = -1000;\n"
32  " else if (x > 500) x = 1000\n"
33  " else x = 0;\n"
34  "\n"
35  " if (y < -500) y = -1000;\n"
36  " else if (y > 500) y = 1000\n"
37  " else y = 0;\n"
38  "}\n";
39 
42 public:
48  EmbAJAXJoystick(const char* id, int width, int height, const char* position_adjust=EmbAJAXJoystick_FREE_POSITION, const char* snap_back=EmbAJAXJoystick_SNAP_BACK) : EmbAJAXElement(id) {
49  _width = width;
50  _height = height;
51  _position_adjust = position_adjust;
52  _snap_back = snap_back;
53  }
54  void print() const override {
55  EmbAJAXBase::_driver->printFormatted("<canvas id=", HTML_QUOTED_STRING(_id), " width=", INTEGER_VALUE(_width), " height=", INTEGER_VALUE(_height),
56  " style=\"cursor: all-scroll\"></canvas>" // style="border-radius:50%; background-color:grey; cursor: all-scroll"
57  "<script>\n"
58  "var elem = document.getElementById(", JS_QUOTED_STRING(_id), ");\n");
59  EmbAJAXBase::_driver->printFormatted(
60  "elem.__defineSetter__('coords', function(value) {\n"
61  " var vals = value.split(',');\n"
62  " this.update(vals[0], vals[1], false);\n"
63  "});\n"
64  "\n"
65  "elem.updateFromClient = function(x, y, nomerge=false) {\n"
66  " var width = this.width;\n"
67  " var height = this.height;\n"
68  " var pressed = this.pressed;\n"
69  " x = Math.round(((x - width / 2) * 2000) / (width-40));\n" // Scale values to +/-1000, independent of display size
70  " y = Math.round(((y - height / 2) * 2000) / (height-40));\n",
71  PLAIN_STRING(_snap_back), "", // NOTE: inserted "", because printFormatted macro assumed static string between each arg
72  PLAIN_STRING(_position_adjust),
73  " this.update(x, y, true, nomerge);\n"
74  "}\n"
75  "\n"
76  "elem.update = function(x, y, send=true, nomerge=false) {\n"
77  " var oldx = this.posx;\n"
78  " var oldy = this.posy;\n"
79  " this.posx = x;\n"
80  " this.posy = y;\n"
81  " if (this.posx != oldx || this.posy != oldy) {\n"
82  " var ctx = this.getContext('2d');\n"
83  " ctx.clearRect(0, 0, this.width, this.height);\n"
84  " this.drawKnob(ctx, this.posx, this.posy);\n"
85  " if(send) doRequest(this.id,this.pressed + ',' + this.posx + ',' + this.posy, nomerge ? 2 : 1);\n"
86  " }\n"
87  "}\n"
88  "\n"
89  // TODO: This should be customizable
90  "elem.drawKnob = function(ctx, x, y) {\n"
91  " var width = this.width;\n"
92  " var height = this.height;\n"
93  " x = x * (width-40) / 2000 + width / 2;\n"
94  " y = y * (height-40) / 2000 + height / 2;\n"
95  " ctx.beginPath();\n"
96  " ctx.arc(x, y, 15, 0, 2 * Math.PI);\n"
97  " ctx.stroke();\n"
98  " ctx.fill();\n"
99  "}\n"
100  "\n"
101  "elem.press = function(x, y) {\n"
102  " this.pressed = 1;\n"
103  " this.updateFromClient(x, y, true);\n"
104  "}\n"
105  "\n"
106  "elem.move = function(x, y) {\n"
107  " this.updateFromClient(x, y);\n"
108  "}\n"
109  "\n"
110  "elem.release = function(x, y) {\n"
111  " this.pressed = 0;\n"
112  " this.updateFromClient(x, y, true);\n"
113  "}\n"
114  "\n"
115  "elem.addEventListener('mousedown', function(event) { this.press(event.offsetX, event.offsetY); }.bind(elem), false);\n"
116  "elem.addEventListener('mousemove', function(event) { this.move(event.offsetX, event.offsetY); }.bind(elem), false);\n"
117  "elem.addEventListener('mouseup', function(event) { this.release(event.offsetX, event.offsetY); }.bind(elem), false);\n"
118  "elem.addEventListener('mouseleave', function(event) { this.release(event.offsetX, event.offsetY); }.bind(elem), false);\n"
119  "elem.addEventListener('touchstart', function(event) { this.press(event.touches[0].offsetX, event.touches[0].offsetY); }.bind(elem), false);\n"
120  "elem.addEventListener('touchmove', function(event) { this.move(event.touches[0].offsetX, event.touches[0].offsetY); }.bind(elem), false);\n"
121  "elem.addEventListener('touchend', function(event) { this.release(event.touches[0].offsetX, event.touches[0].offsetY); }.bind(elem), false);\n"
122  "</script>\n");
123  }
124  void updateFromDriverArg(const char* argname) {
125  const int bufsize = 16;
126  char buf[bufsize];
127  _driver->getArg(argname, buf, bufsize);
128  // format: "P,X,Y", each a number. Parsing from reverse
129  int p = bufsize;
130  while (--p >= 0) if (buf[p] == '\0') break;
131  while (--p >= 0) if (buf[p] == ',') break;
132  _cury = atoi(buf + p + 1);
133  buf[p] = '\0';
134  while (--p >= 0) if (buf[p] == ',') break;
135  _curx = atoi(buf + p + 1);
136  buf[p] = '\0';
137  _pressed = atoi(buf);
138  updateValueString();
139  }
141  int getX() const { return _curx; };
143  int getY() const { return _cury; };
145  void setPosition (int x, int y) {
146  if (x != _curx || y != _cury) {
147  _curx = x;
148  _cury = y;
149  setChanged();
150  updateValueString();
151  }
152  }
153  const char* valueProperty(uint8_t which = EmbAJAXBase::Value) const override {
154  if (which == EmbAJAXBase::Value) return "coords";
155  return EmbAJAXElement::valueProperty(which);
156  }
157  const char* value(uint8_t which = EmbAJAXBase::Value) const override {
158  if (which == EmbAJAXBase::Value) return _value;
159  return EmbAJAXElement::value(which);
160  }
161 private:
162  void updateValueString() {
163  itoa(_curx, _value, 10);
164  int p = 0;
165  while (_value[p] != '\0') ++p;
166  _value[p] = ',';
167  itoa(_cury, _value + p + 1, 10);
168  }
169  char _value[16];
170  int _width;
171  int _height;
172  const char* _snap_back;
173  const char* _position_adjust;
174  int _curx, _cury;
175  bool _pressed;
176 };
177 
178 #endif
Abstract base class for modifiable elements.
Definition: EmbAJAX.h:296
virtual const char * value(uint8_t which=EmbAJAXBase::Value) const
Definition: EmbAJAX.h:309
virtual const char * valueProperty(uint8_t which=EmbAJAXBase::Value) const
Definition: EmbAJAX.h:324
Definition: EmbAJAXJoystick.h:41
void updateFromDriverArg(const char *argname)
Definition: EmbAJAXJoystick.h:124
int getY() const
Definition: EmbAJAXJoystick.h:143
EmbAJAXJoystick(const char *id, int width, int height, const char *position_adjust=EmbAJAXJoystick_FREE_POSITION, const char *snap_back=EmbAJAXJoystick_SNAP_BACK)
Definition: EmbAJAXJoystick.h:48
int getX() const
Definition: EmbAJAXJoystick.h:141
const char * valueProperty(uint8_t which=EmbAJAXBase::Value) const override
Definition: EmbAJAXJoystick.h:153
void setPosition(int x, int y)
Definition: EmbAJAXJoystick.h:145
const char * value(uint8_t which=EmbAJAXBase::Value) const override
Definition: EmbAJAXJoystick.h:157
#define INTEGER_VALUE(X)
Definition: macro_definitions.h:56
#define PLAIN_STRING(X)
Definition: macro_definitions.h:54
#define HTML_QUOTED_STRING(X)
Definition: macro_definitions.h:49
#define JS_QUOTED_STRING(X)
Definition: macro_definitions.h:47