Famo.us swipe on scrollview - scrollview

I have go through the Timbre tutorial in Famo.us University and it works fine but when I add a scrollview to the layout.content the swipe function stop working the scrollview view works fine but not the swipe.
Anyone know how to aplly the swipe right function from the Trimbe tutorial with a scrollview?
///AppView///
function _handleSwipe() {
var sync = new GenericSync(
['mouse', 'touch'],
{direction : GenericSync.DIRECTION_X}
);
this.pageView.pipe(sync);
sync.on('update', function(data) {
var currentPosition = this.pageViewPos.get();
if(currentPosition === 0 && data.velocity > 0) {
this.menuView.animateStrips();
}
this.pageViewPos.set(Math.max(0, currentPosition + data.delta));
}.bind(this));
sync.on('end', (function(data) {
var velocity = data.velocity;
var position = this.pageViewPos.get();
if(this.pageViewPos.get() > this.options.posThreshold) {
if(velocity < -this.options.velThreshold) {
this.slideLeft();
} else {
this.slideRight();
}
} else {
if(velocity > this.options.velThreshold) {
this.slideRight();
} else {
this.slideLeft();
}
}
}).bind(this));
}
///PageView///
function _createBody() {
var surfaces = [];
this.scrollview = new Scrollview();
var temp;
for (var i = 0; i < 20; i++) {
temp = new Surface({
size: [undefined, 80],
content: 'I am surface: ' + (i + 1),
properties: {
textAlign: 'left',
lineHeight: '80px',
borderTop: '1px solid #f1f1f1',
borderBottom: '1px solid #fff',
backgroundColor: '#f9f9f9',
fontFamily: 'Arial',
backfaceVisibility: 'visible',
paddingLeft: '10px'
}
});
temp.pipe(this.scrollview);
surfaces.push(temp);
}
this.scrollview.sequenceFrom(surfaces);
this.bodyContent = new Surface({
size: [undefined, undefined],
properties: {
backgroundColor: '#f5f5f5'
}
});
//this.layout.content.add(this.bodyContent);
this.layoutContainer.add(this.scrollview);
}
function _setListeners() {
this.hamburgerSurface.on('click', function() {
this._eventOutput.emit('menuToggle');
}.bind(this));
//this.bodyContent.pipe(this._eventOutput);
this.scrollview.pipe(this._eventOutput);
}

I have figured out by myself if I put the pipe(this._eventOutPut) in the for each with the temp variable it works. I don't know if is the best solution so I will be happy if anyone can give a better exemplo.
for (var i = 0; i < 10; i++) {
temp = new Surface({
size: [undefined, 80],
content: 'I am surface: ' + (i + 1),
properties: {
textAlign: 'left',
lineHeight: '80px',
borderTop: '1px solid #f1f1f1',
backgroundColor: '#f9f9f9',
fontFamily: 'Arial',
backfaceVisibility: 'visible',
paddingLeft: '10px'
}
});
/// Add the ._eventOutput to the temp
temp.pipe(this._eventOutput);
temp.pipe(scrollview);
surfaces.push(temp);
}

You should indeed relay the events processed by the scrollview to your own sync.
I have created a SwipeSync to make this easier: http://famousco.de/2014/08/swipesync-famo-us/
var scrollview = {your scrollview};
var sync = new SwipeSync();
scrollview.pipe(sync);
sync.on('swipe', function(data) {
alert('Swiped to: ' + data.direction);
});

Related

How put label into bar with vue-charjs

Hi I need help with put value into bar with simbole % how de image
I try with install chartjs-plugin-datalabels but dont work.
The value I need is the value I get with which the bar is measured
The version is :
"chart.js": "^2.7.3",
"vue-chartjs": "^3.4.0",
I can't change the version becouse I have others graphics in these versions
My code
const horizonalLinePlugin = {
id: 'horizontalLine',
afterDraw: function (chartInstance) {
var yValue;
var yScale = chartInstance.scales["y-axis-0"];
var canvas = chartInstance.chart;
var ctx = canvas.ctx;
var index;
var line;
var style;
var fontSize = (200 / 114).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
var data = ['20%', '30%', '40%', '60%', '10%', '30%', '20%'];
// var dataPresupuesto = ['10', '20', '30', '40', '10', '30', '20'];
var positionX = 130;
if (chartInstance.options.horizontalLine) {
for (index = 0; index < chartInstance.options.horizontalLine.length; index++) {
line = chartInstance.options.horizontalLine[index];
if (!line.style) {
style = "#080808";
} else {
style = line.style;
}
if (line.y) {
yValue = yScale.getPixelForValue(line.y);
} else {
yValue = 0;
}
ctx.lineWidth = 3;
if (yValue) {
window.chart = chartInstance;
ctx.beginPath();
ctx.moveTo(0, yValue);
ctx.lineTo(canvas.width, yValue);
ctx.strokeStyle = style;
ctx.stroke();
}
if (line.text) {
ctx.fillStyle = style;
ctx.fillText(line.text, 0, yValue + ctx.lineWidth);
}
}
return;
}
}
}
import { Bar } from 'vue-chartjs'
// import ChartJSPluginDatalabels from "chartjs-plugin-datalabels";
export default {
beforeMount() {
this.addPlugin(horizonalLinePlugin)
},
extends: Bar,
mounted() {
// Overwriting base render method with actual data.
this.renderChart({
labels: ['S01', 'S02', 'S03', 'S04', 'S05', 'S06', 'S07'],
datasets: [
{
label: 'Producción',
backgroundColor: '#000349',
data: [40, 39, 10, 40, 39, 80, 40]
},
{
label: 'Presupuesto',
backgroundColor: '#3AA9E0',
data: [40, 39, 10, 40, 39, 80, 40]
}
]
},
{
scales: {
xAxes: [{
stacked: true,
categoryPercentage: 0.5,
barPercentage: 1,
scaleLabel: {
display: true,
labelString: 'Semanas Comerciales'
}
}],
yAxes: [{
stacked: true,
}]
},
responsive: false,
plugins: {
datalabels: {
display: true,
color: "white",
textAlign: "center",
font: {
weight: "bold",
size: 16
}
}
}
})
}
}
Please someone that cant help me

Loading Vue component based on (changeable) variable

total newbie with Vue.js here, so sorry if I'm missing something obvious.
I want to load components based on the content of a variable - so if the content of my variable changes, I want the component to change accordingly. I have all components imported (e.g. import Project1 from "#/components/Project1";), which again is saved in components: {'p1': Project1}
I use <component :is="this.goTo.page"/>
with goTo.page being defined in data as data() {return {goTo: {page: "p1"}}}.
The problem seems to be the reactivness of goTo.page. I update it via this.$set(this.goTo, "page", "p2");. When running, i get the error Uncaught TypeError: Cannot read property 'page' of undefined, which I honestly don't understand, since its initialized with "p1".
import * as Matter from "matter-js";
import Project1 from "#/components/Project1";
import Project2 from "#/components/Project2";
import Project3 from "#/components/Project3";
export default {
name: "Work",
components: {
'p1': Project1,
'p2': Project2,
'p3': Project3
},
data() {
return {
goTo: {
page: "p1"
}
}
},
methods: {
startMatter: function () {
let harrie = require('#/assets/img/harrie.png');
let kub = require('#/assets/img/kub.png');
let jacs = require('#/assets/img/jacs.png');
let container = document.getElementById('threecontainerWork');
let nameTag = document.getElementById("title");
let width = container.offsetWidth;
let height = container.offsetHeight;
let engine = Matter.Engine.create({});
let renderer = Matter.Render.create({
element: document.getElementById('matterContainer'),
canvas: container,
engine: engine,
options: {
width: width,
height: height,
wireframes: false
}
})
let borderLeft = Matter.Bodies.rectangle(0, 0, 1, height * 2, {isStatic: true});
let borderRight = Matter.Bodies.rectangle(width, 0, 1, height * 2, {isStatic: true});
let roof = Matter.Bodies.rectangle(container.getBoundingClientRect().left, 0, width * 2, 1, {isStatic: true});
let ground = Matter.Bodies.rectangle(container.getBoundingClientRect().left, height, width * 2, 1, {isStatic: true});
let collider = Matter.Bodies.rectangle(container.offsetWidth / 2, container.offsetHeight, nameTag.offsetWidth, 1, {
isStatic: true,
isSensor: true,
render: {
fillStyle: 'red'
}
});
let nameTagBox = Matter.Bodies.rectangle(container.offsetWidth / 2, container.offsetHeight / 2, nameTag.offsetWidth, nameTag.offsetHeight, {isStatic: true});
let project1 = Matter.Bodies.rectangle(container.offsetWidth / 2, 100, 200, 200, {
render: {
sprite: {
texture: harrie
}
}
});
let project2 = Matter.Bodies.rectangle(201, 0, 200, 200, {
render: {
sprite: {
texture: kub
}
}
});
let project3 = Matter.Bodies.rectangle(1400, 0, 200, 200, {
render: {
sprite: {
texture: jacs
}
}
});
let polyStack = Matter.Composites.stack(container.offsetWidth / 2, 50, 2, 10, 0, 0, function (x, y) {
let sides = Math.round(Matter.Common.random(2, 8));
return Matter.Bodies.polygon(x, y, sides, Matter.Common.random(100, 100));
})
let mouse = Matter.Mouse.create(renderer.canvas);
let mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse: mouse
})
let colStart = Matter.Events.on(engine, 'collisionStart', function (event) {
var pairs = event.pairs;
for (var i = 0, j = pairs.length; i != j; ++i) {
var pair = pairs[i];
if (pair.bodyA === collider) {
switch (pair.bodyB.id) {
case project1.id:
this.$set(this.goTo, 'page', "p1");
break;
case project2.id:
this.$set(this.goTo, 'page', "p2");
break;
case project3.id:
this.$set(this.goTo, 'page', "p3");
break;
}
} else if (pair.bodyB === collider) {
switch (pair.bodyA.id) {
case project1.id:
this.$set(this.goTo, 'page', "p1");
break;
case project2.id:
this.$set(this.goTo, 'page', "p2");
break;
case project3.id:
this.$set(this.goTo, 'page', "p3");
break;
}
}
}
});
let colEnd = Matter.Events.on(engine, 'collisionEnd', function (event) {
var pairs = event.pairs;
for (var i = 0, j = pairs.length; i != j; ++i) {
var pair = pairs[i];
if (pair.bodyA === collider) {
switch (pair.bodyB.id) {
case project1.id:
this.$set(this.goTo, 'page', "noview");
break;
case project2.id:
this.$set(this.goTo, 'page', "noview");
break;
case project3.id:
this.$set(this.goTo, 'page', "noview");
break;
}
} else if (pair.bodyB === collider) {
switch (pair.bodyA.id) {
case project1.id:
this.$set(this.goTo, 'page', "noview");
break;
case project2.id:
this.$set(this.goTo, 'page', "noview");
break;
case project3.id:
this.$set(this.goTo, 'page', "noview");
break;
}
}
}
});
// TODO implement Vue.set(this.goTo, 'page', "p2"); correctly -> Matter Hell
Matter.World.add(engine.world, [ground, borderLeft, borderRight, roof, collider, project1, project2, project3, nameTagBox, polyStack, mouseConstraint, colStart, colEnd]);
Matter.Engine.run(engine);
Matter.Render.run(renderer);
}
},
},
mounted() {
this.$nextTick(function () {
this.startMatter();
})
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
#upperDiv {
position: relative;
width: 98vw;
height: 81vh;
margin: auto auto 1vh auto;
display: flex;
justify-content: center;
align-items: center;
top: 9vh /*Für alle anderen auch*/
}
#title {
position: absolute;
font-family: 'Playfair Display', serif;
font-weight: 600;
font-size: 5rem;
color: #f0f0f0;
padding: 2vh 3vw;
border: 1px solid #f0f0f0;
background-color: #1d1c1c;
z-index: 2;
text-align: center;
}
.threeContainer {
width: 96vw;
height: 70vh;
z-index: 1;
margin-bottom: 0;
}
<template>
<div>
<div id="upperDiv">
<div class="threeContainer" id="matterContainer">
<canvas id="threecontainerWork" class="threeContainer"></canvas>
</div>
<p id="title">My work</p>
</div>
<component :is="goTo.page"/>
</div>
</template>
<component :is="goTo.page"/>
this is not available in <template>. Everything "inside" this, is available.
In addition to the above and per your update,
methods: {
startMatter: function () {
//some matter.js
//if body collision detected:
this.$set(this.goTo, 'page', "p2");
},
},
The second argument of this.$set should be a string with the key name you wish to update.
If that doesn't work, your nextTick might be the problem. As in, there is no nextTick after mounted, unless something is updated.
mounted() {
this.$nextTick(function () {
this.startMatter();
})
}
Updated based on comments.
I believe that it's this line (line 108?), which overrides your this.
let colStart = Matter.Events.on(engine, 'collisionStart', function (event) {
Try instead:
let colStart = Matter.Events.on(engine, 'collisionStart', (event) => {
Function has it own scope /this. Vue normally binds to it, however I think that doesn't work as you're in matters callback now. The arrow function ensures the scope is lexical.
Same goes for:
let colEnd = Matter.Events.on(engine, 'collisionEnd', function (event) {,
change it to:
let colEnd = Matter.Events.on(engine, 'collisionEnd', (event) => {

draw rectangle with mouse move with Konva in VUE

This is the behavior I want to achieve in Vue.js Here is the Js fiddle example i am trying to make: https://jsfiddle.net/richardcwc/ukqhf54k/
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX-canvasx);
last_mousey = parseInt(e.clientY-canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX-canvasx);
mousey = parseInt(e.clientY-canvasy);
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
ctx.beginPath();
var width = mousex-last_mousex;
var height = mousey-last_mousey;
ctx.rect(last_mousex,last_mousey,width,height);
ctx.strokeStyle = 'black';
ctx.lineWidth = 10;
ctx.stroke();
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
I am using a library called Konva.js. Right now I am able to free drawing in Vue.js with Konva.js. But When I try to draw the rectangle with mousemove. It does not work correctly. I am not sure what causes the issue. Thanks for any help! Here is my work on
Code sandbox
This is the behavior I found out for my work. It only draws the rectangle after the mouse move event and then mouse click event.
<template>
<v-stage
ref="stage"
:config="stageSize"
#mousemove="handleMouseMove"
#mouseDown="handleMouseDown"
#mouseUp="handleMouseUp"
>
<v-layer ref="layer">
<v-text
ref="text"
:config="{
x: 10,
y: 10,
fontSize: 20,
text: text,
fill: 'black',
}"
/>
<v-rect
v-for="(rec, index) in recs"
:key="index"
:config="{
x: Math.min(rec.startPointX, rec.startPointX + rec.width),
y: Math.min(rec.startPointY, rec.startPointY + rec.height),
width: Math.abs(rec.width),
height: Math.abs(rec.height),
fill: 'rgb(0,0,0,0)',
stroke: 'black',
strokeWidth: 3,
}"
/>
</v-layer>
</v-stage>
</template>
<script>
const width = window.innerWidth;
const height = window.innerHeight;
export default {
data() {
return {
stageSize: {
width: width,
height: height,
},
text: "Try to draw a rectangle",
lines: [],
isDrawing: false,
recs: [],
};
},
methods: {
handleMouseDown(event) {
this.isDrawing = true;
const pos = this.$refs.stage.getNode().getPointerPosition();
this.setRecs([
...this.recs,
{ startPointX: pos.x, startPointY: pos.y, width: 0, height: 0 },
]);
},
handleMouseUp() {
this.isDrawing = false;
},
setRecs(element) {
this.recs = element;
},
handleMouseMove(event) {
// no drawing - skipping
if (!this.isDrawing) {
return;
}
// console.log(event);
const point = this.$refs.stage.getNode().getPointerPosition();
// handle rectangle part
let curRec = this.recs[this.recs.length - 1];
curRec.width = point.x - curRec.startPointX;
curRec.height = point.y - curRec.startPointY;
},
},
};
</script>
Demo: https://codesandbox.io/s/vue-konva-drawings-rectangles-ivjtu?file=/src/App.vue

Smooth 60 fps video from konva canvas animation using ccapturejs

Hey everyone so I have a Konvajs application that works great as a video editor running on the vuejs library. However, I want to capture the canvas and create a seamless video at 60 fps. In order to do this, I am trying to utilize the CCapturejs library. It kind of works except for now the playback of the webm is really fast and still a bit choppy. Can any of ya'll look at this code and help me find the problem? Thanks.
<template>
<div>
<button #click="render">Render</button>
<button #click="stop">stop</button>
<h2>Backgrounds</h2>
<template v-for="background in backgrounds">
<img
:src="background.poster"
class="backgrounds"
#click="changeBackground(background.video)"
/>
</template>
<h2>Images</h2>
<template v-for="image in images">
<img
:src="image.source"
#click="addImage(image)"
class="images"
/>
</template>
<br />
<button #click="addText">Add Text</button>
<button v-if="selectedNode" #click="removeNode">
Remove selected {{ selectedNode.type }}
</button>
<label>Font:</label>
<select v-model="selectedFont">
<option value="Arial">Arial</option>
<option value="Courier New">Courier New</option>
<option value="Times New Roman">Times New Roman</option>
<option value="Desoto">Desoto</option>
<option value="Kalam">Kalam</option>
</select>
<label>Font Size</label>
<input type="number" v-model="selectedFontSize" />
<label>Font Style:</label>
<select v-model="selectedFontStyle">
<option value="normal">Normal</option>
<option value="bold">Bold</option>
<option value="italic">Italic</option>
</select>
<label>Color:</label>
<input type="color" v-model="selectedColor" />
<button
v-if="selectedNode && selectedNode.type === 'text'"
#click="updateText"
>
Update Text
</button>
<template v-if="selectedNode && selectedNode.lottie">
<input type="text" v-model="text">
<button #click="updateAnim(selectedNode.image)">
Update Animation
</button>
</template>
<br />
<video
id="preview"
v-show="preview"
:src="preview"
:width="width"
:height="height"
preload="auto"
controls
/>
<a v-if="file" :href="file" download="dopeness.mp4">download</a>
<div id="container"></div>
</div>
</template>
<script>
import lottie from "lottie-web";
import CCapture from "../ccapture";
import * as anim from "../AEAnim/anim.json";
import * as anim2 from "../AEAnim/anim2.json";
import * as anim3 from "../AEAnim/anim3.json";
import * as anim4 from "../AEAnim/anim4.json";
import * as anim5 from "../AEAnim/anim5.json";
export default {
data() {
return {
source: null,
stage: null,
layer: null,
video: null,
animations: [],
text: "",
animationData: null,
captures: [],
capturer: null,
backgrounds: [
{
poster: "/api/files/stock/3oref310k1uud86w/poster/poster.jpg",
video:
"/api/files/stock/3oref310k1uud86w/main/1080/3oref310k1uud86w_1080.mp4"
},
{
poster: "https://i2.wp.com/livinglifefearless.co/wp-content/uploads/2019/08/Forrest-Gump-25-1.jpg?fit=1920%2C1220&ssl=1",
video: "/api/files/jedi/run_forest_run.mp4"
},
{
poster: "/api/files/stock/3yj2e30tk5x6x0ww/poster/poster.jpg",
video:
"/api/files/stock/3yj2e30tk5x6x0ww/main/1080/3yj2e30tk5x6x0ww_1080.mp4"
},
{
poster: "/api/files/stock/2ez931ik1mggd6j/poster/poster.jpg",
video:
"/api/files/stock/2ez931ik1mggd6j/main/1080/2ez931ik1mggd6j_1080.mp4"
},
{
poster: "/api/files/stock/yxrt4ej4jvimyk15/poster/poster.jpg",
video:
"/api/files/stock/yxrt4ej4jvimyk15/main/1080/yxrt4ej4jvimyk15_1080.mp4"
},
{
poster:
"https://images.costco-static.com/ImageDelivery/imageService?profileId=12026540&itemId=100424771-847&recipeName=680",
video: "/api/files/jedi/surfing.mp4"
},
{
poster:
"https://thedefensepost.com/wp-content/uploads/2018/04/us-soldiers-afghanistan-4308413-1170x610.jpg",
video: "/api/files/jedi/soldiers.mp4"
}
],
images: [
{ source: "/api/files/jedi/solo.jpg" },
{ source: "api/files/jedi/yoda.jpg" },
{ source: "api/files/jedi/yodaChristmas.jpg" },
{ source: "api/files/jedi/darthMaul.jpg" },
{ source: "api/files/jedi/darthMaul1.jpg" },
{ source: "api/files/jedi/trump.jpg" },
{ source: "api/files/jedi/hat.png" },
{ source: "api/files/jedi/trump.png" },
{ source: "api/files/jedi/bernie.png" },
{ source: "api/files/jedi/skywalker.png" },
{ source: "api/files/jedi/vader.gif" },
{ source: "api/files/jedi/vader2.gif" },
{ source: "api/files/jedi/yoda.gif" },
{ source: "api/files/jedi/kylo.gif" },
{
source: "https://media3.giphy.com/media/R3IxJW14a3QNa/source.gif",
animation: anim
},
{
source: "https://bestanimations.com/Text/Cool/cool-story-3.gif",
animation: anim2
},
{
source: "https://freefrontend.com/assets/img/css-text-animations/HTML-CSS-Animated-Text-Fill.gif",
animation: anim3
},
{
source: "api/files/jedi/slider.gif",
animation: anim4
},
{
source: "api/files/jedi/zoomer.gif",
animation: anim5
}
],
backgroundVideo: null,
imageGroups: [],
anim: null,
selectedNode: null,
selectedFont: "Arial",
selectedColor: "black",
selectedFontSize: 20,
selectedFontStyle: "normal",
width: 1920,
height: 1080,
texts: [],
preview: null,
file: null,
canvas: null
};
},
mounted: function() {
this.initCanvas();
},
methods: {
changeBackground(source) {
this.source = source;
this.video.src = this.source;
this.anim.stop();
this.anim.start();
this.video.play();
},
removeNode() {
if (this.selectedNode && this.selectedNode.type === "text") {
this.selectedNode.transformer.destroy(
this.selectedNode.text.transformer
);
this.selectedNode.text.destroy(this.selectedNode.text);
this.texts.splice(this.selectedNode.text.index - 1, 1);
this.selectedNode = null;
this.layer.draw();
} else if (this.selectedNode && this.selectedNode.type == "image") {
this.selectedNode.group.destroy(this.selectedNode);
this.imageGroups.splice(this.selectedNode.group.index - 1, 1);
if (this.selectedNode.lottie) {
cancelAnimationFrame(this.animations.animFrame);
this.selectedNode.lottie.destroy();
this.animations.splice(this.selectedNode.lottie.index - 1, 1);
}
this.selectedNode = null;
this.layer.draw();
}
},
async addImage(imageToAdd, isUpdate) {
let lottieAnimation = null;
let imageObj = null;
const type = imageToAdd.source.slice(imageToAdd.source.lastIndexOf("."));
const vm = this;
function process(img) {
return new Promise((resolve, reject) => {
img.onload = () => resolve({ width: img.width, height: img.height });
});
}
imageObj = new Image();
imageObj.src = imageToAdd.source;
imageObj.width = 200;
imageObj.height = 200;
await process(imageObj);
if (type === ".gif" && !imageToAdd.animation) {
const canvas = document.createElement("canvas");
canvas.setAttribute("id", "gif");
async function onDrawFrame(ctx, frame) {
ctx.drawImage(frame.buffer, frame.x, frame.y);
// redraw the layer
vm.layer.draw();
}
gifler(imageToAdd.source).frames(canvas, onDrawFrame);
canvas.onload = async () => {
canvas.parentNode.removeChild(canvas);
};
imageObj = canvas;
const gif = new Image();
gif.src = imageToAdd.source;
const gifImage = await process(gif);
imageObj.width = gifImage.width;
imageObj.height = gifImage.height;
} else if (imageToAdd.animation) {
if(!isUpdate){this.text = "new text";}
const canvas = document.createElement("canvas");
canvas.style.width = 1920;
canvas.style.height= 1080;
canvas.setAttribute("id", "animationCanvas");
const ctx = canvas.getContext("2d");
const div = document.createElement("div");
div.setAttribute("id", "animationContainer");
div.style.display = "none";
canvas.style.display = "none";
this.animationData = imageToAdd.animation.default;
for(let i =0; i <this.animationData.layers.length; i++){
for(let b =0; b<this.animationData.layers[i].t.d.k.length; b++){
this.animationData.layers[i].t.d.k[b].s.t = this.text;
}
}
lottieAnimation = lottie.loadAnimation({
container: div, // the dom element that will contain the animation
renderer: "svg",
loop: true,
autoplay: true,
animationData: this.animationData
});
lottieAnimation.imgSrc = imageToAdd.source;
lottieAnimation.text = this.text;
const svg = await div.getElementsByTagName("svg")[0];
async function updateSvg() {
const xml = new XMLSerializer().serializeToString(svg);
const svg64 = window.btoa(xml);
const b64Start = "data:image/svg+xml;base64,";
const image64 = b64Start + svg64;
imageObj = new Image({ width: canvas.width, height: canvas.height });
imageObj.src = image64;
await process(imageObj);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(imageObj, 0, 0, canvas.width, canvas.height);
vm.layer.draw();
updateSvg();
};
const animFrame = requestAnimationFrame(updateSvg);
this.animations.push({ lottie: lottieAnimation, animFrame });
imageObj = canvas;
canvas.onload = async () => {
canvas.parentNode.removeChild(canvas);
};
}
const image = new Konva.Image({
x: 50,
y: 50,
image: imageObj,
width: imageObj.width,
height: imageObj.height,
position: (0, 0),
strokeWidth: 10,
stroke: "blue",
strokeEnabled: false
});
const group = new Konva.Group({
draggable: true
});
// add the shape to the layer
addAnchor(group, 0, 0, "topLeft");
addAnchor(group, imageObj.width, 0, "topRight");
addAnchor(group, imageObj.width, imageObj.height, "bottomRight");
addAnchor(group, 0, imageObj.height, "bottomLeft");
imageObj = null;
image.on("click", function () {
vm.hideAllHelpers();
vm.selectedNode = {
type: "image",
group,
lottie: lottieAnimation,
image: imageToAdd
};
if(lottieAnimation && lottieAnimation.text){vm.text = lottieAnimation.text}
group.find("Circle").show();
vm.layer.draw();
});
image.on("mouseover", function(evt) {
if (vm.selectedNode && vm.selectedNode.type === "image") {
const index = image.getParent().index;
const groupId = vm.selectedNode.group.index;
if (index != groupId) {
evt.target.strokeEnabled(true);
vm.layer.draw();
}
} else {
evt.target.strokeEnabled(true);
vm.layer.draw();
}
});
image.on("mouseout", function(evt) {
evt.target.strokeEnabled(false);
vm.layer.draw();
});
vm.hideAllHelpers();
group.find("Circle").show();
group.add(image);
vm.layer.add(group);
vm.imageGroups.push(group);
vm.selectedNode = {
type: "image",
group,
lottie: lottieAnimation,
image: imageToAdd
};
function update(activeAnchor) {
const group = activeAnchor.getParent();
let topLeft = group.get(".topLeft")[0];
let topRight = group.get(".topRight")[0];
let bottomRight = group.get(".bottomRight")[0];
let bottomLeft = group.get(".bottomLeft")[0];
let image = group.get("Image")[0];
let anchorX = activeAnchor.getX();
let anchorY = activeAnchor.getY();
// update anchor positions
switch (activeAnchor.getName()) {
case "topLeft":
topRight.y(anchorY);
bottomLeft.x(anchorX);
break;
case "topRight":
topLeft.y(anchorY);
bottomRight.x(anchorX);
break;
case "bottomRight":
bottomLeft.y(anchorY);
topRight.x(anchorX);
break;
case "bottomLeft":
bottomRight.y(anchorY);
topLeft.x(anchorX);
break;
}
image.position(topLeft.position());
let width = topRight.getX() - topLeft.getX();
let height = bottomLeft.getY() - topLeft.getY();
if (width && height) {
image.width(width);
image.height(height);
}
}
function addAnchor(group, x, y, name) {
let stage = vm.stage;
let layer = vm.layer;
let anchor = new Konva.Circle({
x: x,
y: y,
stroke: "#666",
fill: "#ddd",
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false
});
anchor.on("dragmove", function() {
update(this);
layer.draw();
});
anchor.on("mousedown touchstart", function() {
group.draggable(false);
this.moveToTop();
});
anchor.on("dragend", function() {
group.draggable(true);
layer.draw();
});
// add hover styling
anchor.on("mouseover", function() {
let layer = this.getLayer();
document.body.style.cursor = "pointer";
this.strokeWidth(4);
layer.draw();
});
anchor.on("mouseout", function() {
let layer = this.getLayer();
document.body.style.cursor = "default";
this.strokeWidth(2);
layer.draw();
});
group.add(anchor);
}
},
async updateAnim(image){
this.addImage(image, true);
this.removeNode();
},
hideAllHelpers() {
for (let i = 0; i < this.texts.length; i++) {
this.texts[i].transformer.hide();
}
for (let b = 0; b < this.imageGroups.length; b++) {
this.imageGroups[b].find("Circle").hide();
}
},
render(){
this.video.currentTime =0;
this.video.loop = false;
this.captureCanvas();
},
captureCanvas (){
this.capturer = new CCapture( {
verbose: true,
//display: false,
framerate: 60,
//motionBlurFrames: 0,
//quality: 100,
format: "webm",
timeLimit: 0
//frameLimit: 0,
//autoSaveTime: 0,
} );
this.capturer.start();
this.updateCapturer();
},
stop(){
this.capturer.stop();
this.capturer.save();
},
updateCapturer(){
console.log("holy crap I was called");
console.log("this is the canvas", this.canvas);
let rAF;
if(this.capturer){
this.capturer.capture(this.canvas)
rAF = requestAnimationFrame(this.updateCapturer);
} else {
cancelAnimationFrame(rAf);
}
},
updateText() {
if (this.selectedNode && this.selectedNode.type === "text") {
const text = this.selectedNode.text;
const transformer = this.selectedNode.transformer;
text.fontSize(this.selectedFontSize);
text.fontFamily(this.selectedFont);
text.fontStyle(this.selectedFontStyle);
text.fill(this.selectedColor);
this.layer.draw();
}
},
addText() {
const vm = this;
const text = new Konva.Text({
text: "new text " + (vm.texts.length + 1),
x: 50,
y: 80,
fontSize: this.selectedFontSize,
fontFamily: this.selectedFont,
fontStyle: this.selectedFontStyle,
fill: this.selectedColor,
align: "center",
width: this.width * 0.5,
draggable: true
});
const transformer = new Konva.Transformer({
node: text,
keepRatio: true,
enabledAnchors: ["top-left", "top-right", "bottom-left", "bottom-right"]
});
text.on("click", async () => {
for (let i = 0; i < this.texts.length; i++) {
let item = this.texts[i];
if (item.index === text.index) {
let transformer = item.transformer;
this.selectedNode = { type: "text", text, transformer };
this.selectedFontSize = text.fontSize();
this.selectedFont = text.fontFamily();
this.selectedFontStyle = text.fontStyle();
this.selectedColor = text.fill();
vm.hideAllHelpers();
transformer.show();
transformer.moveToTop();
text.moveToTop();
vm.layer.draw();
break;
}
}
});
text.on("mouseover", () => {
transformer.show();
this.layer.draw();
});
text.on("mouseout", () => {
if (
(this.selectedNode &&
this.selectedNode.text &&
this.selectedNode.text.index != text.index) ||
(this.selectedNode && this.selectedNode.type === "image") ||
!this.selectedNode
) {
transformer.hide();
this.layer.draw();
}
});
text.on("dblclick", () => {
text.hide();
transformer.hide();
vm.layer.draw();
let textPosition = text.absolutePosition();
let stageBox = vm.stage.container().getBoundingClientRect();
let areaPosition = {
x: stageBox.left + textPosition.x,
y: stageBox.top + textPosition.y
};
let textarea = document.createElement("textarea");
window.document.body.appendChild(textarea);
textarea.value = text.text();
textarea.style.position = "absolute";
textarea.style.top = areaPosition.y + "px";
textarea.style.left = areaPosition.x + "px";
textarea.style.width = text.width() - text.padding() * 2 + "px";
textarea.style.height = text.height() - text.padding() * 2 + 5 + "px";
textarea.style.fontSize = text.fontSize() + "px";
textarea.style.border = "none";
textarea.style.padding = "0px";
textarea.style.margin = "0px";
textarea.style.overflow = "hidden";
textarea.style.background = "none";
textarea.style.outline = "none";
textarea.style.resize = "none";
textarea.style.lineHeight = text.lineHeight();
textarea.style.fontFamily = text.fontFamily();
textarea.style.transformOrigin = "left top";
textarea.style.textAlign = text.align();
textarea.style.color = text.fill();
let rotation = text.rotation();
let transform = "";
if (rotation) {
transform += "rotateZ(" + rotation + "deg)";
}
let px = 0;
let isFirefox =
navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
if (isFirefox) {
px += 2 + Math.round(text.fontSize() / 20);
}
transform += "translateY(-" + px + "px)";
textarea.style.transform = transform;
textarea.style.height = "auto";
textarea.focus();
// start
function removeTextarea() {
textarea.parentNode.removeChild(textarea);
window.removeEventListener("click", handleOutsideClick);
text.show();
transformer.show();
transformer.forceUpdate();
vm.layer.draw();
}
function setTextareaWidth(newWidth) {
if (!newWidth) {
// set width for placeholder
newWidth = text.placeholder.length * text.fontSize();
}
// some extra fixes on different browsers
let isSafari = /^((?!chrome|android).)*safari/i.test(
navigator.userAgent
);
let isFirefox =
navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
if (isSafari || isFirefox) {
newWidth = Math.ceil(newWidth);
}
let isEdge =
document.documentMode || /Edge/.test(navigator.userAgent);
if (isEdge) {
newWidth += 1;
}
textarea.style.width = newWidth + "px";
}
textarea.addEventListener("keydown", function(e) {
// hide on enter
// but don't hide on shift + enter
if (e.keyCode === 13 && !e.shiftKey) {
text.text(textarea.value);
removeTextarea();
}
// on esc do not set value back to node
if (e.keyCode === 27) {
removeTextarea();
}
});
textarea.addEventListener("keydown", function(e) {
let scale = text.getAbsoluteScale().x;
setTextareaWidth(text.width() * scale);
textarea.style.height = "auto";
textarea.style.height =
textarea.scrollHeight + text.fontSize() + "px";
});
function handleOutsideClick(e) {
if (e.target !== textarea) {
text.text(textarea.value);
removeTextarea();
}
}
setTimeout(() => {
window.addEventListener("click", handleOutsideClick);
});
// end
});
text.transformer = transformer;
this.texts.push(text);
this.layer.add(text);
this.layer.add(transformer);
this.hideAllHelpers();
this.selectedNode = { type: "text", text, transformer };
transformer.show();
this.layer.draw();
},
initCanvas() {
const vm = this;
this.stage = new Konva.Stage({
container: "container",
width: vm.width,
height: vm.height
});
this.layer = new Konva.Layer();
this.stage.add(this.layer);
let video = document.createElement("video");
video.setAttribute("id", "video");
video.setAttribute("ref", "video");
if (this.source) {
video.src = this.source;
}
video.preload = "auto";
video.loop = "loop";
video.style.display = "none";
this.video = video;
this.backgroundVideo = new Konva.Image({
image: vm.video,
draggable: false
});
this.video.addEventListener("loadedmetadata", function(e) {
vm.backgroundVideo.width(vm.width);
vm.backgroundVideo.height(vm.height);
});
this.video.addEventListener("ended", () => {
console.log("the video ended");
this.stop();
this.capturer = null;
this.anim.stop();
this.anim.start();
this.video.loop = "loop";
this.video.play();
});
this.anim = new Konva.Animation(function() {
console.log("animation called");
// do nothing, animation just need to update the layer
}, vm.layer);
this.layer.add(this.backgroundVideo);
this.layer.draw();
const canvas = document.getElementsByTagName("canvas")[0];
canvas.style.border = "3px solid red";
this.canvas = canvas;
}
}
};
</script>
<style scoped>
body {
margin: 0;
padding: 0;
background-color: #f0f0f0;
}
.backgrounds,
.images {
width: 100px;
height: 100px;
padding-left: 2px;
padding-right: 2px;
}
</style>
Use this code to pause the video and take screenshots. You can than use Whammy to generate a webm and convert it to whatever file format you like with ffmpeg
generateVideo(){
const vid = new Whammy.fromImageArray(this.captures, 30);
vid.name = "project_id_238.webm";
vid.lastModifiedDate = new Date();
this.file = URL.createObjectURL(vid);
},
async pauseAll(){
this.pauseVideo();
if(this.animations.length){
this.pauseLotties()
}
this.captures.push(this.canvas.toDataURL('image/webp'));
if(!this.ended){
setTimeout(()=>{
this.pauseAll();
}, 500);
}
},
async pauseVideo(){
console.log("curretTime",this.video.currentTime);
console.log("duration", this.video.duration);
this.video.pause();
const oneFrame = 1/30;
this.video.currentTime += oneFrame;
},
async pauseLotties(){
lottie.freeze();
for(let i =0; i<this.animations.length; i++){
let step =0;
let animation = this.animations[i].lottie;
if(animation.currentFrame<=animation.totalFrames){
step = animation.currentFrame + animation.totalFrames/30;
}
lottie.goToAndStop(step, true, animation.name);
}
},

Appcelerator Titanium Facebook Like Menu

at that moment i'm developing an App where i want to use the Facebook Like Menü from here:
https://github.com/mpociot/titanium-facebook-slide-menu
// ALPHABYTES
// Facebook like menu window
var leftMenu = Ti.UI.createWindow({
backgroundColor: 'red',
top: 0,
left: 0,
width: 150,
zIndex: 1
});
var data = [{title:"Row 1"},{title:"Row 2"},{title:"Row 3"},{title:"Row 4"}];
var tableView = Ti.UI.createTableView({ data: data });
leftMenu.add(tableView);
leftMenu.open();
// Facebook like menu window
var rightMenu = Ti.UI.createWindow({
backgroundColor: 'red',
top: 0,
right: 0,
width: 150,
zIndex: 1
});
var data = [{title:"Row 1"},{title:"Row 2"},{title:"Row 3"},{title:"Row 4"}];
var tableView = Ti.UI.createTableView({ data: data });
rightMenu.add(tableView);
rightMenu.open();
// animations
var animateLeft = Ti.UI.createAnimation({
left: 150,
curve: Ti.UI.iOS.ANIMATION_CURVE_EASE_OUT,
duration: 500
});
var animateRight = Ti.UI.createAnimation({
left: 0,
curve: Ti.UI.iOS.ANIMATION_CURVE_EASE_OUT,
duration: 500
});
var animateNegativeLeft = Ti.UI.createAnimation({
left: -150,
curve: Ti.UI.iOS.ANIMATION_CURVE_EASE_OUT,
duration: 500
});
var win = Titanium.UI.createWindow({
left: 0,
zIndex: 10
});
var win1 = Titanium.UI.createWindow({
backgroundColor: 'white',
title: 'Facebook menu',
left: 0,
zIndex: 10
});
var nav = Titanium.UI.iPhone.createNavigationGroup({
window: win1,
left: 0,
width: Ti.Platform.displayCaps.platformWidth
});
var button = Ti.UI.createButton({
title: 'm',
left: 10,
width: 30,
height: 30,
top: 10
});
var button2 = Ti.UI.createButton({
title: 'm',
right: 10,
width: 30,
height: 30,
top: 10
});
var touchStartX = 0;
var touchStarted = false;
win1.addEventListener('touchstart',function(e){
touchStartX = parseInt(e.x,10);
});
win1.addEventListener('touchend',function(e){
touchStarted = false;
if( win.left < 0 ){
if( win.left <= -140 ){
win.animate(animateNegativeLeft);
isToggled = true;
} else {
win.animate(animateRight);
isToggled = false;
}
} else {
if( win.left >= 140 ){
win.animate(animateLeft);
isToggled = true;
} else {
win.animate(animateRight);
isToggled = false;
}
}
});
win1.addEventListener('touchmove',function(e){
var x = parseInt(e.globalPoint.x, 10);
var newLeft = x - touchStartX;
if( touchStarted ){
if( newLeft <= 150 && newLeft >= -150)
win.left = newLeft;
}
// Minimum movement is 30
if( newLeft > 30 || newLeft < -30 ){
touchStarted = true;
}
});
nav.add(button);
nav.add(button2);
win.add(nav);
win.open();
var isToggled = false;
button.addEventListener('click',function(e){
if( !isToggled ){
win.animate(animateLeft);
isToggled = true;
} else {
win.animate(animateRight);
isToggled = false;
}
});
button2.addEventListener('click',function(e){
if( !isToggled ){
win.animate(animateNegativeLeft);
isToggled = true;
} else {
win.animate(animateRight);
isToggled = false;
}
});
I have also implemented the menu and everything works as expected.
Now my Problem is the following:
If i click in the leftMenu on e.g. "Row 1" ("Settings" with me), i want to have my Settings Menu shown in the Main Window. How to do that?
If i create a new Window and open it, i get a complete new window without the facebook menu on the left and the buttons... I don't know how to do?!?! Can someone help?
Thanks,
Sascha
I hope I did't misunderstand your question, but I would open new windows as views inside of the main window. Here's some code: https://gist.github.com/manumaticx/4961175
Or do you want to change the menu? Then you would do the same to the left menu window!
var curWin = Titanium.UI.createWindow();
var menuBtn = Titanium.UI.createButton({
title : "Menu",
top : 20,
left : 5,
zIndex : 999
});
var windowView = Titanium.UI.createView({
top : 60,
left : 0,
right : 0,
width : '100%',
height : '100%',
backgroundColor : "blue",
zIndex : 1
});
curWin.add(windowView);
curWin.add(menuBtn);
curWin.open();
var menuWindow = Titanium.UI.createView({
top : 20,
left : 0,
width : 150
});
curWin.add(menuWindow);
//// ---- Menu Table
// Menu Titles
var menuTitles = [{
title : 'Menu 1'
}, {
title : 'Menu 2'
}, {
title : 'Menu 3'
}, {
title : 'Menu 4'
}, {
title : 'Menu 5'
}, {
title : 'Menu 6'
}];
// Tableview
var tableView = Titanium.UI.createTableView({
data : menuTitles
});
menuWindow.add(tableView);
var toggle = false;
menuWindow.hide();
menuBtn.addEventListener('click', function(e) {
if (toggle) {
menuWindow.hide();
toggle = false;
windowView.left = 0;
menuBtn.left = 5;
} else {
menuWindow.show();
toggle = true;
windowView.left = 150;
menuBtn.left = 160;
}
});
windowView.addEventListener('click', function(e) {
if (toggle) {
menuWindow.hide();
toggle = false;
windowView.left = 0;
menuBtn.left = 5;
}
});