Skip to content

Instantly share code, notes, and snippets.

@valex
Created September 18, 2020 11:05
Show Gist options
  • Save valex/95a9f2449763a292646164a1a52170a2 to your computer and use it in GitHub Desktop.
Save valex/95a9f2449763a292646164a1a52170a2 to your computer and use it in GitHub Desktop.
<template></template>
<script>
import SVGVector2D from './../../SVGVector2D'
export default {
data() {
return {
svg: null,
mainGroup: null,
scaleX: null,
scaleY: null,
vectorDefaults:{
dasharray: '',
color: '#0000FF',
linecap: "butt",
width: 2,
},
vectors: {
a: new SVGVector2D(1.5, 3, {
id: 'vector_a',
html_label: "a&#773;",
}),
b: new SVGVector2D(2.5, 1, {
id: 'vector_b',
html_label: "b&#773;",
}),
a_plus_b: {
id: 'a_plus_b_vector',
color: '#FF0000',
html_label: "a&#773; + b&#773;",
},
b_moved: new SVGVector2D(2.5, 1, {
id: 'b_moved_vector',
color: '#AAAAAA',
dasharray: '3 2'
}, 1.5, 3)
},
options:{
width: 480,
height: 480,
circlesRadius: 5,
margins: {
top: 10,
right: 10,
bottom: 10,
left: 10,
xAxis: {
left: 0,
right: 0,
}},
},
}
},
template: '<div></div>',
mounted() {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
this.ready();
});
this.svg = d3.select(this.$el)
.append("svg")
.attr('xmlns', 'http://www.w3.org/2000/svg')
.attr("width", this.options.width)
.attr("height", this.options.height)
.on('click', function() {
console.log('onClickSvg');
});
this.mainGroup = this.svg.append('g')
.attr('transform', 'translate(' + this.options.margins.left + ',' + this.options.margins.top + ')');
this.scaleX = d3.scaleLinear()
.domain([-5, 5])
.range([0, this.chartWidth - this.options.margins.xAxis.left - this.options.margins.xAxis.right]);
this.scaleY = d3.scaleLinear()
.domain([-5, 5])
.range([this.chartHeight, 0]);
// axes
var axisXGroup = this.svg.append('g')
.attr('transform', 'translate(' + (this.options.margins.left + this.options.margins.xAxis.left) + ',' + (this.chartHeight/2 + this.options.margins.top) + ')');
var axisX = d3.axisBottom(this.scaleX).tickValues([-5,-4,-3,-2,-1, 1, 2, 3, 4, 5]);
axisXGroup.call(axisX);
var axisYGroup = this.svg.append('g')
.attr('transform', 'translate(' + (this.options.margins.left + this.options.margins.xAxis.left + this.scaleX(0)) + ',' + this.options.margins.top + ')');
var axisY = d3.axisLeft(this.scaleY).tickValues([-5,-4,-3,-2,-1, 1, 2, 3, 4, 5]);
axisYGroup.call(axisY);
// Vector a info
this.mainGroup.append('text')
.attr('id', 'a_vector_info')
.html(this.a_vectorInfo)
.style('text-anchor', 'start')
.style('alignment-baseline', 'bottom')
.attr('fill',"#333")
.attr('x',this.options.margins.left)
.attr('y',18)
.attr('dx',0)
.attr('dy',0)
.attr('font-size','16px');
// Vector b info
this.mainGroup.append('text')
.attr('id', 'b_vector_info')
.html(this.b_vectorInfo)
.style('text-anchor', 'start')
.style('alignment-baseline', 'bottom')
.attr('fill',"#333")
.attr('x',this.options.margins.left)
.attr('y',40)
.attr('dx',0)
.attr('dy',0)
.attr('font-size','16px');
this.mainGroup.append('text')
.attr('id', 'a_plus_b_vector_info')
.html(this.a_plus_b_vectorInfo)
.style('text-anchor', 'start')
.style('alignment-baseline', 'bottom')
.attr('fill',"#333")
.attr('x',this.options.margins.left)
.attr('y',62)
.attr('dx',0)
.attr('dy',0)
.attr('font-size','16px');
this.drawVector(this.vectors.a);
this.drawVector(this.vectors.b);
this.drawVector(this.vectors.b_moved);
this.drawVector(this.a_plus_b);
// Draggable circles
this.mainGroup.append('circle')
.classed("draggable", true)
.attr("cx", this.scaleX(this.vectors.a.x))
.attr("cy", this.scaleY(this.vectors.a.y))
.attr("r", this.options.circlesRadius)
.call(
d3.drag()
.on("start", this.dragstarted)
.on('drag', this.a_dragged)
.on("end", this.dragended)
);
this.mainGroup.append('circle')
.classed("draggable", true)
.attr("cx", this.scaleX(this.vectors.b.x))
.attr("cy", this.scaleY(this.vectors.b.y))
.attr("r", this.options.circlesRadius)
.call(
d3.drag()
.on("start", this.dragstarted)
.on('drag', this.b_dragged)
.on("end", this.dragended)
);
},
methods: {
ready(){
},
drawVector(vector){
if( ! vector.hasOption('id'))
return;
let x1=vector.offsetX;
let y1=vector.offsetY;
let x2=vector.offsetX + vector.x;
let y2=vector.offsetY + vector.y;
let dasharray = vector.getOption('dasharray');
let color = vector.getOption('color');
let linecap = vector.getOption('linecap');
let width = vector.getOption('width');
let html_label = vector.getOption('html_label');
// place label
if( ! _.isNil(html_label)){
this.mainGroup.append('text')
.html(html_label)
.attr('id',vector.id+"_label")
.style('text-anchor', 'middle')
.style('alignment-baseline', 'middle')
.attr("transform", "rotate("+(-vector.angle)+","+this.scaleX(x1+((x2-x1) / 2))+","+this.scaleY(y1+((y2-y1) / 2))+")")
.attr('fill', color)
.attr('x',this.scaleX(x1+((x2-x1) / 2)))
.attr('y',this.scaleY(y1+((y2-y1) / 2)))
.attr('dx',0)
.attr('dy',-14)
.attr('font-size','24px');
}
// place arrow
this.svg.append("svg:defs").append("svg:marker")
.attr("id", vector.id+"_arrow")
.attr("refX", 7)
.attr("refY", 4)
.attr("markerWidth", 8)
.attr("markerHeight", 8)
.attr("markerUnits", "strokeWidth")
.attr("viewBox", "0 0 8 8")
.attr("orient", "auto")
.append("path")
.attr("d", "M0,0 L8,4 L0,8 L4,4 L0,0")
.style("fill", color);
// draw line
this.mainGroup.append("line")
.attr('id', vector.id)
.attr("x1", this.scaleX(x1))
.attr("y1", this.scaleY(y1))
.attr("x2", this.scaleX(x2))
.attr("y2", this.scaleY(y2))
.attr("stroke-dasharray", dasharray)
.attr("stroke-width", width)
.attr("stroke-linecap", linecap)
.attr("stroke", color)
.attr("marker-end","url(#"+vector.id+"_arrow)");
},
a_dragged(d, i, els){
let x = d3.event.x,
y = d3.event.y;
if ((x < 0) || x > this.chartWidth || (y < 0) || y > this.chartHeight)
return;
d3.select(els[i])
.attr("cx", x)
.attr("cy", y);
this.vectors.a.x = this.scaleX.invert(x);
this.vectors.a.y = this.scaleY.invert(y);
this.vectors.b_moved.offsetX = this.scaleX.invert(x);
this.vectors.b_moved.offsetY = this.scaleY.invert(y);
d3.select('#'+this.vectors.a.id)
.attr("x2", this.scaleX(this.vectors.a.x))
.attr("y2", this.scaleY(this.vectors.a.y));
d3.select('#'+this.vectors.b_moved.id)
.attr("x1", this.scaleX(this.vectors.b_moved.offsetX))
.attr("y1", this.scaleY(this.vectors.b_moved.offsetY))
.attr("x2", this.scaleX(this.vectors.b_moved.offsetX + this.vectors.b_moved.x))
.attr("y2", this.scaleY(this.vectors.b_moved.offsetY + this.vectors.b_moved.y));
d3.select('#'+this.vectors.a.id + '_label')
.attr('x',this.scaleX(this.vectors.a.x/2))
.attr('y',this.scaleY(this.vectors.a.y/2))
.attr("transform", "rotate("+(-this.vectors.a.angle)+","+this.scaleX(this.vectors.a.x / 2)+","+this.scaleY(this.vectors.a.y / 2)+")")
d3.select('#'+this.a_plus_b.id)
.attr("x2", this.scaleX(this.a_plus_b.x))
.attr("y2", this.scaleY(this.a_plus_b.y));
d3.select('#'+this.a_plus_b.id + '_label')
.attr('x',this.scaleX(this.a_plus_b.x/2))
.attr('y',this.scaleY(this.a_plus_b.y/2))
.attr("transform", "rotate("+(-this.a_plus_b.angle)+","+this.scaleX(this.a_plus_b.x / 2)+","+this.scaleY(this.a_plus_b.y / 2)+")")
d3.select('#a_vector_info')
.html(this.a_vectorInfo);
d3.select('#a_plus_b_vector_info')
.html(this.a_plus_b_vectorInfo);
},
b_dragged(d, i, els){
let x = d3.event.x,
y = d3.event.y;
if ((x < 0) || x > this.chartWidth || (y < 0) || y > this.chartHeight)
return;
d3.select(els[i])
.attr("cx", x)
.attr("cy", y);
this.vectors.b.x = this.scaleX.invert(x);
this.vectors.b.y = this.scaleY.invert(y);
this.vectors.b_moved.x = this.scaleX.invert(x);
this.vectors.b_moved.y = this.scaleY.invert(y);
d3.select('#'+this.vectors.b.id)
.attr("x2", this.scaleX(this.vectors.b.x))
.attr("y2", this.scaleY(this.vectors.b.y));
d3.select('#'+this.vectors.b_moved.id)
.attr("x2", this.scaleX(this.vectors.b_moved.offsetX + this.vectors.b_moved.x))
.attr("y2", this.scaleY(this.vectors.b_moved.offsetY + this.vectors.b_moved.y));
d3.select('#'+this.vectors.b.id + '_label')
.attr('x',this.scaleX(this.vectors.b.x/2))
.attr('y',this.scaleY(this.vectors.b.y/2))
.attr("transform", "rotate("+(-this.vectors.b.angle)+","+this.scaleX(this.vectors.b.x / 2)+","+this.scaleY(this.vectors.b.y / 2)+")")
d3.select('#'+this.a_plus_b.id)
.attr("x2", this.scaleX(this.a_plus_b.x))
.attr("y2", this.scaleY(this.a_plus_b.y));
d3.select('#'+this.a_plus_b.id + '_label')
.attr('x',this.scaleX(this.a_plus_b.x/2))
.attr('y',this.scaleY(this.a_plus_b.y/2))
.attr("transform", "rotate("+(-this.a_plus_b.angle)+","+this.scaleX(this.a_plus_b.x / 2)+","+this.scaleY(this.a_plus_b.y / 2)+")")
d3.select('#b_vector_info')
.html(this.b_vectorInfo);
d3.select('#a_plus_b_vector_info')
.html(this.a_plus_b_vectorInfo);
},
dragstarted(d, i, els){
let circle = d3.select(els[i]).classed("dragging", true);
},
dragended(d, i, els){
let circle = d3.select(els[i]).classed("dragging", false);
}
},
computed: {
chartWidth: function () {
// `this` указывает на экземпляр vm
return this.options.width - this.options.margins.left - this.options.margins.right
},
chartHeight: function () {
// `this` указывает на экземпляр vm
return this.options.height - this.options.margins.top - this.options.margins.bottom;
},
a_plus_b :function(){
return new SVGVector2D(
this.vectors.a.x+this.vectors.b.x,
this.vectors.a.y+this.vectors.b.y,
this.vectors.a_plus_b);
},
a_vectorInfo: function (){
let info = "a&#773;&nbsp;&nbsp;&lang;";
info+=this.vectors.a.x.toFixed(2);
info+=", ";
info+=this.vectors.a.y.toFixed(2);
info+="&rang;";
return info;
},
b_vectorInfo: function (){
let info = "b&#773;&nbsp;&nbsp;&lang;";
info+=this.vectors.b.x.toFixed(2);
info+=", ";
info+=this.vectors.b.y.toFixed(2);
info+="&rang;";
return info;
},
a_plus_b_vectorInfo: function (){
let info = "a&#773; + b&#773;&nbsp;&nbsp;&lang;";
info+=this.a_plus_b.x.toFixed(2);
info+=", ";
info+=this.a_plus_b.y.toFixed(2);
info+="&rang;";
return info;
}
}
}
</script>
<style>
svg text {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
svg text::selection {
background: none;
}
svg path.domain{
stroke: #AAAAAA;
}
svg g.tick line{
stroke: #AAAAAA;
}
svg g.tick text{
font-size: 0.9rem;
stroke-width: 0.3px;
stroke: #AAAAAA;
}
circle.draggable {
fill: lightsteelblue;
stroke: steelblue;
stroke-width: 1.5px;
opacity: 0.85;
fill-opacity: 0.5;
cursor: pointer;
}
circle.draggable.dragging {
fill: red;
stroke: brown;
opacity: 1.0;
fill-opacity: 1.0;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment