namespace pxsim.visuals { export class DistanceSliderControl extends ControlView { private group: SVGGElement; private gradient: SVGLinearGradientElement; private slider: SVGGElement; private rect: SVGRectElement; private reporter: SVGTextElement; private static SLIDER_HANDLE_HEIGHT = 26; private static SLIDER_SIDE_PADDING = 6; getInnerWidth() { return 111; } getInnerHeight() { return 192; } private getReporterHeight() { return 38; } private getSliderWidth() { return 62; } private getSliderHeight() { return 131; } private getMaxValue() { return 250; // cm } updateState() { if (!this.visible) { return; } const node = this.state; const percentage = node.getValue() / 10; /* convert back to cm */ const y = this.getSliderHeight() * percentage / this.getMaxValue(); this.slider.setAttribute("transform", `translate(0, ${y - DistanceSliderControl.SLIDER_HANDLE_HEIGHT / 2})`); // Update reporter text this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}cm`; } updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) { let cur = svg.cursorPoint(pt, parent, ev); const bBox = this.rect.getBoundingClientRect(); const height = bBox.height; let t = Math.max(0, Math.min(1, (height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height)); const state = this.state; state.setDistance((1 - t) * (this.getMaxValue())); } getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) { let gid = "gradient-slider-" + this.getPort(); this.group = svg.elt("g") as SVGGElement; const prevGradient = globalDefs.querySelector(`#${gid}`) as SVGLinearGradientElement; this.gradient = prevGradient ? prevGradient : 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}, 20)`); 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.getInnerWidth() / 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.rect = rect as SVGRectElement; 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': DistanceSliderControl.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': DistanceSliderControl.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' }) as SVGRectElement; 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; } private getGradientDefinition(): LinearGradientDefinition { return { stops: [ { offset: 0, color: '#626262' }, { offset: 100, color: "#ddd" } ] }; } } }