sorry for the lousy copy&paste code. as it is the first time i am using stackoverflow. In raphael.js example below. it is strange that before this line
this.cx = this.cx || 300; once you print out this.cx = "undefined". it is the circle and at very beginging this.cx should be equal to 100px. once I console.log (this); before this.cx = this.cx || 300; cx in element object is equal to 100px rather than "undefined". can anyone help to explain it?
paper.rect(0,0,500,500).attr({fill: "#1a1a1a"})
var targets = paper.set();
targets.push(paper.circle(300, 100, 20),
paper.circle(300, 150, 20),
paper.circle(300, 200, 20),
paper.circle(300, 250, 20),
paper.circle(300, 300, 20),
paper.circle(300, 350, 20),
paper.circle(300, 400, 20),
paper.circle(300, 450, 20));
targets.attr({fill: "#000", stroke: "#fff", "stroke-dasharray": "-", opacity: .2});
var labels = paper.set();
labels.push(paper.text(330, 100, "linear (default)"),
paper.text(330, 150, ">"),
paper.text(330, 200, "<"),
paper.text(330, 250, "<>"),
paper.text(330, 300, "bounce"),
paper.text(330, 350, "elastic"),
paper.text(330, 400, "backIn"),
paper.text(330, 450, "backOut"));
labels.attr({font: "12px Fontin-Sans, Arial", fill: "#fff", "text-anchor": "start"});
var movers = paper.set();
movers.push(paper.circle(100, 100, 20),
paper.circle(100, 150, 20),
paper.circle(100, 200, 20),
paper.circle(100, 250, 20),
paper.circle(100, 300, 20),
paper.circle(100, 350, 20),
paper.circle(100, 400, 20),
paper.circle(100, 450, 20));
movers.attr({fill: "#000", stroke: "#fff", "fill-opacity": 0});
movers[0].click(function () {
this.cx = this.cx || 300;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(0, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000);
console.log(movers[0].attr('fill-opacity'));
this.cx = this.cx == 300 ? 100 : 300;
});
movers[1].click(function () {
_this.cx = this.cx || 300_;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(.1, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000, ">");
this.cx = this.cx == 300 ? 100 : 300;
});
movers[2].click(function () {
this.cx = this.cx || 300;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(.2, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000, "<");
this.cx = this.cx == 300 ? 100 : 300;
});
movers[3].click(function () {
this.cx = this.cx || 300;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(.3, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000, "<>");
this.cx = this.cx == 300 ? 100 : 300;
});
movers[4].click(function () {
this.cx = this.cx || 300;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(.4, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000, "bounce");
this.cx = this.cx == 300 ? 100 : 300;
});
movers[5].click(function () {
this.cx = this.cx || 300;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(.5, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000, "elastic");
this.cx = this.cx == 300 ? 100 : 300;
});
movers[6].click(function () {
this.cx = this.cx || 300;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(.6, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000, "backIn");
this.cx = this.cx == 300 ? 100 : 300;
});
movers[7].click(function () {
this.cx = this.cx || 300;
this.animate({cx: this.cx, "stroke-width": this.cx / 100, fill: this.cx - 100 ? "hsb(.7, .75, .75)" : "#000", "fill-opacity": +!!(this.cx - 100)}, 1000, "backOut");
this.cx = this.cx == 300 ? 100 : 300;
});
This probably because 'this' will be a Raphael object, not a simple circle object, so it will have a wrapper around it.
What you probably want, is something more like...
this.attr('cx', this.attr('cx') || 300)
As you want to get and set the attribute, not a direct key on the Raphael object.
Related
I have a vertical bar chart which is displaying exactly as I want it when the number of bars is up to 50 or so. However, I also need to display up to 365 bars, one for each day of the year. It displays the bars with the code I was using but there were artefacts due to using a barPercentage less than 1.0 and a border.
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1.0)',
borderWidth: 2,
categoryPercentage: 1.0,
barPercentage: 0.8
So when the number of bars is over 100, I change these values as follows and do a chart update:
backgroundColor: 'rgba(54, 162, 235, 1.0)', // No transparency in the bar colour
borderColor: 'rgba(54, 162, 235, 1.0)',
borderWidth: 0,
categoryPercentage: 1.0,
barPercentage: 1.0
However, there is still a faint visible vertical line between the bars where I would expect nothing. I'm on Mac OSX with Safari and I also see the problem on iPad and iPhone.
Any idea what I'm doing wrong??
(click on the 'SWITCH' button to swap between 50 and 120 bars)
https://jsfiddle.net/8xdLb9qe/
I've searched and found this comment:
Be sure you don't have the Dataset barThickness value set, or it will
override the barPercentage setting. Philip F
I change the chart settings as follows:
myChart = new Chart(document.getElementById('thisChart'), {
type: 'bar',
data: {
labels: myScales,
datasets: [{
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1.0)',
data: myValues,
barThickness: 16 //
}]
},
options: option
});
Here is the working jsfiddle.
Full code:
var thisChart = null;
var myScales = [];
var myValues = [];
var numBars = 50;
var option = {
responsive: true,
maintainAspectRatio: false,
interaction: {
intersect: false,
mode: 'nearest'
},
scales: {
x: {
display: true,
grid: {
drawOnChartArea: false,
drawTicks: false
}
},
y: {
max: 100,
grace: '5%',
grid: {
drawTicks: false
},
display: true
}
},
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false
},
hover: {
mode: null
}
}
};
myChart = new Chart(document.getElementById('thisChart'), {
type: 'bar',
data: {
labels: myScales,
datasets: [{
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1.0)',
//borderWidth: 2,
data: myValues,
barThickness: 16,
//categoryPercentage: 1.0,
//barPercentage: 0.1
}]
},
options: option
});
for (var i = 1; i != numBars; i++) {
myScales[i] = i;
myValues[i] = Math.floor(Math.random() * (100 - 50 + 1) + 50);
}
displayGraph();
function displayGraph() {
// Remove the old data
myChart.data.labels.pop();
myChart.data.datasets.forEach((dataset) => {
dataset.data.pop();
});
myChart.update();
// Add in the new data
myChart.data.labels = myScales;
myChart.data.datasets.forEach((dataset, i) => {
dataset.data = myValues;
});
if (myValues.length > 100) {
myChart.data.datasets.forEach((dataset, i) => {
dataset.barPercentage = 1.0; // Remove gap between bars
dataset.borderWidth = 0; // Remove bar border
dataset.backgroundColor = 'rgba(54, 162, 235, 1.0)'; // Remove transparency
});
} else {
myChart.data.datasets.forEach((dataset, i) => {
dataset.barPercentage = 0.8; // Default width of gap between bars
dataset.borderWidth = 2; // Default bar border
dataset.backgroundColor = 'rgba(54, 162, 235, 0.6)'; // Default bar background colour
dataset.borderColor = 'rgba(54, 162, 235, 1.0)'; // Default bar border colour
});
}
myChart.update();
}
function switchBars() {
if (numBars == 50) { // Toggle number of bars
numBars = 120;
} else {
numBars = 50;
}
myScales.length = numBars;
myValues.length = numBars;
for (var i = 1; i != numBars; i++) {
myScales[i] = i;
myValues[i] = Math.floor(Math.random() * (100 - 50 + 1) + 50);
}
displayGraph();
}
.chart-container {
width: 100vw;
height: 60vh;
margin-top: 4em;
position: relative;
}
canvas {
display: block;
margin-left: 2em;
margin-right: 2em;
}
.styleSelectorButton {
width: 100vw;
height: 5em;
margin-top: 1em;
display: flex;
justify-content: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.min.js"></script>
<div class="chart-container">
<canvas id="thisChart"></canvas>
</div>
<div id="selectorButton" class="styleSelectorButton">
<input type="button" onclick="switchBars()" class="button" value="SWITCH">
</div>
I am trying to replicate the NSE Stock exchange comparison graph as displayed here.
I am using Chartjs 2.0. I have 2 line graphs in the chart.
On hovering on the data points I want to show the tooltip's ylabel in a div which is outside the canvas, (like the changing values are displayed in the top right corner in the chart above)
I found GRUNT's code helpful
Moving vertical line when hovering over the chart using chart.js
You can use Label Callback
document.getElementById('y-label').textContent = tooltipItem.yLabel;
Chart.defaults.LineWithLine = Chart.defaults.line;
Chart.controllers.LineWithLine = Chart.controllers.line.extend({
draw: function(ease) {
Chart.controllers.line.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
topY = this.chart.scales['y-axis-0'].top,
bottomY = this.chart.scales['y-axis-0'].bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 2;
ctx.strokeStyle = '#07C';
ctx.stroke();
ctx.restore();
}
}
});
var chart = new Chart(ctx, {
type: 'LineWithLine',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
datasets: [{
label: 'Statistics',
data: [3, 1, 2, 5, 4, 7, 6],
backgroundColor: 'rgba(0, 119, 204, 0.8)',
borderColor: 'rgba(0, 119, 204, 0.3)',
fill: false
}]
},
options: {
responsive: false,
tooltips: {
intersect: false,
callbacks: {
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
if (label) {
label += ': ';
}
label += Math.round(tooltipItem.yLabel * 100) / 100;
document.getElementById('y-label').textContent = tooltipItem.yLabel;
return label;
}
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<h4 id="y-label"> </h4>
<canvas id="ctx" height="200"></canvas>
heyhey,
since a few days I attempt to create the "Material-Design-Chip", but only with half success.
The attempt with the most success I had, is to make a subclass from "Button" (Button is a subclass from UIButton created from cosmicmind in his MaterialDesign-Framework for swift).
For the people who doesn't know I mean with "chips": click here
my examples:
The simple / non-deletable chip
import UIKit
import Material
class ChipButton: Button {
override func prepare() {
super.prepare()
cornerRadiusPreset = .cornerRadius5
backgroundColor = UIColor.lightGray
titleColor = Color.darkText.primary
pulseAnimation = .none
contentEdgeInsets = EdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
isUserInteractionEnabled = false
titleLabel?.font = RobotoFont.regular
isOpaque = true
}
}
and to create this button:
let button = ChipButton()
button.title = "default chip"
view.layout(button).height(32).center(offsetY: -150)
The contact-chip / icon-chip
import UIKit
import Material
class ChipIconButton: ChipButton {
/*override func prepare() {
super.prepare()
contentEdgeInsets = EdgeInsets(top: 0, left: 16, bottom: 0, right: 12)
}*/
public convenience init(image: UIImage?, title: String?){
self.init()
prepare(with: image, title: title)
}
private func prepare(with image: UIImage?, title: String?) {
self.image = image
self.title = title
self.imageView?.backgroundColor = UIColor.darkGray // this works
self.imageView?.cornerRadiusPreset = .cornerRadius4 // this works
self.imageView?.tintColor = Color.black // this doesn't work
self.imageEdgeInsets = EdgeInsets(top: 0, left: -8, bottom: 0, right: 12)
self.titleEdgeInsets = EdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.contentEdgeInsets = EdgeInsets(top: 0, left: 8, bottom: 0, right: 12)
}
}
here I want to
resize the UIImageView to the height of the chip (which is 32 points)
I tried with self.imageView?.frame = CGRect(x: 50, y: 50, width: 32, height: 32) but nothing changed
resize the UIImage little bit smaller (to 20 points)
to change the tintColor of the UIImage
I tryed with self.imageView?.tintColor = Color.black but nothing changed
The deletable chip
import UIKit
import Material
class ChipDeleteableButton: ChipButton {
override func prepare() {
super.prepare()
self.image = #imageLiteral(resourceName: "ic_close_white_24px")
self.title = title
//self.frame = CGRect(x: 50, y: 50, width: 32, height: 32)
self.imageView?.backgroundColor = UIColor.darkGray
self.imageView?.cornerRadiusPreset = .cornerRadius4
self.imageView?.tintColor = Color.black
self.imageEdgeInsets = EdgeInsets(top: 0, left: self.frame.size.width, bottom: 0, right: 0)
self.titleEdgeInsets = EdgeInsets(top: 0, left: 0, bottom: 0, right: self.frame.size.width)
self.contentEdgeInsets = EdgeInsets(top: 0, left: 8, bottom: 0, right: 12)
}
}
here I tried to switch the positions of the label and with imageEdgeInsets and titleEdgeInsets, but self.frame.size.width returns a incorrect width (maybe couse of AutoLayout but i'm not sure)
help
hope that somebody can help me!
ps. I'm little newbe at swift/xcode
The simple / non-deletable chip
here nothing changed.
look at the question.
The contact-chip / icon-chip
import UIKit
import Material
class ChipIconButton: ChipButton {
public convenience init(image: UIImage?, title: String?){
self.init()
prepare(with: image, title: title)
}
private func prepare(with image: UIImage?, title: String?) {
//self.imageView?.frame = CGRect(x: 0, y: 0, width: 60, height: 60)
let myThumb = image?.resize(toWidth: 20)?.resize(toHeight: 20)
let shapeView = UIView(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
shapeView.backgroundColor = UIColor.darkGray
shapeView.cornerRadiusPreset = .cornerRadius5
shapeView.zPosition = (self.imageView?.zPosition)! - 1
self.addSubview(shapeView)
self.image = myThumb?.withRenderingMode(.alwaysTemplate)
self.title = title
self.imageView?.tintColor = self.backgroundColor
self.imageEdgeInsets = EdgeInsets(top: 0, left: -28, bottom: 0, right: 0)
self.titleEdgeInsets = EdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.contentEdgeInsets = EdgeInsets(top: 0, left: 20, bottom: 0, right: 12)
}
}
and the creation-snipped:
open func prepareChipIconButton () {
let icon: UIImage? = #imageLiteral(resourceName: "ic_close_white_24px")
let button = ChipIconButton(image: icon, title: "icon chip")
view.layout(button).height(32).center(offsetY: 0)
}
The deletable chip
import UIKit
import Material
class ChipDeleteableButton: ChipButton {
override func prepare() {
super.prepare()
let img = #imageLiteral(resourceName: "ic_close_white_24px").resize(toHeight:18)?.resize(toWidth: 18)
let myThumb = img?.withRenderingMode(.alwaysTemplate)
self.image = myThumb
self.title = title
self.imageView?.tintColor = self.backgroundColor
self.isUserInteractionEnabled = true
self.addTarget(self, action: #selector(clickAction), for: .touchUpInside)
self.imageView?.isUserInteractionEnabled = false
}
open func swapLabelWithImage() {
let rightLableSize = self.titleLabel?.sizeThatFits((self.titleLabel?.frame.size)!)
self.imageEdgeInsets = EdgeInsets(top: 0, left: (rightLableSize?.width)! - 4, bottom: 0, right: 0)
self.titleEdgeInsets = EdgeInsets(top: 0, left: -54, bottom: 0, right: 0)
self.contentEdgeInsets = EdgeInsets(top: 0, left: 20, bottom: 0, right: 4)
let shapeView = UIView(frame: CGRect(x: self.imageEdgeInsets.left + 19, y: 6, width: 20, height: 20))
shapeView.backgroundColor = UIColor.darkGray
shapeView.cornerRadius = shapeView.frame.size.width/2
shapeView.zPosition = (self.imageView?.zPosition)! - 1
shapeView.isUserInteractionEnabled = false
self.addSubview(shapeView)
}
internal func clickAction(sender: ChipDeleteableButton) {
print("do something")
}
}
and the creation-snipped:
open func prepareChipDeleteableButton () {
let button = ChipDeleteableButton()
button.title = "deleteable chip"
button.swapLabelWithImage()
view.layout(button).height(32).center(offsetY: 150)
}
more info:
the creation-function r called in my ViewController, in viewWillAppear()
why i have a extra-function for my deletable-chip? - because i let AutoLayout do his job and after that i can get the necessary "String-width" of its label with let rightLableSize = self.titleLabel?.sizeThatFits((self.titleLabel?.frame.size)!)
I did collapse/expand table cell in swift 3. But, I would like to add some padding bottom to the title header. In my screenshot, there is no padding between Title 1 and Title 2.
Another problem is that how can I move arrow image to the right?
Here is my code.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView.init(frame: CGRect(x: 0, y: 0, width: 300, height: 28))
var imageView = UIImageView()
if (expandSections.contains(section)) {
imageView = UIImageView.init(frame: CGRect(x: 7, y: 5, width: 25, height: 25))
imageView.image = UIImage(named: "down_image")
} else {
imageView = UIImageView.init(frame: CGRect(x: 7, y: 5, width: 25, height: 25))
imageView.image = UIImage(named: "up_image")
}
let headerTitle = UILabel.init(frame: CGRect(x: 38, y: 4, width: 250, height: 28))
headerTitle.text = sectionData[section]
headerTitle.textColor = UIColor.white
let tappedSection = UIButton.init(frame: CGRect(x: 0, y: 0, width: headerView.frame.size.width, height: headerView.frame.size.height))
tappedSection.addTarget(self, action: #selector(sectionTapped), for: .touchUpInside)
tappedSection.tag = section
headerView.addSubview(imageView)
headerView.addSubview(headerTitle)
headerView.addSubview(tappedSection)
headerView.backgroundColor = UIColor.lightGray
return headerView
}
Try this, In here I added another view inside of headerView. Then only u can add padding in headerView.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView.init(frame: CGRect(x: 0, y: 0, width: 300, height: 28))
let internalView = UIView.init(frame: CGRect(x: 0, y: 0, width: 300, height: 25))
var imageView = UIImageView()
if (expandSections.contains(section)) {
imageView = UIImageView.init(frame: CGRect(x: internalView.frame.size.width - 10 , y: 5, width: 25, height: 25))
imageView.image = UIImage(named: "down_image")
} else {
imageView = UIImageView.init(frame: CGRect(x: internalView.frame.size.width - 10 , y: 5, width: 25, height: 25))
imageView.image = UIImage(named: "up_image")
}
let headerTitle = UILabel.init(frame: CGRect(x: 38, y: 4, width: 250, height: 28))
headerTitle.text = sectionData[section]
headerTitle.textColor = UIColor.white
let tappedSection = UIButton.init(frame: CGRect(x: 0, y: 0, width: headerView.frame.size.width, height: headerView.frame.size.height))
tappedSection.addTarget(self, action: #selector(sectionTapped), for: .touchUpInside)
tappedSection.tag = section
internalView.addSubview(imageView)
internalView.addSubview(headerTitle)
internalView.addSubview(tappedSection)
headerView.addSubview(internalView)
headerView.backgroundColor = UIColor.lightGray
return headerView
}
I'm having an issue where the last bubble in my chart cuts off. I need a way of extending the chart so that the entire circle is displayed. I've tried everything from adding an extra value to the end, to adjusting padding. Nothing seems to work. Unfortunately, the Chart JS documention on bubble charts is severely lacking as well.
var randomScalingFactor = function() {
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
};
var randomColorFactor = function() {
return Math.round(Math.random() * 255);
};
var randomColor = function() {
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
};
var bubbleChartData = {
animation: {
duration: 10000
},
datasets: [{
label: "My First dataset",
backgroundColor: randomColor(),
data: [
{
x: 10,
y: 0,
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: 20,
y: 0,
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: 30,
y: 0,
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: 40,
y: 0,
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: 50,
y: 0,
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: 60,
y: 0,
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: 70,
y: 0,
r: 30,
}]
}]
};
var ctx = document.getElementById('Chart').getContext('2d');
var chart = new Chart(ctx, {
type: 'bubble',
data: bubbleChartData
})
JSFiddle: https://jsfiddle.net/3dog0bec/
I solved this issue by modifying the xAxes ticks min and max. This worked because I have a set number of data to display, so I simply set the values to 10 less than the first data point and 10 more than the last.
var chart = new Chart(ctx, {
type: 'bubble',
data: bubbleChartData,
options: {
scales: {
xAxes: [
{
ticks: {
min: -10,
max: 100
}
}]
}
}
});