SVGHMI: Rewrote button widget.
--- a/svghmi/gen_index_xhtml.xslt Wed Dec 02 14:33:24 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt Sat Dec 05 16:59:27 2020 +0100
@@ -1675,134 +1675,219 @@
<xsl:text>}
</xsl:text>
</xsl:template>
+ <xsl:variable name="_button_fsm">
+ <fsm>
+ <state name="init">
+ <on-dispatch value="false">
+ <jump state="released"/>
+ </on-dispatch>
+ <on-dispatch value="true">
+ <jump state="pressed"/>
+ </on-dispatch>
+ </state>
+ <state name="pressing">
+ <hmi-value value="true"/>
+ <on-dispatch value="true">
+ <jump state="pressed"/>
+ </on-dispatch>
+ <on-mouse position="up">
+ <jump state="shortpress"/>
+ </on-mouse>
+ </state>
+ <state name="pressed">
+ <show eltname="active"/>
+ <on-mouse position="up">
+ <jump state="releasing"/>
+ </on-mouse>
+ <on-dispatch value="false">
+ <jump state="released"/>
+ </on-dispatch>
+ </state>
+ <state name="shortpress">
+ <on-dispatch value="true">
+ <jump state="releasing"/>
+ </on-dispatch>
+ <on-mouse position="down">
+ <jump state="pressing"/>
+ </on-mouse>
+ </state>
+ <state name="releasing">
+ <hmi-value value="false"/>
+ <on-dispatch value="false">
+ <jump state="released"/>
+ </on-dispatch>
+ <on-mouse position="down">
+ <jump state="shortrelease"/>
+ </on-mouse>
+ </state>
+ <state name="released">
+ <show eltname="inactive"/>
+ <on-mouse position="down">
+ <jump state="pressing"/>
+ </on-mouse>
+ <on-dispatch value="true">
+ <jump state="pressed"/>
+ </on-dispatch>
+ </state>
+ <state name="shortrelease">
+ <on-dispatch value="false">
+ <jump state="pressing"/>
+ </on-dispatch>
+ <on-mouse position="up">
+ <jump state="releasing"/>
+ </on-mouse>
+ </state>
+ </fsm>
+ </xsl:variable>
+ <xsl:template mode="dispatch_transition" match="fsm">
+ <xsl:text> switch (this.state) {
+</xsl:text>
+ <xsl:apply-templates mode="dispatch_transition" select="state"/>
+ <xsl:text> }
+</xsl:text>
+ </xsl:template>
+ <xsl:template mode="dispatch_transition" match="state">
+ <xsl:text> case "</xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>":
+</xsl:text>
+ <xsl:apply-templates select="on-dispatch"/>
+ <xsl:text> break;
+</xsl:text>
+ </xsl:template>
+ <xsl:template match="on-dispatch">
+ <xsl:text> if(value == </xsl:text>
+ <xsl:value-of select="@value"/>
+ <xsl:text>) {
+</xsl:text>
+ <xsl:apply-templates mode="transition" select="jump"/>
+ <xsl:text> }
+</xsl:text>
+ </xsl:template>
+ <xsl:template mode="mouse_transition" match="fsm">
+ <xsl:param name="position"/>
+ <xsl:text> switch (this.state) {
+</xsl:text>
+ <xsl:apply-templates mode="mouse_transition" select="state">
+ <xsl:with-param name="position" select="$position"/>
+ </xsl:apply-templates>
+ <xsl:text> }
+</xsl:text>
+ </xsl:template>
+ <xsl:template mode="mouse_transition" match="state">
+ <xsl:param name="position"/>
+ <xsl:text> case "</xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>":
+</xsl:text>
+ <xsl:apply-templates select="on-mouse[@position = $position]"/>
+ <xsl:text> break;
+</xsl:text>
+ </xsl:template>
+ <xsl:template match="on-mouse">
+ <xsl:apply-templates mode="transition" select="jump"/>
+ </xsl:template>
+ <xsl:template mode="transition" match="jump">
+ <xsl:text> this.state = "</xsl:text>
+ <xsl:value-of select="@state"/>
+ <xsl:text>";
+</xsl:text>
+ <xsl:text> this.</xsl:text>
+ <xsl:value-of select="@state"/>
+ <xsl:text>_action();
+</xsl:text>
+ </xsl:template>
+ <xsl:template mode="actions" match="fsm">
+ <xsl:apply-templates mode="actions" select="state"/>
+ </xsl:template>
+ <xsl:template mode="actions" match="state">
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@name"/>
+ <xsl:text>_action(){
+</xsl:text>
+ <xsl:apply-templates mode="actions" select="*"/>
+ <xsl:text> }
+</xsl:text>
+ </xsl:template>
+ <xsl:template mode="actions" match="show">
+ <xsl:text> this.display = "</xsl:text>
+ <xsl:value-of select="@eltname"/>
+ <xsl:text>";
+</xsl:text>
+ <xsl:text> this.request_animate();
+</xsl:text>
+ </xsl:template>
+ <xsl:template mode="actions" match="hmi-value">
+ <xsl:text> this.apply_hmi_value(0, </xsl:text>
+ <xsl:value-of select="@value"/>
+ <xsl:text>);
+</xsl:text>
+ </xsl:template>
<xsl:template mode="widget_class" match="widget[@type='Button']">
+ <xsl:variable name="fsm" select="exsl:node-set($_button_fsm)"/>
<xsl:text>class ButtonWidget extends Widget{
</xsl:text>
<xsl:text> frequency = 5;
</xsl:text>
- <xsl:text> state_plc = 0;
-</xsl:text>
- <xsl:text> state_hmi = 0;
-</xsl:text>
- <xsl:text> plc_lock = false;
-</xsl:text>
- <xsl:text> active_style = undefined;
-</xsl:text>
- <xsl:text> inactive_style = undefined;
-</xsl:text>
- <xsl:text>
+ <xsl:text> display = "inactive";
+</xsl:text>
+ <xsl:text> state = "init";
</xsl:text>
<xsl:text> dispatch(value) {
</xsl:text>
- <xsl:text> this.state_plc = value;
-</xsl:text>
- <xsl:text> if(this.plc_lock){
-</xsl:text>
- <xsl:text> if(this.state_plc == 1){
-</xsl:text>
- <xsl:text> this.apply_hmi_value(0, 0);
-</xsl:text>
- <xsl:text> this.plc_lock = false;
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text>
-</xsl:text>
- <xsl:text> //redraw button
-</xsl:text>
- <xsl:text> this.state_hmi = this.state_plc;
-</xsl:text>
- <xsl:text> this.request_animate();
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text>
-</xsl:text>
+ <xsl:apply-templates mode="dispatch_transition" select="$fsm"/>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text> onmouseup(evt) {
+</xsl:text>
+ <xsl:text> svg_root.removeEventListener("pointerup", this.bound_onmouseup, true);
+</xsl:text>
+ <xsl:apply-templates mode="mouse_transition" select="$fsm">
+ <xsl:with-param name="position" select="'up'"/>
+ </xsl:apply-templates>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text> onmousedown(evt) {
+</xsl:text>
+ <xsl:text> svg_root.addEventListener("pointerup", this.bound_onmouseup, true);
+</xsl:text>
+ <xsl:apply-templates mode="mouse_transition" select="$fsm">
+ <xsl:with-param name="position" select="'down'"/>
+ </xsl:apply-templates>
+ <xsl:text> }
+</xsl:text>
+ <xsl:apply-templates mode="actions" select="$fsm"/>
<xsl:text> animate(){
</xsl:text>
- <xsl:text> if (this.active_style && this.inactive_style) {
-</xsl:text>
- <xsl:text> // redraw button on screen refresh
-</xsl:text>
- <xsl:text> if (this.state_hmi) {
-</xsl:text>
- <xsl:text> this.active_elt.setAttribute("style", this.active_style);
-</xsl:text>
- <xsl:text> this.inactive_elt.setAttribute("style", "display:none");
-</xsl:text>
- <xsl:text> } else {
-</xsl:text>
- <xsl:text> this.inactive_elt.setAttribute("style", this.inactive_style);
-</xsl:text>
- <xsl:text> this.active_elt.setAttribute("style", "display:none");
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text>
-</xsl:text>
- <xsl:text> on_click(evt) {
-</xsl:text>
- <xsl:text> //set state and apply if plc is 0
-</xsl:text>
- <xsl:text> this.plc_lock = true;
-</xsl:text>
- <xsl:text> if(this.state_plc == 0){
-</xsl:text>
- <xsl:text> this.apply_hmi_value(0, 1);
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text> //redraw button
-</xsl:text>
- <xsl:text> this.request_animate();
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text>
-</xsl:text>
- <xsl:text> on_press(evt) {
-</xsl:text>
- <xsl:text> //set graphic
-</xsl:text>
- <xsl:text> this.state_hmi = 1;
-</xsl:text>
- <xsl:text> //redraw button
-</xsl:text>
- <xsl:text> this.request_animate();
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text>
-</xsl:text>
- <xsl:text> init() {
-</xsl:text>
- <xsl:text> this.active_style = this.active_elt ? this.active_elt.style.cssText : undefined;
-</xsl:text>
- <xsl:text> this.inactive_style = this.inactive_elt ? this.inactive_elt.style.cssText : undefined;
-</xsl:text>
- <xsl:text>
-</xsl:text>
- <xsl:text> if (this.active_style && this.inactive_style) {
-</xsl:text>
- <xsl:text> this.active_elt.setAttribute("style", "display:none");
-</xsl:text>
- <xsl:text> this.inactive_elt.setAttribute("style", this.inactive_style);
-</xsl:text>
- <xsl:text> }
-</xsl:text>
- <xsl:text>
-</xsl:text>
- <xsl:text> this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
-</xsl:text>
- <xsl:text> this.element.setAttribute("onmousedown", "hmi_widgets['"+this.element_id+"'].on_press(evt)");
-</xsl:text>
- <xsl:text> }
+ <xsl:text> if (this.active_elt && this.inactive_elt) {
+</xsl:text>
+ <xsl:for-each select="str:split('active inactive')">
+ <xsl:text> if(this.display == "</xsl:text>
+ <xsl:value-of select="."/>
+ <xsl:text>")
+</xsl:text>
+ <xsl:text> this.</xsl:text>
+ <xsl:value-of select="."/>
+ <xsl:text>_elt.style.display = "";
+</xsl:text>
+ <xsl:text> else
+</xsl:text>
+ <xsl:text> this.</xsl:text>
+ <xsl:value-of select="."/>
+ <xsl:text>_elt.style.display = "none";
+</xsl:text>
+ </xsl:for-each>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text> init() {
+</xsl:text>
+ <xsl:text> this.bound_onmouseup = this.onmouseup.bind(this);
+</xsl:text>
+ <xsl:text> this.element.addEventListener("pointerdown", this.onmousedown.bind(this));
+</xsl:text>
+ <xsl:text> }
</xsl:text>
<xsl:text>}
</xsl:text>
@@ -6645,12 +6730,16 @@
</xsl:text>
<xsl:text>function prepare_svg() {
</xsl:text>
+ <xsl:text> // prevents context menu from appearing on right click and long touch
+</xsl:text>
<xsl:text> document.body.addEventListener('contextmenu', e => {
</xsl:text>
<xsl:text> e.preventDefault();
</xsl:text>
<xsl:text> });
</xsl:text>
+ <xsl:text>
+</xsl:text>
<xsl:text> for(let eltid in detachable_elements){
</xsl:text>
<xsl:text> let [element,parent] = detachable_elements[eltid];
--- a/svghmi/widget_button.ysl2 Wed Dec 02 14:33:24 2020 +0100
+++ b/svghmi/widget_button.ysl2 Sat Dec 05 16:59:27 2020 +0100
@@ -1,73 +1,152 @@
// widget_button.ysl2
+// Finite state machine
+decl fsm(name);
+decl state(name);
+decl on_mouse(position);
+decl on_dispatch(value);
+decl jump(state);
+decl show(eltname);
+decl hmi_value(value);
+
+// State machine to drive HMI_BOOL on a potentially laggy connection
+// TODO: make more robust in case other widget or PLC change value on their own
+const "_button_fsm" fsm {
+ state "init" {
+ on_dispatch "false" jump "released";
+ on_dispatch "true" jump "pressed";
+ }
+
+ state "pressing" {
+ // show "waitactive";
+ hmi_value "true";
+ on_dispatch "true" jump "pressed";
+ on_mouse "up" jump "shortpress";
+ }
+ state "pressed" {
+ show "active";
+ on_mouse "up" jump "releasing";
+ on_dispatch "false" jump "released";
+ }
+ state "shortpress" {
+ on_dispatch "true" jump "releasing";
+ on_mouse "down" jump "pressing";
+ }
+
+ state "releasing" {
+ // show "waitinactive";
+ hmi_value "false";
+ on_dispatch "false" jump "released";
+ on_mouse "down" jump "shortrelease";
+ }
+ state "released" {
+ show "inactive";
+ on_mouse "down" jump "pressing";
+ on_dispatch "true" jump "pressed";
+ }
+ state "shortrelease" {
+ on_dispatch "false" jump "pressing";
+ on_mouse "up" jump "releasing";
+ }
+}
+
+template "fsm", mode="dispatch_transition" {
+ | switch (this.state) {
+ apply "state", mode="dispatch_transition";
+ | }
+}
+template "state", mode="dispatch_transition" {
+ | case "«@name»":
+ apply "on-dispatch";
+ | break;
+}
+template "on-dispatch" {
+ | if(value == «@value») {
+ apply "jump", mode="transition";
+ | }
+}
+
+template "fsm", mode="mouse_transition" {
+ param "position";
+ | switch (this.state) {
+ apply "state", mode="mouse_transition" with "position", "$position";
+ | }
+}
+template "state", mode="mouse_transition" {
+ param "position";
+ | case "«@name»":
+ apply "on-mouse[@position = $position]";
+ | break;
+}
+template "on-mouse" {
+ // up or down state is already assumed because apply statement filters it
+ apply "jump", mode="transition";
+}
+
+template "jump", mode="transition" {
+ | this.state = "«@state»";
+ | this.«@state»_action();
+}
+
+template "fsm", mode="actions" {
+ apply "state", mode="actions";
+}
+template "state", mode="actions" {
+ | «@name»_action(){
+ //| console.log("Entering state «@name»");
+ apply "*", mode="actions";
+ | }
+}
+template "show", mode="actions" {
+ | this.display = "«@eltname»";
+ | this.request_animate();
+}
+template "hmi-value", mode="actions" {
+ | this.apply_hmi_value(0, «@value»);
+}
+
template "widget[@type='Button']", mode="widget_class"{
- ||
- class ButtonWidget extends Widget{
- frequency = 5;
- state_plc = 0;
- state_hmi = 0;
- plc_lock = false;
- active_style = undefined;
- inactive_style = undefined;
+ const "fsm","exsl:node-set($_button_fsm)";
+ | class ButtonWidget extends Widget{
+ | frequency = 5;
- dispatch(value) {
- this.state_plc = value;
- if(this.plc_lock){
- if(this.state_plc == 1){
- this.apply_hmi_value(0, 0);
- this.plc_lock = false;
- }
- }
+ | display = "inactive";
+ | state = "init";
- //redraw button
- this.state_hmi = this.state_plc;
- this.request_animate();
- }
+ | dispatch(value) {
+ // | console.log("dispatch"+value);
+ apply "$fsm", mode="dispatch_transition";
+ | }
- animate(){
- if (this.active_style && this.inactive_style) {
- // redraw button on screen refresh
- if (this.state_hmi) {
- this.active_elt.setAttribute("style", this.active_style);
- this.inactive_elt.setAttribute("style", "display:none");
- } else {
- this.inactive_elt.setAttribute("style", this.inactive_style);
- this.active_elt.setAttribute("style", "display:none");
- }
- }
- }
+ | onmouseup(evt) {
+ | svg_root.removeEventListener("pointerup", this.bound_onmouseup, true);
+ // | console.log("onmouseup");
+ apply "$fsm", mode="mouse_transition" with "position", "'up'";
+ | }
+ | onmousedown(evt) {
+ | svg_root.addEventListener("pointerup", this.bound_onmouseup, true);
+ // | console.log("onmousedown");
+ apply "$fsm", mode="mouse_transition" with "position", "'down'";
+ | }
- on_click(evt) {
- //set state and apply if plc is 0
- this.plc_lock = true;
- if(this.state_plc == 0){
- this.apply_hmi_value(0, 1);
- }
- //redraw button
- this.request_animate();
- }
+ apply "$fsm", mode="actions";
- on_press(evt) {
- //set graphic
- this.state_hmi = 1;
- //redraw button
- this.request_animate();
- }
+ | animate(){
+ | if (this.active_elt && this.inactive_elt) {
+ foreach "str:split('active inactive')" {
+ | if(this.display == "«.»")
+ | this.«.»_elt.style.display = "";
+ | else
+ | this.«.»_elt.style.display = "none";
+ }
+ | }
+ | }
- init() {
- this.active_style = this.active_elt ? this.active_elt.style.cssText : undefined;
- this.inactive_style = this.inactive_elt ? this.inactive_elt.style.cssText : undefined;
-
- if (this.active_style && this.inactive_style) {
- this.active_elt.setAttribute("style", "display:none");
- this.inactive_elt.setAttribute("style", this.inactive_style);
- }
-
- this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
- this.element.setAttribute("onmousedown", "hmi_widgets['"+this.element_id+"'].on_press(evt)");
- }
- }
- ||
+ | init() {
+ | this.bound_onmouseup = this.onmouseup.bind(this);
+ | this.element.addEventListener("pointerdown", this.onmousedown.bind(this));
+ | }
+ | }
}
--- a/tests/svghmi/svghmi_0@svghmi/svghmi.svg Wed Dec 02 14:33:24 2020 +0100
+++ b/tests/svghmi/svghmi_0@svghmi/svghmi.svg Sat Dec 05 16:59:27 2020 +0100
@@ -197,12 +197,12 @@
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:document-units="px"
- inkscape:current-layer="hmi0"
+ inkscape:current-layer="g443"
showgrid="false"
units="px"
- inkscape:zoom="0.27282898"
- inkscape:cx="646.17826"
- inkscape:cy="652.93449"
+ inkscape:zoom="0.77167689"
+ inkscape:cx="379.87087"
+ inkscape:cy="462.91635"
inkscape:window-width="1848"
inkscape:window-height="1016"
inkscape:window-x="72"
@@ -2442,19 +2442,19 @@
<g
inkscape:label="HMI:Input@/SELECTION"
id="g446"
- transform="matrix(0.28590269,0,0,0.28590269,487.38811,348.87609)">
+ transform="matrix(0.28590269,0,0,0.28590269,1047.3881,408.87609)">
<text
xml:space="preserve"
- style="font-style:normal;font-weight:normal;font-size:160px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- x="136.32812"
+ style="font-style:normal;font-weight:normal;font-size:160px;line-height:125%;font-family:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="216.32812"
y="218.24219"
id="text432"
inkscape:label="value"><tspan
sodipodi:role="line"
id="tspan430"
- x="136.32812"
+ x="216.32812"
y="218.24219"
- style="stroke-width:1px">8</tspan></text>
+ style="text-align:end;text-anchor:end;stroke-width:1px">8</tspan></text>
<path
transform="scale(1,-1)"
sodipodi:type="star"
@@ -2477,7 +2477,7 @@
inkscape:label="edit"
onclick=""
y="95.40741"
- x="139.85185"
+ x="-174.94055"
height="128"
width="407.7037"
id="rect438"
@@ -2519,41 +2519,46 @@
inkscape:transform-center-x="1.0089177e-06" />
</g>
<g
- transform="matrix(0.28590269,0,0,0.28590269,170.16209,215.31977)"
+ transform="matrix(0.57180538,0,0,0.57180538,417.18774,31.574523)"
id="g443"
inkscape:label="HMI:Button@/SELECTION"
- style="stroke-width:2">
- <g
- id="g435"
- inkscape:label="bg"
- style="stroke-width:2">
- <rect
- style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:#ff6600;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="rect433"
- width="245.44583"
- height="95.723877"
- x="971.96545"
- y="594.82263"
- ry="47.861938"
- inkscape:label="button"
- rx="47.861938" />
- </g>
- <g
- id="g441"
+ style="stroke-width:1">
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:#ff6600;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5492"
+ width="245.44583"
+ height="95.723877"
+ x="971.96545"
+ y="594.82263"
+ ry="23.930969"
+ inkscape:label="inactive"
+ rx="23.930969" />
+ <rect
+ rx="23.930969"
+ inkscape:label="active"
+ ry="23.930969"
+ y="594.82263"
+ x="971.96545"
+ height="95.723877"
+ width="245.44583"
+ id="rect433"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fdfdfd;fill-opacity:1;fill-rule:nonzero;stroke:#ffd0b2;stroke-width:28.60938356;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ style="stroke-width:1"
inkscape:label="text"
- style="stroke-width:2">
- <text
- inkscape:label="setting_jmp"
- id="text439"
+ id="g952">
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="1090.7626"
y="656.98151"
- x="1090.7626"
- style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ff6600;fill-opacity:1;stroke:none;stroke-width:1.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- xml:space="preserve"><tspan
- style="text-align:center;text-anchor:middle;fill:#ff6600;stroke-width:1.99999988px"
+ id="text950"
+ inkscape:label="setting_jmp"><tspan
+ sodipodi:role="line"
+ id="tspan948"
+ x="1090.7626"
y="656.98151"
- x="1090.7626"
- id="tspan437"
- sodipodi:role="line">up</tspan></text>
+ style="text-align:center;text-anchor:middle;fill:#ff6600;stroke-width:0.99999994px">up</tspan></text>
</g>
</g>
<g