I'm trying to fit 4 triangles in a master template using jquery, html5 and canvas,
I can't seem to make them fit...
Here is what I got so far...
https://jsfiddle.net/ax67r91y/
The code I think is wrong:
ctx.drawImage(part.img, // random image
0, 0, part.w, part.h, // source
part.x,part.y,part.trisize.w,part.trisize.h); // destination
All images should be cut down into 2 forms: a " v " and a " ^ ",
I can move images, but shrinking them to the correct size seems unattainable...
I think I'm close, but it's been hours I'm on this, help is welcome!!!
Expected result:
Is this what you are looking for?
function createSVG(name, attributes) {
var svg_node = document.createElementNS("http://www.w3.org/2000/svg", name);
Object.keys(attributes).forEach(function(key) {
if (key == 'textContent') {
svg_node.textContent = attributes[key];
return;
}
svg_node.setAttribute(key, attributes[key]);
});
return svg_node;
}
Element.prototype.appendSVG = function(name, attributes) {
this.appendChild(createSVG(name, attributes));
}
function Polygons() {
this.canvas = createSVG('svg', {
'version': '1.1',
'shape-rendering': 'geometricPrecision',
'viewBox': '0 0 1589 745',
'class': 'svg-content',
});
this.defs = createSVG('defs', {});
this.canvas.appendChild(this.defs);
this.registerPatterns();
this.drawInnerLayer();
this.drawOuterLayer();
}
Polygons.prototype.registerPatterns = function() {
var patternBottom = createSVG('pattern', {
'height': "100%",
'width': "100%",
'patternContentUnits': "objectBoundingBox",
'viewBox': "0 0 1 1",
'preserveAspectRatio': "xMidYMid slice",
});
var imgBottom = createSVG('image', {
'height': "1",
'width': "1",
'preserveAspectRatio': "xMidYMid slice",
});
var imgLeft = imgBottom.cloneNode(true)
imgLeft.setAttributeNS('http://www.w3.org/1999/xlink','href', "http://waw.wizard.build/wp-content/themes/twentyseventeen/TMP/1.png");
var imgMiddle = imgBottom.cloneNode(true);
imgMiddle.setAttributeNS('http://www.w3.org/1999/xlink','href', "http://waw.wizard.build/wp-content/themes/twentyseventeen/TMP/2.png");
var imgRight = imgBottom.cloneNode(true);
imgRight.setAttributeNS('http://www.w3.org/1999/xlink','href', "http://waw.wizard.build/wp-content/themes/twentyseventeen/TMP/3.png");
imgBottom.setAttributeNS('http://www.w3.org/1999/xlink','href', "http://waw.wizard.build/wp-content/themes/twentyseventeen/TMP/4.png");
var patternLeft = patternBottom.cloneNode(true);
patternLeft.setAttribute('id', "img-left");
patternLeft.appendChild(imgLeft);
var patternRight = patternBottom.cloneNode(true);
patternRight.setAttribute('id', "img-right");
patternRight.appendChild(imgRight);
var patternMiddle = patternBottom.cloneNode(true);
patternMiddle.setAttribute('id', "img-middle");
patternMiddle.appendChild(imgMiddle);
patternBottom.setAttribute('id', "img-bottom");
patternBottom.appendChild(imgBottom);
this.defs.appendChild(patternLeft);
this.defs.appendChild(patternRight);
this.defs.appendChild(patternMiddle);
this.defs.appendChild(patternBottom);
var patternOverlayer = createSVG('pattern', {
'height': "100%",
'width': "100%",
'patternContentUnits': "objectBoundingBox",
'id': "img-overlayer",
});
var imgOverlayer = createSVG('image', {
'height': "1",
'width': "1",
'preserveAspectRatio': "none",
});
imgOverlayer.setAttributeNS('http://www.w3.org/1999/xlink','href', "http://waw.wizard.build/wp-content/themes/twentyseventeen/assets/images/frame-all.png");
patternOverlayer.appendChild(imgOverlayer);
this.defs.appendChild(patternOverlayer);
}
Polygons.prototype.drawOuterLayer = function() {
this.canvas.appendSVG('rect', {
'x': '0',
'y': '0',
'width': '100%',
'height': '100%',
'fill': 'url(#img-overlayer)',
'class': 'img-overlayer',
});
}
Polygons.prototype.drawInnerLayer = function() {
this.canvas.appendSVG('polygon', {
'points': '500,55 800,50 643,370',
'class': 'inner-polygon polygon-left',
'fill': 'url(#img-left)',
});
this.canvas.appendSVG('polygon', {
'points': '800,70 665,395 935,395',
'class': 'inner-polygon polygon-middle',
'fill': 'url(#img-middle)',
});
this.canvas.appendSVG('polygon', {
'points': '820,50 1115,45 950,375',
'class': 'inner-polygon polygon-right',
'fill': 'url(#img-right)',
});
this.canvas.appendSVG('polygon', {
'points': '660,415 940,415 805,720',
'class': 'inner-polygon polygon-down',
'fill': 'url(#img-bottom)',
});
}
var polygons = new Polygons();
document.getElementById('svg-container').appendChild(polygons.canvas);
#svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%;
vertical-align: middle;
overflow: hidden;
}
.svg-content {
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
<div id="svg-container"></div>
Related
I know nothing of jquery/js but i applied a News Slider/Ticker script that I found online to my website home page. The script itself works fine. The html and css parts were easy enough but I can't find the proper way to make it PAUSE ON HOVER. The .js file that came with it is lengthy and has much that I suspect isn't even being used, but as I said, I don't know js. Sorry for the long js file but I don't know what parts are even involved. Can somebody help this complete novice?
(function ($) {
$.simpleTicker = function (elem, options) {
var defaults = {
speed: 1000,
delay: 4000,
easing: 'swing',
effectType: 'slide'
};
var param = {
'ul': '',
'li': '',
'initList': '',
'ulWidth': '',
'liHeight': '',
'tickerHook': 'tickerHook',
'effect': {}
};
var plugin = this;
plugin.settings = {};
var $element = $(elem),
element = elem;
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'
});
//dispatch
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);
if (element.find(param.li).length > 1) {
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);
In my opinion, that library is old and very very complicated to work with. I would personally recommend you move to something along the lines of Slick Slider.
Slick: https://kenwheeler.github.io/slick/
You can use the CDN version <script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel#1.8.1/slick/slick.min.js"></script>
I was able to recreate your use case in about 5min (with hover pause) with Click. Because it's an actual slider, it's better to wrap things in <div> containers, so I've done so in the fiddle I've shown you. You can tweak the CSS opacity animations to taste, but it's basically what you're doing now.
The Fiddle: Slick Slider
I'm trying to create several groups. Each of the group will get a custom attribute to indicate its position. Depending on this attribute I want to set different images as a group members. This part doesn't work and I cannot figure it out. image header.png is added twice and shows in content-footer area. in the header area there is no image at all.
Also when I try to log the output
console.log(JSON.stringify(canvasBuild)
there is no content inside the "objects" property of a group. When I try to log stringified group - it does show the image objects.
This is the simplified code so far
var hasHeader = false;
var hasFooter = false;
// users choice of layout
var customPosition = [];
$(this).siblings('.layoutOptions').children('input:checked').each(function(i)
{
customPosition[i] = $(this).val();
if ( customPosition[i]=='content-header'){
hasHeader = true;
}else if (customPosition[i]=='content-footer'){
hasFooter = true;
}
});
$(this).siblings('.contentOptions').children('input:checked').val();
for (i = 0; i< customPosition.length; i++){
console.log(i);
console.log(customPosition[i]);
var canvField = (canvasBHeight - shadowBVal*2) - strokeBWidth*2;
if (customPosition[i] == 'content-header'){
//header positioning
var group = new fabric.Group([],{
left: strokeBWidth + 10,
stroke: '#ddd',
strokeLineJoin: 'round',
strokeWidth: 2,
hasControls: true,
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
selectable: true,
position: posB,
fill: '#ccc',
width: ((canvasBWidth - shadowBVal*2) - strokeBWidth*2 - 10),
//height: canvasBHeight/5 - strokeBWidth,
height: canvField/5,
top: strokeBWidth,
ry: 0,
rx: 20,
//originX: 'center',
//originY: 'center'
});
//add dummy content
fabric.Image.fromURL('image/bordenconfigurator/dummies/header.png', function(oImg) {
oImg.set({
});
group.add(oImg);
console.log('group '+i+' '+customPosition[i]+':');
console.log(JSON.stringify(group));
//console.log(group);
});
}else if(customPosition[i] == 'content-footer') {
console.log(customPosition[i]);
//footer positioning
var group = new fabric.Group([],{
left: strokeBWidth + 10,
stroke: '#ddd',
strokeLineJoin: 'round',
strokeWidth: 2,
hasControls: true,
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
selectable: true,
position: posB,
fill: '#ccc',
width: ((canvasBWidth - shadowBVal*2) - strokeBWidth*2 - 10),
//height: canvasBHeight/5 - strokeBWidth,
height: canvField/5,
top: strokeBWidth + canvField*4/5 + 10,
ry: 0,
rx: 20,
//originX: 'center',
//originY: 'center'
});
//add dummy content
fabric.Image.fromURL('image/bordenconfigurator/dummies/footer.png', function(oImg) {
oImg.set({
top: canvasBHeight- strokeBWidth-shadowBVal,
});
group.add(oImg);
canvasBuild.centerObjectH(oImg);
console.log('group '+i+' '+customPosition[i]+':');
console.log(JSON.stringify(group));
});
}else{
console.log(customPosition[i]);
//body positioning
var height,top;
if (hasHeader === true && hasFooter === true){
height = canvField*3/5 + 5;
top = strokeBWidth + canvField/5 + 5;
}else if(hasHeader ===true && hasFooter === false){
height = canvField*4/5 + 5;
top = strokeBWidth + canvField/5 + 5;
}else if(hasHeader ===false && hasFooter === true){
height = canvField*4/5;
top = strokeBWidth + 5;
}
var group = new fabric.Group([],{
left: strokeBWidth + 10,
stroke: '#ddd',
strokeLineJoin: 'round',
strokeWidth: 2,
hasControls: true,
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
selectable: true,
position: posB,
fill: 'rgba(255,255,255,0)',
width: ((canvasBWidth - shadowBVal*2) - strokeBWidth*2 - 10),
height: height,
//top: strokeBWidth + canvField/5 + 5,
top: top,
ry: 20,
rx: 20
});
}
group.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
customPosition: this.customPosition,
label: this.label,
id: this.id
});
};
})(group.toObject);
group.customPosition = customPosition[i];
group.id = posB;
canvasBuild.add(group);
group.length = 0;
posB++;
}
//addOrientationLines();
//canvasBuild.renderAll();
//console.log(JSON.stringify(canvasBuild));
});
A dropdown component is rendered twice adjacently.
When an item from a dropdown is selected, the entire dropdown component is pushed down.
I am not sure why this issue is occuring. (I am guessing this could be due to lack of space between the 2 dropdowns).
Don't know how to resolve this issue.
I have posted the code below.
function Dropdown() {
this.id = '';
this.items = [];
this.settings = {
isRendered: false,
isListOpen: false
};
this.init = function(componentId) {
this.id = componentId;
this.cacheDOM();
};
this.cacheDOM = function() {
this.$el = $('#' + this.id);
if (this.settings.isRendered)
{
this.$input = this.$el.find('input');
this.$dropbox = this.$el.find('div');
this.$dropdownicon = this.$el.find('span:first');
this.$ul = this.$el.find('ul');
this.$li = this.$ul.find('li');
}
this.template = `<div id='`+ this.id +`'>
<div class='dropbox'><input /><span class='material-icons'>expand_more</span></div>
<ul style='display: none'>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
</div>`;
};
this.populateItems = function(items) {
this.items = items;
this.render();
};
this.applyStyles = function() {
var elStyle = {
'display': 'inline-block',
'position': 'relative',
'padding': '0',
'margin': '0'
};
var dropboxStyle = {
'display' : 'inline-flex',
'border' : '1px solid #9DD9D2'
};
var inputStyle = {
'font': 'inherit',
'padding': '3px',
'border': 'none'
};
var inputFocusStyle = {
'border': 'none',
'outline': 'none'
};
var dropdownIconStyle = {
'background-color': '',
'color': '#17BEBB'
};
var dropdownIconHoverStyle = {
'cursor': 'default',
'background-color': '#9DD9D2',
'color': 'white'
};
this.$el.css(elStyle);
this.$dropbox.css(dropboxStyle);
this.$input.css(inputStyle);
this.$input.on('focus', function() {
$(this).css(inputFocusStyle);
});
this.$dropdownicon
.css(dropdownIconStyle)
.on('mouseenter', function() {
$(this).css(dropdownIconHoverStyle);
})
.on('mouseleave', function() {
$(this).css(dropdownIconStyle);
});
};
this.bindEvents = function() {
this.$dropdownicon.on('click', this.toggleList.bind(this));
this.$li.on('mouseenter', this.toggleHoverItem.bind(this)).on('mouseleave', this.toggleHoverItem.bind(this));
this.$li.on('click', this.itemClickHandler.bind(this));
};
this.itemClickHandler = function(event) {
var itemSelected = $(event.target).closest('li').text();
this.settings.isListOpen = !this.settings.isListOpen;
this.$ul.css('display', 'none');
this.$input.val(itemSelected);
}
this.toggleHoverItem = function(event) {
var itemMouseEnterStyle = {
'background-color': '#9DD9D2',
'color': 'white'
}
var itemMouseLeaveStyle = {
'background-color': 'white',
'color': 'black'
}
var backgroundColor = $(event.target).closest('li').css( "background-color" );
if(backgroundColor == 'rgb(157, 217, 210)')
$(event.target).closest('li').css(itemMouseLeaveStyle);
else
$(event.target).closest('li').css(itemMouseEnterStyle);
};
this.toggleList = function() {
var listOpenStyle = {
'position': 'absolute',
'display': 'block',
'list-style-type': 'none',
'border' : '1px solid #9DD9D2',
'margin': '0',
'padding': '2px 2px 2px 2px',
'left': '0',
'right': '0'
}
var listClosedStyle = {
'display': 'none'
}
this.settings.isListOpen = !this.settings.isListOpen;
if(this.settings.isListOpen)
this.$ul.css(listOpenStyle);
else
this.$ul.css(listClosedStyle);
};
this.render = function() {
var data = {items: this.items};
this.$el.replaceWith(Mustache.render(this.template, data));
this.settings.isRendered = true;
this.cacheDOM();
this.applyStyles();
this.bindEvents();
};
};
var dropdown = new Dropdown();
dropdown.init('city');
dropdown.populateItems(['Munich', 'Oslo', 'Havana']);
dropdown.render();
var dropdown2 = new Dropdown();
dropdown2.init('city2');
dropdown2.populateItems(['Los Angeles', 'Miami', 'Edinburg']);
dropdown2.render();
html, body {
height: 100%;
width: 100%;
overflow: hidden;
font-size: 1em;
font-family: 'Lato', sans-serif;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<span id='city'></span>
<span id='city2'></span>
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
</body>
</html>
Try adding vertical-align:middle; to the div with id 'city' and 'city2'
function Dropdown() {
this.id = '';
this.items = [];
this.settings = {
isRendered: false,
isListOpen: false
};
this.init = function(componentId) {
this.id = componentId;
this.cacheDOM();
};
this.cacheDOM = function() {
this.$el = $('#' + this.id);
if (this.settings.isRendered)
{
this.$input = this.$el.find('input');
this.$dropbox = this.$el.find('div');
this.$dropdownicon = this.$el.find('span:first');
this.$ul = this.$el.find('ul');
this.$li = this.$ul.find('li');
}
this.template = `<div id='`+ this.id +`'>
<div class='dropbox'><input /><span class='material-icons'>expand_more</span></div>
<ul style='display: none'>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
</div>`;
};
this.populateItems = function(items) {
this.items = items;
this.render();
};
this.applyStyles = function() {
var elStyle = {
'display': 'inline-block',
'position': 'relative',
'padding': '0',
'margin': '0','vertical-align':'middle',
};
var dropboxStyle = {
'display' : 'inline-flex',
'border' : '1px solid #9DD9D2'
};
var inputStyle = {
'font': 'inherit',
'padding': '3px',
'border': 'none'
};
var inputFocusStyle = {
'border': 'none',
'outline': 'none'
};
var dropdownIconStyle = {
'background-color': '',
'color': '#17BEBB'
};
var dropdownIconHoverStyle = {
'cursor': 'default',
'background-color': '#9DD9D2',
'color': 'white'
};
this.$el.css(elStyle);
this.$dropbox.css(dropboxStyle);
this.$input.css(inputStyle);
this.$input.on('focus', function() {
$(this).css(inputFocusStyle);
});
this.$dropdownicon
.css(dropdownIconStyle)
.on('mouseenter', function() {
$(this).css(dropdownIconHoverStyle);
})
.on('mouseleave', function() {
$(this).css(dropdownIconStyle);
});
};
this.bindEvents = function() {
this.$dropdownicon.on('click', this.toggleList.bind(this));
this.$li.on('mouseenter', this.toggleHoverItem.bind(this)).on('mouseleave', this.toggleHoverItem.bind(this));
this.$li.on('click', this.itemClickHandler.bind(this));
};
this.itemClickHandler = function(event) {
var itemSelected = $(event.target).closest('li').text();
this.settings.isListOpen = !this.settings.isListOpen;
this.$ul.css('display', 'none');
this.$input.val(itemSelected);
}
this.toggleHoverItem = function(event) {
var itemMouseEnterStyle = {
'background-color': '#9DD9D2',
'color': 'white'
}
var itemMouseLeaveStyle = {
'background-color': 'white',
'color': 'black'
}
var backgroundColor = $(event.target).closest('li').css( "background-color" );
if(backgroundColor == 'rgb(157, 217, 210)')
$(event.target).closest('li').css(itemMouseLeaveStyle);
else
$(event.target).closest('li').css(itemMouseEnterStyle);
};
this.toggleList = function() {
var listOpenStyle = {
'position': 'absolute',
'display': 'block',
'list-style-type': 'none',
'border' : '1px solid #9DD9D2',
'margin': '0',
'padding': '2px 2px 2px 2px',
'left': '0',
'right': '0'
}
var listClosedStyle = {
'display': 'none'
}
this.settings.isListOpen = !this.settings.isListOpen;
if(this.settings.isListOpen)
this.$ul.css(listOpenStyle);
else
this.$ul.css(listClosedStyle);
};
this.render = function() {
var data = {items: this.items};
this.$el.replaceWith(Mustache.render(this.template, data));
this.settings.isRendered = true;
this.cacheDOM();
this.applyStyles();
this.bindEvents();
};
};
var dropdown = new Dropdown();
dropdown.init('city');
dropdown.populateItems(['Munich', 'Oslo', 'Havana']);
dropdown.render();
var dropdown2 = new Dropdown();
dropdown2.init('city2');
dropdown2.populateItems(['Los Angeles', 'Miami', 'Edinburg']);
dropdown2.render();
html, body {
height: 100%;
width: 100%;
overflow: hidden;
font-size: 1em;
font-family: 'Lato', sans-serif;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<span id='city'></span>
<span id='city2'></span>
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
</body>
</html>
Something's fishy with inline-flex. But I overcame the issue by adding: 'vertical-align': 'top' to elStyle:
function Dropdown() {
this.id = '';
this.items = [];
this.settings = {
isRendered: false,
isListOpen: false
};
this.init = function(componentId) {
this.id = componentId;
this.cacheDOM();
};
this.cacheDOM = function() {
this.$el = $('#' + this.id);
if (this.settings.isRendered)
{
this.$input = this.$el.find('input');
this.$dropbox = this.$el.find('div');
this.$dropdownicon = this.$el.find('span:first');
this.$ul = this.$el.find('ul');
this.$li = this.$ul.find('li');
}
this.template = `<div id='`+ this.id +`'>
<div class='dropbox'><input /><span class='material-icons'>expand_more</span></div>
<ul style='display: none'>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
</div>`;
};
this.populateItems = function(items) {
this.items = items;
this.render();
};
this.applyStyles = function() {
var elStyle = {
'display': 'inline-block',
'position': 'relative',
'padding': '0',
'margin': '0',
'vertical-align': 'top'
};
var dropboxStyle = {
'display' : 'inline-flex',
'border' : '1px solid #9DD9D2'
};
var inputStyle = {
'font': 'inherit',
'padding': '3px',
'border': 'none'
};
var inputFocusStyle = {
'border': 'none',
'outline': 'none'
};
var dropdownIconStyle = {
'background-color': '',
'color': '#17BEBB'
};
var dropdownIconHoverStyle = {
'cursor': 'default',
'background-color': '#9DD9D2',
'color': 'white'
};
this.$el.css(elStyle);
this.$dropbox.css(dropboxStyle);
this.$input.css(inputStyle);
this.$input.on('focus', function() {
$(this).css(inputFocusStyle);
});
this.$dropdownicon
.css(dropdownIconStyle)
.on('mouseenter', function() {
$(this).css(dropdownIconHoverStyle);
})
.on('mouseleave', function() {
$(this).css(dropdownIconStyle);
});
};
this.bindEvents = function() {
this.$dropdownicon.on('click', this.toggleList.bind(this));
this.$li.on('mouseenter', this.toggleHoverItem.bind(this)).on('mouseleave', this.toggleHoverItem.bind(this));
this.$li.on('click', this.itemClickHandler.bind(this));
};
this.itemClickHandler = function(event) {
var itemSelected = $(event.target).closest('li').text();
this.settings.isListOpen = !this.settings.isListOpen;
this.$ul.css('display', 'none');
this.$input.val(itemSelected);
}
this.toggleHoverItem = function(event) {
var itemMouseEnterStyle = {
'background-color': '#9DD9D2',
'color': 'white'
}
var itemMouseLeaveStyle = {
'background-color': 'white',
'color': 'black'
}
var backgroundColor = $(event.target).closest('li').css( "background-color" );
if(backgroundColor == 'rgb(157, 217, 210)')
$(event.target).closest('li').css(itemMouseLeaveStyle);
else
$(event.target).closest('li').css(itemMouseEnterStyle);
};
this.toggleList = function() {
var listOpenStyle = {
'position': 'absolute',
'display': 'block',
'list-style-type': 'none',
'border' : '1px solid #9DD9D2',
'margin': '0',
'padding': '2px 2px 2px 2px',
'left': '0',
'right': '0'
}
var listClosedStyle = {
'display': 'none'
}
this.settings.isListOpen = !this.settings.isListOpen;
if(this.settings.isListOpen)
this.$ul.css(listOpenStyle);
else
this.$ul.css(listClosedStyle);
};
this.render = function() {
var data = {items: this.items};
this.$el.replaceWith(Mustache.render(this.template, data));
this.settings.isRendered = true;
this.cacheDOM();
this.applyStyles();
this.bindEvents();
};
};
var dropdown = new Dropdown();
dropdown.init('city');
dropdown.populateItems(['Munich', 'Oslo', 'Havana']);
dropdown.render();
var dropdown2 = new Dropdown();
dropdown2.init('city2');
dropdown2.populateItems(['Los Angeles', 'Miami', 'Edinburg']);
dropdown2.render();
html, body {
height: 100%;
width: 100%;
overflow: hidden;
font-size: 1em;
font-family: 'Lato', sans-serif;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<span id='city'></span>
<span id='city2'></span>
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
</body>
</html>
I am new to jointJs library and I am trying to add ports to my custom element that contains html code in it. I followed this tutorial (http://www.jointjs.com/tutorial/html-elements) and created my element. But when I try to add ports to it (based on this tutorial: http://www.jointjs.com/tutorial/ports) it does not work.
Another problem I have is that I want the textbox(textarea on my custom shape) to disappear when I click on the blank paper, and just the label with its content stays visible on the element. For that I used the following piece of code (but it does not give me the above-mentioned functionality):
paper.on('blank:pointerdown', function(evt, x, y) { this.$box.find('textarea').toBack(); });
this.model.on('cell:pointerclick', function(evt, x, y) {this.$box.find('textarea').toFront();});
My whole code is as below:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="graph.css">
<script type="text/javascript" src="http://www.jointjs.com/downloads/joint.js" ></script>
<script src="http://www.jointjs.com/downloads/joint.shapes.devs.js" ></script>
<script src="http://www.jointjs.com/downloads/joint.shapes.devs.min.js" ></script>
</head>
<title>Test</title>
<body>
<div id="myholder"></div>
</body>
<script>
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: $('#myholder'),
width: 1500,
height: 700,
model: graph
});
// Create a custom element.
// ------------------------
joint.shapes.html = {};
joint.shapes.html.Element = joint.shapes.basic.Rect.extend({
defaults: joint.util.deepSupplement({
type: 'html.Element',
attrs: {
rect: { stroke: 'none', 'fill-opacity': 0 }
}
}, joint.shapes.basic.Rect.prototype.defaults)
});
// Create a custom view for that element that displays an HTML div above it.
// -------------------------------------------------------------------------
joint.shapes.html.ElementView = joint.dia.ElementView.extend({
template: [
'<div class="html-element">',
'<button class="delete">x</button>',
'<span id="lbl" value="Please write here"></span>',
'<textarea id="txt" type="text" value="Please write here"></textarea>',
'</div>'
].join(''),
initialize: function() {
_.bindAll(this, 'updateBox');
joint.dia.ElementView.prototype.initialize.apply(this, arguments);
this.$box = $(_.template(this.template)());
// Prevent paper from handling pointerdown.
this.$box.find('input,select').on('mousedown click', function(evt) { evt.stopPropagation(); });
// This is an example of reacting on the input change and storing the input data in the cell model.
this.$box.find('textarea').on('change', _.bind(function(evt) {
this.model.set('textarea', $(evt.target).val());
}, this));
this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
// Update the box position whenever the underlying model changes.
this.model.on('change', this.updateBox, this);
// Remove the box when the model gets removed from the graph.
this.model.on('remove', this.removeBox, this);
this.updateBox();
},
render: function() {
joint.dia.ElementView.prototype.render.apply(this, arguments);
this.paper.$el.prepend(this.$box);
this.updateBox();
return this;
},
updateBox: function() {
// Set the position and dimension of the box so that it covers the JointJS element.
var bbox = this.model.getBBox();
// Example of updating the HTML with a data stored in the cell model.
paper.on('blank:pointerdown', function(evt, x, y) { this.$box.find('textarea').toBack(); });
this.$box.find('span').text(this.model.get('textarea'));
this.model.on('cell:pointerclick', function(evt, x, y) { this.$box.find('textarea').toFront(); });
this.$box.css({ width: bbox.width, height: bbox.height, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' });
},
removeBox: function(evt) {
this.$box.remove();
}
});
// Create JointJS elements and add them to the graph as usual.
// -----------------------------------------------------------
var el1 = new joint.shapes.html.Element({
position: { x: 600, y: 250 },
size: { width: 200, height: 100 },
inPorts: ['in'],
outPorts: ['out'],
attrs: {
'.inPorts circle': { fill: 'gray'},
'.outPorts circle': { fill: 'gray'}
},
textarea: 'Start writing'});
graph.addCells([el1]);
paper.on('cell:pointerdblclick', function(cellView, evt, x, y) {
var el2 = new joint.shapes.html.Element({ position: { x: 600, y: 400 }, size: { width: 200, height: 100 }, textarea: 'Start writing'});
var l = new joint.dia.Link({
source: { id: el1.id },
target: { id: el2.id },
attrs: { '.connection': { 'stroke-width': 1, stroke: 'gray' } }
});
graph.addCells([el2, l]);
});
</script>
</html>
I have searched a lot for answers to these problems but I was not successful finding simple and comprehensive ones.
Any help will be appreciated.
Thanks.
I am also new to jointJs and stuck with same problem and found this thread. I have tried and worked successfully.
You have to customize css of element to get better view. Go to working with ports for more work with ports.
Here's the code:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://www.jointjs.com/downloads/joint.min.css">
<style type="text/css">
#myholder .html-element{
position: absolute;
margin-left: 8px;
padding: 5px 0 10px 0;
background-color: #fff;
border: 1px solid #eee;
border-radius: 5px;
pointer-events: none;
-webkit-user-select: none;
}
</style>
<script type="text/javascript" src="http://www.jointjs.com/downloads/joint.min.js" ></script>
</head>
<title>Test</title>
<body>
<div id="myholder"></div>
</body>
<script>
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: $('#myholder'),
width: 1500,
height: 700,
model: graph
});
// Create a custom element.
// ------------------------
joint.shapes.html = {};
joint.shapes.html.Element = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
markup: '<g class="rotatable"><g class="scalable"><rect/></g><g class="inPorts"/><g class="outPorts"/></g>',
portMarkup: '<g class="port<%= id %>"><circle/></g>',
defaults: joint.util.deepSupplement({
type: 'html.Element',
size: { width: 100, height: 80 },
inPorts: [],
outPorts: [],
attrs: {
'.': { magnet: false },
rect: {
stroke: 'none', 'fill-opacity': 0, width: 150, height: 250,
},
circle: {
r: 6, //circle radius
magnet: true,
stroke: 'black'
},
'.inPorts circle': { fill: 'green', magnet: 'passive', type: 'input'},
'.outPorts circle': { fill: 'red', type: 'output'}
}
}, joint.shapes.basic.Generic.prototype.defaults),
getPortAttrs: function (portName, index, total, selector, type) {
var attrs = {};
var portClass = 'port' + index;
var portSelector = selector + '>.' + portClass;
var portCircleSelector = portSelector + '>circle';
attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type), type: type } };
attrs[portSelector] = { ref: 'rect', 'ref-y': (index + 0.5) * (1 / total) };
if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
return attrs;
}
}));
// Create a custom view for that element that displays an HTML div above it.
// -------------------------------------------------------------------------
joint.shapes.html.ElementView = joint.dia.ElementView.extend({
template: [
'<div class="html-element">',
'<button class="delete">x</button>',
'<span id="lbl" value="Please write here"></span>',
'<textarea id="txt" type="text" value="Please write here"></textarea>',
'</div>'
].join(''),
initialize: function() {
_.bindAll(this, 'updateBox');
joint.dia.ElementView.prototype.initialize.apply(this, arguments);
this.$box = $(_.template(this.template)());
// Prevent paper from handling pointerdown.
this.$box.find('input,select').on('mousedown click', function(evt) { evt.stopPropagation(); });
// This is an example of reacting on the input change and storing the input data in the cell model.
this.$box.find('textarea').on('change', _.bind(function(evt) {
this.model.set('textarea', $(evt.target).val());
}, this));
this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
// Update the box position whenever the underlying model changes.
this.model.on('change', this.updateBox, this);
// Remove the box when the model gets removed from the graph.
this.model.on('remove', this.removeBox, this);
this.updateBox();
this.listenTo(this.model, 'process:ports', this.update);
joint.dia.ElementView.prototype.initialize.apply(this, arguments);
},
render: function() {
joint.dia.ElementView.prototype.render.apply(this, arguments);
this.paper.$el.prepend(this.$box);
// this.paper.$el.mousemove(this.onMouseMove.bind(this)), this.paper.$el.mouseup(this.onMouseUp.bind(this));
this.updateBox();
return this;
},
renderPorts: function () {
var $inPorts = this.$('.inPorts').empty();
var $outPorts = this.$('.outPorts').empty();
var portTemplate = _.template(this.model.portMarkup);
_.each(_.filter(this.model.ports, function (p) { return p.type === 'in' }), function (port, index) {
$inPorts.append(V(portTemplate({ id: index, port: port })).node);
});
_.each(_.filter(this.model.ports, function (p) { return p.type === 'out' }), function (port, index) {
$outPorts.append(V(portTemplate({ id: index, port: port })).node);
});
},
update: function () {
// First render ports so that `attrs` can be applied to those newly created DOM elements
// in `ElementView.prototype.update()`.
this.renderPorts();
joint.dia.ElementView.prototype.update.apply(this, arguments);
},
updateBox: function() {
// Set the position and dimension of the box so that it covers the JointJS element.
var bbox = this.model.getBBox();
// Example of updating the HTML with a data stored in the cell model.
// paper.on('blank:pointerdown', function(evt, x, y) { this.$box.find('textarea').toBack(); });
this.$box.find('span').text(this.model.get('textarea'));
this.model.on('cell:pointerclick', function(evt, x, y) { this.$box.find('textarea').toFront(); });
this.$box.css({ width: bbox.width, height: bbox.height, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' });
},
removeBox: function(evt) {
this.$box.remove();
}
});
// Create JointJS elements and add them to the graph as usual.
// -----------------------------------------------------------
var el1 = new joint.shapes.html.Element({
position: { x: 600, y: 250 },
size: { width: 170, height: 100 },
inPorts: ['in'],
outPorts: ['out'],
textarea: 'Start writing'
});
var el2 = new joint.shapes.html.Element({
position: { x: 600, y: 400 },
size: { width: 170, height: 100 },
inPorts: ['in'],
outPorts: ['out'],
textarea: 'Start writing'
});
graph.addCells([el1, el2]);
</script>
</html>
I have asked a question that no one has answered it. It was how I can make the textarea disappear when I click on the blank paper and appear when I click on the cell: First I thought I have to solve it through the jsonJS events inside the javascript. But I found out that there is a very simple solution for this. I just need to use the hover function in css styling and change the opacity from 0 to 1 when you hover over the box (in your css file) :
.html-element textarea {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 60px;
width: 150px;
border: none;
color: #333;
background-color: white;
padding: 5px;
margin: 5px;
opacity:0;
}
.html-element textarea:hover {
opacity:1;
}
rzkmr's answer worked for me, +1'd his response. (Thank you!)
In his example, to allow the textarea to be used, add this to the css:
.html-element select,
.html-element input,
.html-element textarea,
.html-element button {
/* Enable mouse interaction. */
pointer-events: auto;
}
I want to show an activity indicator in my screen using Titanium but it is not showing me any result. It is not showing any progress sign.
Here is my code:
var actInd = Titanium.UI.createActivityIndicator();
actInd.message = 'Please wait...';
//message will only shows in android.
var self = Ti.UI.createWindow({
title : "About",
navBarHidden : false,
barColor : "#50b849",
backgroundColor : "#2d2d2d",
});
self.add(actInd);
actInd.show();
self.orientationModes = [Titanium.UI.PORTRAIT];
var text = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory + "info.txt").read();
var infoText = Ti.UI.createTextArea({
width : "100%",
height : "100%",
color : "#fff",
backgroundColor : "#2d2d2d",
value : text,
editable : false,
scrollable : false,
font : {
fontWeight : 'bold',
fontSize : 20,
fontFamily : 'Helvetica Neue'
},
textAlign : Ti.UI.TEXT_ALIGNMENT_CENTER,
autoLink : Ti.UI.AUTODETECT_LINK
});
infoText.addEventListener("click", function() {
Ti.Platform.openURL("http://tellusanotherone.org/c2p");
});
var scrollView = Ti.UI.createScrollView({
width : "100%",
height : "100%",
verticalBounce : true,
scrollType : "vertical",
});
scrollView.add(infoText);
self.add(infoText);
return self;
Thanks in advance.
Just create file (lib/indicator.js) and add the following code int it
function createIndicatorWindow(args) {
var width = 180,
height = 50;
var args = args || {};
var top = args.top || 140;
var text = args.text || 'Loading ...';
var win = Titanium.UI.createWindow({
height: height,
width: width,
top: top,
borderRadius: 10,
touchEnabled: false,
backgroundColor: '#000',
opacity: 0.6
});
var view = Ti.UI.createView({
width: Ti.UI.SIZE,
height: Ti.UI.FILL,
center: { x: (width/2), y: (height/2) },
layout: 'horizontal'
});
var style;
if (Ti.Platform.name === 'iPhone OS') {
style = Ti.UI.iPhone.ActivityIndicatorStyle.PLAIN;
} else {
style = Ti.UI.ActivityIndicatorStyle.DARK;
}
var activityIndicator = Ti.UI.createActivityIndicator({
style : style,
height : Ti.UI.FILL,
width : 30
});
var label = Titanium.UI.createLabel({
left: 10,
width: Ti.UI.FILL,
height: Ti.UI.FILL,
text: text,
color: '#fff',
font: { fontFamily: 'Helvetica Neue', fontSize: 16, fontWeight: 'bold' }
});
view.add(activityIndicator);
view.add(label);
win.add(view);
function openIndicator() {
win.open();
activityIndicator.show();
}
win.openIndicator = openIndicator;
function closeIndicator() {
activityIndicator.hide();
win.close();
}
win.closeIndicator = closeIndicator;
return win;
}
// Public interface
exports.createIndicatorWindow = createIndicatorWindow
Use in your code like this
var uie = require('lib/indicator');
var indicator = uie.createIndicatorWindow();
someViewObject.addEventListener('click', function(e) {
indicator.openIndicator();
setTimeout(function() {
// Do the work that takes a while
// and requires an activity indicator
indicator.closeIndicator();
},0);
});