mo.js animation for multiple items - javascript

I need your help.
To apply animation to multiple elements with a single class of "my-button"? Now this only works for a single button.
Replacement querySelector on querySelectorAll not solve the problem, the script becomes not working
Thank you.
var el = document.querySelector('.my-button'),
elSpan = el.querySelector('span'),
// mo.js timeline obj
timeline = new mojs.Timeline(),
scaleCurve = mojs.easing.path('M0,100 L25,99.9999983 C26.2328835,75.0708847 19.7847843,0 100,0'),
// tweens for the animation:
// burst animation
tween1 = new mojs.Burst({
parent: el,
duration: 1500,
shape : 'circle',
fill : [ '#e67e22', '#DE8AA0', '#8AAEDE', '#8ADEAD', '#DEC58A', '#8AD1DE' ],
x: '50%',
y: '50%',
opacity: 0.8,
childOptions: { radius: {20:0} },
radius: {40:120},
angle: {0: 180},
count: 8,
isSwirl: true,
isRunLess: true,
easing: mojs.easing.bezier(0.1, 1, 0.3, 1)
}),
// ring animation
tween2 = new mojs.Transit({
parent: el,
duration: 750,
type: 'circle',
radius: {0: 50},
fill: 'transparent',
stroke: '#2ecc71',
strokeWidth: {15:0},
opacity: 0.6,
x: '50%',
y: '50%',
isRunLess: true,
easing: mojs.easing.bezier(0, 1, 0.5, 1)
}),
// icon scale animation
tween3 = new mojs.Tween({
duration : 900,
onUpdate: function(progress) {
if(progress > 0.3) {
var scaleProgress = scaleCurve(progress);
elSpan.style.WebkitTransform = elSpan.style.transform = 'scale3d(' + scaleProgress + ',' + scaleProgress + ',1)';
elSpan.style.WebkitTransform = elSpan.style.color = '#2ecc71';
} else {
elSpan.style.WebkitTransform = elSpan.style.transform = 'scale3d(0,0,1)';
elSpan.style.WebkitTransform = elSpan.style.color = 'rgba(0,0,0,0.3)';
}
}
});
// add tweens to timeline:
timeline.add(tween1, tween2, tween3);
// when clicking the button start the timeline/animation:
el.addEventListener('mousedown', function() {
timeline.start();
});
.wrapper {
display: flex;
justify-content: center;
align-items: center;
align-content: center;
text-align: center;
height: 200px;
}
.my-button {
background: transparent;
border: none;
outline: none;
margin: 0;
padding: 0;
position: relative;
text-align:center;
}
svg {
top: 0;
left: 0;
}
.send-icon {
position: relative;
font-size: 40px;
color: rgba(0,0,0,0.3);
}
<link href="http://fontawesome.io/assets/font-awesome/css/font-awesome.css" rel="stylesheet"/>
<script src="http://netgon.net/mo.min.js"></script>
<div class="wrapper">
<button class="my-button">
<span class="send-icon fa fa-paper-plane"></span>
</button>
</div>
Codepen

Working CodePen Here!
the "parent element" el must be a single element, so achieving this would be tricky and create a complicated messy code.
so I created a different method that'll create the animations once and set their position using tune() when a button is clicked, this will improve performance since you only have one animation object in the DOM.
instead of creating three animations for each parent/button.
I listen to the all buttons with the class "my-button" set animation's top and left values accordingly
$( ".my-button" ).on( "click", function() {
aniPos = findCenter($(this));
myAnimation1.tune({ top: aniPos.y, left: aniPos.x });
myAnimation2.tune({ top: aniPos.y, left: aniPos.x });
myTimeline.replay();
anipos is calculated with a simple function that'll return an object with .x and .y values
function findCenter ($this) {
var offset = $this.offset();
var width = $this.width();
var height = $this.height();
IDs = {
x: offset.left + (width / 2),
y: offset.top + (height / 2)
};
console.log(offset);
return IDs;
}
I also added a method to animate the clicked button automatically.
elSpan = this.querySelector('span');
new mojs.Tween({
duration : 900,
onUpdate: function(progress) {
if(progress > 0.3) {
var scaleProgress = scaleCurve(progress);
elSpan.style.WebkitTransform = elSpan.style.transform = 'scale3d(' + scaleProgress + ',' + scaleProgress + ',1)';
elSpan.style.WebkitTransform = elSpan.style.color = '#2ecc71';
} else {
elSpan.style.WebkitTransform = elSpan.style.transform = 'scale3d(0,0,1)';
elSpan.style.WebkitTransform = elSpan.style.color = 'rgba(0,0,0,0.3)';
}
}
}).play();
});
please note that my example will require JQuery to work.
I used the exact animations you provided but you can change them as long as you don't change X, Y, top and left properties

Related

Add element using javascript at specific position

I'm creating a small game to use in one of my English classes. I've managed to add all the items and create the animations of the items.
What I need now is to place the items in their fixed and starting positions. The blue and red items have their fixed positions at the bottom corner of each side and the soccerball starts in the middle before any movement.
I don't know how to do this. Can anybody help me or point me in the right direction, please.
This is what I have now:
This is what I would like to do:
This is my code so far
<script>
//Set Background
document.body.style.backgroundImage =
"url('./back.jpg')";
document.body.style.backgroundSize = 'contain';
document.body.style.backgroundRepeat = 'no-repeat';
document.body.style.backgroundPosition = 'center';
document.body.style.backgroundSize = '100%';
//Add images
function show_image(src, width, height, alt, id) {
var img = document.createElement("img");
img.src = src;
img.width = width;
img.height = height;
img.alt = alt;
img.id = id;
if (id == "s") {
img.style.position = "center"
}
document.body.appendChild(img);
}
show_image("./b.png", 100, 100, "btnBlue", "b")
show_image("./r.png", 100, 100, "btnRed", "r")
show_image("./s.png", 100, 100, "btnSoccerBall", "s")
//Add onclick
document.getElementById("b").addEventListener("click", myMoveLeft);
document.getElementById("r").addEventListener("click", myMoveRight);
//Add animation
var item = document.getElementById('s');
var anim;
var x = 0, y = 0;
function myMoveLeft() {
anim = item.animate([
// keyframes
{ transform: `translate(${x}px, ${y}px)` },
{ transform: `translate(${x - 60}px, ${y}px)` }
], {
duration: 1000,
iterations: 1,
fill: 'forwards'
});
x -= 60;
}
function myMoveRight() {
anim = item.animate([
// keyframes
{ transform: `translate(${x}px, ${y}px)` },
{ transform: `translate(${x + 60}px, ${y}px)` }
], {
duration: 1000,
iterations: 1,
fill: 'forwards'
});
x += 60;
}
item.addEventListener('animationend', () => {
console.log('Animation ended');
});
</script>
I think what you want to achieve can be done with CSS, specifically by using Flexbox.
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 5rem;
}
.btnBlue {
color: blue;
}
.btnRed {
color: red;
}
.btnSoccerBall {
color: white;
position: relative;
margin: auto;
}
.soccer-field {
background-color: lightgreen;
height: 100vh;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
padding: 0 20px; /*optional*/
}
<html lang="en">
<body>
<div class="soccer-field">
<div class="btnBlue">O</div>
<div class="btnSoccerBall">O</div>
<div class="btnRed">O</div>
</div>
</body>
</html>

Scroll area by mouse drag in qooxdoo?

Is there any built in possibily to drag content inside container by dragging for example qx.ui.container.Scroll? I found there are qx.ui.core.MDragDropScrolling and qx.ui.core.DragDropScrolling but don't know that is what I am looking for.
Try the code below (eg copy and paste into the Qooxdoo playground).
It traps the mouse movements and apply the relative movement of the mouse (while the button is down) to the scroll bars
// This is a little hack to persuade Chrome to always show the scroll bars
qx.bom.Stylesheet.createElement(
"::-webkit-scrollbar { -webkit-appearance: none; width: 7px; }\n" +
"::-webkit-scrollbar-thumb { border-radius: 4px; background-color: rgba(0, 0, 0, .5); box-shadow: 0 0 1px rgba(255, 255, 255, .5); }\n"
);
// This is a simple thing to add a border to our bigWidget
var border = new qx.ui.decoration.Decorator().set({
width: 3,
style: "solid",
color: "black"
});
// Creates a massive widget
var bigWidget = new qx.ui.core.Widget().set({
minWidth: 2000,
minHeight: 2000,
backgroundColor: "red",
decorator: border
});
// Scrollable area
var scrollable = new qx.ui.container.Scroll(bigWidget).set({
scrollbar: [ "on", "on" ]
});
var mouseDown = false;
var mouseStartPos = null;
var widgetStartPos = null;
bigWidget.addListener("mousedown", evt => {
mouseDown = true;
mouseStartPos = { top: evt.getScreenTop(), left: evt.getScreenLeft() };
widgetStartPos = { top: scrollable.getScrollX(), left: scrollable.getScrollY() };
});
bigWidget.addListener("mouseup", () => {
mouseDown = false;
});
bigWidget.addListener("mousemove", evt => {
if (!mouseDown || !evt.isLeftPressed())
return;
let deltaPos = { top: mouseStartPos.top - evt.getScreenTop(), left: mouseStartPos.left - evt.getScreenLeft() };
scrollable.scrollToX(widgetStartPos.left - deltaPos.left);
scrollable.scrollToY(widgetStartPos.top - deltaPos.top);
console.log("deltaPos=" + JSON.stringify(deltaPos) + ", mouseStartPos=" + JSON.stringify(mouseStartPos) + ", widgetStartPos=" + JSON.stringify(widgetStartPos));
});
var doc = this.getRoot();
doc.add(scrollable, {
left : 0,
top : 0,
right: 0,
bottom: 0
});

Spinner using spin.js Not Spinning

Good day Guys,
I am trying to use a spinner that shows on the entire page when i click on Submit button. The below are the codes snippets.
This is the JS code
<script type="text/javascript"
src="#Url.Content("~/Scripts/spin.js")"></script>
<script type="text/javascript">
$(function () {
$("#searchbtn").click(function () {
$("#loading").fadeIn();
var opts = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 4, // The line thickness
radius: 10, // The radius of the inner circle
color: '#000', // #rgb or #rrggbb
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false // Whether to use hardware acceleration
};
var target = document.getElementById('loading');
//var spinner = new Spinner(opts).spin(target);
var spinner = new Spin.Spinner(opts).spin(target);
});
});
This is the CSS below
#loading {
display: none;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,0.8);
z-index: 1000;
}
#loadingcontent {
display: table;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#loadingspinner {
display: table-cell;
vertical-align: middle;
width: 100%;
text-align: center;
font-size: larger;
padding-top: 80px;
}
Below is the DIV that holds the searching.
<div id="loading">
<div id="loadingcontent">
<p id="loadingspinner">
Searching things...
</p>
</div>
</div>
<div class="col-md-12">
<p>
#using (Html.BeginForm("AllLoanProcessed", "Transactions", new { area = "Transactions" }, FormMethod.Get))
{
<b>Search By:</b>
#Html.RadioButton("searchBy", "Account_Number", true) <text>Account Number</text>
#Html.RadioButton("searchBy", "Surname") <text> Surname </text> <br />
#Html.TextBox("search", null, new { placeholder = "Search Value", #class = "form-control" })
<br />
<input type="submit" value="Search" id="searchbtn" class="btn btn-primary btn-block" />
}
</p>
</div>
The issue is that, when i click on the search button, The spin does not load.
Am I missing something? OR any one has any other spinner method that works that will cover the whole page when running.
EDIT:
The below is the spin.js file content.
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function (t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var defaults = {
lines: 12,
length: 7,
width: 5,
radius: 10,
scale: 1.0,
corners: 1,
color: '#000',
fadeColor: 'transparent',
animation: 'spinner-line-fade-default',
rotate: 0,
direction: 1,
speed: 1,
zIndex: 2e9,
className: 'spinner',
top: '50%',
left: '50%',
shadow: '0 0 1px transparent',
position: 'absolute',
};
var Spinner = /** #class */ (function () {
function Spinner(opts) {
if (opts === void 0) { opts = {}; }
this.opts = __assign(__assign({}, defaults), opts);
}
/**
* Adds the spinner to the given target element. If this instance is already
* spinning, it is automatically removed from its previous target by calling
* stop() internally.
*/
Spinner.prototype.spin = function (target) {
this.stop();
this.el = document.createElement('div');
this.el.className = this.opts.className;
this.el.setAttribute('role', 'progressbar');
css(this.el, {
position: this.opts.position,
width: 0,
zIndex: this.opts.zIndex,
left: this.opts.left,
top: this.opts.top,
transform: "scale(" + this.opts.scale + ")",
});
if (target) {
target.insertBefore(this.el, target.firstChild || null);
}
drawLines(this.el, this.opts);
return this;
};
/**
* Stops and removes the Spinner.
* Stopped spinners may be reused by calling spin() again.
*/
Spinner.prototype.stop = function () {
if (this.el) {
if (typeof requestAnimationFrame !== 'undefined') {
cancelAnimationFrame(this.animateId);
}
else {
clearTimeout(this.animateId);
}
if (this.el.parentNode) {
this.el.parentNode.removeChild(this.el);
}
this.el = undefined;
}
return this;
};
return Spinner;
}());
export { Spinner };
/**
* Sets multiple style properties at once.
*/
function css(el, props) {
for (var prop in props) {
el.style[prop] = props[prop];
}
return el;
}
/**
* Returns the line color from the given string or array.
*/
function getColor(color, idx) {
return typeof color == 'string' ? color : color[idx % color.length];
}
/**
* Internal method that draws the individual lines.
*/
function drawLines(el, opts) {
var borderRadius = (Math.round(opts.corners * opts.width * 500) / 1000) +
'px';
var shadow = 'none';
if (opts.shadow === true) {
shadow = '0 2px 4px #000'; // default shadow
}
else if (typeof opts.shadow === 'string') {
shadow = opts.shadow;
}
var shadows = parseBoxShadow(shadow);
for (var i = 0; i < opts.lines; i++) {
var degrees = ~~(360 / opts.lines * i + opts.rotate);
var backgroundLine = css(document.createElement('div'), {
position: 'absolute',
top: -opts.width / 2 + "px",
width: (opts.length + opts.width) + 'px',
height: opts.width + 'px',
background: getColor(opts.fadeColor, i),
borderRadius: borderRadius,
transformOrigin: 'left',
transform: "rotate(" + degrees + "deg) translateX(" + opts.radius +
"px)",
});
var delay = i * opts.direction / opts.lines / opts.speed;
delay -= 1 / opts.speed; // so initial animation state will include trail
var line = css(document.createElement('div'), {
width: '100%',
height: '100%',
background: getColor(opts.color, i),
borderRadius: borderRadius,
boxShadow: normalizeShadow(shadows, degrees),
animation: 1 / opts.speed + "s linear " + delay + "s infinite " +
opts.animation,
});
backgroundLine.appendChild(line);
el.appendChild(backgroundLine);
}
}
function parseBoxShadow(boxShadow) {
var regex = /^\s*([a-zA-Z]+\s+)?(-?\d+(\.\d+)?)([a-zA-Z]*)\s+(-?\d+(\.\d+)?)
([a-zA-Z]*)(.*)$/;
var shadows = [];
for (var _i = 0, _a = boxShadow.split(','); _i < _a.length; _i++) {
var shadow = _a[_i];
var matches = shadow.match(regex);
if (matches === null) {
continue; // invalid syntax
}
var x = +matches[2];
var y = +matches[5];
var xUnits = matches[4];
var yUnits = matches[7];
if (x === 0 && !xUnits) {
xUnits = yUnits;
}
if (y === 0 && !yUnits) {
yUnits = xUnits;
}
if (xUnits !== yUnits) {
continue; // units must match to use as coordinates
}
shadows.push({
prefix: matches[1] || '',
x: x,
y: y,
xUnits: xUnits,
yUnits: yUnits,
end: matches[8],
});
}
return shadows;
}
/**
* Modify box-shadow x/y offsets to counteract rotation
*/
function normalizeShadow(shadows, degrees) {
var normalized = [];
for (var _i = 0, shadows_1 = shadows; _i < shadows_1.length; _i++) {
var shadow = shadows_1[_i];
var xy = convertOffset(shadow.x, shadow.y, degrees);
normalized.push(shadow.prefix + xy[0] + shadow.xUnits + ' ' + xy[1] +
shadow.yUnits + shadow.end);
}
return normalized.join(', ');
}
function convertOffset(x, y, degrees) {
var radians = degrees * Math.PI / 180;
var sin = Math.sin(radians);
var cos = Math.cos(radians);
return [
Math.round((x * cos + y * sin) * 1000) / 1000,
Math.round((-x * sin + y * cos) * 1000) / 1000,
];
}

Trying the native Element.animate method, but cannot add keyframe percentages

Someone asked a related question and I am trying to make it work with the experimental technology Element.animate.
The MDN documentation is rather...slim and the state of the technology is lets say infantile.
https://developer.mozilla.org/en-US/docs/Web/API/Element/animate
What I have is this markup:
<div class="container">
<div id="movetxt">left to right, right to left</div>
</div>
Just want the movetxt div to move from left to right ad infinity within the container div.
Css is hard coded, as I do not know how to get the width of the div text node.
.container {
margin: 0 auto;
width: 300px;
border: 1px solid red;
}
#movetxt {
width: 180px;
}
Now, the JS
var container = document.querySelector(".container");
var movingText = document.getElementById("movetxt");
var containerWidth = container.offsetWidth;
var textWidth = movingText.offsetWidth;
var totalDistance = containerWidth - textWidth;
var oneWayDistance = totalDistance / 2; //just establishing the travel distance
And now the experiment part:
movingText.animate([
// keyframes
{ transform: 'translateX(' + oneWayDistance + 'px)' },
{ transform: 'translateX(-' + totalDistance + 'px)' }
], {
// timing options
duration: 1000,
iterations: Infinity
});
This kind of works, the console throws some errors, but the thing runs.
But, I want to have this kind of keyframas format, just an example:
0% { transform: 'translateX(' + oneWayDistance + 'px)' },
10% { transform: 'translateX(-' + totalDistance + 'px)' }
If I try that, I get Failed to execute 'animate' on 'Element': Keyframes must be objects, or null or undefined.
Link to fiddle:
http://jsfiddle.net/vdb3ofmL/1135/
There must be some way to place the keyframe % values there, can anyone figure this out?
Cheers
You need to consider the fact that the text is initially on the left edge of the container, so you need to translate form 0 to width of container - width of text:
And what you are looking for is the offset valueref
var container = document.querySelector(".container");
var movingText = document.getElementById("movetxt");
var containerWidth = container.offsetWidth;
var textWidth = movingText.offsetWidth;
var totalDistance = containerWidth - textWidth;
var oneWayDistance = totalDistance / 2;
console.log(containerWidth);
console.log(textWidth);
movingText.animate([
// keyframes
{ transform: 'translateX(0)',offset:0 }, /*0%*/
{ transform: 'translateX(' + totalDistance + 'px)',offset:0.3 }, /*30%*/
{ transform: 'translateX(0)',offset:1 } /*100%*/
], {
// timing options
duration: 1000,
iterations: Infinity
});
.container {
margin: 0 auto;
width: 300px;
border: 1px solid red;
}
#movetxt {
width: 180px;
border:1px solid;
}
<div class="container">
<div id="movetxt">left to right, right to left</div>
</div>
You should use offset like this
element.animate({
opacity: [ 0, 0.9, 1 ],
offset: [ 0, 0.8 ], // Shorthand for [ 0, 0.8, 1 ]
easing: [ 'ease-in', 'ease-out' ],
}, 2000);
and in your case you can use like this and change your own
var container = document.querySelector(".container");
var movingText = document.getElementById("movetxt");
var containerWidth = container.offsetWidth;
var textWidth = movingText.offsetWidth;
var totalDistance = containerWidth - textWidth;
var oneWayDistance = totalDistance / 2;
movingText.animate(
{transform:['translateX(' + oneWayDistance + 'px)','translateX(-' + totalDistance + 'px)','translateX(' + oneWayDistance + 'px)'],
offset: [0,0.1]
}, {
duration: 1000,
iterations: Infinity
});
.container {
margin: 0 auto;
width: 300px;
border: 1px solid red;
}
#movetxt {
width: 180px;
}
<div class="container">
<div id="movetxt">left to right, right to left</div>
</div>

How to insert a faceless square of a person into an image?

The user forwards an image and receives a response through a json on that image, one of the answers is as follows:
"faceRectangle": {
"top": 187,
"left": 458,
"width": 186,
"height": 186
},
The big question is:
Through the information shown above, how do I insert a square in each
top and left with the javascript?
MY CODE [CSS]
.teste {
border-radius: 0px 0px 0px 0px;
-moz-border-radius: 0px 0px 0px 0px;
-webkit-border-radius: 0px 0px 0px 0px;
border: 5px solid #efff0d;
}
MY CODE [HTML]
<div class="col s12 m12 l6 xl6 center-align">
<div class="container-image-uploaded">
<div id="teste"></div>
<img id="sourceImagem" class="responsive-img sourceImagem">
</div>
</div>
MY CODE [JAVASCRIPT]
document.getElementById('teste').innerHTML.style.width += obj[o].faceRectangle.width + "px";
document.getElementById('teste').innerHTML.style.height += obj[o].faceRectangle.height + "px";
document.getElementById('teste').innerHTML.style.top += obj[o].faceRectangle.top + "px";
document.getElementById('teste').innerHTML.style.left += obj[o].faceRectangle.left + "px";
I would prefer to use appendChild because then you can create your new dom elements in memory and add it with this method.
.innerHtml is also working but then you're more working with strings.
Please have a look at the demo below or this fiddle.
Vue.js is not really needed in this example but with it's easier to work component based. If you don't know Vue then just have a look at the add method that's called by the mousedown eventhandler markImage.
As O'Kane mentioned in the comments, you need to be careful with your string concatenation. I'm using back-tick syntax / template string for the strings in my demo so you can easily insert your values into the string. e.g.
var style = `
left: ${pos.x}px;
top: ${pos.y}px;`
The same is also possible with single quotes but that's harder to write. e.g.
var style = 'left: ' + pos.x + 'px; top: ' + pos.y + 'px;'
Note: Babel is required to work with template strings. With-out it browser support is limited see here
In the demo I've created two variants:
SVG rectangles (less css required to make it work)
DIVs like your code (requires more css)
I think both variants are working and OK. I would probably use SVG because it's easier to create and also exporting later is no problem. e.g. if you like to save it as a new image.
A note to the css
The following zero-space width character is needed to have the div react on the size specified. Probably setting min-width would also work.
.image-marker-png:after {
content: '\200b';
}
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
const svgOutput = {
mounted () {
this.svg = this.$el.querySelector('svg')
let img = document.createElementNS('http://www.w3.org/2000/svg', 'image')
img.setAttribute('x', 0)
img.setAttribute('y', 0)
img.setAttribute('width', '100%')
img.setAttribute('height', '100%')
img.setAttribute('href', 'https://unsplash.it/300')
console.log(img)
this.svg.appendChild(img)
// setInterval(this.add, 50)
this.image = this.svg.querySelector('image')
this.image.addEventListener('mousedown', this.markImage)
},
beforeDestroy() {
// clean listeners
this.image.removeEventListener('mousedown', this.markImage)
},
template: `
<div>
<svg width="300px" height="300px" xmlns="http://www.w3.org/2000/svg"></svg>
<button #click="add">add random</button>
<button #click="add($event, {x: 20, y: 40}, {width: 50, height: 100})">
add "x20,y40,w50,h100"
</button>
</div>
`,
methods: {
add (evt, pos, dimension, color) {
let rectangle = document.createElementNS("http://www.w3.org/2000/svg", 'rect')
let containerSize = this.svg.getBoundingClientRect();
dimension = dimension || {}
pos = pos || {}
let sizeX = dimension.width || 50;
let sizeY = dimension.height || 50;
let x = pos.x || (Math.random()*(containerSize.width) - sizeX)
let y = pos.y || (Math.random()*(containerSize.height) - sizeY)
// some limiting
if (x > containerSize.width) {
x = containerSize.width - sizeX + 1
}
if (x < 0) {
x = 1
}
if (y > containerSize.height) {
y = containerSize.height - sizeY + 1
}
if (y < 0) {
y = 1
}
rectangle.setAttribute('class', 'image-marker')
rectangle.setAttribute('width', sizeX)
rectangle.setAttribute('height', sizeY)
rectangle.setAttribute('x', x)
rectangle.setAttribute('y', y)
rectangle.setAttribute('fill', color || getRandomColor())
rectangle.setAttribute('stroke', 'black')
this.svg.appendChild(rectangle)
},
markImage (evt) {
console.log('clicked svg', evt)
this.add(evt, {x: evt.offsetX, y: evt.offsetY}, {width: 20, height: 20})
}
}
}
const imgOutput = {
beforeDestroy() {
// clean listeners
this.container.removeEventListener('mousedown', this.markImage)
},
mounted() {
this.container = this.$el
this.container.addEventListener('mousedown', this.markImage)
},
template: `
<div class="image-container">
<img src="https://unsplash.it/300"/>
</div>
`,
methods: {
add (evt, pos, dimension, color) {
let marker = document.createElement('div')
marker.setAttribute('class', 'image-marker-png')
marker.setAttribute('style', `
left: ${pos.x}px;
top: ${pos.y}px;
width: ${dimension.width}px;
height: ${dimension.height}px;
background-color: ${color || getRandomColor()}`)
console.log('add marker', marker)
this.container.appendChild(marker)
},
markImage (evt) {
console.log('clicked image', evt)
this.add(evt, {x: evt.offsetX, y: evt.offsetY}, {width: 20, height: 20})
}
}
}
console.log(imgOutput)
new Vue({
components: {
svgOutput,
imgOutput
},
el: '#app'
})
.image-marker:hover {
stroke-width: 1px;
stroke: yellow;
}
.image-container {
position: relative;
display: inline-block;
overflow: hidden;
}
.image-marker-png {
position: absolute;
z-index: +1;
}
.image-marker-png:hover{
border: 1px solid yellow;
}
.image-marker-png:after {
content: '\200b';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<svg-output></svg-output>
<img-output></img-output>
</div>

Categories