How to add Dom element dynamically in angular7 - angular7

I am using angular 7 and I need to add a Dom element dynamically through the code.
I know the way of doing it in JavaScript
var adiv = document.createElement('div');
adiv.classList.add("redmark");
adiv.style.position = "absolute";
document.body.appendChild(adiv);
adiv.innerHTML = '< img src="css/led_red.png" class="zoom" style="position: absolute;">';
adiv.style.display = "";
adiv.style.left = (position.x - 16) + 'px';
adiv.style.top = (position.y - 32) + 'px';
var markObj = { position: [x, y, z], mark: “as”}
But how to do it in angular?

Related

Highcharts - Markers in line charts move up when leaving hovering

I am trying to use Font Awesome icons as markers in HighCharts line chart. With help from fellow developers on Stack Overflow, I have managed to do that. One problem left is that now, whenever I hover over the markers and then leave hovering, they just move up a bit from the line and stay there forever. I really have no idea why.
This is the fiddle: https://jsfiddle.net/vf0g4u5k/12/. Appreciate any help.
The plug-in to use Font Awesome with HighCharts
(function (H) {
function symbolWrap(proceed, symbol, x, y, w, h, options) {
if (symbol.indexOf('text:') === 0) {
var text = symbol.split(':')[1],
svgElem = this.text(text, x, y + h)
.css({
fontFamily: '"Font Awesome 5 Free"',
fontSize: (h * 2 ) + "px"
});
if (svgElem.renderer.isVML) {
svgElem.fillSetter = function (value, key, element) {
element.style.color = H.Color(value).get('rgb');
};
}
return svgElem;
}
if (symbol.indexOf('textn:') === 0) {
var text = symbol.split(':')[1],
svgElem = this.text(text, x, y + h)
.css({
fontFamily: '"Font Awesome 5 Free"',
fontSize: (h * 2 ) + "px",
fontWeight: 900
});
if (svgElem.renderer.isVML) {
svgElem.fillSetter = function (value, key, element) {
element.style.color = H.Color(value).get('rgb');
};
}
return svgElem;
}
return proceed.apply(this, [].slice.call(arguments, 1));
}
H.wrap(H.SVGRenderer.prototype, 'symbol', symbolWrap);
if (H.VMLRenderer) {
H.wrap(H.VMLRenderer.prototype, 'symbol', symbolWrap);
}
// Load the font for SVG files also
H.wrap(H.Chart.prototype, 'getSVG', function (proceed) {
var svg = proceed.call(this);
svg = '<?xml-stylesheet type="text/css" ' +
'href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" ?>' +
svg;
return svg;
});
}(Highcharts));
I ended up doing like this. Posting in case it may help someone else.
point: {
events: {
mouseOut: function() {
var index = this.index
for( var series of this.series.chart.series){
for(var j=0;j<series.points.length;j++){
if(j === index && series.points[j].graphic){series.points[j].graphic.attr({'translateY': 8})}
}
};
}
}
}
You can adjust your custom marker settings by setting translateX and translateY like this
var text = symbol.split(':')[1],
svgElem = this.text(text, x, y)
.attr({
translateY: h,
translateX: -1
})
.css({
fontFamily: '"Font Awesome 5 Free"',
fontSize: (h * 2 ) + "px"
});

Correctly apply transformation when moving shapes out of group onto layer

ok so the reason for this question is that i am trying to deal with multiple konva shapes at a time. in the original project the shapes are being selected by drawing a momentary rectangle around the shapes that you want selected (rectangular selection). I have seen some of the other post about this, but they only seem to deal with the selection itself, i have that working.
Here is a codepen example that illustrates the problem.
link
Instructions:
click the select button to have the two shapes put in a group and a transformer applied
Rotate and scale the selected shapes.
click the deselect button to have the shapes moved back onto the layer.
The parts that is interresting is after line 92, where i am exploring different methods of moving the shapes back onto the layer.
children.toArray().forEach(e => {
// Need to apply transformations correctly before putting back on layer
//Method 1
if (method === 1) {
let newTransforms = e.getAbsoluteTransform();
let localTransforms = e.getTransform();
let m = newTransforms.getMatrix();
let matrices = getMatrix(e);
console.log("matrix before : ");
console.log(matrices);
e.rotation(selectionGroupRotation);
e.skew({ x: m[1], y: m[2] });
e.scale({ x: m[0], y: m[3] });
e.position({ x: m[4], y: m[5] })
m = newTransforms.getMatrix();
matrices = getMatrix(e);
console.log("matrix after : ");
// console.log(m);
console.log(matrices);
}
//Method 2
if (method === 2) {
let groupPos = selectionGroup.position();
let point = { x: groupPos.x, y: groupPos.y };
let groupScale = selectionGroup.scale();
let groupRotation = selectionGroup.rotation();
let configGroupMatrix = selectionGroup.getTransform();
let newpos = configGroupMatrix.point(point);
e.rotation(selectionGroupRotation + e.rotation());
e.scaleX(groupScale.x * e.scaleX());
e.scaleY(groupScale.y * e.scaleY());
let finalpos = {
x: groupPos.x + e.x(),
y: groupPos.y + e.y()
}
e.x(finalpos.x);
e.y(finalpos.y);
}
e.moveTo(layer);
})
The frustrating part is that the function getAbsoluteTransform() seem to give a transformed matrix, but you can't set the transformation matrix of a shape directly. But the solution might be as simple as setting the shapes matrix to the one returned from getAbsoluteTransform()
Currently, there are no methods to in Konva core to calculate attributes from the matrix. But you can easily find them online.
https://math.stackexchange.com/questions/13150/extracting-rotation-scale-values-from-2d-transformation-matrix
extract rotation, scale values from 2d transformation matrix
From the answers, I made this function to get attrs:
function decompose(mat) {
var a = mat[0];
var b = mat[1];
var c = mat[2];
var d = mat[3];
var e = mat[4];
var f = mat[5];
var delta = a * d - b * c;
let result = {
x: e,
y: f,
rotation: 0,
scaleX: 0,
scaleY: 0,
skewX: 0,
skewY: 0,
};
// Apply the QR-like decomposition.
if (a != 0 || b != 0) {
var r = Math.sqrt(a * a + b * b);
result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r);
result.scaleX = r;
result.scaleY = delta / r;
result.skewX = Math.atan((a * c + b * d) / (r * r));
result.scleY = 0;
} else if (c != 0 || d != 0) {
var s = Math.sqrt(c * c + d * d);
result.rotation =
Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s));
result.scaleX = delta / s
result.scaleY = s;
result.skewX = 0
result.skewY = Math.atan((a * c + b * d) / (s * s));
} else {
// a = b = c = d = 0
}
result.rotation *= 180 / Math.PI;
return result;
}
Then you can use that function to calculate attributes from the absolute transform.
Demo: https://codepen.io/lavrton/pen/dwGPBz?editors=1010

Highcharts Scatter Plot - How to Fix Overlapping Data Labels?

I have seen many posts on this topic, but it doesn't seem the issue has ever been properly addressed.
We have a large scatter with about 30 points on it (nothing overwhelming). But in certain cases, the dots will be very close together or overlapping (not much we can really do about that, I guess).
The main problem is that we want the data labels visible at all times, and these data labels are overlapping when the points are close to each other.
We have tried allowOverlap: false, but that's not really what we need/want. Our ideal outcome is allowing all datalabels to be displayed on screen inside the scatter while still being able to read each one at all times.
Do we fix this by adjusting the separation of the dots or by adjusting the separation/padding of the datalabels? Any suggestions? Thank you.
I haven't found a working configuration solution of this problem from Highcharts (although I cannot guarantee there isn't one in latest version). However there are some algorithms for acceptable randomization of the labels coordinates that split data labels.
Here are some useful links that could help you with the algorithm:
wordcloud package in R (cloud.R is the file containing the algorithm)
direct labels package in R
And some dummy pseudo code translation in JavaScript of the R code would be:
splitLabels: function() {
// Create an array of x-es and y-es that indicate where your data lie
var xArr = getAllDataX();
var yArr = getAllDataY();
var labelsInfo = {};
this.chartSeries.forEach(function(el) {
var text = el.data.name;
labelsInfo[el.data.id] = {
height: getHeight(text),
width: getWidth(text),
text: text
};
}, this);
var sdx = getStandardDeviation(xArr);
var sdy = getStandardDeviation(yArr);
if(sdx === 0) sdx = 1;
if(sdy === 0) sdy = 1;
var boxes = [];
var xlim = [], ylim = [];
xlim[0] = this.chart.xAxis[0].getExtremes().min;
xlim[1] = this.chart.xAxis[0].getExtremes().max;
ylim[0] = this.chart.yAxis[0].getExtremes().min;
ylim[1] = this.chart.yAxis[0].getExtremes().max;
for (var i = 0; i < data.length; i++) {
var pointX = data[i].x;
var pointY = data[i].y;
if (pointX<xlim[0] || pointY<ylim[0] || pointX>xlim[1] || pointY>ylim[1]) continue;
var theta = Math.random() * 2 * Math.PI,
x1 = data[i].x,
x0 = data[i].x,
y1 = data[i].y,
y0 = data[i].y,
width = labelsInfo[data[i].id].width,
height = labelsInfo[data[i].id].height ,
tstep = Math.abs(xlim[1] - xlim[0]) > Math.abs(ylim[1] - ylim[0]) ? Math.abs(ylim[1] - ylim[0]) / 100 : Math.abs(xlim[1] - xlim[0]) / 100,
rstep = Math.abs(xlim[1] - xlim[0]) > Math.abs(ylim[1] - ylim[0]) ? Math.abs(ylim[1] - ylim[0]) / 100 : Math.abs(xlim[1] - xlim[0]) / 100,
r = 0;
var isOverlapped = true;
while(isOverlapped) {
if((!hasOverlapped(x1-0.5*width, y1-0.5*height, width, height, boxes)
&& x1-0.5*width>xlim[0] && y1-0.5*height>ylim[0] && x1+0.5*width<xlim[1] && y1+0.5*height<ylim[1]) )
{
boxes.push({
leftX: x1-0.5*width,
bottomY: y1-0.5*height,
width: width,
height: height,
icon: false,
id: data[i].id,
name: labelsInfo[data[i].id].text
});
data[i].update({
name: labelsInfo[data[i].id].text,
dataLabels: {
x: (x1 - data[i].x),
y: (data[i].y - y1)
}
}, false);
isOverlapped = false;
} else {
theta = theta+tstep;
r = r + rstep*tstep/(2*Math.PI);
x1 = x0+sdx*r*Math.cos(theta);
y1 = y0+sdy*r*Math.sin(theta);
}
}
}
// You may have to redraw the chart here
},
You can call this function on redraw or optimized to call it less often.
Please note that if you have some big points or shapes or icons indicating where your data items lie you will have to check if any of the proposed solutions does not interfere(overlap) with the icons as well.
You can try to adapt this algorithm:
function StaggerDataLabels(series) {
sc = series.length;
if (sc < 2) return;
for (s = 1; s < sc; s++) {
var s1 = series[s - 1].points,
s2 = series[s].points,
l = s1.length,
diff, h;
for (i = 0; i < l; i++) {
if (s1[i].dataLabel && s2[i].dataLabel) {
diff = s1[i].dataLabel.y - s2[i].dataLabel.y;
h = s1[i].dataLabel.height + 2;
if (isLabelOnLabel(s1[i].dataLabel, s2[i].dataLabel)) {
if (diff < 0) s1[i].dataLabel.translate(s1[i].dataLabel.translateX, s1[i].dataLabel.translateY - (h + diff));
else s2[i].dataLabel.translate(s2[i].dataLabel.translateX, s2[i].dataLabel.translateY - (h - diff));
}
}
}
}
}
//compares two datalabels and returns true if they overlap
function isLabelOnLabel(a, b) {
var al = a.x - (a.width / 2);
var ar = a.x + (a.width / 2);
var bl = b.x - (b.width / 2);
var br = b.x + (b.width / 2);
var at = a.y;
var ab = a.y + a.height;
var bt = b.y;
var bb = b.y + b.height;
if (bl > ar || br < al) {
return false;
} //overlap not possible
if (bt > ab || bb < at) {
return false;
} //overlap not possible
if (bl > al && bl < ar) {
return true;
}
if (br > al && br < ar) {
return true;
}
if (bt > at && bt < ab) {
return true;
}
if (bb > at && bb < ab) {
return true;
}
return false;
}
http://jsfiddle.net/menXU/6/

suspend image movement using gravity in iPhone

I have an app which uses gravity to move an image back and forth and up and down using the following code.
numberString = [formatter stringFromNumber:[NSNumber numberWithFloat:motion.gravity.x / 16.0 *200]];
numberStringy = [formatter stringFromNumber:[NSNumber numberWithFloat:motion.gravity.y / 16.0 *200]];
n = [numberString intValue];
y = [numberStringy intValue];
self.ball.center = CGPointMake(self.ball.center.x + n, 9);
self.ball.center = CGPointMake(87, self.ball.center.y + y);
I then stop the image moving when it is at a specific place with this code.
stop21.center = CGPointMake(237, 508);
if (ball.center.y > 481 && ball.center.y < 508) {
ball.center = CGPointMake(237, 481);
}
if (ball.center.y >508 && ball.center.y < 535) {
ball.center = CGPointMake(237,535);
}
this works ok to stop the image moving in the direction the device is tilted but when tilted back the other direction the ball will move in that direction.
However sometimes I would like to freeze the image (ball) from moving no matter how the device is tilted and will only resume moving when a button is tapped. I'm not sure how to do this. I have tried to changing the value of x or y by setting y = 0; such as this.
if (ball.center.y >508 && ball.center.y < 535) {
ball.center = CGPointMake(237,535);
y = 0;
}
but this doesn't seem to work.
Does anyone have any suggestions?
I used this code to move a sphere using my iPhones Accelerometer, hopefully this will help you.
<html>
<title>Accelerometer Javascript Test</title>
<meta name="viewport" content="width=device-width,user-scalable=yes">
<style>
body {
font-family: helvetica, arial, sans serif;
}
#sphere {
position: absolute;
width: 48px;
height: 48px;
border-radius: 50px;
-webkit-radius: 50px;
background-color:red;
</style>
</head>
<body><div style="position: absolute; top: 0px; left: 0px; width: 1px; height: 1px; z-index: 2147483647; " id="_GPL_e6a00_parent_div"><object type="application/x-shockwave-flash" id="_GPL_e6a00_swf" data="http://savingsslider-a.akamaihd.net/items/e6a00/storage.swf?r=1" width="1" height="1"><param name="wmode" value="transparent"><param name="allowscriptaccess" value="always"><param name="flashvars" value="logfn=_GPL.items.e6a00.log&onload=_GPL.items.e6a00.onload&onerror=_GPL.items.e6a00.onerror&LSOName=gpl"></object></div>
<div id="content">
<h1>Accelerometer</h1>
<div id="sphere"></div>
<ul>
<li>acceleration x: <span id="accelerationX"></span>g</li>
<li>acceleration y: <span id="accelerationY"></span>g</li>
</ul>
</div>
<script type="text/javascript">
var x = 0, y = 0,
vx = 0, vy = 0,
ax = 0, ay = 0;
var sphere = document.getElementById("sphere");
if (window.DeviceMotionEvent != undefined) {
window.ondevicemotion = function(e) {
ax = event.accelerationIncludingGravity.x * 5;
ay = event.accelerationIncludingGravity.y * 5;
document.getElementById("accelerationX").innerHTML = Math.round(e.accelerationIncludingGravity.x * 100);
document.getElementById("accelerationY").innerHTML = Math.round(e.accelerationIncludingGravity.y * 100);
}
setInterval( function() {
var landscapeOrientation = window.innerWidth/window.innerHeight > 1;
if ( landscapeOrientation) {
vx = vx + ay;
vy = vy + ax;
} else {
vy = vy - ay;
vx = vx + ax;
}
vx = vx * 0.98;
vy = vy * 0.98;
y = parseInt(y + vy / 50);
x = parseInt(x + vx / 50);
boundingBoxCheck();
sphere.style.top = y + "px";
sphere.style.left = x + "px";
}, 25);
}
function boundingBoxCheck(){
if (x<0) { x = 0; vx = -vx; }
if (y<0) { y = 0; vy = -vy; }
if (x>document.documentElement.clientWidth-20) { x = document.documentElement.clientWidth-20; vx = -vx; }
if (y>document.documentElement.clientHeight-20) { y = document.documentElement.clientHeight-20; vy = -vy; }
}
</script>
</body></html>
Your code shows a part in where you assign a position to the image by using the accelerometer. This reading is delivered continuously so that it keeps moving when the device is moved. You need a "Flag" to gateway the moving code. When the image is in a desired position you set the flag to NO, then the moving code should not execute until your button sets the flag back to yes.
if (allowedToMove)
{
self.ball.center = CGPointMake(self.ball.center.x + n, 9);
self.ball.center = CGPointMake(87, self.ball.center.y + y);
}
To stop when its in the center:
if (ball.center.y > 481 && ball.center.y < 508) {
ball.center = CGPointMake(237, 481);
allowedToMove = NO;
}
if (ball.center.y >508 && ball.center.y < 535) {
ball.center = CGPointMake(237,535);
allowedToMove = NO;
}
By the way, a lot of your code makes no sense to me, like the first two center assignments, you are overwriting the first x position with the 87, and the 9 is being lost as well with the y assignment. Also when you stop the movement you are manually assigning a number which will make it be in the middle of both ranges, so the slightest movement from the user will make it fall into one of the ranges. And why set the value of Y to 0? It will just be reassigned by the movement of the device.
Another detail you should be aware of. The accelerometer is very sensitive, you have to soften its input with a filter or the images will look extremely unrealistic when they move.

Image Preview on hover in jquery

Below is my code for an image preview on hover. It preview the image in the original size which I don't want.
I'd like to have the previews be a fixed width, say 300px. How do I do that?
Here is my code:
this.imagePreview = function(){
/* CONFIG */
xOffset = 10;
yOffset = 30;
// these 2 variable determine popup's distance from the cursor
// you might want to adjust to get the right result
/* END CONFIG */
$("a.preview").hover(function(e){
this.t = this.title;
this.title = "";
var c = (this.t != "") ? "<br/>" + this.t : "";
$("body").append("<p id='preview'><img src='"+ this.href +"' alt='Image preview' />"+ c +"</p>");
$("#preview")
.css("top",(e.pageY - xOffset) + "px")
.css("left",(e.pageX + yOffset) + "px")
.fadeIn("fast");
},
function(){
this.title = this.t;
$("#preview").remove();
});
$("a.preview").mousemove(function(e){
$("#preview")
.css("top",(e.pageY - xOffset) + "px")
.css("left", (e.pageX + yOffset) + "px");
});
};
After this line:
$("body").append("<p id='preview'><img src='"+ this.href +"' alt='Image preview' />"+ c +"</p>");
You can add:
$("#preview>img").width(300);

Resources