I've got a CodePen of what I've created (with the help of other sources) and everything looks great. I want the ability to click on the text (or the page) and pause the JQuery loop. As well as the ability to click it again to resume it. CodePen Link
If that's too hard, I would like to look at the Next button so I can manually toggle to the next line, as well as a manual toggle button to the main line of <li>#SSBASKETBALL | SUMMERSERIES.NZ</li>
The button needs to be at the bottom further down as it's part of OBS's Browser tool.
If anyone could help me out with this, please feel free. It does the job at the moment, but I would really like to incorporate it more professionally and have more control over it. Cheers!
(function($) {
$.simpleTicker = function(element, options) {
var defaults = {
speed: 800,
delay: 10000,
easing: 'swing',
effectType: 'fade'
}
var param = {
'ul': '',
'li': '',
'initList': '',
'ulWidth': '',
'liHeight': '',
'tickerHook': 'tickerHook',
'effect': {}
}
var plugin = this;
plugin.settings = {}
var $element = $(element),
element = element;
plugin.init = function() {
plugin.settings = $.extend({}, defaults, options);
param.ul = element.children('ul');
param.li = element.find('li');
param.initList = element.find('li:first');
param.ulWidth = param.ul.width();
param.liHeight = param.li.height();
element.css({
height: (param.liHeight)
});
param.li.css({
top: '0',
left: '0',
position: 'absolute'
});
switch (plugin.settings.effectType) {
case 'fade':
plugin.effect.fade();
break;
case 'roll':
plugin.effect.roll();
break;
case 'slide':
plugin.effect.slide();
break;
}
plugin.effect.exec();
}
plugin.effect = {};
plugin.effect.exec = function() {
param.initList.css(param.effect.init.css)
.animate(param.effect.init.animate, plugin.settings.speed, plugin.settings.easing)
.addClass(param.tickerHook);
setInterval(function() {
element.find('.' + param.tickerHook)
.animate(param.effect.start.animate, plugin.settings.speed, plugin.settings.easing)
.next()
.css(param.effect.next.css)
.animate(param.effect.next.animate, plugin.settings.speed, plugin.settings.easing)
.addClass(param.tickerHook)
.end()
.appendTo(param.ul)
.css(param.effect.end.css)
.removeClass(param.tickerHook);
}, plugin.settings.delay);
}
plugin.effect.fade = function() {
param.effect = {
'init': {
'css': {
display: 'block',
opacity: '0'
},
'animate': {
opacity: '1',
zIndex: '98'
}
},
'start': {
'animate': {
opacity: '0'
}
},
'next': {
'css': {
display: 'block',
opacity: '0',
zIndex: '99'
},
'animate': {
opacity: '1'
}
},
'end': {
'css': {
display: 'none',
zIndex: '98'
}
}
}
}
plugin.effect.roll = function() {
param.effect = {
'init': {
'css': {
top: '-3em',
display: 'block',
opacity: '0'
},
'animate': {
top: '0',
opacity: '1',
zIndex: '98'
}
},
'start': {
'animate': {
top: '3em',
opacity: '0'
}
},
'next': {
'css': {
top: '-3em',
display: 'block',
opacity: '0',
zIndex: '99'
},
'animate': {
top: '0',
opacity: '1'
}
},
'end': {
'css': {
zIndex: '98'
}
}
}
}
plugin.effect.slide = function() {
param.effect = {
'init': {
'css': {
left: (-(200)),
display: 'block',
opacity: '0'
},
'animate': {
left: '0',
opacity: '1',
zIndex: '98'
}
},
'start': {
'animate': {
left: (200),
opacity: '0'
}
},
'next': {
'css': {
left: (param.ulWidth),
display: 'block',
opacity: '0',
zIndex: '99'
},
'animate': {
left: '0',
opacity: '1'
}
},
'end': {
'css': {
zIndex: '98'
}
}
}
}
plugin.init();
}
$.fn.simpleTicker = function(options) {
return this.each(function() {
if (undefined == $(this).data('simpleTicker')) {
var plugin = new $.simpleTiecker(this, options);
$(this).data('simpleTicker', plugin);
}
});
}
})(jQuery);
$(function() {
$.simpleTicker($('#js-ticker-fade'), {
'effectType': 'fade'
});
$.simpleTicker($('#js-ticker-roll'), {
'effectType': 'roll'
});
$.simpleTicker($('#js-ticker-slide'), {
'effectType': 'slide'
});
});
#font-face {
font-family: "DharmaGothicEW01-Light";
src: url("https:https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.eot");
src: url("https:https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.eot?#iefix") format("embedded-opentype"), url("https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.woff2") format("woff2"), url("https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.woff") format("woff"), url("https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.ttf") format("truetype"), url("https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.svg#DharmaGothicEW01-Light") format("svg");
}
#font-face {
font-family: "DharmaGothicEW01-Bold";
src: url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.eot");
src: url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.eot?#iefix") format("embedded-opentype"), url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.woff2") format("woff2"), url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.woff") format("woff"), url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.ttf") format("truetype"), url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.svg#DharmaGothicEW01-Bold") format("svg");
}
* {
font-size: 32px;
word-spacing: 5px;
font-family: DharmaGothicEW01-Light;
text-align: center;
color: #000;
}
.hvhbox {
display: inline-block;
width: 50px;
border: 0px solid #000;
background: #fe3249;
text-align: center;
}
.simple-ticker {
position: relative;
text-align: center;
width: 100%;
padding: 30px;
border: 0px solid #ddd;
overflow: hidden;
}
.simple-ticker ul {
position: relative;
width: 100%;
margin: 0;
padding: 0;
list-style: none;
}
.simple-ticker ul li {
display: none;
width: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery simple news ticker</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<section>
<div class="simple-ticker" id="js-ticker-roll">
<ul>
<li>#SSBASKETBALL | SUMMERSERIES.NZ</li>
<li>THE SUMMER SERIES 20: <span style="background: #979797; color: #fff;"> HUTT VALLEY </span> VS <span style="background: #0053a3; color: #fff;"> UPPER HUTT </span></li>
<li>THE SUMMMER SERIES IS PROUDLY SUPPORTED BY TRIPLE THREAT</li>
<li><span style="background: #0053a3; color: #fff"> UHC </span> RJ WICHMAN 13 PTS</li>
<li><span style="background: #979797; color: #fff;"> HVH </span> 25% [1/4] 3PT PERCENTAGE 20% [1/5] <span style="background: #0053a3; color: #fff;"> UHC </span></li>
<!-- <li>NEXT UP: <span style="background: #fb1414; color: #fff;"> SACRED HEART </span> VS <span style="background: #fff200; color: #000;"> WELLINGTON EAST </span></li> -->
</ul>
</div>
</section>
<!-- partial -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js'></script>
<script src="./script.js"></script>
</body>
</html>
Related
I have a grid of cards with a button to remove each one of them with an animation. I chose to reduce the width to 0 so that the cards to the right (on the same row) slide to the left and occupy the removed card spot.
What I would like to achieve is to animate the first element of the following row into the last position of the row above (the one that had the card removed).
The best example I can provide is the home page of the Vivaldi browser, where you can remove a speed dial widget and the following ones animate to their new positions.
This example in CodePen is what I have so far.
$(document).ready(function() {
const content = $('#inner-content');
let listCourses = '';
let courses = [
{ title: 'html' },
{ title: 'css' },
{ title: 'javascript' },
{ title: 'python' },
{ title: 'react' },
{ title: 'node' },
{ title: 'angular' },
{ title: 'SEO' },
{ title: 'UX/UI' },
{ title: 'jQuery' },
{ title: 'SQL' },
{ title: 'noSql' }
]
courses.forEach((course) => {
let newCourse = `
<div class="course-container">
<div class="inner-container">
<h2>${course.title}</h2>
<button class="courses-control"> Remove </button>
</div>
</div>
`;
listCourses += newCourse;
});
content.html(listCourses);
$('.courses-control').on('click', function(e){
$(this)
.parents('.course-container').animate({
'width': '0px',
'padding': '12px 0px',
'opacity': '0'}, function() {
$(this).remove();
});
})
});
* {
box-sizing: border-box;
}
body { font-family: 'lato'; }
#inner-content {
display: flex;
flex-wrap: wrap;
}
.centered {
max-width: 960px;
margin: auto;
}
.course-container {
width: 25%;
padding: 12px;
overflow: hidden;
}
.inner-container {
overflow: hidden;
text-align: center;
border: 1px solid gray;
border-radius: 6px;
padding: 12px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Courses</h1>
<div id="inner-content" class="centered">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="scripts.js"></script>
</body>
</html>
change the forEach loop to have an index and give each button an id:
courses.forEach((course, index) => {
let newCourse = `
<div class="course-container">
<div class="inner-container">
<h2>${course.title}</h2>
<button id="${index}" class="courses-control"> Remove </button>
</div>
</div>
`;
listCourses += newCourse;
});
Then in the click function after this:
$(this)
.parents('.course-container').animate({
'width': '0px',
'padding': '12px 0px',
'opacity': '0'
}, function () {
$(this).remove();
});
add this:
$(`#${Number(this.id) + 4}`).parents('.course-container').animate({
'margin-top': '-100px',
'z-index': '1',
'opacity': '0'
}, 500, function () {
$(this).css({ 'margin': '0px', 'opacity': '1' });
});
Try it out and tell me what you think...
new Vue({
el: "#app",
data: {
getQuestionAnswers: [
{
name: 'foo',
checked: false,
status: 'ok'
},
{
name: 'bar',
checked: false,
status: 'notok'
},
{
name: 'baz',
checked: false,
status: 'medium'
},
{
name: 'oo',
checked: false,
status: 'medium'
}
]
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
width:100%
}
.red {
color: red;
}
.bcom {
width: 100%;
display: flex;
}
.container1 {
width: 50px;
}
.container2 {
width: calc(100% - 105px);
padding: 8px 0;
height: 30px;
box-sizing: border-box;
}
.h-line {
height: 1px;
margin-bottom: 18px;
width: 100%;
background-color: black;
}
.container3{
margin-left: 5px;
width: 50px;
}
.point:hover {
width: 200px;
}
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
<div class="bcom"
v-for="(group, index) in getQuestionAnswers"
:key="index + group.name"
:group="group"
>
<div>
<input type="checkbox" v-model="group.checked"/>
{{ group.name }}
</div>
<div class="container2">
<div class="h-line" v-if="group.checked"></div>
</div>
<div>
<input type="checkbox"/>
{{ group.status }}
</div>
</div>
</div>
Onclick of checkbox, how to add multiple lines from one point in Vuejs?
As seen in the image, On click of the checkbox, Based on the status, I need to match from one point to three multiple status. like "ok, notok, medium"
i have taken v-model in the checkbox,to check and perfome two way data binding But not sure....what to do further. Do I need to take computed property and write condition to check and draw three multiple lines???
there are som positioning issues here, but this sample should be enough for you to get it working:
template
<div id="demo" :ref="'plane'">
<canvas :ref="'canvas'"></canvas>
<div
class="bcom"
v-for="(group, index) in getQuestionAnswers"
:key="index + group.name"
:group="group"
>
<div>
<input
type="checkbox"
v-on:click="() => onToggleCheckbox(group)"
v-model="group.checked"
:ref="'checkbox_' + group.name"
/>
<span>{{ group.name }}</span>
</div>
<div>
<span>{{ group.status }}</span>
<input type="checkbox" :ref="'status_' + group.name" />
</div>
</div>
</div>
script:
export default {
name: 'App',
data: () => ({
ctx: undefined,
draw(begin, end, stroke = 'black', width = 1) {
if (!this.ctx) {
const canvas = this.$refs['canvas'];
if (!canvas?.getContext) return;
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
this.ctx = canvas.getContext('2d');
}
if (stroke) {
this.ctx.strokeStyle = stroke;
}
if (width) {
this.ctx.lineWidth = width;
}
this.ctx.beginPath();
this.ctx.moveTo(...begin);
this.ctx.lineTo(...end);
this.ctx.stroke();
},
onToggleCheckbox(group) {
const planeEl = this.$refs['plane'];
const planeRect = planeEl.getBoundingClientRect();
const fromEl = this.$refs['checkbox_' + group.name];
const fromRect = fromEl.getBoundingClientRect();
const from = {
x: fromRect.right - planeRect.left,
y: fromRect.top + fromRect.height / 2 - planeRect.top,
};
const toEl = this.$refs['status_' + group.name];
const toRect = toEl.getBoundingClientRect();
const to = {
x: toRect.left - planeRect.left,
y: toRect.top + toRect.height / 2 - planeRect.top,
};
console.log(planeRect, from, to);
this.draw(
Object.values(from),
Object.values(to),
group.checked ? 'white' : 'black',
group.checked ? 3 : 2
);
},
getQuestionAnswers: [
{
name: 'foo',
checked: false,
status: 'ok',
},
{
name: 'bar',
checked: false,
status: 'notok',
},
{
name: 'baz',
checked: false,
status: 'medium',
},
{
name: 'oo',
checked: false,
status: 'medium',
},
],
}),
};
style
body {
background: #20262e;
padding: 20px;
font-family: Helvetica;
}
#demo {
position: relative;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
canvas {
position: absolute;
background: red;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: #fff;
z-index: -1;
}
.bcom {
width: 100%;
display: flex;
justify-content: space-between;
z-index: 2;
}
this only draws one line but you could easily add the others. I figured you might change your data schema to something like:
getQuestions() {
{
name: string,
checked: boolean,
statuses: [string...],
},
getStatuses() {
{
name: string
}
but not knowing about your requirements here, I decided to post the above before making further changes. (here is the sort of refactor I was referring to: https://stackblitz.com/edit/vue-yuvsxa )
addressing first comment:
in app.vue only there is one data called[((questions))], inside question we are looping and setting the status.
this is easy to address with a bit of preprocessing:
questionsAndStatusesMixed: // such as [{...question, ...statuses}],
questions: [],
statuses: [],
mounted() {
const statusesSet = new Set()
this.questionsAndStatusesMixed.forEach(item => {
const question = {
name: item.name,
checked: item.checked,
answer: item.status // is this the answer or .. these never made sense to me,
statuses: this.statuses // assuming each question should admit all statuses/that is, draw a line to each
}
const status = {
name: item.name
}
this.questions.push(question)
statusesSet.add(status)
})
Array.from(statusesSet).forEach(item => this.statuses.push(item))
}
I use Xampp to try GrapesJS, I downloaded GrapesJS from github then copied the rources to my HTDOCS folder, grap my Browser then hit Localhost :) it works, something like Web Builder appear and works as well, but how can I save the Edited Website using PHP ?,
I use intact INDEX.HTML found from GrapesJs github, only change it name to INDEX.PHP to work with PHP, so this is the codes I've been using
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>GrapesJS</title>
<link rel="stylesheet" href="dist/css/grapes.min.css">
<script src="dist/grapes.min.js"></script>
<style>
body,
html {
height: 100%;
margin: 0;
}
</style>
</head>
<body>
<div id="gjs" style="height:0px; overflow:hidden;">
<div class="panel">
<h1 class="welcome">Welcome to</h1>
<div class="big-title">
<svg class="logo" viewBox="0 0 100 100">
<path d="M40 5l-12.9 7.4 -12.9 7.4c-1.4 0.8-2.7 2.3-3.7 3.9 -0.9 1.6-1.5 3.5-1.5 5.1v14.9 14.9c0 1.7 0.6 3.5 1.5 5.1 0.9 1.6 2.2 3.1 3.7 3.9l12.9 7.4 12.9 7.4c1.4 0.8 3.3 1.2 5.2 1.2 1.9 0 3.8-0.4 5.2-1.2l12.9-7.4 12.9-7.4c1.4-0.8 2.7-2.2 3.7-3.9 0.9-1.6 1.5-3.5 1.5-5.1v-14.9 -12.7c0-4.6-3.8-6-6.8-4.2l-28 16.2"/>
</svg>
<span>GrapesJS</span>
</div>
<div class="description">
This is a demo content from index.html. For the development, you shouldn't edit this file, instead you can
copy and rename it to _index.html, on next server start the new file will be served, and it will be ignored by git.
</div>
</div>
<style>
.panel {
width: 90%;
max-width: 700px;
border-radius: 3px;
padding: 30px 20px;
margin: 150px auto 0px;
background-color: #d983a6;
box-shadow: 0px 3px 10px 0px rgba(0,0,0,0.25);
color:rgba(255,255,255,0.75);
font: caption;
font-weight: 100;
}
.welcome {
text-align: center;
font-weight: 100;
margin: 0px;
}
.logo {
width: 70px;
height: 70px;
vertical-align: middle;
}
.logo path {
pointer-events: none;
fill: none;
stroke-linecap: round;
stroke-width: 7;
stroke: #fff
}
.big-title {
text-align: center;
font-size: 3.5rem;
margin: 15px 0;
}
.description {
text-align: justify;
font-size: 1rem;
line-height: 1.5rem;
}
</style>
</div>
<script type="text/javascript">
var editor = grapesjs.init({
showOffsets: 1,
noticeOnUnload: 0,
container: '#gjs',
height: '100%',
fromElement: true,
storageManager: { autoload: 0 },
styleManager : {
sectors: [{
name: 'General',
open: false,
buildProps: ['float', 'display', 'position', 'top', 'right', 'left', 'bottom']
},{
name: 'Flex',
open: false,
buildProps: ['flex-direction', 'flex-wrap', 'justify-content', 'align-items', 'align-content', 'order', 'flex-basis', 'flex-grow', 'flex-shrink', 'align-self']
},{
name: 'Dimension',
open: false,
buildProps: ['width', 'height', 'max-width', 'min-height', 'margin', 'padding'],
},{
name: 'Typography',
open: false,
buildProps: ['font-family', 'font-size', 'font-weight', 'letter-spacing', 'color', 'line-height', 'text-shadow'],
},{
name: 'Decorations',
open: false,
buildProps: ['border-radius-c', 'background-color', 'border-radius', 'border', 'box-shadow', 'background'],
},{
name: 'Extra',
open: false,
buildProps: ['transition', 'perspective', 'transform'],
}
],
},
});
editor.BlockManager.add('testBlock', {
label: 'Block',
attributes: { class:'gjs-fonts gjs-f-b1' },
content: `<div style="padding-top:50px; padding-bottom:50px; text-align:center">Test block</div>`
})
</script>
</body>
</html>
thanks for your help
This way worked for me.
First added a Save button to grapesjs panel.
editor.Panels.addButton('options',
[{
id: 'save-db',
className: 'fas fa-save',
command: 'save-db',
attributes: {
title: 'Save Changes'
}
}]
);
Then added a command for save button.
editor.Commands.add('save-db', {
run: function(editor, sender) {
sender && sender.set('active', 0); // turn off the button
editor.store();
//storing values to variables
var htmldata = editor.getHtml();
var cssdata = editor.getCss();
$.post("save.php", {
//you can get value in post by calling this name
"htmldata": htmldata,
"cssdata": cssdata,
success: function(data) {
alert(data);
console.log("Success");
},
});
}
});
In save.php
$editor_html_content = $_POST['htmldata'];
$editor_css_content = $_POST['cssdata'];
editor.on('component:add', options => {
var html = editor.getHtml();
var css = editor.getCss();
function create () {
$.ajax({
url:base_url+"/savepagedata.php",
type: "post",
data: {html_data: html , css_data:css },
success:function(result){
console.log(result);
}
});
}
});
I am working on a prototype that uses AngularJS to filter JSON data. A working sandbox is here:
https://codepen.io/ixdarchitects/pen/BaypxrW
I need your help to solve 2 Problems:
How to use the "Check All" and "Uncheck All" button to activate/deactivate all of the checkbox filters?
Filter by default: How to make the webpage only show gray bird when the page is initialized?
Thank you
Image
HTML:
<div ng-app="petSelector" ng-controller="PetCtrl" class="wrapper">
<h1>Pet Picker!</h1>
<hr>
<h3>Problems to solve:</h3>
<ol>
<li>How to use the "Check All" and "Uncheck All" button to activate/deactivate all of the checkbox filters?</li>
<li>Filter by default: How to make the webpage only show gray bird when the page is initialized?</li>
</ol>
<hr>
<div class="attr" ng-repeat="(prop, ignoredValue) in pets[0].FilterAttributes" ng-init="filter[prop]={}" ng-class="prop">
<b>{{prop}}:</b><br />
<span class="checkbox" ng-repeat="opt in getOptionsFor(prop)">
<label><input type="checkbox" ng-model="filter[prop][opt]" /> {{opt}}</label>
</span>
</div>
<button ng-click="checkAll()" style="margin-right: 10px">Check all</button>
<button ng-click="uncheckAll()" style="margin-right: 10px">Uncheck all</button>
<div class="results">Number of results: {{filtered.length}}</div>
<div class="pet" ng-repeat="p in filtered=(pets | filter:filterByProp | orderBy:order)">
<img ng-src="{{p.img}}">
<p>{{p.name}}</p>
</div>
<div ng-if="filtered.length == 0">Sorry, nothing matches your selection</div>
</div>
JS:
var petSelector = angular.module("petSelector", []);
petSelector.controller("PetCtrl", [
"$scope",
function($scope) {
$scope.pets = [
{
name: "Finch",
FilterAttributes: { species: "bird", size: "x-small", color: "red" },
img:
"http://upload.wikimedia.org/wikipedia/commons/7/7c/Fringilla_coelebs_chaffinch_male_edit2.jpg"
},
{
name: "Cockatiel",
FilterAttributes: { species: "bird", size: "small", color: "yellow" },
img: "http://upload.wikimedia.org/wikipedia/commons/0/07/Captive.jpg"
},
{
name: "African Gray Parrot",
FilterAttributes: { species: "bird", size: "large", color: "gray" },
img:
"http://upload.wikimedia.org/wikipedia/commons/2/28/Psittacus_erithacus_-perching_on_tray-8d.jpg"
},
{
name: "Macaw",
FilterAttributes: { species: "bird", size: "x-large", color: "blue" },
img:
"http://upload.wikimedia.org/wikipedia/commons/0/00/Macaw.blueyellow.arp.750pix.jpg"
},
{
name: "Shih Tzu",
FilterAttributes: { species: "dog", size: "x-small", color: "multi" },
img: "http://upload.wikimedia.org/wikipedia/commons/3/30/Shih-Tzu.JPG"
},
{
name: "Border Collie",
FilterAttributes: { species: "dog", size: "small", color: "multi" },
img:
"http://upload.wikimedia.org/wikipedia/commons/b/b1/Border_Collie_liver_portrait.jpg"
},
{
name: "American Staffordshire Terrier",
FilterAttributes: { species: "dog", size: "large", color: "gray" },
img: "http://upload.wikimedia.org/wikipedia/commons/d/de/AmStaff2.jpg"
},
{
name: "Bullmastiff",
FilterAttributes: { species: "dog", size: "x-large", color: "brown" },
img:
"http://upload.wikimedia.org/wikipedia/commons/9/9e/Bullmastiff_Junghund_1_Jahr.jpg"
}
];
$scope.filter = {};
$scope.getOptionsFor = function(propName) {
return ($scope.pets || [])
.map(function(p) {
return p.FilterAttributes[propName];
})
.filter(function(p, idx, arr) {
return arr.indexOf(p) === idx;
});
};
$scope.filterByProp = function(pets) {
var matchesAND = true;
for (var prop in $scope.filter) {
if (noSubFilter($scope.filter[prop])) continue;
if (!$scope.filter[prop][pets.FilterAttributes[prop]]) {
matchesAND = false;
break;
}
}
return matchesAND;
};
function noSubFilter(subFilterObj) {
for (var key in subFilterObj) {
if (subFilterObj[key]) return false;
}
return true;
}
}
]);
CSS
* {
box-sizing: border-box;
}
body {
font-family: 'Helvetica', arial, sans-sarif;
color: #fff;
}
h1 {
color: #fff;
margin: 0;
}
p {
margin-top: 0;
}
b {
color: #fff;
text-transform: uppercase;
}
.wrapper {
width: 800px;
margin: 20px auto;
padding: 40px;
background: #00a5bb;
border-radius: 8px;
}
.attr {
width: 32%;
margin: 0 .5%;
padding: 20px;
display: inline-block;
vertical-align: top;
}
.checkbox {
width: 49%;
display: inline-block;
margin: 10px 0 0;
}
.results {
font-size: 12px;
margin: 10px 0 20px;
padding-bottom: 10px;
border-bottom: 1px solid white;
}
.pet {
margin-bottom: 10px;
display: inline-block;
width: 33%;
text-align: center;
}
.pet img {
max-width: 85%;
max-height: 200px;
}
.pet.ng-enter, .pet.ng-leave {
-webkit-transition: all linear 0.5s;
transition: all linear 0.5s;
}
.pet .ng-enter {
opacity: 0;
}
.pet.ng-enter-active {
opacity: 1;
height: auto;
}
.pet.ng-leave-active {
opacity: 0;
height: 0;
}
I achieve what you are asking for adding the following two $scope functions.
$scope.checkAll iterates all pets FilteredAttributes and their values and set them at true into $scopeFilter.
$scope.uncheckAll simply reset the $scopeFilter object.
For the default filter, I removed ng-init="filter[prop]={}" to initiliaze $scopeFilter in the .js file as follows :
$scope.filter = {species : {bird : true} , color : {gray: true}};
$scope.checkAll = function(){
const result = {};
$scope.pets.map(pet => pet.FilterAttributes)
.forEach( attribute => Object.keys(attribute)
.forEach( prop => {
if(result[prop]){
result[prop][attribute[prop]] = true
}
else
{
result[prop] = {};
result[prop][attribute[prop]] = true
}
})
);
$scope.filter = result;
};
$scope.uncheckAll = function(){
$scope.filter = {}
};
You can find the solution here https://codepen.io/dmnized/pen/povRQOE?editors=1010
I have a problem with marker, I want the marker to be stretchable to mark anywhere on the progress bar
As shown in below GIF
Question: I want to select any point on the progress bar and be able to stretch the marker, which can be multiple marker points.
I don't know how to do it with below code:
var player = videojs('demo');
player.markers({
markerStyle: {
'width':'9px',
'border-radius': '40%',
'background-color': 'orange'
},
markerTip:{
display: true,
text: function(marker) {
return "I am a marker tip: "+ marker.text;
}
},
breakOverlay:{
display: true,
displayTime: 4,
style:{
'width':'100%',
'height': '30%',
'background-color': 'rgba(10,10,10,0.6)',
'color': 'white',
'font-size': '16px'
},
text: function(marker) {
return "This is a break overlay: " + marker.overlayText;
},
},
markers: [
{time: 9.5, text: "this", overlayText: "1", class: "special-blue"},
{time: 16, text: "is", overlayText: "2"},
{time: 23.6,text: "so", overlayText: "3"},
{time: 28, text: "cool", overlayText: "4"}
]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="http://vjs.zencdn.net/4.2/video.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-markers/0.7.0/videojs-markers.js"></script>
<link href="http://vjs.zencdn.net/4.2/video-js.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/videojs-markers/0.7.0/videojs.markers.min.css" rel="stylesheet"/>
<video id="demo" width="400" height="210" controls class="video-js vjs-default-skin">
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
</video>
where you want the pointer, just put time in the time: 20.5 and increase the width of the markerStyle: { 'width': '190px' }, so you'll get long line in video progressbar!
here we go
var player = videojs('demo');
player.markers({
markerStyle: {
'width':'190px',
'border-radius': '2px',
'background-color': 'orange'
},
markerTip:{
display: true,
text: function(marker) {
return "I am a marker tip: "+ marker.text;
}
},
breakOverlay:{
display: true,
displayTime: 120,
style:{
'width':'100%',
'height': '30%',
'background-color': 'rgba(10,10,10,0.6)',
'color': 'white',
'font-size': '16px'
},
text: function(marker) {
return "This is a break overlay: " + marker.overlayText;
},
},
markers: [
{time: 20.5, text: "this", overlayText: "1", class: "special-blue"},
]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="http://vjs.zencdn.net/4.2/video.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-markers/0.7.0/videojs-markers.js"></script>
<link href="http://vjs.zencdn.net/4.2/video-js.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/videojs-markers/0.7.0/videojs.markers.min.css" rel="stylesheet"/>
<video id="demo" width="400" height="210" controls class="video-js vjs-default-skin">
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
</video>
you can study here more about all things docs.
if you have any issue please, inform us!
Happy codin'!
One way you can do it is hook into mousedown and mousemove events on seekbar. Add the marker on mousedown with a custom class. Then on mousemove calculate the movement and add the width to the marker element using the custom class.
See this example:
var player = videojs('demo');
// Set variable so we can add values later
let lastAddedMarker = null;
let moving = false;
let seekBar = player.controlBar.progressControl.seekBar;
let startPoint = 0;
// When seekbar is clicked add marker and set values to startpoint and set moving flag to true
seekBar.on('mousedown', function(event) {
var seekBarEl = this.el();
startPoint = videojs.dom.getPointerPosition(seekBarEl, event).x;
player.markers.add([{
time: player.currentTime(),
text: "I'm new",
overlayText: "I'm new",
class: 'custom-marker'
}]);
lastAddedMarker = jQuery(".custom-marker");
moving = true;
});
// When user moves while on seekbar get the width and set it to 'custom-marker' class
seekBar.on("mousemove", function(e) {
if (moving) {
let seekBarEl = this.el();
let movingPoint = videojs.dom.getPointerPosition(seekBarEl, event).x;
let containerWidth = jQuery(seekBarEl).width();
let markerWidth = containerWidth * (movingPoint - startPoint);
lastAddedMarker.width(markerWidth + "px");
}
});
jQuery(document).on("mouseup", function() {
moving = false;
});
player.markers({
markerStyle: {
'width': '9px',
'border-radius': '2px',
'background-color': 'orange'
},
markerTip: {
display: true,
text: function(marker) {
return "I am a marker tip: " + marker.text;
}
},
onMarkerClick: function(marker) {
console.log("AS");
},
breakOverlay: {
display: true,
displayTime: 4,
style: {
'width': '100%',
'height': '30%',
'background-color': 'rgba(10,10,10,0.6)',
'color': 'white',
'font-size': '16px'
},
text: function(marker) {
return "This is a break overlay: " + marker.overlayText;
},
},
markers: []
});
.vjs-marker {
position: absolute;
left: 0;
bottom: 0;
opacity: 1;
height: 100%;
transition: opacity .2s ease;
-webkit-transition: opacity .2s ease;
-moz-transition: opacity .2s ease;
z-index: 100
}
.vjs-break-overlay,
.vjs-tip {
visibility: hidden;
position: absolute;
z-index: 100000
}
.vjs-marker:hover {
cursor: pointer;
-webkit-transform: scale(1.3, 1.3);
-moz-transform: scale(1.3, 1.3);
-o-transform: scale(1.3, 1.3);
-ms-transform: scale(1.3, 1.3);
transform: scale(1.3, 1.3)
}
.vjs-tip {
display: block;
opacity: .8;
padding: 5px;
font-size: 10px;
bottom: 14px
}
.vjs-tip .vjs-tip-arrow {
background: url(data:image/gif;base64,R0lGODlhCQAJAIABAAAAAAAAACH5BAEAAAEALAAAAAAJAAkAAAIRjAOnwIrcDJxvwkplPtchVQAAOw==) bottom left no-repeat;
bottom: 0;
left: 50%;
margin-left: -4px;
position: absolute;
width: 9px;
height: 5px
}
.vjs-tip .vjs-tip-inner {
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
padding: 5px 8px 4px;
background-color: #000;
color: #fff;
max-width: 200px;
text-align: center
}
.vjs-break-overlay {
top: 0
}
.vjs-break-overlay .vjs-break-overlay-text {
padding: 9px;
text-align: center
}
<link href="https://vjs.zencdn.net/7.5.5/video-js.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.6.5/video.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/videojs-markers/0.7.0/videojs.markers.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-markers/0.7.0/videojs-markers.min.js"></script>
<video id="demo" width="400" height="210" controls class="video-js vjs-default-skin">
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
</video>