Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
if (visible && autoRotate) requestAnimationFrame(frame);
$solid.scene.draw();
if (!dragging) $solid.object.rotation.y += speed * 0.012;
}
if (autoRotate) {
$solid.scene.$canvas.on('enterViewport', () => { visible = true; frame(); });
$solid.scene.$canvas.on('exitViewport', () => { visible = false; });
} else {
setTimeout(frame);
}
// The 1.1 creates rotations that are slightly faster than the mouse/finger.
const s = Math.PI / 2 / $solid.scene.$canvas.width * 1.1;
slide($solid.scene.$canvas, {
start() { dragging = true; },
move(posn, start, last) {
const d = posn.subtract(last).scale(s);
const q = new THREE.Quaternion().setFromEuler(new THREE.Euler(d.y, d.x));
$solid.object.quaternion.multiplyQuaternions(q, $solid.object.quaternion);
$solid.trigger('rotate', {quaternion: $solid.object.quaternion});
if (!autoRotate) frame();
},
end() { dragging = false; }
});
}
this.$canvas.css({width: this.sx + 'px', height: this.sy + 'px'});
this.loadBackground(this.attr('src'));
this.depthMap1 = repeat2D(0, this.sx, this.sy);
this.depthMap2 = repeat2D(0, this.sx, this.sy);
this.damping = +this.attr('damping') || 0.994;
this.clipping = +this.attr('clipping') || 5;
this.refraction = +this.attr('refraction') || 8;
this.reflection = +this.attr('reflection') || 1;
// The touch pattern is a 2D array containing numbers between -1 and 1.
this.touchPattern = this.createDropPattern(this.touchSize * 2);
slide(this.$canvas, {
start: (p) => this.touchWater(p.scale(1 / r), 0.5),
move: (p) => this.touchWater(p.scale(1 / r), 0.1)
});
}
constructor(shape: ShapeOptions, initial: {x: number, y: number, a?: number},
private readonly $parent: Tessellation) {
this.$el = $N('g', {class: 'shape'});
this.$shape =
$N('polygon', {points: shape.points, fill: shape.colour}, this.$el);
const $rotate = $N('circle', {r: 8, cy: -30}, this.$el);
this.polygon = polygonFromPoints(shape.points);
this.setPosition(new Point(initial.x, initial.y), initial.a || 0);
let offset: Point;
slide(this.$shape, {
start: p => {
$parent.$svg.append(this.$el); // Move element to the front.
offset = p.subtract(this.posn); // If you're not clicking in the center.
},
move: p => this.setPosition(p.subtract(offset), this.angle)
});
slide($rotate, {
move: p => this.setPosition(this.posn, getAngle(p, this.posn))
});
$parent.add(this);
}
constructor(private $svg: SVGParentView,
private readonly options: SketchOptions = {}) {
super();
$svg.addClass('drawing-pointer');
$svg.css('touch-action', 'none');
slide($svg, {
start: p => {
if (!this.options.noStart) this.start(p);
},
move: p => {
if (!this.drawing) return;
const box = $svg.viewBox;
if (!isBetween(p.x, 0, box.width) || !isBetween(p.y, 0, box.height))
return this.stop();
this.addPoint(p);
},
end: () => this.stop()
});
$body.on('scroll', () => this.stop());
obj.setRotationFromEuler(new THREE.Euler(Math.PI / 2, 0, 0));
cylinder.setClipPlanes!([new THREE.Plane(new THREE.Vector3(0, -1, 0), 1.4),
new THREE.Plane(new THREE.Vector3(0, 1, 0), 1.4)]);
function update(a: number) {
angle = a;
const dx = Math.tan(angle) * 1.4;
for (let obj of [top, topCircle]) obj.position.set(dx, 1.4, 0);
for (let obj of [bottom, bottomCircle]) obj.position.set(-dx, -1.4, 0);
cylinder.setRotationFromEuler(new THREE.Euler(0, 0, -angle));
cylinder.scale.set(Math.cos(angle), 1, 1);
scene.draw();
}
slide($solid, {
move: (p, _, last) => update(
clamp(angle + (p.x - last.x) / 150, -0.7, 0.7)),
end: () => $step.score('slide')
});
update(0.4);
return [top, bottom];
});
}
if (options.directed) {
let $defs = $N('defs', {}, $svg);
let $marker = $N('marker', {
id: 'arrow-head',
viewBox: '0 -5 10 10',
refX: '14',
refY: '0',
markerWidth: '6',
markerHeight: '6',
orient: 'auto'
}, $defs);
$N('path', {d: 'M0,-5L10,0L0,5', 'class': 'arrow'}, $marker);
}
slide($svg, {
start: (posn) => {
for (let v of this.vertices) {
if (Point.distance(posn, v.posn) < 18) {
this.dragging = v;
this.dragging.posn = posn;
this.stable = false;
this.redraw();
break;
}
}
},
move: (posn) => {
if (!this.dragging) return;
this.dragging.posn = posn;
this.redraw();
this.stable = false;
if (options.directed) {
let $defs = $N('defs', {}, $svg);
let $marker = $N('marker', {
id: 'arrow-head',
viewBox: '0 -5 10 10',
refX: '14',
refY: '0',
markerWidth: '6',
markerHeight: '6',
orient: 'auto'
}, $defs);
$N('path', { d: 'M0,-5L10,0L0,5', 'class': 'arrow' }, $marker);
}
slide($svg, {
start(posn) {
for (let v of _this.vertices) {
if (Point.distance(posn, v.posn) < 18) {
_this.dragging = v;
_this.dragging.posn = posn;
_this.stable = false;
_this.redraw();
break;
}
}
},
move(posn) {
if (!_this.dragging) return;
_this.dragging.posn = posn;
_this.redraw();
_this.stable = false;
$solids[1].addMesh((scene) => {
const geo = new THREE.CylinderGeometry(1.2, 1.2, 0.1, 64, 1);
const cylinders = tabulate(() => $solids[1].addSolid(geo, 0xfd8c00, 45),
20);
function update(s: number) {
shift = s;
cylinders.forEach(
(c, i) => c.position.set(s * (i / 10 - 1) / 2, -1 + 0.1 * i, 0));
scene.draw();
}
slide($solids[1], {
move: (p, _, last) => update(clamp(shift + (p.x - last.x) / 60, -2, 2)),
end: () => $step.score('slide')
});
update(0);
});
this.$svg = this.$('svg') as SVGParentView;
for (let c of INITIAL) new Shape(SHAPES[c.p], c, this);
for (let $a of this.$$('.add')) {
const s = +$a.data.shape!;
const shape = SHAPES[s];
$a.css('background', shape.colour);
const transform = `transform: translate(25px, 25px) scale(${1 / (1 + .4 *
s)})`;
$N('polygon', {points: shape.points, style: transform}, $a.$('svg'));
let instance: Shape;
let offset: Point;
slide($a, {
start: (p) => {
offset = new Point(this.bounds.left, this.bounds.top);
instance = new Shape(shape, p.subtract(offset), this);
this.trigger('add-shape');
},
move: p => instance.setPosition(p.subtract(offset), 0),
end: (a, b) => {
if (Point.distance(a, b) < 10) {
instance.setPosition(new Point(this.width / 2, this.height / 2), 0);
}
}
});
}
this.$('.clear')!.on('click', () => {
this.$svg.removeChildren();
$groups.on('change', $active => {
context.clearRect(0, 0, 1e10, 1e10);
activeGroup = +$active.data.value;
this.trigger('switch', activeGroup);
});
const $colours = this.$('x-select.colours') as Select;
context.fillStyle = $colours.$active.css('background-color')!;
$colours.on('change', $active => {
context.fillStyle = $active.css('background-color');
});
this.$('.clear')!.on('click', () => context.clearRect(0, 0, 1e10, 1e10));
this.$('.save')!.on('click', e => e.target.href = $canvas.pngImage);
slide($canvas, {
start: p => drawPoint(context, activeGroup, p),
move(p, _, last) {
let l = new Line(last, p);
let n = l.length / 8;
for (let i = 0; i < n; ++i) drawPoint(context, activeGroup,
l.at(i / n));
},
end: () => this.trigger('draw'),
justInside: true
});
}
}