b69af383a6
* Use learnings from touch events in Blockly and apply to the Ev3 sim. Register move and up events on the document rather than the individual element allowing users greater flexibility where they move their mouse once it's down. * Add mouse leave events
135 lines
5.3 KiB
TypeScript
135 lines
5.3 KiB
TypeScript
|
|
|
|
namespace pxsim.visuals {
|
|
|
|
export class ProximitySliderControl extends ControlView<InfraredSensorNode> {
|
|
private group: SVGGElement;
|
|
private gradient: SVGLinearGradientElement;
|
|
private slider: SVGGElement;
|
|
|
|
private reporter: SVGTextElement;
|
|
|
|
private static SLIDER_HANDLE_HEIGHT = 26;
|
|
private static SLIDER_SIDE_PADDING = 6;
|
|
|
|
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
|
let gid = "gradient-slider-" + this.getId();
|
|
this.group = svg.elt("g") as SVGGElement;
|
|
this.gradient = createGradient(gid, this.getGradientDefinition());
|
|
this.gradient.setAttribute('x1', '0%');
|
|
this.gradient.setAttribute('y1', '0%');
|
|
this.gradient.setAttribute('x2', '0%');
|
|
this.gradient.setAttribute('y2', '100%');
|
|
// this.gradient.setAttribute('gradientTransform', 'matrix(50, 0, 0, -110, 21949.45, 46137.67)');
|
|
// this.gradient.setAttribute('gradientUnits', 'userSpaceOnUse');
|
|
globalDefs.appendChild(this.gradient);
|
|
|
|
this.group = svg.elt("g") as SVGGElement;
|
|
|
|
const reporterGroup = pxsim.svg.child(this.group, "g");
|
|
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 42)`);
|
|
this.reporter = pxsim.svg.child(reporterGroup, "text", { 'text-anchor': 'middle', 'x': 0, 'y': '0', 'class': 'sim-text number large inverted' }) as SVGTextElement;
|
|
|
|
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': ProximitySliderControl.SLIDER_SIDE_PADDING, 'y': 2, 'width': this.getSliderWidth() - ProximitySliderControl.SLIDER_SIDE_PADDING * 2, 'height': this.getSliderHeight(), 'style': `fill: url(#${gid})` });
|
|
|
|
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
|
const sliderInner = pxsim.svg.child(this.slider, "g");
|
|
pxsim.svg.child(sliderInner, "rect", { 'width': this.getSliderWidth(), 'height': ProximitySliderControl.SLIDER_HANDLE_HEIGHT, 'rx': '2', 'ry': '2', 'style': 'fill: #f12a21' });
|
|
pxsim.svg.child(sliderInner, "rect", { 'x': '0.5', 'y': '0.5', 'width': this.getSliderWidth() - 1, 'height': ProximitySliderControl.SLIDER_HANDLE_HEIGHT - 1, 'rx': '1.5', 'ry': '1.5', 'style': 'fill: none;stroke: #b32e29' });
|
|
|
|
const dragSurface = svg.child(this.group, "rect", {
|
|
x: 0,
|
|
y: 0,
|
|
width: this.getInnerWidth(),
|
|
height: this.getInnerHeight(),
|
|
opacity: 0,
|
|
cursor: '-webkit-grab'
|
|
})
|
|
|
|
let pt = parent.createSVGPoint();
|
|
let captured = false;
|
|
|
|
touchEvents(dragSurface, ev => {
|
|
if (captured && (ev as MouseEvent).clientY != undefined) {
|
|
ev.preventDefault();
|
|
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
|
}
|
|
}, ev => {
|
|
captured = true;
|
|
if ((ev as MouseEvent).clientY != undefined) {
|
|
dragSurface.setAttribute('cursor', '-webkit-grabbing');
|
|
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
|
}
|
|
}, () => {
|
|
captured = false;
|
|
dragSurface.setAttribute('cursor', '-webkit-grab');
|
|
})
|
|
|
|
return this.group;
|
|
}
|
|
|
|
getInnerHeight() {
|
|
return 192;
|
|
}
|
|
|
|
getInnerWidth() {
|
|
return 111;
|
|
}
|
|
|
|
private getReporterHeight() {
|
|
return 50;
|
|
}
|
|
|
|
private getSliderHeight() {
|
|
return 110;
|
|
}
|
|
|
|
private getSliderWidth() {
|
|
return 62;
|
|
}
|
|
|
|
updateState() {
|
|
if (!this.visible) {
|
|
return;
|
|
}
|
|
const node = this.state;
|
|
const percentage = node.getValue();
|
|
const y = this.getSliderHeight() * percentage / this.getMax();
|
|
this.slider.setAttribute("transform", `translate(0, ${y - ProximitySliderControl.SLIDER_HANDLE_HEIGHT / 2})`);
|
|
// Update reporter text
|
|
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}`;
|
|
}
|
|
|
|
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
|
let cur = svg.cursorPoint(pt, parent, ev);
|
|
const height = this.getSliderHeight();
|
|
const bBox = this.content.getBoundingClientRect();
|
|
let t = Math.max(0, Math.min(1, (ProximitySliderControl.SLIDER_HANDLE_HEIGHT + height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height))
|
|
|
|
const state = this.state;
|
|
const v = Math.floor((1 - t) * (this.getMax()));
|
|
state.setPromixity(v);
|
|
}
|
|
|
|
private getMin() {
|
|
return 0;
|
|
}
|
|
|
|
private getMax() {
|
|
return 100;
|
|
}
|
|
|
|
private getGradientDefinition(): LinearGradientDefinition {
|
|
return {
|
|
stops: [
|
|
{ offset: 0, color: '#626262' },
|
|
{ offset: 100, color: "#ddd" }
|
|
]
|
|
};
|
|
}
|
|
}
|
|
|
|
} |