Related
I'm trying to add a space between the actual Chart and the Legend/labels.
Legend has a position rigtht and I don't know how to add a padding/margin between Chart and labels.
Found some discussions but not relevant to react hooks.
From what I understood, I need to make use of beforeinit built in function.
Here is the code snippet and sandbox link.
import React from "react";
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
import { Doughnut } from "react-chartjs-2";
ChartJS.register(ArcElement, Tooltip, Legend);
export const data = {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [
{
label: "# of Votes",
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
"rgba(255, 99, 132, 0.2)",
"rgba(54, 162, 235, 0.2)",
"rgba(255, 206, 86, 0.2)",
"rgba(75, 192, 192, 0.2)",
"rgba(153, 102, 255, 0.2)",
"rgba(255, 159, 64, 0.2)"
],
borderColor: [
"rgba(255, 99, 132, 1)",
"rgba(54, 162, 235, 1)",
"rgba(255, 206, 86, 1)",
"rgba(75, 192, 192, 1)",
"rgba(153, 102, 255, 1)",
"rgba(255, 159, 64, 1)"
],
borderWidth: 1
}
]
};
export function App() {
return (
<div style={{ width: "300px", height: "300px" }}>
<Doughnut
options={{
maintainAspectRatio: true,
plugins: {
legend: {
position: "right",
rtl: true,
labels: {
usePointStyle: true,
pointStyle: "circle",
padding: 20
}
}
}
}}
data={data}
/>
</div>
);
}
Any help will be appreciated
You can't add space but increase the width of the legend using the beforeInit plugin (codesandbox). Increasing the width adds some space but it decreases the overall width available to the chart, so you might have to tweak that a little -
const plugin = {
beforeInit(chart) {
console.log("be");
// reference of original fit function
const originalFit = chart.legend.fit;
// override the fit function
chart.legend.fit = function fit() {
// call original function and bind scope in order to use `this` correctly inside it
originalFit.bind(chart.legend)();
// increase the width to add more space
this.width += 20;
};
}
};
<Doughnut
plugins={[plugin]}
...
Is there any way to add an image into chart area [I'm using chart JS bubble chart].
Presently I added image to canvas through css.
Best approach, drawing it on the canvas
The best way to achieve this is by drawing it directly on the canvas since you have direct access and control over the pixels so you are sure it is aligned pixel perfect.
Extending on uminders answer, but making it so it only draws within the chart area:
const myChart = new Chart('myChart', {
type: 'bubble',
plugins: [{
beforeDraw: chart => {
var ctx = chart.ctx;
ctx.save();
const image = new Image();
image.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Stack_Overflow_logo.svg/2560px-Stack_Overflow_logo.svg.png';
ctx.drawImage(image, chart.chartArea.left, chart.chartArea.top, chart.chartArea.width, chart.chartArea.height);
ctx.restore();
}
}],
data: {
datasets: [{
label: 'My Dataset',
data: [{
x: 0,
y: 12,
r: 10
},
{
x: 1,
y: 19,
r: 12
},
{
x: 2,
y: 3,
r: 8
},
{
x: 3,
y: 5,
r: 7
},
{
x: 4,
y: 2,
r: 4
},
{
x: 5,
y: 3,
r: 8
}
],
backgroundColor: [
'rgba(255, 99, 132, 0.4)',
'rgba(54, 162, 235, 0.4)',
'rgba(255, 206, 86, 0.4)',
'rgba(75, 192, 192, 0.4)',
'rgba(153, 102, 255, 0.4)',
'rgba(255, 159, 64, 0.4)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
]
}]
},
options: {
responsive: true,
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.js"></script>
<canvas id="myChart" height="80"></canvas>
Alternative approach without drawing on the canvas
If you really don't want to draw it on the canvas but use a normal img element, you can use an absolute position and use a custom plugin to position it correctly, downside is that it seems that canvas pixels are different from CSS so they cant be used 1:1 and have to be approximated which may lead to slight alignment issues:
const myChart = new Chart('myChart', {
type: 'bubble',
plugins: [{
beforeDraw: chart => {
const image = document.getElementById('img')
image.width = chart.chartArea.width;
image.height = chart.chartArea.height;
image.style.left = `${chart.chartArea.left*1.3}px`;
image.style.top = `${chart.chartArea.top*1.3}px`;
}
}],
data: {
datasets: [{
label: 'My Dataset',
data: [{
x: 0,
y: 12,
r: 10
},
{
x: 1,
y: 19,
r: 12
},
{
x: 2,
y: 3,
r: 8
},
{
x: 3,
y: 5,
r: 7
},
{
x: 4,
y: 2,
r: 4
},
{
x: 5,
y: 3,
r: 8
}
],
backgroundColor: [
'rgba(255, 99, 132, 0.4)',
'rgba(54, 162, 235, 0.4)',
'rgba(255, 206, 86, 0.4)',
'rgba(75, 192, 192, 0.4)',
'rgba(153, 102, 255, 0.4)',
'rgba(255, 159, 64, 0.4)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
]
}]
},
options: {
responsive: true,
}
});
#img {
position: absolute;
z-index: -1/* Draw image behind the canvas */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.js"></script>
<img id="img" src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Stack_Overflow_logo.svg/2560px-Stack_Overflow_logo.svg.png" />
<canvas id="myChart" height="80"></canvas>
The Plugin Core API offers a range of hooks that can be used for performing custom code. You can use the beforeDraw for example to draw the images through CanvasRenderingContext2D.drawImage(). But this effectively draws the image directly on the canvas.
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
ctx.save();
var image = new Image();
image.src = 'https://i.stack.imgur.com/S7tJH.png';
imageSize = 250;
ctx.drawImage(image, chart.chart.width / 2 - imageSize / 2, chart.chart.height / 2 - imageSize / 2, imageSize, imageSize);
ctx.restore();
}
}],
Please have a look at the runnable code snippet below.
var myChart = new Chart('myChart', {
type: 'bubble',
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
ctx.save();
var image = new Image();
image.src = 'https://i.stack.imgur.com/S7tJH.png';
imageSize = 250;
ctx.drawImage(image, chart.chart.width / 2 - imageSize / 2, chart.chart.height / 2 - imageSize / 2, imageSize, imageSize);
ctx.restore();
}
}],
data: {
datasets: [{
label: 'My Dataset',
data: [
{ x: "05:22", y: 12, r: 10 },
{ x: "12:13", y: 19, r: 12 },
{ x: "13:45", y: 3, r: 8 },
{ x: "18:31", y: 5, r: 7 },
{ x: "19:05", y: 2, r: 4 },
{ x: "22:55", y: 3, r: 8 }
],
backgroundColor: [
'rgba(255, 99, 132, 0.4)',
'rgba(54, 162, 235, 0.4)',
'rgba(255, 206, 86, 0.4)',
'rgba(75, 192, 192, 0.4)',
'rgba(153, 102, 255, 0.4)',
'rgba(255, 159, 64, 0.4)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
]
}]
},
options: {
responsive: true,
legend: {
display: false
},
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'HH:mm',
unit: 'hour',
stepSize: 1,
displayFormats: {
hour: 'HH:mm'
},
tooltipFormat: 'HH:mm'
},
ticks: {
min: '00:00',
max: '24:00',
callback: (value, index) => index == 24 ? '24:00' : value
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 5
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="myChart" height="80"></canvas>
Here is my current project code:
size(500,500);
background(255, 255, 255);
fill(250,0,0);
ellipse(150, 230, 100, 200);
fill(10,0,0);
ellipse(180, 233, 30, 30);
fill(10,0,0);
ellipse(120, 233, 30, 30);
fill(250,250,250);
ellipse(120,233,10,20);
fill(250,250,250);
ellipse(180,233,10,20);
arc(150, 280, 60, 90, 0, PI/1);
fill(250,0,0);
rect(100,330,100,100);
fill(10,10,10);
rect(50,330,50,50);
fill(10,10,10);
rect(200,330,50,50);
fill(250,0,0);
rect(90,430,50,100);
fill(250,0,0);
rect(160,430,50,100);
fill(10,0,0);
triangle(60, 300, 101, 10, 50, 450);
Could someone please provide code on how to draw a basic 5 pointed star beside the deadpool character? (within the sized 500,500 dimensions)
See the processing documentation of PShapes where there is a very simple implementation of a star shape in the Custom PShapes section.
See the p5.js example which is very similar.
The code can be used in processing.js, too. You have to change createCanvas(500,500) to size(500,500) and push() respectively pop() to pushMatrix() respectively popMatrix():
function setup() {
createCanvas(500,500);
}
function draw() {
background(255, 255, 255);
// star
push();
translate(280, 290); // center of the star
fill(102);
beginShape();
vertex(0, -50);
vertex(14, -20);
vertex(47, -15);
vertex(23, 7);
vertex(29, 40);
vertex(0, 25);
vertex(-29, 40);
vertex(-23, 7);
vertex(-47, -15);
vertex(-14, -20);
endShape(CLOSE);
translate(100, 100);
pop();
// character
fill(250,0,0);
ellipse(150, 230, 100, 200);
fill(10,0,0);
ellipse(180, 233, 30, 30);
fill(10,0,0);
ellipse(120, 233, 30, 30);
fill(250,250,250);
ellipse(120,233,10,20);
fill(250,250,250);
ellipse(180,233,10,20);
arc(150, 280, 60, 90, 0, PI/1);
fill(250,0,0);
rect(100,330,100,100);
fill(10,10,10);
rect(50,330,50,50);
fill(10,10,10);
rect(200,330,50,50);
fill(250,0,0);
rect(90,430,50,100);
fill(250,0,0);
rect(160,430,50,100);
fill(10,0,0);
triangle(60, 300, 101, 10, 50, 450);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"></script>
https://github.com/evrencoskun/TableView
It's primarily the first row and the first column fixed,That's what I want
Try PaginatedDataTable. This example is extracted from Flutter Gallery example.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(new MaterialApp(debugShowCheckedModeBanner: false, home: new DataTableDemo(),));
class Dessert {
Dessert(this.name, this.calories, this.fat, this.carbs, this.protein, this.sodium, this.calcium, this.iron);
final String name;
final int calories;
final double fat;
final int carbs;
final double protein;
final int sodium;
final int calcium;
final int iron;
bool selected = false;
}
class DessertDataSource extends DataTableSource {
final List<Dessert> _desserts = <Dessert>[
new Dessert('Frozen yogurt', 159, 6.0, 24, 4.0, 87, 14, 1),
new Dessert('Ice cream sandwich', 237, 9.0, 37, 4.3, 129, 8, 1),
new Dessert('Eclair', 262, 16.0, 24, 6.0, 337, 6, 7),
new Dessert('Cupcake', 305, 3.7, 67, 4.3, 413, 3, 8),
new Dessert('Gingerbread', 356, 16.0, 49, 3.9, 327, 7, 16),
new Dessert('Jelly bean', 375, 0.0, 94, 0.0, 50, 0, 0),
new Dessert('Lollipop', 392, 0.2, 98, 0.0, 38, 0, 2),
new Dessert('Honeycomb', 408, 3.2, 87, 6.5, 562, 0, 45),
new Dessert('Donut', 452, 25.0, 51, 4.9, 326, 2, 22),
new Dessert('KitKat', 518, 26.0, 65, 7.0, 54, 12, 6),
new Dessert('Frozen yogurt with sugar', 168, 6.0, 26, 4.0, 87, 14, 1),
new Dessert('Ice cream sandwich with sugar', 246, 9.0, 39, 4.3, 129, 8, 1),
new Dessert('Eclair with sugar', 271, 16.0, 26, 6.0, 337, 6, 7),
new Dessert('Cupcake with sugar', 314, 3.7, 69, 4.3, 413, 3, 8),
new Dessert('Gingerbread with sugar', 345, 16.0, 51, 3.9, 327, 7, 16),
new Dessert('Jelly bean with sugar', 364, 0.0, 96, 0.0, 50, 0, 0),
new Dessert('Lollipop with sugar', 401, 0.2, 100, 0.0, 38, 0, 2),
new Dessert('Honeycomb with sugar', 417, 3.2, 89, 6.5, 562, 0, 45),
new Dessert('Donut with sugar', 461, 25.0, 53, 4.9, 326, 2, 22),
new Dessert('KitKat with sugar', 527, 26.0, 67, 7.0, 54, 12, 6),
new Dessert('Frozen yogurt with honey', 223, 6.0, 36, 4.0, 87, 14, 1),
new Dessert('Ice cream sandwich with honey', 301, 9.0, 49, 4.3, 129, 8, 1),
new Dessert('Eclair with honey', 326, 16.0, 36, 6.0, 337, 6, 7),
new Dessert('Cupcake with honey', 369, 3.7, 79, 4.3, 413, 3, 8),
new Dessert('Gingerbread with honey', 420, 16.0, 61, 3.9, 327, 7, 16),
new Dessert('Jelly bean with honey', 439, 0.0, 106, 0.0, 50, 0, 0),
new Dessert('Lollipop with honey', 456, 0.2, 110, 0.0, 38, 0, 2),
new Dessert('Honeycomb with honey', 472, 3.2, 99, 6.5, 562, 0, 45),
new Dessert('Donut with honey', 516, 25.0, 63, 4.9, 326, 2, 22),
new Dessert('KitKat with honey', 582, 26.0, 77, 7.0, 54, 12, 6),
new Dessert('Frozen yogurt with milk', 262, 8.4, 36, 12.0, 194, 44, 1),
new Dessert('Ice cream sandwich with milk', 339, 11.4, 49, 12.3, 236, 38, 1),
new Dessert('Eclair with milk', 365, 18.4, 36, 14.0, 444, 36, 7),
new Dessert('Cupcake with milk', 408, 6.1, 79, 12.3, 520, 33, 8),
new Dessert('Gingerbread with milk', 459, 18.4, 61, 11.9, 434, 37, 16),
new Dessert('Jelly bean with milk', 478, 2.4, 106, 8.0, 157, 30, 0),
new Dessert('Lollipop with milk', 495, 2.6, 110, 8.0, 145, 30, 2),
new Dessert('Honeycomb with milk', 511, 5.6, 99, 14.5, 669, 30, 45),
new Dessert('Donut with milk', 555, 27.4, 63, 12.9, 433, 32, 22),
new Dessert('KitKat with milk', 621, 28.4, 77, 15.0, 161, 42, 6),
new Dessert('Coconut slice and frozen yogurt', 318, 21.0, 31, 5.5, 96, 14, 7),
new Dessert('Coconut slice and ice cream sandwich', 396, 24.0, 44, 5.8, 138, 8, 7),
new Dessert('Coconut slice and eclair', 421, 31.0, 31, 7.5, 346, 6, 13),
new Dessert('Coconut slice and cupcake', 464, 18.7, 74, 5.8, 422, 3, 14),
new Dessert('Coconut slice and gingerbread', 515, 31.0, 56, 5.4, 316, 7, 22),
new Dessert('Coconut slice and jelly bean', 534, 15.0, 101, 1.5, 59, 0, 6),
new Dessert('Coconut slice and lollipop', 551, 15.2, 105, 1.5, 47, 0, 8),
new Dessert('Coconut slice and honeycomb', 567, 18.2, 94, 8.0, 571, 0, 51),
new Dessert('Coconut slice and donut', 611, 40.0, 58, 6.4, 335, 2, 28),
new Dessert('Coconut slice and KitKat', 677, 41.0, 72, 8.5, 63, 12, 12),
];
void _sort<T>(Comparable<T> getField(Dessert d), bool ascending) {
_desserts.sort((Dessert a, Dessert b) {
if (!ascending) {
final Dessert c = a;
a = b;
b = c;
}
final Comparable<T> aValue = getField(a);
final Comparable<T> bValue = getField(b);
return Comparable.compare(aValue, bValue);
});
notifyListeners();
}
int _selectedCount = 0;
#override
DataRow getRow(int index) {
assert(index >= 0);
if (index >= _desserts.length)
return null;
final Dessert dessert = _desserts[index];
return new DataRow.byIndex(
index: index,
selected: dessert.selected,
onSelectChanged: (bool value) {
if (dessert.selected != value) {
_selectedCount += value ? 1 : -1;
assert(_selectedCount >= 0);
dessert.selected = value;
notifyListeners();
}
},
cells: <DataCell>[
new DataCell(new Text('${dessert.name}')),
new DataCell(new Text('${dessert.calories}')),
new DataCell(new Text('${dessert.fat.toStringAsFixed(1)}')),
new DataCell(new Text('${dessert.carbs}')),
new DataCell(new Text('${dessert.protein.toStringAsFixed(1)}')),
new DataCell(new Text('${dessert.sodium}')),
new DataCell(new Text('${dessert.calcium}%')),
new DataCell(new Text('${dessert.iron}%')),
]
);
}
#override
int get rowCount => _desserts.length;
#override
bool get isRowCountApproximate => false;
#override
int get selectedRowCount => _selectedCount;
void _selectAll(bool checked) {
for (Dessert dessert in _desserts)
dessert.selected = checked;
_selectedCount = checked ? _desserts.length : 0;
notifyListeners();
}
}
class DataTableDemo extends StatefulWidget {
static const String routeName = '/material/data-table';
#override
_DataTableDemoState createState() => new _DataTableDemoState();
}
class _DataTableDemoState extends State<DataTableDemo> {
int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage;
int _sortColumnIndex;
bool _sortAscending = true;
final DessertDataSource _dessertsDataSource = new DessertDataSource();
void _sort<T>(Comparable<T> getField(Dessert d), int columnIndex, bool ascending) {
_dessertsDataSource._sort<T>(getField, ascending);
setState(() {
_sortColumnIndex = columnIndex;
_sortAscending = ascending;
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: const Text('Data tables')),
body: new ListView(
padding: const EdgeInsets.all(20.0),
children: <Widget>[
new PaginatedDataTable(
header: const Text('Nutrition'),
rowsPerPage: _rowsPerPage,
onRowsPerPageChanged: (int value) { setState(() { _rowsPerPage = value; }); },
sortColumnIndex: _sortColumnIndex,
sortAscending: _sortAscending,
onSelectAll: _dessertsDataSource._selectAll,
columns: <DataColumn>[
new DataColumn(
label: const Text('Dessert (100g serving)'),
onSort: (int columnIndex, bool ascending) => _sort<String>((Dessert d) => d.name, columnIndex, ascending)
),
new DataColumn(
label: const Text('Calories'),
tooltip: 'The total amount of food energy in the given serving size.',
numeric: true,
onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.calories, columnIndex, ascending)
),
new DataColumn(
label: const Text('Fat (g)'),
numeric: true,
onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.fat, columnIndex, ascending)
),
new DataColumn(
label: const Text('Carbs (g)'),
numeric: true,
onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.carbs, columnIndex, ascending)
),
new DataColumn(
label: const Text('Protein (g)'),
numeric: true,
onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.protein, columnIndex, ascending)
),
new DataColumn(
label: const Text('Sodium (mg)'),
numeric: true,
onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.sodium, columnIndex, ascending)
),
new DataColumn(
label: const Text('Calcium (%)'),
tooltip: 'The amount of calcium as a percentage of the recommended daily amount.',
numeric: true,
onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.calcium, columnIndex, ascending)
),
new DataColumn(
label: const Text('Iron (%)'),
numeric: true,
onSort: (int columnIndex, bool ascending) => _sort<num>((Dessert d) => d.iron, columnIndex, ascending)
),
],
source: _dessertsDataSource
)
]
)
);
}
}
DessertDataSource class contains the input fields displayed in the data table. Change them and update getRow method based on your needs.
I am wondering if someone can show me how to write this code so it resizes automatically for different screen sizes. I have 4 storyboards with different screen sizes and just want a way to show the code, if this storyboard then (numbers change) follow this code, else (numbers chafe according to storyboard size) this code.
I already tried resizing by adding to each axis number for example / 568 * size.frame.height after each y and height axis and same for x and width of course, but the code becomes too long and complex to read.
Ideally I'd like an if statement saying if this screen size then it's storyboard 'this' then go to this code..
pianoButtonsWaterDropFrames = [
cNote: (CGRect(x: 33 , y: 40 , width: 20, height: 35), CGRect(x: 33, y: 360, width: 20, height: 35)),
dNote: (CGRect(x: 66 , y: 42 , width: 20, height: 35), CGRect(x: 66, y: 360, width: 20, height: 35)),
eNote: (CGRect(x: 99 , y: 41 , width: 20, height: 35), CGRect(x: 99 , y: 360, width: 20, height: 35)),
fNote: (CGRect(x: 132, y: 48, width: 20, height: 35), CGRect(x: 132, y: 360, width: 20, height: 35)),
gNote: (CGRect(x: 165, y: 39, width: 20, height: 35), CGRect(x: 165, y: 360, width: 20, height: 35)),
aNote: (CGRect(x: 198, y: 57, width: 20, height: 35), CGRect(x: 198, y: 360, width: 20, height: 35)),
bNote: (CGRect(x: 231, y: 60, width: 20, height: 35), CGRect(x: 231, y: 360, width: 20, height: 35)),
cFourNote: (CGRect(x: 263, y: 54, width: 20, height: 35), CGRect(x: 263, y: 360, width: 20, height: 35))
]
Any help would be appreciated !
You can use HAS answer in this question to check, which iPhone your app is running on. Then you can use a switch statement and call different methods:
let modelName = UIDevice.currentDevice().modelName
switch modelName{
case "iPhone 3G", "iPhone 3GS":
method1()
case "iPhone 4", "iPhone 4S":
method2()
default:
println("no size found")
}