Text overlapping the another enter image description heretext in Layout Customized Chart.js
enter image description here
Please , somebody can helpe me?
const { x, y } = datapoint.tooltipPosition();
const halfWidth = width / 2;
const halfHeight = width / 2;
const xLine = x >= halfWidth ? x + 100 : x - 25;
const yLine = y >= halfHeight ? y + 100 : y - 25;
const extraLine = x >= halfWidth ? 40 : -40;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(xLine, yLine);
ctx.lineTo(xLine + extraLine, yLine);
ctx.strokeStyle = dataset.backgroundColor[index];
ctx.stroke();
ctx.font = 'bold 12px Arial';
const textXPosition = x >= halfWidth ? 'left' : 'right';
const plusFivePx = x >= halfWidth ? 5 : -5;
ctx.textAlign = textXPosition;
ctx.fillStyle = 'black';
ctx.fillText(
chart.data.labels[index],
xLine + extraLine + plusFivePx,
yLine
);
Related
When some values are small in QML pie chart, slice labels are messed up:
How can I arrange slice labels like this?
Note that this is available in telerik and /or dev components for c#.
I used of #luffy 's comment and with some modification, I reached to following code and result:
import QtQuick 2.4
Rectangle {
id: root
// public
property string fontFamily: "sans-serif"
property int fontPointSize: 9
property double donutHoleSize: 0.4 //0~1
property string title: 'title'
property variant points: []//[['Zero', 60, 'red'], ['One', 40, 'blue']] // y values don't need to add to 100
width: 500
height: 700
// private
onPointsChanged: myCanvas.requestPaint()
Canvas {
id: myCanvas
anchors.fill: parent
property double factor: Math.min(width, height)
Text { // title
text: title
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 0.03 * myCanvas.factor
}
onPaint: {
var context = getContext("2d")
var total = 0 // automatically calculated from points.y
var start = -Math.PI / 2 // Start from vertical. 0 is 3 o'clock and positive is clockwise
var radius = 0.25 * myCanvas.factor
var pixelSize = 0.03 * myCanvas.factor // text
context.font = root.fontPointSize + 'pt ' + root.fontFamily
var i = 0;
for(i = 0; i < points.length; i++) total += points[i][1] // total
context.clearRect(0, 0, width, height) // new points data
//--------------------------------------------------------
var end = 0;
var center = 0;
var angle = 0;
var midSlice = 0;
var point = 0;
var topRightCnt = 0
var bottomRightCnt = 0
var topLeftCnt = 0
var bottomLeftCnt = 0
var itemsPos = []
center = Qt.vector2d(width / 2, height / 2) // center
for(i = 0; i < points.length; i++) {
end = start + 2 * Math.PI * points[i][1] / total // radians
angle = (start + end) / 2 // of line
midSlice = Qt.vector2d(Math.cos((end + start) / 2), Math.sin((end + start) / 2)).times(radius) // point on edge/middle of slice
point = midSlice.times(1 + 1.4 * (1 - Math.abs(Math.cos(angle)))).plus(center) // elbow of line
if(point.x<center.x && point.y<=center.y) {
topLeftCnt++;
itemsPos[i] = "tl"
}
else if(point.x<center.x && point.y>center.y) {
bottomLeftCnt++;
itemsPos[i] = "bl"
}
else if(point.x>=center.x && point.y<=center.y) {
topRightCnt++;
itemsPos[i] = "tr"
}
else {
bottomRightCnt++;
itemsPos[i] = "br"
}
start = end // radians
}
//--------------------------------------------------------
end = 0;
angle = 0;
midSlice = 0;
point = 0;
var itemPosCounterTR = 0;
var itemPosCounterTL = 0;
var itemPosCounterBR = 0;
var itemPosCounterBL = 0;
for(i = 0; i < points.length; i++) {
end = start + 2 * Math.PI * points[i][1] / total // radians
// pie
context.fillStyle = points[i][2]
context.beginPath()
midSlice = Qt.vector2d(Math.cos((end + start) / 2), Math.sin((end + start) / 2)).times(radius) // point on edge/middle of slice
context.arc(center.x, center.y, radius, start, end) // x, y, radius, startingAngle (radians), endingAngle (radians)
context.lineTo(center.x, center.y) // center
context.fill()
// text
context.fillStyle = points[i][2]
angle = (start + end) / 2 // of line
point = midSlice.times(1 + 1.4 * (1 - Math.abs(Math.cos(angle)))).plus(center) // elbow of line
//---------------------------------------------
var textX = 0;
var textY = 0;
var dis = 0;
var percent = points[i][1] / total * 100
var text = points[i][0] + ': ' + (percent < 1? '< 1': Math.round(percent)) + '%' // display '< 1%' if < 1
var textWidth = context.measureText(text).width
var textHeight = 15
var diameter = radius * 2
var topCircle = center.y - radius
var leftCircle = center.x - radius
if(itemsPos[i] === "tr") {
textX = leftCircle + 1.15 * diameter
dis = Math.floor((1.15*radius) / topRightCnt) //Math.floor((height/2) / topRightCnt)
dis = (dis < 20 ? 20 : dis)
textY = topCircle -(0.15*diameter) + (itemPosCounterTR*dis) + (textHeight/2)
itemPosCounterTR++
}
else if(itemsPos[i] === "br") {
textX = leftCircle + 1.15 * diameter
dis = Math.floor((1.15*radius) / bottomRightCnt)
dis = (dis < 20 ? 20 : dis)
textY = topCircle+(1.15*diameter) - ((bottomRightCnt-itemPosCounterBR-1)*dis) - (textHeight/2)
itemPosCounterBR++
}
else if(itemsPos[i] === "tl") {
textX = leftCircle - (0.15 * diameter) - textWidth
dis = Math.floor((1.15*radius) / topLeftCnt)
dis = (dis < 20 ? 20 : dis)
textY = topCircle-(0.15*diameter) + ((topLeftCnt-itemPosCounterTL-1)*dis) + (textHeight/2)
itemPosCounterTL++;
}
else {
textX = leftCircle - (0.15 * diameter) - textWidth //-0.2 * width - textWidth
dis = Math.floor((1.15*radius) / bottomLeftCnt)
dis = (dis < 20 ? 20 : dis)
textY = topCircle+(1.15*diameter) - (itemPosCounterBL*dis) - (textHeight/2)
itemPosCounterBL++
}
//---------------------------------------------
context.fillText(text, textX, textY)
// line
context.lineWidth = 1
context.strokeStyle = points[i][2]
context.beginPath()
context.moveTo(center.x + midSlice.x, center.y + midSlice.y) // center
var endLineX = (point.x < center.x ? (textWidth + 0.5 * pixelSize) : (-0.5 * pixelSize)) + textX;
context.lineTo(endLineX, textY+3)
context.lineTo(endLineX + (point.x < center.x? -1: 1) * ((0.5 * pixelSize)+textWidth), textY+3) // horizontal
context.stroke()
start = end // radians
}
if(root.donutHoleSize > 0) {
root.donutHoleSize = Math.min(0.99, root.donutHoleSize);
var holeRadius = root.donutHoleSize * radius;
context.fillStyle = root.color
context.beginPath()
context.arc(center.x, center.y, holeRadius, 0, 2*Math.PI) // x, y, radius, startingAngle (radians), endingAngle (radians)
//context.lineTo(center.x, center.y) // center
context.fill()
}
}
}
}
And it's result:
Thanks #luffy.
I want to convert camera image from function startImageStream of camera plugin in Flutter to Image to crop that image but I only find the way to convert to FirebaseVisionImage.
Edit For Color Image
if I understand you clear. You are trying to covnert YUV420 format. The following is code snippet from: https://github.com/flutter/flutter/issues/26348
const shift = (0xFF << 24);
Future<Image> convertYUV420toImageColor(CameraImage image) async {
try {
final int width = image.width;
final int height = image.height;
final int uvRowStride = image.planes[1].bytesPerRow;
final int uvPixelStride = image.planes[1].bytesPerPixel;
print("uvRowStride: " + uvRowStride.toString());
print("uvPixelStride: " + uvPixelStride.toString());
// imgLib -> Image package from https://pub.dartlang.org/packages/image
var img = imglib.Image(width, height); // Create Image buffer
// Fill image buffer with plane[0] from YUV420_888
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int uvIndex = uvPixelStride * (x / 2).floor() + uvRowStride * (y / 2).floor();
final int index = y * width + x;
final yp = image.planes[0].bytes[index];
final up = image.planes[1].bytes[uvIndex];
final vp = image.planes[2].bytes[uvIndex];
// Calculate pixel color
int r = (yp + vp * 1436 / 1024 - 179).round().clamp(0, 255);
int g = (yp - up * 46549 / 131072 + 44 - vp * 93604 / 131072 + 91).round().clamp(0, 255);
int b = (yp + up * 1814 / 1024 - 227).round().clamp(0, 255);
// color: 0x FF FF FF FF
// A B G R
img.data[index] = shift | (b << 16) | (g << 8) | r;
}
}
imglib.PngEncoder pngEncoder = new imglib.PngEncoder(level: 0, filter: 0);
List<int> png = pngEncoder.encodeImage(img);
muteYUVProcessing = false;
return Image.memory(png);
} catch (e) {
print(">>>>>>>>>>>> ERROR:" + e.toString());
}
return null;
}
I found, sometimes planes[0] bytes per row is not same as width. In that case, you should do something like the code below.
static image_lib.Image convertYUV420ToImage(CameraImage cameraImage) {
final width = cameraImage.width;
final height = cameraImage.height;
final yRowStride = cameraImage.planes[0].bytesPerRow;
final uvRowStride = cameraImage.planes[1].bytesPerRow;
final uvPixelStride = cameraImage.planes[1].bytesPerPixel!;
final image = image_lib.Image(width, height);
for (var w = 0; w < width; w++) {
for (var h = 0; h < height; h++) {
final uvIndex =
uvPixelStride * (w / 2).floor() + uvRowStride * (h / 2).floor();
final index = h * width + w;
final yIndex = h * yRowStride + w;
final y = cameraImage.planes[0].bytes[yIndex];
final u = cameraImage.planes[1].bytes[uvIndex];
final v = cameraImage.planes[2].bytes[uvIndex];
image.data[index] = yuv2rgb(y, u, v);
}
}
return image;
}
static int yuv2rgb(int y, int u, int v) {
// Convert yuv pixel to rgb
var r = (y + v * 1436 / 1024 - 179).round();
var g = (y - u * 46549 / 131072 + 44 - v * 93604 / 131072 + 91).round();
var b = (y + u * 1814 / 1024 - 227).round();
// Clipping RGB values to be inside boundaries [ 0 , 255 ]
r = r.clamp(0, 255);
g = g.clamp(0, 255);
b = b.clamp(0, 255);
return 0xff000000 |
((b << 16) & 0xff0000) |
((g << 8) & 0xff00) |
(r & 0xff);
}
I'm trying to introduce alpha blending into the MATLAB panoramic stitching example. The algorithm successfully blends, but the stitched image is translated, when using the example's "tforms" transformation matrices.
The alpha blending code is here:
%% merge images using Alpha blending
% input: imgs - source images
% mask - image mask
% transforms - transformation matrices to transform each images
% into the new coordinate system
% newHeight, newWidth - size of the new coordinate system
% output: newImg - merged image
function [ newImg ] = alphaBlend( imgs, mask, transforms, newHeight, newWidth )
% image information
height = size(imgs, 1);
width = size(imgs, 2);
nChannels = size(imgs, 3);
nImgs = size(imgs, 4);
% alpha mask
mask = imcomplement(mask);
mask(1, :) = 1;
mask(end, :) = 1;
mask(:, 1) = 1;
mask(:, end) = 1;
mask = bwdist(mask, 'euclidean');
mask = mask ./ max(max(mask));
% backward transformation
backTransforms = zeros(size(transforms));
for i = 1 : nImgs
backTransforms(:, :, i) = inv(transforms(:, :, i));
end
% image merging
newImg = zeros([newHeight newWidth nChannels], 'uint8');
for y = 1 : newHeight
for x = 1 : newWidth
% p1 = [y; x; 1];
p1 = [x; y; 1];
pixelSum = zeros(nChannels, 1);
alphaSum = 0;
for k = 1 : nImgs
% p2 = backTransforms(:, :, k) * p1;
p2 = p1' * backTransforms(:,:,k);
p2 = p2 ./ p2(3);
xx = p2(1);
yy = p2(2);
p2 = [yy; xx; 1];
if p2(1) >= 1 && p2(1) < height && p2(2) >= 1 && p2(2) < width
i = floor(p2(2));
a = p2(2) - i;
j = floor(p2(1));
b = p2(1) - j;
pixel = (1 - a) * (1 - b) * imgs(j, i, :, k)...
+ a * (1 - b) * imgs(j, i + 1, :, k)...
+ a * b * imgs(j + 1, i + 1, :, k)...
+ (1 - a) * b * imgs(j + 1, i, :, k);
alpha = (1 - a) * (1 - b) * mask(j, i)...
+ a * (1 - b) * mask(j, i + 1)...
+ a * b * mask(j + 1, i + 1)...
+ (1 - a) * b * mask(j + 1, i);
pixelSum = pixelSum + double(squeeze(pixel)) * double(alpha);
alphaSum = alphaSum + double(alpha);
end
end
newImg(y, x, :) = pixelSum / alphaSum;
end
end
end
After the Panoramic Stitching example tforms matrices have been formed by step 4 , I try translating the image this way:
mask = ones(imageSize(1),imageSize(2));
% Create the panorama.
% Alpha blending
horiz = 200;
verti = 100;
Translate = [1, 0, 0; 0, 1, 0; horiz, verti, 1];
transforms = Translate * tforms(1).T;
for i =1:numel(tforms) transforms(:,:,i) = Translate * tforms(i).T; end
panorama1 = alphaBlend( temp, mask, transforms, height, width );
But, the resulting image overlap is off. How do I translate the tforms matrix, in order to translate the stitched panoramic image?
This is my progress with a mandelbrot fractal generation:
It appears with cases where the edge cases between colors are small, it has a good "blending" effect. However, as the distance between colors become larger, you can see very explicitly and evidently the separation of colors. I was wondering, how would I achieve a blending effect without using something like bicubic interpolation post-processing?
Attached is the code I have to generate the fractal:
public static void drawFractal()
{
Complex Z;
Complex C;
double x;
double y;
// The min and max values should be between -2 and +2
double minX = -2.0; // use -2 for the full-range fractal image
double minY = -2.0; // use -2 for the full-range fractal image
double maxX = 2.0; // use 2 for the full-range fractal image
double maxY = 2.0; // use 2 for the full-range fractal image
double xStepSize = ( maxX - minX ) / width;
double yStepSize = ( maxY - minY ) / height;
int maxIterations = 100;
int maxColors = 0xFF0000;
// for each pixel on the screen
for( x = minX; x < maxX; x = x + xStepSize)
{
for ( y = minY; y < maxY; y = y + yStepSize )
{
C = new Complex( x, y );
Z = new Complex( 0, 0 );
int iter = getIterValue( Z, C, 0, maxIterations );
int myX = (int) ( ( x - minX ) / xStepSize );
int myY = (int) ( ( y - minY ) / yStepSize );
if ( iter < maxIterations )
{
myPixel[ myY * width + myX ] = iter * ( maxColors / maxIterations ) / 50;
}
}
}
}
I have reached up to image shown in the snapshot.
But still its Y is at bottom only and I am not able to set the X properly overlapped.
Images at Y can be up and down but cannot have the same Y as of pervious Image.
Image at X have to be overlapped to previous but can not have distance between any of Image.
I was able to set Y but still It should be in the middle of screen and not at bottom and not able to set X.
This is the code I am using
CGFloat randomX = (arc4random()%100) *1.1;
CGFloat randomY = (arc4random()%100) *.40;
UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
NSLog(#"prevnode : %#",NSStringFromCGPoint(prevNodeCenter));
attributes.size = CGSizeMake(ITEM_SIZE, ITEM_SIZE);
attributes.center = CGPointMake(_center.x + _radius + randomX * cosf(2 * path.item * M_PI / _cellCount) ,
_center.y + _radius + randomY);
NSLog(#"randomX : %f randomY : %f",randomX,randomY);
NSLog(#"attrib center x : %f",attributes.center.x);
/*
if(attributes.center.x <= prevNodeCenter.x )
{
attributes.center = CGPointMake(prevNodeCenter.x+_radius+cosf(2 * path.item * M_PI / _cellCount), attributes.center.y);
}
if(attributes.center.x >= prevNodeCenter.x+_radius)
{
NSLog(#"its far");
}
*/
/*
if(attributes.center.y > self.collectionView.frame.size.height)
{
attributes.center = CGPointMake(attributes.center.x, self.collectionView.frame.size.height/2);
}*/
prevNodeCenter = attributes.center;
return attributes;