Related
I'm creating a greeting card app with VueJS3. I want to download 2 images (the background and a star sprite), then showing the image with animated sprites.
If I put onMounted"at the end it doesn't work, I have this error:
[Vue warn]: onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.
at <RouterView>
at <App>
If I put onMounted like this, it doesn't show the MOUNTED log...
<template>
<div class="board">
<canvas
id='carte'
ref='carte'
:width="size.w"
:height="size.h"
max-width="100%"
tabindex='0'
style="border:1px solid #000000;"
></canvas>
</div>
<div id="texteRemplacement" v-if="petit">
<p v-for="p in texte.split('\n')" v-bind:key="p">
{{ p }}
</p>
</div>
</template>
<script>
import {
defineComponent,
onMounted,
ref,
reactive,
nextTick,
toRefs,
watch,
} from 'vue';
import axios from 'axios';
export default defineComponent({
name: 'Visionneuse',
props: ['texteEnvoye', 'taille'],
async setup(props) {
const myCanvas = ref(null);
const carte = ref(null);
const { texteEnvoye, taille } = toRefs(props);
const texte = ref('');
const rapport = ref(0);
const petit = ref((window.innerWidth < 750));
const size = reactive({
w: window.innerWidth * taille.value,
h: window.innerHeight * taille.value,
});
const tailleFond = reactive({
w: 0,
h: 0,
});
let fpsInterval;
let startTime;
let now;
let then;
let elapsed;
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function genererEtoile() {
return ({
taille: getRandomInt(10) + 10,
position: {
x: Math.random(),
y: Math.random(),
},
deviation: {
x: {
valeur: getRandomInt(18) - 9,
sens: 1,
amplitude: 5 + getRandomInt(5),
},
y: {
valeur: getRandomInt(8) - 4,
sens: 1,
amplitude: 5 + getRandomInt(5),
},
},
grossissement: {
valeur: getRandomInt(5) - 3,
sens: 1,
},
});
}
const etoiles = ref(new Array(50).fill(null).map(() => (genererEtoile())));
const date = ref([
{
valeur: {
chiffre: '2',
position: 0,
sens: 1,
},
},
{
valeur: {
chiffre: '0',
position: 3,
sens: -1,
},
},
{
valeur: {
chiffre: '2',
position: -3,
sens: 1,
},
},
{
valeur: {
chiffre: '1',
position: -3,
sens: -1,
},
},
]);
function drawText() {
const fontSize = 0.05 * size.w - 10;
myCanvas.value.font = `${fontSize}px Caviar Dream`;
myCanvas.value.textAlign = 'center';
myCanvas.value.fillStyle = 'white';
myCanvas.value.strokeStyle = 'black';
myCanvas.value.lineWidth = 0.006 * size.w - 10;
const x = (size.w * 9) / 13;
const y = (size.h * 5) / 7;
const lineHeight = fontSize;
const lines = texte.value.split('\n');
for (let i = 0; i < lines.length; i += 1) {
myCanvas.value.fillText(
lines[lines.length - i - 1],
x,
y + ((lines.length - 1) * lineHeight) / 2 - (i * lineHeight),
);
// myCanvas.value.strokeText(
// lines[lines.length - i - 1],
// x,
// y + ((lines.length - 1) * lineHeight) / 2 - (i * lineHeight),
// );
}
}
watch(texteEnvoye, (x) => {
texte.value = x;
// requestAnimationFrame(initCarte);
});
onMounted(() => {
console.log('MOUNTED');
const c = carte.value;
const ctx = c.getContext('2d');
myCanvas.value = ctx;
// requestAnimationFrame(initCarte);
// eslint-disable-next-line
startAnimating(20);
});
async function getImage(chemin) {
await axios.get(`${process.env.VUE_APP_PUBLICPATH}img/${chemin}`, { responseType: 'arraybuffer' })
.then((res) => {
console.log(`data:${res.headers['content-type']};base64,${btoa(String.fromCharCode(...new Uint8Array(res.data)))}`);
return `data:${res.headers['content-type']};base64,${btoa(String.fromCharCode(...new Uint8Array(res.data)))}`;
})
.catch((e) => {
console.log(e);
});
}
const imgFond = await getImage('fond.jpeg');
const imgEtoile = await getImage('etoile.png');
function initCarte() {
console.log('init de la carte');
// changer les chargement
// https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations
requestAnimationFrame(initCarte);
now = Date.now();
elapsed = now - then;
if (elapsed > fpsInterval) {
then = now - (elapsed % fpsInterval);
petit.value = window.innerWidth < 750;
const etoile = new Image();
// etoile.src = `${process.env.VUE_APP_PUBLICPATH}img/etoile.png`;
etoile.src = imgEtoile;
const background = new Image();
// background.src = `${process.env.VUE_APP_PUBLICPATH}img/fond.jpeg`;
background.src = imgFond;
background.onload = () => {
rapport.value = background.naturalWidth / background.naturalHeight;
tailleFond.w = background.naturalWidth;
tailleFond.h = background.naturalHeight;
size.w = window.innerWidth * taille.value;
size.h = size.w / rapport.value;
if (size.w > window.innerWidth) {
size.h = size.w / rapport.value;
} else if (size.h > window.innerHeight) {
size.h = window.innerHeight * taille.value;
size.w = size.h * rapport.value;
}
nextTick(() => {
try {
myCanvas.value.drawImage(background, 0, 0, size.w, size.h);
// on dessine les étoiles
etoiles.value.forEach((e) => {
if (e.grossissement.valeur > 2 && e.grossissement.sens === 1) {
e.grossissement.sens = -1;
}
if (e.grossissement.valeur < -3 && e.grossissement.sens === -1) {
e.grossissement.sens = 1;
}
if (e.deviation.x.valeur > e.deviation.x.amplitude && e.deviation.x.sens === 1) {
e.deviation.x.sens = -1;
}
if (e.deviation.x.valeur < -e.deviation.x.amplitude && e.deviation.x.sens === -1) {
e.deviation.x.sens = 1;
}
if (e.deviation.y.valeur > e.deviation.y.amplitude && e.deviation.y.sens === 1) {
e.deviation.y.sens = -1;
}
if (e.deviation.y.valeur < -e.deviation.y.amplitude && e.deviation.y.sens === -1) {
e.deviation.y.sens = 1;
}
e.deviation.x.valeur += e.deviation.x.sens;
e.deviation.y.valeur += e.deviation.y.sens;
e.grossissement.valeur += e.grossissement.sens;
myCanvas.value.drawImage(etoile,
(e.position.x * size.w) + e.deviation.x.valeur - e.grossissement.valeur / 2,
(e.position.y * size.h) + e.deviation.y.valeur - e.grossissement.valeur / 2,
(e.taille + e.grossissement.valeur) * (size.w / background.naturalWidth),
(e.taille + e.grossissement.valeur) * (size.h / background.naturalHeight));
});
// on dessine 2021
const fontSize = 0.1 * size.w - 10;
myCanvas.value.font = `${fontSize}px Caviar Dream`;
myCanvas.value.textAlign = 'center';
myCanvas.value.fillStyle = 'white';
myCanvas.value.strokeStyle = 'black';
myCanvas.value.lineWidth = 0.006 * size.w - 10;
const x = (size.w * 7) / 12;
const y = (size.h * 4) / 9;
const ecart = 0.07 * size.w - 10;
date.value.forEach((ch, i) => {
if (ch.valeur.position > 6 && ch.valeur.sens === 1) {
ch.valeur.sens = -1;
}
if (ch.valeur.position < -6 && ch.valeur.sens === -1) {
ch.valeur.sens = 1;
}
ch.valeur.position += 1 * ch.valeur.sens;
myCanvas.value.fillText(
ch.valeur.chiffre,
x + (ecart * i),
y + ch.valeur.position,
);
});
} catch (e) {
console.log(`ERREUR DE CHARGEMENT D'IMAGE: ${e}`);
}
if (!petit.value) {
drawText();
}
});
};
}
}
function startAnimating(fps) {
fpsInterval = 1000 / fps;
then = Date.now();
startTime = then;
console.log(startTime);
initCarte();
}
window.addEventListener('resize', initCarte);
return {
myCanvas,
size,
texte,
petit,
carte,
tailleFond,
};
},
});
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#font-face {
font-family: 'Caviar Dream';
src: local('Caviar Dream'), url(~#/assets/fonts/CaviarDreams.ttf) format('truetype');
}
#texteRemplacement {
font-size: 20pt;
font-family: 'Caviar Dream';
}
#myCanvas {
border: 1px solid grey;
}
</style>
What did I not understand in this page?
I am fairly new to Vue so excuse my stupidity!!
Can anyone tell me what I am doing wrong in my code below that is preventing me from getting my 'series_interactions_daily' variable data from inside the mounted() method please? I am console.log()'ing it but nothing shows! I can print 'series_interactions_daily' to screen in the HTML though!
<script>
import * as am4core from "#amcharts/amcharts4/core";
import * as am4charts from "#amcharts/amcharts4/charts";
import am4themes_animated from "#amcharts/amcharts4/themes/animated";
am4core.useTheme(am4themes_animated);
export default {
mounted() {
let chart = am4core.create(this.$refs.chartdiv, am4charts.XYChart);
chart.paddingRight = 20;
let dummydata = [];
let visits = 10;
for (let i = 1; i < 366; i++) {
visits += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
dummydata.push({ date: new Date(2018, 0, i), name: "name" + i, value: visits });
}
chart.data = dummydata;
console.log(this.series_interactions_daily);
let dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.renderer.minWidth = 35;
let series = chart.series.push(new am4charts.LineSeries());
series.dataFields.dateX = "date";
series.dataFields.valueY = "value";
series.tooltipText = "{valueY.value}";
chart.cursor = new am4charts.XYCursor();
let scrollbarX = new am4charts.XYChartScrollbar();
scrollbarX.series.push(series);
chart.scrollbarX = scrollbarX;
this.chart = chart;
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose();
}
},
data() {
return {
campaign_id: this.$route.params.campaign_id,
campaign: [],
dateranges: [],
total_interactions: '',
average_daily_interactions: '',
series_interactions_daily: [],
}
},
methods: {
onChange(event) {
this.$router.push('?range=' + event.target.value);
this.$http.get('https://dev.local/api/portal/campaign/' + this.campaign_id + '?range=' + event.target.value)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
this.total_interactions = data.totalInteractions;
this.average_daily_interactions = data.averagreDailyInteractions;
this.series_interactions_daily = data.interactions_per_day.stats.interaction.daily;
});
}
},
created() {
this.$http.get('https://dev.local/api/portal/campaign/' + this.campaign_id + '?' + this.axiosParams)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
this.total_interactions = data.totalInteractions;
this.average_daily_interactions = data.averagreDailyInteractions;
this.series_interactions_daily = data.interactions_per_day.stats.interaction.daily;
});
},
computed: {
axiosParams() {
const params = new URLSearchParams();
if(this.$route.query.range) params.append('range', this.$route.query.range);
return params;
}
},
filters: {
},
directives: {
},
}
</script>
EDIT
OK, so I have create a method to fetchData() from mounted(){} - however I am still not getting my 'series_interactions_daily' variable data!
<script>
import * as am4core from "#amcharts/amcharts4/core";
import * as am4charts from "#amcharts/amcharts4/charts";
import am4themes_animated from "#amcharts/amcharts4/themes/animated";
am4core.useTheme(am4themes_animated);
export default {
mounted() {
this.fetchData();
let chart = am4core.create(this.$refs.chartdiv, am4charts.XYChart);
chart.paddingRight = 20;
let dummydata = [];
let visits = 10;
for (let i = 1; i < 366; i++) {
visits += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
dummydata.push({ date: new Date(2018, 0, i), name: "name" + i, value: visits });
}
chart.data = dummydata;
console.log(this.series_interactions_daily);
let dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.renderer.minWidth = 35;
let series = chart.series.push(new am4charts.LineSeries());
series.dataFields.dateX = "date";
series.dataFields.valueY = "value";
series.tooltipText = "{valueY.value}";
chart.cursor = new am4charts.XYCursor();
let scrollbarX = new am4charts.XYChartScrollbar();
scrollbarX.series.push(series);
chart.scrollbarX = scrollbarX;
this.chart = chart;
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose();
}
},
data() {
return {
campaign_id: this.$route.params.campaign_id,
campaign: [],
dateranges: [],
total_interactions: '',
average_daily_interactions: '',
series_interactions_daily: [],
}
},
methods: {
fetchData() {
this.$http.get('https://dev.local/api/portal/campaign/' + this.campaign_id + '?' + this.axiosParams)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
this.total_interactions = data.totalInteractions;
this.average_daily_interactions = data.averagreDailyInteractions;
this.series_interactions_daily = data.interactions_per_day.stats.interaction.daily;
});
},
onChange(event) {
this.$router.push('?range=' + event.target.value);
this.$http.get('https://connie.laravel/api/portal/campaign/' + this.campaign_id + '?range=' + event.target.value)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
this.total_interactions = data.totalInteractions;
this.average_daily_interactions = data.averagreDailyInteractions;
this.series_interactions_daily = data.interactions_per_day.stats.interaction.daily;
});
}
},
created() {
},
computed: {
axiosParams() {
const params = new URLSearchParams();
if(this.$route.query.range) params.append('range', this.$route.query.range);
return params;
}
},
filters: {
},
directives: {
},
}
</script>
Any help appreciated.
Thanks,
K...
In fetchData, return the promise returned by the async $http call:
fetchData() {
return this.$http.get(...)
...
}
Now you can register a callback on that promise in mounted:
mounted() {
this.fetchData().then(result => {
...
});
}
Or just await it with async/await:
async mounted() {
await this.fetchData();
...
// Now everything will be ready
}
As #tao mentioned in comments, note that the await would delay any code that comes after it. If you don't have anything else to do in the hook anyway that's no problem but it's something to understand.
I am trying to run a sketch on the canvas element in Nuxt JS but I am having some issues (I am completely new to Vue JS).
While I have no errors in VS Code, there is an error in the browser console:
client.js?06a0:84 TypeError: Cannot read property 'width' of undefined
at Blob.get (Blob_Point.js?a5e5:126)
at Blob.render (Blob_Point.js?a5e5:29)
below is the code for my Vue file:
<template>
<div>
<h1 class="pa-5 text-center">Blob</h1>
<canvas id="myCanvas" width="600" height="400"></canvas>
<!--<v-btn #click="drawRect">Clear</v-btn> -->
</div>
</template>
<script>
import Blob from "../assets/content/Blob_Point"
//import { Point } from "../assets/content/Blob_Point"
//import Point from "../assets/content/Blob_Point"
let oldMousePoint = { x: 0, y: 0 }
let blob = new Blob()
//let point = new Point()
let hover = false
let canvas
export default {
data() {
return {
canvas: null,
x: 0,
y: 0,
isDrawing: false,
rectWidth: 200,
//hover: false,
//oldMousePoint: { x: 0, y: 0 },
}
},
mounted() {
let canvas = document.getElementById("myCanvas")
this.canvas = canvas.getContext("2d")
},
created() {
new Blob("#C09EFF")
blob.canvas = canvas
blob.init()
blob.render()
},
methods: {
/* showCoordinates(e) {
this.x = e.offsetX
this.y = e.offsetY
},
drawLine(x1, y1, x2, y2) {
let ctx = this.vueCanvas
ctx.beginPath()
ctx.strokeStyle = "black"
ctx.lineWidth = 1
ctx.moveTo(x1, y1)
ctx.lineTo(x2, y2)
ctx.stroke()
ctx.closePath()
},
draw(e) {
if (this.isDrawing) {
this.drawLine(this.x, this.y, e.offsetX, e.offsetY)
this.x = e.offsetX
this.y = e.offsetY
}
},
beginDrawing(e) {
this.x = e.offsetX
this.y = e.offsetY
this.isDrawing = true
},
stopDrawing(e) {
if (this.isDrawing) {
this.drawLine(this.x, this.y, e.offsetX, e.offsetY)
this.x = 0
this.y = 0
this.isDrawing = false
//windowWidth = 0,
}
}, */
resize() {
document.getElementById("myCanvas").width = window.innerWidth
document.getElementById("myCanvas").height = window.innerHeight
},
/*drawRect() {
this.vueCanvas.clearRect(0, 0, 600, 800)
//this.vueCanvas.beginPath()
//this.vueCanvas.rect(20, 20, this.rectWidth, 100)
//this.vueCanvas.stroke()
},*/
mouseMove(e) {
let pos = blob.center
let diff = { x: e.clientX - pos.x, y: e.clientY - pos.y }
let dist = Math.sqrt(diff.x * diff.x + diff.y * diff.y)
let angle = null
blob.mousePos = {
x: pos.x - e.clientX,
y: pos.y - e.clientY,
}
if (dist < blob.radius && hover === false) {
let vector = {
x: e.clientX - pos.x,
y: e.clientY - pos.y,
}
angle = Math.atan2(vector.y, vector.x)
hover = true
// blob.color = '#77FF00';
} else if (dist > blob.radius && hover === true) {
let vector = {
x: e.clientX - pos.x,
y: e.clientY - pos.y,
}
angle = Math.atan2(vector.y, vector.x)
hover = false
blob.color = null
}
if (typeof angle == "number") {
let nearestPoint = null
let distanceFromPoint = 100
blob.points.forEach((point) => {
if (Math.abs(angle - point.azimuth) < distanceFromPoint) {
// console.log(point.azimuth, angle, distanceFromPoint);
nearestPoint = point
distanceFromPoint = Math.abs(angle - point.azimuth)
}
})
if (nearestPoint) {
let strength = {
x: oldMousePoint.x - e.clientX,
y: oldMousePoint.y - e.clientY,
}
strength =
Math.sqrt(strength.x * strength.x + strength.y * strength.y) * 1
if (strength > 100) strength = 100
nearestPoint.acceleration = (strength / 100) * (hover ? -1 : 1)
}
}
oldMousePoint.x = e.clientX
oldMousePoint.y = e.clientY
},
},
}
</script>
<style scoped>
#myCanvas {
border: 1px solid grey;
}
</style>
and below is the Blob_Point JS file that I am importing:
/* eslint-disable */
// Blob Class
export default class Blob {
// setup function
constructor(color) {
//the objects setup
// 'this' is a reference to the current class
this.points = []
this._color = color
}
init() {
for (let i = 0; i < this.numPoints; i++) {
let point = new Point(this.divisional * (i + 1), this)
//point.acceleration = -1 + Math.random() * 2;
this.push(point)
}
}
render() {
let canvas = this.canvas
let ctx = this.ctx
let position = this.position
let pointsArray = this.points
let radius = this.radius
let points = this.numPoints
let divisional = this.divisional
let center = this.center
ctx.clearRect(0, 0, canvas.width, canvas.height)
pointsArray[0].solveWith(pointsArray[points - 1], pointsArray[1])
let p0 = pointsArray[points - 1].position
let p1 = pointsArray[0].position
let _p2 = p1
// this is the draw
ctx.beginPath()
ctx.moveTo(center.x, center.y)
ctx.moveTo((p0.x + p1.x) / 2, (p0.y + p1.y) / 2)
for (let i = 1; i < points; i++) {
pointsArray[i].solveWith(
pointsArray[i - 1],
pointsArray[i + 1] || pointsArray[0]
)
let p2 = pointsArray[i].position
var xc = (p1.x + p2.x) / 2
var yc = (p1.y + p2.y) / 2
ctx.quadraticCurveTo(p1.x, p1.y, xc, yc)
// ctx.lineTo(p2.x, p2.y);
//ctx.fillStyle = this.color;
// ctx.fillRect(p1.x-2.5, p1.y-2.5, 5, 5);
p1 = p2
}
var xc = (p1.x + _p2.x) / 2
var yc = (p1.y + _p2.y) / 2
ctx.quadraticCurveTo(p1.x, p1.y, xc, yc)
ctx.lineTo(_p2.x, _p2.y)
ctx.closePath()
ctx.fillStyle = this.color
ctx.fill()
ctx.strokeStyle = this.color
// ctx.stroke();
/*
ctx.fillStyle = '#000000';
if(this.mousePos) {
let angle = Math.atan2(this.mousePos.y, this.mousePos.x) + Math.PI;
}*/
//requestAnimationFrame(this.render.bind(this))
}
push(item) {
if (item instanceof Point) {
this.points.push(item)
}
}
set color(value) {
this._color = value
}
get color() {
return this._color
}
set canvas(value) {
if (
value instanceof HTMLElement &&
value.tagName.toLowerCase() === "canvas"
) {
this._canvas = canvas
this.ctx = this._canvas.getContext("2d")
}
}
get canvas() {
return this._canvas
}
set numPoints(value) {
if (value > 10) {
this._points = value
}
}
get numPoints() {
return this._points || 32
}
set radius(value) {
if (value > 0) {
this._radius = value
}
}
get radius() {
return this._radius || 300
}
set position(value) {
if (typeof value == "object" && value.x && value.y) {
this._position = value
}
}
get position() {
return this._position || { x: 0.5, y: 0.5 }
}
get divisional() {
return (Math.PI * 2) / this.numPoints
}
get center() {
return {
x: this.canvas.width * this.position.x,
y: this.canvas.height * this.position.y,
}
}
set running(value) {
this._running = value === true
}
get running() {
return this.running !== false
}
}
// Point Class
export class Point {
constructor(azimuth, parent) {
this.parent = parent
this.azimuth = Math.PI - azimuth
this._components = {
x: Math.cos(this.azimuth),
y: Math.sin(this.azimuth),
}
this.acceleration = -0.3 + Math.random() * 0.6
}
solveWith(leftPoint, rightPoint) {
this.acceleration =
(-0.3 * this.radialEffect +
(leftPoint.radialEffect - this.radialEffect) +
(rightPoint.radialEffect - this.radialEffect)) *
this.elasticity -
this.speed * this.friction
}
set acceleration(value) {
if (typeof value == "number") {
this._acceleration = value
this.speed += this._acceleration * 2
}
}
get acceleration() {
return this._acceleration || 0
}
set speed(value) {
if (typeof value == "number") {
this._speed = value
this.radialEffect += this._speed * 3
}
}
get speed() {
return this._speed || 0
}
set radialEffect(value) {
if (typeof value == "number") {
this._radialEffect = value
}
}
get radialEffect() {
return this._radialEffect || 0
}
get position() {
return {
x:
this.parent.center.x +
this.components.x * (this.parent.radius + this.radialEffect),
y:
this.parent.center.y +
this.components.y * (this.parent.radius + this.radialEffect),
}
}
get components() {
return this._components
}
set elasticity(value) {
if (typeof value === "number") {
this._elasticity = value
}
}
get elasticity() {
return this._elasticity || 0.001
}
set friction(value) {
if (typeof value === "number") {
this._friction = value
}
}
get friction() {
return this._friction || 0.0085
}
}
Any ideas on the why lines 29 and 127 of the Blob_Point.js file are throwing errors?
I attached 2 screens of the developer tools in chrome to show the errors along with the JS its pointing to.
Thanks for any help!
The main issue I can identify is here. I have added comments to the code.
Blob_Point.js
render() {
let canvas = this.canvas // this references the Blob Class (not the Vue instance) and there is no initialised property such as canvas in the class
}
To fix this main issue, you can do something like
Blob_Point.js
export default class Blob {
constructor(color, canvas) {
//the objects setup
// 'this' is a reference to the current class
this.points = []
this._color = color;
this.canvas = canvas
}
}
And then in the .vue file
.Vue
mounted() {
let canvas = document.getElementById("myCanvas");
this.canvas = canvas.getContext("2d");
blob = new Blob("#C09EFF", this.canvas); // now canvas in the Blob Class constructor will refer to the vue instance canvas
blob.canvas = canvas;
blob.init();
blob.render();
},
I have identified another issue here.
set canvas(value) {
if (
value instanceof HTMLElement &&
value.tagName.toLowerCase() === "canvas"
) {
this._canvas = canvas // there is no initialised constructor property as _canvas
this.ctx = this._canvas.getContext("2d") // there is no initialised constructor property such as _canvas
}
}
get canvas() {
return this._canvas // there is no initialised constructor property as _canvas
}
PDF export for custom widget doesn't work from icCube reporting. Server engine version is 5.0.3 and reporting 5.0.3 (6:2163).
We didn't see any error message within the logs, the process remains stuck into the Monitoring -> Active Requests tab.
The report included is based on icCube demo Sales schema.
Widget code:
FishboneChart.js:
test = {
module : {}
}
test.module.FishboneChart = (function (_super) {
__extends(FishboneChart, _super);
function FishboneChart(container, options) {
_super.call(this, container, options);
this.options = options;
this.container = container;
var chartContainer = $("<div class='ic3w-fishbone-chart'></div>");
var contentContainer = $("<div class='ic3w-fishbone-chart-content'></div>");
var ct = $(this.container);
ct.append(chartContainer);
chartContainer.append(contentContainer);
};
$.extend(FishboneChart.prototype, {
buildInHtml : function (gviTable) {
var chartData = buildChartDataJson(gviTable);
renderFishboneChart(chartData);
}
});
return FishboneChart;
})(viz.GviChartBase);
test.module.FishboneChartAdapterFactory = (function (_super) {
__extends(FishboneChartAdapterFactory, _super);
function FishboneChartAdapterFactory() {
_super.call(this, "test.module.FishboneChartAdapter");
}
FishboneChartAdapterFactory.prototype.getId = function () {
return 'testFishboneChart';
};
FishboneChartAdapterFactory.prototype.getMenuGroupName = function () {
return "testMenu"
};
FishboneChartAdapterFactory.prototype.getTag = function () {
return "testFishboneChart"
};
return FishboneChartAdapterFactory;
})(ic3.WidgetAdapterFactory);
test.module.FishboneChartAdapter = (function (_super) {
__extends(FishboneChartAdapter, _super);
function FishboneChartAdapter(context) {
_super.call(this, context);
this.classID = "test.module.FishboneChartAdapter";
}
FishboneChartAdapter.prototype.reportTypeName = function () {
return 'Test fishbone-chart';
};
FishboneChartAdapter.prototype.getWidgetGroupName = function() {
return 'chart';
};
FishboneChartAdapter.prototype.getNameForCssClass = function() {
return 'test-chart';
};
FishboneChartAdapter.prototype.gutsMeta = function () {
return [
{
name: 'title',
type: 'text'
}
]
};
FishboneChartAdapter.prototype.createWidget = function (options, container) {
return new test.module.FishboneChart(container, options);
};
return FishboneChartAdapter;
})(ic3.ChartAdapter);
var initializeFishbone = function(d3){
"use strict";
d3.fishbone = function(){
var _margin = 50,
_marginRoot = 20,
_marginTail = 100,
_marginTop = 30,
_nodes,
_links,
_node,
_link,
_root,
_arrowId = function(d){ return "arrow"; },
_children = function(d){ return d.children; },
_label = function(d){ return d.name; },
_perNodeTick = function(d){},
_linkScale = d3.scale.log()
.domain([1, 5])
.range([20, 10]),
_chartSize = getChartSize(),
_force = d3.layout.force()
.gravity(0)
.size([
_chartSize.width,
_chartSize.height
])
.linkDistance(_linkDistance)
.chargeDistance([10])
.on("tick", _tick);
var fb1 = function($){
_links = [];
_nodes = [];
_build_nodes($.datum());
_force
.nodes(_nodes)
.links(_links);
_link = $.selectAll(".link")
.data(_links);
_link.enter().append("line");
_link
.attr({
"class": function(d){ return "link link-" + d.depth; },
"marker-end": function(d){
return d.arrow ? "url(#" + _arrowId(d) + ")" : null;
}
});
_link.exit().remove();
_node = $.selectAll(".node").data(_nodes);
_node.enter().append("g")
.attr({
"class": function(d){ return "node" + (d.root ? " root" : ""); }
})
.append("text");
_node.select("text")
.attr({
"class": function(d){ return "label-" + d.depth; },
"text-anchor": function(d){
return !d.depth ? "start" : d.horizontal ? "end" : "middle";
},
dy: function(d){
return d.horizontal ? ".35em" : d.region === 1 ? "1em" : "-.2em";
}
})
.text(_label);
_node.exit().remove();
_node
.call(_force.drag)
.on("mousedown", function(){ d3.event.stopPropagation(); });
_root = $.select(".root").node();
};
function _arrow($){
var defs = $.selectAll("defs").data([1]);
defs.enter().append("defs");
defs.selectAll("marker#" + _arrowId())
.data([1])
.enter().append("marker")
.attr({
id: _arrowId(),
viewBox: "0 -5 10 10",
refX: 10,
refY: 0,
markerWidth: 10,
markerHeight: 10,
orient: "auto"
})
.append("path")
.attr({d: "M0,-5L10,0L0,5"});
}
function _build_nodes(node){
_nodes.push(node);
var cx = 0;
var between = [node, node.connector],
nodeLinks = [{
source: node,
target: node.connector,
arrow: true,
depth: node.depth || 0
}],
prev,
childLinkCount;
if(!node.parent){
_nodes.push(prev = {tail: true});
between = [prev, node];
nodeLinks[0].source = prev;
nodeLinks[0].target = node;
node.horizontal = true;
node.vertical = false;
node.depth = 0;
node.root = true;
node.totalLinks = []
}else{
node.connector.maxChildIdx = 0;
node.connector.totalLinks = [];
}
node.linkCount = 1;
(_children(node) || []).forEach(function(child, idx){
child.parent = node;
child.depth = (node.depth || 0) + 1;
child.childIdx = idx;
child.region = node.region ? node.region : (idx & 1 ? 1 : -1);
child.horizontal = !node.horizontal;
child.vertical = !node.vertical;
if(node.root && prev && !prev.tail){
_nodes.push(child.connector = {
between: between,
childIdx: prev.childIdx
})
prev = null;
}else{
_nodes.push(prev = child.connector = {between: between, childIdx: cx++});
}
nodeLinks.push({
source: child,
target: child.connector,
depth: child.depth
});
childLinkCount = _build_nodes(child);
node.linkCount += childLinkCount;
between[1].totalLinks.push(childLinkCount);
});
between[1].maxChildIdx = cx;
Array.prototype.unshift.apply(_links, nodeLinks);
return node.linkCount;
}
function _linePosition($){
$.attr({
x1: function(d){ return d.source.x; },
y1: function(d){ return d.source.y; },
x2: function(d){ return d.target.x; },
y2: function(d){ return d.target.y; }
})
}
function _nodePosition($){
$.attr("transform", function(d){
return "translate(" + d.x + "," + d.y + ")";
})
}
function _linkDistance(d){
return (d.target.maxChildIdx + 1) * _linkScale(d.depth === 0 ? 1 : d.depth);
}
function _tick(e){
var k = 6 * e.alpha,
size = _force.size(),
width = size[0],
height = size[1],
a,
b;
_nodes.forEach(function(d){
if(d.root){ d.x = width - (_marginRoot + _root.getBBox().width); }
if(d.tail){ d.x = _marginTail; d.y = height / 2; }
if(d.depth === 1){
d.y = d.region === -1 ? _marginTop : (height - _marginTop);
d.x -= 10 * k;
}
if(d.vertical){ d.y += k * d.region; }
if(d.depth){ d.x -= k; }
if(d.between){
a = d.between[0];
b = d.between[1];
d.x = b.x - (1 + d.childIdx) * (b.x - a.x) / (b.maxChildIdx + 1);
d.y = b.y - (1 + d.childIdx) * (b.y - a.y) / (b.maxChildIdx + 1);
}
_perNodeTick(d);
});
_node.call(_nodePosition);
_link.call(_linePosition);
}
fb1.links = function(){ return _links; };
fb1.nodes = function(){ return _nodes; };
fb1.force = function(){ return _force; };
fb1.defaultArrow = _arrow;
fb1.margin = function(_){
if(!arguments.length){ return _margin; }
_margin = _;
return my;
};
fb1.children = function(_){
if(!arguments.length){ return _children; }
_children = _;
return my;
};
fb1.label = function(_){
if(!arguments.length){ return _label; }
_label = _;
return my;
};
fb1.perNodeTick = function(_){
if(!arguments.length){ return _perNodeTick; }
_perNodeTick = _;
return my;
};
return fb1;
};
};
var getChartSize = function() {
var chart = $('.ic3w-fishbone-chart');
return {
width : chart.width() || 0,
height : chart.height() || 0
};
};
var renderFishboneChart = function(chartData) {
if (!d3.fishbone) {
initializeFishbone(d3);
}
d3.selectAll('.ic3w-fishbone-chart-content svg').remove();
var fishbone = d3.fishbone();
d3.select('.ic3w-fishbone-chart-content')
.append("svg")
.attr(getChartSize())
.datum(chartData)
.call(fishbone.defaultArrow)
.call(fishbone);
fishbone.force().start();
};
var buildChartDataJson = function(gviTable) {
var rowCount = gviTable.getRowCount();
var colCount = gviTable.getColumnCount();
var currentLevel, levelDepthStr;
var currentBranch = [];
for (var i = 0; i < colCount; i++) {
levelDepthStr = gviTable.getPropertyForColumnHeader(i, 0, "a_ld");
currentLevel = parseInt(levelDepthStr);
if (!isNaN(currentLevel)) {
var currentEl = {
name: gviTable.getColumnLabel(i),
children: []
};
if (currentLevel <= currentBranch.length - 1) {
removeElements(currentBranch, currentLevel);
}
currentBranch[currentLevel] = currentEl;
if (currentLevel != 0) {
var parent = currentBranch[currentLevel - 1];
parent.children.push(currentEl);
}
}
}
return currentBranch.length > 0 ? currentBranch[0] : {};
};
var removeElements = function(array, targetLength) {
if (array) {
while (array.length > targetLength) {
array.pop();
}
}
};
FishBonePlugin.js:
ic3globals.plugins.push(
{
name: "Fishbone Chart",
loadCSS: function (options) {
var root = options.rootLocal + "plugins/";
ic3css(root + 'Fishbone.css');
},
loadJS: function (options) {
var root = options.rootLocal + "plugins/";
var deps = ['FishboneChart'];
$script(root + 'FishboneChart.js', deps[0]);
$script.ready(deps, function () { /* asynchronous callback */
options.callback && options.callback();
});
},
registerWidgetFactories: function (manager) {
manager.addWidgetFactory(new test.module.FishboneChartAdapterFactory());
},
registerBabylonTags: function (babylon) {
}
});
Fishbone.css:
.ic3w-fishbone-chart {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.ic3w-fishbone-chart-content *{
font-family: "Gill Sans", "Gill Sans MT";
}
.ic3w-fishbone-chart-content .label-0 {
font-size: 2em;
}
.ic3w-fishbone-chart-content .label-1 {
font-size: 1.5em;
fill: #111;
}
.ic3w-fishbone-chart-content .label-2 {
font-size: 1em;
fill: #444;
}
.ic3w-fishbone-chart-content .label-3 {
font-size: .9em;
fill: #888;
}
.ic3w-fishbone-chart-content .label-4 {
font-size: .8em;
fill: #aaa;
}
.ic3w-fishbone-chart-content .link-0 {
stroke: #000;
stroke-width: 2px;
}
.ic3w-fishbone-chart-content .link-1 {
stroke: #333;
stroke-width: 1px;
}
.ic3w-fishbone-chart-content .link-2, .ic3w-fishbone-chart-content .link-3, .ic3w-fishbone-chart-content .link-4 {
stroke: #666;
stroke-width: .5px;
}
Report code:
{"classID":"ic3.ReportGuts","guts_":{"ic3Version":13,"schemaName":"Sales","cubeName":"Sales","layout":{"classID":"ic3.FixedLayout","guts_":{"ic3Version":13,"grid":10,"boxes":[{"classID":"ic3.FixedLayoutBox","guts_":{"ic3Version":13,"header":"widget-0 ( widgetGroup.testMenu/testFishboneChart )","behaviour":"Fixed Box","noPrint":false,"position":{"top":0,"left":170,"width":1380,"height":820},"widgetAdapterUid":"w1","zIndex":2001,"ic3_uid":"ic3-164"}}]}},"widgetMgr":{"classID":"ic3.WidgetAdapterContainerMgr","guts_":{"ic3Version":13,"items":[{"classID":"test.module.FishboneChartAdapter","guts_":{"ic3Version":13,"navigationGuts":{"classID":"ic3.NavigationStrategy","guts_":{"ic3Version":13,"menuVisibility":{"back":true,"axisXChange":"All","axisYChange":"All","filter":"All","reset":true,"widget":true,"others":"All"},"maxAxisMemberCount":25}},"ic3_name":"widget-0","ic3_uid":"w1","ic3_eventMapper":{"classID":"ic3.EventWidgetMapper","guts_":{"__ic3_widgetEventsDescription":{}}},"ic3_mdxBuilderUid":"m1","__ic3_widgetTypeName":"widgetGroup.testMenu/testFishboneChart"}}]}},"constantMgr":{"classID":"ic3.ConstantsMgr","guts_":{"ic3Version":13}},"cssMgr":{"classID":"ic3.CssMgr","guts_":{}},"javascriptMgr":{"classID":"ic3.ReportJavascriptMgr","guts_":{"ic3Version":13,"js":"/** \n * A function called each time an event is generated. \n * \n * #param context the same object is passed between consumeEvent calls. \n * Can be used to store information. \n * { \n * $report : jQuery context of the report container \n * fireEvent : a function( name, value ) triggering an event \n * } \n * \n * #param event the event information \n * \n { \n * name : as specified in the 'Events' tab \n * value : (optional) actual event value \n * type : (optional) e.g., ic3selection \n * } \n * \n * Check the 'Report Event Names' menu for the list of available events. \n */ \n \nfunction consumeEvent( context, event ) { \n if (event.name == 'ic3-report-init') { \n \n ic3globals.plugins.push(\n {\n name: \"Fishbone Chart\",\n\n loadCSS: function (options) {\n },\n\n loadJS: function (options) {\n },\n\n registerWidgetFactories: function (manager) {\n console.log('korte1');\n manager.addWidgetFactory(new test.module.FishboneChartAdapterFactory());\n },\n\n registerBabylonTags: function (babylon) {\n }\n });\n } \n}"}},"calcMeasureMgr":{"classID":"ic3.CalcMeasureMgr","guts_":{"measures":[]}},"mdxQueriesMgr":{"classID":"ic3.MdxQueriesContainerMgr","guts_":{"mdxQueries":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[{"classID":"ic3.QueryBuilderWidget","guts_":{"mdxWizard":{"classID":"ic3.QueryBuilderWizardForm","guts_":{"rows":[],"cols":[{"classID":"ic3.QueryBuilderHierarchyForm","guts_":{"hierarchy":{"name":"Geography","uniqueName":"[Customers].[Geography]"},"type":"membersOf","membersOf":"all members"}}],"filters":[],"nonEmptyOnRows":false,"nonEmptyOnColumns":false}},"mdxFlat":{"classID":"ic3.QueryBuilderFlatMdxForm","guts_":{"useMdxStatement":false}},"ic3_name":"mdx Query-0","ic3_uid":"m1"}}]}},"mdxFilter":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[]}},"actionBuilders":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[]}}}}}}
Thanks,
Balint Ruzsa
Widget adapter code needs two extra functions(workaround for internal bug):
FishboneChartAdapter.prototype.hasNavigation = function()
{
return false;
};
FishboneChartAdapter.prototype.getNavigationMenuItems = function()
{
return [];
};
isRendered method should be modified, because layout for chart computed dynamicaly. I suggest to use simple setTimeout to with heuristic timeout, but you may implement custom check.
FishboneChart:
test.module.FishboneChart = (function (_super) {
__extends(FishboneChart, _super);
function FishboneChart(container, options) {
_super.call(this, container, options);
this.options = options;
this.container = container;
this.rendered = false;
var chartContainer = $("<div class='ic3w-fishbone-chart'></div>");
var contentContainer = $("<div class='ic3w-fishbone-chart-content'></div>");
var ct = $(this.container);
ct.append(chartContainer);
chartContainer.append(contentContainer);
};
$.extend(FishboneChart.prototype, {
buildInHtml: function (gviTable) {
var chartData = buildChartDataJson(gviTable);
renderFishboneChart(chartData);
var self = this;
// wait until layout is stabilized
setTimeout(function(){self.rendered = true;}, 10000);
},
isRendered: function () {
return this.rendered;
}
});
return FishboneChart;
})(viz.GviChartBase);
As I am new to KineticJs so, I have tried implementing the functionality using Kinectic js for drawing the multiple image on different- different x and y. Now I wanted to resize the stage layer or canvas. I have done that by using the code given below
window.onresize = function (event) {
stage.setWidth(($('#tab' + tabId).innerWidth() / 100) * 80);
var _images = layer.getChildren();
for (var i = 0; i < _images.length; i++) {
if (typeof _images[i].getId() != 'undefined') {
//alert(stage.getScale().x);
_images[i].setX(_images[i].getX() * stage.getScale().x);
layer.draw();
}
}
}
but now the problem is the are being defined and now if browser resize than stage is resized but the images on the prev x and y are fixed . I would like to keep them fixed on the position on resizing of stage layer or canvas.Here are the link of the image before resize and after resizing.beforeresize and afterResize .
Here is my entire code given below:-
$("#tabs li").each(function () {
$(this).live("click", function () {
clearInterval(_timer);
var tabname = $(this).find("a").attr('name');
tabname = $.trim(tabname.replace("#tab", ""));
var tabId = $(this).find("a").attr('href');
tabId = $.trim(tabId.replace("#", ""));
$.ajax({
url: "/Home/GetTabsDetail",
dataType: 'json',
type: 'GET',
data: { tabId: tabId },
cache: false,
success: function (data) {
var bayStatus = [];
var i = 0;
var image_array = [];
var BayExist = false;
var BayCondition;
var imgSrc;
var CanvasBacgroundImage;
var _X;
var _bayNumber;
var _Y;
var _ZoneName;
$(data).each(function (i, val) {
i = i + 1;
if (!BayExist) {
bayStatus = val.BayStatus;
CanvasBacgroundImage = val.TabImageLocation;
BayExist = true;
}
$.each(val, function (k, v) {
if (k == "BayNumber") {
BayCondition = bayStatus[v];
_bayNumber = v;
if (BayCondition == "O")
imgSrc = "../../images/Parking/OccupiedCar.gif"
else if (BayCondition == "N")
imgSrc = "../../images/Parking/OpenCar.gif";
}
if (k == "BayX")
_X = v;
if (k == "BayY")
_Y = v;
if (k == "ZoneName")
_ZoneName = v;
});
image_array.push({ img: imgSrc, xAxis: _X, yAxis: _Y, toolTip: _bayNumber, ZoneName: _ZoneName });
});
var imageUrl = CanvasBacgroundImage;
if ($('#tab' + tabId).length) {
// $('#tab' + tabId).css('background-image', 'url("../../images/Parking/' + imageUrl + '")');
var stage = new Kinetic.Stage({
container: 'tab' + tabId,
width: ($('#tab' + tabId).innerWidth() / 100) * 80, // 80% width of the window.
height: 308
});
window.onresize = function (event) {
stage.setWidth(($('#tab' + tabId).innerWidth() / 100) * 80);
}
$('#tab' + tabId).find('.kineticjs-content').css({ 'background-image': 'url("../../images/Parking/' + imageUrl + '")', 'background-repeat': ' no-repeat', 'background-size': '100% 100%' });
var layer = new Kinetic.Layer();
var planetOverlay;
function writeMessage(message, _x, _y) {
text.setX(_x + 20);
text.setY(_y + 1);
text.setText(message);
layer.draw();
}
var text = new Kinetic.Text({
fontFamily: 'Arial',
fontSize: 14,
text: '',
fill: '#000',
width: 200,
height: 60,
align: 'center'
});
var opentooltip = new Opentip(
"div#tab" + tabId, //target element
"dummy", // will be replaced
"", // title
{
showOn: null // I'll manually manage the showOn effect
});
Opentip.styles.win = {
borderColor: "black",
shadow: false,
background: "#EAEAEA"
};
Opentip.defaultStyle = "win";
// _timer = setInterval(function () {
for (i = 0; i < image_array.length; i++) {
img = new Image();
img.src = image_array[i].img;
planetOverlay = new Kinetic.Image({
x: image_array[i].xAxis,
y: image_array[i].yAxis,
image: img,
height: 18,
width: 18,
id: image_array[i].toolTip,
name: image_array[i].ZoneName
});
planetOverlay.on('mouseover', function () {
opentooltip.setContent("<span style='color:#87898C;'><b>Bay:</b></span> <span style='color:#25A0D3;'>" + this.getId() + "</span><br> <span style='color:#87898C;'><b>Zone:</b></span><span style='color:#25A0D3;'>" + this.getName() + "</span>");
//writeMessage("Bay: " + this.getId() + " , Zone: " + this.getName(), this.getX(), this.getY());//other way of showing tooltip
opentooltip.show();
$("#opentip-1").offset({ left: this.getX(), top: this.getY() });
});
planetOverlay.on('mouseout', function () {
opentooltip.hide();
// writeMessage('');
});
planetOverlay.createImageHitRegion(function () {
layer.draw();
});
layer.add(planetOverlay);
layer.add(text);
stage.add(layer);
}
// clearInterval(_timer);
//$("#tab3 .kineticjs-content").find("canvas").css('background-image', 'url("' + imageUrl + '")');
// },
// 500)
}
}
,
error: function (result) {
alert('error');
}
});
});
});
I want to keep the icons on the position where they were before resizing. I have tried but could not get the right solution to get this done.
How can How can I update x,y position for the images . Any suggestions would be appreciated.
Thanks is advance.
In window.resize, you're changing the stage width by a scaling factor.
Save that scaling factor.
Then multiply the 'x' coordinate of your images by that scaling factor.
You can reset the 'x' position of your image like this:
yourImage.setX( yourImage.getX() * scalingFactor );
layer.draw();
In the above mentioned code for window.onresize. The code has been modified which as follow:-
window.onresize = function (event) {
_orignalWidth = stage.getWidth();
var _orignalHeight = stage.getHeight();
// alert(_orignalWidth);
// alert($('#tab' + tabId).outerHeight());
stage.setWidth(($('#tab' + tabId).innerWidth() / 100) * 80);
//stage.setHeight(($('#tab' + tabId).outerHeight() / 100) * 80);
_resizedWidth = stage.getWidth();
_resizedHeight = stage.getHeight();
// alert(_resizedWidth);
_scaleFactorX = _resizedWidth / _orignalWidth;
var _scaleFactorY = _resizedHeight / _orignalHeight;
//alert(_scaleFactor);
var _images = layer.getChildren();
for (var i = 0; i < _images.length; i++) {
if (typeof _images[i].getId() != 'undefined') {
//alert(stage.getScale().x);
_images[i].setX(_images[i].getX() * _scaleFactorX);
//_images[i].setY(_images[i].getY() * _scaleFactorY);
layer.draw();
}
}
}