Amcharts: Multiple category axis grid alignment issue in Column series chart - amcharts

I am trying to create horizontal column series chart having multiple category axis.
Both categories are not aligned with same grid lines.
I am tried below but still same issue.
categoryAxis1.syncWithAxis = categoryAxis;
Need help to resolve this.
Please refer below link
https://jsfiddle.net/8e0hqa6b/2/
/**
* ---------------------------------------
* This demo was created using amCharts 4.
*
* For more information visit:
* https://www.amcharts.com/
*
* Documentation is available at:
* https://www.amcharts.com/docs/v4/
* ---------------------------------------
*/
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.padding(40, 40, 40, 40);
chart.topAxesContainer.layout = "horizontal";
chart.topAxesContainer.reverseOrder = false;
var categoryAxis = chart.yAxes.push(new am4charts.CategoryAxis());
/* categoryAxis.renderer.grid.template.location = 0; */
categoryAxis.dataFields.category = "network";
/* categoryAxis.renderer.minGridDistance = 1; */
categoryAxis.renderer.inversed = true;
categoryAxis.renderer.grid.template.disabled = true;
categoryAxis.layout = "absolute";
categoryAxis.renderer.labels.template.align = 'left';
// Set up axis title
categoryAxis.title.text = "Accounts";
categoryAxis.title.rotation = 0;
categoryAxis.title.align = "left";
categoryAxis.title.valign = "top";
categoryAxis.title.dy = -22;
categoryAxis.title.fontWeight = 500;
var categoryAxis1 = chart.yAxes.push(new am4charts.CategoryAxis());
categoryAxis1.dataFields.category = "MAU1";
categoryAxis1.renderer.inversed = true;
categoryAxis1.renderer.grid.template.disabled = true;
categoryAxis1.layout = "absolute";
categoryAxis1.renderer.labels.template.align = 'right';
categoryAxis1.syncWithAxis = categoryAxis;
// Set up axis title
categoryAxis1.title.text = "Amount";
categoryAxis1.title.rotation = 0;
categoryAxis1.title.align = "right";
categoryAxis1.title.valign = "top";
categoryAxis1.title.dy = -22;
categoryAxis1.title.fontWeight = 500;
var interfaceColors = new am4core.InterfaceColorSet();
var positiveColor = interfaceColors.getFor("positive");
var negativeColor = interfaceColors.getFor("negative");
var valueAxis = chart.xAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.opposite = true;
valueAxis.min = 0;
valueAxis.renderer.labels.template.disabled = true;
valueAxis.renderer.grid.template.disabled = true;
valueAxis.renderer.baseGrid.disabled = true;
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.categoryY = "network";
series.dataFields.valueX = "MAU";
series.yAxis = categoryAxis;
series.tooltipText = "{valueX.value}"
series.columns.template.strokeOpacity = 0;
series.columns.template.column.cornerRadiusBottomRight = 2;
series.columns.template.column.cornerRadiusTopRight = 2;
/* series.columns.template.column.dy = -6 */
var series1 = chart.series.push(new am4charts.ColumnSeries());
series1.dataFields.categoryY = "MAU1";
series1.dataFields.valueX = "MAU";
series1.yAxis = categoryAxis1;
series1.tooltipText = "{valueX.value}"
series1.columns.template.disabled = true;
// as by default columns of the same series are of the same color, we add adapter which takes colors from chart.colors color set
/* series.columns.template.adapter.add("fill", function(fill, target){
return chart.colors.getIndex(target.dataItem.index);
}); */
/* categoryAxis1.sortBySeries = series; */
/* categoryAxis.sortBySeries = series; */
chart.data = [{
"network": "Facebook",
"MAU": 2255250000,
"MAU1": 2255250000
},
{
"network": "Google+",
"MAU": 430000000,
"MAU1": 430000000
},
{
"network": "Instagram",
"MAU": 1000000000,
"MAU1": 1000000000
},
{
"network": "Pinterest",
"MAU": 246500000,
"MAU1": 246500000
},
{
"network": "Reddit",
"MAU": 355000000,
"MAU1": 355000000
},
{
"network": "TikTok",
"MAU": 500000000,
"MAU1": 500000000
},
{
"network": "Tumblr",
"MAU": 624000000,
"MAU1": 624000000
},
{
"network": "Twitter",
"MAU": 329500000,
"MAU1": 329500000
},
{
"network": "WeChat",
"MAU": 1000000000,
"MAU1": 1000000000
}
]

Related

how to make labels curved in amcharts radar chart

i want to curve labels of radar chart as done on pie chart here https://codepen.io/team/amcharts/pen/wNYbbo
how to achieve same curved lables on this radarchart
below is the code snippets of my radar chart
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#chartdiv {
width: 100%;
height: 600px;
}
am4core.useTheme(am4themes_animated);
// Themes end
var chart = am4core.create("chartdiv", am4charts.RadarChart);
chart.hiddenState.properties.opacity = 0; // this creates initial fade-in
chart.data = [
{
category: "Happiness",
value1: 8,
"config":{"fill": "red"},
"background": {"fill":"green"}
},
{
category: "Anxiety",
value1: 9,
"config":{"fill": "blue"}
},
{
category: "Three",
value1: 7,
"config":{"fill": "green"}
},
{
category: "Four",
value1: 1,
"config":{"fill": "red"}
},
{
category: "Five",
value1: 2,
"config":{"fill": "orange"}
},
{
category: "Six",
value1: 5,
value2: -5,
"config":{"fill": "black"}
}
];
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "category";
categoryAxis.renderer.labels.template.location = 0.5;
categoryAxis.renderer.tooltipLocation = 0.5;
categoryAxis.renderer.cellStartLocation = 0;
categoryAxis.renderer.cellEndLocation = 1;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.renderer.labels.template.horizontalCenter = "left";
valueAxis.min = 0;
var series1 = chart.series.push(new am4charts.RadarColumnSeries());
series1.columns.template.tooltipText = "{category}: {valueY.value}";
series1.columns.template.width = am4core.percent(100);
series1.name = "Series 1";
series1.dataFields.categoryX = "category";
series1.dataFields.valueY = "value1";
series1.columns.template.radarColumn.configField = 'config';
chart.seriesContainer.zIndex = -1;
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.exportable = false;
chart.scrollbarY = new am4core.Scrollbar();
chart.scrollbarY.exportable = false;
chart.cursor = new am4charts.RadarCursor();
chart.cursor.xAxis = categoryAxis;
chart.cursor.fullWidthXLine = true;
chart.cursor.lineX.strokeOpacity = 0;
chart.cursor.lineX.fillOpacity = 0.1;
https://codepen.io/omar630/pen/KKWWbNe?editors=0010
here is the codepen link
just need labels curved on outside of respective area sections
var chart = am4core.create("chartdiv", am4charts.RadarChart);
chart.hiddenState.properties.opacity = 0; // this creates initial fade-in
chart.data = [
{
category: "Happiness",
value1: 8,
"config":{"fill": "red"},
"background": {"fill":"green"}
},
{
category: "Anxiety",
value1: 9,
"config":{"fill": "blue"}
},
{
category: "Three",
value1: 7,
"config":{"fill": "green"}
},
{
category: "Four",
value1: 1,
"config":{"fill": "red"}
},
{
category: "Five",
value1: 2,
"config":{"fill": "orange"}
},
{
category: "Six",
value1: 5,
value2: -5,
"config":{"fill": "black"}
}
];
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "category";
categoryAxis.renderer.labels.template.location = 0.5;
categoryAxis.renderer.tooltipLocation = 0.5;
categoryAxis.renderer.cellStartLocation = 0;
categoryAxis.renderer.cellEndLocation = 1;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.renderer.labels.template.horizontalCenter = "left";
valueAxis.min = 0;
var series1 = chart.series.push(new am4charts.RadarColumnSeries());
series1.columns.template.tooltipText = "{category}: {valueY.value}";
series1.columns.template.width = am4core.percent(100);
series1.name = "Series 1";
series1.dataFields.categoryX = "category";
series1.dataFields.valueY = "value1";
series1.columns.template.radarColumn.configField = 'config';
chart.seriesContainer.zIndex = -1;
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.exportable = false;
chart.scrollbarY = new am4core.Scrollbar();
chart.scrollbarY.exportable = false;
chart.cursor = new am4charts.RadarCursor();
chart.cursor.xAxis = categoryAxis;
chart.cursor.fullWidthXLine = true;
chart.cursor.lineX.strokeOpacity = 0;
chart.cursor.lineX.fillOpacity = 0.1;
//add below lines in your code
categoryAxis.renderer.labels.template.adapter.add("rotation", function (rotation, target) {
var value = target.dataItem.category;
var position = categoryAxis.categoryToPosition(value);
var angle = categoryAxis.renderer.positionToAngle(position) + 90;
return angle;
});
Try this it will work check bottom lines which are added.
found solution here is the snippet
am4core.ready(function () {
// the chart
var chart = am4core.create("amchart_wheel_of_life", am4charts.RadarChart);
chart.hiddenState.properties.opacity = 0; // this creates initial fade-in
chart.innerRadius = am4core.percent(30);
chart.width = am4core.percent(100);
chart.height = am4core.percent(100);
chart.seriesContainer.zIndex = -1; // grid over series
//chart.seriesContainer.background.fill = '#0f0'
//chart.seriesContainer.opacity = 0.5
//chart.padding(20, 20, 20, 20);
// chart data
var wheel_data = [
{
'range': 'another',
'data': [{
"category": "another",
"value": 10,
"color": chart.colors.next(),
}]
},{
'range': 'Your hapsadpiness',
'data': [{
"category": "your haasdppiness",
"value": 10,
"color": chart.colors.next(),
}]
},{
'range': 'Your happiness',
'data': [{
"category": "your happiness",
"value": 10,
"color": chart.colors.next(),
}]
}, {
'range': 'Self Esteem',
'data': [{
"category": "self esteem",
"value": 6,
"color": chart.colors.next()
}]
}, {
'range': 'Your Mood',
'data': [{
"category": "your mood",
"value": 3,
"color": chart.colors.next()
}]
}, {
'range': 'Digital Usage',
'data': [{
"category": "digial usage",
"value": 7,
"color": chart.colors.next()
}]
}, {
'range': 'Job Satisfaction',
'data': [{
"category": "Job Satisfaction",
"value": 9,
"color": chart.colors.next()
}]
}, {
'range': 'your calmness',
'data': [{
"category": "sad",
"value": 5,
"color": chart.colors.next()
}]
}, {
'range': 'stress level',
'data': [{
"category": "stress level",
"value": 2,
"color": chart.colors.next()
}]
}];
// interaction
var categoryIndex = 0;
chart.cursor = new am4charts.RadarCursor();
chart.cursor.innerRadius = am4core.percent(25);
chart.cursor.behavior = "none"; // disable zoom
//chart.cursor.lineX.disabled = true;
//chart.cursor.lineY.fillOpacity = 0.1;
//chart.cursor.lineY.fill = am4core.color("#000000");
//chart.cursor.lineY.strokeOpacity = 0;
//chart.cursor.fullWidthLineY = true;
chart.cursor.events.on("cursorpositionchanged", function (ev) { // up
var xAxis = ev.target.chart.xAxes.getIndex(0);
var yAxis = ev.target.chart.yAxes.getIndex(0);
categoryIndex = xAxis.positionToIndex(xAxis.toAxisPosition(ev.target.xPosition));
//console.log(yAxis.toAxisPosition(ev.target.yPosition));
//console.log("y: ", yAxis.positionToValue(yAxis.toAxisPosition(ev.target.yPosition)));
});
// var interaction = am4core.getInteraction();
// interaction.events.on("up", function (event) {
// var point = am4core.utils.documentPointToSprite(event.pointer.point, chart.seriesContainer);
// var empty = 4.2;
// var x = (valueAxis.max + empty) - valueAxis.xToValue(point.x);
// var y = (valueAxis.max + empty) - valueAxis.yToValue(point.y);
// var r = Math.sqrt(x * x + y * y) - empty;
// //console.log(x,y,r);
// if (r > valueAxis.min - 1 && r < valueAxis.max) {
// //console.log(r);
// setValue(categoryIndex, Math.ceil(r));
// }
// });
// set value
function setValue(index, value) {
chart.data[index].value = value;
chart.invalidateRawData();
}
// categoryAxis
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
// categoryAxis.renderer.lebels.template.background = 'black';
categoryAxis.dataFields.category = "category";
categoryAxis.renderer.labels.template.location = 0.5;
categoryAxis.renderer.tooltipLocation = 0.5;
categoryAxis.renderer.labels.template.bent = true;
categoryAxis.renderer.labels.template.padding(0, 0, 0, 0);
categoryAxis.renderer.labels.template.fill = am4core.color("#414042");
// categoryAxis.renderer.fill = am4core.color('red')
categoryAxis.renderer.labels.template.disabled = true; //hide label name
categoryAxis.renderer.grid.template.strokeDasharray = "1,2"
categoryAxis.renderer.labels.template.adapter.add("radius", (innerRadius, target) => {
return -valueAxis.valueToPoint(-3.8).y;
});
categoryAxis.tooltip.defaultState.properties.opacity = 0.; // hide tooltip
/*categoryAxis.renderer.axisFills.template.disabled = false;
categoryAxis.renderer.axisFills.template.fillOpacity = 1;
categoryAxis.renderer.axisFills.template.fill = am4core.color("#e7e8e8");
*/
// valueAxis
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
//valueAxis.renderer.labels.template.disabled = true;
valueAxis.renderer.labels.template.fill = am4core.color("#414042");
valueAxis.min = 0;
valueAxis.max = 10;
valueAxis.renderer.minGridDistance = 10;
valueAxis.fontSize = '10px';
// valueAxis.renderer.labels.template.adapter.add("dy", (innerRadius, target) => {
// return -valueAxis.valueToPoint(-3.7).y;
// });
// series
var series = chart.series.push(new am4charts.RadarColumnSeries());
series.columns.template.width = am4core.percent(100);
series.columns.template.strokeWidth = 0;
series.columns.template.column.propertyFields.fill = "color";
series.dataFields.categoryX = "category";
series.dataFields.valueY = "value";
// series tootltip
series.columns.template.tooltipText = "{categoryX}: {valueY.value}";
series.tooltip.getFillFromObject = false;
series.tooltip.background.fill = am4core.color("#f7aa00");
series.tooltip.label.fill = am4core.color("#414042");
series.tooltip.label.fontWeight = 'bold';
series.tooltip.background.strokeOpacity = 0;
// center image
var image = categoryAxis.createChild(am4core.Image);
image.horizontalCenter = "middle";
image.verticalCenter = "middle";
image.href = "https://happimynd.com/images/icons/icon-512x512.png";
image.width = am4core.percent(23);
image.height = am4core.percent(23);
// image.zIndex = 1; // grid over series
var circle = chart.seriesContainer.createChild(am4core.Circle);
circle.horizontalCenter = "middle";
circle.verticalCenter = "middle";
circle.fill = am4core.color('#e7e8e8');
circle.zIndex = -5; // grid over seriesd
categoryAxis.events.on('sizechanged', (ev) => {
circle.radius = -valueAxis.valueToPoint(11.5).y;
});
function generateRadarData() {
let data = [];
for (let i in wheel_data) {
// capitalize
for (let t in wheel_data[i].data) {
wheel_data[i].data[t].category = wheel_data[i].data[t].category.toUpperCase();
}
data = data.concat(wheel_data[i].data);
createRange(wheel_data[i].range, wheel_data[i].data, i);
}
//console.log(data);
return data;
}
function createRange(name, data, index) {
let axisRange = categoryAxis.axisRanges.create();
axisRange.text = name.toUpperCase();
// first country
axisRange.category = data[0].category;
// last country
axisRange.endCategory = data[data.length - 1].category;
// range grid
//axisRange.grid.disabled = true;
axisRange.label.mouseEnabled = false;
axisRange.grid.stroke = am4core.color("#FFFFFF");
axisRange.grid.strokeWidth = 1;
axisRange.grid.strokeOpacity = 1;
axisRange.grid.strokeDasharray = "0,0";
axisRange.grid.adapter.add("radius", (innerRadius, target) => {
return -valueAxis.valueToPoint(13.8).y;
});
// range background
let axisFill = axisRange.axisFill;
axisFill.fill = data[0].color; // chart.colors.next
axisFill.disabled = false;
axisFill.fillOpacity = 1;
axisFill.adapter.add("innerRadius", (innerRadius, target) => {
return -valueAxis.valueToPoint(11.5).y;
});
axisFill.adapter.add("radius", (innerRadius, target) => {
return -valueAxis.valueToPoint(13.8).y;
});
//axisFill.togglable = true;
//axisFill.showSystemTooltip = true;
//axisFill.readerTitle = "click to zoom";
//axisFill.cursorOverStyle = am4core.MouseCursorStyle.pointer;
// range label
let axisLabel = axisRange.label;
axisLabel.location = 0.5;
axisLabel.fill = am4core.color("#414042");
axisLabel.fontWeight = 'bold';
axisLabel.fontSize = '10px';
axisLabel.adapter.add("radius", (innerRadius, target) => {
return -valueAxis.valueToPoint(-1.9).y;
});
}
chart.data = generateRadarData();
});
#amchart_wheel_of_life {
width: 100%;
height: 98vh;
font-family:arial;
}
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<div id="amchart_wheel_of_life"></div>
https://codepen.io/omar630/pen/YzZVVGr

I want to change this vertical image slider to horizontal one

This is the current vertical image slider URL.
current vertical image slider URL.
I want to change the slider direction to horizontal.
These are my codes.
right view.js
import { View } from './view.js'
class SliderAnimator {
// Ramon: Frame count of animation
static MAX_COUNT = 50
constructor(view) {
this.view = view
this.running = false
this.view.plane.children[0].material.uniforms.hidden.value = false
}
update() {
if (this.running) {
this.stepCount++
this.view.divider = this.from + (this.to - this.from) /
SliderAnimator.MAX_COUNT * this.stepCount
// this.view.plane.children[0].material.uniforms.divider.value = this.view.divider
// this.view.plane.children[0].material.uniforms.hidden.value = false
if (this.stepCount == SliderAnimator.MAX_COUNT) {
this.running = false
// this.view.plane.children[0].material.uniforms.hidden.value = true
}
}
}
}
export class TopRightView extends View {
static DIVIDER_THRESHOLD = 30
async init() {
await super.init()
let textureLoader = new THREE.TextureLoader()
let texture0 = textureLoader.setPath('./images/jpeg/').load(param.JPEG_FILES[this.id])
let texture1 = textureLoader.setPath('./images/jpeg/').load(param.JPEG_FILES[4])
this.plane.children[0].material = new THREE.ShaderMaterial({
uniforms: {
divider: { value: 0 },
hidden: {value: true },
zoomFactor: { value: 1.0 },
tex0: { type: "t", value: texture0 },
tex1: { type: "t", value: texture1 }
},
vertexShader: this.vertexShader(),
fragmentShader: this.fragmentShader()
})
// this.divider = this.planeWidth / 2
this.divider = 0
this.plane.children[0].material.uniforms.divider.value = this.divider
// this.plane.children[0].material.uniforms.divider.value = 1.3333
this.dividerMoving = false
this.snappable = false
this.sliderAnimator = new SliderAnimator(this)
}
vertexShader() {
return `
varying vec2 vUv;
varying vec3 vPosition;
void main() {
vUv = uv;
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
}
fragmentShader() {
return `
varying vec2 vUv;
varying vec3 vPosition;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform float divider;
uniform float zoomFactor;
uniform bool hidden;
void main() {
float dividerWidth;
if (hidden) {
dividerWidth = 0.0;
} else {
dividerWidth = 0.03 / zoomFactor;
}
if (vPosition.x > divider + dividerWidth) {
gl_FragColor = texture2D(tex1, vUv);
} else if (vPosition.x < divider - dividerWidth) {
gl_FragColor = texture2D(tex0, vUv);
} else {
gl_FragColor = vec4(0.5, 0.5, 1.0, 1.0);
}
}
`
}
}
views.js
import { SVGPlane } from './svg-plane.js';
export class View {
static DRAG_TRESHOLD = 3;
constructor(id, containter, vector, elementControl) {
this.id = id;
this.width = window.innerWidth - 2 * param.cLeft;
this.height = param.cHeight * 2 + param.cTop;
this.container = containter;
this.vector = vector;
this.elementControl = elementControl;
this.mouseDownPosition = new THREE.Vector2();
}
async init() {
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
this.renderer.setSize(this.width, this.height);
this.container.appendChild(this.renderer.domElement);
// this.renderer.setClearColor(param.BACK_COLORS[this.id], 0);
this.camera = new THREE.OrthographicCamera(
param.orthoWidth / (-2),
param.orthoWidth / 2,
param.orthoHeight / 2,
param.orthoHeight / (-2),
0.05, 1000
);
this.camera.position.fromArray(param.CAMERA_POSITIONS[this.id]);
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(param.BACK_COLORS[this.id]);
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableRotate = false;
await this._initMeshes();
this._calibrateCamera();
this.animate();
this.container.addEventListener('mousemove', (event) => { this.onMouseMove(event) }, false);
this.container.addEventListener('mousedown', (event) => { this.onMouseDown(event) }, false);
this.container.addEventListener('mouseup', (event) => { this.onMouseUp(event) }, false);
this.container.addEventListener('mouseout', (event) => { this.onMouseUp(event) }, false);
this.renderer.domElement.addEventListener(
'wheel', (event) => { this.onWheel(event) }, false
);
}
_calibrateCamera() {
this.camera.left = -this.planeWidth / 2;
this.camera.right = this.planeWidth / 2;
this.camera.top = this.planeWidth / 2 * this.height / this.width;
this.camera.bottom = -this.camera.top;
this.camera.updateProjectionMatrix();
}
async _initMeshes() {
this.plane = new THREE.Group();
var imageMesh = await this._getImageMesh();
imageMesh.name = "plane";
this.plane.add(imageMesh);
var helper = new THREE.GridHelper(400, 800);
helper.material.opacity = 0.75;
helper.material.transparent = true;
helper.material.depthTest = false;
helper.position.y = 0.1;
this.plane.add(helper);
this.plane.rotation.fromArray(param.PLANE_ROTATIONS[this.id]);
this.scene.add(this.plane);
}
async _getImageMesh() {
if (param.SVG_MODE) {
return await new SVGPlane().createSVGPlane(param.SVG_FILES[this.id]);
} else {
return new Promise((resolve, reject) => {
new THREE.TextureLoader().setPath('./images/jpeg/').load(
param.JPEG_FILES[this.id],
(t) => {
var s = param.JPEG_SCALES[this.id];
this.planeWidth = s * param.pLength;
this.planeHeight = s * param.pLength * t.image.height / t.image.width;
console.log(this.planeWidth, this.planeHeight);
var planeGeo = new THREE.BoxGeometry(
this.planeWidth, 0.01, this.planeHeight
);
var planeMat = new THREE.MeshPhongMaterial({ map: t });
var planeMesh = new THREE.Mesh(planeGeo, planeMat);
planeMesh.position.copy(param.JPEG_OFFSETS[this.id]);
resolve(planeMesh);
});
});
}
}
animate() {
window.requestAnimationFrame(() => { this.animate(); });
this.renderer.clear();
this.renderer.render(this.scene, this.camera);
}
}
parameter.js
class Parameter {
TOP_LEFT = 0;
TOP_RIGHT = 1;
BOTTOM_LEFT = 2;
BOTTOM_RIGHT = 3;
TO_METER = 0.3048;
PLANE_COLOR = 0xaaaaaa;
BALL_COLOR = 0x0000ff;
LINE_COLOR = 0xff0000;
BACK_COLORS = [
0x598d4b,
0x598d4b,
0xc6ced1,
0xc6ced1
];
MAP_SCALE = 100 / 1.5 * 100 / 53; // no meaning anymore
SVG_MODE = false;
JPEG_FILES = [
'1-Top-Left-Quadrant.jpg',
'2-Top-Right-Quadrant.jpg',
'3-Bottom-Left-Quadrant.jpg',
'4-Bottom-Right-Quadrant.jpg',
'2-Top-Right-Quadrant-2.jpg'
];
SVG_FILES = [
'1-Top-Left-Quadrant.svg',
'2-Top-Right-Quadrant.svg',
'3-Bottom-Left-Quadrant.svg',
'4-Bottom-Right-Quadrant.svg'
];
CAMERA_POSITIONS = [
[ -5, 5, 5],
[ 0, 10, 0],
[-10, 0, 0],
[ 0, 0, 10]
];
PLANE_ROTATIONS = [
[0, 0, 0],
[0, 0, 0],
[Math.PI / 2, 0, Math.PI / 2],
[Math.PI / 2, 0, 0]
];
// PLANE_AXES = ['', 'xz', 'yz', 'xy'];
JPEG_SCALES = [0.8267, 1, 0.95, 0.5688];
JPEG_OFFSETS = [
new THREE.Vector3(0.4, 0, -0.3),
new THREE.Vector3(),
new THREE.Vector3(0, 0, -0.73),
new THREE.Vector3(0.9, 0, -0.98),
];
CAMERA_OFFSETS = [
this.JPEG_OFFSETS[0],
this.JPEG_OFFSETS[1],
new THREE.Vector3(-this.JPEG_OFFSETS[2].z, 0, this.JPEG_OFFSETS[2].x),
new THREE.Vector3(this.JPEG_OFFSETS[3].x, 0, -this.JPEG_OFFSETS[3].z)
]
BALL_SIZE = 0.05;
constructor() {
if (!!Parameter.instance) {
return Parameter.instance;
}
Parameter.instance = this;
this._init();
return this;
}
_init() {
var controlBarHeight = 0;
var gap = 2;
this.cWidth = (window.innerWidth - gap * 3) / 2;
this.cHeight = (window.innerHeight - controlBarHeight - gap * 3) / 2;
this.cTop = gap;
this.cLeft = gap;
this.cRate = this.cWidth / this.cHeight;
this.orthoHeight = 8;
this.orthoWidth = this.orthoHeight * this.cRate;
this.pLength = 8;
this.hLength = 5;
}
}
var param = new Parameter();
Please help me.

Multiple Dataset AmstockChart with multiple Axis [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I want to implement multiple value axis in following amchart sample:
https://www.amcharts.com/demos/multiple-data-sets/
Multiple axis example: http://www.amcharts.com/tips/multiple-value-axes-stock-chart/
I tried a lot but I think I miss some minor thing.
Is there any way to combine above charts (multi value and multi data Set) and create a multiple value axis multiple data sets Chart?
Examples with jsfiddle will work best for me. Thanks :)
I did this myself. Hope this becomes helpful to someone. Here is the solution:
AmCharts.ready(function () {
generateChartData();
createStockChart();
});
var colors = [
"#FF6600", "#B0DE09", "#FCD202", "#2A0CD0",
"#CD0D74", "#CC0000", "#00CC00", "#0000CC", "#DDDDDD",
"#999999", "#333333", "#990000", "#0D8ECF"
];
var chartData1 = [];
var chartData2 = [];
var chartData3 = [];
var chartData4 = [];
function generateChartData() {
var firstDate = new Date();
firstDate.setDate(firstDate.getDate() - 500);
firstDate.setHours(0, 0, 0, 0);
for (var i = 0; i < 500; i++) {
var newDate = new Date(firstDate);
newDate.setDate(newDate.getDate()+i);
newDate.setHours(0, 0, 0, 0);
var value1 = Math.round(Math.random() * (40 + i)) + 100 + i;
var value2 = Math.round(Math.random() * (100 + i)) + 200 + i;
var value3 = Math.round(Math.random() * (100 + i)) + 200;
var value4 = Math.round(Math.random() * (100 + i)) + 200 + i;
chartData1.push({date: newDate,value1: value1});
chartData2.push({date: newDate,value2: value2});
chartData3.push({date: newDate,value3: value3});
chartData4.push({date: newDate,value4: value4});
}
}
function createStockChart() {
var chart = new AmCharts.AmStockChart();
chart.pathToImages = "http://www.amcharts.com/lib/3/images/";
var dataSet1 = new AmCharts.DataSet();
dataSet1.fieldMappings = [{fromField: "value1", toField: "value1"}];
dataSet1.dataProvider = chartData1;
dataSet1.categoryField = "date";
dataSet1.title = "Value1";
dataSet1.color = colors[0];
var dataSet2 = new AmCharts.DataSet();
dataSet2.fieldMappings = [{fromField: "value2", toField: "value2"}];
dataSet2.dataProvider = chartData2;
dataSet2.categoryField = "date";
dataSet2.title = "Value2";
dataSet2.color = colors[1];
var dataSet3 = new AmCharts.DataSet();
dataSet3.fieldMappings = [{fromField: "value3", toField: "value3"}];
dataSet3.dataProvider = chartData3;
dataSet3.categoryField = "date";
dataSet3.title = "Value3";
dataSet3.color = colors[2];
var dataSet4 = new AmCharts.DataSet();
dataSet4.fieldMappings = [{fromField: "value4", toField: "value4"}];
dataSet4.dataProvider = chartData4;
dataSet4.categoryField = "date";
dataSet4.title = "Value4";
dataSet4.color = colors[3];
// set data sets to the chart
chart.dataSets = [dataSet1,dataSet2,dataSet3,dataSet4];
// PANELS ///////////////////////////////////////////
// first stock panel
var stockPanel = new AmCharts.StockPanel();
stockPanel.recalculateToPercents = "never";
stockPanel.title = "Volume";
var categoryAxesSettings = new AmCharts.CategoryAxesSettings();
categoryAxesSettings.minPeriod = "DD";
chart.categoryAxesSettings = categoryAxesSettings;
// apply custom style for value axes
var valueAxesSettings = new AmCharts.ValueAxesSettings();
valueAxesSettings.axisAlpha = 1;
valueAxesSettings.gridThickness = 0;
valueAxesSettings.axisThickness = 2;
valueAxesSettings.inside = false;
chart.valueAxesSettings = valueAxesSettings;
// apply custom style for panels settings
var panelsSettings = new AmCharts.PanelsSettings();
panelsSettings.marginLeft = 100;
panelsSettings.marginRight = 100;
chart.panelsSettings = panelsSettings;
// add first value axes
var valueAxis1 = new AmCharts.ValueAxis();
valueAxis1.axisColor = colors[0];
valueAxis1.color = colors[0];
valueAxis1.offset = 0;
stockPanel.addValueAxis(valueAxis1);
// add second value axes
var valueAxis2 = new AmCharts.ValueAxis();
valueAxis2.axisColor = colors[1];
valueAxis2.color = colors[1];
valueAxis2.offset = 0;
valueAxis2.position = "right";
stockPanel.addValueAxis(valueAxis2);
// add third value axes
var valueAxis3 = new AmCharts.ValueAxis();
valueAxis3.axisColor = colors[2];
valueAxis3.color = colors[2];
valueAxis3.offset = 50;
stockPanel.addValueAxis(valueAxis3);
// add fourth value axes
var valueAxis4 = new AmCharts.ValueAxis();
valueAxis4.axisColor = colors[3];
valueAxis4.color = colors[3];
valueAxis4.offset = 50;
valueAxis4.position = "right";
stockPanel.addValueAxis(valueAxis4);
// graph of first stock panel
var graph1 = new AmCharts.StockGraph();
graph1.valueField = "value1";
graph1.comparable = true;
graph1.title = "Value1";
graph1.useDataSetColors = false;
graph1.lineColor = colors[0];
graph1.bullet = "round";
graph1.bulletBorderColor = "#FFFFFF";
graph1.bulletBorderAlpha = 1;
graph1.balloonText = "[[title]]:<b>[[value]]</b>";
graph1.compareGraphBalloonText = "[[title]]:<b>[[value]]</b>";
graph1.compareGraphBullet = "round";
graph1.compareGraphBulletBorderColor = "#FFFFFF";
graph1.compareGraphBulletBorderAlpha = 1;
graph1.valueAxis = valueAxis1;
stockPanel.addStockGraph(graph1);
// graph of second stock panel
var graph2 = new AmCharts.StockGraph();
graph2.valueField = "value2";
graph2.comparable = true;
graph2.title = "Value2";
graph2.useDataSetColors = false;
graph2.lineColor = colors[1];
graph2.bullet = "round";
graph2.bulletBorderColor = "#FFFFFF";
graph2.bulletBorderAlpha = 1;
graph2.balloonText = "[[title]]:<b>[[value]]</b>";
graph2.compareGraphBalloonText = "[[title]]:<b>[[value]]</b>";
graph2.compareGraphBullet = "round";
graph2.compareGraphBulletBorderColor = "#FFFFFF";
graph2.compareGraphBulletBorderAlpha = 1;
graph2.valueAxis = valueAxis2;
stockPanel.addStockGraph(graph2);
// graph of third stock panel
var graph3 = new AmCharts.StockGraph();
graph3.valueField = "value3";
graph3.comparable = true;
graph3.title = "Value3";
graph3.useDataSetColors = false;
graph3.lineColor = colors[2];
graph3.bullet = "round";
graph3.bulletBorderColor = "#FFFFFF";
graph3.bulletBorderAlpha = 1;
graph3.balloonText = "[[title]]:<b>[[value]]</b>";
graph3.compareGraphBalloonText = "[[title]]:<b>[[value]]</b>";
graph3.compareGraphBullet = "round";
graph3.showEventsOnComparedGraphs = true;
graph3.compareGraphBulletBorderColor = "#FFFFFF";
graph3.compareGraphBulletBorderAlpha = 1;
graph3.valueAxis = valueAxis3;
stockPanel.addStockGraph(graph3);
// graph of fourth stock panel
var graph4 = new AmCharts.StockGraph();
graph4.comparable = true;
graph4.valueField = "value4";
graph4.title = "Value4";
graph4.useDataSetColors = false;
graph4.lineColor = colors[3];
graph4.bullet = "round";
graph4.bulletBorderColor = "#FFFFFF";
graph4.bulletBorderAlpha = 1;
graph4.balloonText = "[[title]]:<b>[[value]]</b>";
graph4.compareGraphBalloonText = "[[title]]:<b>[[value]]</b>";
graph4.compareGraphBullet = "round";
graph4.compareGraphBulletBorderColor = "#FFFFFF";
graph4.compareGraphBulletBorderAlpha = 1;
graph4.valueAxis = valueAxis4;
stockPanel.addStockGraph(graph4);
// create stock legend
var stockLegend1 = new AmCharts.StockLegend();
stockLegend1.periodValueTextComparing = "[[percents.value.close]]%";
stockLegend1.periodValueTextRegular = "[[value.close]]";
stockPanel.stockLegend = stockLegend1;
var periodSelector = new AmCharts.PeriodSelector();
periodSelector.periods = [
{period: "DD",count: 5,label: "5 day"},{period: "DD",count: 10,label: "10 days"},
{period: "MM",count: 1,label: "1 month",selected: true}, {period: "YYYY",count: 1,label: "1 year"},
{period: "YTD",label: "YTD"}, {period: "MAX",label: "MAX"}];
periodSelector.position = "left";
chart.periodSelector = periodSelector;
// DATA SET SELECTOR
var dataSetSelector = new AmCharts.DataSetSelector();
dataSetSelector.position = "left";
chart.dataSetSelector = dataSetSelector;
// set panels to the chart
chart.panels = [stockPanel];
// OTHER SETTINGS ////////////////////////////////////
var sbsettings = new AmCharts.ChartScrollbarSettings();
sbsettings.backgroundColor = "#222";
sbsettings.selectedBackgroundColor = "#555";
sbsettings.selectedGraphFillAlpha = 1;
chart.chartScrollbarSettings = sbsettings;
var chartScrollbar = new AmCharts.ChartScrollbar();
chartScrollbar.autoGridCount = true;
chartScrollbar.scrollbarHeight = 40;
chart.chartScrollbar = chartScrollbar;
// CURSOR settings
var cursorSettings = new AmCharts.ChartCursorSettings();
cursorSettings.valueBalloonsEnabled = true;
cursorSettings.cursorAlpha = 0.5;
cursorSettings.valueLineBalloonEnabled = true;
cursorSettings.valueLineEnabled = true;
cursorSettings.valueLineAlpha = 0.5;
cursorSettings.cursorPosition = "mouse";
chart.chartCursorSettings = cursorSettings;
var categoryAxis = new AmCharts.CategoryAxis();
chart.categoryAxis = categoryAxis;
chart.write('chartdiv');
}
body{
font-size:12px;
color:#000000;
background-color:#ffffff;
font-family:verdana,helvetica,arial,sans-serif;
}
.amChartsButtonSelected{
background-color:#CC0000;
border-style:solid;
border-color:#CC0000;
border-width:1px;
color:#FFFFFF;
-moz-border-radius: 5px;
border-radius: 5px;
margin: 1px;
}
.amChartsButton{
background-color:#EEEEEE;
border-style:solid;
border-color:#CCCCCC;
border-width:1px;
color:#000000;
-moz-border-radius: 5px;
border-radius: 5px;
margin: 1px;
}
.amChartsCompareList{
border-style:solid;
border-color:#CCCCCC;
border-width:1px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://www.amcharts.com/lib/3/amcharts.js" type="text/javascript"></script>
<script src="http://www.amcharts.com/lib/3/serial.js" type="text/javascript"></script>
<script src="http://www.amcharts.com/lib/3/amstock.js" type="text/javascript"></script>
<div id="chartdiv" style="width: 100%; height: 500px;"></div>

Make a draggable, rotating wheel snap to evenly distributed positions

I'm rendering a wheel in a WebGL canvas using mrdoob's THREE.js.
I want the wheel to
Spin around it's center
Be draggable by mouse or touch interaction
Slow down by applying fake friction
Snap to the center of a wedge whenever the rotation speed reaches a certain threshold.
You may think of the behaviour of the wheel as that of a lottery wheel.
So far I have achieved points 1-3. This is my code:
'use strict';
var WIDTH = 1080,
HEIGHT = 1080;
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
var scene = new THREE.Scene();
scene.add(camera);
camera.position.z = 300;
// Create renderer
var container = document.querySelector('#test');
var renderer = new THREE.WebGLRenderer();
renderer.setSize(WIDTH, HEIGHT);
renderer.setClearColor(0x000000, 0);
container.appendChild(renderer.domElement);
// Create objects
var wheelMaterial = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture('wheel.png'),
depthWrite: false,
alphaTest: 0.5
});
wheelMaterial.overdraw = true;
var wheel = new THREE.Mesh(
new THREE.PlaneGeometry(240, 240),
wheelMaterial);
scene.add(wheel);
// Mouse interaction
var isDragging = false;
var lastMouseCoords = null;
var mouseCoords = null;
container.addEventListener('mousedown', onDragStart, false);
container.addEventListener('touchstart', onDragStart, false);
container.addEventListener('mouseup', onDragEnd, false);
container.addEventListener('mouseout', onDragEnd, false);
container.addEventListener('touchend', onDragEnd, false);
container.addEventListener('mousemove', onMouseMove, false);
container.addEventListener('touchmove', onMouseMove, false);
function onDragStart(e) {
isDragging = true;
console.log('Dragging', e);
mouseCoords = pageCoordsToCanvasCoords(e);
rotationHistory = [];
}
function onDragEnd(e) {
isDragging = false;
lastMouseCoords = null;
mouseCoords = null;
console.log('Drag end');
}
function onMouseMove(e) {
e.preventDefault();
mouseCoords = pageCoordsToCanvasCoords(e);
}
// Utility functions
function pageCoordsToCanvasCoords(e) {
var canvasX;
var canvasY;
if ('touches' in e && e.touches.length > 0) {
canvasX = e.touches[0].pageX;
canvasY = e.touches[0].pageY;
} else {
canvasX = e.pageX
canvasY = e.pageY
}
canvasX -= e.target.offsetLeft;
canvasY -= e.target.offsetTop;
console.log(canvasX, canvasY);
return {
x: canvasX,
y: canvasY
};
}
function mouseCoordsToRotation(x, y) {
var origoX = WIDTH / 2.0,
origoY = HEIGHT / 2.0;
x = x - origoX;
y = y - origoY;
var atan = Math.atan2(x, y);
return atan;
}
function getMeanVelocity(history) {
if (history.length <= 1) {
return 0;
}
var movements = [];
var startTime = history[0].time;
var totalTimeElapsed = 0;
// Start from the second item in deltaRadians
for (var i = 1; i < history.length; i++) {
var item = history[i];
var movement = item.deltaRad;
movements.push(item.deltaRad);
var movementTimeDelta = item.time - startTime - totalTimeElapsed;
if (movementTimeDelta < 0) {
console.error('movementTimeDelta for history entry #' +
i + ' has travelled back in time somehow.');
}
totalTimeElapsed += movementTimeDelta;
}
var sum = movements.reduce(function (a, b) {
return a + b;
});
return sum / totalTimeElapsed;
}
function applyFakeFriction(velocity, time) {
/*
var currentRotation = wheel.rotation.z;
var nearestBorder = 0;
var nearestBorderDistance = 100;
for (var i = 0; i < PARTITIONS; i++) {
var partition = PARTITION_ARC * i - PARTITION_ARC * PARTITIONS / 2;
var distance = currentRotation - partition;
if (distance < 0) {
distance /= -1;
}
if (distance < nearestBorderDistance) {
console.log('distance is less than nearestBorderDistance')
nearestBorder = partition;
nearestBorderDistance = distance;
if (nearestBorderDistance < 0) {
nearestBorderDistance /= -1;
}
}
}
console.log('nearestBorderDistance: ', nearestBorderDistance);
*/
for (var i = 0; i < time; i++) {
velocity -= WHEEL_FRICTION; // * (nearestBorderDistance * BORDER_FRICTION);
}
return velocity;
}
var rotation = 1;
function snap() {
isSnapping = true;
/* Disabled, this the issue I'm asking about in the post
var update = function () {
cube.position.rotation = current.rotation;
}
var current = {
rotation: rotation
};
TWEEN.removeAll();
var easing = TWEEN.Easing['Elastic']['EaseInOut'];
var tweenHead = neww TWEEN.Tween(current)
.to({rotation: rotation})
.easing(easing)
.onUpdate(update);
tweenHead.start();
*/
}
var rotationHistory = []
var ROTATION_HISTORY_MAX_LENGTH = 5;
var WHEEL_FRICTION = 0.000001;
var BORDER_FRICTION = 2;
var PARTITIONS = 12;
var PARTITION_ARC = 1 * Math.PI / (PARTITIONS / 2); // The width of each section
var wheelVelocity = 0.1;
var wheelSlowDownVelocity = 0;
var lastWheelRotationTime;
var isSnapping = false;
// Render
function tick() {
// Rotate wheel
var currentTime = (new Date).getTime();
if (lastMouseCoords && isDragging) {
// Reset the velocity for the slowdown
wheelSlowDownVelocity = 0;
// Get the delta rotation since last mouse coordinates
var deltaRadians = mouseCoordsToRotation(mouseCoords.x, mouseCoords.y)
- mouseCoordsToRotation(lastMouseCoords.x, lastMouseCoords.y);
// Set the wheel rotation
wheel.rotation.z += deltaRadians;
// Save the rotation in the history and remove any excessive elements
rotationHistory.push({
time: currentTime,
deltaRad: deltaRadians
});
while (rotationHistory.length > ROTATION_HISTORY_MAX_LENGTH) {
rotationHistory.shift();
}
}
if (isDragging) {
lastMouseCoords = mouseCoords;
}
// Continue rotation of the released wheel
if (!isDragging && !lastMouseCoords && lastWheelRotationTime) {
var delta = currentTime - lastWheelRotationTime;
if (wheelSlowDownVelocity == 0) {
var meanVelocityOverTime = getMeanVelocity(rotationHistory);
wheelSlowDownVelocity = meanVelocityOverTime;
} else {
var currentIsNegative = wheelSlowDownVelocity < 0 ? true : false;
var currentVelocity = wheelSlowDownVelocity;
if (currentIsNegative) {
currentVelocity /= -1;
}
console.log('Current velocity: ', currentVelocity);
console.log('delta: ', delta);
var newVelocity = applyFakeFriction(currentVelocity,
delta);
console.log('New velocity: ', newVelocity);
if (newVelocity < 0) {
wheelSlowDownVelocity = 0;
rotationHistory = [];
} else {
if (currentIsNegative) {
// Revert to old polarity
newVelocity /= -1;
}
wheelSlowDownVelocity = newVelocity;
}
}
wheel.rotation.z += wheelSlowDownVelocity * delta;
}
while (wheel.rotation.z > 2 * Math.PI) {
console.log('Correcting rotation: ', wheel.rotation.z);
wheel.rotation.z -= 2 * Math.PI;
}
while (wheel.rotation.z < - (2 * Math.PI)) {
console.log('Correcting rotation: ', wheel.rotation.z);
wheel.rotation.z += 2 * Math.PI;
}
// Update the history record
lastWheelRotationTime = currentTime;
// Render scene and attach render callback to next animation frame.
renderer.render(scene, camera);
window.requestAnimationFrame(tick);
}
tick();
I have the complete code, minus wheel.png over at https://gist.github.com/joar/5747498.
I have been searching for examples of this behaviour but this far I haven't found any.
Note to editors. Please do not change the tags of this post. tween.js != TweenJS.
I have solved the issue.
'use strict';
function Wheel (element, options) {
var self = this;
// Variable initialization
var WIDTH = options.width;
var HEIGHT = options.height;
if (!options.image) {
throw new Error('Image argument missing');
}
var image = options.image;
var showStats = options.showStats || options.stats;
// Core variables
var stats;
var wheel;
var domElement;
var scene;
var camera;
var renderer;
var rotationHistory;
var input;
var animate;
var run = false;
var ROTATION_HISTORY_MAX_LENGTH = 5;
switch (typeof element) {
case 'string':
domElement = document.querySelector(element);
break;
default:
if ('className' in element) {
domElement = element;
} else {
throw new Error('Invalid element: ', element);
}
}
if (typeof element == 'undefined') {
throw new Error('Invalid element.')
}
/* Initializes the WebGL canvas with the wheel plane */
function setupScene() {
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
scene = new THREE.Scene();
scene.add(camera);
camera.position.z = 300;
// Create renderer
var container = domElement;
renderer = new THREE.WebGLRenderer();
renderer.setSize(WIDTH * 2, HEIGHT * 2);
renderer.setClearColor(0x000000, 0);
// Create objects
var wheelMaterial = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture(image),
depthWrite: false,
alphaTest: 0.5
});
wheelMaterial.overdraw = true;
wheel = new THREE.Mesh(
new THREE.PlaneGeometry(245, 245),
wheelMaterial);
scene.add(wheel);
container.appendChild(renderer.domElement);
}
function setupStats() {
// Init stats
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
document.body.appendChild(stats.domElement);
}
function setup() {
setupScene();
if (showStats) {
setupStats();
}
}
setup();
// The tick function
function update() {
animate.update(); // Process interactions
self.renderer.render(self.scene, self.camera);
if (showStats) {
self.stats.update();
}
if (run) {
window.requestAnimationFrame(update);
}
}
animate = new Animate();
// Start and run the wheel every animationframe
function start() {
self.input = input = new Input(); // Start capturing input
run = true;
update();
}
/**
* Animate the wheel
*/
function Animate() {
var self = this;
self.velocity = 0;
var velocityPositive = 0;
self.friction = 0.001;
self.snapThreshold = 0.03;
self.isSnapping = false;
var lastAnimationTime;
self.tween;
var rotationHistory = [];
var PARTITIONS = 12;
var PARTITION_ARC = 1 * Math.PI / (PARTITIONS / 2); // The width of each section
function update() {
var currentTime = (new Date).getTime();
velocityPositive = self.velocity;
if (velocityPositive < 0) {
velocityPositive /= -1;
}
if (!self.isSnapping
&& !input.isDragging
&& velocityPositive < self.snapThreshold
&& velocityPositive > 0
&& lastAnimationTime) {
rotationHistory = [];
snap();
}
if (input.isDragging) {
self.isSnapping = false;
TWEEN.removeAll();
}
if (!self.isSnapping) {
/**
* If the mouse is dragging the wheel
*/
if (input.lastMouseCoords && input.isDragging && !input.isSnapping) {
// Reset the velocity for the slowdown
self.velocity = 0;
// Get the delta rotation since last mouse coordinates
var deltaRadians = input.mouseCoordsToRadian(
input.mouseCoords.x, input.mouseCoords.y)
- input.mouseCoordsToRadian(
input.lastMouseCoords.x,
input.lastMouseCoords.y);
// Set the wheel rotation
wheel.rotation.z += deltaRadians;
// Save the rotation in the history and remove any excessive elements
rotationHistory.push({
time: currentTime,
deltaRad: deltaRadians
});
while (rotationHistory.length > ROTATION_HISTORY_MAX_LENGTH) {
rotationHistory.shift();
}
}
if (input.isDragging) {
input.lastMouseCoords = input.mouseCoords;
}
// Continue rotation of the released wheel
if (!input.isDragging
&& !input.lastMouseCoords
&& lastAnimationTime
&& !self.isSnapping) {
var delta = currentTime - lastAnimationTime;
if (self.velocity == 0) {
var meanVelocityOverTime = getMeanVelocity(rotationHistory);
self.velocity = meanVelocityOverTime;
} else if (!self.isSnapping && !self.isDragging) {
var currentIsNegative = self.velocity < 0 ? true : false;
var currentVelocity = self.velocity;
if (currentIsNegative) {
currentVelocity /= -1;
}
var newVelocity = applyFakeFriction(currentVelocity,
delta);
if (newVelocity < 0) {
self.velocity = 0;
rotationHistory = [];
} else {
if (currentIsNegative) {
// Revert to old polarity
newVelocity /= -1;
}
self.velocity = newVelocity;
}
}
wheel.rotation.z += self.velocity * delta;
}
if (!self.isSnapping) {
while (wheel.rotation.z > 2 * Math.PI) {
wheel.rotation.z -= 2 * Math.PI;
}
while (wheel.rotation.z < - (2 * Math.PI)) {
wheel.rotation.z += 2 * Math.PI;
}
}
}
// Update snap tween
TWEEN.update();
// Update the history record
lastAnimationTime = currentTime;
}
function applyFakeFriction(velocity, time) {
/*
var currentRotation = wheel.rotation.z;
var nearestBorder = 0;
var nearestBorderDistance = 100;
for (var i = 0; i < PARTITIONS; i++) {
var partition = PARTITION_ARC * i - PARTITION_ARC * PARTITIONS / 2;
var distance = currentRotation - partition;
if (distance < 0) {
distance /= -1;
}
if (distance < nearestBorderDistance) {
console.log('distance is less than nearestBorderDistance')
nearestBorder = partition;
nearestBorderDistance = distance;
if (nearestBorderDistance < 0) {
nearestBorderDistance /= -1;
}
}
}
console.log('nearestBorderDistance: ', nearestBorderDistance);
*/
for (var i = 0; i < time; i++) {
velocity -= self.friction; // * (10000 * wheelSlowDownVelocityPositive); // * (nearestBorderDistance * BORDER_FRICTION);
}
return velocity;
}
function getNearestWedge() {
var currentRotation = wheel.rotation.z;
var nearestBorder = 0;
var nearestBorderDistance = 100;
for (var i = 0; i < PARTITIONS; i++) {
var partition = PARTITION_ARC * i - PARTITION_ARC * PARTITIONS / 2;
var distance = currentRotation - partition;
if (distance < 0) {
distance /= -1;
}
if (distance < nearestBorderDistance) {
console.log('distance is less than nearestBorderDistance')
nearestBorder = partition;
nearestBorderDistance = distance;
if (nearestBorderDistance < 0) {
nearestBorderDistance /= -1;
}
}
}
return {
position: nearestBorder,
distance: nearestBorderDistance
};
}
function snap() {
console.log('Snapping');
if (self.isSnapping) {
console.error('Already snapping, aborting.');
return;
}
self.isSnapping = true;
self.velocity = 0;
var nearest = getNearestWedge();
TWEEN.removeAll();
console.log('nearest: ', nearest.position, nearest.distance)
self.tween = new TWEEN.Tween({r: wheel.rotation.z})
.to({r: nearest.position})
.easing(TWEEN.Easing.Elastic.Out)
.onUpdate(onUpdate)
.onComplete(onComplete)
.start();
function onUpdate() {
//console.log('current: ', this.r, self.velocity);
wheel.rotation.z = this.r;
};
function onComplete() {
self.isSnapping = false;
console.log('Not snapping');;
}
}
function getMeanVelocity(history) {
if (history.length <= 1) {
return 0;
}
var movements = [];
var startTime = history[0].time;
var totalTimeElapsed = 0;
// Start from the second item in deltaRadians
for (var i = 1; i < history.length; i++) {
var item = history[i];
var movement = item.deltaRad;
movements.push(item.deltaRad);
var movementTimeDelta = item.time - startTime - totalTimeElapsed;
if (movementTimeDelta < 0) {
console.error('movementTimeDelta for history entry #' +
i + ' has travelled back in time somehow.');
}
totalTimeElapsed += movementTimeDelta;
}
var sum = movements.reduce(function (a, b) {
return a + b;
});
return sum / totalTimeElapsed;
}
// Internal utilities
function log() {
if (console && _log) {
var args = Array.prototype.slice.call(arguments, 0);
args.unshift('Animate: ')
console.log.apply(console, args);
}
}
// exports
this.update = update;
this.rotationHistory = rotationHistory;
this.PARTITIONS = PARTITIONS;
this.PARTITION_ARC = PARTITION_ARC;
this.snap = snap;
return this;
}
/**
* Handles input to the wheel.
*/
function Input() {
var self = this;
var _log = true;
domElement.addEventListener('mousedown', onDragStart, false);
//domElement.addEventListener('touchstart', onDragStart, false);
domElement.addEventListener('mouseup', onDragEnd, false);
domElement.addEventListener('mouseout', onDragEnd, false);
//domElement.addEventListener('touchend', onDragEnd, false);
domElement.addEventListener('mousemove', onMouseMove, false);
//domElement.addEventListener('touchmove', onMouseMove, false);
function onDragStart(e) {
self.isDragging = true;
log('Drag start');
self.mouseCoords = pageCoordsToCanvasCoords(e);
animate.rotationHistory = [];
}
function onDragEnd(e) {
self.isDragging = false;
self.lastMouseCoords = null;
self.mouseCoords = null;
log('Drag end');
}
function onMouseMove(e) {
e.preventDefault();
self.mouseCoords = pageCoordsToCanvasCoords(e);
}
function pageCoordsToCanvasCoords(e) {
var canvasX, canvasY;
if ('touches' in e && e.touches.length > 0) {
canvasX = e.touches[0].pageX;
canvasY = e.touches[0].pageY;
} else {
canvasX = e.pageX
canvasY = e.pageY
}
canvasX -= e.target.offsetLeft;
canvasY -= e.target.offsetTop;
// console.log(canvasX, canvasY);
return {
x: canvasX,
y: canvasY
};
}
function mouseCoordsToRadian(x, y) {
var origoX = WIDTH / 2.0,
origoY = HEIGHT / 2.0;
x = x - origoX;
y = y - origoY;
var atan = Math.atan2(x, y);
return atan;
}
// exports
this.mouseCoordsToRadian = mouseCoordsToRadian;
function log() {
if (console && _log) {
var args = Array.prototype.slice.call(arguments, 0);
args.unshift('Input: ')
console.log.apply(console, args);
}
}
return this;
}
// Internal utils
function log() {
if (console && _log) {
var args = Array.prototype.slice.call(arguments, 0);
args.unshift('Wheel: ')
console.log.apply(console, args);
}
}
// exports
self.start = start;
self.update = update;
self.scene = scene;
self.camera = camera;
self.wheel = wheel;
self.renderer = renderer;
self.stats = stats;
self.domElement = domElement;
self.input = input;
self.animate = animate;
return self;
}

Excanvas does not work in IE8

Excanvas does not work in IE8!!! I write program to paint by mouse on canvas element. There are fragment of my js-code
window.attachEvent('onload', function () {
function init() {
var w = document.getElementById('signatureImage').getAttribute('width');
var h = document.getElementById('signatureImage').getAttribute('height');
var removeSignatureImage = document.getElementById('signatureImage');
removeSignatureImage.parentNode.removeChild(removeSignatureImage);
var canvasDiv = document.getElementById('canvasDiv');
canvas = document.createElement('canvas');
canvas.setAttribute('width', w);
canvas.setAttribute('height', h);
canvas.setAttribute('style', 'border:1px solid #000000');
canvas.setAttribute('id', 'signatureImage');
canvasDiv.appendChild(canvas);
if (typeof G_vmlCanvasManager != 'undefined') {
canvas = window.G_vmlCanvasManager.initElement(canvas);
}
context = canvas.getContext("2d");
tool = new tool_pencil();
// Attach the mousedown, mousemove and mouseup event listeners.
var trackend = false;
var trackstart = false;
var trackmid = false;
canvas.onselectstart = function () {
canvas.onmousemove(); trackstart = true;
return false; }
canvas.onclick = function () { trackend = true; }
canvas.onmousemove = function () {
var mtarget = document.getElementById('signatureImage');
var x = event.clientX - canvas.offsetLeft;
var y = event.clientY - canvas.offsetTop;
var mtype = 'mousemove';
if (trackstart) {
trackstart = false;
trackmid = true;
mtype = 'mousedown';
}
if (trackend) {
trackmid = false;
mtype = 'mouseup';
}
if (trackend || trackmid || trackstart) {
trackend = false;
ev_canvas({
type: mtype,
_x: x,
_y: y,
target: mtarget
});
}
}
}
function tool_pencil() {
var tool = this;
this.started = false;
function getCoord(ev) {
var x = ev._x;
var y = ev._y;
if (tool.started == true) {
coords += x + "," + y + " ";
}
return [x, y];
}
this.mousedown = function (ev) {
context.beginPath();
context.moveTo(ev._x, ev._y);
tool.started = true;
};
this.mousemove = function (ev) {
if (tool.started) {
context.lineTo(ev._x, ev._y);
context.stroke();
var coord = getCoord(ev);
}
};
this.mouseup = function (ev) {
if (tool.started) {
tool.mousemove(ev);
tool.started = false;
coordList += coords + ";";
document.getElementById('coord').value = coordList;
coords = "";
}
};
}
When there is context.lineTo(ev._x, ev._y);
context.stroke(); - nothing happens! Although the coordinates are passed and canvas painted and initialized

Resources