Related
For my dev lessons, I need to create a social network for a company.
One of the functionalities is to display the comment number linked to a publication (a bit like on Facebook).
To get the comments, I am using vueX to get all data from one source. So, to display the comment count number, here is my idea : for each publication contained in an array, I get all publication comments in another array. So, if I do a {{comments.length}}, for example, this should display "3 comments"
So I wrote the following code :
<div v-if="publications.length > 0">
<AddPostForm />
<section
v-for="post in publications"
:key="post.postId"
class="publications"
>
<div v-bind:data-id="post.postId" class="publications__card">
<div class="publications__author" :data-user-id="post.userId">
<img :src="post.avatarUrl" alt="Photo de profil" />
<span
class="publications__author-profile"
#click="goToProfile(post.userId)"
>
{{ post.firstName }} {{ post.lastName }}
</span>
</div>
<div
class="publications__content"
v-if="post.postContent !== null && post.postContent !== ''"
>
<p>{{ post.postContent }}</p>
</div>
<div
class="publications__content"
v-else-if="
post.postContent === null ||
(post.postContent === '' &&
(post.imageUrl !== null || post.imageUrl !== ''))
"
>
<img :src="post.imageUrl" alt="Image de publication" />
</div>
<div
class="publications__content"
v-else-if="
(post.postContent !== null || post.postContent !== '') &&
(post.imageUrl !== null || post.imageUrl !== '')
"
>
<p>{{ post.postContent }}</p>
<img :src="post.imageUrl" alt="Image de publication" />
</div>
<div class="publications__date-time">
<p>PubliƩ le {{ post.post_date }}</p>
</div>
<div class="publications__delete" v-if="user.admin === 1">
<p class="publications__delete-txt" #click="deletePost(post.postId)">
Supprimer
</p>
</div>
<div
class="publications__like-comment-count"
v-if="post.comment_count > 0"
>
<div
class="publications__comment-count"
#click="goToComments(post.userId, post.postId)"
v-if="comments.length === 1"
>
{{ comments.length }} commentaire
</div>
<div
class="publications__comment-count"
#click="goToComments(post.userId, post.postId)"
v-else
>
{{ comments.length }} commentaires
</div>
</div>
<div class="publications__like-comment">
<div class="like-comment__like">
<FaSolidHeart />
<span class="icon__legend"> J'aime</span>
</div>
<div class="like-comment__comment" #click="comment = true">
<FaSolidComment />
<span
class="icon__legend"
#click="goToComments(post.userId, post.postId)"
> Commenter</span
>
</div>
</div>
</div>
</section>
</div>
<div v-else-if="publications.length === 0">
<p>Aucune publication pour le moment</p>
</div>
</template>
<script>
import axios from 'axios';
import { mapState } from 'vuex';
import FaSolidHeart from './Heart.vue';
import FaSolidComment from './CommentIcon.vue';
import AddPostForm from './AddPost.vue';
const userSessionData = JSON.parse(localStorage.getItem('userSession'));
const sessionToken = userSessionData.token;
if (sessionToken) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + sessionToken;
}
export default {
name: 'Wall',
components: {
FaSolidHeart,
FaSolidComment,
AddPostForm
},
data() {
return {
comment: false,
user: []
};
},
beforeMount() {
this.getResult();
this.getSession();
},
methods: {
getResult: function () {
this.$store.dispatch('setPublications');
},
goToProfile: function (userId) {
this.$router.push(`/profile/${userId}`);
},
goToComments: function (userId, postId) {
this.$router.push(`/comments/${userId}/${postId}`);
},
getSession: function () {
if (localStorage.userSession) {
this.user = JSON.parse(localStorage.userSession);
}
},
deletePost: function (postId) {
axios
.delete(`http://localhost:3000/api/publications/${postId}`)
.then(() => this.$router.go())
.catch((error) => console.log(error));
},
getComments: function (postId) {
// this.$store.dispatch('getPublicationComments', postId);
console.log(postId);
}
},
computed: {
...mapState(['publications', 'comments'])
}
};
</script>
<style scoped>
.publications {
width: 30%;
margin: 10px auto;
}
.publications__card {
width: 99%;
padding: 10px;
padding-left: 15px;
display: flex;
flex-direction: column;
justify-content: center;
background-color: rgba(138, 185, 241, 0.4);
}
.publications__card .publications__author:hover {
cursor: pointer;
}
.publications__card .publications__date-time {
margin-top: -20px;
font-size: 0.8rem;
color: grey;
}
.publications__card .publications__delete .publications__delete-txt {
margin-top: -5px;
font-size: 0.85rem;
}
.publications__card .publications__like-comment-count {
width: 92%;
height: fit-content;
margin: auto 0;
padding: 5px;
border-top: 1px solid white;
}
.publications__card .publications__comment-count {
margin-right: 15px;
text-align: right;
}
.publications__card .publications__like-comment {
width: 95%;
height: fit-content;
margin: auto 0;
padding-top: 10px;
display: flex;
justify-content: space-around;
border-top: 1px solid white;
}
.publications__card .like-comment__like:hover,
.publications__card .like-comment__comment:hover,
.publications__card .publications__comment-count:hover,
.publications__card .publications__delete .publications__delete-txt:hover {
cursor: pointer;
color: #4b77be;
}
.publications__card .publications__add-comment {
width: 95%;
padding-top: 5px;
border-top: 1px solid white;
}
.publications__card .publications__add-comment .add-comment__field {
width: 98%;
height: 25px;
margin-top: 5px;
padding-top: 0px;
padding: 13px;
border-radius: 50px;
resize: none;
font-family: 'poppins';
outline: none;
}
</style>
My question is how may I call the getComments function from the HTML so that I can display comment count number properly ?
Thank you so much for your help :)
You can simply do {{ getComments() }} in your markup.
I am not sure if this will work, but if you store the comments in vuex, you can use this:
<p>{{ this.$store.state.comments.length }}<p>
This only works if the comments is correctly stored in vuex, I hope this will work for you.
I try to implement a table with large size of data. then due to the performance issue, I just want to render the data in the body window.
But the new render element border disappear.
HTML:
<script src="//unpkg.com/vue#2.5.15/dist/vue.js"></script>
<script type="text/x-template" id="list-template">
<div class='table-body' ref="body" #scroll="handleScroll">
<div class="list-view">
<div
class="list-view-phantom"
:style="{
height: contentHeight
}">
</div>
<div class="list-view-colgroup">
<div class="list-view-item-col-g" v-for='count in 5'>
</div>
</div>
<div
ref="content"
class="list-view-content">
<ul
class="list-view-item"
:style="{
height: itemHeight + 'px'
}"
v-for="item in visibleData" :key='item.value'>
<li class="list-view-item-col" v-for='count in 5'>
{{item.value+count}}
</li>
</ul>
</div>
</div>
</div>
</script>
<div id="app">
<template>
<list-view :data="data"></list-view>
</template>
</div>
JS:
const ListView = {
name: 'ListView',
template: '#list-template',
props: {
data: {
type: Array,
required: true
},
itemHeight: {
type: Number,
default: 30
}
},
computed: {
contentHeight() {
return this.data.length * this.itemHeight + 'px';
}
},
mounted() {
this.updateVisibleData();
},
data() {
return {
visibleData: []
};
},
methods: {
updateVisibleData(scrollTop) {
scrollTop = scrollTop || 0;
const visibleCount = Math.ceil(this.$el.clientHeight / this.itemHeight);
const start = Math.floor(scrollTop / this.itemHeight);
const end = start + visibleCount;
this.visibleData = this.data.slice(start, end);
this.$refs.content.style.transform = `translate3d(0, ${ start * this.itemHeight }px, 0)`;
},
handleScroll() {
const scrollTop = this.$refs.body.scrollTop;
this.updateVisibleData(scrollTop);
}
}
};
new Vue({
components: {
ListView
},
data() {
const data = [];
for (let i = 0; i < 1000; i++) {
data.push({ value: i });
}
return {
data
};
}
}).$mount('#app')
code example:
https://jsfiddle.net/441701328/hq1ej6bx/6/
you can see only the data render in the first time can have border.
could anyone help?
thanks all!!!
table-row-group does not work with divs you can change the whole layout and use tables or instead you can do it like this.
.list-view-item {
padding: 5px;
color: #666;
display: table;
line-height: 30px;
box-sizing: border-box;
border-bottom: 1px solid red;
min-width: 100vw;
}
.list-view-item-col {
display: table-cell;
min-width: 50px;
}
jsfiddle for table-row-group
Hope it helps.
Use display :flex for list-view-item class, Try with following code.Hope it will work fine for you.
.list-view-item {
padding: 5px;
color: #666;
display: flex;
flex-basis: 100%;
flex-direction: row;
line-height: 30px;
box-sizing: border-box;
border-bottom: 1px solid red;
}
Try with this CSS. I hope it will works for you.
.list-view-item {
padding: 5px;
color: #666;
display:table;
line-height: 30px;
box-sizing: border-box;
border-bottom: 1px solid green;
}
I try to change the js code :
this.$refs.content.style.transform = `translateY(0, ${ start * this.itemHeight }px, 0)`;
to :
this.$refs.content.style.transform = `translateY(${ start * this.itemHeight }px)`;
and add a css to div class is list-view:
transform:translateY(0)px;
then the border showed.
don't understand why this action work!
.list-view-item {
padding: 5px;
color: #666;
display: flex;
flex-basis: 100%;
flex-direction: row;
line-height: 30px;
box-sizing: border-box;
border-bottom: 1px solid red;
}
I'm using VueJS and have nested elements which are dynamically created like so:
<container>
<outerElement class="outer" v-for="obj in objects">
<innerElement class="inner" v-for="element in obj"/>
</outerElement>
</container>
Now when it comes to CSS I'm having a slight problem. Since the innerElements are intended to be moveable, they need the outer element to have the same size/position as the container.
Is there some way in CSS to remove the box-model from the 'outer' class whilst remaining in the container?
Here's a sketch of what I'm trying to achieve.
EDIT:
To fix the mentioned XY-Problem, here is the template in a simplified version, using the same implementation methods as in my application.
<template>
<div class="home">
<h1>This is the main Page.</h1>
<h2>Testing area:</h2>
<br />Simple Data Example:
<br />
<div class="container">
<button #click="simpleXOR()">XOR</button>
{{ data }}
<vue-draggable-resizable
class="simple"
v-for="(bit,index) in simpleData"
:key="index"
:w="50"
:h="50"
:parent="true"
:resizable="false"
>
{{`Bit-${index} => `}}
<status-indicator :status="bit ? 'positive' : 'negative'" />
</vue-draggable-resizable>
</div>
<br />Nested Data Example
<div class="container">
<div class="outer" v-for="obj in nestedObj.data" :key="obj.name">
<div class="label">
<button #click="nestedXOR(obj.name)">XOR -> {{ obj.name }}</button>
{{ obj.states }}
</div>
<vue-draggable-resizable
class="inner"
v-for="(state, index) in obj.states"
:key="index"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div v-if="obj.contentType === 'TypeA'">
<b>{{ `Bit-${index} of ${obj.name}` }}</b>
<br />
<status-indicator :status="state ? 'positive' : 'negative'" />
</div>
<div v-else>
<b>{{ `Bit-${index} of ${obj.name}` }}</b>
<br />
<status-indicator :status="state ? 'active' : 'intermediary'" />
</div>
</vue-draggable-resizable>
</div>
</div>
</div>
</template>
<script>
// # is an alias to /src
export default {
name: "home",
components: {},
data() {
return {
simpleData: [0, 1, 0, 1],
nestedObj: {
data: [
{
states: [0, 1, 0, 1],
name: "a",
contentType: "TypeA"
},
{
states: [0, 1, 0, 1],
name: "b",
contentType: "TypeB"
}
]
}
};
},
computed: {
data() {
return this.simpleData;
}
},
methods: {
simpleXOR() {
var x = [];
for (var i = 0; i < this.simpleData.length; i++) {
x.push(this.simpleData[i] ^ 1);
}
this.simpleData = x;
console.debug(this.simpleData);
},
nestedXOR(name) {
var index = this.nestedObj.data.findIndex(obj => {
return obj.name === name;
});
var x = [];
for (var i = 0; i < this.nestedObj.data[index].states.length; i++) {
x.push(this.nestedObj.data[index].states[i] ^ 1);
}
this.nestedObj.data[index].states = x;
}
}
};
</script>
<style scoped>
.container {
margin: auto;
height: 200px;
width: 1000px;
border: 2px solid black;
position: relative;
}
.simple {
top: 0px;
left: 0px;
}
.outer {
display: contents; /* as suggested */
}
.inner {
/* ??? */
}
.label {
border: 1px dashed green;
padding: 10px;
height: 20%;
width: 20%;
}
/* // This is the css for vue-draggable-resizable */
/* // DON'T EDIT unless customization is needed */
.vdr {
touch-action: none;
position: absolute;
box-sizing: border-box;
border: 1px dashed black;
}
.handle {
box-sizing: border-box;
position: absolute;
width: 10px;
height: 10px;
background: #eee;
border: 1px solid #333;
}
.handle-tl {
top: -10px;
left: -10px;
cursor: nw-resize;
}
.handle-tm {
top: -10px;
left: 50%;
margin-left: -5px;
cursor: n-resize;
}
.handle-tr {
top: -10px;
right: -10px;
cursor: ne-resize;
}
.handle-ml {
top: 50%;
margin-top: -5px;
left: -10px;
cursor: w-resize;
}
.handle-mr {
top: 50%;
margin-top: -5px;
right: -10px;
cursor: e-resize;
}
.handle-bl {
bottom: -10px;
left: -10px;
cursor: sw-resize;
}
.handle-bm {
bottom: -10px;
left: 50%;
margin-left: -5px;
cursor: s-resize;
}
.handle-br {
bottom: -10px;
right: -10px;
cursor: se-resize;
}
#media only screen and (max-width: 768px) {
[class*="handle-"]:before {
content: "";
left: -10px;
right: -10px;
bottom: -10px;
top: -10px;
position: absolute;
}
}
</style>
Currently the problem in this code is that the innerElements can't be moved inside the container, because the outerElement is their container.
Since I can't change the parent selector to use the container instead of the outerElement this is hard to change.
Thus I wanted to make the outerElements borders non-existant so that the innerElement uses the container as parent.
But I suppose my thought is a bit weird, considering that the vue-draggable-resizable component will use the outerElement as parent anyways.
Here's a screenshot of the problem:
The moveable boxes can't be moved inside the container because the outerElement doesn't inherit the position and size of the container.
Try using CSS display:contents on the outer element. This display property basically makes the element "invisible" to the browser.
However, I think you'd be better off by refactoring your Vue template to remove the outer element. For example, you could process the objects array to combine its children before doing the loop.
For your simple example, you could just flatten the nested array before iterating over it:
<container>
<innerElement class="inner" v-for="element in objects.flat(1)" />
</container>
The more complex example you posted is a bit trickier, since the inner loop also needs access to obj. Still, you could do it by writing a custom method that wraps each state in an wrapper that contains both the state and a reference to the object it belongs to, like this:
<div class="container">
<div class="label" v-for="obj in nestedObj.data" :key="obj.name">
<button #click="nestedXOR(obj.name)">XOR -> {{ obj.name }}</button>
{{ obj.states }}
</div>
<vue-draggable-resizable
class="inner"
v-for="wrapper in flattenStates(nestedObj.data)"
:key="wrapper.key"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div v-if="wrapper.obj.contentType === 'TypeA'">
<b>{{ `Bit-${wrapper.index} of ${wrapper.obj.name}` }}</b>
<br />
<status-indicator :status="wrapper.state ? 'positive' : 'negative'" />
</div>
<div v-else>
<b>{{ `Bit-${wrapper.index} of ${wrapper.obj.name}` }}</b>
<br />
<status-indicator :status="wrapper.state ? 'active' : 'intermediary'" />
</div>
</vue-draggable-resizable>
</div>
where the flattenStates method would look something like this:
flattenStates: function (objects) {
return objects.flatMap( obj => {
return obj.states.map( (state, index) => {
return {
obj: obj,
state: state,
index: index,
key: obj.name + " state " + index
};
} );
} );
}
Compatibility note: .flat() and .flatMap() are not available on IE or on current stable versions of Edge. To make this code work on those browsers, you'll need a polyfill. The new Chromium-based versions of Edge, still in beta as of this writing, do however support both.
Alternatively, you could simplify the template by moving some logic into the flattenStates method:
<div class="container">
<!-- label divs omitted for brevity -->
<vue-draggable-resizable
class="inner"
v-for="wrapper in flattenStates(nestedObj.data)"
:key="wrapper.title"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div>
<b>{{ wrapper.title }}</b>
<br />
<status-indicator :status="wrapper.status" />
</div>
</vue-draggable-resizable>
</div>
flattenStates: function (objects) {
return objects.flatMap( obj => {
return obj.states.map( (state, index) => {
const wrapper = {
title: `Bit-${index} of ${obj.name}` // also used as :key
};
if (obj.contentType === 'TypeA') {
wrapper.status = (state ? 'positive' : 'negative');
} else {
wrapper.status = (state ? 'active' : 'intermediary');
}
return wrapper;
} );
} );
}
...or even:
<div class="container">
<!-- label divs omitted for brevity -->
<vue-draggable-resizable
class="inner"
v-for="(status, title) in flattenStates(nestedObj.data)"
:key="title"
:resizable="false"
:w="100"
:h="50"
:parent="true"
>
<div>
<b>{{ title }}</b>
<br />
<status-indicator :status="status" />
</div>
</vue-draggable-resizable>
</div>
flattenStates: function (objects) {
const objStates = {};
for (const obj of objects) {
obj.states.forEach( (state, index) => {
const title = `Bit-${index} of ${obj.name}`;
if (obj.contentType === 'TypeA') {
objStates[title] = (state ? 'positive' : 'negative');
} else {
objStates[title] = (state ? 'active' : 'intermediary');
}
} );
}
return objStates;
}
I am able to create a pie chart using Chart.JS with this code:
HTML
<div>
<canvas id="top10ItemsChart" style="padding-left:20px" width="320" height="320"></canvas>
<div id="top10Legend" class="chart-legend"></div>
</div>
jQuery
var data = [{
value: 2755,
color: "#FFE135",
label: "Bananas"
}, {
value: 2256,
color: "#3B5323",
label: "Lettuce, Romaine"
}, {
value: 1637,
color: "#fc6c85",
label: "Melons, Watermelon"
}, {
value: 1608,
color: "#ffec89",
label: "Pineapple"
}, {
value: 1603,
color: "#021c3d",
label: "Berries"
}, {
value: 1433,
color: "#3B5323",
label: "Lettuce, Spring Mix"
}, {
value: 1207,
color: "#046b00",
label: "Broccoli"
}, {
value: 1076,
color: "#cef45a",
label: "Melons, Honeydew"
}, {
value: 1056,
color: "#421C52",
label: "Grapes"
}, {
value: 1048,
color: "#FEA620",
label: "Melons, Cantaloupe"
}];
var optionsPie = {
legend: {
display: true,
position: 'right',
labels: {
fontColor: 'rgb(255, 99, 132)'
}
}
}
var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var top10PieChart = new Chart(ctx).Pie(data, optionsPie);
document.getElementById('top10Legend').innerHTML = top10PieChart.generateLegend();
The problem is that it positions the legend to the bottom of the pie, and even spilling and bleeding outside of the boundaries of the div to which I want the pie to restrict itself:
It also presents the legend as a simple unordered list. What I want to do is to control the color of the various elements in the legend ("Banana" should be the same color (#FFE135) as the piece of banana pie (so to speak), etc.)
How can I make the individual elements match the color of its respective data point?
UPDATE
The "Legend Label Configuration" topic in the official docs here indicate you can set the fontColor of the legends, but this is for the whole shebang; what I want to know is, how is it possible to control the color of each item?
UPDATE 2
In an attempt to at least get the legend displaying in the desired spot, I added this to the jQuery:
var optionsPie = {
legend: {
display: true,
position: 'right',
labels: {
fontColor: 'rgb(255, 99, 132)'
}
}
}
. . .
var myPieChart = new Chart(ctx).Pie(data, optionsPie);
document.getElementById("legendDiv").innerHTML = myPieChart.generateLegend();
...but it makes no difference - the legend is still hung from the bottom of the pie chart, and its font is still the default black.
UPDATE 3
I utilized some suggested code, but the legend is still gravity-fed instead of hanging off to the right:
So the legend impinges on the chart below it, rather than restricting itself to its own neighborhood.
Also, I don't want the bullet points to infest the legend - the colored squares (and the verbiage - but also the values) are all I need. How can I shove the legend from south of the pie to east of the pie?
UPDATE 4
I have refactored the code based on this and it's looking better (I added more data to the "label" value of the data array, too):
Still, though, as you can see the legend is infringing on the quadrant below it. There is a "ton" of empty/wasted space around the pie, though - I want to move the pie to the left, and the legend to the right of the pie. That would also allow more vertical space for the pie to grow in stature.
How can I do that? Here is the code I'm using now:
HTML
<div>
<canvas id="top10ItemsChart" class="pie" style="padding-left:20px"></canvas>
<div id="top10Legend"></div>
</div>
CSS
.pie-legend {
list-style: none;
margin: 0;
padding: 0;
}
.pie-legend span {
display: inline-block;
width: 14px;
height: 14px;
border-radius: 100%;
margin-right: 16px;
margin-bottom: -2px;
}
.pie-legend li {
margin-bottom: 10px;
display: inline-block;
margin-right: 10px;
}
JQUERY
var data = [{
value: 2755,
color: "#FFE135",
label: "Bananas: 2,755 (18%)"
}, {
. . .
}, {
value: 1048,
color: "#FEA620",
label: "Melons, Cantaloupe: 1,048 (7%)"
}];
var optionsPie = {
responsive: true,
scaleBeginAtZero: true,
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
}
var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var top10PieChart = new Chart(ctx).Pie(data, optionsPie);
$("#top10Legend").html(top10PieChart.generateLegend());
NOTE: Adding this to optionsPie:
legend: {
display: true,
position: 'right'
},
...does nothing - the legend remains weighted down to the floor like a frog filled to the chin with quail shot.
UPDATE 5
I've played around with Teo's example, trying to get it to work just right but, although it's better, the pie is very puny, and the legend should be wider, but I can't figure out how to stretch the legend horizontally and the pie in all directions. Here's how it looks now:
This is the code now (JQUERY is the same):
HTML
<div class="col-md-6">
<div class="topleft">
<h2 class="sectiontext">Top 10 Items</h2>
<br />
<div class="legendTable">
<div class="legendCell">
<canvas id="top10ItemsChart" class="pie" style="padding-left:20px"></canvas>
</div>
<div class="legendCell" id="top10Legend">
</div>
</div>
</div>
</div>
CSS
.topleft {
margin-top: -4px;
margin-left: 16px;
margin-bottom: 16px;
padding: 16px;
border: 1px solid black;
}
canvas {
width: 100% !important;
height: auto !important;
}
.legendTable {
border: 1px solid forestgreen;
display: table;
width: 100%;
table-layout: fixed;
}
.legendCell {
display: table-cell;
vertical-align: middle;
}
.pie-legend ul {
list-style: none;
margin: 0;
padding: 0;
width: 300px;
}
.pie-legend span {
display: inline-block;
width: 14px;
height: 12px;
border-radius: 100%;
margin-right: 4px;
margin-bottom: -2px;
}
.pie-legend li {
margin-bottom: 4px;
display: inline-block;
margin-right: 4px;
}
Something is squashing the pie and pushing the outer edges of the legend together.
UPDATE 6
Ochi, et al: Here's what I see after the Ochification of my code:
This is my code - I even ordered the jQuery in the way you have it, although I doubt that is really necessary:
HTML
<div class="row" id="top10Items">
<div class="col-md-6">
<div class="topleft">
<h2 class="sectiontext">Top 10 Items</h2>
<br />
#*<div class="legendTable">
<div class="legendCell">
<canvas id="top10ItemsChart" class="pie" style="padding-left:20px"></canvas>
</div>
<div class="legendCell" id="top10Legend">
</div>
</div>*#
<div class="chart">
<canvas id="top10ItemsChart" class="pie"></canvas>
<div id="pie_legend"></div>
</div>
</div>
</div>
. . .
</div>
CSS
.pie-legend {
list-style: none;
margin: 0;
padding: 0;
}
.pie-legend span {
display: inline-block;
width: 14px;
height: 14px;
border-radius: 100%;
margin-right: 16px;
margin-bottom: -2px;
}
.pie-legend li {
margin-bottom: 10px;
display: block;
margin-right: 10px;
}
.chart,
#priceComplianceBarChart,
#pie_legend {
display: inline-flex;
padding: 0;
margin: 0;
}
JQUERY
var optionsPie = {
responsive: true,
scaleBeginAtZero: true,
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
}
var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var data = [{
value: 2755,
color: "#FFE135",
label: "Bananas: 2,755 (18%)"
. . .
}, {
value: 1048,
color: "#FEA620",
label: "Melons, Cantaloupe: 1,048 (7%)"
}];
var top10PieChart = new Chart(ctx).Pie(data, optionsPie);
$("#pie_legend").html(top10PieChart.generateLegend());
...and yet the pie is stretchier than stretch pants on an elephant.
UPDATE 7
Maybe there's a configuration problem or something. I decided to "upgrade" to version 2.1.3 of Chart.JS (started out w. version 1.0.2):
#*<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>*#
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.js"></script>
...and copied almost exactly Teo Dragovic's CodePen here.
The only things I changed were the names of two CSS class ("table" became "legendTable" and "cell" became "legendCell") and the color of the table border from red to forestgreen, and I get this now:
Do I need to also a reference a Chart.JS CSS file or something?
I think this what you want: DEMO
First, you need to make canvas responsive by overriding fixed width and height and wrap it in additional div that can be used for positioning. I used display: table for centering elements but setting inner divs to inline-block also works if you wish for chart and legend to take different amount of space than 50:50.
HTML:
<div class="table">
<div class="cell">
<canvas id="top10ItemsChart" class="pie"></canvas>
</div>
<div class="cell" id="top10Legend"></div>
</div>
CSS:
canvas {
width: 100% !important;
height: auto !important;
}
.table {
border: 1px solid red;
display: table;
width: 100%;
table-layout: fixed;
}
.cell {
display: table-cell;
vertical-align: middle;
}
UPDATE: Did some adjustment based on additional information by OP NEW DEMO
HTML:
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="topleft">
<h2 class="sectiontext">Top 10 Items</h2>
<br />
<div class="chart">
<div class="pie">
<canvas id="top10ItemsChart" class="pie"></canvas>
</div>
<div class="legend" id="top10Legend">
</div>
</div>
</div>
</div>
</div>
</div>
CSS:
.topleft {
margin-top: -4px;
margin-left: 16px;
margin-bottom: 16px;
padding: 16px;
border: 1px solid black;
}
canvas {
width: 100% !important;
height: auto !important;
margin-left: -25%;
}
.chart {
border: 1px solid forestgreen;
width: 100%;
overflow: hidden;
position: relative;
}
.pie {
position: relative;
padding: 10px 0;
// adjust as necessary
padding-left: 10px;
padding-right: 0;
}
.legend {
position: absolute;
right: 10px;
top: 10px;
height: 100%;
// adjust as necessary:
width: 48%;
}
#media (max-width: 480px) {
.legend {
position: relative;
width: 100%;
}
.pie {
margin: 0;
}
}
.pie-legend ul {
list-style: none;
margin: 0;
padding: 0;
width: 300px;
}
.pie-legend span {
display: inline-block;
width: 14px;
height: 12px;
border-radius: 100%;
margin-right: 4px;
margin-bottom: -2px;
}
.pie-legend li {
margin-bottom: 4px;
display: inline-block;
margin-right: 4px;
}
As #B.ClayShannon mentioned, version 2 is quite a bit different than verison 1. Here is an example of how to customize the legend template using version 2.
options: {
legendCallback: function (chart) {
var text = [];
text.push('<ul class="' + chart.id + '-legend" style="list-style:none">');
for (var i = 0; i < chart.data.datasets[0].data.length; i++) {
text.push('<li><div style="width:10px;height:10px;display:inline-block;background:' + chart.data.datasets[0].backgroundColor[i] + '" /> ');
if (chart.data.labels[i]) {
text.push(chart.data.labels[i]);
}
text.push('</li>');
}
text.push('</ul>');
return text.join('');
},
legend: {display: false},
}
It's not shown directly in the accepted solution above, but to render your legend elsewhere you'll want to call:
$("#myChartLegend").html(myChart.generateLegend());
Finally, some HTML to pull it together (note clearfix is a Bootstrap class that :
<div class="chart">
<div style="float:left">
<canvas id="myChart" class="pie" style="max-width:300px;"></canvas>
</div>
<div class="legend" id="myChartLegend" style="float:left;"></div>
<div style="clear: both;"/>
</div>
This is what works (more or less) using version 2 of Chart.JS:
HTML
<h2 class="sectiontext">Top 10 Items</h2>
<br />
<div class="chart">
<canvas id="top10ItemsChart" class="pie"></canvas>
<div id="pie_legend"></div>
</div>
JQUERY
var data = {
labels: [
"Bananas: 2,755 (18%)",
"Lettuce, Romaine: 2,256 (14%)",
"Melons, Watermelon: 1,637 (10%)",
"Pineapple: 1,608 (10%)",
"Berries: 1,603 (10%)",
"Lettuce, Spring Mix: 1,433 (9%)",
"Broccoli: 1,207 (8%)",
"Melons, Honeydew: 1,076 (7%)",
"Grapes: 1,056 (7%)",
"Melons, Cantaloupe: 1,048 (7%)"
],
datasets: [
{
data: [2755, 2256, 1637, 1608, 1603, 1433, 1207, 1076, 1056, 1048],
backgroundColor: [
"#FFE135",
"#3B5323",
"#fc6c85",
"#ffec89",
"#021c3d",
"#3B5323",
"#046b00",
"#cef45a",
"#421C52",
"#FEA620"
],
}]
};
var optionsPie = {
responsive: true,
scaleBeginAtZero: true
}
var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var top10PieChart = new Chart(ctx,
{
type: 'pie',
data: data,
options: optionsPie
});
$("#top10Legend").html(top10PieChart.generateLegend());
I say, "more or less" because the pie pieces are still pitifully puny:
I have this html tag which reffers to the backButton provided by the WinJS library:
<button data-win-control="WinJS.UI.BackButton"></button>
I want to change its size. How can I do that? I tried using CSS by adding the ID "backButton" and font-size OR width/height properties, like this:
#backButton {
font-size: small;
}
#backButton {
height: 30px;
width: 30px;
}
EDIT: Code added and a picture of what happens when changing the values of width/height of the button.
// For an introduction to the Page Control template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232511
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/anime/anime.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
this.renderAnimeInfo(Identifier.file);
},
unload: function () {
// TODO: Respond to navigations away from this page.
},
updateLayout: function (element) {
/// <param name="element" domElement="true" />
// TODO: Respond to changes in layout.
},
renderAnimeInfo: function (id) {
// Path for the anime data.
var path = "data/animes.json";
// Retrieve the .json.
WinJS.xhr({ url: path }).then(
function (response) {
var json = JSON.parse(response.responseText);
for (var i = 0; i < json.length; i++) {
if (json[i].file == id) {
var animeData = json[i];
break;
}
}
},
function (error) {},
function (progress) {}
);
},
});
})();
.right {
float: right;
}
.left {
float: left;
}
.active {
background-color: blue;
}
#animeDetails {
background: red;
height: 100%;
width: 300px;
float: left;
}
#animeInfo {
display: -ms-grid;
height: 100%;
width: calc(100% - 300px);
float: right;
}
#navbar {
-ms-grid-row: 1;
padding: 20px 25px;
}
#navbar .right button {
margin-right: 4px;
}
#navbar input {
width: 150px;
}
#details {
-ms-grid-row: 2;
padding: 0 25px;
text-align: justify;
white-space: pre-line;
}
#details h3 {
width: 100%;
padding: 5px 0;
border-bottom: 1px solid #bebebe;
margin-bottom: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>anime</title>
<link href="anime.css" rel="stylesheet" />
<script src="anime.js"></script>
</head>
<body>
<div id="animeDetails"></div>
<div id="animeInfo">
<div id="navbar">
<div class="left">
<button class="left" data-win-control="WinJS.UI.BackButton"></button>
<h3>Back</h3>
</div>
<div class="right">
<button type="button" class="active">Details</button>
<button type="button">Episodes</button>
<button type="button">Characters</button>
<button type="button">Staff</button>
<input type="search" placeholder="Search" />
</div>
</div>
<div id="details">
<div id="synopsis">
<h3>Synopsis</h3>
<span>
</span>
</div>
</div>
</div>
</body>
When using the width/height properties, what happens is that the button does resize to the specified value, but the icon inside (which is not a background) doesn't. http://i.imgur.com/lMqmL0G.png
Possibly you have to set display: inline-block to button because the width of an element with display: inline (the default for buttons) is exactly the same as its content because it only takes up the space needed to display its contents so try with:
With id selector
#backButton {
height: 30px;
width: 30px;
display: inline-block;
}
<button id="backButton" data-win-control="WinJS.UI.BackButton"></button>
With style inline
<button data-win-control="WinJS.UI.BackButton" style="width: 30px; height: 30px; display: inline-block"></button>
Try to set the styles to child element .win-back
#backButton .win-back{
/*---styles---*/
}
You haven't given your button an ID. The CSS does not know what tag to link to.
<button id="backButton" data-win-control="WinJS.UI.BackButton"></button>
edit: you may find the following reference useful CSS Selectors