I would to create a menu with the following appearance:
I have managed to create the background color using css and the rounded corners as well.
I am now attempting to add the top arrow.
How can I add an element to the menu itself (the arrow), and shift its original open position?
You can modify the renderTpl of the menu to include the triangle at the top. I would recommend creating a class which extends Ext.menu.Menu. See this example.
Ext.define('Ext.menu.TriangleMenu', {
extend: 'Ext.menu.Menu',
initComponent: function () {
//get the original template
var originalTpl = Ext.XTemplate.getTpl(this, 'renderTpl');
//add the triangle div (or img, span, etc.)
this.renderTpl = new Ext.XTemplate([
'<div class="menu-triangle"></div>',
originalTpl.html, //the html from the original tpl
originalTpl.initialConfig //the config options from the original tpl
]);
this.callParent();
},
beforeSetPosition: function () {
//shift the menu down from its original position
var pos = this.callParent(arguments);
if (pos) {
pos.y += 5; //the offset (should be the height of your triangle)
}
return pos;
}
});
How you render the triangle is entirely up to you. You can do it without having to use an image by using this neat little border trick.
.menu-triangle {
height: 0;
width: 0;
border-bottom: 5px solid black;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
}
Related
I have a big svg tag, with lots of svg polygons, line, text inside it making a 2D map, which need overflow to see it full size on screen, something like that:
I need a way to print it from broswer when I click "print" or use "ctrl + p", but for that i need to break it into pieces and put then on column layout, so they can fit on A4 size to print the entire content, something like that:
When I try to print i get this:
So, I need a way to break this svg field into pieces to fit the page to print.
Is there any way to do that, using js, css, anything? Thank you!
There is no way to do what you want with pure CSS.
You'll need Javascript to create the split sections of the SVG.
Here's some demonstration code. I've left comments in the code to explain how it works.
The example uses a checkbox to simulate "print mode" but you could run the split and unsplit functions automatically, when printing, by listening to the beforeprint and afterprint events.
https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeprint
function splitSVGs(splitWidth) {
let splittables = document.querySelectorAll(".splittable");
splittables.forEach(function(svgElem) {
// Get starting size of the original SVG now
const computed = getComputedStyle(svgElem);
const width = parseInt(computed.width, 10);
const height = parseInt(computed.height, 10);
const vB = svgElem.viewBox.baseVal;
// Get the viewBox of the SVG also
const bbox = (svgElem.getAttribute("viewBox") !== null) ? {x:vB.x, y:vB.y, width:vB.width, height:vB.height}
: {x:0, y:0, width, height};
// Hide the original SVG
svgElem.classList.add("hide");
// Create a temporary div element to hold our generated sections
const div = document.createElement("div");
div.classList.add("sections");
svgElem.insertAdjacentElement('afterend', div);
let remainingWidth = width;
while (remainingWidth > 0) {
const sectionWidth = Math.min(splitWidth, remainingWidth);
// Convert sectionWidth relative to viewBox
bbox.width = sectionWidth * bbox.height / height;
// Create an SVG element to contain one section of the split
const section = document.createElementNS("http://www.w3.org/2000/svg", "svg");
section.setAttribute("width", sectionWidth);
// Add a viewBox that shows the area of the original that we want to see in this section
section.setAttribute("viewBox", [bbox.x, bbox.y, bbox.width, bbox.height].join(' '));
// Add a <use> element to the section SVG that references the original
const use = document.createElementNS("http://www.w3.org/2000/svg", "use");
use.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", '#'+svgElem.id);
use.setAttribute("width", vB.width);
use.setAttribute("height", vB.height);
section.appendChild(use);
// Add this section SVG to the sections div
div.appendChild(section);
// How much of the original SVG width is left?
remainingWidth -= splitWidth;
// Update bbox so the next SVG will show the next section of the original
bbox.x += bbox.width;
}
});
}
function unsplitSVGs() {
// Get rid of the generated sections
const sections = document.querySelectorAll(".sections");
sections.forEach(function(div) {
div.remove();
});
// Unhide all the original SVGs
const splittables = document.querySelectorAll(".splittable");
splittables.forEach(function(svgElem) {
svgElem.classList.remove("hide");
});
}
document.getElementById("print-mode").addEventListener("change", function(evt) {
if (evt.target.checked) {
splitSVGs(600);
} else {
unsplitSVGs();
}
});
svg {
background: linen;
}
svg#test {
width: 2960px;
height: 80px;
border: solid 2px black;
}
/* Hide while still keeping the contents visible to our section SVGs */
.hide {
position: absolute;
top: -9999px;
}
.sections svg {
border: solid 2px black;
}
.sections svg:not(:first-child) {
border-left: dashed 2px black;
}
.sections svg:not(:last-child) {
border-right: dashed 2px black;
}
<p>
<input type="checkbox" id="print-mode">
<label for="print-mode"> Simulate print mode (split the SVG)</label>
</p>
<svg viewBox="0 0 1480 40" id="test" class="splittable">
<text x="10" y="30" font-size="30px">We choose to go to the Moon in this decade and do the other things, not because they are easy, but because they are hard.</text>
</svg>
I am struggling since 2 days with something I was thinking easy, on a map, I have to display a marker for each user with the user FB profile picture inside.
I am wondering how I can have a result similar to this one? What I tried was really hackish.
I put the FB picture as the marker icon
I put a CSS class on the label of the marker
I find the sibling to add this border and this arrow to decorate the user picture
but it doesn't work when there is more than one marker on the map.
.marker-labels {
display: none !important;
+ div {
background-color: $dark-gray;
border: 2px solid $dark-gray;
#include radius(0.2em);
height: 54px !important;
width: 54px !important;
overflow: inherit !important;
> img {
height: 50px;
width: 50px;
}
&:after {
content: ' ';
height: 0;
width: 0;
border: 6px solid transparent;
border-top-color: $dark-gray;
position: absolute;
top: 52px;
left: 19px;
}
}
}
global question:
how can I get an icon like that (http://mt-st.rfclipart.com/image/thumbnail/24-1d-5f/blue-glossy-square-map-pin-or-speech-bubble-Download-Royalty-free-Vector-File-EPS-29153.jpg for instance) with a custom user picture inside? is it possible?
otherwise how is it possible to customize the icon (if it is the profile picture) to have a result similar to the screenshot
thanks for your help
This answer assumes you already have the URIs for the facebook profile images. Honestly, it feels there is an easier way, but I found some code that shows how to create a custom marker with custom HTML elements and I went from there. From there's it's pretty easy to create a custom marker that accepts a image URI as a parameter. From the original, I just added an imageSrc parameter, moved the styling outside the code by attaching a class name to the new div. In terms of html and css, I just appended an image with the passed image URI into the div, and just added some CSS to make it look like what you have.
Demo
So the javascript code looks something like this:
function CustomMarker(latlng, map, imageSrc) {
this.latlng_ = latlng;
this.imageSrc = imageSrc; //added imageSrc
this.setMap(map);
}
CustomMarker.prototype = new google.maps.OverlayView();
CustomMarker.prototype.draw = function () {
// Check if the div has been created.
var div = this.div_;
if (!div) {
// Create a overlay text DIV
div = this.div_ = document.createElement('div');
// Create the DIV representing our CustomMarker
div.className = "customMarker" //replaced styles with className
var img = document.createElement("img");
img.src = this.imageSrc; //attach passed image uri
div.appendChild(img);
google.maps.event.addDomListener(div, "click", function (event) {
google.maps.event.trigger(me, "click");
});
// Then add the overlay to the DOM
var panes = this.getPanes();
panes.overlayImage.appendChild(div);
}
// Position the overlay
var point = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (point) {
div.style.left = point.x + 'px';
div.style.top = point.y + 'px';
}
};
CustomMarker.prototype.remove = function () {
// Check if the overlay was on the map and needs to be removed.
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
CustomMarker.prototype.getPosition = function () {
return this.latlng_;
};
I think I added only one or two lines here. You can just add this to your page I think. With this in place you can just style the container as normal, and it should apply to all the custom markers. You can add elements and classes as you see fit to achieve the look you are looking for. But for completion's sake I added the styles I used for the demo here.
.customMarker { /* the marker div */
position:absolute;
cursor:pointer;
background:#424242;
width:100px;
height:100px;
/* we'll offset the div so that
the point passed doesn't end up at
the upper left corner but at the bottom
middle. so we'll move it left by width/2 and
up by height+arrow-height */
margin-left:-50px;
margin-top:-110px;
border-radius:10px;
padding:0px;
}
.customMarker:after { //triangle
content:"";
position: absolute;
bottom: -10px;
left: 40px;
border-width: 10px 10px 0;
border-style: solid;
border-color: #424242 transparent;
display: block;
width: 0;
}
.customMarker img { //profile image
width:90px;
height:90px;
margin:5px;
border-radius:2px;
}
And for the demo I have some sample data in array and placed them on the map using a for loop.
var data = [{
profileImage: "http://domain.com/image1.jpg",
pos: [37.77, -122.41],
}, {
profileImage: "http://domain.com/image2.jpg",
pos: [37.77, -122.41],
}]
for(var i=0;i<data.length;i++){
new CustomMarker(
new google.maps.LatLng(data[i].pos[0],data[i].pos[1]),
map,
data[i].profileImage
)
}
I hope that helps.
I am trying to code a vertical slider in enyo (Like a control on mixing desk). I was trying to avoid starting from scratch so I started tweaking the onyx.Slider class. I changed to styles from left to top and from width to height and with a few other tweaks, it's working. I'm now stuck on getting the slider to fill from bottom to top as at the minute it is vertical but it fills from the top down. Thanks in advance for any help.
Here are the code changes I have done:
in ProgressBar.js:
updateBarPosition: function(inPercent) {
this.$.bar.applyStyle("height", inPercent + "%");
},
in Slider.js (dividing by 64 is a temporary hack):
valueChanged: function() {
this.value = this.clampValue(this.min, this.max, this.value);
var p = this.calcPercent(this.value);
this.updateKnobPosition(p/64);
if (this.lockBar) {
this.setProgress(this.value);
}
},
updateKnobPosition: function(inPercent) {
this.$.knob.applyStyle("top", inPercent + "%");
},
calcKnobPosition: function(inEvent) {
var y = inEvent.clientY - this.hasNode().getBoundingClientRect().top;
return (y / this.getBounds().height) * (this.max - this.min) + this.min;
},
CSS:
/* ProgressBar.css */
.onyx-progress-bar {
margin: 8px;
height: 400px;
width: 8px;
border: 1px solid rgba(15, 15, 15, 0.2);
border-radius: 3px;
background: #b8b8b8 url(./../images/gradient-invert.png) repeat-x;
background-size: auto 100%;
}
.onyx-progress-bar-bar {
height: 100%;
border-radius: 3px;
background: #58abef url(./../images/gradient.png) repeat-x;
background-size: auto 100%;
}
Tom
There are a couple of approaches you could take. The most obvious (except for the fact it didn't occur to me first) is just to swap the background/gradient of the bar and the bar-bar. This will give you the appearance of filling from the bottom. I would recommend this.
The other method is what I did in this jsFiddle here: http://jsfiddle.net/RoySutton/b9PmA/ (Do ignore the doubled updateBarPosition function)
Instead of modifying those files directly, I derived from Slider and overrode the appropriate functions and added a new class for the vertical slider.
I changed the 'fill' to be absolutely positioned within the slider.
Now, your next problem is that value '0' is fully filled and '100' is fully empty. I handled that by modifying your calcKnobPosition to adjust from max and inverting the positioning logic as seen in this fiddle here: http://jsfiddle.net/RoySutton/b9PmA/2/
return this.max - (y / this.getBounds().height) * (this.max - this.min);
The source is here http://jsfiddle.net/4fV3k/
I have a function SetGridBorder which take style of border like 1px solid red and selector of wrapper like box-wrapper.
As my example code 4 rows is lived in a row so their is 4 cols and 4 rows. How I can determine it in JavaScript. I want to set the border in this rules.
the 2 and 3 in first row have missing left and right border (so this is not duplicate border).
2nd and third column (middles rows) have missing top and bottom border so no duplicate border for here also.
How I can do it in JavaScript? Do someone have suggestion for how to do it better?
$(document).ready(function () {
var box_wrapper = $(".box-box-wrapper", ".box");
SetGridBorder(4,4)
});
function SetGridBorder(style,selector) {
}
You can get how many rows and columns by divide wrapper width and height to box width and height. In your example wrapper height was zero, so i added overflow:auto; to body .box-wrapper class. Updated fiddle at http://jsfiddle.net/4fV3k/7/
function getRows() {
var wrapperWidth = $(".box-wrapper").width();
var boxWidth = $(".box-wrapper > div").width();
return Math.floor(wrapperWidth / boxWidth);
}
function getColumns() {
var wrapperHeight = $(".box-wrapper").height();
var boxHeight = $(".box-wrapper > div").height();
return Math.floor(wrapperHeight / boxHeight);
}
FYI.
body .box {
width: 128px;
height: 128px;
float: left;
text-align: center;
border:solid 1px #555;
}
$(document).ready(function () {
$.each($(".box"),function(i,n){
if((i+1)%4!=0){
$(n).css({'border-right':'none'})
}
if((i+1)>4){
$(n).css({'border-top':'none'})
}
});
});
Basically I want to split a square div diagonally in two resulting in two triangles.
Each triangle has to respond to the hover event.
This is what I have so far but the problem is: if you go from one corner of the div straight to the opposite corner it doesn't re-trigger the hover event since the event is applied to the div element and not the define triangle area within.
I'm open to any suggestions, I don't even mind if I need to approach the problem from a different angle all together. There's got to be an easier solution, at least I hope!
The HTML
<div class="day_box">
</div>
The CSS
html, body { margin: 0; }
.day_box, .upper_left_hover, .lower_right_hover, .full_day {
background: url(/images/corner-sprites.png);
border: 1px solid black;
width: 25px;
height: 25px;
float: left;
margin: 100px;
}
.upper_left_hover { background-position: 75px 0; }
.lower_right_hover { background-position: 50px 0; }
.full_day { background-position: 25px 0; }
The JS
$(".day_box").hover(function(event){
var offset = $(this).offset();
var h = $(this).height() + offset.top;
if((h - event.pageY)>(event.pageX - offset.left)) {
console.log("Upper left");
$(this).toggleClass("upper_left_hover");
} else {
console.log("Lower right");
$(this).toggleClass("lower_right_hover");
}
});
The Fiddle: http://jsfiddle.net/zsay6/
You can use the mousemove event like this (adding mouseout to remove both of the classes when you leave the square):
$(".day_box").mousemove(function(event){
var offset = $(this).offset();
var h = $(this).height() + offset.top;
if((h - event.pageY)>(event.pageX - offset.left)) {
console.log("Upper left");
$(this).removeClass("lower_right_hover");
$(this).addClass("upper_left_hover");
} else if ((h - event.pageY)<(event.pageX - offset.left)) {
console.log("Lower right");
$(this).removeClass("upper_left_hover");
$(this).addClass("lower_right_hover");
}
}).mouseout(function(event)
{
$(this).removeClass("lower_right_hover upper_left_hover");
});
http://jsfiddle.net/zsay6/14/
I altered your fiddle to produce the effect you wanted... and I didn't clean it up at all (was just fiddling... haha)
Using the right-triangle formula (here), I set the given style you set up in your original fiddle. It also throws up some values in a debugging div so you can see it in action a little more clearly.
You can also use HTML map areas for that purpose:
http://www.w3schools.com/tags/tag_map.asp
On hover, change the background of the element to which the usemap is applied.