This commit is contained in:
Sam El-Husseini 2018-01-02 17:11:24 -08:00
commit 436500babb
50 changed files with 1214 additions and 925 deletions

View File

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; font-family: "iconfont";
src: url("iconfont.eot?1aaa45a81be328d93991341b518bf26d?#iefix") format("embedded-opentype"), src: url("iconfont.eot?d6ed5932401120dae3c35f6048fd5e76?#iefix") format("embedded-opentype"),
url("iconfont.woff2?1aaa45a81be328d93991341b518bf26d") format("woff2"), url("iconfont.woff2?d6ed5932401120dae3c35f6048fd5e76") format("woff2"),
url("iconfont.woff?1aaa45a81be328d93991341b518bf26d") format("woff"); url("iconfont.woff?d6ed5932401120dae3c35f6048fd5e76") format("woff");
} }
.icon { .icon {
@ -31,57 +31,51 @@ url("iconfont.woff?1aaa45a81be328d93991341b518bf26d") format("woff");
.icon-addpackage:before { .icon-addpackage:before {
content: "\f105"; content: "\f105";
} }
.icon-advancedcollapsed:before { .icon-brick:before {
content: "\f106"; content: "\f106";
} }
.icon-advancedexpanded:before { .icon-controls:before {
content: "\f107"; content: "\f107";
} }
.icon-brick:before { .icon-functions:before {
content: "\f108"; content: "\f108";
} }
.icon-controls:before { .icon-list:before {
content: "\f109"; content: "\f109";
} }
.icon-functions:before { .icon-logic:before {
content: "\f10a"; content: "\f10a";
} }
.icon-list:before { .icon-loops:before {
content: "\f10b"; content: "\f10b";
} }
.icon-logic:before { .icon-math:before {
content: "\f10c"; content: "\f10c";
} }
.icon-loops:before { .icon-motors:before {
content: "\f10d"; content: "\f10d";
} }
.icon-math:before { .icon-music:before {
content: "\f10e"; content: "\f10e";
} }
.icon-motors:before { .icon-sensors:before {
content: "\f10f"; content: "\f10f";
} }
.icon-music:before { .icon-text:before {
content: "\f110"; content: "\f110";
} }
.icon-sensors:before { .icon-variables:before {
content: "\f111"; content: "\f111";
} }
.icon-text:before { .icon-cancel:before {
content: "\f112"; content: "\f112";
} }
.icon-variables:before { .icon-check:before {
content: "\f113"; content: "\f113";
} }
.icon-cancel:before { .icon-download:before {
content: "\f114"; content: "\f114";
} }
.icon-check:before { .icon-save:before {
content: "\f115"; content: "\f115";
} }
.icon-download:before {
content: "\f116";
}
.icon-save:before {
content: "\f117";
}

Binary file not shown.

View File

@ -22,59 +22,53 @@
<glyph glyph-name="addpackage" <glyph glyph-name="addpackage"
unicode="&#xF105;" unicode="&#xF105;"
horiz-adv-x="40" d=" M4.3 19.1C4.3 10.5 11.4 3.5 20 3.5C28.6 3.5 35.7 10.5 35.7 19.1C35.7 27.8 28.6 34.8 20 34.8C11.4 34.8 4.3 27.8 4.3 19.1z M18.3 29.6H21.7V8.7H18.3V29.6z M19.1 28.7H20.9V9.6H19.1V28.7z M-15984.1 -6224.1H-15984.1V-6224.1H-15984.1V-6224.1z M-15985.2 -6223.8H-15985.2V-6223.8H-15985.2V-6223.8z" /> horiz-adv-x="40" d=" M4.3 19.1C4.3 10.5 11.4 3.5 20 3.5C28.6 3.5 35.7 10.5 35.7 19.1C35.7 27.8 28.6 34.8 20 34.8C11.4 34.8 4.3 27.8 4.3 19.1z M18.3 29.6H21.7V8.7H18.3V29.6z M19.1 28.7H20.9V9.6H19.1V28.7z M-15984.1 -6224.1H-15984.1V-6224.1H-15984.1V-6224.1z M-15985.2 -6223.8H-15985.2V-6223.8H-15985.2V-6223.8z" />
<glyph glyph-name="advancedcollapsed"
unicode="&#xF106;"
horiz-adv-x="40" d=" M17281.9 -6644.3H17284.3V-6658.2H17281.9V-6644.3z M17294 -6655.8H17307.9V-6658.3H17294V-6655.8z M17295 -6657.4H17296.2V-6658.6H17295V-6657.4z" />
<glyph glyph-name="advancedexpanded"
unicode="&#xF107;"
horiz-adv-x="40" d=" M16003.8 42714.4H16002.3V42722.7H16003.8V42714.4z M16004.6 42714.5H15996.2V42715.9H16004.6V42714.5z M15995.8 42725.1H15995V42725.9H15995.8V42725.1z" />
<glyph glyph-name="brick" <glyph glyph-name="brick"
unicode="&#xF108;" unicode="&#xF106;"
horiz-adv-x="40" d=" M34.3 0.9H5.7V39.1H34.4V0.9zM10.4 32.7V18.4H29.6V32.7H10.4z" /> horiz-adv-x="40" d=" M34.3 0.9H5.7V39.1H34.4V0.9zM10.4 32.7V18.4H29.6V32.7H10.4z" />
<glyph glyph-name="controls" <glyph glyph-name="controls"
unicode="&#xF109;" unicode="&#xF107;"
horiz-adv-x="40" d=" M6.1 33H9.6V5.2H6.1V33z M18.3 33H21.7V5.2H18.3V33z M30.4 33H33.9V5.2H30.4V33z M2.6 15.7H13V7H2.6V15.7z M14.8 31.3H25.2V22.6H14.8V31.3z M27 22.6H37.4V13.9H27V22.6z" /> horiz-adv-x="40" d=" M6.1 33H9.6V5.2H6.1V33z M18.3 33H21.7V5.2H18.3V33z M30.4 33H33.9V5.2H30.4V33z M2.6 15.7H13V7H2.6V15.7z M14.8 31.3H25.2V22.6H14.8V31.3z M27 22.6H37.4V13.9H27V22.6z" />
<glyph glyph-name="functions" <glyph glyph-name="functions"
unicode="&#xF10A;" unicode="&#xF108;"
horiz-adv-x="40" d=" M12.7 25.1H9.8C9.8 25.9 9.8 26.1 10.6 26.1C12 26.1 13.1 26.8 13.6 28C14.3 29.4 15.2 30.8 16 32.2C16.9 33.4 18.3 34.3 19.9 34.5C20.9 34.6 21.9 34.3 22.5 33.4C22.8 32.9 22.8 32.4 22.6 31.9C22.3 31.3 21.8 31.2 21.2 31.3C20.7 31.3 20.4 31.9 20.4 32.4C20.4 32.6 20.4 32.6 20.4 32.7C20.4 33.1 20.5 33.4 20.5 33.8C20.2 33.8 19.7 33.9 19.3 33.8C18.6 33.4 18.1 33.1 17.8 32.4C17.1 31.3 16.5 30.1 16.2 28.9C15.9 28 15.5 27 15.3 26.1H17.6C17.4 25.8 17.4 25.4 17.2 25.1H15C14.5 23.3 14.1 21.8 13.6 20.2C12.9 16.9 11.7 13.8 10.3 10.6C9.6 9.3 8.7 8 7.7 7C6.8 6.1 5.8 5.6 4.5 5.6C3.9 5.4 3.2 5.8 2.5 6.1C2.1 6.5 1.9 7.2 2.1 7.7C2.5 8.2 3 8.6 3.7 8.4C4.2 8.4 4.4 7.9 4.4 7.3C4.4 7.2 4.2 7 4.2 7C4 6.8 4 6.6 4 6.5C4.2 6.5 4.4 6.3 4.7 6.3C5.6 6.3 6.5 6.8 7 7.7C7.5 8.6 8 9.4 8.2 10.3C9.6 15.2 11 20 12.4 24.9C12.7 24.9 12.7 24.9 12.7 25.1z M31.9 5.6C32 5.8 32 5.9 32.2 6.1C33.9 7.2 35.2 9.1 35.5 11C36.2 14.3 36.2 17.6 35.3 20.7C34.8 22.5 33.8 23.9 32.4 24.9C32.2 25.1 32 25.3 32 25.4C35.2 24.2 38.1 20.4 38.1 15.5C38.1 11.3 35.7 7.3 31.9 5.6z M23.7 25.4C23.7 25.3 23.5 25.1 23.5 25.1C21.8 24 20.5 22.1 20.2 20.2C19.5 16.9 19.5 13.6 20.4 10.3C20.9 8.6 21.9 7.2 23.3 6.1C23.5 5.9 23.7 5.9 23.7 5.6C20 7.3 17.6 11.2 17.8 15.3C17.6 20.7 20.9 24.6 23.7 25.4z M31.3 12.7C31.3 12.7 31.5 12.7 31.7 12.6C31.7 12.6 31.7 12.6 31.7 12.4C31.2 11.5 30.6 10.8 29.8 10.3C29.4 9.9 28.7 9.8 28.2 10.3C28 10.5 27.9 10.6 27.9 11C27.5 12 27.3 12.9 27.2 13.9C27.2 14.1 27.2 14.1 27 14.3C26.8 13.9 26.6 13.6 26.3 13.3C25.8 12.6 25.2 11.7 24.5 11C24.2 10.6 23.9 10.3 23.3 10.1C22.8 9.9 22.3 10.1 21.9 10.6C21.9 10.6 21.9 10.8 21.9 10.8C21.9 11.2 21.9 11.5 22.3 11.7C22.5 11.9 22.8 11.9 23.2 11.7C23.2 11.7 23.3 11.5 23.3 11.5C23.9 11.2 24 11 24.4 11.7C25.1 12.7 25.8 13.9 26.6 15C26.6 15.2 26.6 15.3 26.6 15.5C26.5 16.2 26.3 16.9 26.1 17.6C25.8 18.8 25.2 19.2 24 19.2H23.9C23.7 19.3 23.9 19.5 24 19.5C24.7 19.7 25.6 19.9 26.3 19.9C26.5 19.9 26.6 19.9 26.8 19.7C27.3 19 27.7 18.3 27.9 17.4C27.9 17.3 28 16.9 28 16.7C28.2 17.1 28.5 17.6 28.9 17.9C29.4 18.5 29.9 19.2 30.5 19.5C30.8 19.7 31.2 19.9 31.5 19.9C32 19.9 32.4 19.5 32.4 19C32.4 19 32.4 18.8 32.4 18.8C32.2 18.3 31.9 18.1 31.3 18.3C31.3 18.3 31.3 18.3 31.3 18.3C31.2 18.3 31.2 18.3 31 18.3C30.5 18.6 29.8 18.5 29.4 17.9C29.4 17.9 29.4 17.9 29.4 17.9C29.1 17.4 28.5 16.7 28.2 16.2C28.2 16 28.2 16 28.2 15.9C28.5 14.6 28.7 13.4 29.1 12C29.1 11.9 29.1 11.9 29.2 11.7C29.4 11.2 29.8 11 30.1 11.5C30.6 11.9 30.8 12.4 31.3 12.7z" /> horiz-adv-x="40" d=" M12.7 25.1H9.8C9.8 25.9 9.8 26.1 10.6 26.1C12 26.1 13.1 26.8 13.6 28C14.3 29.4 15.2 30.8 16 32.2C16.9 33.4 18.3 34.3 19.9 34.5C20.9 34.6 21.9 34.3 22.5 33.4C22.8 32.9 22.8 32.4 22.6 31.9C22.3 31.3 21.8 31.2 21.2 31.3C20.7 31.3 20.4 31.9 20.4 32.4C20.4 32.6 20.4 32.6 20.4 32.7C20.4 33.1 20.5 33.4 20.5 33.8C20.2 33.8 19.7 33.9 19.3 33.8C18.6 33.4 18.1 33.1 17.8 32.4C17.1 31.3 16.5 30.1 16.2 28.9C15.9 28 15.5 27 15.3 26.1H17.6C17.4 25.8 17.4 25.4 17.2 25.1H15C14.5 23.3 14.1 21.8 13.6 20.2C12.9 16.9 11.7 13.8 10.3 10.6C9.6 9.3 8.7 8 7.7 7C6.8 6.1 5.8 5.6 4.5 5.6C3.9 5.4 3.2 5.8 2.5 6.1C2.1 6.5 1.9 7.2 2.1 7.7C2.5 8.2 3 8.6 3.7 8.4C4.2 8.4 4.4 7.9 4.4 7.3C4.4 7.2 4.2 7 4.2 7C4 6.8 4 6.6 4 6.5C4.2 6.5 4.4 6.3 4.7 6.3C5.6 6.3 6.5 6.8 7 7.7C7.5 8.6 8 9.4 8.2 10.3C9.6 15.2 11 20 12.4 24.9C12.7 24.9 12.7 24.9 12.7 25.1z M31.9 5.6C32 5.8 32 5.9 32.2 6.1C33.9 7.2 35.2 9.1 35.5 11C36.2 14.3 36.2 17.6 35.3 20.7C34.8 22.5 33.8 23.9 32.4 24.9C32.2 25.1 32 25.3 32 25.4C35.2 24.2 38.1 20.4 38.1 15.5C38.1 11.3 35.7 7.3 31.9 5.6z M23.7 25.4C23.7 25.3 23.5 25.1 23.5 25.1C21.8 24 20.5 22.1 20.2 20.2C19.5 16.9 19.5 13.6 20.4 10.3C20.9 8.6 21.9 7.2 23.3 6.1C23.5 5.9 23.7 5.9 23.7 5.6C20 7.3 17.6 11.2 17.8 15.3C17.6 20.7 20.9 24.6 23.7 25.4z M31.3 12.7C31.3 12.7 31.5 12.7 31.7 12.6C31.7 12.6 31.7 12.6 31.7 12.4C31.2 11.5 30.6 10.8 29.8 10.3C29.4 9.9 28.7 9.8 28.2 10.3C28 10.5 27.9 10.6 27.9 11C27.5 12 27.3 12.9 27.2 13.9C27.2 14.1 27.2 14.1 27 14.3C26.8 13.9 26.6 13.6 26.3 13.3C25.8 12.6 25.2 11.7 24.5 11C24.2 10.6 23.9 10.3 23.3 10.1C22.8 9.9 22.3 10.1 21.9 10.6C21.9 10.6 21.9 10.8 21.9 10.8C21.9 11.2 21.9 11.5 22.3 11.7C22.5 11.9 22.8 11.9 23.2 11.7C23.2 11.7 23.3 11.5 23.3 11.5C23.9 11.2 24 11 24.4 11.7C25.1 12.7 25.8 13.9 26.6 15C26.6 15.2 26.6 15.3 26.6 15.5C26.5 16.2 26.3 16.9 26.1 17.6C25.8 18.8 25.2 19.2 24 19.2H23.9C23.7 19.3 23.9 19.5 24 19.5C24.7 19.7 25.6 19.9 26.3 19.9C26.5 19.9 26.6 19.9 26.8 19.7C27.3 19 27.7 18.3 27.9 17.4C27.9 17.3 28 16.9 28 16.7C28.2 17.1 28.5 17.6 28.9 17.9C29.4 18.5 29.9 19.2 30.5 19.5C30.8 19.7 31.2 19.9 31.5 19.9C32 19.9 32.4 19.5 32.4 19C32.4 19 32.4 18.8 32.4 18.8C32.2 18.3 31.9 18.1 31.3 18.3C31.3 18.3 31.3 18.3 31.3 18.3C31.2 18.3 31.2 18.3 31 18.3C30.5 18.6 29.8 18.5 29.4 17.9C29.4 17.9 29.4 17.9 29.4 17.9C29.1 17.4 28.5 16.7 28.2 16.2C28.2 16 28.2 16 28.2 15.9C28.5 14.6 28.7 13.4 29.1 12C29.1 11.9 29.1 11.9 29.2 11.7C29.4 11.2 29.8 11 30.1 11.5C30.6 11.9 30.8 12.4 31.3 12.7z" />
<glyph glyph-name="list" <glyph glyph-name="list"
unicode="&#xF10B;" unicode="&#xF109;"
horiz-adv-x="40" d=" M11.1 30.4H36.9V27.3H11.1V30.4z M11.1 22.4H36.9V19.3H11.1V22.4z M11.1 14.4H36.9V11.3H11.1V14.4z M5.6 27.3H3.8V33.6H2.4V34.6C3.3 34.6 4 35.1 4.2 36.2H5.6V27.3z M7.7 17.6V16H1.4V16.7C1.4 18.8 2.8 19.7 4 20.3C5.7 21.2 5.7 21.6 5.7 22.1C5.7 22.6 5.4 23.1 4.5 23.1C3.7 23.1 3.1 22.4 3.1 21.6H1.4C1.4 23.1 2.4 24.7 4.5 24.7C6.6 24.7 7.5 23.3 7.5 22.1C7.5 20.3 6.3 19.8 4.9 19C4 18.4 3.3 17.9 3.3 17.4H7.7z M4.5 4.5C2.4 4.5 1.4 5.9 1.2 7.5H3C3 6.6 3.5 6.1 4.5 6.1C5.6 6.1 6.1 6.6 6.1 7.3C6.1 8 5.6 8.5 4.7 8.5H4.2V9.9H4.5C5.6 9.9 5.9 10.4 5.9 11C5.9 11.7 5.4 12 4.7 12C3.8 12 3.3 11.3 3.3 10.6H1.6C1.6 12.2 2.6 13.6 4.5 13.6C6.4 13.6 7.5 12.3 7.5 11.1C7.5 10.4 7.1 9.7 6.3 9.4C7.3 9 7.7 8.2 7.7 7.3C7.8 6.1 6.8 4.5 4.5 4.5z" /> horiz-adv-x="40" d=" M11.1 30.4H36.9V27.3H11.1V30.4z M11.1 22.4H36.9V19.3H11.1V22.4z M11.1 14.4H36.9V11.3H11.1V14.4z M5.6 27.3H3.8V33.6H2.4V34.6C3.3 34.6 4 35.1 4.2 36.2H5.6V27.3z M7.7 17.6V16H1.4V16.7C1.4 18.8 2.8 19.7 4 20.3C5.7 21.2 5.7 21.6 5.7 22.1C5.7 22.6 5.4 23.1 4.5 23.1C3.7 23.1 3.1 22.4 3.1 21.6H1.4C1.4 23.1 2.4 24.7 4.5 24.7C6.6 24.7 7.5 23.3 7.5 22.1C7.5 20.3 6.3 19.8 4.9 19C4 18.4 3.3 17.9 3.3 17.4H7.7z M4.5 4.5C2.4 4.5 1.4 5.9 1.2 7.5H3C3 6.6 3.5 6.1 4.5 6.1C5.6 6.1 6.1 6.6 6.1 7.3C6.1 8 5.6 8.5 4.7 8.5H4.2V9.9H4.5C5.6 9.9 5.9 10.4 5.9 11C5.9 11.7 5.4 12 4.7 12C3.8 12 3.3 11.3 3.3 10.6H1.6C1.6 12.2 2.6 13.6 4.5 13.6C6.4 13.6 7.5 12.3 7.5 11.1C7.5 10.4 7.1 9.7 6.3 9.4C7.3 9 7.7 8.2 7.7 7.3C7.8 6.1 6.8 4.5 4.5 4.5z" />
<glyph glyph-name="logic" <glyph glyph-name="logic"
unicode="&#xF10C;" unicode="&#xF10A;"
horiz-adv-x="40" d=" M2.8 14.1H7.4C10 14.2 12.2 16 13.1 18.6C15 23.1 18.3 31.3 23.7 31.3S29.8 31.3 29.8 31.3V35.8L36.9 28.3L29.8 21.5V26.4H24.9C22.3 25.7 20.2 24 19.4 21.5C17.3 17 15.2 9.4 8.2 9.2C5.1 9.2 3 9.2 3 9.2V14.1z M2.8 31.1V26.2H8.2C8.2 26.2 11.4 26.2 13.1 22.1C13.8 23.8 14.7 25.4 15.7 26.9C15.7 26.9 12.2 30.9 8.4 30.9S2.8 31.1 2.8 31.1z M19.5 18.4C19.5 18.4 21.8 13.9 24.4 13.9H30V18.4L37.3 11.3L30 4.2V9H23.7C23.7 9 20.2 9 16.9 13.4C18 14.9 18.8 16.7 19.5 18.4z" /> horiz-adv-x="40" d=" M2.8 14.1H7.4C10 14.2 12.2 16 13.1 18.6C15 23.1 18.3 31.3 23.7 31.3S29.8 31.3 29.8 31.3V35.8L36.9 28.3L29.8 21.5V26.4H24.9C22.3 25.7 20.2 24 19.4 21.5C17.3 17 15.2 9.4 8.2 9.2C5.1 9.2 3 9.2 3 9.2V14.1z M2.8 31.1V26.2H8.2C8.2 26.2 11.4 26.2 13.1 22.1C13.8 23.8 14.7 25.4 15.7 26.9C15.7 26.9 12.2 30.9 8.4 30.9S2.8 31.1 2.8 31.1z M19.5 18.4C19.5 18.4 21.8 13.9 24.4 13.9H30V18.4L37.3 11.3L30 4.2V9H23.7C23.7 9 20.2 9 16.9 13.4C18 14.9 18.8 16.7 19.5 18.4z" />
<glyph glyph-name="loops" <glyph glyph-name="loops"
unicode="&#xF10D;" unicode="&#xF10B;"
horiz-adv-x="40" d=" M7.6 12.2C6.1 14.5 4.3 16.6 2.8 18.8H6.1C6.1 22.6 7.6 26.5 10.4 29.1C12.3 31 14.6 32.2 17.2 32.7C21.9 33.8 27 32.4 30.4 28.9C29.6 28 28.9 27.3 28.2 26.6C24 30.1 19.6 30.8 14.8 28.2C11.3 26.3 9.4 22.6 9.4 18.8H12.7C11 16.6 9.2 14.3 7.6 12.2z M31.3 18.8H28C29.7 21.1 31.3 23.2 32.9 25.4C34.6 23.2 36.2 21.1 37.7 18.8H34.4C34.4 14.8 32.7 11 29.9 8.4C28 6.6 25.7 5.4 23.3 4.9C18.6 3.9 13.6 5.3 10.1 8.7L12.3 11C16.3 7.5 20.9 6.6 25.7 9.4C29.2 11.2 31.3 14.8 31.3 18.8z" /> horiz-adv-x="40" d=" M7.6 12.2C6.1 14.5 4.3 16.6 2.8 18.8H6.1C6.1 22.6 7.6 26.5 10.4 29.1C12.3 31 14.6 32.2 17.2 32.7C21.9 33.8 27 32.4 30.4 28.9C29.6 28 28.9 27.3 28.2 26.6C24 30.1 19.6 30.8 14.8 28.2C11.3 26.3 9.4 22.6 9.4 18.8H12.7C11 16.6 9.2 14.3 7.6 12.2z M31.3 18.8H28C29.7 21.1 31.3 23.2 32.9 25.4C34.6 23.2 36.2 21.1 37.7 18.8H34.4C34.4 14.8 32.7 11 29.9 8.4C28 6.6 25.7 5.4 23.3 4.9C18.6 3.9 13.6 5.3 10.1 8.7L12.3 11C16.3 7.5 20.9 6.6 25.7 9.4C29.2 11.2 31.3 14.8 31.3 18.8z" />
<glyph glyph-name="math" <glyph glyph-name="math"
unicode="&#xF10E;" unicode="&#xF10C;"
horiz-adv-x="40" d=" M15.6 7.9C15.2 7.5 14.7 7 14.4 6.7L10.5 10.5C9.1 9.1 7.9 7.9 6.7 6.7C6.4 7 5.8 7.5 5.5 7.9L9.3 11.7C7.9 13.1 6.7 14.3 5.5 15.5C5.8 15.9 6.4 16.4 6.7 16.7L10.5 12.9L14.4 16.7C14.7 16.4 15.2 15.9 15.6 15.5L11.8 11.7C13 10.3 14.4 9.1 15.6 7.9z M4.3 26.8V28.4H9.7V33.8C10.2 33.8 10.7 33.8 11.2 33.8V28.4H16.6V26.8H11.2V21.4H9.5V26.8H4.3z M34.9 12.4H21.3V15.4H34.9V12.4z M34.9 9.4V6.5H21.3V9.4H34.9z M34.9 29.3V26.3H21.3V29.3H34.9z" /> horiz-adv-x="40" d=" M15.6 7.9C15.2 7.5 14.7 7 14.4 6.7L10.5 10.5C9.1 9.1 7.9 7.9 6.7 6.7C6.4 7 5.8 7.5 5.5 7.9L9.3 11.7C7.9 13.1 6.7 14.3 5.5 15.5C5.8 15.9 6.4 16.4 6.7 16.7L10.5 12.9L14.4 16.7C14.7 16.4 15.2 15.9 15.6 15.5L11.8 11.7C13 10.3 14.4 9.1 15.6 7.9z M4.3 26.8V28.4H9.7V33.8C10.2 33.8 10.7 33.8 11.2 33.8V28.4H16.6V26.8H11.2V21.4H9.5V26.8H4.3z M34.9 12.4H21.3V15.4H34.9V12.4z M34.9 9.4V6.5H21.3V9.4H34.9z M34.9 29.3V26.3H21.3V29.3H34.9z" />
<glyph glyph-name="motors" <glyph glyph-name="motors"
unicode="&#xF10F;" unicode="&#xF10D;"
horiz-adv-x="40" d=" M28.9 25.8C27.5 24.4 25.9 22.9 24.5 21.5H35.7V32.6L32.2 29.1C29.6 32.3 25.9 34.3 21.8 34.9C18.3 35.4 14.6 34.5 11.7 32.6C4.2 28.1 1.9 18.3 6.5 10.9S20.7 1.1 28.2 5.6C30.8 7.2 32.7 9.5 34.1 12.1C32.7 12.6 31.3 13.3 29.9 13.8C28.5 11 25.9 9 23 8.1C20.7 7.4 18.3 7.6 16 8.4C10.3 10.7 7.3 17.1 9.4 22.9C10.6 26.3 13.6 29 17.1 29.8C21.6 31.2 26.3 29.5 28.9 25.8z M16.7 19C16.7 17.1 18.3 15.7 20 15.7S23.3 17.3 23.3 19C23.3 21 21.8 22.3 20 22.3C18.1 22.5 16.7 21 16.7 19C16.7 19 16.7 19 16.7 19z" /> horiz-adv-x="40" d=" M28.9 25.8C27.5 24.4 25.9 22.9 24.5 21.5H35.7V32.6L32.2 29.1C29.6 32.3 25.9 34.3 21.8 34.9C18.3 35.4 14.6 34.5 11.7 32.6C4.2 28.1 1.9 18.3 6.5 10.9S20.7 1.1 28.2 5.6C30.8 7.2 32.7 9.5 34.1 12.1C32.7 12.6 31.3 13.3 29.9 13.8C28.5 11 25.9 9 23 8.1C20.7 7.4 18.3 7.6 16 8.4C10.3 10.7 7.3 17.1 9.4 22.9C10.6 26.3 13.6 29 17.1 29.8C21.6 31.2 26.3 29.5 28.9 25.8z M16.7 19C16.7 17.1 18.3 15.7 20 15.7S23.3 17.3 23.3 19C23.3 21 21.8 22.3 20 22.3C18.1 22.5 16.7 21 16.7 19C16.7 19 16.7 19 16.7 19z" />
<glyph glyph-name="music" <glyph glyph-name="music"
unicode="&#xF110;" unicode="&#xF10E;"
horiz-adv-x="40" d=" M24.2 17.7C27.1 17.2 29.9 15.7 31.7 13.2C32.5 13.2 33.4 13.2 33.4 13.2S36 20.9 30.3 26.3S13.4 31.7 9.2 26.3C6.3 22.6 5.2 17.6 6.8 13.2C7.3 13.2 7.7 13.2 8.2 13.2C8.2 13.2 11.1 17.6 15.8 17.7C15.7 10.1 15.7 3.5 15.7 3.5C12.3 4.2 9.6 6.3 8 9.4C4.5 10.1 1.7 13.2 1.7 17C1.7 28.3 10.3 34.8 20 34.8S38.8 27.3 38.1 17C37.7 9.9 31.8 9.4 31.8 9.4C30.4 6.3 27.7 4 24.3 3.5C24.2 11.3 24.2 17.7 24.2 17.7z" /> horiz-adv-x="40" d=" M24.2 17.7C27.1 17.2 29.9 15.7 31.7 13.2C32.5 13.2 33.4 13.2 33.4 13.2S36 20.9 30.3 26.3S13.4 31.7 9.2 26.3C6.3 22.6 5.2 17.6 6.8 13.2C7.3 13.2 7.7 13.2 8.2 13.2C8.2 13.2 11.1 17.6 15.8 17.7C15.7 10.1 15.7 3.5 15.7 3.5C12.3 4.2 9.6 6.3 8 9.4C4.5 10.1 1.7 13.2 1.7 17C1.7 28.3 10.3 34.8 20 34.8S38.8 27.3 38.1 17C37.7 9.9 31.8 9.4 31.8 9.4C30.4 6.3 27.7 4 24.3 3.5C24.2 11.3 24.2 17.7 24.2 17.7z" />
<glyph glyph-name="sensors" <glyph glyph-name="sensors"
unicode="&#xF111;" unicode="&#xF10F;"
horiz-adv-x="40" d=" M20 37.4C29.6 37.4 37.4 29.6 37.4 20S29.6 2.6 20 2.6S2.6 10.4 2.6 20S10.4 37.4 20 37.4z M20 7.8C26.8 7.8 32.2 13.2 32.2 20S26.8 32.2 20 32.2S7.8 26.8 7.8 20S13.2 7.8 20 7.8M20 2.6C10.4 2.6 2.6 10.4 2.6 20S10.4 37.4 20 37.4S37.4 29.6 37.4 20S29.6 2.6 20 2.6z M20 27C23.8 27 27 23.8 27 20S23.8 13 20 13S13 16.2 13 20S16.2 27 20 27z" /> horiz-adv-x="40" d=" M20 37.4C29.6 37.4 37.4 29.6 37.4 20S29.6 2.6 20 2.6S2.6 10.4 2.6 20S10.4 37.4 20 37.4z M20 7.8C26.8 7.8 32.2 13.2 32.2 20S26.8 32.2 20 32.2S7.8 26.8 7.8 20S13.2 7.8 20 7.8M20 2.6C10.4 2.6 2.6 10.4 2.6 20S10.4 37.4 20 37.4S37.4 29.6 37.4 20S29.6 2.6 20 2.6z M20 27C23.8 27 27 23.8 27 20S23.8 13 20 13S13 16.2 13 20S16.2 27 20 27z" />
<glyph glyph-name="text" <glyph glyph-name="text"
unicode="&#xF112;" unicode="&#xF110;"
horiz-adv-x="40" d=" M23.1 30.6V2.8H16.5V30.6H7.7V36.7H32.3V30.6H23.1z" /> horiz-adv-x="40" d=" M23.1 30.6V2.8H16.5V30.6H7.7V36.7H32.3V30.6H23.1z" />
<glyph glyph-name="variables" <glyph glyph-name="variables"
unicode="&#xF113;" unicode="&#xF111;"
horiz-adv-x="40" d=" M5.2 31.3H33V8.7H5.2V31.3z M33 31.3V27.8H5.2V31.3H33z M33 22.6V19.1H5.2V22.6H33z M33 13.9V10.4H5.2V13.9H33z" /> horiz-adv-x="40" d=" M5.2 31.3H33V8.7H5.2V31.3z M33 31.3V27.8H5.2V31.3H33z M33 22.6V19.1H5.2V22.6H33z M33 13.9V10.4H5.2V13.9H33z" />
<glyph glyph-name="cancel" <glyph glyph-name="cancel"
unicode="&#xF114;" unicode="&#xF112;"
horiz-adv-x="40" d=" M4285.9 23284.1H4308.1V23280.4H4285.9V23284.1z M4285.9 23302.6H4289.6V23280.4H4285.9V23302.6z" /> horiz-adv-x="40" d=" M4285.9 23284.1H4308.1V23280.4H4285.9V23284.1z M4285.9 23302.6H4289.6V23280.4H4285.9V23302.6z" />
<glyph glyph-name="check" <glyph glyph-name="check"
unicode="&#xF115;" unicode="&#xF113;"
horiz-adv-x="40" d=" M4209.2 23456H4231.3V23452.3H4209.2V23456z M4201.2 23463.4H4204.9V23452.3H4201.2V23463.4z" /> horiz-adv-x="40" d=" M4209.2 23456H4231.3V23452.3H4209.2V23456z M4201.2 23463.4H4204.9V23452.3H4201.2V23463.4z" />
<glyph glyph-name="download" <glyph glyph-name="download"
unicode="&#xF116;" unicode="&#xF114;"
horiz-adv-x="40" d=" M5.2 15.7H36.5V1.7H5.2V15.7z M19.1 36.5H22.6V19.1H19.1V36.5z M18803.9 -5968.6H18811.3V-5971.1H18803.9V-5968.6z M18798.7 -5963.7H18801.2V-5971.1H18798.7V-5963.7z" /> horiz-adv-x="40" d=" M5.2 15.7H36.5V1.7H5.2V15.7z M19.1 36.5H22.6V19.1H19.1V36.5z M18803.9 -5968.6H18811.3V-5971.1H18803.9V-5968.6z M18798.7 -5963.7H18801.2V-5971.1H18798.7V-5963.7z" />
<glyph glyph-name="save" <glyph glyph-name="save"
unicode="&#xF117;" unicode="&#xF115;"
horiz-adv-x="40" d=" M4.2 19.2V33.8C4.2 34.9 4.3 35 5.4 35H12.3C13.4 35 13.6 34.9 13.6 33.8V26.7C13.6 25.8 13.7 25.6 14.6 25.6H25C25.9 25.6 26.1 25.8 26.1 26.7V34C26.1 34.9 26.3 35 27.1 35C29.2 35 29.2 35 30.6 33.6C32.2 32.1 33.6 30.7 35.1 29.1C35.5 28.8 35.7 28.4 35.7 27.9V4.4C35.7 3.6 35.5 3.2 34.6 3.2H5.2C4.3 3.2 4.2 3.4 4.2 4.4C4.2 9.5 4.2 14.3 4.2 19.2zM20 6.7H31.5C32.5 6.7 32.7 6.9 32.7 7.9V21.3C32.7 22.2 32.5 22.5 31.5 22.5H8.5C7.7 22.5 7.3 22.3 7.3 21.3V7.9C7.3 6.9 7.5 6.7 8.5 6.7H20z M24 31.9C24 31.2 24 30.3 24 29.6C24 28.9 23.7 28.8 23.1 28.8C22.6 28.8 22.1 28.8 21.7 28.8C21.4 28.8 20.9 28.9 20.9 29.5C20.9 29.5 20.9 29.6 20.9 29.6V34.2C20.9 34.5 21 34.9 21.6 35C21.6 35 21.6 35 21.7 35C22.3 35 22.8 35 23.3 35C23.8 35 24.2 34.7 24.2 34.3C24.2 34.3 24.2 34.3 24.2 34.2C24 33.5 24 32.6 24 31.9z M6.7 23.6H33.5V5.7H6.7V23.6z M7.6 22.8H32.6V6.6H7.6V22.8z" /> horiz-adv-x="40" d=" M4.2 19.2V33.8C4.2 34.9 4.3 35 5.4 35H12.3C13.4 35 13.6 34.9 13.6 33.8V26.7C13.6 25.8 13.7 25.6 14.6 25.6H25C25.9 25.6 26.1 25.8 26.1 26.7V34C26.1 34.9 26.3 35 27.1 35C29.2 35 29.2 35 30.6 33.6C32.2 32.1 33.6 30.7 35.1 29.1C35.5 28.8 35.7 28.4 35.7 27.9V4.4C35.7 3.6 35.5 3.2 34.6 3.2H5.2C4.3 3.2 4.2 3.4 4.2 4.4C4.2 9.5 4.2 14.3 4.2 19.2zM20 6.7H31.5C32.5 6.7 32.7 6.9 32.7 7.9V21.3C32.7 22.2 32.5 22.5 31.5 22.5H8.5C7.7 22.5 7.3 22.3 7.3 21.3V7.9C7.3 6.9 7.5 6.7 8.5 6.7H20z M24 31.9C24 31.2 24 30.3 24 29.6C24 28.9 23.7 28.8 23.1 28.8C22.6 28.8 22.1 28.8 21.7 28.8C21.4 28.8 20.9 28.9 20.9 29.5C20.9 29.5 20.9 29.6 20.9 29.6V34.2C20.9 34.5 21 34.9 21.6 35C21.6 35 21.6 35 21.7 35C22.3 35 22.8 35 23.3 35C23.8 35 24.2 34.7 24.2 34.3C24.2 34.3 24.2 34.3 24.2 34.2C24 33.5 24 32.6 24 31.9z M6.7 23.6H33.5V5.7H6.7V23.6z M7.6 22.8H32.6V6.6H7.6V22.8z" />
</font> </font>
</defs> </defs>

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -21,8 +21,6 @@
"brick.Button.pauseUntil": "Waits until the event is raised", "brick.Button.pauseUntil": "Waits until the event is raised",
"brick.Button.pauseUntil|param|ev": "the event to wait for", "brick.Button.pauseUntil|param|ev": "the event to wait for",
"brick.Button.wasPressed": "See if the button was pressed again since the last time you checked.", "brick.Button.wasPressed": "See if the button was pressed again since the last time you checked.",
"brick._imagePicker": "An image",
"brick._imagePicker|param|image": "the image",
"brick.buttonDown": "Down button on the EV3 Brick.", "brick.buttonDown": "Down button on the EV3 Brick.",
"brick.buttonEnter": "Enter button on the EV3 Brick.", "brick.buttonEnter": "Enter button on the EV3 Brick.",
"brick.buttonLeft": "Left button on the EV3 Brick.", "brick.buttonLeft": "Left button on the EV3 Brick.",

View File

@ -28,7 +28,6 @@
"brick.Button.onEvent|block": "on %button|%event", "brick.Button.onEvent|block": "on %button|%event",
"brick.Button.pauseUntil|block": "pause until %button|%event", "brick.Button.pauseUntil|block": "pause until %button|%event",
"brick.Button.wasPressed|block": "%button|was pressed", "brick.Button.wasPressed|block": "%button|was pressed",
"brick._imagePicker|block": "%image",
"brick.buttonDown|block": "down", "brick.buttonDown|block": "down",
"brick.buttonEnter|block": "enter", "brick.buttonEnter|block": "enter",
"brick.buttonLeft|block": "left", "brick.buttonLeft|block": "left",

View File

@ -1,260 +1,260 @@
namespace images { namespace images {
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsBigSmile = screen.unpackPNG(hex``); export const expressionsBigSmile = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsHeartLarge = screen.unpackPNG(hex``); export const expressionsHeartLarge = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsHeartSmall = screen.unpackPNG(hex``); export const expressionsHeartSmall = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsMouth1open = screen.unpackPNG(hex``); export const expressionsMouth1open = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsMouth1shut = screen.unpackPNG(hex``); export const expressionsMouth1shut = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsMouth2open = screen.unpackPNG(hex``); export const expressionsMouth2open = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsMouth2shut = screen.unpackPNG(hex``); export const expressionsMouth2shut = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsSad = screen.unpackPNG(hex``); export const expressionsSad = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsSick = screen.unpackPNG(hex``); export const expressionsSick = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsSmile = screen.unpackPNG(hex``); export const expressionsSmile = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsSwearing = screen.unpackPNG(hex``); export const expressionsSwearing = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsTalking = screen.unpackPNG(hex``); export const expressionsTalking = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsWink = screen.unpackPNG(hex``); export const expressionsWink = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const expressionsZzz = screen.unpackPNG(hex``); export const expressionsZzz = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesAngry = screen.unpackPNG(hex``); export const eyesAngry = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesAwake = screen.unpackPNG(hex``); export const eyesAwake = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesBlackEye = screen.unpackPNG(hex``); export const eyesBlackEye = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesBottomLeft = screen.unpackPNG(hex``); export const eyesBottomLeft = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesBottomRight = screen.unpackPNG(hex``); export const eyesBottomRight = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesCrazy1 = screen.unpackPNG(hex``); export const eyesCrazy1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesCrazy2 = screen.unpackPNG(hex``); export const eyesCrazy2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesDisappointed = screen.unpackPNG(hex``); export const eyesDisappointed = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesDizzy = screen.unpackPNG(hex``); export const eyesDizzy = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesDown = screen.unpackPNG(hex``); export const eyesDown = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesEvil = screen.unpackPNG(hex``); export const eyesEvil = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesHurt = screen.unpackPNG(hex``); export const eyesHurt = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesKnockedOut = screen.unpackPNG(hex``); export const eyesKnockedOut = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesLove = screen.unpackPNG(hex``); export const eyesLove = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesMiddleLeft = screen.unpackPNG(hex``); export const eyesMiddleLeft = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesMiddleRight = screen.unpackPNG(hex``); export const eyesMiddleRight = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesNeutral = screen.unpackPNG(hex``); export const eyesNeutral = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesNuclear = screen.unpackPNG(hex``); export const eyesNuclear = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesPinchLeft = screen.unpackPNG(hex``); export const eyesPinchLeft = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesPinchMiddle = screen.unpackPNG(hex``); export const eyesPinchMiddle = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesPinchRight = screen.unpackPNG(hex``); export const eyesPinchRight = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesSleeping = screen.unpackPNG(hex``); export const eyesSleeping = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesTear = screen.unpackPNG(hex``); export const eyesTear = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesTiredLeft = screen.unpackPNG(hex``); export const eyesTiredLeft = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesTiredMiddle = screen.unpackPNG(hex``); export const eyesTiredMiddle = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesTiredRight = screen.unpackPNG(hex``); export const eyesTiredRight = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesToxic = screen.unpackPNG(hex``); export const eyesToxic = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesUp = screen.unpackPNG(hex``); export const eyesUp = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const eyesWinking = screen.unpackPNG(hex``); export const eyesWinking = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationAccept = screen.unpackPNG(hex``); export const informationAccept = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationBackward = screen.unpackPNG(hex``); export const informationBackward = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationDecline = screen.unpackPNG(hex``); export const informationDecline = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationForward = screen.unpackPNG(hex``); export const informationForward = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationLeft = screen.unpackPNG(hex``); export const informationLeft = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationNoGo = screen.unpackPNG(hex``); export const informationNoGo = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationQuestionMark = screen.unpackPNG(hex``); export const informationQuestionMark = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationRight = screen.unpackPNG(hex``); export const informationRight = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationStop1 = screen.unpackPNG(hex``); export const informationStop1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationStop2 = screen.unpackPNG(hex``); export const informationStop2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationThumbsDown = screen.unpackPNG(hex``); export const informationThumbsDown = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationThumbsUp = screen.unpackPNG(hex``); export const informationThumbsUp = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const informationWarning = screen.unpackPNG(hex``); export const informationWarning = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoColorSensor = screen.unpackPNG(hex``); export const legoColorSensor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoEv3icon = screen.unpackPNG(hex``); export const legoEv3icon = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoEv3 = screen.unpackPNG(hex``); export const legoEv3 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoGyroSensor = screen.unpackPNG(hex``); export const legoGyroSensor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoIrBeacon = screen.unpackPNG(hex``); export const legoIrBeacon = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoIrSensor = screen.unpackPNG(hex``); export const legoIrSensor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoLego = screen.unpackPNG(hex``); export const legoLego = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoLargeMotor = screen.unpackPNG(hex``); export const legoLargeMotor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoMindstorms = screen.unpackPNG(hex``); export const legoMindstorms = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoMediumMotor = screen.unpackPNG(hex``); export const legoMediumMotor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoSoundSensor = screen.unpackPNG(hex``); export const legoSoundSensor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoTempSensor = screen.unpackPNG(hex``); export const legoTempSensor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoTouchSensor = screen.unpackPNG(hex``); export const legoTouchSensor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const legoUsSensor = screen.unpackPNG(hex``); export const legoUsSensor = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsBomb = screen.unpackPNG(hex``); export const objectsBomb = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsBoom = screen.unpackPNG(hex``); export const objectsBoom = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsFire = screen.unpackPNG(hex``); export const objectsFire = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsFlowers = screen.unpackPNG(hex``); export const objectsFlowers = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsForest = screen.unpackPNG(hex``); export const objectsForest = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsLightOff = screen.unpackPNG(hex``); export const objectsLightOff = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsLightOn = screen.unpackPNG(hex``); export const objectsLightOn = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsLightning = screen.unpackPNG(hex``); export const objectsLightning = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsNight = screen.unpackPNG(hex``); export const objectsNight = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsPirate = screen.unpackPNG(hex``); export const objectsPirate = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsSnow = screen.unpackPNG(hex``); export const objectsSnow = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const objectsTarget = screen.unpackPNG(hex``); export const objectsTarget = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar0 = screen.unpackPNG(hex``); export const progressBar0 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar1 = screen.unpackPNG(hex``); export const progressBar1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar2 = screen.unpackPNG(hex``); export const progressBar2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar3 = screen.unpackPNG(hex``); export const progressBar3 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressBar4 = screen.unpackPNG(hex``); export const progressBar4 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial0 = screen.unpackPNG(hex``); export const progressDial0 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial1 = screen.unpackPNG(hex``); export const progressDial1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial2 = screen.unpackPNG(hex``); export const progressDial2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial3 = screen.unpackPNG(hex``); export const progressDial3 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDial4 = screen.unpackPNG(hex``); export const progressDial4 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDots0 = screen.unpackPNG(hex``); export const progressDots0 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDots1 = screen.unpackPNG(hex``); export const progressDots1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDots2 = screen.unpackPNG(hex``); export const progressDots2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressDots3 = screen.unpackPNG(hex``); export const progressDots3 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressHourglass0 = screen.unpackPNG(hex``); export const progressHourglass0 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressHourglass1 = screen.unpackPNG(hex``); export const progressHourglass1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressHourglass2 = screen.unpackPNG(hex``); export const progressHourglass2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer0 = screen.unpackPNG(hex``); export const progressTimer0 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer1 = screen.unpackPNG(hex``); export const progressTimer1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer2 = screen.unpackPNG(hex``); export const progressTimer2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer3 = screen.unpackPNG(hex``); export const progressTimer3 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressTimer4 = screen.unpackPNG(hex``); export const progressTimer4 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressWaterLevel0 = screen.unpackPNG(hex``); export const progressWaterLevel0 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressWaterLevel1 = screen.unpackPNG(hex``); export const progressWaterLevel1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressWaterLevel2 = screen.unpackPNG(hex``); export const progressWaterLevel2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const progressWaterLevel3 = screen.unpackPNG(hex``); export const progressWaterLevel3 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemAccept1 = screen.unpackPNG(hex``); export const systemAccept1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemAccept2 = screen.unpackPNG(hex``); export const systemAccept2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemAlert = screen.unpackPNG(hex``); export const systemAlert = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemBox = screen.unpackPNG(hex``); export const systemBox = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemBusy0 = screen.unpackPNG(hex``); export const systemBusy0 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemBusy1 = screen.unpackPNG(hex``); export const systemBusy1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemDecline1 = screen.unpackPNG(hex``); export const systemDecline1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemDecline2 = screen.unpackPNG(hex``); export const systemDecline2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemDotEmpty = screen.unpackPNG(hex``); export const systemDotEmpty = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemDotFull = screen.unpackPNG(hex``); export const systemDotFull = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemEv3small = screen.unpackPNG(hex``); export const systemEv3small = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemPlay = screen.unpackPNG(hex``); export const systemPlay = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider0 = screen.unpackPNG(hex``); export const systemSlider0 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider1 = screen.unpackPNG(hex``); export const systemSlider1 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider2 = screen.unpackPNG(hex``); export const systemSlider2 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider3 = screen.unpackPNG(hex``); export const systemSlider3 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider4 = screen.unpackPNG(hex``); export const systemSlider4 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider5 = screen.unpackPNG(hex``); export const systemSlider5 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider6 = screen.unpackPNG(hex``); export const systemSlider6 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider7 = screen.unpackPNG(hex``); export const systemSlider7 = screen.unpackPNG(hex``);
//% fixedInstance jres blockIdentity=brick._imagePicker //% fixedInstance jres blockIdentity=brick.__imagePicker
export const systemSlider8 = screen.unpackPNG(hex``); export const systemSlider8 = screen.unpackPNG(hex``);
} }

View File

@ -158,7 +158,7 @@ namespace brick {
//% image.fieldOptions.columns=6 //% image.fieldOptions.columns=6
//% image.fieldOptions.hasSearchBar=true //% image.fieldOptions.hasSearchBar=true
//% group="Screen" weight=0 blockHidden=1 //% group="Screen" weight=0 blockHidden=1
export function _imagePicker(image: Image): Image { export function __imagePicker(image: Image): Image {
return image; return image;
} }

View File

@ -1,19 +1,19 @@
//% color="#68C3E2" weight=100 icon="\uf108" //% color="#68C3E2" weight=100 icon="\uf106"
//% groups='["Buttons", "Screen"]' //% groups='["Buttons", "Screen"]'
//% labelLineWidth=0 //% labelLineWidth=0
namespace brick { namespace brick {
} }
//% color="#C8509B" weight=95 icon="\uf111" //% color="#C8509B" weight=95 icon="\uf10f"
//% labelLineWidth=0 //% labelLineWidth=0
//% groups='["Ultrasonic Sensor", "Touch Sensor", "Color Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]' //% groups='["Ultrasonic Sensor", "Touch Sensor", "Color Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
//% groupIcons='["\uf101","\uf103","\uf102","","","\uf104"]' //% groupIcons='["\uf101","\uf103","\uf102","","","\uf104"]'
namespace sensors { namespace sensors {
} }
//% color="#A5CA18" weight=90 icon="\uf10f" //% color="#A5CA18" weight=90 icon="\uf10d"
//% groups='["Motion", "Sensors", "Chassis"]' //% groups='["Motion", "Sensors", "Chassis"]'
//% labelLineWidth=0 //% labelLineWidth=0
namespace motors { namespace motors {

View File

@ -1,6 +1,6 @@
{ {
"name": "pxt-ev3", "name": "pxt-ev3",
"version": "0.0.45", "version": "0.0.46",
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode", "description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
"private": true, "private": true,
"keywords": [ "keywords": [

View File

@ -139,9 +139,7 @@
}, },
"monacoColors": { "monacoColors": {
"editor.background": "#ecf6ff" "editor.background": "#ecf6ff"
}, }
"simAnimationEnter": "horizontal flip in",
"simAnimationExit": "horizontal flip out"
}, },
"ignoreDocsErrors": true "ignoreDocsErrors": true
} }

View File

@ -23,20 +23,6 @@ namespace pxsim {
} }
export class EV3Board extends CoreBoard { export class EV3Board extends CoreBoard {
// state & update logic for component services
// neopixelState: CommonNeoPixelState;
buttonState: EV3ButtonState;
slideSwitchState: SlideSwitchState;
lightSensorState: AnalogSensorState;
thermometerState: AnalogSensorState;
thermometerUnitState: number;
microphoneState: AnalogSensorState;
edgeConnectorState: EdgeConnectorState;
capacitiveSensorState: CapacitiveSensorState;
accelerometerState: AccelerometerState;
touchButtonState: TouchButtonState;
irState: InfraredState;
view: SVGSVGElement; view: SVGSVGElement;
outputState: EV3OutputState; outputState: EV3OutputState;
@ -86,11 +72,6 @@ namespace pxsim {
// TODO // TODO
break; break;
} }
case "irpacket": {
let ev = <SimulatorInfraredPacketMessage>msg;
this.irState.receive(new RefBuffer(ev.packet));
break;
}
} }
} }
@ -120,6 +101,9 @@ namespace pxsim {
document.body.innerHTML = ""; // clear children document.body.innerHTML = ""; // clear children
document.body.appendChild(this.view = viewHost.getView() as SVGSVGElement); document.body.appendChild(this.view = viewHost.getView() as SVGSVGElement);
this.inputNodes = [];
this.outputNodes = [];
return Promise.resolve(); return Promise.resolve();
} }
@ -127,26 +111,33 @@ namespace pxsim {
return svg.toDataUri(new XMLSerializer().serializeToString(this.view)); return svg.toDataUri(new XMLSerializer().serializeToString(this.view));
} }
//defaultNeopixelPin() {
// return this.edgeConnectorState.getPin(CPlayPinName.D8);
//}
getDefaultPitchPin() {
return this.edgeConnectorState.getPin(CPlayPinName.D6);
}
getBrickNode() { getBrickNode() {
return this.brickNode; return this.brickNode;
} }
getMotor(port: number, large?: boolean): MotorNode[] { motorUsed(port:number, large: boolean) {
if (port == 0xFF) return this.getMotors(); // Return all motors for(let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
const motorPort = this.motorMap[port]; const p = 1 << i;
if (this.outputNodes[motorPort] == undefined) { if (port & p) {
this.outputNodes[motorPort] = large ? const motorPort = this.motorMap[p];
new LargeMotorNode(motorPort) : new MediumMotorNode(motorPort); if (!this.outputNodes[motorPort])
this.outputNodes[motorPort] = new MotorNode(motorPort, large);
} }
return [this.outputNodes[motorPort]]; }
}
getMotor(port: number, large?: boolean): MotorNode[] {
const r = [];
for(let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
const p = 1 << i;
if (port & p) {
const motorPort = this.motorMap[p];
const outputNode = this.outputNodes[motorPort];
if (outputNode)
r.push(outputNode);
}
}
return r;
} }
getMotors() { getMotors() {
@ -154,7 +145,7 @@ namespace pxsim {
} }
getSensor(port: number, type: number): SensorNode { getSensor(port: number, type: number): SensorNode {
if (this.inputNodes[port] == undefined) { if (!this.inputNodes[port]) {
switch (type) { switch (type) {
case DAL.DEVICE_TYPE_GYRO: this.inputNodes[port] = new GyroSensorNode(port); break; case DAL.DEVICE_TYPE_GYRO: this.inputNodes[port] = new GyroSensorNode(port); break;
case DAL.DEVICE_TYPE_COLOR: this.inputNodes[port] = new ColorSensorNode(port); break; case DAL.DEVICE_TYPE_COLOR: this.inputNodes[port] = new ColorSensorNode(port); break;

View File

@ -20,7 +20,7 @@ namespace pxsim {
export class ColorSensorNode extends UartSensorNode { export class ColorSensorNode extends UartSensorNode {
id = NodeType.ColorSensor; id = NodeType.ColorSensor;
private color: number; private color: number = 50;
constructor(port: number) { constructor(port: number) {
super(port); super(port);
@ -31,11 +31,9 @@ namespace pxsim {
} }
setColor(color: number) { setColor(color: number) {
if (this.color != color) {
this.color = color; this.color = color;
this.setChangedState(); this.setChangedState();
} }
}
getValue() { getValue() {
return this.color; return this.color;

View File

@ -81,7 +81,6 @@ namespace pxsim.control {
export function dmesg(s: string) { export function dmesg(s: string) {
console.log("DMESG: " + s) console.log("DMESG: " + s)
} }
} }
namespace pxsim.output { namespace pxsim.output {

View File

@ -2,8 +2,8 @@
namespace pxsim.motors { namespace pxsim.motors {
export function __motorUsed(port: number, large: boolean) { export function __motorUsed(port: number, large: boolean) {
console.log("MOTOR INIT " + port); //console.log("MOTOR INIT " + port);
const motors = ev3board().getMotor(port, large); ev3board().motorUsed(port, large);
runtime.queueDisplayUpdate(); runtime.queueDisplayUpdate();
} }
} }
@ -11,7 +11,7 @@ namespace pxsim.motors {
namespace pxsim.sensors { namespace pxsim.sensors {
export function __sensorUsed(port: number, type: number) { export function __sensorUsed(port: number, type: number) {
console.log("SENSOR INIT " + port + ", type: " + type); //console.log("SENSOR INIT " + port + ", type: " + type);
const sensor = ev3board().getSensor(port, type); const sensor = ev3board().getSensor(port, type);
runtime.queueDisplayUpdate(); runtime.queueDisplayUpdate();
} }

View File

@ -19,8 +19,8 @@ namespace pxsim {
// console.log("motor before read"); // console.log("motor before read");
for (let port = 0; port < DAL.NUM_OUTPUTS; ++port) { for (let port = 0; port < DAL.NUM_OUTPUTS; ++port) {
const output = outputs[port]; const output = outputs[port];
const speed = output ? Math.round(outputs[port].getSpeed()) : 0; const speed = output ? outputs[port].getSpeed() : 0;
const angle = output ? Math.round(outputs[port].getAngle()) : 0; const angle = output ? outputs[port].getAngle() : 0;
const tci = MotorDataOff.TachoCounts + port * MotorDataOff.Size; const tci = MotorDataOff.TachoCounts + port * MotorDataOff.Size;
const tsi = MotorDataOff.TachoSensor + port * MotorDataOff.Size; const tsi = MotorDataOff.TachoSensor + port * MotorDataOff.Size;
data[tci] = data[tci + 1] = data[tci + 2] = data[tci + 3] = 0; // Tacho count data[tci] = data[tci + 1] = data[tci + 2] = data[tci + 3] = 0; // Tacho count

141
sim/state/motornode.ts Normal file
View File

@ -0,0 +1,141 @@
namespace pxsim {
export class MotorNode extends BaseNode {
isOutput = true;
private rotationsPerMilliSecond: number;
// current state
private angle: number = 0;
private tacho: number = 0;
private speed: number = 0;
private polarity: number = 1; // -1, 1 or -1
private started: boolean;
private speedCmd: DAL;
private speedCmdValues: number[];
private speedCmdTacho: number;
private speedCmdTime: number;
constructor(port: number, large: boolean) {
super(port);
this.setLarge(large);
}
getSpeed() {
return this.speed * (this.polarity == 0 ? -1 : 1);
}
getAngle() {
return this.angle;
}
setSpeedCmd(cmd: DAL, values: number[]) {
this.speedCmd = cmd;
this.speedCmdValues = values;
this.speedCmdTacho = this.angle;
this.speedCmdTime = pxsim.U.now();
}
clearSpeedCmd() {
delete this.speedCmd;
}
setLarge(large: boolean) {
this.id = large ? NodeType.LargeMotor : NodeType.MediumMotor;
// large 170 rpm (https://education.lego.com/en-us/products/ev3-large-servo-motor/45502)
this.rotationsPerMilliSecond = (large ? 170 : 250) / 60000;
}
setPolarity(polarity: number) {
// Either 1 or 255 (reverse)
/*
-1 : Motor will run backward
0 : Motor will run opposite direction
1 : Motor will run forward
*/
this.polarity = polarity;
}
reset() {
// not sure what reset does...
}
clearCount() {
this.tacho = 0;
this.angle = 0;
}
stop() {
this.started = false;
}
start() {
this.started = true;
}
updateState(elapsed: number) {
console.log(`motor: ${elapsed}ms - ${this.speed}% - ${this.angle}> - ${this.tacho}|`)
const interval = Math.min(20, elapsed);
let t = 0;
while(t < elapsed) {
let dt = interval;
if (t + dt > elapsed) dt = elapsed - t;
this.updateStateStep(dt);
t += dt;
}
}
private updateStateStep(elapsed: number) {
// compute new speed
switch (this.speedCmd) {
case DAL.opOutputSpeed:
case DAL.opOutputPower:
// assume power == speed
// TODO: PID
this.speed = this.speedCmdValues[0];
break;
case DAL.opOutputTimeSpeed:
case DAL.opOutputTimePower:
case DAL.opOutputStepPower:
case DAL.opOutputStepSpeed:
// ramp up, run, ramp down, <brake> using time
const speed = this.speedCmdValues[0];
const step1 = this.speedCmdValues[1];
const step2 = this.speedCmdValues[2];
const step3 = this.speedCmdValues[3];
const brake = this.speedCmdValues[4];
const dstep = (this.speedCmd == DAL.opOutputTimePower || this.speedCmd == DAL.opOutputTimeSpeed)
? pxsim.U.now() - this.speedCmdTime
: this.tacho - this.speedCmdTacho;
if (dstep < step1) // rampup
this.speed = speed * dstep / step1;
else if (dstep < step1 + step2) // run
this.speed = speed;
else if (dstep < step1 + step2 + step3)
this.speed = speed * (step1 + step2 + step3 - dstep) / (step1 + step2 + step3);
else {
if (brake) this.speed = 0;
this.clearSpeedCmd();
}
this.speed = Math.round(this.speed); // integer only
break;
}
// compute delta angle
const rotations = this.getSpeed() / 100 * this.rotationsPerMilliSecond * elapsed;
const deltaAngle = Math.round(rotations * 360);
if (deltaAngle) {
this.angle += deltaAngle;
this.tacho += Math.abs(deltaAngle);
this.setChangedState();
}
// if the motor was stopped or there are no speed commands,
// let it coast to speed 0
if (this.speed && !(this.started || this.speedCmd)) {
// decay speed 5% per tick
this.speed = Math.round(Math.max(0, Math.abs(this.speed) - 10) * Math.sign(this.speed));
}
}
}
}

View File

@ -1,87 +0,0 @@
namespace pxsim {
export abstract class MotorNode extends BaseNode {
isOutput = true;
protected angle: number = 0;
private rotationsPerMilliSecond: number;
private speed: number;
private large: boolean;
private rotation: number;
private polarity: boolean;
constructor(port: number, rpm: number) {
super(port);
this.rotationsPerMilliSecond = rpm / 60000;
}
setSpeed(speed: number) {
if (this.speed != speed) {
this.speed = speed;
this.changed = true;
this.setChangedState();
}
}
setLarge(large: boolean) {
this.large = large;
}
getSpeed() {
return this.speed;
}
stepSpeed(speed: number, angle: number, brake: boolean) {
// TODO: implement
}
setPolarity(polarity: number) {
// Either 1 or 255 (reverse)
this.polarity = polarity === 255;
// TODO: implement
}
reset() {
// TODO: implement
}
stop() {
// TODO: implement
}
start() {
// TODO: implement
this.setChangedState();
}
public getAngle() {
return this.angle;
}
updateState(elapsed: number) {
const rotations = this.getSpeed() / 100 * this.rotationsPerMilliSecond * elapsed;
const angle = rotations * 360;
if (angle) {
this.angle += angle;
this.setChangedState();
}
}
}
export class MediumMotorNode extends MotorNode {
id = NodeType.MediumMotor;
constructor(port: number) {
super(port, 250);
}
}
export class LargeMotorNode extends MotorNode {
id = NodeType.LargeMotor;
constructor(port: number) {
super(port, 170);
}
}
}

View File

@ -34,24 +34,32 @@ namespace pxsim {
motors.forEach(motor => motor.reset()); motors.forEach(motor => motor.reset());
return 2; return 2;
} }
case DAL.opOutputStepSpeed: { case DAL.opOutputClearCount:
const port = buf.data[1];
const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.clearCount());
break;
case DAL.opOutputStepPower:
case DAL.opOutputStepSpeed:
case DAL.opOutputTimePower:
case DAL.opOutputTimeSpeed: {
// step speed // step speed
const port = buf.data[1]; const port = buf.data[1];
const speed = buf.data[2] << 24 >> 24; // signed byte const speed = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2); // signed byte
// note that b[3] is padding // note that b[3] is padding
const step1 = buf.data[4]; const step1 = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int32LE, 4);
const step2 = buf.data[5]; // angle const step2 = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int32LE, 8);
const step3 = buf.data[6]; const step3 = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int32LE, 12);
const brake = buf.data[7]; const brake = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 16);
//console.log(buf); //console.log(buf);
const motors = ev3board().getMotor(port); const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.stepSpeed(speed, step2, brake === 1)); motors.forEach(motor => motor.setSpeedCmd(cmd, [speed, step1, step2, step3, brake]));
return 2; return 2;
} }
case DAL.opOutputStop: { case DAL.opOutputStop: {
// stop // stop
const port = buf.data[1]; const port = buf.data[1];
const brake = buf.data[2]; const brake = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2);
const motors = ev3board().getMotor(port); const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.stop()); motors.forEach(motor => motor.stop());
return 2; return 2;
@ -59,9 +67,9 @@ namespace pxsim {
case DAL.opOutputSpeed: { case DAL.opOutputSpeed: {
// setSpeed // setSpeed
const port = buf.data[1]; const port = buf.data[1];
const speed = buf.data[2] << 24 >> 24; // signed byte const speed = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2);
const motors = ev3board().getMotor(port); const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.setSpeed(speed)); motors.forEach(motor => motor.setSpeedCmd(cmd, [speed]));
return 2; return 2;
} }
case DAL.opOutputStart: { case DAL.opOutputStart: {
@ -74,7 +82,7 @@ namespace pxsim {
case DAL.opOutputPolarity: { case DAL.opOutputPolarity: {
// reverse // reverse
const port = buf.data[1]; const port = buf.data[1];
const polarity = buf.data[2]; const polarity = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 2);
const motors = ev3board().getMotor(port); const motors = ev3board().getMotor(port);
motors.forEach(motor => motor.setPolarity(polarity)); motors.forEach(motor => motor.setPolarity(polarity));
return 2; return 2;
@ -86,6 +94,9 @@ namespace pxsim {
motors.forEach(motor => motor.setLarge(large)); motors.forEach(motor => motor.setLarge(large));
return 2; return 2;
} }
default:
console.warn('unknown cmd: ' + cmd);
break;
} }
console.log("pwm write"); console.log("pwm write");

View File

@ -88,7 +88,7 @@ namespace pxsim {
const inputNodes = ev3board().getInputNodes(); const inputNodes = ev3board().getInputNodes();
for (let port = 0; port < DAL.NUM_INPUTS; port++) { for (let port = 0; port < DAL.NUM_INPUTS; port++) {
const node = inputNodes[port]; const node = inputNodes[port];
if (node) { if (node && node.isUart()) {
// Actual // Actual
const index = 0; //UartOff.Actual + port * 2; const index = 0; //UartOff.Actual + port * 2;
util.map16Bit(data, UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index, Math.floor(node.getValue())) util.map16Bit(data, UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index, Math.floor(node.getValue()))

View File

@ -1,69 +1,87 @@
<svg id="e13b39e7-895d-4931-9be9-7aecaf709784" data-name="46d2506d-be16-4175-90b0-aabf357ea333" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 79.56 153.61"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 82 156">
<defs> <defs>
<clipPath id="7dd75c25-af24-4f64-9ea1-f270fbd17872"> <clipPath id="clip-path" transform="translate(0.98 1.9)">
<path d="M12.82.54a17.07,17.07,0,0,1,20.77,12.3,1.53,1.53,0,0,1,1.6-.24l.21.19,10.41,10.1c.31.3.47.3.47,1.14V35.81h6.79a4,4,0,0,1,4,4V65.63a4,4,0,0,1-4,4H46.15v11.8l13.68-.1h.61s7.76,9.81,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78H69.17v7.57A4,4,0,0,1,67,151.75V153h0a.63.63,0,0,1-.61.61H40.08a.6.6,0,0,1-.64-.56V152a4,4,0,0,1-2.89-3.85v-7.57H30.07a5.78,5.78,0,0,1-5.78-5.78v-8.18h-6.8a4,4,0,0,1-4-4V96.84a4,4,0,0,1,4-4h6.8V92l.75-.78v-10L14.13,70.71c-.25-.27-.39-.25-.39-.67V34.27l.37-.39A17.06,17.06,0,0,1,12.82.54Z" style="fill: none"/> <path d="M79,17.05A17.07,17.07,0,0,1,64.92,33.86l.36.39V70c0,.42-.14.4-.39.68L54,81.22v10l.75.78v.79h6.79a4,4,0,0,1,4,4v25.82a4,4,0,0,1-4,4H54.75v8.18A5.79,5.79,0,0,1,49,140.61h-6.5v7.57a4,4,0,0,1-2.9,3.84v1a.6.6,0,0,1-.6.6H12.69a.6.6,0,0,1-.6-.6h0v-1.29a4,4,0,0,1-2.17-3.55v-7.57H6.3a5.78,5.78,0,0,1-5.78-5.79h0V105.18C10.89,91.12,18.65,81.32,18.65,81.32h.59l13.68.1,0-11.8H26a4,4,0,0,1-4-4V39.79a4,4,0,0,1,4-4h6.78l0-11.77c0-.84.15-.84.46-1.14l10.41-10.1.22-.19a1.53,1.53,0,0,1,1.59.23A17.07,17.07,0,0,1,79,17.05Z" style="fill: none"/>
</clipPath> </clipPath>
<clipPath id="9d9a0722-eca6-4c98-bf03-49097e654f0e"> <clipPath id="clip-path-2" transform="translate(0.98 1.9)">
<path d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78V92l9.26-9.58a2.29,2.29,0,0,1,2.38-1c4.4,0,23.86-.15,23.86-.15h.65s7.76,9.8,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/> <path d="M49,140.61H6.3a5.78,5.78,0,0,1-5.78-5.79h0V105.18C10.89,91.12,18.65,81.32,18.65,81.32h.59s19.46.14,23.87.14a2.27,2.27,0,0,1,2.37,1L54.75,92v42.79A5.79,5.79,0,0,1,49,140.61Z" style="fill: none"/>
</clipPath> </clipPath>
<clipPath id="0f29df77-bfe3-4749-8432-7a5b3681f927"> <clipPath id="clip-path-3" transform="translate(0.98 1.9)">
<path d="M35.85,135.26a5.78,5.78,0,0,1-5.78-5.78h0V92.6h0a5.78,5.78,0,0,1,5.77-5.79H57.17S64.08,96,72.73,107.22v22.25h0A5.78,5.78,0,0,1,67,135.26H35.85Z" style="fill: none"/> <path d="M43.18,135.24H12.09a5.78,5.78,0,0,1-5.79-5.78h0V107.21C15,95.94,21.86,86.8,21.86,86.8H43.18A5.78,5.78,0,0,1,49,92.58h0v36.88a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
</clipPath> </clipPath>
</defs> </defs>
<title>Large Motor</title> <title>Large Motor</title>
<g style="clip-path: url(#7dd75c25-af24-4f64-9ea1-f270fbd17872)"> <g style="isolation: isolate">
<g id="e13b39e7-895d-4931-9be9-7aecaf709784">
<g style="clip-path: url(#clip-path)">
<g id="Large_Motor" data-name="Large Motor">
<path id="LM_back2" data-name="LM back2" d="M39,153.62H12.69a.6.6,0,0,1-.6-.6h0v-5.3a.6.6,0,0,1,.6-.6H39a.6.6,0,0,1,.6.6V153A.6.6,0,0,1,39,153.62Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<g> <g>
<path id="1614620b-40ec-4523-b90a-428aad6bd045" data-name="eadcf40d-5b1f-4f82-8d01-d628e9e4bcbb" d="M40.49,64.16V41.26A5.48,5.48,0,0,1,46,35.8h5.62A5.48,5.48,0,0,1,57,41.26v22.9h0a5.45,5.45,0,0,1-5.46,5.46H46A5.45,5.45,0,0,1,40.49,64.16Z" style="fill: #a8a9a8"/> <image width="36" height="20" transform="translate(9 136)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAAAVCAYAAADB5CeuAAAACXBIWXMAAAsSAAALEgHS3X78AAAAp0lEQVRIS+3WsW3DMBBG4Y+GSmcGp/cAHsuzeIasFPdWVpD6c0FKcBWwOxV8wIEgSIAPvOL+EhFKKcUBiIiAgjO+25rJildErJMqdMdVlcwg8MQDv5P6Q1fc5ErRujW1TfmoLPa3T//dymJI9TKkehlSvQypXoZUL5vUNhAz2R1Oao75w9IOMmpRHVZqSpjxo3KRw+YwQ2lx+EsVykqfK+aIWGhSR+MNDy9ID5XUCOsAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<circle id="1a43435f-56ec-4b4e-a3ae-b40d13b2f218" data-name="93612c19-30fe-4c1d-bb05-67002522431d" cx="51.72" cy="64.32" r="3.79" style="fill: #fff"/> <path id="LM_back1-2" data-name="LM back1-2" d="M41.86,152.17H10.53a.6.6,0,0,1-.6-.6v-14.7a.6.6,0,0,1,.6-.6H41.86a.6.6,0,0,1,.6.6h0v14.7A.6.6,0,0,1,41.86,152.17Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<circle id="43fd443a-13b5-48ef-af02-32d5de3e95b1" data-name="aee14a95-6af8-4dce-8543-2eda3545de29" cx="51.72" cy="41.11" r="3.79" style="fill: #fff"/>
<path id="7bfb4e09-fb97-433a-8104-a0426c319fe6" data-name="1d2e9494-7cc7-48f0-9562-12d1d83b7bb0" d="M39.44,153v-5.29a.61.61,0,0,1,.61-.61H66.34a.61.61,0,0,1,.61.61h0V153h0a.63.63,0,0,1-.61.61H40.08a.61.61,0,0,1-.64-.58Z" style="fill: #a8a9a8"/>
<path id="ded8d34f-3eb8-4d18-bbd7-80e03d734fef" data-name="ccd9d8b0-00ff-4f0b-bfdc-94153d199419" d="M36.58,151.58V136.89a.61.61,0,0,1,.61-.61H68.51a.61.61,0,0,1,.61.61h0v14.69a.61.61,0,0,1-.61.61H37.19a.61.61,0,0,1-.61-.61Z" style="fill: #a8a9a8"/>
<path id="a30c6f9d-adb5-4251-ad04-1bd8bfaab7af" data-name="e8b462c5-81f0-4111-9486-bb5fc1221c77" d="M55.44,59.6V57.8c0-.87-.81-.46-.81-.46l-1.19.59c-.38.18-.33-.34-.33-.34V55c0-.72.82-.77.82-.77h1.25s.26-.2.26-1.38-.29-1.32-.29-1.32H53.9a.68.68,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1-.05-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H48.56s-.3.18-.3,1.32.3,1.38.3,1.38h1.38a.73.73,0,0,1,.73.77v2.62c0,.52-.36.34-.36.34l-1-.59c-.68-.38-1.23,0-1.23.46v1.8s0,1,1.23.1a5.08,5.08,0,0,1,3-.7,4.18,4.18,0,0,1,2.35.7C55.37,60.14,55.44,59.6,55.44,59.6Z" style="fill: #fff"/>
<path id="c7805530-90df-4e25-868f-c9475cacc294" data-name="51a46c0a-a8a3-4420-b297-1d82512a0b32" d="M47.79,46.14c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.84,5.72,5.72,0,0,0,2.76-.84.85.85,0,0,1,.31-.09.71.71,0,0,1,.76.65V47.9s-.24,1-1.07.6a5,5,0,0,0-2.76-.77A6.46,6.46,0,0,0,49,48.5a.68.68,0,0,1-.24.08.83.83,0,0,1-1-.61s0,0,0-.07S47.76,46.94,47.79,46.14Z" style="fill: #fff"/>
<path id="f8fcbff1-7e8c-4c85-8f0e-222f81e36654" data-name="be4fbc2c-74e0-495a-bfad-cf557a83a287" d="M13.75,70V34.27L33.21,13.56c0-.84,1.4-1.36,2-1l.21.19,10.42,10.1c.31.3.46.3.46,1.14l-.19,59-18.57.67-13.4-13C13.89,70.44,13.75,70.46,13.75,70Z" style="fill: #a8a9a8"/>
<path id="1dc809f3-4ab0-4e83-b8a0-ab178c9c843d" data-name="4d02192d-b81d-48fe-8732-1ddf5bded46b" d="M35.44,82.8l10.67-.57v-8l-4.43-4.7H30.05a1.6,1.6,0,0,0-1.16.4L25.34,73.6c-.28.27-.3,1.12-.3,1.12V92Z" style="fill: #a8a9a8"/>
<g id="e0794b99-de5a-4337-b43b-7cdb158e4272" data-name="233cb9b7-9706-41a9-a0a4-7b51b61b2ff5">
<path id="c86708aa-fcc1-4e15-8d85-6e5415398b0c" data-name="6ed465b7-465a-4389-8ebc-d8f92a4226dd" d="M13.49,121.2V98.29A5.46,5.46,0,0,1,19,92.84h5.62A5.45,5.45,0,0,1,30,98.3v22.9h0a5.48,5.48,0,0,1-5.46,5.46H19A5.48,5.48,0,0,1,13.49,121.2Z" style="fill: #a8a9a8"/>
<circle id="0355a228-ed20-4633-ba10-c36cf551e228" data-name="955ad5d6-af09-42ad-8d56-9ff62c40912d" cx="18.35" cy="121.35" r="3.79" style="fill: #fff"/>
<circle id="73922eab-afce-48dd-9bae-80da92a8b392" data-name="75a0ff09-d40c-46e3-aaf0-c5878f2efdac" cx="18.35" cy="98.14" r="3.79" style="fill: #fff"/>
<path id="e9f7b6a6-dcdd-4d55-a7bb-ad3951bb1e39" data-name="eeb5a6b6-ef4a-4f05-95cd-8b1c3eb419c4" d="M22.07,116.64v-1.8c0-.86-.81-.46-.81-.46L20,115c-.38.18-.33-.34-.33-.34V112c0-.72.82-.76.82-.76h1.25s.32-.26.29-1.39-.29-1.32-.29-1.32H20.53a.67.67,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1,0-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H15.19s-.3.18-.3,1.32.3,1.39.3,1.39h1.38a.71.71,0,0,1,.73.69v2.69c0,.52-.36.34-.36.34l-1-.58c-.68-.39-1.23,0-1.23.46v1.8s0,1,1.23.1a5.09,5.09,0,0,1,3-.71,4.16,4.16,0,0,1,2.35.71C22,117.17,22.07,116.64,22.07,116.64Z" style="fill: #fff"/>
<path id="82138da6-9b2a-4b9a-952e-568841e5ed52" data-name="80481c02-bb01-43aa-bd64-15ab30fbbb5e" d="M14.44,103.18c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.83,5.78,5.78,0,0,0,2.77-.83.7.7,0,0,1,1,.25.67.67,0,0,1,.1.31v1.76s-.24,1-1.07.59a5,5,0,0,0-2.77-.77,6.59,6.59,0,0,0-2.85.77.68.68,0,0,1-.24.08.83.83,0,0,1-1-.63v0S14.44,104,14.44,103.18Z" style="fill: #fff"/>
</g> </g>
<path id="aa62b88a-4cd5-4c76-acaf-e85a7fd45341" data-name="6b63d025-68d6-47eb-ba62-60017f4a1dd4" d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78h0V92l9.26-9.57a2.29,2.29,0,0,1,2.38-1c4.4,0,23.87-.14,23.87-.14h.64s7.76,9.8,18.13,23.86v29.64h0a5.79,5.79,0,0,1-5.79,5.79Z" style="fill: #a8a9a8"/> <g id="LM_rightside" data-name="LM rightside">
<g> <path id="LM_rightside5" data-name="LM rightside5" d="M33.08,69.61H27.47A5.45,5.45,0,0,1,22,64.15h0V41.25a5.45,5.45,0,0,1,5.46-5.46h5.61a5.46,5.46,0,0,1,5.46,5.46v22.9A5.45,5.45,0,0,1,33.08,69.61Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<g id="1172473e-5b0c-4dd6-85c5-28f5593b9312" data-name="a0498222-7e69-48db-90b7-05f2ce124a03"> <circle id="LM_rightside4" data-name="LM rightside4" cx="28.3" cy="66.21" r="3.79" style="fill: #fff"/>
<g style="clip-path: url(#9d9a0722-eca6-4c98-bf03-49097e654f0e)"> <circle id="LM_rightside3" data-name="LM rightside3" cx="28.3" cy="43" r="3.79" style="fill: #fff"/>
<g id="da9d77a3-c9b0-4118-a8e3-c65ec5cbe7d4" data-name="8270fb93-0862-4480-a5b8-675cc77ac153"> <path id="LM_rightside2" data-name="LM rightside2" d="M24.4,59.69A4.16,4.16,0,0,1,26.74,59a5.23,5.23,0,0,1,3,.71c1.25.93,1.23-.1,1.23-.1v-1.8c0-.45-.56-.85-1.23-.46l-1,.58s-.36.19-.36-.33V55s0-.79.73-.77,1.38,0,1.38,0,.29-.25.29-1.39-.29-1.32-.29-1.32H29.1s-.73,0-.73-.65v-1.3s-.23-.36-1.17-.3a3.56,3.56,0,0,0-1.4.3v1.3a.66.66,0,0,1-.66.65c-.63,0-1.26,0-1.26,0s-.25.19-.29,1.32.29,1.39.29,1.39h1.26s.8.05.82.77,0,2.62,0,2.62,0,.51-.34.33l-1.21-.58s-.83-.41-.82.46,0,1.8,0,1.8S23.67,60.12,24.4,59.69Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
<path id="77253f44-139e-4b90-82df-465a787cab9c" data-name="bb0a4ec3-45a5-4c91-b064-db5494e447e6" d="M78.56,142.76l1-7.69V103.85L66.49,87.72v14.86L42.7,133.66,35.55,141Z" style="fill: #f2f2f2"/> <path id="LM_rightside1" data-name="LM rightside1" d="M31.25,47.89a.84.84,0,0,1-1,.68.85.85,0,0,1-.24-.09,6.63,6.63,0,0,0-2.85-.77,5.11,5.11,0,0,0-2.77.77c-.83.4-1.07-.59-1.07-.59V46.13a.72.72,0,0,1,.76-.66.67.67,0,0,1,.31.1,5.79,5.79,0,0,0,2.77.84,7.12,7.12,0,0,0,2.85-.84s1.18-.24,1.2.56S31.25,47.89,31.25,47.89Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
</g>
</g>
</g>
<path id="9d05c10c-72eb-4f9f-8517-e403ec636357" data-name="74e07bdd-431b-40c1-b0f3-71128f2a0c08" d="M35.85,135.56a5.78,5.78,0,0,1-5.78-5.78h0V92.9h0a5.78,5.78,0,0,1,5.77-5.79H57.17s6.91,9.15,15.56,20.41v22.25h0A5.78,5.78,0,0,1,67,135.56H35.85Z" style="fill: #a8a9a8"/>
<g id="6df8eb1f-3187-427f-8d99-bc7a37e6cc25" data-name="9bbfb3ec-86c2-4d27-8275-76f2f9737a7f">
<g id="e4d7143c-1fb6-45a4-a205-1c920b8a823c" data-name="7e017c33-f09b-4d39-803f-1bedf1ebf566">
<g id="3a4e493d-cd17-48c4-97b6-da7ee3c4898e" data-name="69e3df75-72a6-4499-baab-f65ec194e193">
<g style="clip-path: url(#0f29df77-bfe3-4749-8432-7a5b3681f927)">
<g id="7cada08f-1e90-4ef2-8ae4-3f2adfd3e953" data-name="b7007e32-15c9-40b3-a885-a7231fd104d1">
<path id="02e64b51-bd56-4079-9736-8a269cb37029" data-name="c599a4f4-ae5d-411c-902d-dbcde04a2d6e" d="M60.44,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112Zm-3.61,0a1.09,1.09,0,1,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112ZM46,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6A1.08,1.08,0,0,1,47,140.65h0a1.07,1.07,0,0,1-1-1.11V112Z" style="fill: #6a6a6a"/>
</g>
</g>
</g>
<circle id="a5a29926-0401-43af-b098-0c7439485e7c" data-name="bcdc8e69-90f7-4365-8f7a-7c1567704161" cx="29.69" cy="135.22" r="2.24" style="fill: #9a9a9a"/>
<circle id="313e9fdc-7bbb-4d49-9d19-2415450fb691" data-name="b7785d8e-a2e4-41a7-9c34-4d9f6aebd906" cx="58.36" cy="84.71" r="2.24" style="fill: #9a9a9a"/>
<g id="1eb2ae58-2419-47d4-86bf-4f26a7f0cf61" data-name="KNOB">
<g id="26377a78-5df7-4bea-8daa-669ea612118c" data-name="5301e639-3e28-489d-96ec-91bda6d459b7">
<circle id="13e05316-9dcc-4be0-9e0e-4b1df48fad92" data-name="f1bc8b30-bdb2-4084-8c02-e322d1c0b9bf" cx="17.06" cy="17.06" r="17.06" style="fill: #b72b1c"/>
</g> </g>
<g> <g>
<circle id="58277aee-b73f-4f42-94ef-3b959dc26807" data-name="ce4b2c57-9b3b-4aed-902e-31d9f366dc61" cx="20.12" cy="28.12" r="3.79" style="fill: #3c3c3c"/> <image width="36" height="76" transform="translate(32 12)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAABNCAYAAAAhOa00AAAACXBIWXMAAAsSAAALEgHS3X78AAACAElEQVRoQ+3avVHDMBiA4VdcypgREmo4RggLpKKHAZiIAWgoKZggrEAGCBsQpxeFpNgJ/vkkK5YLvXe6g2Cb53zE9oVPaa3xSSmlALTvjh4pn2MrpQpgab/dAYdL4MQoC3oAnuxLH8AW2Gmty9YdAxKhaqAXYAUozJnaAm/AJiZs1rfBGegBKOyP7oAFMLfbRYN1ojpAYM7WtX3dbR8F1orqAdVz27n9BsMaUR4gV1yY1vpkYX7BGvgE9oD2WL/AO3CPfROFrKs6MOAMnVcAt3b57lsV6QzV194eYw0UfWelacUGRYFdAjQYNsPcy54xV+rwv4P/Bb8jZ5gr8oK4IFcQzF2nVOdWw/KG9d77IuUFGwsFHrAxUSCEjY0CASwFCnpgqVDQAUuJghZYahQY2Ao4YJ77v08eXRJWUHvenwoKaneVKaGOZZS0jJKWUdIySlpGScsoaRklLaOkZZS0jJKWUdIySlpGScsoaRklLaOkTQml3RdTQZXAD+bD2EmgSuALMwmyg/SoEtgAr9RGU1KiGkGQDtUKgjSoThCMj+oFwbgoEQjGQ4lBMA7KCwSXR3mDoPonpBsFccWYUwgCgUEdMAN/YDBzzKjJvG0nQe7W4Q2CCnFDhVgCj1TznCHtGDDVqLTWxylXW4wzdWDA/GfjnOcZMijddGBhouHTsfsDst/cEY24RzwAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<circle id="980a54d2-804e-408d-8655-debf2e5856d0" data-name="6a44a65a-f04b-4564-81a2-4eefa438c5f1" cx="28.27" cy="14" r="3.79" style="fill: #3c3c3c"/> <path id="LM_level4-2" data-name="LM level4-2" d="M64.91,70.7,51.5,83.63,32.93,83,32.76,24c0-.84.16-.84.46-1.13l10.42-10.1.21-.19c.59-.4,2,.11,2,.95L65.29,34.25V70C65.3,70.44,65.16,70.43,64.91,70.7Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<circle id="9b2e3cd0-e4bd-42ce-b558-4f4bc46eaf23" data-name="d5fea8d1-47c1-448e-adb6-8519e2516216" cx="14.15" cy="5.85" r="3.79" style="fill: #3c3c3c"/> </g>
<circle id="06781f30-70ec-4914-81c3-4083325e7c18" data-name="1faf9727-3903-4be3-a3d3-4ab2d5d92b1f" cx="6" cy="19.97" r="3.79" style="fill: #3c3c3c"/> <g>
<path id="f1de636f-1fd2-4419-ae5c-d6a853c5834d" data-name="9e52c672-4ec8-4d92-9380-e44b4f69f848" d="M13.56,16.89a2.91,2.91,0,0,0,.7,2.26,12,12,0,0,1,1.2-.39c.69-.18.95.59.95.59l.33,1.21s.33.24,1.41-.08,1.2-.62,1.2-.62-.17-.6-.32-1.22a.66.66,0,0,1,.45-.8l1.26-.34a3.63,3.63,0,0,0-.07-1.43c-.19-.93-.6-1.05-.6-1.05l-1.25.34c-.65.17-.82-.54-.82-.54l-.36-1.33s-.25-.24-1.35,0-1.26.64-1.26.64.14.61.35,1.34a.7.7,0,0,1-.48.88l-.07,0Z" style="fill: #242424"/> <image width="25" height="27" transform="translate(32 69)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAYAAAB/E6/TAAAACXBIWXMAAAsSAAALEgHS3X78AAABYUlEQVRIS+2WvVXDMBRG7/NxGVf0CRVFchghWSAVA2QAxmEGGgZgguzgHlPTELv/KCSD/BMs2wkV9xwf2/LPlZ70JJkk2piZdQojUd8PAWuXm1kGrIBF3wcDVEAhqWw/aIi8ZAcccLKxFMAzcGzL0voikDwCWyBjPGt8JMysKfMtMuAeeAE+Ac04TsArsAcySUj6blGGq82aaS0JyXARqYDCzHJJSnzItrh+ucW1bi4ZsCQYUAmu0w9M75dzNCqc4KxLLivpkPjzJcL1Kwl/xL9oMnXC1lkdw6SBk+IyOPf3Qz9Z8DOzD73bIAXegCfiloUV8ABs/HV07qWSKjPLiSP3xwY3m+yIlKVwflXsofSVeseFHCJlKSPxlTqZ2TEoHpSNFtVIKsfIJotgnGyWCHplW3pG8GwRdGQVbqXu35zMJZAVONEdgayzr5uL33wugBvgQ1IFVxDVmJmF+Xk1UZsvIeCPQjWq5BoAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<path id="e8012624-d689-4ee7-a77a-99e9713ea199" data-name="3179af54-0c25-42bc-9804-f3575e0b1b0b" d="M17.44,24.25a.47.47,0,0,1-.56-.32l-.55-2.06h0a.45.45,0,0,1,.32-.55h0l1.63-.23,1.44-.6a.47.47,0,0,1,.56.32l.55,2.05h0a.45.45,0,0,1-.32.55h0L18.94,24Z" style="fill: #3c3c3c"/> <path id="LM_level3-2" data-name="LM level3-2" d="M54,92V74.7a2.19,2.19,0,0,0-.3-1.12c-.28-.27-3.52-3.62-3.52-3.62a1.55,1.55,0,0,0-1.16-.4c-.75,0-11.62,0-11.62,0L33,74.26v8l10.66.57Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<path id="31a64bab-6b92-41d0-afe9-392c1fae8ddb" data-name="841a583e-aa25-4a7e-8907-fbe64ce57066" d="M9.88,17.31a.46.46,0,0,1,.33-.56l2-.55h0a.47.47,0,0,1,.56.33L13,18.16l.6,1.45a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.57-1.53L9.84,17.3Z" style="fill: #3c3c3c"/> </g>
<path id="2b1c6b9e-6fda-40be-8bb8-318c30b7dca4" data-name="42515acc-688f-41c7-884c-80b8a90e09c0" d="M16.82,9.8a.47.47,0,0,1,.56.32l.55,2.05h0a.46.46,0,0,1-.33.55L16,13l-1.45.61a.45.45,0,0,1-.55-.32h0l-.53-2.1h0a.45.45,0,0,1,.31-.56h0l1.53-.57,1.55-.25Z" style="fill: #3c3c3c"/> <g id="LM_leftside" data-name="LM leftside">
<path id="be04cab5-eaac-4d03-a1ee-dbe70dd5bf90" data-name="8690082b-7091-4631-a199-b79823698dd6" d="M24.33,16.74a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.22-1.64-.6-1.44a.45.45,0,0,1,.31-.56h0l2-.55h0a.46.46,0,0,1,.56.33l.57,1.53.25,1.55Z" style="fill: #3c3c3c"/> <path id="LM_leftside5" data-name="LM leftside5" d="M60.08,126.64H54.47A5.45,5.45,0,0,1,49,121.18h0V98.28a5.46,5.46,0,0,1,5.46-5.46h5.61a5.47,5.47,0,0,1,5.46,5.46v22.9A5.45,5.45,0,0,1,60.08,126.64Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<circle id="LM_leftside4" data-name="LM leftside4" cx="61.67" cy="123.24" r="3.79" style="fill: #fff"/>
<circle id="LM_leftside3" data-name="LM leftside3" cx="61.67" cy="100.03" r="3.79" style="fill: #fff"/>
<path id="LM_leftside2" data-name="LM leftside2" d="M57.77,116.72a4.15,4.15,0,0,1,2.34-.7,5.14,5.14,0,0,1,3,.7c1.25.93,1.23-.1,1.23-.1v-1.8c0-.45-.56-.84-1.23-.46l-1,.58s-.36.19-.36-.33V112s0-.79.73-.77,1.38,0,1.38,0,.29-.25.29-1.38-.29-1.33-.29-1.33H62.47s-.73,0-.73-.64v-1.3s-.23-.36-1.17-.31a3.57,3.57,0,0,0-1.4.31v1.3a.66.66,0,0,1-.66.64H57.25s-.25.2-.29,1.33.29,1.38.29,1.38h1.26s.8,0,.82.77,0,2.62,0,2.62,0,.51-.34.33l-1.21-.58s-.83-.4-.82.46,0,1.8,0,1.8S57,117.16,57.77,116.72Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
<path id="LM_leftside1" data-name="LM leftside1" d="M64.62,104.92a.83.83,0,0,1-1,.68.68.68,0,0,1-.24-.08,6.46,6.46,0,0,0-2.85-.77,5,5,0,0,0-2.77.77c-.83.4-1.07-.6-1.07-.6v-1.76a.71.71,0,0,1,.76-.65.8.8,0,0,1,.31.09,5.79,5.79,0,0,0,2.77.84,7,7,0,0,0,2.85-.84s1.18-.24,1.2.56S64.62,104.92,64.62,104.92Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
</g>
<g>
<image width="58" height="64" transform="translate(0 81)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAABBCAYAAABvnNwUAAAACXBIWXMAAAsSAAALEgHS3X78AAACFElEQVRoQ+2bQY7TMBSGvxcqsaFbJDbDrEEcYeYCcwYOwIlYsWLDjg0nGG6A1ANkbgCNhGb1WNgBpxPbaUjT+smf5E3lxPlq/25S5YmqshQiIrk+S6EzLlxmHDOKiGyB18CLXN8F6IAW6I6RXkTWi94C73HCp6YFvgI7oFXVfaY/sIBsIPoBuAG26SMWoZ/ZHfAZuJ8ivMl1SHEgess6ouDGeQtc4WMjInlhVZ3VcAPeAd+AX4Ceqf0EvgDv8Cs11hpm4Hfda1xG11q6MbbAG9+S1zFLliMGWIHBF++jNcrRmfUnu8Gd/Bo32Lnp9w4gnt+jZM+4IU0hKzxZ9sJyGiMpPFmWy8ppiqjwJNkLzWmK/no7oBWRnapqdje+8Jym2BLcdEDmp6eQnKYYrMDczJaS00lEZQvMaZZR2YJzmuSJrIGcRhmbWVM5DRnIWsxpyF9ZqzkNacB2TkP6mTWb05DGek5DGtxfn6aXb0+Du1G+wrgo/Mus2aUbknsQMEWVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUovq8le5TLwanBvbj4A2VKRwtjjvLr+g2fAb1wFxUvgFfB89NCy2APfgU/AD1V9BNio6l5E7oOOpb9u0It+5KC4aQNwINyxTonZqWiJVHENytNk3eLBU9ERqc97UovnXwArGj2U8vx34WFJ/AG0vvY6LSeZMAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<path id="LM_level2_grey-2" data-name="LM level2 grey-2" d="M49,140.61H6.31a5.78,5.78,0,0,1-5.78-5.78h0V105.19C10.89,91.13,18.65,81.32,18.65,81.32h.6s19.46.15,23.86.15a2.29,2.29,0,0,1,2.38,1L54.75,92v42.8A5.78,5.78,0,0,1,49,140.61Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
</g>
<g id="LM_total" data-name="LM total">
<g id="LM_whitepart" data-name="LM whitepart">
<g style="clip-path: url(#clip-path-2)">
<g id="LM_whitepart_combined" data-name="LM whitepart combined">
<path id="LM_whitepart_top" data-name="LM whitepart top" d="M43.48,141l-7.15-7.37L12.54,102.56V87.7L-.52,103.84v31.22l1,7.69Z" transform="translate(0.98 1.9)" style="fill: #f1f1f1"/>
</g>
</g>
</g>
<g>
<image width="47" height="52" transform="translate(5 87)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAA1CAYAAAAHz2g0AAAACXBIWXMAAAsSAAALEgHS3X78AAABnElEQVRoQ+2azXHCMBBG3zIccQuBM5MWoIHUkAJSUQrIJQWkAlIJ6SDYd+UgGWTjHxQHr5TRm9HFIzz75G8Z8KwYY5iKiMjYnr/AdBQrUwVEpADWwGps70Qq4GiMKf2LkwRc8XvgGStxT47AG3DwJZb9+4fxin8BdkAx/InJbHFPWUQuEsaY4IUt9gn4AE6AmWl9A+/AIy49CwJxDbvBxmaOk/cpgAe8fgsWwN5k69acxdc0vvGCBFzud9jT39C6mQY3C7Sado/O6V9xk4By7ge5SQD93PcyKhBj7n0GBWLNvU+vQArFQ49AzE3bpu8JRNu0ba4EYm/aNg2BVHLvcxZIKfc+/hNIJvc+C0gv9z4LF501iUWnpo7QCvtHIaniodkDycTGZ/THXOxkAW2ygDZZQJssoE0W0CYLaJMFtMkC2mQBbbKANv9K4PdDE/PSqLMWqIAvoDEJEiElts7qfEV59iFknbD1PQFFPbexBDDGlCJy4EJs70hL4BN4pW/cpiVRcf/5nxA6Z4WgY+BpxgmsEDqntWDixFYM/ACNRtJx4q2GRAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<path id="LM_top_grey-2" data-name="LM top grey-2" d="M43.18,135.54H12.09a5.78,5.78,0,0,1-5.79-5.78h0V107.51C15,96.24,21.86,87.1,21.86,87.1H43.18A5.78,5.78,0,0,1,49,92.88h0v36.88a5.78,5.78,0,0,1-5.78,5.78Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
</g>
<g id="LM_top" data-name="LM top">
<g style="clip-path: url(#clip-path-3)">
<g id="LM_top_total" data-name="LM top total">
<path id="LM_top_lines" data-name="LM top lines" d="M18.6,112.05v27.47a1.08,1.08,0,0,1-1.12,1,1.06,1.06,0,0,1-1.05-1V112.05A1.09,1.09,0,0,1,18.6,112Zm3.61,0v27.47a1.09,1.09,0,1,1-2.17,0V112.05a1.09,1.09,0,1,1,2.17,0Zm3.62,0v27.47a1.09,1.09,0,1,1-2.17,0V112.05a1.09,1.09,0,1,1,2.17,0Zm3.61,0v27.47a1.09,1.09,0,0,1-2.17.07V112.05a1.09,1.09,0,0,1,2.17-.07Zm3.62,0v27.47A1.1,1.1,0,0,1,32,140.64a1.08,1.08,0,0,1-1.11-1V112.05a1.09,1.09,0,0,1,2.17-.07Z" transform="translate(0.98 1.9)" style="fill: #6a6a6a"/>
</g>
</g>
</g>
<circle id="LM_detail_2" data-name="LM detail 2" cx="50.32" cy="137.11" r="2.24" style="fill: #9a9a9a"/>
<circle id="LM_detail_1" data-name="LM detail 1" cx="21.66" cy="86.59" r="2.24" style="fill: #9a9a9a"/>
<g id="hole">
<g>
<image width="38" height="38" transform="translate(44)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAAnCAYAAACMo1E1AAAACXBIWXMAAAsSAAALEgHS3X78AAACRklEQVRYR9WYPXLbMBBGHzgpxRwhTJ3ER0gukMauUvl0btIlhU9gdSkzQ9dWbmBTtTYFdiUA/BGh0ILyzWBAUiTx+C0JYdeJCDlyzrlgdwU02pu2wEb7vSR3IMDNvUahUpgGuNHetAF+aG/aA+dAzoJzztV4gI/EMHOdM+AW2IhIxwxNwqlbNfAZuMXDpTBhmE3pTQ24Be6ANdAdc/HN2A+JW7d4wJphmFTpOTX+Pu/wD7YCWufcpIuDzinYF2K36t6Jp6kjdvFhFFBEooaH+ArcA8/ADh+mJdtO732vY9Uph4iQgjngCviuFx8b5F/bs451hUYxbBWxauCDtqXCOKXp8UbC+cLxp16qvTAS3lLhTJuF9xNBeC2sK84bzlQ2bYXzJ5VOtA1+5n/PvHnsNdT7twmdswmyhEKDGltchF9rKcdMPYMMrjSYyRGwVJQPaaiIpSJek5V0MHrv4D9w7pK0Bf5oT5UeKCghWeJXyQEZvfQ8uljnTHuD7J0r7Zgp4gg/iNKAvQgaXOnQRh+DZWWVbtgPT5RzsJfvhs49apuV8C4sy8jiyF38Mj0AfAt8A37zOinhbLCh7KvjfOHd4d/xO2AtA4l1BKcfx/4CDuFdWh0+4/+l/aARvVqJiHTOuQfd3bJsOULwIGu8AS3wZFNHqtEq00QhB/LXfcIJlabRKpM62HKYnLccsiPrQxlwOlgIlVWjyy0eGlhazbTjcKRwSEZ1cxYcRLXgIeca4Fq3f7JAyRUy4EIlRWuYdo5cKNNJcOfSX2jmA7RYwAeRAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<circle id="LM_red-2" data-name="LM red-2" cx="62.96" cy="18.95" r="17.06" style="fill: #d42715"/>
</g>
<g id="LM_details_in_red" data-name="LM details in red">
<circle id="LM_detail_red_hole4" data-name="LM detail red hole4" cx="59.9" cy="30.01" r="3.79" style="fill: #393939"/>
<circle id="LM_detail_red_hole3" data-name="LM detail red hole3" cx="51.75" cy="15.89" r="3.79" style="fill: #393939"/>
<circle id="LM_detail_red_hole2" data-name="LM detail red hole2" cx="65.87" cy="7.74" r="3.79" style="fill: #393939"/>
<circle id="LM_detail_red_hole1" data-name="LM detail red hole1" cx="74.02" cy="21.86" r="3.79" style="fill: #393939"/>
<path id="LM_detail_hole" data-name="LM detail hole" d="M64.2,16.41a.72.72,0,0,1-.55-.91c.21-.72.36-1.33.36-1.33s-.17-.35-1.27-.64-1.35-.06-1.35-.06L61,14.8s-.16.72-.81.54L59,15s-.4.13-.6,1.06a3.44,3.44,0,0,0-.06,1.43l1.25.33a.68.68,0,0,1,.46.81c-.16.61-.33,1.21-.33,1.21s.12.3,1.2.62,1.42.09,1.42.09l.32-1.22s.26-.76,1-.59q.6.17,1.2.39a2.92,2.92,0,0,0,.7-2.25C64.91,16.65,64.2,16.41,64.2,16.41Z" transform="translate(0.98 1.9)" style="fill: #1f1f1f"/>
<path id="LM_detail_red4" data-name="LM detail red4" d="M61.64,24.23,60.09,24l-1.53-.57a.46.46,0,0,1-.33-.56h0l.55-2.05a.46.46,0,0,1,.56-.32l1.45.6,1.63.22a.46.46,0,0,1,.33.56h0l-.55,2.05a.44.44,0,0,1-.55.32Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
<path id="LM_detail_red3" data-name="LM detail red3" d="M69.15,17.3l-.26,1.55-.57,1.52a.45.45,0,0,1-.55.33h0l-2.06-.55a.46.46,0,0,1-.32-.56L66,18.15l.22-1.63a.45.45,0,0,1,.55-.33h0l2,.55a.46.46,0,0,1,.32.56Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
<path id="LM_detail_red2" data-name="LM detail red2" d="M62.21,9.79l1.55.25,1.53.57a.46.46,0,0,1,.33.55h0l-.55,2.05a.46.46,0,0,1-.56.32l-1.45-.6-1.63-.22a.47.47,0,0,1-.33-.56h0l.55-2.05a.44.44,0,0,1,.55-.32Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
<path id="LM_detail_red1" data-name="LM detail red1" d="M54.7,16.72,55,15.17l.57-1.52a.45.45,0,0,1,.55-.33h0l2.06.55a.46.46,0,0,1,.32.56l-.61,1.44-.22,1.63a.45.45,0,0,1-.55.33h0l-2-.55a.46.46,0,0,1-.32-.56Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
</g> </g>
</g> </g>
</g> </g>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,70 +1,88 @@
namespace pxsim { namespace pxsim {
export const LARGE_MOTOR_SVG = `<svg id="e13b39e7-895d-4931-9be9-7aecaf709784" data-name="46d2506d-be16-4175-90b0-aabf357ea333" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 79.56 153.61"> export const LARGE_MOTOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 82 156">
<defs> <defs>
<clipPath id="7dd75c25-af24-4f64-9ea1-f270fbd17872"> <clipPath id="clip-path" transform="translate(0.98 1.9)">
<path d="M12.82.54a17.07,17.07,0,0,1,20.77,12.3,1.53,1.53,0,0,1,1.6-.24l.21.19,10.41,10.1c.31.3.47.3.47,1.14V35.81h6.79a4,4,0,0,1,4,4V65.63a4,4,0,0,1-4,4H46.15v11.8l13.68-.1h.61s7.76,9.81,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78H69.17v7.57A4,4,0,0,1,67,151.75V153h0a.63.63,0,0,1-.61.61H40.08a.6.6,0,0,1-.64-.56V152a4,4,0,0,1-2.89-3.85v-7.57H30.07a5.78,5.78,0,0,1-5.78-5.78v-8.18h-6.8a4,4,0,0,1-4-4V96.84a4,4,0,0,1,4-4h6.8V92l.75-.78v-10L14.13,70.71c-.25-.27-.39-.25-.39-.67V34.27l.37-.39A17.06,17.06,0,0,1,12.82.54Z" style="fill: none"/> <path d="M79,17.05A17.07,17.07,0,0,1,64.92,33.86l.36.39V70c0,.42-.14.4-.39.68L54,81.22v10l.75.78v.79h6.79a4,4,0,0,1,4,4v25.82a4,4,0,0,1-4,4H54.75v8.18A5.79,5.79,0,0,1,49,140.61h-6.5v7.57a4,4,0,0,1-2.9,3.84v1a.6.6,0,0,1-.6.6H12.69a.6.6,0,0,1-.6-.6h0v-1.29a4,4,0,0,1-2.17-3.55v-7.57H6.3a5.78,5.78,0,0,1-5.78-5.79h0V105.18C10.89,91.12,18.65,81.32,18.65,81.32h.59l13.68.1,0-11.8H26a4,4,0,0,1-4-4V39.79a4,4,0,0,1,4-4h6.78l0-11.77c0-.84.15-.84.46-1.14l10.41-10.1.22-.19a1.53,1.53,0,0,1,1.59.23A17.07,17.07,0,0,1,79,17.05Z" style="fill: none"/>
</clipPath> </clipPath>
<clipPath id="9d9a0722-eca6-4c98-bf03-49097e654f0e"> <clipPath id="clip-path-2" transform="translate(0.98 1.9)">
<path d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78V92l9.26-9.58a2.29,2.29,0,0,1,2.38-1c4.4,0,23.86-.15,23.86-.15h.65s7.76,9.8,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/> <path d="M49,140.61H6.3a5.78,5.78,0,0,1-5.78-5.79h0V105.18C10.89,91.12,18.65,81.32,18.65,81.32h.59s19.46.14,23.87.14a2.27,2.27,0,0,1,2.37,1L54.75,92v42.79A5.79,5.79,0,0,1,49,140.61Z" style="fill: none"/>
</clipPath> </clipPath>
<clipPath id="0f29df77-bfe3-4749-8432-7a5b3681f927"> <clipPath id="clip-path-3" transform="translate(0.98 1.9)">
<path d="M35.85,135.26a5.78,5.78,0,0,1-5.78-5.78h0V92.6h0a5.78,5.78,0,0,1,5.77-5.79H57.17S64.08,96,72.73,107.22v22.25h0A5.78,5.78,0,0,1,67,135.26H35.85Z" style="fill: none"/> <path d="M43.18,135.24H12.09a5.78,5.78,0,0,1-5.79-5.78h0V107.21C15,95.94,21.86,86.8,21.86,86.8H43.18A5.78,5.78,0,0,1,49,92.58h0v36.88a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
</clipPath> </clipPath>
</defs> </defs>
<title>Large Motor</title> <title>Large Motor</title>
<g style="clip-path: url(#7dd75c25-af24-4f64-9ea1-f270fbd17872)"> <g style="isolation: isolate">
<g id="e13b39e7-895d-4931-9be9-7aecaf709784">
<g style="clip-path: url(#clip-path)">
<g id="Large_Motor" data-name="Large Motor">
<path id="LM_back2" data-name="LM back2" d="M39,153.62H12.69a.6.6,0,0,1-.6-.6h0v-5.3a.6.6,0,0,1,.6-.6H39a.6.6,0,0,1,.6.6V153A.6.6,0,0,1,39,153.62Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<g> <g>
<path id="1614620b-40ec-4523-b90a-428aad6bd045" data-name="eadcf40d-5b1f-4f82-8d01-d628e9e4bcbb" d="M40.49,64.16V41.26A5.48,5.48,0,0,1,46,35.8h5.62A5.48,5.48,0,0,1,57,41.26v22.9h0a5.45,5.45,0,0,1-5.46,5.46H46A5.45,5.45,0,0,1,40.49,64.16Z" style="fill: #a8a9a8"/> <image width="36" height="20" transform="translate(9 136)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAAAVCAYAAADB5CeuAAAACXBIWXMAAAsSAAALEgHS3X78AAAAp0lEQVRIS+3WsW3DMBBG4Y+GSmcGp/cAHsuzeIasFPdWVpD6c0FKcBWwOxV8wIEgSIAPvOL+EhFKKcUBiIiAgjO+25rJildErJMqdMdVlcwg8MQDv5P6Q1fc5ErRujW1TfmoLPa3T//dymJI9TKkehlSvQypXoZUL5vUNhAz2R1Oao75w9IOMmpRHVZqSpjxo3KRw+YwQ2lx+EsVykqfK+aIWGhSR+MNDy9ID5XUCOsAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<circle id="1a43435f-56ec-4b4e-a3ae-b40d13b2f218" data-name="93612c19-30fe-4c1d-bb05-67002522431d" cx="51.72" cy="64.32" r="3.79" style="fill: #fff"/> <path id="LM_back1-2" data-name="LM back1-2" d="M41.86,152.17H10.53a.6.6,0,0,1-.6-.6v-14.7a.6.6,0,0,1,.6-.6H41.86a.6.6,0,0,1,.6.6h0v14.7A.6.6,0,0,1,41.86,152.17Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<circle id="43fd443a-13b5-48ef-af02-32d5de3e95b1" data-name="aee14a95-6af8-4dce-8543-2eda3545de29" cx="51.72" cy="41.11" r="3.79" style="fill: #fff"/>
<path id="7bfb4e09-fb97-433a-8104-a0426c319fe6" data-name="1d2e9494-7cc7-48f0-9562-12d1d83b7bb0" d="M39.44,153v-5.29a.61.61,0,0,1,.61-.61H66.34a.61.61,0,0,1,.61.61h0V153h0a.63.63,0,0,1-.61.61H40.08a.61.61,0,0,1-.64-.58Z" style="fill: #a8a9a8"/>
<path id="ded8d34f-3eb8-4d18-bbd7-80e03d734fef" data-name="ccd9d8b0-00ff-4f0b-bfdc-94153d199419" d="M36.58,151.58V136.89a.61.61,0,0,1,.61-.61H68.51a.61.61,0,0,1,.61.61h0v14.69a.61.61,0,0,1-.61.61H37.19a.61.61,0,0,1-.61-.61Z" style="fill: #a8a9a8"/>
<path id="a30c6f9d-adb5-4251-ad04-1bd8bfaab7af" data-name="e8b462c5-81f0-4111-9486-bb5fc1221c77" d="M55.44,59.6V57.8c0-.87-.81-.46-.81-.46l-1.19.59c-.38.18-.33-.34-.33-.34V55c0-.72.82-.77.82-.77h1.25s.26-.2.26-1.38-.29-1.32-.29-1.32H53.9a.68.68,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1-.05-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H48.56s-.3.18-.3,1.32.3,1.38.3,1.38h1.38a.73.73,0,0,1,.73.77v2.62c0,.52-.36.34-.36.34l-1-.59c-.68-.38-1.23,0-1.23.46v1.8s0,1,1.23.1a5.08,5.08,0,0,1,3-.7,4.18,4.18,0,0,1,2.35.7C55.37,60.14,55.44,59.6,55.44,59.6Z" style="fill: #fff"/>
<path id="c7805530-90df-4e25-868f-c9475cacc294" data-name="51a46c0a-a8a3-4420-b297-1d82512a0b32" d="M47.79,46.14c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.84,5.72,5.72,0,0,0,2.76-.84.85.85,0,0,1,.31-.09.71.71,0,0,1,.76.65V47.9s-.24,1-1.07.6a5,5,0,0,0-2.76-.77A6.46,6.46,0,0,0,49,48.5a.68.68,0,0,1-.24.08.83.83,0,0,1-1-.61s0,0,0-.07S47.76,46.94,47.79,46.14Z" style="fill: #fff"/>
<path id="f8fcbff1-7e8c-4c85-8f0e-222f81e36654" data-name="be4fbc2c-74e0-495a-bfad-cf557a83a287" d="M13.75,70V34.27L33.21,13.56c0-.84,1.4-1.36,2-1l.21.19,10.42,10.1c.31.3.46.3.46,1.14l-.19,59-18.57.67-13.4-13C13.89,70.44,13.75,70.46,13.75,70Z" style="fill: #a8a9a8"/>
<path id="1dc809f3-4ab0-4e83-b8a0-ab178c9c843d" data-name="4d02192d-b81d-48fe-8732-1ddf5bded46b" d="M35.44,82.8l10.67-.57v-8l-4.43-4.7H30.05a1.6,1.6,0,0,0-1.16.4L25.34,73.6c-.28.27-.3,1.12-.3,1.12V92Z" style="fill: #a8a9a8"/>
<g id="e0794b99-de5a-4337-b43b-7cdb158e4272" data-name="233cb9b7-9706-41a9-a0a4-7b51b61b2ff5">
<path id="c86708aa-fcc1-4e15-8d85-6e5415398b0c" data-name="6ed465b7-465a-4389-8ebc-d8f92a4226dd" d="M13.49,121.2V98.29A5.46,5.46,0,0,1,19,92.84h5.62A5.45,5.45,0,0,1,30,98.3v22.9h0a5.48,5.48,0,0,1-5.46,5.46H19A5.48,5.48,0,0,1,13.49,121.2Z" style="fill: #a8a9a8"/>
<circle id="0355a228-ed20-4633-ba10-c36cf551e228" data-name="955ad5d6-af09-42ad-8d56-9ff62c40912d" cx="18.35" cy="121.35" r="3.79" style="fill: #fff"/>
<circle id="73922eab-afce-48dd-9bae-80da92a8b392" data-name="75a0ff09-d40c-46e3-aaf0-c5878f2efdac" cx="18.35" cy="98.14" r="3.79" style="fill: #fff"/>
<path id="e9f7b6a6-dcdd-4d55-a7bb-ad3951bb1e39" data-name="eeb5a6b6-ef4a-4f05-95cd-8b1c3eb419c4" d="M22.07,116.64v-1.8c0-.86-.81-.46-.81-.46L20,115c-.38.18-.33-.34-.33-.34V112c0-.72.82-.76.82-.76h1.25s.32-.26.29-1.39-.29-1.32-.29-1.32H20.53a.67.67,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1,0-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H15.19s-.3.18-.3,1.32.3,1.39.3,1.39h1.38a.71.71,0,0,1,.73.69v2.69c0,.52-.36.34-.36.34l-1-.58c-.68-.39-1.23,0-1.23.46v1.8s0,1,1.23.1a5.09,5.09,0,0,1,3-.71,4.16,4.16,0,0,1,2.35.71C22,117.17,22.07,116.64,22.07,116.64Z" style="fill: #fff"/>
<path id="82138da6-9b2a-4b9a-952e-568841e5ed52" data-name="80481c02-bb01-43aa-bd64-15ab30fbbb5e" d="M14.44,103.18c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.83,5.78,5.78,0,0,0,2.77-.83.7.7,0,0,1,1,.25.67.67,0,0,1,.1.31v1.76s-.24,1-1.07.59a5,5,0,0,0-2.77-.77,6.59,6.59,0,0,0-2.85.77.68.68,0,0,1-.24.08.83.83,0,0,1-1-.63v0S14.44,104,14.44,103.18Z" style="fill: #fff"/>
</g> </g>
<path id="aa62b88a-4cd5-4c76-acaf-e85a7fd45341" data-name="6b63d025-68d6-47eb-ba62-60017f4a1dd4" d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78h0V92l9.26-9.57a2.29,2.29,0,0,1,2.38-1c4.4,0,23.87-.14,23.87-.14h.64s7.76,9.8,18.13,23.86v29.64h0a5.79,5.79,0,0,1-5.79,5.79Z" style="fill: #a8a9a8"/> <g id="LM_rightside" data-name="LM rightside">
<g> <path id="LM_rightside5" data-name="LM rightside5" d="M33.08,69.61H27.47A5.45,5.45,0,0,1,22,64.15h0V41.25a5.45,5.45,0,0,1,5.46-5.46h5.61a5.46,5.46,0,0,1,5.46,5.46v22.9A5.45,5.45,0,0,1,33.08,69.61Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<g id="1172473e-5b0c-4dd6-85c5-28f5593b9312" data-name="a0498222-7e69-48db-90b7-05f2ce124a03"> <circle id="LM_rightside4" data-name="LM rightside4" cx="28.3" cy="66.21" r="3.79" style="fill: #fff"/>
<g style="clip-path: url(#9d9a0722-eca6-4c98-bf03-49097e654f0e)"> <circle id="LM_rightside3" data-name="LM rightside3" cx="28.3" cy="43" r="3.79" style="fill: #fff"/>
<g id="da9d77a3-c9b0-4118-a8e3-c65ec5cbe7d4" data-name="8270fb93-0862-4480-a5b8-675cc77ac153"> <path id="LM_rightside2" data-name="LM rightside2" d="M24.4,59.69A4.16,4.16,0,0,1,26.74,59a5.23,5.23,0,0,1,3,.71c1.25.93,1.23-.1,1.23-.1v-1.8c0-.45-.56-.85-1.23-.46l-1,.58s-.36.19-.36-.33V55s0-.79.73-.77,1.38,0,1.38,0,.29-.25.29-1.39-.29-1.32-.29-1.32H29.1s-.73,0-.73-.65v-1.3s-.23-.36-1.17-.3a3.56,3.56,0,0,0-1.4.3v1.3a.66.66,0,0,1-.66.65c-.63,0-1.26,0-1.26,0s-.25.19-.29,1.32.29,1.39.29,1.39h1.26s.8.05.82.77,0,2.62,0,2.62,0,.51-.34.33l-1.21-.58s-.83-.41-.82.46,0,1.8,0,1.8S23.67,60.12,24.4,59.69Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
<path id="77253f44-139e-4b90-82df-465a787cab9c" data-name="bb0a4ec3-45a5-4c91-b064-db5494e447e6" d="M78.56,142.76l1-7.69V103.85L66.49,87.72v14.86L42.7,133.66,35.55,141Z" style="fill: #f2f2f2"/> <path id="LM_rightside1" data-name="LM rightside1" d="M31.25,47.89a.84.84,0,0,1-1,.68.85.85,0,0,1-.24-.09,6.63,6.63,0,0,0-2.85-.77,5.11,5.11,0,0,0-2.77.77c-.83.4-1.07-.59-1.07-.59V46.13a.72.72,0,0,1,.76-.66.67.67,0,0,1,.31.1,5.79,5.79,0,0,0,2.77.84,7.12,7.12,0,0,0,2.85-.84s1.18-.24,1.2.56S31.25,47.89,31.25,47.89Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
</g>
</g>
</g>
<path id="9d05c10c-72eb-4f9f-8517-e403ec636357" data-name="74e07bdd-431b-40c1-b0f3-71128f2a0c08" d="M35.85,135.56a5.78,5.78,0,0,1-5.78-5.78h0V92.9h0a5.78,5.78,0,0,1,5.77-5.79H57.17s6.91,9.15,15.56,20.41v22.25h0A5.78,5.78,0,0,1,67,135.56H35.85Z" style="fill: #a8a9a8"/>
<g id="6df8eb1f-3187-427f-8d99-bc7a37e6cc25" data-name="9bbfb3ec-86c2-4d27-8275-76f2f9737a7f">
<g id="e4d7143c-1fb6-45a4-a205-1c920b8a823c" data-name="7e017c33-f09b-4d39-803f-1bedf1ebf566">
<g id="3a4e493d-cd17-48c4-97b6-da7ee3c4898e" data-name="69e3df75-72a6-4499-baab-f65ec194e193">
<g style="clip-path: url(#0f29df77-bfe3-4749-8432-7a5b3681f927)">
<g id="7cada08f-1e90-4ef2-8ae4-3f2adfd3e953" data-name="b7007e32-15c9-40b3-a885-a7231fd104d1">
<path id="02e64b51-bd56-4079-9736-8a269cb37029" data-name="c599a4f4-ae5d-411c-902d-dbcde04a2d6e" d="M60.44,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112Zm-3.61,0a1.09,1.09,0,1,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112ZM46,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6A1.08,1.08,0,0,1,47,140.65h0a1.07,1.07,0,0,1-1-1.11V112Z" style="fill: #6a6a6a"/>
</g>
</g>
</g>
<circle id="a5a29926-0401-43af-b098-0c7439485e7c" data-name="bcdc8e69-90f7-4365-8f7a-7c1567704161" cx="29.69" cy="135.22" r="2.24" style="fill: #9a9a9a"/>
<circle id="313e9fdc-7bbb-4d49-9d19-2415450fb691" data-name="b7785d8e-a2e4-41a7-9c34-4d9f6aebd906" cx="58.36" cy="84.71" r="2.24" style="fill: #9a9a9a"/>
<g id="1eb2ae58-2419-47d4-86bf-4f26a7f0cf61" data-name="KNOB">
<g id="26377a78-5df7-4bea-8daa-669ea612118c" data-name="5301e639-3e28-489d-96ec-91bda6d459b7">
<circle id="13e05316-9dcc-4be0-9e0e-4b1df48fad92" data-name="f1bc8b30-bdb2-4084-8c02-e322d1c0b9bf" cx="17.06" cy="17.06" r="17.06" style="fill: #b72b1c"/>
</g> </g>
<g> <g>
<circle id="58277aee-b73f-4f42-94ef-3b959dc26807" data-name="ce4b2c57-9b3b-4aed-902e-31d9f366dc61" cx="20.12" cy="28.12" r="3.79" style="fill: #3c3c3c"/> <image width="36" height="76" transform="translate(32 12)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAABNCAYAAAAhOa00AAAACXBIWXMAAAsSAAALEgHS3X78AAACAElEQVRoQ+3avVHDMBiA4VdcypgREmo4RggLpKKHAZiIAWgoKZggrEAGCBsQpxeFpNgJ/vkkK5YLvXe6g2Cb53zE9oVPaa3xSSmlALTvjh4pn2MrpQpgab/dAYdL4MQoC3oAnuxLH8AW2Gmty9YdAxKhaqAXYAUozJnaAm/AJiZs1rfBGegBKOyP7oAFMLfbRYN1ojpAYM7WtX3dbR8F1orqAdVz27n9BsMaUR4gV1yY1vpkYX7BGvgE9oD2WL/AO3CPfROFrKs6MOAMnVcAt3b57lsV6QzV194eYw0UfWelacUGRYFdAjQYNsPcy54xV+rwv4P/Bb8jZ5gr8oK4IFcQzF2nVOdWw/KG9d77IuUFGwsFHrAxUSCEjY0CASwFCnpgqVDQAUuJghZYahQY2Ao4YJ77v08eXRJWUHvenwoKaneVKaGOZZS0jJKWUdIySlpGScsoaRklLaOkZZS0jJKWUdIySlpGScsoaRklLaOkTQml3RdTQZXAD+bD2EmgSuALMwmyg/SoEtgAr9RGU1KiGkGQDtUKgjSoThCMj+oFwbgoEQjGQ4lBMA7KCwSXR3mDoPonpBsFccWYUwgCgUEdMAN/YDBzzKjJvG0nQe7W4Q2CCnFDhVgCj1TznCHtGDDVqLTWxylXW4wzdWDA/GfjnOcZMijddGBhouHTsfsDst/cEY24RzwAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<circle id="980a54d2-804e-408d-8655-debf2e5856d0" data-name="6a44a65a-f04b-4564-81a2-4eefa438c5f1" cx="28.27" cy="14" r="3.79" style="fill: #3c3c3c"/> <path id="LM_level4-2" data-name="LM level4-2" d="M64.91,70.7,51.5,83.63,32.93,83,32.76,24c0-.84.16-.84.46-1.13l10.42-10.1.21-.19c.59-.4,2,.11,2,.95L65.29,34.25V70C65.3,70.44,65.16,70.43,64.91,70.7Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<circle id="9b2e3cd0-e4bd-42ce-b558-4f4bc46eaf23" data-name="d5fea8d1-47c1-448e-adb6-8519e2516216" cx="14.15" cy="5.85" r="3.79" style="fill: #3c3c3c"/> </g>
<circle id="06781f30-70ec-4914-81c3-4083325e7c18" data-name="1faf9727-3903-4be3-a3d3-4ab2d5d92b1f" cx="6" cy="19.97" r="3.79" style="fill: #3c3c3c"/> <g>
<path id="f1de636f-1fd2-4419-ae5c-d6a853c5834d" data-name="9e52c672-4ec8-4d92-9380-e44b4f69f848" d="M13.56,16.89a2.91,2.91,0,0,0,.7,2.26,12,12,0,0,1,1.2-.39c.69-.18.95.59.95.59l.33,1.21s.33.24,1.41-.08,1.2-.62,1.2-.62-.17-.6-.32-1.22a.66.66,0,0,1,.45-.8l1.26-.34a3.63,3.63,0,0,0-.07-1.43c-.19-.93-.6-1.05-.6-1.05l-1.25.34c-.65.17-.82-.54-.82-.54l-.36-1.33s-.25-.24-1.35,0-1.26.64-1.26.64.14.61.35,1.34a.7.7,0,0,1-.48.88l-.07,0Z" style="fill: #242424"/> <image width="25" height="27" transform="translate(32 69)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAcCAYAAAB/E6/TAAAACXBIWXMAAAsSAAALEgHS3X78AAABYUlEQVRIS+2WvVXDMBRG7/NxGVf0CRVFchghWSAVA2QAxmEGGgZgguzgHlPTELv/KCSD/BMs2wkV9xwf2/LPlZ70JJkk2piZdQojUd8PAWuXm1kGrIBF3wcDVEAhqWw/aIi8ZAcccLKxFMAzcGzL0voikDwCWyBjPGt8JMysKfMtMuAeeAE+Ac04TsArsAcySUj6blGGq82aaS0JyXARqYDCzHJJSnzItrh+ucW1bi4ZsCQYUAmu0w9M75dzNCqc4KxLLivpkPjzJcL1Kwl/xL9oMnXC1lkdw6SBk+IyOPf3Qz9Z8DOzD73bIAXegCfiloUV8ABs/HV07qWSKjPLiSP3xwY3m+yIlKVwflXsofSVeseFHCJlKSPxlTqZ2TEoHpSNFtVIKsfIJotgnGyWCHplW3pG8GwRdGQVbqXu35zMJZAVONEdgayzr5uL33wugBvgQ1IFVxDVmJmF+Xk1UZsvIeCPQjWq5BoAAAAASUVORK5CYII=" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<path id="e8012624-d689-4ee7-a77a-99e9713ea199" data-name="3179af54-0c25-42bc-9804-f3575e0b1b0b" d="M17.44,24.25a.47.47,0,0,1-.56-.32l-.55-2.06h0a.45.45,0,0,1,.32-.55h0l1.63-.23,1.44-.6a.47.47,0,0,1,.56.32l.55,2.05h0a.45.45,0,0,1-.32.55h0L18.94,24Z" style="fill: #3c3c3c"/> <path id="LM_level3-2" data-name="LM level3-2" d="M54,92V74.7a2.19,2.19,0,0,0-.3-1.12c-.28-.27-3.52-3.62-3.52-3.62a1.55,1.55,0,0,0-1.16-.4c-.75,0-11.62,0-11.62,0L33,74.26v8l10.66.57Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<path id="31a64bab-6b92-41d0-afe9-392c1fae8ddb" data-name="841a583e-aa25-4a7e-8907-fbe64ce57066" d="M9.88,17.31a.46.46,0,0,1,.33-.56l2-.55h0a.47.47,0,0,1,.56.33L13,18.16l.6,1.45a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.57-1.53L9.84,17.3Z" style="fill: #3c3c3c"/> </g>
<path id="2b1c6b9e-6fda-40be-8bb8-318c30b7dca4" data-name="42515acc-688f-41c7-884c-80b8a90e09c0" d="M16.82,9.8a.47.47,0,0,1,.56.32l.55,2.05h0a.46.46,0,0,1-.33.55L16,13l-1.45.61a.45.45,0,0,1-.55-.32h0l-.53-2.1h0a.45.45,0,0,1,.31-.56h0l1.53-.57,1.55-.25Z" style="fill: #3c3c3c"/> <g id="LM_leftside" data-name="LM leftside">
<path id="be04cab5-eaac-4d03-a1ee-dbe70dd5bf90" data-name="8690082b-7091-4631-a199-b79823698dd6" d="M24.33,16.74a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.22-1.64-.6-1.44a.45.45,0,0,1,.31-.56h0l2-.55h0a.46.46,0,0,1,.56.33l.57,1.53.25,1.55Z" style="fill: #3c3c3c"/> <path id="LM_leftside5" data-name="LM leftside5" d="M60.08,126.64H54.47A5.45,5.45,0,0,1,49,121.18h0V98.28a5.46,5.46,0,0,1,5.46-5.46h5.61a5.47,5.47,0,0,1,5.46,5.46v22.9A5.45,5.45,0,0,1,60.08,126.64Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
<circle id="LM_leftside4" data-name="LM leftside4" cx="61.67" cy="123.24" r="3.79" style="fill: #fff"/>
<circle id="LM_leftside3" data-name="LM leftside3" cx="61.67" cy="100.03" r="3.79" style="fill: #fff"/>
<path id="LM_leftside2" data-name="LM leftside2" d="M57.77,116.72a4.15,4.15,0,0,1,2.34-.7,5.14,5.14,0,0,1,3,.7c1.25.93,1.23-.1,1.23-.1v-1.8c0-.45-.56-.84-1.23-.46l-1,.58s-.36.19-.36-.33V112s0-.79.73-.77,1.38,0,1.38,0,.29-.25.29-1.38-.29-1.33-.29-1.33H62.47s-.73,0-.73-.64v-1.3s-.23-.36-1.17-.31a3.57,3.57,0,0,0-1.4.31v1.3a.66.66,0,0,1-.66.64H57.25s-.25.2-.29,1.33.29,1.38.29,1.38h1.26s.8,0,.82.77,0,2.62,0,2.62,0,.51-.34.33l-1.21-.58s-.83-.4-.82.46,0,1.8,0,1.8S57,117.16,57.77,116.72Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
<path id="LM_leftside1" data-name="LM leftside1" d="M64.62,104.92a.83.83,0,0,1-1,.68.68.68,0,0,1-.24-.08,6.46,6.46,0,0,0-2.85-.77,5,5,0,0,0-2.77.77c-.83.4-1.07-.6-1.07-.6v-1.76a.71.71,0,0,1,.76-.65.8.8,0,0,1,.31.09,5.79,5.79,0,0,0,2.77.84,7,7,0,0,0,2.85-.84s1.18-.24,1.2.56S64.62,104.92,64.62,104.92Z" transform="translate(0.98 1.9)" style="fill: #fff"/>
</g>
<g>
<image width="58" height="64" transform="translate(0 81)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAABBCAYAAABvnNwUAAAACXBIWXMAAAsSAAALEgHS3X78AAACFElEQVRoQ+2bQY7TMBSGvxcqsaFbJDbDrEEcYeYCcwYOwIlYsWLDjg0nGG6A1ANkbgCNhGb1WNgBpxPbaUjT+smf5E3lxPlq/25S5YmqshQiIrk+S6EzLlxmHDOKiGyB18CLXN8F6IAW6I6RXkTWi94C73HCp6YFvgI7oFXVfaY/sIBsIPoBuAG26SMWoZ/ZHfAZuJ8ivMl1SHEgess6ouDGeQtc4WMjInlhVZ3VcAPeAd+AX4Ceqf0EvgDv8Cs11hpm4Hfda1xG11q6MbbAG9+S1zFLliMGWIHBF++jNcrRmfUnu8Gd/Bo32Lnp9w4gnt+jZM+4IU0hKzxZ9sJyGiMpPFmWy8ppiqjwJNkLzWmK/no7oBWRnapqdje+8Jym2BLcdEDmp6eQnKYYrMDczJaS00lEZQvMaZZR2YJzmuSJrIGcRhmbWVM5DRnIWsxpyF9ZqzkNacB2TkP6mTWb05DGek5DGtxfn6aXb0+Du1G+wrgo/Mus2aUbknsQMEWVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUqVtUovq8le5TLwanBvbj4A2VKRwtjjvLr+g2fAb1wFxUvgFfB89NCy2APfgU/AD1V9BNio6l5E7oOOpb9u0It+5KC4aQNwINyxTonZqWiJVHENytNk3eLBU9ERqc97UovnXwArGj2U8vx34WFJ/AG0vvY6LSeZMAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<path id="LM_level2_grey-2" data-name="LM level2 grey-2" d="M49,140.61H6.31a5.78,5.78,0,0,1-5.78-5.78h0V105.19C10.89,91.13,18.65,81.32,18.65,81.32h.6s19.46.15,23.86.15a2.29,2.29,0,0,1,2.38,1L54.75,92v42.8A5.78,5.78,0,0,1,49,140.61Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
</g>
<g id="LM_total" data-name="LM total">
<g id="LM_whitepart" data-name="LM whitepart">
<g style="clip-path: url(#clip-path-2)">
<g id="LM_whitepart_combined" data-name="LM whitepart combined">
<path id="LM_whitepart_top" data-name="LM whitepart top" d="M43.48,141l-7.15-7.37L12.54,102.56V87.7L-.52,103.84v31.22l1,7.69Z" transform="translate(0.98 1.9)" style="fill: #f1f1f1"/>
</g>
</g>
</g>
<g>
<image width="47" height="52" transform="translate(5 87)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAA1CAYAAAAHz2g0AAAACXBIWXMAAAsSAAALEgHS3X78AAABnElEQVRoQ+2azXHCMBBG3zIccQuBM5MWoIHUkAJSUQrIJQWkAlIJ6SDYd+UgGWTjHxQHr5TRm9HFIzz75G8Z8KwYY5iKiMjYnr/AdBQrUwVEpADWwGps70Qq4GiMKf2LkwRc8XvgGStxT47AG3DwJZb9+4fxin8BdkAx/InJbHFPWUQuEsaY4IUt9gn4AE6AmWl9A+/AIy49CwJxDbvBxmaOk/cpgAe8fgsWwN5k69acxdc0vvGCBFzud9jT39C6mQY3C7Sado/O6V9xk4By7ge5SQD93PcyKhBj7n0GBWLNvU+vQArFQ49AzE3bpu8JRNu0ba4EYm/aNg2BVHLvcxZIKfc+/hNIJvc+C0gv9z4LF501iUWnpo7QCvtHIaniodkDycTGZ/THXOxkAW2ygDZZQJssoE0W0CYLaJMFtMkC2mQBbbKANv9K4PdDE/PSqLMWqIAvoDEJEiElts7qfEV59iFknbD1PQFFPbexBDDGlCJy4EJs70hL4BN4pW/cpiVRcf/5nxA6Z4WgY+BpxgmsEDqntWDixFYM/ACNRtJx4q2GRAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<path id="LM_top_grey-2" data-name="LM top grey-2" d="M43.18,135.54H12.09a5.78,5.78,0,0,1-5.79-5.78h0V107.51C15,96.24,21.86,87.1,21.86,87.1H43.18A5.78,5.78,0,0,1,49,92.88h0v36.88a5.78,5.78,0,0,1-5.78,5.78Z" transform="translate(0.98 1.9)" style="fill: #a8aaa8"/>
</g>
<g id="LM_top" data-name="LM top">
<g style="clip-path: url(#clip-path-3)">
<g id="LM_top_total" data-name="LM top total">
<path id="LM_top_lines" data-name="LM top lines" d="M18.6,112.05v27.47a1.08,1.08,0,0,1-1.12,1,1.06,1.06,0,0,1-1.05-1V112.05A1.09,1.09,0,0,1,18.6,112Zm3.61,0v27.47a1.09,1.09,0,1,1-2.17,0V112.05a1.09,1.09,0,1,1,2.17,0Zm3.62,0v27.47a1.09,1.09,0,1,1-2.17,0V112.05a1.09,1.09,0,1,1,2.17,0Zm3.61,0v27.47a1.09,1.09,0,0,1-2.17.07V112.05a1.09,1.09,0,0,1,2.17-.07Zm3.62,0v27.47A1.1,1.1,0,0,1,32,140.64a1.08,1.08,0,0,1-1.11-1V112.05a1.09,1.09,0,0,1,2.17-.07Z" transform="translate(0.98 1.9)" style="fill: #6a6a6a"/>
</g>
</g>
</g>
<circle id="LM_detail_2" data-name="LM detail 2" cx="50.32" cy="137.11" r="2.24" style="fill: #9a9a9a"/>
<circle id="LM_detail_1" data-name="LM detail 1" cx="21.66" cy="86.59" r="2.24" style="fill: #9a9a9a"/>
<g id="hole">
<g>
<image width="38" height="38" transform="translate(44)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAAnCAYAAACMo1E1AAAACXBIWXMAAAsSAAALEgHS3X78AAACRklEQVRYR9WYPXLbMBBGHzgpxRwhTJ3ER0gukMauUvl0btIlhU9gdSkzQ9dWbmBTtTYFdiUA/BGh0ILyzWBAUiTx+C0JYdeJCDlyzrlgdwU02pu2wEb7vSR3IMDNvUahUpgGuNHetAF+aG/aA+dAzoJzztV4gI/EMHOdM+AW2IhIxwxNwqlbNfAZuMXDpTBhmE3pTQ24Be6ANdAdc/HN2A+JW7d4wJphmFTpOTX+Pu/wD7YCWufcpIuDzinYF2K36t6Jp6kjdvFhFFBEooaH+ArcA8/ADh+mJdtO732vY9Uph4iQgjngCviuFx8b5F/bs451hUYxbBWxauCDtqXCOKXp8UbC+cLxp16qvTAS3lLhTJuF9xNBeC2sK84bzlQ2bYXzJ5VOtA1+5n/PvHnsNdT7twmdswmyhEKDGltchF9rKcdMPYMMrjSYyRGwVJQPaaiIpSJek5V0MHrv4D9w7pK0Bf5oT5UeKCghWeJXyQEZvfQ8uljnTHuD7J0r7Zgp4gg/iNKAvQgaXOnQRh+DZWWVbtgPT5RzsJfvhs49apuV8C4sy8jiyF38Mj0AfAt8A37zOinhbLCh7KvjfOHd4d/xO2AtA4l1BKcfx/4CDuFdWh0+4/+l/aARvVqJiHTOuQfd3bJsOULwIGu8AS3wZFNHqtEq00QhB/LXfcIJlabRKpM62HKYnLccsiPrQxlwOlgIlVWjyy0eGlhazbTjcKRwSEZ1cxYcRLXgIeca4Fq3f7JAyRUy4EIlRWuYdo5cKNNJcOfSX2jmA7RYwAeRAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<circle id="LM_red-2" data-name="LM red-2" cx="62.96" cy="18.95" r="17.06" style="fill: #d42715"/>
</g>
<g id="LM_details_in_red" data-name="LM details in red">
<circle id="LM_detail_red_hole4" data-name="LM detail red hole4" cx="59.9" cy="30.01" r="3.79" style="fill: #393939"/>
<circle id="LM_detail_red_hole3" data-name="LM detail red hole3" cx="51.75" cy="15.89" r="3.79" style="fill: #393939"/>
<circle id="LM_detail_red_hole2" data-name="LM detail red hole2" cx="65.87" cy="7.74" r="3.79" style="fill: #393939"/>
<circle id="LM_detail_red_hole1" data-name="LM detail red hole1" cx="74.02" cy="21.86" r="3.79" style="fill: #393939"/>
<path id="LM_detail_hole" data-name="LM detail hole" d="M64.2,16.41a.72.72,0,0,1-.55-.91c.21-.72.36-1.33.36-1.33s-.17-.35-1.27-.64-1.35-.06-1.35-.06L61,14.8s-.16.72-.81.54L59,15s-.4.13-.6,1.06a3.44,3.44,0,0,0-.06,1.43l1.25.33a.68.68,0,0,1,.46.81c-.16.61-.33,1.21-.33,1.21s.12.3,1.2.62,1.42.09,1.42.09l.32-1.22s.26-.76,1-.59q.6.17,1.2.39a2.92,2.92,0,0,0,.7-2.25C64.91,16.65,64.2,16.41,64.2,16.41Z" transform="translate(0.98 1.9)" style="fill: #1f1f1f"/>
<path id="LM_detail_red4" data-name="LM detail red4" d="M61.64,24.23,60.09,24l-1.53-.57a.46.46,0,0,1-.33-.56h0l.55-2.05a.46.46,0,0,1,.56-.32l1.45.6,1.63.22a.46.46,0,0,1,.33.56h0l-.55,2.05a.44.44,0,0,1-.55.32Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
<path id="LM_detail_red3" data-name="LM detail red3" d="M69.15,17.3l-.26,1.55-.57,1.52a.45.45,0,0,1-.55.33h0l-2.06-.55a.46.46,0,0,1-.32-.56L66,18.15l.22-1.63a.45.45,0,0,1,.55-.33h0l2,.55a.46.46,0,0,1,.32.56Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
<path id="LM_detail_red2" data-name="LM detail red2" d="M62.21,9.79l1.55.25,1.53.57a.46.46,0,0,1,.33.55h0l-.55,2.05a.46.46,0,0,1-.56.32l-1.45-.6-1.63-.22a.47.47,0,0,1-.33-.56h0l.55-2.05a.44.44,0,0,1,.55-.32Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
<path id="LM_detail_red1" data-name="LM detail red1" d="M54.7,16.72,55,15.17l.57-1.52a.45.45,0,0,1,.55-.33h0l2.06.55a.46.46,0,0,1,.32.56l-.61,1.44-.22,1.63a.45.45,0,0,1-.55.33h0l-2-.55a.46.46,0,0,1-.32-.56Z" transform="translate(0.98 1.9)" style="fill: #393939"/>
</g> </g>
</g> </g>
</g> </g>

View File

@ -1,28 +1,33 @@
<svg id="svg7610" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 44.14 44.15"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48">
<defs> <defs>
<linearGradient id="motor-linear-gradient" x1="-313.1" y1="551.59" x2="-313.1" y2="551.43" gradientTransform="matrix(44.14, 0, 0, -44.15, 13843.7, 24396.04)" gradientUnits="userSpaceOnUse"> <linearGradient id="linear-gradient" x1="-427.2" y1="440.79" x2="-427.2" y2="440.63" gradientTransform="matrix(44.14, 0, 0, -44.15, 18878.72, 19502.57)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#a8a9a8"/> <stop offset="0" stop-color="#a8aaa8"/>
<stop offset="1" stop-color="#545554"/> <stop offset="1" stop-color="#535453"/>
</linearGradient> </linearGradient>
</defs> </defs>
<title>MediumMotor</title> <title>MediumMotor</title>
<g style="isolation: isolate">
<g id="svg7610">
<g id="Medium_Motor" data-name="Medium Motor"> <g id="Medium_Motor" data-name="Medium Motor">
<g id="Group_4" data-name="Group 4"> <g id="medmotor_box" data-name="medmotor box">
<path id="Path_1" data-name="Path 1" d="M4.07,1.5h39a2.36,2.36,0,0,1,2.57,2V43.82c0,1-1.1,1.82-2.57,1.82h-39c-1.47,0-2.57-.81-2.57-1.82V3.47A2.36,2.36,0,0,1,4.07,1.5Z" transform="translate(-1.5 -1.49)" style="fill: url(#motor-linear-gradient)"/> <path id="medmotor_box_wgradient" data-name="medmotor box wgradient" d="M2.57,0h39a2.36,2.36,0,0,1,2.57,2V42.33c0,1-1.1,1.82-2.57,1.82h-39C1.1,44.15,0,43.34,0,42.33V2A2.36,2.36,0,0,1,2.57,0Z" transform="translate(2 1.84)" style="fill: url(#linear-gradient)"/>
</g> </g>
<g id="Group_7" data-name="Group 7"> <g id="medmotor_star" data-name="medmotor star">
<g id="g7596"> <g>
<path id="Union_1-2" data-name="Union 1-2" d="M1.5,22.74a6.21,6.21,0,0,1,6.22-6.22h8.8V7.72A6.22,6.22,0,0,1,22.74,1.5H24.4a6.21,6.21,0,0,1,6.22,6.22v8.8h8.8a6.21,6.21,0,0,1,6.22,6.22V24.4a6.22,6.22,0,0,1-6.22,6.22h-8.8v8.8a6.22,6.22,0,0,1-6.22,6.22H22.74a6.23,6.23,0,0,1-6.22-6.22h0v-8.8H7.72A6.22,6.22,0,0,1,1.5,24.4h0Z" transform="translate(-1.5 -1.49)" style="fill: #a8a9a8"/> <image width="48" height="48" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAxCAYAAACcXioiAAAACXBIWXMAAAsSAAALEgHS3X78AAACfElEQVRoQ+2aPXLbMBBG32ZUijlCnDo/R1AukCoHyAFS5Sw5g5t0bnwCu0ofpTZ9A1usvSmwoClRJEEAI4gzejMcqliS+2FB4AMoUVVyISICrIErO3dpgBpoNONDJde9RKTCJf4R+Ga/u9TADbAFalXdkYEsAiz5L8B3nICxCmyBa+Auh4jVVMAUneR/ABugAuRIaIUT9w4TJyLJIpIEWJ+/wrX8Bng7fgViMRtcRR5F5G/KO/FmKiCANa5Vq6nADhXwwY7DrjaLHALgeJcZQ4D32MtulYwil4AYfOXOogKxRLe8p7SAZC4CSnMRUJrBmThwbBbSRxIh4HFDs3VPwIQl7oXj/M1U3BBr3PUAY3aiEZGjVnzPjQZY4mOscbNqjIgGeLDzGINWvBUQaImHSOlGIUZu2IqbgAr4CtwCT8AL7sbndLzgcrvF5Vq1jQ98An5bwNSNSh9PuFw/A+KH0RhLXIo9K96dB1L68SnZs+JLnchaK75UAWA9ZskCgGULUFiugAZ4BJquAB0IPjcUZz9ugNoL8IqSNplOxA74Z0ezUlU1p3eNG5787tocUuaQOZXfAfe4XB9UVVcAqroTkTsLaghzoZ5TuFGPb+jWzA3Z6dBk/Hrgp53nVEJx7vKXnUMq0XBgp/cWNFaJbe+yYXzCoS14SINL/g9hAnors96KbM5Gqy0Dg+MHUNxjo+6z1Hmg5SKgNBcBpSktIGrk6VJSQOsopwLHKCVAed2sqmPnAMgnICaB9sv9VOAYOQTEWPEdGZKHRAFWeu8Q74Fnpjemnnm1xEndBxI/dEOUFe9Z4hSy/FcCZlnxniVOIZsACPhKYaR2my5ZBZTgP7HrUIs43RAaAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<path id="medmotor_cut-2" data-name="medmotor cut-2" d="M0,21.25A6.21,6.21,0,0,1,6.22,15H15V6.23A6.22,6.22,0,0,1,21.24,0H22.9a6.22,6.22,0,0,1,6.22,6.22V15h8.8a6.21,6.21,0,0,1,6.22,6.22v1.66a6.21,6.21,0,0,1-6.22,6.22h-8.8v8.8a6.21,6.21,0,0,1-6.22,6.22H21.24A6.22,6.22,0,0,1,15,37.93v-8.8H6.22A6.22,6.22,0,0,1,0,22.92H0Z" transform="translate(2 1.84)" style="fill: #a8aaa8"/>
</g> </g>
<circle id="Ellipse_1" data-name="Ellipse 1" cx="37.77" cy="22.16" r="4.85" style="fill: #3c3c3c"/> <circle id="medmotor_hole_4" data-name="medmotor hole 4" cx="39.77" cy="24" r="4.85" style="fill: #393939"/>
<circle id="Ellipse_2" data-name="Ellipse 2" cx="6.37" cy="22.16" r="4.85" style="fill: #3c3c3c"/> <circle id="medmotor_hole_3" data-name="medmotor hole 3" cx="8.37" cy="24" r="4.85" style="fill: #393939"/>
<circle id="Ellipse_1-2" data-name="Ellipse 1-2" cx="22.15" cy="6.38" r="4.85" style="fill: #3c3c3c"/> <circle id="medmotor_hole_2" data-name="medmotor hole 2" cx="24.15" cy="8.22" r="4.85" style="fill: #393939"/>
<circle id="Ellipse_2-2" data-name="Ellipse 2-2" cx="22.15" cy="37.78" r="4.85" style="fill: #3c3c3c"/> <circle id="medmotor_hole_1" data-name="medmotor hole 1" cx="24.15" cy="39.62" r="4.85" style="fill: #393939"/>
</g>
<g id="medmotor_red" data-name="medmotor red">
<circle cx="24.3" cy="24" r="6.75" style="fill: #d42715"/>
<circle cx="24.3" cy="24" r="6.63" style="fill: none;stroke: #a20800;stroke-width: 0.25px"/>
</g>
<path id="medmotor_Hole" data-name="medmotor Hole" d="M20.59,19.46s-.05,1-.77,1-1.46,0-1.46,0a2.38,2.38,0,0,0-.45,1.69c0,1.27.36,1.6.36,1.6h1.62a.64.64,0,0,1,.7.59.21.21,0,0,1,0,.11v1.67a4,4,0,0,0,1.77.29A6.88,6.88,0,0,0,24,26.15V24.48a.73.73,0,0,1,.73-.7,9.89,9.89,0,0,0,1.44-.14s.4-.37.44-1.63-.36-1.64-.36-1.64H24.6a.65.65,0,0,1-.75-.51.49.49,0,0,1,0-.17,11.22,11.22,0,0,1,0-1.64,4.78,4.78,0,0,0-3.25,0C20.58,18.74,20.59,19.46,20.59,19.46Z" transform="translate(2 1.84)"/>
</g> </g>
<g id="Ellipse_4" data-name="Ellipse 4">
<circle id="ellipse7603" cx="22.3" cy="22.16" r="6.75" style="fill: #b72b1c"/>
<circle id="ellipse7605" cx="22.3" cy="22.16" r="6.63" style="fill: none;stroke: #8b1104;stroke-width: 0.25px"/>
</g> </g>
<path id="Hole" d="M23.9,26.72s.56-.86,1.18-.51,1.27.73,1.27.73a2.37,2.37,0,0,0,1.24-1.23c.63-1.1.49-1.57.49-1.57l-1.41-.81a.64.64,0,0,1-.32-.86l.06-.1.84-1.44a3.9,3.9,0,0,0-1.39-1.13,6,6,0,0,0-1.6-.59l-.83,1.44a.73.73,0,0,1-1,.24,11.15,11.15,0,0,0-1.32-.6s-.54.13-1.2,1.2-.51,1.6-.51,1.6l1.46.84a.64.64,0,0,1,.4.82.55.55,0,0,1-.08.15,11.25,11.25,0,0,1-.82,1.43A4.83,4.83,0,0,0,23.19,28C23.56,27.35,23.9,26.72,23.9,26.72Z" transform="translate(-1.5 -1.49)"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,30 +1,35 @@
namespace pxsim.visuals { namespace pxsim.visuals {
export const MEDIUM_MOTOR_SVG = `<svg id="svg7610" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 44.14 44.15"> export const MEDIUM_MOTOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48">
<defs> <defs>
<linearGradient id="motor-linear-gradient" x1="-313.1" y1="551.59" x2="-313.1" y2="551.43" gradientTransform="matrix(44.14, 0, 0, -44.15, 13843.7, 24396.04)" gradientUnits="userSpaceOnUse"> <linearGradient id="linear-gradient" x1="-427.2" y1="440.79" x2="-427.2" y2="440.63" gradientTransform="matrix(44.14, 0, 0, -44.15, 18878.72, 19502.57)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#a8a9a8"/> <stop offset="0" stop-color="#a8aaa8"/>
<stop offset="1" stop-color="#545554"/> <stop offset="1" stop-color="#535453"/>
</linearGradient> </linearGradient>
</defs> </defs>
<title>MediumMotor</title> <title>MediumMotor</title>
<g style="isolation: isolate">
<g id="svg7610">
<g id="Medium_Motor" data-name="Medium Motor"> <g id="Medium_Motor" data-name="Medium Motor">
<g id="Group_4" data-name="Group 4"> <g id="medmotor_box" data-name="medmotor box">
<path id="Path_1" data-name="Path 1" d="M4.07,1.5h39a2.36,2.36,0,0,1,2.57,2V43.82c0,1-1.1,1.82-2.57,1.82h-39c-1.47,0-2.57-.81-2.57-1.82V3.47A2.36,2.36,0,0,1,4.07,1.5Z" transform="translate(-1.5 -1.49)" style="fill: url(#motor-linear-gradient)"/> <path id="medmotor_box_wgradient" data-name="medmotor box wgradient" d="M2.57,0h39a2.36,2.36,0,0,1,2.57,2V42.33c0,1-1.1,1.82-2.57,1.82h-39C1.1,44.15,0,43.34,0,42.33V2A2.36,2.36,0,0,1,2.57,0Z" transform="translate(2 1.84)" style="fill: url(#linear-gradient)"/>
</g> </g>
<g id="Group_7" data-name="Group 7"> <g id="medmotor_star" data-name="medmotor star">
<g id="g7596"> <g>
<path id="Union_1-2" data-name="Union 1-2" d="M1.5,22.74a6.21,6.21,0,0,1,6.22-6.22h8.8V7.72A6.22,6.22,0,0,1,22.74,1.5H24.4a6.21,6.21,0,0,1,6.22,6.22v8.8h8.8a6.21,6.21,0,0,1,6.22,6.22V24.4a6.22,6.22,0,0,1-6.22,6.22h-8.8v8.8a6.22,6.22,0,0,1-6.22,6.22H22.74a6.23,6.23,0,0,1-6.22-6.22h0v-8.8H7.72A6.22,6.22,0,0,1,1.5,24.4h0Z" transform="translate(-1.5 -1.49)" style="fill: #a8a9a8"/> <image width="48" height="48" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAxCAYAAACcXioiAAAACXBIWXMAAAsSAAALEgHS3X78AAACfElEQVRoQ+2aPXLbMBBG32ZUijlCnDo/R1AukCoHyAFS5Sw5g5t0bnwCu0ofpTZ9A1usvSmwoClRJEEAI4gzejMcqliS+2FB4AMoUVVyISICrIErO3dpgBpoNONDJde9RKTCJf4R+Ga/u9TADbAFalXdkYEsAiz5L8B3nICxCmyBa+Auh4jVVMAUneR/ABugAuRIaIUT9w4TJyLJIpIEWJ+/wrX8Bng7fgViMRtcRR5F5G/KO/FmKiCANa5Vq6nADhXwwY7DrjaLHALgeJcZQ4D32MtulYwil4AYfOXOogKxRLe8p7SAZC4CSnMRUJrBmThwbBbSRxIh4HFDs3VPwIQl7oXj/M1U3BBr3PUAY3aiEZGjVnzPjQZY4mOscbNqjIgGeLDzGINWvBUQaImHSOlGIUZu2IqbgAr4CtwCT8AL7sbndLzgcrvF5Vq1jQ98An5bwNSNSh9PuFw/A+KH0RhLXIo9K96dB1L68SnZs+JLnchaK75UAWA9ZskCgGULUFiugAZ4BJquAB0IPjcUZz9ugNoL8IqSNplOxA74Z0ezUlU1p3eNG5787tocUuaQOZXfAfe4XB9UVVcAqroTkTsLaghzoZ5TuFGPb+jWzA3Z6dBk/Hrgp53nVEJx7vKXnUMq0XBgp/cWNFaJbe+yYXzCoS14SINL/g9hAnors96KbM5Gqy0Dg+MHUNxjo+6z1Hmg5SKgNBcBpSktIGrk6VJSQOsopwLHKCVAed2sqmPnAMgnICaB9sv9VOAYOQTEWPEdGZKHRAFWeu8Q74Fnpjemnnm1xEndBxI/dEOUFe9Z4hSy/FcCZlnxniVOIZsACPhKYaR2my5ZBZTgP7HrUIs43RAaAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
<path id="medmotor_cut-2" data-name="medmotor cut-2" d="M0,21.25A6.21,6.21,0,0,1,6.22,15H15V6.23A6.22,6.22,0,0,1,21.24,0H22.9a6.22,6.22,0,0,1,6.22,6.22V15h8.8a6.21,6.21,0,0,1,6.22,6.22v1.66a6.21,6.21,0,0,1-6.22,6.22h-8.8v8.8a6.21,6.21,0,0,1-6.22,6.22H21.24A6.22,6.22,0,0,1,15,37.93v-8.8H6.22A6.22,6.22,0,0,1,0,22.92H0Z" transform="translate(2 1.84)" style="fill: #a8aaa8"/>
</g> </g>
<circle id="Ellipse_1" data-name="Ellipse 1" cx="37.77" cy="22.16" r="4.85" style="fill: #3c3c3c"/> <circle id="medmotor_hole_4" data-name="medmotor hole 4" cx="39.77" cy="24" r="4.85" style="fill: #393939"/>
<circle id="Ellipse_2" data-name="Ellipse 2" cx="6.37" cy="22.16" r="4.85" style="fill: #3c3c3c"/> <circle id="medmotor_hole_3" data-name="medmotor hole 3" cx="8.37" cy="24" r="4.85" style="fill: #393939"/>
<circle id="Ellipse_1-2" data-name="Ellipse 1-2" cx="22.15" cy="6.38" r="4.85" style="fill: #3c3c3c"/> <circle id="medmotor_hole_2" data-name="medmotor hole 2" cx="24.15" cy="8.22" r="4.85" style="fill: #393939"/>
<circle id="Ellipse_2-2" data-name="Ellipse 2-2" cx="22.15" cy="37.78" r="4.85" style="fill: #3c3c3c"/> <circle id="medmotor_hole_1" data-name="medmotor hole 1" cx="24.15" cy="39.62" r="4.85" style="fill: #393939"/>
</g>
<g id="medmotor_red" data-name="medmotor red">
<circle cx="24.3" cy="24" r="6.75" style="fill: #d42715"/>
<circle cx="24.3" cy="24" r="6.63" style="fill: none;stroke: #a20800;stroke-width: 0.25px"/>
</g>
<path id="medmotor_Hole" data-name="medmotor Hole" d="M20.59,19.46s-.05,1-.77,1-1.46,0-1.46,0a2.38,2.38,0,0,0-.45,1.69c0,1.27.36,1.6.36,1.6h1.62a.64.64,0,0,1,.7.59.21.21,0,0,1,0,.11v1.67a4,4,0,0,0,1.77.29A6.88,6.88,0,0,0,24,26.15V24.48a.73.73,0,0,1,.73-.7,9.89,9.89,0,0,0,1.44-.14s.4-.37.44-1.63-.36-1.64-.36-1.64H24.6a.65.65,0,0,1-.75-.51.49.49,0,0,1,0-.17,11.22,11.22,0,0,1,0-1.64,4.78,4.78,0,0,0-3.25,0C20.58,18.74,20.59,19.46,20.59,19.46Z" transform="translate(2 1.84)"/>
</g> </g>
<g id="Ellipse_4" data-name="Ellipse 4">
<circle id="ellipse7603" cx="22.3" cy="22.16" r="6.75" style="fill: #b72b1c"/>
<circle id="ellipse7605" cx="22.3" cy="22.16" r="6.63" style="fill: none;stroke: #8b1104;stroke-width: 0.25px"/>
</g> </g>
<path id="Hole" d="M22.09,21s-.05,1-.77,1H19.86a2.37,2.37,0,0,0-.45,1.69c0,1.27.36,1.6.36,1.6h1.62a.64.64,0,0,1,.7.59.2.2,0,0,1,0,.11v1.67a4,4,0,0,0,1.77.29,6.88,6.88,0,0,0,1.68-.29V26a.73.73,0,0,1,.73-.7,9.89,9.89,0,0,0,1.44-.14s.4-.37.44-1.63-.36-1.64-.36-1.64H26.1a.65.65,0,0,1-.75-.51.5.5,0,0,1,0-.17,11.36,11.36,0,0,1,0-1.65,4.9,4.9,0,0,0-3.25,0C22.08,20.23,22.09,21,22.09,21Z" transform="translate(-1.5 -1.49)"/>
</g> </g>
</svg>`; </svg>`;
} }

View File

@ -33,13 +33,21 @@ namespace pxsim.visuals {
font-family:"Lucida Console", Monaco, monospace; font-family:"Lucida Console", Monaco, monospace;
font-size:8px; font-size:8px;
fill:#fff; fill:#fff;
pointer-events: none; user-select: none; pointer-events: none;
user-select: none;
} }
.sim-text.small { .sim-text.small {
font-size:6px; font-size:6px;
} }
.sim-text.large {
font-size:30px;
}
.sim-text.number {
font-family: Courier, Lato, Work Sans, PT Serif, Source Serif Pro;
font-weight: bold;
}
.sim-text.inverted { .sim-text.inverted {
fill:#000; fill:#5A5A5A;
} }
/* Color Grid */ /* Color Grid */
@ -99,16 +107,9 @@ namespace pxsim.visuals {
private layoutView: LayoutView; private layoutView: LayoutView;
private controlGroup: ViewContainer;
private selectedNode: NodeType;
private selectedPort: number;
private controlView: View;
private cachedControlNodes: { [index: string]: View[] } = {}; private cachedControlNodes: { [index: string]: View[] } = {};
private cachedDisplayViews: { [index: string]: LayoutElement[] } = {}; private cachedDisplayViews: { [index: string]: LayoutElement[] } = {};
private closeGroup: ViewContainer;
private closeIconView: View;
private screenCanvas: HTMLCanvasElement; private screenCanvas: HTMLCanvasElement;
private screenCanvasCtx: CanvasRenderingContext2D; private screenCanvasCtx: CanvasRenderingContext2D;
private screenCanvasData: ImageData; private screenCanvasData: ImageData;
@ -143,7 +144,12 @@ namespace pxsim.visuals {
Runtime.messagePosted = (msg) => { Runtime.messagePosted = (msg) => {
switch (msg.type || "") { switch (msg.type || "") {
case "status": if ((msg as pxsim.SimulatorStateMessage).state == "killed") this.kill(); break; case "status": {
const state = (msg as pxsim.SimulatorStateMessage).state;
if (state == "killed") this.kill();
if (state == "running") this.begin();
break;
}
} }
} }
} }
@ -177,36 +183,6 @@ namespace pxsim.visuals {
this.layoutView.updateTheme(theme); this.layoutView.updateTheme(theme);
} }
public resize() {
const bounds = this.element.getBoundingClientRect();
this.width = bounds.width;
this.height = bounds.height;
this.layoutView.layout(bounds.width, bounds.height);
if (this.selectedNode) {
const scale = this.width / this.closeIconView.getInnerWidth() / 10;
// Translate close icon
this.closeIconView.scale(Math.max(0, Math.min(1, scale)));
const closeIconWidth = this.closeIconView.getWidth();
const closeIconHeight = this.closeIconView.getHeight();
const closeCoords = this.layoutView.getCloseIconCoords(closeIconWidth, closeIconHeight);
this.closeIconView.translate(closeCoords.x, closeCoords.y);
}
if (this.controlView) {
const h = this.controlView.getInnerHeight();
const w = this.controlView.getInnerWidth();
const bh = this.layoutView.getModuleBounds().height - this.closeIconView.getHeight();
const bw = this.layoutView.getModuleBounds().width - (this.width * MODULE_INNER_PADDING_RATIO * 2);
this.controlView.scale(Math.min(bh / h, bw / w), false);
const controlCoords = this.layoutView.getSelectedCoords();
this.controlView.translate(controlCoords.x, controlCoords.y);
}
//this.updateScreen();
}
private getControlForNode(id: NodeType, port: number) { private getControlForNode(id: NodeType, port: number) {
if (this.cachedControlNodes[id] && this.cachedControlNodes[id][port]) { if (this.cachedControlNodes[id] && this.cachedControlNodes[id][port]) {
return this.cachedControlNodes[id][port]; return this.cachedControlNodes[id][port];
@ -237,9 +213,10 @@ namespace pxsim.visuals {
} }
case NodeType.MediumMotor: case NodeType.MediumMotor:
case NodeType.LargeMotor: { case NodeType.LargeMotor: {
// const state = ev3board().getMotor(port)[0]; // TODO: figure out if the motor is in "input" or "output" mode
// view = new MotorInputControl(this.element, this.defs, state, port); const state = ev3board().getMotors()[port];
// break; view = new MotorReporterControl(this.element, this.defs, state, port);
break;
} }
} }
@ -285,6 +262,10 @@ namespace pxsim.visuals {
return undefined; return undefined;
} }
private getCloseIconView() {
return new CloseIconControl(this.element, this.defs, new PortNode(-1), -1);
}
private buildDom() { private buildDom() {
this.wrapper = document.createElement('div'); this.wrapper = document.createElement('div');
this.wrapper.style.display = 'inline'; this.wrapper.style.display = 'inline';
@ -299,25 +280,10 @@ namespace pxsim.visuals {
this.layoutView = new LayoutView(); this.layoutView = new LayoutView();
this.layoutView.inject(this.element); this.layoutView.inject(this.element);
this.controlGroup = new ViewContainer();
this.controlGroup.inject(this.element);
this.closeGroup = new ViewContainer();
this.closeGroup.inject(this.element);
// Add EV3 module element // Add EV3 module element
this.layoutView.setBrick(new BrickView(-1)); this.layoutView.setBrick(new BrickView(-1));
this.closeIconView = new CloseIconControl(this.element, this.defs, new PortNode(-1), -1);
this.closeIconView.registerClick(() => {
this.layoutView.clearSelected();
this.updateState();
})
this.closeGroup.addView(this.closeIconView);
this.closeIconView.setVisible(false);
this.resize(); this.resize();
//this.updateState();
// Add Screen canvas to board // Add Screen canvas to board
this.buildScreenCanvas(); this.buildScreenCanvas();
@ -331,6 +297,17 @@ namespace pxsim.visuals {
}); });
} }
public resize() {
if (!this.element) return;
this.width = document.body.offsetWidth;
this.height = document.body.offsetHeight;
this.layoutView.layout(this.width, this.height);
this.updateState();
let state = ev3board().screenState;
this.updateScreenStep(state);
}
private buildScreenCanvas() { private buildScreenCanvas() {
this.screenCanvas = document.createElement("canvas"); this.screenCanvas = document.createElement("canvas");
this.screenCanvas.id = "board-screen-canvas"; this.screenCanvas.id = "board-screen-canvas";
@ -357,21 +334,60 @@ namespace pxsim.visuals {
} }
private kill() { private kill() {
if (this.lastAnimationId) cancelAnimationFrame(this.lastAnimationId); this.running = false;
if (this.lastAnimationIds.length > 0) {
this.lastAnimationIds.forEach(animationId => {
cancelAnimationFrame(animationId);
})
}
// Save previous inputs for the next cycle
EV3View.previousSelectedInputs = ev3board().getInputNodes().map((node, index) => (this.getDisplayViewForNode(node.id, index).getSelected()) ? node.id : -1)
EV3View.previousSeletedOutputs = ev3board().getMotors().map((node, index) => (this.getDisplayViewForNode(node.id, index).getSelected()) ? node.id : -1);
} }
private lastAnimationId: number; private static previousSelectedInputs: number[];
private static previousSeletedOutputs: number[];
private static isPreviousInputSelected(index: number, id: number) {
if (EV3View.previousSelectedInputs && EV3View.previousSelectedInputs[index] == id) {
EV3View.previousSelectedInputs[index] = undefined;
return true;
}
return false;
}
private static isPreviousOutputSelected(index: number, id: number) {
if (EV3View.previousSeletedOutputs && EV3View.previousSeletedOutputs[index] == id) {
EV3View.previousSeletedOutputs[index] = undefined;
return true;
}
return false;
}
private begin() {
this.running = true;
this.updateState();
}
private running: boolean = false;
private lastAnimationIds: number[] = [];
public updateState() { public updateState() {
if (this.lastAnimationId) cancelAnimationFrame(this.lastAnimationId); if (this.lastAnimationIds.length > 0) {
this.lastAnimationIds.forEach(animationId => {
cancelAnimationFrame(animationId);
})
}
if (!this.running) return;
const fps = GAME_LOOP_FPS; const fps = GAME_LOOP_FPS;
let now; let now;
let then = Date.now(); let then = pxsim.U.now();
let interval = 1000 / fps; let interval = 1000 / fps;
let delta; let delta;
let that = this; let that = this;
function loop() { function loop() {
that.lastAnimationId = requestAnimationFrame(loop); const animationId = requestAnimationFrame(loop);
now = Date.now(); that.lastAnimationIds.push(animationId);
now = pxsim.U.now();
delta = now - then; delta = now - then;
if (delta > interval) { if (delta > interval) {
then = now; then = now;
@ -382,67 +398,50 @@ namespace pxsim.visuals {
} }
private updateStateStep(elapsed: number) { private updateStateStep(elapsed: number) {
const selected = this.layoutView.getSelected();
let selectedChanged = false;
const inputNodes = ev3board().getInputNodes(); const inputNodes = ev3board().getInputNodes();
inputNodes.forEach((node, index) => { inputNodes.forEach((node, index) => {
node.updateState(elapsed); node.updateState(elapsed);
if (!node.didChange()) return;
const view = this.getDisplayViewForNode(node.id, index); const view = this.getDisplayViewForNode(node.id, index);
if (!node.didChange() && !view.didChange()) return;
if (view) { if (view) {
this.layoutView.setInput(index, view); const isSelected = EV3View.isPreviousInputSelected(index, node.id) || view.getSelected();
if (isSelected && !view.getSelected()) view.setSelected(true);
const control = isSelected ? this.getControlForNode(node.id, index) : undefined;
const closeIcon = control ? this.getCloseIconView() : undefined;
this.layoutView.setInput(index, view, control, closeIcon);
view.updateState(); view.updateState();
if (selected == view) selectedChanged = true; if (control) control.updateState();
} }
}); });
const brickNode = ev3board().getBrickNode(); const brickNode = ev3board().getBrickNode();
if (brickNode.didChange()) { if (brickNode.didChange()) {
this.getDisplayViewForNode(ev3board().getBrickNode().id, -1).updateState(); this.getDisplayViewForNode(brickNode.id, -1).updateState();
} }
const outputNodes = ev3board().getMotors(); const outputNodes = ev3board().getMotors();
outputNodes.forEach((node, index) => { outputNodes.forEach((node, index) => {
node.updateState(elapsed); node.updateState(elapsed);
if (!node.didChange()) return;
const view = this.getDisplayViewForNode(node.id, index); const view = this.getDisplayViewForNode(node.id, index);
if (!node.didChange() && !view.didChange()) return;
if (view) { if (view) {
this.layoutView.setOutput(index, view); const isSelected = EV3View.isPreviousOutputSelected(index, node.id) || view.getSelected();
if (isSelected && !view.getSelected()) view.setSelected(true);
const control = isSelected ? this.getControlForNode(node.id, index) : undefined;
const closeIcon = control ? this.getCloseIconView() : undefined;
this.layoutView.setOutput(index, view, control, closeIcon);
view.updateState(); view.updateState();
if (selected == view) selectedChanged = true; if (control) control.updateState();
} }
}); });
if (selected && (selected.getId() !== this.selectedNode || selected.getPort() !== this.selectedPort)) {
this.selectedNode = selected.getId();
this.selectedPort = selected.getPort();
this.controlGroup.clear();
const control = this.getControlForNode(this.selectedNode, selected.getPort());
if (control) {
this.controlView = control;
this.controlGroup.addView(control);
}
this.closeIconView.setVisible(true);
this.resize();
} else if (!selected) {
this.controlGroup.clear();
this.controlView = undefined;
this.selectedNode = undefined;
this.selectedPort = undefined;
this.closeIconView.setVisible(false);
}
if (selectedChanged && selected) {
this.controlView.updateState();
}
this.updateScreenStep();
}
private updateScreenStep() {
let state = ev3board().screenState; let state = ev3board().screenState;
if (!state.didChange()) return; if (state.didChange()) {
this.updateScreenStep(state);
}
}
private updateScreenStep(state: EV3ScreenState) {
const bBox = this.layoutView.getBrick().getScreenBBox(); const bBox = this.layoutView.getBrick().getScreenBBox();
if (!bBox || bBox.width == 0) return; if (!bBox || bBox.width == 0) return;

View File

@ -1,17 +1,20 @@
/// <reference path="./nodes/staticView.ts" /> /// <reference path="./nodes/moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export const CONTROL_WIDTH = 87.5; export const CONTROL_WIDTH = 87.5;
export const CONTROL_HEIGHT = 175; export const CONTROL_HEIGHT = 175;
export const CONTROL_TEXT_COLOR = '#000';
export abstract class ControlView<T extends BaseNode> extends SimView<T> implements LayoutElement { export abstract class ControlView<T extends BaseNode> extends SimView<T> implements LayoutElement {
private background: SVGSVGElement; protected content: SVGSVGElement;
abstract getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement): SVGElement; abstract getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement): SVGElement;
constructor(protected parent: SVGSVGElement, protected globalDefs: SVGDefsElement, protected state: T, protected port: number) { constructor(protected parent: SVGSVGElement, protected globalDefs: SVGDefsElement, protected state: T, protected port: number) {
super(state); super(state);
} }
getInnerWidth(): number { getInnerWidth(): number {
@ -34,18 +37,39 @@ namespace pxsim.visuals {
return false; return false;
} }
buildDom(width: number): SVGElement { buildDom(): SVGElement {
this.background = svg.elt("svg", { height: "100%", width: "100%"}) as SVGSVGElement; this.content = svg.elt("svg", { viewBox: `0 0 ${this.getInnerWidth()} ${this.getInnerHeight()}` }) as SVGSVGElement;
this.background.appendChild(this.getInnerView(this.parent, this.globalDefs)); this.content.appendChild(this.getInnerView(this.parent, this.globalDefs));
return this.background; return this.content;
}
public resize(width: number, height: number) {
super.resize(width, height);
this.updateDimensions(width, height);
}
private updateDimensions(width: number, height: number) {
if (this.content) {
const currentWidth = this.getInnerWidth();
const currentHeight = this.getInnerHeight();
const newHeight = currentHeight / currentWidth * width;
const newWidth = currentWidth / currentHeight * height;
if (newHeight > height) {
// scale width instead
this.content.setAttribute('width', `${newWidth}`);
this.content.setAttribute('height', `${height}`);
// translate to the middle (width)
this.translate(width / 2 - newWidth / 2, 0);
} else {
this.content.setAttribute('width', `${width}`);
this.content.setAttribute('height', `${newHeight}`);
// translate to the middle (height)
this.translate(0, height / 2 - newHeight / 2);
}
}
} }
onComponentVisible() { onComponentVisible() {
}
getWeight() {
return 0;
} }
} }
} }

View File

@ -17,6 +17,17 @@ namespace pxsim.visuals {
return this.closeGroup; return this.closeGroup;
} }
buildDom(): SVGElement {
this.content = svg.elt("svg", { width: "100%", height: "100%"}) as SVGSVGElement;
this.content.appendChild(this.getInnerView());
return this.content;
}
public resize(width: number, height: number) {
super.resize(width, height);
}
public getInnerHeight() { public getInnerHeight() {
return 32; return 32;
} }

View File

@ -7,35 +7,44 @@ namespace pxsim.visuals {
getInnerView() { getInnerView() {
this.group = svg.elt("g") as SVGGElement; this.group = svg.elt("g") as SVGGElement;
this.group.setAttribute("transform", `translate(17, ${35 + this.getHeight() / 4}) scale(5)`) this.group.setAttribute("transform", `translate(1.02, 1.5) scale(0.8)`)
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey']; const colorIds = ['red', 'yellow', 'blue', 'green', undefined, 'grey'];
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00']; const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', undefined, '#6c2d00'];
const colorValue = [5, 4, 2, 3, 1, 7]; const colorValue = [5, 4, 2, 3, 1, 7];
let cy = -4; let cy = -4;
for (let c = 0; c < colorIds.length; c++) { for (let c = 0; c < colorIds.length; c++) {
const cx = c % 2 == 0 ? 2.2 : 8.2; const cx = c % 2 == 0 ? 2.2 : 8.2;
if (c % 2 == 0) cy += 5; if (c % 2 == 0) cy += 5;
if (colorIds[c]) {
const circle = pxsim.svg.child(this.group, "circle", { 'class': 'sim-color-grid-circle', 'cx': cx, 'cy': cy, 'r': '2', 'style': `fill: ${colors[c]}` }); const circle = pxsim.svg.child(this.group, "circle", { 'class': 'sim-color-grid-circle', 'cx': cx, 'cy': cy, 'r': '2', 'style': `fill: ${colors[c]}` });
circle.addEventListener(pointerEvents.down, ev => { circle.addEventListener(pointerEvents.down, ev => {
this.setColor(colorValue[c]); this.setColor(colorValue[c]);
}) })
} }
}
const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' }); const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' });
pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle', 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: #fff` }); pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle', 'cx': 2.2, 'cy': '11', 'r': '2', 'style': `fill: #fff` });
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.5px` }); pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '11', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.1px` });
whiteCircleWrapper.addEventListener(pointerEvents.down, ev => { whiteCircleWrapper.addEventListener(pointerEvents.down, ev => {
this.setColor(6); this.setColor(6);
}) })
return this.group; return this.group;
} }
getInnerWidth() {
return 10.2;
}
getInnerHeight() {
return 15;
}
private setColor(color: number) { private setColor(color: number) {
const state = this.state; const state = this.state;
state.setColor(color); state.setColor(color);
} }
} }
} }

View File

@ -10,7 +10,7 @@ namespace pxsim.visuals {
getInnerView(parent: SVGSVGElement) { getInnerView(parent: SVGSVGElement) {
this.defs = <SVGDefsElement>svg.child(this.element, "defs", {}); this.defs = <SVGDefsElement>svg.child(this.element, "defs", {});
this.group = svg.elt("g") as SVGGElement; this.group = svg.elt("g") as SVGGElement;
this.group.setAttribute("transform", `translate(12, ${this.getHeight() / 2 - 15}) scale(2.5)`) this.group.setAttribute("transform", `translate(12, 0) scale(2)`)
let gc = "gradient-color"; let gc = "gradient-color";
this.colorGradient = svg.linearGradient(this.defs, gc, true); this.colorGradient = svg.linearGradient(this.defs, gc, true);
@ -53,6 +53,14 @@ namespace pxsim.visuals {
return this.group; return this.group;
} }
getInnerWidth() {
return CONTROL_WIDTH;
}
getInnerHeight() {
return CONTROL_WIDTH;
}
updateState() { updateState() {
if (!this.visible) { if (!this.visible) {
return; return;

View File

@ -7,33 +7,38 @@ namespace pxsim.visuals {
private gradient: SVGLinearGradientElement; private gradient: SVGLinearGradientElement;
private slider: SVGGElement; private slider: SVGGElement;
private static SLIDER_HANDLE_HEIGHT = 31; private reporter: SVGTextElement;
private isVisible = false; private static SLIDER_HANDLE_HEIGHT = 26;
private static SLIDER_SIDE_PADDING = 6;
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) { getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
let gid = "gradient-slider-" + this.getId(); let gid = "gradient-slider-" + this.getId();
this.group = svg.elt("g") as SVGGElement; this.group = svg.elt("g") as SVGGElement;
this.gradient = createGradient(gid, this.getGradientDefinition()); this.gradient = createGradient(gid, this.getGradientDefinition());
this.gradient.setAttribute('x1', '-438.37'); this.gradient.setAttribute('x1', '0%');
this.gradient.setAttribute('y1', '419.43'); this.gradient.setAttribute('y1', '0%');
this.gradient.setAttribute('x2', '-438.37'); this.gradient.setAttribute('x2', '0%');
this.gradient.setAttribute('y2', '418.43'); this.gradient.setAttribute('y2', '100%');
this.gradient.setAttribute('gradientTransform', 'matrix(50, 0, 0, -110, 21949.45, 46137.67)'); // this.gradient.setAttribute('gradientTransform', 'matrix(50, 0, 0, -110, 21949.45, 46137.67)');
this.gradient.setAttribute('gradientUnits', 'userSpaceOnUse'); // this.gradient.setAttribute('gradientUnits', 'userSpaceOnUse');
globalDefs.appendChild(this.gradient); globalDefs.appendChild(this.gradient);
this.group = svg.elt("g") as SVGGElement; this.group = svg.elt("g") as SVGGElement;
const sliderGroup = pxsim.svg.child(this.group, "g"); const reporterGroup = pxsim.svg.child(this.group, "g");
sliderGroup.setAttribute("transform", `translate(0, ${10 + this.getTopPadding()})`) reporterGroup.setAttribute("transform", `translate(31, 42)`);
this.reporter = pxsim.svg.child(reporterGroup, "text", { 'x': 0, 'y': '0', 'class': 'sim-text number large inverted' }) as SVGTextElement;
const rect = pxsim.svg.child(sliderGroup, "rect", { 'x': this.getLeftPadding(), 'y': 2, 'width': this.getWidth() - this.getLeftPadding() * 2, 'height': this.getContentHeight(), 'style': `fill: url(#${gid})` }); const sliderGroup = pxsim.svg.child(this.group, "g");
sliderGroup.setAttribute("transform", `translate(${this.getWidth() / 2 - this.getSliderWidth() / 2}, ${this.getReporterHeight()})`)
const rect = pxsim.svg.child(sliderGroup, "rect", { 'x': DistanceSliderControl.SLIDER_SIDE_PADDING, 'y': 2, 'width': this.getSliderWidth() - DistanceSliderControl.SLIDER_SIDE_PADDING * 2, 'height': this.getSliderHeight(), 'style': `fill: url(#${gid})` });
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement; this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
const sliderInner = pxsim.svg.child(this.slider, "g"); const sliderInner = pxsim.svg.child(this.slider, "g");
pxsim.svg.child(sliderInner, "rect", { 'width': this.getWidth(), 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT, 'rx': '2', 'ry': '2', 'style': 'fill: #f12a21' }); pxsim.svg.child(sliderInner, "rect", { 'width': this.getSliderWidth(), 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT, 'rx': '2', 'ry': '2', 'style': 'fill: #f12a21' });
pxsim.svg.child(sliderInner, "rect", { 'x': '0.5', 'y': '0.5', 'width': this.getWidth() - 1, 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT - 1, 'rx': '1.5', 'ry': '1.5', 'style': 'fill: none;stroke: #b32e29' }); pxsim.svg.child(sliderInner, "rect", { 'x': '0.5', 'y': '0.5', 'width': this.getSliderWidth() - 1, 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT - 1, 'rx': '1.5', 'ry': '1.5', 'style': 'fill: none;stroke: #b32e29' });
const dragSurface = svg.child(this.group, "rect", { const dragSurface = svg.child(this.group, "rect", {
x: 0, x: 0,
@ -66,41 +71,43 @@ namespace pxsim.visuals {
return this.group; return this.group;
} }
private getLeftPadding() { getInnerHeight() {
return this.getInnerWidth() * 0.12; return 192;
} }
private getTopPadding() { getInnerWidth() {
return this.getInnerHeight() / 4; return 111;
} }
private getContentHeight() { private getReporterHeight() {
return this.getInnerHeight() * 0.6; return 50;
}
private getSliderHeight() {
return 110;
}
private getSliderWidth() {
return 62;
} }
updateState() { updateState() {
if (!this.isVisible) { if (!this.visible) {
return; return;
} }
const node = this.state; const node = this.state;
const percentage = node.getValue() / 10; /* convert back to cm */ const percentage = node.getValue() / 10; /* convert back to cm */
const y = this.getContentHeight() * percentage / this.getMax(); const y = this.getSliderHeight() * percentage / this.getMax();
this.slider.setAttribute("transform", `translate(0, ${y - DistanceSliderControl.SLIDER_HANDLE_HEIGHT / 2})`); this.slider.setAttribute("transform", `translate(0, ${y - DistanceSliderControl.SLIDER_HANDLE_HEIGHT / 2})`);
} // Update reporter text
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}`;
onComponentVisible() {
super.onComponentVisible();
this.isVisible = true;
}
onComponentHidden() {
this.isVisible = false;
} }
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) { private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
let cur = svg.cursorPoint(pt, parent, ev); let cur = svg.cursorPoint(pt, parent, ev);
const height = this.getContentHeight(); //DistanceSliderControl.SLIDER_HEIGHT; const height = this.getSliderHeight();
let t = Math.max(0, Math.min(1, (this.getTopPadding() + height + this.top / this.scaleFactor - cur.y / this.scaleFactor) / height)) const bBox = this.content.getBoundingClientRect();
let t = Math.max(0, Math.min(1, (DistanceSliderControl.SLIDER_HANDLE_HEIGHT + height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height))
const state = this.state; const state = this.state;
state.setDistance((1 - t) * (this.getMax())); state.setDistance((1 - t) * (this.getMax()));
@ -118,7 +125,7 @@ namespace pxsim.visuals {
return { return {
stops: [ stops: [
{ offset: 0, color: '#626262' }, { offset: 0, color: '#626262' },
{ offset: 1, color: "#ddd" } { offset: 100, color: "#ddd" }
] ]
}; };
} }

View File

@ -0,0 +1,60 @@
namespace pxsim.visuals {
export class MotorReporterControl extends ControlView<MotorNode> {
private group: SVGGElement;
private circleBar: SVGCircleElement;
private reporter: SVGTextElement;
getInnerView() {
this.group = svg.elt("g") as SVGGElement;
const outerCircle = pxsim.svg.child(this.group, "circle", {
'stroke-dasharray': '565.48', 'stroke-dashoffset': '0',
'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 1s linear;`,
'stroke': '#a8aaa8', 'stroke-width': '1rem' }) as SVGCircleElement;
this.circleBar = pxsim.svg.child(this.group, "circle", {
'stroke-dasharray': '565.48', 'stroke-dashoffset': '0',
'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 1s linear;`,
'stroke': '#f12a21', 'stroke-width': '1rem' }) as SVGCircleElement;
this.reporter = pxsim.svg.child(this.group, "text", {
'x': this.getWidth() / 2, 'y': this.getHeight() / 2,
'text-anchor': 'middle', 'alignment-baseline': 'middle',
'style': 'font-size: 50px',
'class': 'sim-text inverted number' }) as SVGTextElement;
return this.group;
}
getInnerWidth() {
return 200;
}
getInnerHeight() {
return 200;
}
updateState() {
if (!this.visible) {
return;
}
const node = this.state;
const speed = node.getSpeed();
this.updateSpeed(speed);
// Update reporter
this.reporter.textContent = `${speed}`;
}
private updateSpeed(speed: number) {
let c = Math.PI * (90 * 2);
speed = Math.abs(speed);
let pct = ((100 - speed) / 100) * c;
this.circleBar.setAttribute('stroke-dashoffset', `${pct}`);
}
}
}

View File

@ -6,8 +6,6 @@ namespace pxsim.visuals {
private group: SVGGElement; private group: SVGGElement;
private slider: SVGGElement; private slider: SVGGElement;
private isVisible = false;
private static SLIDER_WIDTH = 70; private static SLIDER_WIDTH = 70;
private static SLIDER_HEIGHT = 78; private static SLIDER_HEIGHT = 78;
@ -61,7 +59,7 @@ namespace pxsim.visuals {
} }
updateState() { updateState() {
if (!this.isVisible) { if (!this.visible) {
return; return;
} }
const node = this.state; const node = this.state;
@ -71,19 +69,11 @@ namespace pxsim.visuals {
this.slider.setAttribute("transform", `translate(${x}, ${y})`); this.slider.setAttribute("transform", `translate(${x}, ${y})`);
} }
onComponentVisible() {
super.onComponentVisible();
this.isVisible = true;
}
onComponentHidden() {
this.isVisible = false;
}
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) { private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
let cur = svg.cursorPoint(pt, parent, ev); let cur = svg.cursorPoint(pt, parent, ev);
const width = CONTROL_WIDTH; //DistanceSliderControl.SLIDER_HEIGHT; const width = CONTROL_WIDTH; //DistanceSliderControl.SLIDER_HEIGHT;
let t = Math.max(0, Math.min(1, (width + this.left / this.scaleFactor - cur.x / this.scaleFactor) / width)) const bBox = this.content.getBoundingClientRect();
let t = Math.max(0, Math.min(1, (width + bBox.left / this.scaleFactor - cur.x / this.scaleFactor) / width))
const state = this.state; const state = this.state;
state.setAngle((1 - t) * (100)); state.setAngle((1 - t) * (100));

View File

@ -1,67 +1,56 @@
/// <reference path="./view.ts" /> /// <reference path="./view.ts" />
/// <reference path="./nodes/staticView.ts" /> /// <reference path="./nodes/moduleView.ts" />
/// <reference path="./nodes/portView.ts" /> /// <reference path="./nodes/portView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export const DEFAULT_WIDTH = 350;
export const DEFAULT_HEIGHT = 700;
export const BRICK_HEIGHT_RATIO = 1 / 3; export const BRICK_HEIGHT_RATIO = 1 / 3;
export const MODULE_AND_WIRING_HEIGHT_RATIO = 1 / 3; // For inputs and outputs export const MODULE_AND_WIRING_HEIGHT_RATIO = 1 / 3; // For inputs and outputs
export const MODULE_HEIGHT_RATIO = MODULE_AND_WIRING_HEIGHT_RATIO * 3 / 4; export const MODULE_HEIGHT_RATIO = MODULE_AND_WIRING_HEIGHT_RATIO * 4 / 5;
export const WIRING_HEIGHT_RATIO = MODULE_AND_WIRING_HEIGHT_RATIO / 4; export const WIRING_HEIGHT_RATIO = MODULE_AND_WIRING_HEIGHT_RATIO / 5;
export const MODULE_INNER_PADDING_RATIO = 1 / 35; export const MODULE_INNER_PADDING_RATIO = 1 / 35;
export const MAX_MODULE_WIDTH = 100;
export interface LayoutElement extends View { export interface LayoutElement extends View {
getId(): number; getId(): number;
getPort(): number; getPort(): number;
getPaddingRatio(): number; getPaddingRatio(): number;
getWiringRatio(): number; getWiringRatio(): number;
setSelected(selected: boolean): void;
} }
export class LayoutView extends ViewContainer { export class LayoutView extends ViewContainer {
private inputs: LayoutElement[] = []; private inputs: LayoutElement[] = [];
private outputs: LayoutElement[] = []; private outputs: LayoutElement[] = [];
private inputContainers: ViewContainer[] = [];
private outputContainers: ViewContainer[] = [];
private inputControls: View[] = [];
private outputControls: View[] = [];
private inputCloseIcons: View[] = [];
private outputCloseIcons: View[] = [];
private inputWires: WireView[] = []; private inputWires: WireView[] = [];
private outputWires: WireView[] = []; private outputWires: WireView[] = [];
private selected: number;
private selectedIsInput: boolean;
private brick: BrickView; private brick: BrickView;
private offsets: number[]; private offsets: number[];
private contentGroup: SVGGElement; private contentGroup: SVGGElement;
private scrollGroup: SVGGElement; private scrollGroup: SVGGElement;
private renderedViews: Map<boolean> = {}; private renderedViews: Map<boolean> = {};
private childScaleFactor: number;
private totalLength: number;
private height: number;
private hasDimensions = false; private hasDimensions = false;
constructor() { constructor() {
super(); super();
this.outputs = [ this.outputContainers = [new ViewContainer(), new ViewContainer, new ViewContainer(), new ViewContainer()];
new PortView(0, 'A'), this.inputContainers = [new ViewContainer(), new ViewContainer, new ViewContainer(), new ViewContainer()];
new PortView(1, 'B'),
new PortView(2, 'C'),
new PortView(3, 'D')
];
this.brick = new BrickView(0); this.brick = new BrickView(0);
this.inputs = [
new PortView(0, '1'),
new PortView(1, '2'),
new PortView(2, '3'),
new PortView(3, '4')
];
for (let port = 0; port < DAL.NUM_OUTPUTS; port++) { for (let port = 0; port < DAL.NUM_OUTPUTS; port++) {
this.outputWires[port] = new WireView(port); this.outputWires[port] = new WireView(port);
} }
@ -72,8 +61,7 @@ namespace pxsim.visuals {
public layout(width: number, height: number) { public layout(width: number, height: number) {
this.hasDimensions = true; this.hasDimensions = true;
this.width = width; this.resize(width, height);
this.height = height;
this.scrollGroup.setAttribute("width", width.toString()); this.scrollGroup.setAttribute("width", width.toString());
this.scrollGroup.setAttribute("height", height.toString()); this.scrollGroup.setAttribute("height", height.toString());
this.position(); this.position();
@ -81,6 +69,7 @@ namespace pxsim.visuals {
public setBrick(brick: BrickView) { public setBrick(brick: BrickView) {
this.brick = brick; this.brick = brick;
this.brick.inject(this.scrollGroup);
this.position(); this.position();
} }
@ -88,55 +77,112 @@ namespace pxsim.visuals {
return this.brick; return this.brick;
} }
public setInput(port: number, child: LayoutElement) { public setInput(port: number, view: LayoutElement, control?: View, closeIcon?: View) {
if (this.inputs[port] != view || this.inputControls[port] != control) {
if (this.inputs[port]) { if (this.inputs[port]) {
// Remove current input // Remove current input
this.inputs[port].dispose(); this.inputs[port].dispose();
} }
this.inputs[port] = child; this.inputs[port] = view;
if (this.inputControls[port]) {
this.inputControls[port].dispose();
}
this.inputControls[port] = control;
this.inputCloseIcons[port] = closeIcon;
this.inputContainers[port].clear();
this.inputContainers[port].addView(view);
if (control) this.inputContainers[port].addView(control);
if (view.hasClick()) view.registerClick((ev: any) => {
view.setSelected(true);
runtime.queueDisplayUpdate();
}, true);
if (control && closeIcon) {
this.inputContainers[port].addView(closeIcon);
closeIcon.registerClick(() => {
// Clear selection
view.setSelected(false);
runtime.queueDisplayUpdate();
})
}
}
this.position(); this.position();
} }
public setOutput(port: number, child: LayoutElement) { public setOutput(port: number, view: LayoutElement, control?: View, closeIcon?: View) {
if (this.outputs[port] != view || this.outputControls[port] != control) {
if (this.outputs[port]) { if (this.outputs[port]) {
// Remove current input // Remove current output
this.outputs[port].dispose(); this.outputs[port].dispose();
} }
this.outputs[port] = child; this.outputs[port] = view;
if (this.outputControls[port]) {
this.outputControls[port].dispose();
}
this.outputControls[port] = control;
this.outputCloseIcons[port] = closeIcon;
this.outputContainers[port].clear();
this.outputContainers[port].addView(view);
if (control) this.outputContainers[port].addView(control);
if (view.hasClick()) view.registerClick((ev: any) => {
view.setSelected(true);
runtime.queueDisplayUpdate();
}, true)
if (control && closeIcon) {
this.outputContainers[port].addView(closeIcon);
closeIcon.registerClick(() => {
// Clear selection
view.setSelected(false);
runtime.queueDisplayUpdate();
})
}
}
this.position(); this.position();
} }
public onClick(index: number, input: boolean, ev: any) { protected buildDom() {
this.setSelected(index, input);
}
public clearSelected() {
this.selected = undefined;
this.selectedIsInput = undefined;
}
public setSelected(index: number, input?: boolean) {
if (index !== this.selected || input !== this.selectedIsInput) {
this.selected = index;
this.selectedIsInput = input;
const node = this.getSelected();
if (node) node.setSelected(true);
//this.redoPositioning();
runtime.queueDisplayUpdate();
}
}
public getSelected() {
if (this.selected !== undefined) {
return this.selectedIsInput ? this.inputs[this.selected] : this.outputs[this.selected];
}
return undefined;
}
protected buildDom(width: number) {
this.contentGroup = svg.elt("g") as SVGGElement; this.contentGroup = svg.elt("g") as SVGGElement;
this.scrollGroup = svg.child(this.contentGroup, "g") as SVGGElement; this.scrollGroup = svg.child(this.contentGroup, "g") as SVGGElement;
this.inputs = [];
this.outputs = [];
this.inputControls = [];
this.outputControls = [];
// Inject all wires
for (let port = 0; port < DAL.NUM_OUTPUTS; port++) {
this.outputWires[port].inject(this.scrollGroup);
}
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
this.inputWires[port].inject(this.scrollGroup);
}
// Inject all view containers
for (let i = 0; i < 4; i++) {
this.inputContainers[i].inject(this.scrollGroup);
this.outputContainers[i].inject(this.scrollGroup);
}
// Inject all ports
this.setInput(0, new PortView(0, 'A'));
this.setInput(1, new PortView(1, 'B'));
this.setInput(2, new PortView(2, 'C'));
this.setInput(3, new PortView(3, 'D'));
this.setOutput(0, new PortView(0, '1'));
this.setOutput(1, new PortView(1, '2'));
this.setOutput(2, new PortView(2, '3'));
this.setOutput(3, new PortView(3, '4'));
return this.contentGroup; return this.contentGroup;
} }
@ -171,34 +217,63 @@ namespace pxsim.visuals {
this.offsets = []; this.offsets = [];
const selectedNode = this.getSelected(); const contentWidth = this.width;
if (!contentWidth) return;
const contentHeight = this.height;
if (!contentHeight) return;
const contentWidth = this.width || DEFAULT_WIDTH; const noConnections = this.outputs.concat(this.inputs).filter(m => m.getId() != NodeType.Port).length == 0;
const contentHeight = this.height || DEFAULT_HEIGHT;
if (noConnections) {
// No connections render the entire board
this.brick.resize(contentWidth, contentHeight);
this.brick.translate(0, 0);
// Hide all other connections
this.outputs.concat(this.inputs).forEach(m => m.setVisible(false));
return;
} else {
this.outputs.concat(this.inputs).forEach(m => m.setVisible(true));
}
const moduleHeight = this.getModuleHeight(); const moduleHeight = this.getModuleHeight();
const brickHeight = this.getBrickHeight(); const brickHeight = this.getBrickHeight();
this.brick.inject(this.scrollGroup);
const brickWidth = this.brick.getInnerWidth() / this.brick.getInnerHeight() * brickHeight; const brickWidth = this.brick.getInnerWidth() / this.brick.getInnerHeight() * brickHeight;
const brickPadding = (contentWidth - brickWidth) / 2; const brickPadding = (contentWidth - brickWidth) / 2;
const modulePadding = contentWidth / 35; const modulePadding = this.getModulePadding();
const moduleSpacing = contentWidth / 4; const moduleSpacing = contentWidth / 4;
const moduleWidth = moduleSpacing - (modulePadding * 2); const moduleWidth = this.getInnerModuleWidth();
let currentX = modulePadding; let currentX = this.getModulePadding();
let currentY = 0; let currentY = 0;
this.outputs.forEach((n, i) => { this.outputs.forEach((n, i) => {
const outputPadding = moduleWidth * n.getPaddingRatio(); this.outputContainers[i].translate(currentX, currentY);
const outputWidth = moduleWidth - outputPadding * 2; if (this.outputs[i]) {
n.inject(this.scrollGroup, outputWidth); const view = this.outputs[i];
n.resize(outputWidth); const outputPadding = this.getInnerModuleWidth() * view.getPaddingRatio();
const nHeight = n.getHeight() / n.getWidth() * outputWidth; const desiredOutputWidth = this.getInnerModuleWidth() - outputPadding * 2;
n.translate(currentX + outputPadding, currentY + moduleHeight - nHeight); const outputWidth = Math.min(desiredOutputWidth, MAX_MODULE_WIDTH);
n.setSelected(n == selectedNode); const outputHeight = this.getModuleHeight();
if (n.hasClick()) n.registerClick((ev: any) => {
this.onClick(i, false, ev); // Translate and resize view
}) view.resize(outputWidth, outputHeight);
const viewHeight = view.getInnerHeight() / view.getInnerWidth() * outputWidth;
view.translate(outputPadding + ((desiredOutputWidth - outputWidth) / 2), outputHeight - viewHeight, true);
// Resize control
const control = this.outputControls[i];
if (control) {
control.resize(this.getInnerModuleWidth(), outputHeight);
// Translate close icon
const closeIcon = this.outputCloseIcons[i];
if (closeIcon) {
const closeIconWidth = closeIcon.getWidth();
closeIcon.translate(this.getInnerModuleWidth() / 2 - closeIconWidth / 2, 0);
}
}
}
currentX += moduleSpacing; currentX += moduleSpacing;
}) })
@ -206,7 +281,7 @@ namespace pxsim.visuals {
currentY = moduleHeight; currentY = moduleHeight;
const wireBrickSpacing = brickWidth / 5; const wireBrickSpacing = brickWidth / 5;
const wiringYPadding = 10; const wiringYPadding = 5;
let wireStartX = 0; let wireStartX = 0;
let wireEndX = brickPadding + wireBrickSpacing; let wireEndX = brickPadding + wireBrickSpacing;
let wireEndY = currentY + this.getWiringHeight() + wiringYPadding; let wireEndY = currentY + this.getWiringHeight() + wiringYPadding;
@ -214,7 +289,6 @@ namespace pxsim.visuals {
// Draw output lines // Draw output lines
for (let port = 0; port < DAL.NUM_OUTPUTS; port++) { for (let port = 0; port < DAL.NUM_OUTPUTS; port++) {
if (!this.outputWires[port].isRendered()) this.outputWires[port].inject(this.scrollGroup);
this.outputWires[port].updateDimensions(wireStartX + moduleSpacing * this.outputs[port].getWiringRatio(), wireStartY, wireEndX, wireEndY); this.outputWires[port].updateDimensions(wireStartX + moduleSpacing * this.outputs[port].getWiringRatio(), wireStartY, wireEndX, wireEndY);
this.outputWires[port].setSelected(this.outputs[port].getId() == NodeType.Port); this.outputWires[port].setSelected(this.outputs[port].getId() == NodeType.Port);
wireStartX += moduleSpacing; wireStartX += moduleSpacing;
@ -225,22 +299,39 @@ namespace pxsim.visuals {
currentY += this.getWiringHeight(); currentY += this.getWiringHeight();
// Render the brick in the middle // Render the brick in the middle
this.brick.resize(brickWidth); this.brick.resize(brickWidth, brickHeight);
this.brick.translate(currentX, currentY); this.brick.translate(currentX, currentY);
currentX = modulePadding; currentX = modulePadding;
currentY += brickHeight + this.getWiringHeight(); currentY += brickHeight + this.getWiringHeight();
this.inputs.forEach((n, i) => { this.inputs.forEach((n, i) => {
const inputPadding = moduleWidth * n.getPaddingRatio(); this.inputContainers[i].translate(currentX, currentY);
const inputWidth = moduleWidth - inputPadding * 2; if (this.inputs[i]) {
n.inject(this.scrollGroup, inputWidth); const view = this.inputs[i];
n.resize(inputWidth); const inputPadding = this.getInnerModuleWidth() * view.getPaddingRatio();
n.translate(currentX + inputPadding, currentY); const desiredInputWidth = this.getInnerModuleWidth() - inputPadding * 2;
n.setSelected(n == selectedNode); const inputWidth = Math.min(desiredInputWidth, MAX_MODULE_WIDTH);
if (n.hasClick()) n.registerClick((ev: any) => { const inputHeight = this.getModuleHeight();
this.onClick(i, true, ev);
}) // Translate and resize view
view.resize(inputWidth, inputHeight);
view.translate(inputPadding + ((desiredInputWidth - inputWidth) / 2), 0, true);
// Resize control
const control = this.inputControls[i];
if (control) {
control.resize(this.getInnerModuleWidth(), inputHeight);
// Translate and resize close icon
const closeIcon = this.inputCloseIcons[i];
if (closeIcon) {
const closeIconWidth = closeIcon.getWidth();
const closeIconHeight = closeIcon.getHeight();
closeIcon.translate(this.getInnerModuleWidth() / 2 - closeIconWidth / 2, this.getModuleHeight() - closeIconHeight);
}
}
}
currentX += moduleSpacing; currentX += moduleSpacing;
}) })
@ -251,7 +342,6 @@ namespace pxsim.visuals {
// Draw input lines // Draw input lines
for (let port = 0; port < DAL.NUM_INPUTS; port++) { for (let port = 0; port < DAL.NUM_INPUTS; port++) {
if (!this.inputWires[port].isRendered()) this.inputWires[port].inject(this.scrollGroup);
this.inputWires[port].updateDimensions(wireStartX, wireStartY, wireEndX, wireEndY); this.inputWires[port].updateDimensions(wireStartX, wireStartY, wireEndX, wireEndY);
this.inputWires[port].setSelected(this.inputs[port].getId() == NodeType.Port); this.inputWires[port].setSelected(this.inputs[port].getId() == NodeType.Port);
wireStartX += moduleSpacing; wireStartX += moduleSpacing;
@ -259,33 +349,12 @@ namespace pxsim.visuals {
} }
} }
public getSelectedCoords() {
const selected = this.getSelected();
if (!selected) return undefined;
const port = this.getSelected().getPort();
return {
x: this.getSelected().getPort() * this.width / 4 + this.width * MODULE_INNER_PADDING_RATIO,
y: this.selectedIsInput ? this.getModuleHeight() + 2 * this.getWiringHeight() + this.getBrickHeight() : this.getModuleHeight() / 4
}
}
public getCloseIconCoords(closeIconWidth: number, closeIconHeight: number) {
return {
x: this.getSelected().getPort() * this.width / 4 + this.getModuleBounds().width / 2 - closeIconWidth / 2,
y: this.selectedIsInput ? this.getModuleHeight() + 2 * this.getWiringHeight() + this.getBrickHeight() + this.getModuleHeight() - closeIconHeight : 0
}
}
public getModuleHeight() {
return (this.height || DEFAULT_HEIGHT) * MODULE_HEIGHT_RATIO;
}
public getBrickHeight() { public getBrickHeight() {
return (this.height || DEFAULT_HEIGHT) * BRICK_HEIGHT_RATIO; return this.height * BRICK_HEIGHT_RATIO;
} }
public getWiringHeight() { public getWiringHeight() {
return (this.height || DEFAULT_HEIGHT) * WIRING_HEIGHT_RATIO; return this.height * WIRING_HEIGHT_RATIO;
} }
public getModuleBounds() { public getModuleBounds() {
@ -294,5 +363,17 @@ namespace pxsim.visuals {
height: this.getModuleHeight() height: this.getModuleHeight()
} }
} }
public getModulePadding() {
return this.getModuleBounds().width / 35;
}
public getInnerModuleWidth() {
return this.getModuleBounds().width - (this.getModulePadding() * 2);
}
public getModuleHeight() {
return this.height * MODULE_HEIGHT_RATIO;
}
} }
} }

View File

@ -1,8 +1,8 @@
/// <reference path="./staticView.ts" /> /// <reference path="./moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export class BrickView extends StaticModuleView implements LayoutElement { export class BrickView extends ModuleView implements LayoutElement {
private static EV3_SCREEN_ID = "ev3_screen"; private static EV3_SCREEN_ID = "ev3_screen";
private static EV3_LIGHT_ID = "btn_color"; private static EV3_LIGHT_ID = "btn_color";
@ -41,9 +41,9 @@ namespace pxsim.visuals {
public updateThemeCore() { public updateThemeCore() {
let theme = this.theme; let theme = this.theme;
svg.fill(this.buttons[0], theme.buttonUps[0]); // svg.fill(this.buttons[0], theme.buttonUps[0]);
svg.fill(this.buttons[1], theme.buttonUps[1]); // svg.fill(this.buttons[1], theme.buttonUps[1]);
svg.fill(this.buttons[2], theme.buttonUps[2]); // svg.fill(this.buttons[2], theme.buttonUps[2]);
} }
private lastLightPattern: number = -1; private lastLightPattern: number = -1;

View File

@ -1,7 +1,7 @@
/// <reference path="./staticView.ts" /> /// <reference path="./moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export class ColorSensorView extends StaticModuleView implements LayoutElement { export class ColorSensorView extends ModuleView implements LayoutElement {
private control: ColorGridControl; private control: ColorGridControl;
@ -10,10 +10,11 @@ namespace pxsim.visuals {
} }
public getPaddingRatio() { public getPaddingRatio() {
return 1 / 8; return 1 / 4;
} }
public updateState() { public updateState() {
super.updateState();
// TODO: show different color modes // TODO: show different color modes
} }
} }

View File

@ -1,14 +1,14 @@
/// <reference path="./staticView.ts" /> /// <reference path="./moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export class GyroSensorView extends StaticModuleView implements LayoutElement { export class GyroSensorView extends ModuleView implements LayoutElement {
constructor(port: number) { constructor(port: number) {
super(GYRO_SVG, "gyro", NodeType.GyroSensor, port); super(GYRO_SVG, "gyro", NodeType.GyroSensor, port);
} }
public getPaddingRatio() { public getPaddingRatio() {
return 1 / 4; return 0.3;
} }
} }
} }

View File

@ -1,15 +1,16 @@
/// <reference path="./staticView.ts" /> /// <reference path="./moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export class LargeMotorView extends StaticModuleView implements LayoutElement { export class LargeMotorView extends ModuleView implements LayoutElement {
private static ROTATING_ECLIPSE_ID = "1eb2ae58-2419-47d4-86bf-4f26a7f0cf61"; private static ROTATING_ECLIPSE_ID = "hole";
constructor(port: number) { constructor(port: number) {
super(LARGE_MOTOR_SVG, "large-motor", NodeType.LargeMotor, port); super(LARGE_MOTOR_SVG, "large-motor", NodeType.LargeMotor, port);
} }
updateState() { updateState() {
super.updateState();
const motorState = ev3board().getMotors()[this.port]; const motorState = ev3board().getMotors()[this.port];
if (!motorState) return; if (!motorState) return;
const speed = motorState.getSpeed(); const speed = motorState.getSpeed();
@ -20,14 +21,14 @@ namespace pxsim.visuals {
private setMotorAngle(angle: number) { private setMotorAngle(angle: number) {
const holeEl = this.content.getElementById(this.normalizeId(LargeMotorView.ROTATING_ECLIPSE_ID)) const holeEl = this.content.getElementById(this.normalizeId(LargeMotorView.ROTATING_ECLIPSE_ID))
const width = 34; const width = 125.92;
const height = 34; const height = 37.9;
const transform = `rotate(${angle} ${width / 2} ${height / 2})`; const transform = `rotate(${angle} ${width / 2} ${height / 2})`;
holeEl.setAttribute("transform", transform); holeEl.setAttribute("transform", transform);
} }
getWiringRatio() { getWiringRatio() {
return 0.62; return 0.37;
} }
} }
} }

View File

@ -1,12 +1,12 @@
/// <reference path="./staticView.ts" /> /// <reference path="./moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export const MOTOR_ROTATION_FPS = 32; export const MOTOR_ROTATION_FPS = 32;
export class MediumMotorView extends StaticModuleView implements LayoutElement { export class MediumMotorView extends ModuleView implements LayoutElement {
private static ROTATING_ECLIPSE_ID = "Hole"; private static ROTATING_ECLIPSE_ID = "medmotor_Hole";
private hasPreviousAngle: boolean; private hasPreviousAngle: boolean;
private previousAngle: number; private previousAngle: number;
@ -16,10 +16,11 @@ namespace pxsim.visuals {
} }
public getPaddingRatio() { public getPaddingRatio() {
return 1 / 10; return 1 / 5;
} }
updateState() { updateState() {
super.updateState();
const motorState = ev3board().getMotors()[this.port]; const motorState = ev3board().getMotors()[this.port];
if (!motorState) return; if (!motorState) return;
const speed = motorState.getSpeed(); const speed = motorState.getSpeed();
@ -30,9 +31,9 @@ namespace pxsim.visuals {
private setMotorAngle(angle: number) { private setMotorAngle(angle: number) {
const holeEl = this.content.getElementById(this.normalizeId(MediumMotorView.ROTATING_ECLIPSE_ID)) const holeEl = this.content.getElementById(this.normalizeId(MediumMotorView.ROTATING_ECLIPSE_ID))
const width = 47.9; const width = 44.45;
const height = 47.2; const height = 44.45;
const transform = `translate(-1.5 -1.49) rotate(${angle} ${width / 2} ${height / 2})`; const transform = `translate(2 1.84) rotate(${angle} ${width / 2} ${height / 2})`;
holeEl.setAttribute("transform", transform); holeEl.setAttribute("transform", transform);
} }
} }

View File

@ -1,10 +1,11 @@
namespace pxsim.visuals { namespace pxsim.visuals {
export class StaticModuleView extends View implements LayoutElement { export class ModuleView extends View implements LayoutElement {
protected content: SVGSVGElement; protected content: SVGSVGElement;
protected controlShown: boolean; protected controlShown: boolean;
protected selected: boolean;
protected opacity: number;
constructor(protected xml: string, protected prefix: string, protected id: NodeType, protected port: NodeType) { constructor(protected xml: string, protected prefix: string, protected id: NodeType, protected port: NodeType) {
super(); super();
@ -45,9 +46,8 @@ namespace pxsim.visuals {
return 0.5; return 0.5;
} }
protected buildDom(width: number): SVGElement { protected buildDom(): SVGElement {
this.content = svg.parseString(this.xml); this.content = svg.parseString(this.xml);
this.updateDimensions(width);
this.buildDomCore(); this.buildDomCore();
this.attachEvents(); this.attachEvents();
if (this.hasClick()) if (this.hasClick())
@ -82,15 +82,17 @@ namespace pxsim.visuals {
public attachEvents() { public attachEvents() {
} }
public resize(width: number) { public resize(width: number, height: number) {
this.updateDimensions(width); super.resize(width, height);
this.updateDimensions(width, height);
} }
private updateDimensions(width: number) { private updateDimensions(width: number, height: number) {
if (this.content) { if (this.content) {
const currentWidth = this.getInnerWidth(); const currentWidth = this.getInnerWidth();
const currentHeight = this.getInnerHeight(); const currentHeight = this.getInnerHeight();
const newHeight = currentHeight / currentWidth * width; const newHeight = currentHeight / currentWidth * width;
const newWidth = currentWidth / currentHeight * height;
this.content.setAttribute('width', `${width}`); this.content.setAttribute('width', `${width}`);
this.content.setAttribute('height', `${newHeight}`); this.content.setAttribute('height', `${newHeight}`);
} }
@ -101,23 +103,28 @@ namespace pxsim.visuals {
} }
public setSelected(selected: boolean) { public setSelected(selected: boolean) {
this.selected = selected; super.setSelected(selected);
this.updateOpacity();
}
public updateState() {
this.updateOpacity(); this.updateOpacity();
} }
protected updateOpacity() { protected updateOpacity() {
if (this.rendered) { if (this.rendered) {
const opacity = this.selected ? "0.5" : "1"; const opacity = this.selected ? 0.2 : 1;
if (this.hasClick()) { if (this.hasClick() && this.opacity != opacity) {
this.setOpacity(opacity); this.opacity = opacity;
this.setOpacity(this.opacity);
if (this.selected) this.content.style.cursor = ""; if (this.selected) this.content.style.cursor = "";
else this.content.style.cursor = "pointer"; else this.content.style.cursor = "pointer";
} }
} }
} }
protected setOpacity(opacity: string) { protected setOpacity(opacity: number) {
this.element.setAttribute("opacity", opacity); this.element.setAttribute("opacity", `${opacity}`);
} }
} }
} }

View File

@ -1,8 +1,8 @@
/// <reference path="./staticView.ts" /> /// <reference path="./moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export class PortView extends StaticModuleView implements LayoutElement { export class PortView extends ModuleView implements LayoutElement {
constructor(port: NodeType, private label: string) { constructor(port: NodeType, private label: string) {
super(PORT_SVG, "port", NodeType.Port, port); super(PORT_SVG, "port", NodeType.Port, port);

View File

@ -1,7 +1,7 @@
/// <reference path="./staticView.ts" /> /// <reference path="./moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export class TouchSensorView extends StaticModuleView implements LayoutElement { export class TouchSensorView extends ModuleView implements LayoutElement {
private static RECT_ID = ["touch_gradient4", "touch_gradient3", "touch_gradient2", "touch_gradient1"]; private static RECT_ID = ["touch_gradient4", "touch_gradient3", "touch_gradient2", "touch_gradient1"];
private static TOUCH_GRADIENT_UNPRESSED = ["linear-gradient-2", "linear-gradient-3", "linear-gradient-4", "linear-gradient-5"]; private static TOUCH_GRADIENT_UNPRESSED = ["linear-gradient-2", "linear-gradient-3", "linear-gradient-4", "linear-gradient-5"];
@ -17,7 +17,7 @@ namespace pxsim.visuals {
} }
public getPaddingRatio() { public getPaddingRatio() {
return 1 / 10; return 1 / 4;
} }
public hasClick() { public hasClick() {

View File

@ -1,7 +1,7 @@
/// <reference path="./staticView.ts" /> /// <reference path="./moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export class UltrasonicSensorView extends StaticModuleView implements LayoutElement { export class UltrasonicSensorView extends ModuleView implements LayoutElement {
constructor(port: number) { constructor(port: number) {
super(ULTRASONIC_SVG, "ultrasonic", NodeType.UltrasonicSensor, port); super(ULTRASONIC_SVG, "ultrasonic", NodeType.UltrasonicSensor, port);

View File

@ -3,14 +3,19 @@ namespace pxsim.visuals {
protected element: SVGGElement; protected element: SVGGElement;
protected rendered = false; protected rendered = false;
protected visible = false; protected visible = false;
protected selected: boolean;
protected width: number = 0; protected width: number = 0;
protected height: number = 0;
protected left: number = 0; protected left: number = 0;
protected top: number = 0; protected top: number = 0;
protected scaleFactor: number = 1; protected scaleFactor: number = 1;
private changed: boolean;
private hover: boolean = false;
protected theme: IBoardTheme; protected theme: IBoardTheme;
protected abstract buildDom(width: number): SVGElement; protected abstract buildDom(): SVGElement;
public abstract getInnerWidth(): number; public abstract getInnerWidth(): number;
public abstract getInnerHeight(): number; public abstract getInnerHeight(): number;
@ -83,10 +88,27 @@ namespace pxsim.visuals {
} }
private onClickHandler: (ev: any) => void; private onClickHandler: (ev: any) => void;
public registerClick(handler: (ev: any) => void) { public registerClick(handler: (ev: any) => void, zoom?: boolean) {
this.onClickHandler = handler; this.onClickHandler = handler;
if (zoom) {
this.getView().addEventListener(pointerEvents.up, (ev: any) => {
if (!this.getSelected()) {
this.onClickHandler(ev);
this.setHover(false);
}
});
this.getView().addEventListener(pointerEvents.move, () => {
if (!this.getSelected()) {
this.setHover(true);
}
});
this.getView().addEventListener(pointerEvents.leave, () => {
this.setHover(false);
});
} else {
this.getView().addEventListener(pointerEvents.up, this.onClickHandler); this.getView().addEventListener(pointerEvents.up, this.onClickHandler);
} }
}
public dispose() { public dispose() {
if (this.onClickHandler) this.getView().removeEventListener(pointerEvents.up, this.onClickHandler) if (this.onClickHandler) this.getView().removeEventListener(pointerEvents.up, this.onClickHandler)
@ -98,7 +120,7 @@ namespace pxsim.visuals {
this.element = svg.elt("g") as SVGGElement; this.element = svg.elt("g") as SVGGElement;
View.track(this); View.track(this);
const content = this.buildDom(this.width); const content = this.buildDom();
if (content) { if (content) {
this.element.appendChild(content); this.element.appendChild(content);
} }
@ -108,16 +130,30 @@ namespace pxsim.visuals {
return this.element; return this.element;
} }
public resize(width: number) { public resize(width: number, height: number) {
this.width = width; this.width = width;
this.height = height;
} }
private updateTransform() { private updateTransform() {
if (this.rendered) { if (this.rendered) {
let transform = `translate(${this.left} ${this.top})`; let left = this.left;
let top = this.top;
let scaleFactor = this.scaleFactor;
if (this.hover) {
const hoverScaleFactor = scaleFactor + 0.05;
// Scale around center of module
const centerX = this.getWidth() / 2;
const centerY = this.getHeight() / 2;
left = left - centerX * (hoverScaleFactor - 1);
top = top - centerY * (hoverScaleFactor - 1);
scaleFactor = hoverScaleFactor;
}
if (this.scaleFactor !== 1) { let transform = `translate(${left} ${top})`;
transform += ` scale(${this.scaleFactor})`;
if (scaleFactor !== 1) {
transform += ` scale(${scaleFactor})`;
} }
this.element.setAttribute("transform", transform); this.element.setAttribute("transform", transform);
@ -149,6 +185,40 @@ namespace pxsim.visuals {
delete View.allViews[id]; delete View.allViews[id];
} }
} }
///////// HOVERED STATE /////////////
public getHover() {
return this.hover;
}
public setHover(hover: boolean) {
if (this.hover != hover) {
this.hover = hover;
this.updateTransform();
}
}
///////// SELECTED STATE /////////////
public getSelected() {
return this.selected;
}
public setSelected(selected: boolean) {
this.selected = selected;
this.setChangedState();
}
protected setChangedState() {
this.changed = true;
}
public didChange() {
const res = this.changed;
this.changed = false;
return res;
}
} }
export abstract class SimView<T extends BaseNode> extends View implements LayoutElement { export abstract class SimView<T extends BaseNode> extends View implements LayoutElement {
@ -222,7 +292,7 @@ namespace pxsim.visuals {
}); });
} }
protected buildDom(width: number): SVGElement { protected buildDom(): SVGElement {
return undefined; return undefined;
} }
} }

View File

@ -1,11 +1,10 @@
/// <reference path="./nodes/staticView.ts" /> /// <reference path="./nodes/moduleView.ts" />
namespace pxsim.visuals { namespace pxsim.visuals {
export class WireView extends View implements LayoutElement { export class WireView extends View implements LayoutElement {
private wire: SVGSVGElement; private wire: SVGSVGElement;
private path: SVGPathElement; private path: SVGPathElement;
private selected: boolean;
private hasDimensions: boolean; private hasDimensions: boolean;
protected startX: number; protected startX: number;
@ -30,7 +29,7 @@ namespace pxsim.visuals {
this.updatePath(); this.updatePath();
} }
buildDom(width: number): SVGElement { buildDom(): SVGElement {
this.wire = svg.elt("svg", { height: "100%", width: "100%" }) as SVGSVGElement; this.wire = svg.elt("svg", { height: "100%", width: "100%" }) as SVGSVGElement;
this.path = pxsim.svg.child(this.wire, "path", { this.path = pxsim.svg.child(this.wire, "path", {
'd': '', 'd': '',
@ -45,8 +44,8 @@ namespace pxsim.visuals {
updatePath() { updatePath() {
if (!this.hasDimensions) return; if (!this.hasDimensions) return;
const height = this.endY - this.startY; const height = this.endY - this.startY;
const quarterHeight = height / 4; const thirdHeight = height / 3;
const middleHeight = this.port == 1 || this.port == 2 ? quarterHeight : quarterHeight * 2; const middleHeight = this.port == 1 || this.port == 2 ? thirdHeight : thirdHeight * 2;
let d = `M${this.startX} ${this.startY}`; let d = `M${this.startX} ${this.startY}`;
d += ` L${this.startX} ${this.startY + middleHeight}`; d += ` L${this.startX} ${this.startY + middleHeight}`;
d += ` L${this.endX} ${this.startY + middleHeight}`; d += ` L${this.endX} ${this.startY + middleHeight}`;
@ -79,7 +78,7 @@ namespace pxsim.visuals {
} }
public setSelected(selected: boolean) { public setSelected(selected: boolean) {
this.selected = selected; super.setSelected(selected);
this.updateOpacity(); this.updateOpacity();
} }

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="svg41" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 23 23" style="enable-background:new 0 0 23 23;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<title>color</title>
<g id="menu_icn_advanced_closed" transform="translate(-9594 10075)">
<g id="Line_9_1_">
<rect x="9600.7" y="-10067" transform="matrix(0.7071 -0.7071 0.7071 0.7071 9926.6836 3842.5476)" class="st0" width="2" height="11.3"/>
</g>
<g id="Line_10_1_">
<rect x="9603" y="-10062.3" transform="matrix(0.7071 -0.7071 0.7071 0.7071 9928.7334 3847.4973)" class="st0" width="11.3" height="2"/>
</g>
<g id="menu_icn_advanced_closed-2">
<rect x="9604.7" y="-10057.6" transform="matrix(0.7071 -0.7071 0.7071 0.7071 9924.7324 3846.2527)" class="st0" width="1" height="1"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1017 B

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="svg41" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 23 23" style="enable-background:new 0 0 23 23;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<title>color</title>
<g id="menu_icn_advanced_open" transform="translate(-8544 12422.914) rotate(180)">
<g id="Line_9">
<rect x="-8559.7" y="12406.3" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -11283.3965 -2416.5291)" class="st0" width="2" height="11.3"/>
</g>
<g id="Line_10">
<rect x="-8557.4" y="12411" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -11281.3467 -2411.5793)" class="st0" width="11.3" height="2"/>
</g>
<g id="Rectangle_251">
<rect x="-8555.7" y="12415.7" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -11285.3848 -2412.8174)" class="st0" width="1" height="1"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1023 B

View File

@ -7,8 +7,6 @@ webfontsGenerator({
"./touch.svg", "./touch.svg",
"./gyro.svg", "./gyro.svg",
"./categories/addpackage.svg", "./categories/addpackage.svg",
"./categories/advancedcollapsed.svg",
"./categories/advancedexpanded.svg",
"./categories/brick.svg", "./categories/brick.svg",
"./categories/controls.svg", "./categories/controls.svg",
"./categories/functions.svg", "./categories/functions.svg",

View File

@ -13,11 +13,14 @@
} }
.blocklyFlyoutLabel:not(.blocklyFlyoutHeading) .blocklyFlyoutLabelIcon { .blocklyFlyoutLabel:not(.blocklyFlyoutHeading) .blocklyFlyoutLabelIcon {
font-family: 'legoIcons';
fill: white; fill: white;
font-size: 1.7rem; font-size: 1.7rem;
} }
.blocklyFlyoutLabel .blocklyFlyoutLabelIcon {
font-family: 'legoIcons';
}
span.blocklyTreeIcon { span.blocklyTreeIcon {
font-family: 'legoIcons' !important; font-family: 'legoIcons' !important;
} }
@ -73,56 +76,40 @@ span.blocklyTreeLabel {
} }
} }
span.blocklyTreeIcon.blocklyTreeIcontests::before {
content: "";
}
span.blocklyTreeIcon.blocklyTreeIconmusic::before { span.blocklyTreeIcon.blocklyTreeIconmusic::before {
content: "\f110";
}
span.blocklyTreeIcon.blocklyTreeIconloops::before {
content: "\f10d";
}
span.blocklyTreeIcon.blocklyTreeIconlogic::before {
content: "\f10c";
}
span.blocklyTreeIcon.blocklyTreeIconvariables::before {
content: "\f113";
}
span.blocklyTreeIcon.blocklyTreeIconmath::before {
content: "\f10e"; content: "\f10e";
} }
span.blocklyTreeIcon.blocklyTreeIconadvancedcollapsed::before { span.blocklyTreeIcon.blocklyTreeIconloops::before {
content: "\f106";
}
span.blocklyTreeIcon.blocklyTreeIconadvancedexpanded::before {
content: "\f107";
}
span.blocklyTreeIcon.blocklyTreeIconfunctions::before {
content: "\f10a";
}
span.blocklyTreeIcon.blocklyTreeIconarrays::before {
content: "\f10b"; content: "\f10b";
} }
span.blocklyTreeIcon.blocklyTreeIcontext::before { span.blocklyTreeIcon.blocklyTreeIconlogic::before {
content: "\f112"; content: "\f10a";
} }
span.blocklyTreeIcon.blocklyTreeIconconsole::before { span.blocklyTreeIcon.blocklyTreeIconvariables::before {
content: ""; content: "\f111";
}
span.blocklyTreeIcon.blocklyTreeIconmath::before {
content: "\f10c";
}
span.blocklyTreeIcon.blocklyTreeIconfunctions::before {
content: "\f108";
}
span.blocklyTreeIcon.blocklyTreeIconarrays::before {
content: "\f109";
}
span.blocklyTreeIcon.blocklyTreeIcontext::before {
content: "\f110";
} }
span.blocklyTreeIcon.blocklyTreeIconcontrol::before { span.blocklyTreeIcon.blocklyTreeIconcontrol::before {
content: "\f109"; content: "\f107";
} }
span.blocklyTreeIcon.blocklyTreeIconaddpackage::before { span.blocklyTreeIcon.blocklyTreeIconaddpackage::before {
@ -130,18 +117,18 @@ span.blocklyTreeIcon.blocklyTreeIconaddpackage::before {
} }
.save-editortools-btn .icon.save::before { .save-editortools-btn .icon.save::before {
content: "\f117"
}
.download-button .icon.download.icon-and-text::before {
content: "\f116"
}
.button.approve.positive .checkmark.icon::before {
content: "\f115" content: "\f115"
} }
.button.approve.cancel .cancel.icon::before { .download-button .icon.download.icon-and-text::before {
content: "\f114" content: "\f114"
} }
.button.approve.positive .checkmark.icon::before {
content: "\f113"
}
.button.approve.cancel .cancel.icon::before {
content: "\f112"
}