Animation 2 complete.

master
Ben Burlingham 8 years ago
parent a799e30929
commit 628f1a3e24
  1. 43
      css/index.scss
  2. 34
      css/style.css
  3. 18
      index.html
  4. 78
      js/animation2.js
  5. 107
      js/bundle.js
  6. 21
      js/dom.js
  7. 8
      js/index.js
  8. 27
      res/seigaiha.svg

@ -1,19 +1,48 @@
.particles {
background: #fafafa;
border: 5px solid #fafafa;
border-radius: 3px;
height: 400px;
// background: url('../res/seigaiha.svg');
background-size: 100px 50px;
border-radius: 50px;
height: 600px;
margin: 10px auto;
position: relative;
width: 90%;
width: 600px;
}
.particle {
$side: 20px;
$side: 100px;
background: url('../res/seahorse.svg');
background-size: $side $side;
background: url('../res/seahorse.svg') no-repeat center center;
background-size: 20px 20px;
border-color: salmon;
border-style: dashed;
border-radius: 50px;
border-width: 1px;
height: $side;
position: absolute;
width: $side;
}
.highlight {
$h: 30px;
animation: pulse 0.5s 1;
border-radius: $h / 2;
position: absolute;
}
@keyframes pulse {
$h: 30px;
from {
border: 4px solid lightgreen;
height: $h;
margin: (-1 * $h / 2) 0 0 (-1 * $h / 2);
width: $h;
}
to {
height: 0px;
margin: 0;
width: 0px;
}
}

@ -1,18 +1,38 @@
.particles {
background: #fafafa;
border: 5px solid #fafafa;
border-radius: 3px;
height: 400px;
background-size: 100px 50px;
border-radius: 50px;
height: 600px;
margin: 10px auto;
position: relative;
width: 90%; }
width: 600px; }
.particle {
background: url(../res/seahorse.svg);
background: url(../res/seahorse.svg) no-repeat center center;
background-size: 20px 20px;
height: 20px;
border-color: salmon;
border-style: dashed;
border-radius: 50px;
border-width: 1px;
height: 100px;
position: absolute;
width: 20px; }
width: 100px; }
.highlight {
animation: pulse 0.5s 1;
border-radius: 15px;
position: absolute; }
@keyframes pulse {
from {
border: 4px solid lightgreen;
height: 30px;
margin: -15px 0 0 -15px;
width: 30px; }
to {
height: 0px;
margin: 0;
width: 0px; } }
* {
box-sizing: border-box;
margin: 0;

@ -3,12 +3,30 @@
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/style.css">
<!-- <script src='/core/js/ui.js'></script> -->
</head>
<body>
<h1>Dust</h1>
<h2>Swarm behavior experiments with RxJs</h2>
<hr>
<div class="particles"></div>
<h2>Animation 1</h2>
Goal: Animate several seahorses over an interval.
Key points:
- range() used to create N divs
- interval() used to create FPS
<h2>Animation 2</h2>
Goal: Scare a seahorse with a click. Move her to a safe distance away.
Key points:
- last() used with takeWhile() to only update state store at end
- scan() re-emits on each emission. reduce() only emits after last emission (take()).
- CustomEvent can bridge streams
- State store passed between streams
- Random movement vector, collision detection
<script src='js/bundle.js'></script>
</body>
</html>

@ -15,38 +15,90 @@ function checkScare([evt, store]) {
const diffX = Math.abs(state.x - evtX);
const diffY = Math.abs(state.y - evtY);
if (diffX < 50 && diffY < 50) {
if (evt.target === particleDiv) {
DOM.container.dispatchEvent(evtScare(evtX, evtY));
}
};
function move(acc, i) {
let { x, y, dx, dy } = acc;
const east = DOM.containerBounds.width - particleDiv.offsetWidth;
const south = DOM.containerBounds.height - particleDiv.offsetHeight;
x += dx;
y += dy;
if (x < 0) {
x = Math.abs(x);
dx = -dx;
}
if (x > east) {
x = Math.round(2 * east - x);
dx = -dx;
}
if (y < 0) {
y = Math.abs(y);
dy = -dy;
}
if (y > south) {
y = Math.round(2 * south - y);
dy = -dy;
}
return { x, y, dx, dy };
};
function flee([evt, store]) {
const initialState = store.get();
const fleeRadius = 200;
const { scareX, scareY } = evt.detail;
const fps$ = Rx.Observable.interval(1000 / 32);
fps$
.scan((acc, i) => {
return store.set({ x: acc.x + acc.dx, y: acc.y + acc.dy })
}, initialState)
const frames$ = fps$
.scan(move, initialState)
.takeWhile(state => {
const xDanger = Math.abs(initialState.x - state.x) < 150;
const yDanger = Math.abs(initialState.y - state.y) < 150;
const xDanger = Math.abs(initialState.x - state.x) < fleeRadius;
const yDanger = Math.abs(initialState.y - state.y) < fleeRadius;
return xDanger && yDanger;
})
.subscribe(state => {
particleDiv.style.left = `${state.x}px`;
particleDiv.style.top = `${state.y}px`;
})
frames$.last().subscribe(finalState => {
store.set(finalState);
store.set(randomMoveVector());
});
frames$.subscribe(state => {
particleDiv.style.left = `${state.x}px`;
particleDiv.style.top = `${state.y}px`;
});
};
function randomMoveVector() {
const speed = 5;
let dx = Math.round(Math.random() * speed);
let dy = Math.pow(Math.pow(speed, 2) - Math.pow(dx, 2), 0.5);
const negX = Math.random() < 0.5 ? -1 : 1;
const negY = Math.random() < 0.5 ? -1 : 1;
dx *= negX;
dy *= negY;
return { dx, dy };
}
function reset() {
if (particleDiv.parentNode) {
DOM.container.removeChild(particleDiv);
}
const store = new Store({ x: 10, y: 10, dx: 5, dy: 5 });
const { dx, dy } = randomMoveVector();
const store = new Store({ x: 0, y: 0, dx, dy });
const state = store.get();
particleDiv.style.top = `${state.y}px`;
@ -62,6 +114,8 @@ function init() {
const click$ = Rx.Observable
.fromEvent(DOM.container, 'click')
// .do(DOM.calcBounds)
.do(DOM.highlight)
.map(evt => [evt, store])
.subscribe(checkScare);

@ -6113,42 +6113,102 @@ function checkScare(_ref) {
var diffX = Math.abs(state.x - evtX);
var diffY = Math.abs(state.y - evtY);
if (diffX < 50 && diffY < 50) {
if (evt.target === particleDiv) {
_dom2.default.container.dispatchEvent(evtScare(evtX, evtY));
}
};
function move(acc, i) {
var x = acc.x,
y = acc.y,
dx = acc.dx,
dy = acc.dy;
var east = _dom2.default.containerBounds.width - particleDiv.offsetWidth;
var south = _dom2.default.containerBounds.height - particleDiv.offsetHeight;
x += dx;
y += dy;
if (x < 0) {
x = Math.abs(x);
dx = -dx;
}
if (x > east) {
x = Math.round(2 * east - x);
dx = -dx;
}
if (y < 0) {
y = Math.abs(y);
dy = -dy;
}
if (y > south) {
y = Math.round(2 * south - y);
dy = -dy;
}
return { x: x, y: y, dx: dx, dy: dy };
};
function flee(_ref3) {
var _ref4 = _slicedToArray(_ref3, 2),
evt = _ref4[0],
store = _ref4[1];
var initialState = store.get();
var fleeRadius = 200;
var _evt$detail = evt.detail,
scareX = _evt$detail.scareX,
scareY = _evt$detail.scareY;
var fps$ = _rxjs2.default.Observable.interval(1000 / 32);
fps$.scan(function (acc, i) {
return store.set({ x: acc.x + acc.dx, y: acc.y + acc.dy });
}, initialState).takeWhile(function (state) {
var xDanger = Math.abs(initialState.x - state.x) < 150;
var yDanger = Math.abs(initialState.y - state.y) < 150;
var frames$ = fps$.scan(move, initialState).takeWhile(function (state) {
var xDanger = Math.abs(initialState.x - state.x) < fleeRadius;
var yDanger = Math.abs(initialState.y - state.y) < fleeRadius;
return xDanger && yDanger;
}).subscribe(function (state) {
});
frames$.last().subscribe(function (finalState) {
store.set(finalState);
store.set(randomMoveVector());
});
frames$.subscribe(function (state) {
particleDiv.style.left = state.x + 'px';
particleDiv.style.top = state.y + 'px';
});
};
function randomMoveVector() {
var speed = 5;
var dx = Math.round(Math.random() * speed);
var dy = Math.pow(Math.pow(speed, 2) - Math.pow(dx, 2), 0.5);
var negX = Math.random() < 0.5 ? -1 : 1;
var negY = Math.random() < 0.5 ? -1 : 1;
dx *= negX;
dy *= negY;
return { dx: dx, dy: dy };
}
function reset() {
if (particleDiv.parentNode) {
_dom2.default.container.removeChild(particleDiv);
}
var store = new _store2.default({ x: 10, y: 10, dx: 5, dy: 5 });
var _randomMoveVector = randomMoveVector(),
dx = _randomMoveVector.dx,
dy = _randomMoveVector.dy;
var store = new _store2.default({ x: 0, y: 0, dx: dx, dy: dy });
var state = store.get();
particleDiv.style.top = state.y + 'px';
@ -6162,7 +6222,9 @@ function reset() {
function init() {
var store = reset();
var click$ = _rxjs2.default.Observable.fromEvent(_dom2.default.container, 'click').map(function (evt) {
var click$ = _rxjs2.default.Observable.fromEvent(_dom2.default.container, 'click')
// .do(DOM.calcBounds)
.do(_dom2.default.highlight).map(function (evt) {
return [evt, store];
}).subscribe(checkScare);
@ -6213,8 +6275,11 @@ __webpack_require__(72);
_animation4.default.init();
// TODO
// PR: https://github.com/ReactiveX/rxjs/blob/master/doc/decision-tree-widget/tree.yml#L122 "...time past since the last..."
// TODO ANIM2 clicking several times on seahorse creates jumpiness
// TODO display file contents in page
// TODO adding core UI breaks bounds
//
// TODO PR: https://github.com/ReactiveX/rxjs/blob/master/doc/decision-tree-widget/tree.yml#L122 "...time past since the last..."
//
// INTERMEDIATE TOPICS
// === I have one existing Observable and
@ -20110,11 +20175,10 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
var container = document.querySelector('.particles');
var containerBounds = document.querySelector('.particles').getBoundingClientRect();
var containerBounds = container.getBoundingClientRect();
var DOM = {
container: container,
containerBounds: containerBounds,
getEventOffsetCoords: function getEventOffsetCoords(evt, containerCoords) {
@ -20126,7 +20190,24 @@ var DOM = {
evtX: pageX - containerCoords.left,
evtY: pageY - containerCoords.top
};
},
highlight: function highlight(evt) {
var _DOM$getEventOffsetCo = DOM.getEventOffsetCoords(evt, DOM.containerBounds),
evtX = _DOM$getEventOffsetCo.evtX,
evtY = _DOM$getEventOffsetCo.evtY;
var highlightDiv = document.createElement('div');
highlightDiv.className = 'highlight';
highlightDiv.style.left = evtX + 'px';
highlightDiv.style.top = evtY + 'px';
DOM.container.appendChild(highlightDiv);
setTimeout(function () {
DOM.container.removeChild(highlightDiv);
}, 500);
}
};
exports.default = DOM;

@ -1,9 +1,8 @@
const container = document.querySelector('.particles');
const containerBounds = document.querySelector('.particles').getBoundingClientRect();
const containerBounds = container.getBoundingClientRect();
const DOM = {
container,
containerBounds,
getEventOffsetCoords: (evt, containerCoords) => {
@ -13,7 +12,23 @@ const DOM = {
evtX: (pageX - containerCoords.left),
evtY: (pageY - containerCoords.top)
};
}
},
highlight: (evt) => {
const { evtX, evtY } = DOM.getEventOffsetCoords(evt, DOM.containerBounds);
const highlightDiv = document.createElement('div');
highlightDiv.className = 'highlight';
highlightDiv.style.left = `${evtX}px`;
highlightDiv.style.top = `${evtY}px`;
DOM.container.appendChild(highlightDiv);
setTimeout(() => { DOM.container.removeChild(highlightDiv); }, 500);
},
// calcBounds: () => {
// DOM.containerBounds = container.getBoundingClientRect();
// },
};
export default DOM;

@ -8,9 +8,11 @@ require('../css/reset.scss');
Animation2.init();
// TODO
// PR: https://github.com/ReactiveX/rxjs/blob/master/doc/decision-tree-widget/tree.yml#L122 "...time past since the last..."
// TODO ANIM2 clicking several times on seahorse creates jumpiness
// TODO display file contents in page
// TODO adding core UI breaks bounds
//
// TODO PR: https://github.com/ReactiveX/rxjs/blob/master/doc/decision-tree-widget/tree.yml#L122 "...time past since the last..."
//
// INTERMEDIATE TOPICS
// === I have one existing Observable and

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<svg id="svg2" viewBox="0 0 200 100" preserveAspectRatio="xMinYMin" xmlns="http://www.w3.org/2000/svg">
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" id="path3067-3-6-7-5-3-6-9" d="M 199.489 49.534 C 199.489 104.372 155.034 148.828 100.196 148.828 C 45.358 148.828 0.902 104.372 0.902 49.534 C 0.902 -5.304 45.358 -49.76 100.196 -49.76 C 155.034 -49.76 199.489 -5.304 199.489 49.534 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path3067-3-6-7-5-2-3" d="M 182.941 49.534 C 182.941 95.233 145.894 132.279 100.196 132.279 C 54.497 132.279 17.452 95.233 17.452 49.534 C 17.452 3.835 54.497 -33.211 100.196 -33.211 C 145.894 -33.211 182.941 3.835 182.941 49.534 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" id="path3067-3-6-7-9-6" d="M 166.391 49.534 C 166.391 86.093 136.755 115.73 100.196 115.73 C 63.637 115.73 34 86.093 34 49.534 C 34 12.975 63.637 -16.662 100.196 -16.662 C 136.755 -16.662 166.391 12.975 166.391 49.534 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path3067-3-6-1-0" d="M 149.842 49.534 C 149.842 76.953 127.615 99.181 100.196 99.181 C 72.777 99.181 50.549 76.953 50.549 49.534 C 50.549 22.115 72.777 -0.113 100.196 -0.113 C 127.615 -0.113 149.842 22.115 149.842 49.534 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" id="path3067-3-2-6" d="M 133.294 49.534 C 133.294 67.814 118.475 82.632 100.196 82.632 C 81.916 82.632 67.098 67.814 67.098 49.534 C 67.098 31.255 81.916 16.436 100.196 16.436 C 118.475 16.436 133.294 31.255 133.294 49.534 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path3067-7-2" d="M 116.745 49.534 C 116.745 58.674 109.336 66.083 100.196 66.083 C 91.056 66.083 83.647 58.674 83.647 49.534 C 83.647 40.394 91.056 32.985 100.196 32.985 C 109.336 32.985 116.745 40.394 116.745 49.534 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 100.196 99.181 C 100.196 154.019 55.741 198.475 0.902 198.475 C -53.936 198.475 -98.391 154.019 -98.391 99.181 C -98.391 44.343 -53.936 -0.113 0.902 -0.113 C 55.741 -0.113 100.196 44.343 100.196 99.181 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="M 83.647 99.181 C 83.647 144.88 46.601 181.926 0.903 181.926 C -44.796 181.926 -81.842 144.88 -81.842 99.181 C -81.842 53.482 -44.796 16.436 0.903 16.436 C 46.601 16.436 83.647 53.482 83.647 99.181 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 67.098 99.181 C 67.098 135.74 37.461 165.377 0.902 165.377 C -35.657 165.377 -65.293 135.74 -65.293 99.181 C -65.293 62.622 -35.657 32.985 0.902 32.985 C 37.461 32.985 67.098 62.622 67.098 99.181 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="M 50.549 99.181 C 50.549 126.6 28.322 148.828 0.902 148.828 C -26.517 148.828 -48.744 126.6 -48.744 99.181 C -48.744 71.762 -26.517 49.534 0.902 49.534 C 28.322 49.534 50.549 71.762 50.549 99.181 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 34 99.181 C 34 117.461 19.182 132.279 0.903 132.279 C -17.377 132.279 -32.195 117.461 -32.195 99.181 C -32.195 80.902 -17.377 66.083 0.903 66.083 C 19.182 66.083 34 80.902 34 99.181 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="M 17.452 99.181 C 17.452 108.321 10.042 115.73 0.903 115.73 C -8.237 115.73 -15.646 108.321 -15.646 99.181 C -15.646 90.041 -8.237 82.632 0.903 82.632 C 10.042 82.632 17.452 90.041 17.452 99.181 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 298.783 99.181 C 298.783 154.019 254.328 198.475 199.489 198.475 C 144.651 198.475 100.196 154.019 100.196 99.181 C 100.196 44.343 144.651 -0.113 199.489 -0.113 C 254.328 -0.113 298.783 44.343 298.783 99.181 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="M 282.234 99.181 C 282.234 144.88 245.188 181.926 199.489 181.926 C 153.791 181.926 116.745 144.88 116.745 99.181 C 116.745 53.482 153.791 16.436 199.489 16.436 C 245.188 16.436 282.234 53.482 282.234 99.181 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 265.685 99.181 C 265.685 135.74 236.048 165.377 199.489 165.377 C 162.93 165.377 133.293 135.74 133.293 99.181 C 133.293 62.622 162.93 32.985 199.489 32.985 C 236.048 32.985 265.685 62.622 265.685 99.181 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="M 249.136 99.181 C 249.136 126.6 226.908 148.828 199.489 148.828 C 172.07 148.828 149.842 126.6 149.842 99.181 C 149.842 71.762 172.07 49.534 199.489 49.534 C 226.908 49.534 249.136 71.762 249.136 99.181 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 232.587 99.181 C 232.587 117.461 217.769 132.279 199.489 132.279 C 181.21 132.279 166.392 117.461 166.392 99.181 C 166.392 80.902 181.21 66.083 199.489 66.083 C 217.769 66.083 232.587 80.902 232.587 99.181 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="M 216.038 99.181 C 216.038 108.321 208.629 115.73 199.489 115.73 C 190.349 115.73 182.941 108.321 182.941 99.181 C 182.941 90.041 190.349 82.632 199.489 82.632 C 208.629 82.632 216.038 90.041 216.038 99.181 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 199.489 148.33 C 199.489 203.168 155.034 247.624 100.196 247.624 C 45.358 247.624 0.902 203.168 0.902 148.33 C 0.902 93.491 45.358 49.036 100.196 49.036 C 155.034 49.036 199.489 93.491 199.489 148.33 Z"/>
<path style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="M 182.941 148.33 C 182.941 194.029 145.894 231.075 100.196 231.075 C 54.497 231.075 17.452 194.029 17.452 148.33 C 17.452 102.631 54.497 65.585 100.196 65.585 C 145.894 65.585 182.941 102.631 182.941 148.33 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 166.391 148.33 C 166.391 184.889 136.755 214.526 100.196 214.526 C 63.637 214.526 34 184.889 34 148.33 C 34 111.771 63.637 82.134 100.196 82.134 C 136.755 82.134 166.391 111.771 166.391 148.33 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(255, 255, 255);" d="M 149.842 148.33 C 149.842 175.749 127.615 197.977 100.196 197.977 C 72.777 197.977 50.549 175.749 50.549 148.33 C 50.549 120.91 72.777 98.683 100.196 98.683 C 127.615 98.683 149.842 120.91 149.842 148.33 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(250, 250, 250);" d="M 133.294 148.33 C 133.294 166.61 118.475 181.428 100.196 181.428 C 81.916 181.428 67.098 166.61 67.098 148.33 C 67.098 130.05 81.916 115.232 100.196 115.232 C 118.475 115.232 133.294 130.05 133.294 148.33 Z"/>
<path style="color: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 6; marker: none; visibility: visible; display: inline; overflow: visible; fill: rgb(255, 255, 255);" d="M 116.745 148.33 C 116.745 157.469 109.336 164.879 100.196 164.879 C 91.056 164.879 83.647 157.469 83.647 148.33 C 83.647 139.19 91.056 131.781 100.196 131.781 C 109.336 131.781 116.745 139.19 116.745 148.33 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 9.9 KiB

Loading…
Cancel
Save