Skip to content

Commit 99ac35e

Browse files
committed
VID2805 Dual Stepper Element - initial commit
1 parent 3499b15 commit 99ac35e

4 files changed

+246
-0
lines changed

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ export { DipSwitch8Element } from './dip-switch-8-element';
5050
export { StepperMotorElement } from './stepper-motor-element';
5151
export { HX711Element } from './hx711-element';
5252
export { KS2EMDC5Element } from './ks2e-m-dc5-element';
53+
export { VID2805DualStepperElement } from './vid2805-dual-stepper-element';

src/react-types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import { DipSwitch8Element } from './dip-switch-8-element';
4949
import { StepperMotorElement } from './stepper-motor-element';
5050
import { HX711Element } from './hx711-element';
5151
import { KS2EMDC5Element } from './ks2e-m-dc5-element';
52+
import { VID2805DualStepperElement } from './vid2805-dual-stepper-element';
5253

5354
type WokwiElement<T> = Partial<T> & React.ClassAttributes<T>;
5455

@@ -103,6 +104,7 @@ declare global {
103104
'wokwi-stepper-motor': WokwiElement<StepperMotorElement>;
104105
'wokwi-hx711': WokwiElement<HX711Element>;
105106
'wokwi-ks2e-m-dc5': WokwiElement<KS2EMDC5Element>;
107+
'wokwi-vid2805-dual-stepper': WokwiElement<VID2805DualStepperElement>;
106108
}
107109
}
108110
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { html } from 'lit';
2+
import './vid2805-dual-stepper-element';
3+
import { StepperHand } from './vid2805-dual-stepper-element';
4+
5+
export default {
6+
title: 'VID2805 Dual Stepper',
7+
component: 'wokwi-vid2805-dual-stepper',
8+
argTypes: {
9+
outerLength: { control: { type: 'range', min: 20, max: 70 } },
10+
outerAngle: { control: { type: 'range', min: 0, max: 360 } },
11+
outerColour: { control: { type: 'color' } },
12+
outerShape : { options: ['arrow' , 'plain', 'fancy'], control: { type: 'select'}},
13+
innerLength: { control: { type: 'range', min: 20, max: 70 } },
14+
innerAngle: { control: { type: 'range', min: 0, max: 360 } },
15+
innerColour: { control: { type: 'color' } },
16+
innerShape : { options: ['arrow' , 'plain', 'fancy'], control: { type: 'select'}},
17+
},
18+
args: {
19+
outerLength: 20,
20+
outerAngle: 0,
21+
outerColour: 'grey',
22+
outerShape: 'plain',
23+
innerLength: 20,
24+
innerAngle: 0,
25+
innerColour: 'darkgrey',
26+
innerShape: 'plain',
27+
},
28+
};
29+
30+
31+
// .innerHand = ${new ClockHand(innerLength, innerColour, innerShape, innerAngle)}
32+
// .outerHand = ${new ClockHand(outerLength, outerColour, outerShape, outerAngle)}
33+
34+
35+
const Template = ({outerLength, outerAngle, outerColour, outerShape,
36+
innerLength, innerAngle, innerColour, innerShape,
37+
innerHand, outerHand }) => html`<wokwi-vid2805-dual-stepper
38+
.outerLength = ${outerLength}
39+
.outerAngle = ${outerAngle}
40+
.outerColour = ${outerColour}
41+
.outerShape = ${outerShape}
42+
.innerLength = ${innerLength}
43+
.innerAngle = ${innerAngle}
44+
.innerColour = ${innerColour}
45+
.innerShape = ${innerShape}
46+
.innerHand = ${innerHand}
47+
.outerHand = ${outerHand}
48+
></wokwi-vid2805-dual-stepper>`;
49+
50+
export const Default = Template.bind({});
51+
Default.args = {
52+
// outerLength: 20,
53+
// outerAngle: 0,
54+
// outerColour: 'grey',
55+
// outerShape: 'plain',
56+
// innerLength: 20,
57+
// innerAngle: 0,
58+
// innerColour: 'darkgrey',
59+
// innerShape: 'plain',
60+
61+
innerHand: new StepperHand(25, "red", "plain", 225),
62+
outerHand: new StepperHand(30, "green", "plain", 270),
63+
};
64+
65+
export const NineOclock = Template.bind({});
66+
NineOclock.args = {
67+
innerHand: new StepperHand(70, "silver", "plain", 90),
68+
outerHand: new StepperHand(60, "gold", "plain", 0),
69+
};
70+
71+
export const SameLength = Template.bind({});
72+
SameLength.args = {
73+
innerHand: new StepperHand(20, "blue", "plain", 0),
74+
outerHand: new StepperHand(20, "green", "plain", 180),
75+
};

src/vid2805-dual-stepper-element.ts

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import { html, LitElement, svg } from 'lit';
2+
import { customElement, property} from 'lit/decorators.js';
3+
import { ElementPin } from '.';
4+
5+
6+
export type HandShape = 'arrow' | 'plain'; // | 'fancy';
7+
8+
export class StepperHand {
9+
10+
/**
11+
* length used to control hand length
12+
*/
13+
length : number = 25;
14+
15+
/**
16+
* colour used to paint the hand
17+
*/
18+
colour : string = '';
19+
20+
/**
21+
* hand shape selects from predefined shape paths
22+
*/
23+
shape : HandShape = 'plain';
24+
25+
/**
26+
* the current hand angle
27+
*/
28+
angle : number = 0;
29+
30+
31+
32+
constructor(length = 25, colour = '', shape : HandShape = 'plain', angle = 0){
33+
this.angle = angle;
34+
this.colour = colour;
35+
this.shape = shape;
36+
this.length = length;
37+
}
38+
39+
}
40+
41+
@customElement('wokwi-vid2805-dual-stepper')
42+
export class VID2805DualStepperElement extends LitElement {
43+
44+
@property() outerHand = new StepperHand();
45+
@property() innerHand = new StepperHand();
46+
47+
readonly pinInfo: ElementPin[] = [
48+
{ name: 'A1+', y: 237, x: 98, number: 1, signals: [] },
49+
{ name: 'A1-', y: 237, x: 108, number: 2, signals: [] },
50+
{ name: 'B1+', y: 237, x: 117, number: 3, signals: [] },
51+
{ name: 'B1-', y: 237, x: 127, number: 4, signals: [] },
52+
{ name: 'A2+', y: 237, x: 137, number: 5, signals: [] },
53+
{ name: 'A2-', y: 237, x: 147, number: 6, signals: [] },
54+
{ name: 'B2+', y: 237, x: 157, number: 7, signals: [] },
55+
{ name: 'B2-', y: 237, x: 167, number: 8, signals: [] },
56+
];
57+
58+
59+
readonly handMap : {[key:string] : string } = {
60+
"outer_plain_hand" : "m0,0 c0,5,4,9,9,9,3.28,0,6.13-1.73,7.7-4.33v.03c.5-.8,1.2-1.6,2.1-2.1,.8-.5,1.8-.8,2.8-.8h${len}c1,0,1.8-.8,1.8-1.8s-.8-1.8-1.8-1.8h-${len}c-1,0-1.9-.3-2.8-.8-.8-.5-1.6-1.2-2.1-2h0c-1.56-2.64-4.43-4.4-7.74-4.4-5,0-9,4.1-9,9Zm3.5,0c0-3,2.4-5.4,5.5-5.4s5.5,2.4,5.5,5.4-2.5,5.4-5.5,5.4-5.5-2.4-5.5-5.4Z",
61+
"outer_arrow_hand" : "m0,0 c0,5,4,9,9,9,3.89,0,7.16-2.42,8.43-5.85,.3-.58,.78-1.16,1.27-1.45,.6-.3,1.29-.4,1.99-.2,0,0,0,0,0,0h.01s.9,.2,.9,.2l34.4-1.7-34.4-1.9-.9,.3c-.7,.2-1.4,.1-2-.2-.6-.3-1.1-.8-1.3-1.5,0,0-.01,.02-.02,.02C16.13,2.41,12.89,.05,9.05,.05c-5,0-9,4-9,9Zm3.5,0c0-3.1,2.5-5.5,5.5-5.5s5.5,2.5,5.5,5.5-2.5,5.5-5.5,5.5-5.5-2.5-5.5-5.5Z",
62+
"inner_plain_hand" : "m0,0 c 0 2.6 2.1 4.7 4.7 4.7 c 1.27 0 2.41 -0.5 3.25 -1.31 h 0 c 0.5 -0.49 1.1 -0.89 1.8 -1.19 c 0.7 -0.3 1.4 -0.4 2.1 -0.4 h ${len} c 1 0 1.8 -0.8 1.8 -1.8 s -0.8 -1.8 -1.8 -1.8 h -${len} s -0.06 0 -0.06 0 c -0.7 0 -1.5 -0.1 -2.1 -0.4 c -0.7 -0.3 -1.3 -0.7 -1.8 -1.2 h 0 c -0.84 -0.8 -1.98 -1.3 -3.24 -1.3 c -2.6 0 -4.7 2.1 -4.7 4.7 Z m 2.7 0 c 0 -1.1 0.9 -2 2 -2 s 2 0.9 2 2 s -0.9 2 -2 2 s -2 -0.9 -2 -2 Z",
63+
"inner_arrow_hand" : "m0,0 c0,2.6,2.1,4.7,4.7,4.7,1.37,0,2.59-.59,3.44-1.52v.02c.7-.7,1.5-1.2,2.5-1.5s2-.3,2.9-.1h-.04l.9,.2,86.5-1.8-86.5-1.8-.9,.2h.04c-1,.2-2,.2-2.9-.1-1-.3-1.8-.8-2.5-1.5v.02c-.86-.93-2.08-1.52-3.44-1.52-2.6,0-4.7,2.1-4.7,4.7Zm2.7,0c0-1.1,.9-2,2-2s2,.9,2,2-.9,2-2,2-2-.9-2-2Z",
64+
}
65+
66+
67+
render() {
68+
69+
const x = 112.3; // x location of shaft point
70+
const y = 50; // y location of shaft point
71+
const innerOff = 4.7; // offset to center of inner hand's ring
72+
const outerOff = 9; // offset to center of outer hand's ring
73+
let trY = 0;
74+
75+
let inner_svg = this.handMap['inner_' + this.innerHand.shape + '_hand'];
76+
let outer_svg = this.handMap['outer_' + this.outerHand.shape + '_hand'];
77+
78+
// todo: validate hands
79+
80+
// replace length from args
81+
if (this.innerHand.length > 70) {
82+
this.innerHand.length = 70;
83+
}
84+
if (this.outerHand.length > 70) {
85+
this.outerHand.length = 70;
86+
}
87+
88+
inner_svg = inner_svg.replaceAll("${len}", this.innerHand.length.toString());
89+
outer_svg = outer_svg.replaceAll("${len}", this.outerHand.length.toString());
90+
91+
const ml = Math.max(this.innerHand.length, this.outerHand.length);
92+
if (ml > 30) {
93+
trY = ml - 30;
94+
}
95+
96+
return html`
97+
<svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 160">
98+
<defs>
99+
<style>.cls-1{fill:#939598;}.cls-2{fill:#f1f2f2;}.cls-3{fill:#808285;}.cls-4{fill:#ed1f24;}.cls-5{fill:#70bf44;}.cls-6{fill:#414042;}
100+
.cls-h{fill:"blue";stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:.1px;
101+
transform-box: fill-box;
102+
}
103+
104+
</style>
105+
</defs>
106+
<g id="Layer_1-2" transform="translate(0,${trY})">
107+
<g id="scaled_body">
108+
<g id="pins">
109+
<path id="pin-1" class="cls-3" d="M58.42,86.17v12.76c0,.78,.63,1.42,1.42,1.42s1.42-.63,1.42-1.42v-12.76h-2.83Z" />
110+
<path id="pin-2" class="cls-3" d="M65.62,86.17v12.76c0,.78,.63,1.42,1.42,1.42s1.42-.63,1.42-1.42v-12.76h-2.83Z" />
111+
<path id="pin-3" class="cls-3" d="M72.82,86.17v12.76c0,.78,.63,1.42,1.42,1.42s1.42-.63,1.42-1.42v-12.76h-2.83Z" />
112+
<path id="pin-4" class="cls-3" d="M80.02,86.17v12.76c0,.78,.63,1.42,1.42,1.42s1.42-.63,1.42-1.42v-12.76h-2.83Z" />
113+
<path id="pin-5" class="cls-3" d="M87.22,86.17v12.76c0,.78,.63,1.42,1.42,1.42s1.42-.63,1.42-1.42v-12.76h-2.83Z" />
114+
<path id="pin-6" class="cls-3" d="M94.42,86.17v12.76c0,.78,.63,1.42,1.42,1.42s1.42-.63,1.42-1.42v-12.76h-2.83Z" />
115+
<path id="pin-7" class="cls-3" d="M101.62,86.17v12.76c0,.78,.63,1.42,1.42,1.42s1.42-.63,1.42-1.42v-12.76h-2.83Z" />
116+
<path id="pin-8" class="cls-3" d="M108.82,86.17v12.76c0,.78,.63,1.42,1.42,1.42s1.42-.63,1.42-1.42v-12.76h-2.83Z" />
117+
</g>
118+
<path id="base" class="cls-6" d="M170.08,32.12c-4.98-15.86-18.92-27.75-35.9-29.71-1.2-1.4-2.96-2.31-4.96-2.31s-3.76,.91-4.96,2.31c-2.13,.25-4.2,.67-6.23,1.22H51.81c-1.93-.52-3.9-.92-5.92-1.17-1.2-1.48-3.01-2.45-5.07-2.45s-3.82,.94-5.02,2.39C19,4.27,5.19,15.86,0,31.41v27.09c5.15,15.43,18.82,26.97,35.45,28.97,1.2,1.56,3.06,2.58,5.17,2.58s3.98-1.02,5.17-2.58c2.18-.26,4.3-.7,6.37-1.28H117.67c2.07,.58,4.19,1.01,6.37,1.28,1.2,1.56,3.06,2.58,5.17,2.58s3.98-1.02,5.17-2.58c16.89-2.04,30.72-13.89,35.69-29.68v-25.67Z" />
119+
<g id="ribs">
120+
<path class="cls-3" d="M51.36,17.58l7.77-13.95h-5.11l-17.04,30.61c-.85-.27-1.74-.44-2.66-.5L30.9,3.26c-1.48,.34-2.93,.77-4.35,1.27l3.34,29.78c-1.43,.48-2.71,1.23-3.83,2.2l-13.79-10.54-.03,.03c-.38-.26-.82-.44-1.31-.44-1.33,0-2.4,1.08-2.4,2.4,0,1.2,.9,2.16,2.06,2.33l12.75,9.75c-.42,.84-.77,1.72-.97,2.67H.22v4.47H22.3c.18,1.01,.51,1.97,.95,2.87l-12.69,9.94c-1.14,.18-2.03,1.13-2.03,2.33,0,1.33,1.08,2.4,2.4,2.4,.79,0,1.46-.4,1.89-.99l.08,.1,13.03-10.2c1.1,.98,2.37,1.75,3.78,2.25l-3.18,29.5c1.42,.5,2.87,.93,4.35,1.27l3.25-30.13c1.05-.05,2.05-.25,3.01-.57l16.78,30.25h5.11l-7.82-14.1H118.91l-7.85,14.1h5.11l16.81-30.2c.81,.25,1.66,.42,2.54,.49l3.38,30.17c1.48-.34,2.93-.78,4.35-1.27l-3.3-29.44c1.59-.52,3.04-1.36,4.24-2.48l12.76,9.75c.36,.87,1.22,1.49,2.22,1.49,1.33,0,2.4-1.08,2.4-2.4,0-.81-.43-1.49-1.04-1.93l.02-.02-13.75-10.51c.38-.84,.67-1.74,.84-2.67h22.43v-4.47h-22.49c-.19-.88-.5-1.7-.88-2.49l12.62-9.88c1.25-.09,2.24-1.1,2.24-2.37s-1.08-2.4-2.4-2.4c-.3,0-.58,.07-.85,.17l-.13-.17-14.15,11.08c-1.13-1.02-2.45-1.8-3.91-2.3l3.21-29.78c-1.42-.5-2.87-.93-4.35-1.27l-3.28,30.45c-.89,.05-1.75,.21-2.57,.46L116.18,3.62h-5.11l7.74,13.95h-31.55V3.62h-4.47v13.95h-31.43Zm31.43,50.05H48.73l-7.71-13.9c1.93-1.67,3.3-3.95,3.77-6.56h28.93c.84,4.63,4.45,8.29,9.07,9.18v11.28Zm0-33.75c-4.5,.87-8.06,4.36-9.01,8.83h-29.04c-.54-2.53-1.94-4.71-3.85-6.32l7.79-13.99h34.12v11.48Zm4.47-11.48h34.22l7.7,13.88c-1.98,1.61-3.43,3.84-3.98,6.43h-1.92c-1.03-5.27-5.66-9.25-11.23-9.25s-10.21,3.98-11.23,9.25h-4.65c-.95-4.43-4.45-7.92-8.91-8.82v-11.49Zm0,33.94c4.57-.93,8.13-4.57,8.96-9.17h4.6c1.05,5.24,5.68,9.2,11.23,9.2s10.18-3.95,11.23-9.2h1.87c.49,2.68,1.92,5,3.92,6.68l-7.67,13.77h-34.14v-11.29Z" />
121+
</g>
122+
<g id="holes">
123+
<g>
124+
<circle class="cls-2" cx="40.81" cy="6.55" r="4.83" />
125+
<path class="cls-1" d="M40.81,3.32c1.78,0,3.23,1.45,3.23,3.23s-1.45,3.23-3.23,3.23-3.23-1.45-3.23-3.23,1.45-3.23,3.23-3.23m0-3.2c-3.55,0-6.43,2.88-6.43,6.43s2.88,6.43,6.43,6.43,6.43-2.88,6.43-6.43S44.36,.12,40.81,.12h0Z" />
126+
</g>
127+
<g>
128+
<path class="cls-2" d="M40.62,88.33c-2.66,0-4.83-2.17-4.83-4.83s2.17-4.83,4.83-4.83,4.83,2.17,4.83,4.83-2.17,4.83-4.83,4.83Z" />
129+
<path class="cls-1" d="M40.62,80.26c1.78,0,3.23,1.45,3.23,3.23s-1.45,3.23-3.23,3.23-3.23-1.45-3.23-3.23,1.45-3.23,3.23-3.23m0-3.2c-3.55,0-6.43,2.88-6.43,6.43s2.88,6.43,6.43,6.43,6.43-2.88,6.43-6.43-2.88-6.43-6.43-6.43h0Z" />
130+
</g>
131+
<g>
132+
<path class="cls-2" d="M129.22,88.32c-2.66,0-4.83-2.17-4.83-4.83s2.17-4.83,4.83-4.83,4.83,2.17,4.83,4.83-2.17,4.83-4.83,4.83Z" />
133+
<path class="cls-1" d="M129.22,80.26c1.78,0,3.23,1.45,3.23,3.23s-1.45,3.23-3.23,3.23-3.23-1.45-3.23-3.23,1.45-3.23,3.23-3.23m0-3.2c-3.55,0-6.43,2.88-6.43,6.43s2.88,6.43,6.43,6.43,6.43-2.88,6.43-6.43-2.88-6.43-6.43-6.43h0Z" />
134+
</g>
135+
<g>
136+
<path class="cls-2" d="M129.22,11.38c-2.66,0-4.83-2.17-4.83-4.83s2.17-4.83,4.83-4.83,4.83,2.17,4.83,4.83-2.17,4.83-4.83,4.83Z" />
137+
<path class="cls-1" d="M129.22,3.32c1.78,0,3.23,1.45,3.23,3.23s-1.45,3.23-3.23,3.23-3.23-1.45-3.23-3.23,1.45-3.23,3.23-3.23m0-3.2c-3.55,0-6.43,2.88-6.43,6.43s2.88,6.43,6.43,6.43,6.43-2.88,6.43-6.43S132.77,.12,129.22,.12h0Z" />
138+
</g>
139+
</g>
140+
<g id="hours">
141+
<path class="cls-h" transform="
142+
translate(${x} ${y+outerOff/2})
143+
rotate(${this.innerHand.angle})
144+
translate(-${outerOff}, -${outerOff})"
145+
fill="${this.outerHand.colour}" d=${outer_svg} />
146+
</g>
147+
<g id="minutes">
148+
<path class="cls-h"
149+
transform="
150+
translate(${x} ${y})
151+
rotate(${this.outerHand.angle})
152+
translate(-${innerOff}, -${innerOff})"
153+
fill="${this.innerHand.colour}" d=${inner_svg} />
154+
</g>
155+
</svg>
156+
`;
157+
}
158+
}
159+
160+
161+
162+
163+
164+
/**
165+
*
166+
*/
167+
168+

0 commit comments

Comments
 (0)