init
This commit is contained in:
commit
813abcd9d4
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/node_modules/
|
||||
/public/build/
|
||||
/tmp
|
||||
|
||||
conf.js
|
||||
package-lock.json
|
||||
test
|
||||
|
||||
.DS_Store
|
||||
8
index.js
Normal file
8
index.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
MapBuilder: require('./svgmap/svg-map-builder'),
|
||||
MapSaver: require('./svgmap/svg-map-saver'),
|
||||
BBox: require('./libs/bbox'),
|
||||
StyleAdaptor: require('./svgmap/helpers/style-adaptor'),
|
||||
SvgNode: require('./svgmap/svg-node'),
|
||||
SvgNodes: require('./svgmap/drawers/svg-nodes'),
|
||||
}
|
||||
77
libs/bbox.js
Normal file
77
libs/bbox.js
Normal file
@ -0,0 +1,77 @@
|
||||
class BBox {
|
||||
static fromLTWH(l, t, w, h){
|
||||
return BBox.fromLTRB(l, t, l + w, t + h)
|
||||
}
|
||||
|
||||
static fromLTRB(l, t, r, b){
|
||||
return Object.assign(new BBox(), {l: Math.min(l, r), t: Math.min(t, b), r: Math.max(l, r), b: Math.max(t, b)})
|
||||
}
|
||||
|
||||
static from_array(arr_xy){
|
||||
const bbox = BBox.fromLTWH(arr_xy[0].x, arr_xy[0].y, 0, 0)
|
||||
return bbox.append_many(arr_xy)
|
||||
}
|
||||
|
||||
w(){
|
||||
return this.r - this.l
|
||||
}
|
||||
|
||||
h(){
|
||||
return this.b - this.t
|
||||
}
|
||||
|
||||
toLTWH(){
|
||||
const {l, t, r, b} = this
|
||||
return {l, t, w: r - l, h: b - t }
|
||||
}
|
||||
|
||||
toLTRB(){
|
||||
const {l, t, r, b} = this
|
||||
return {l, t, r, b}
|
||||
}
|
||||
|
||||
toLTRBarr(){
|
||||
const {l, t, r, b} = this
|
||||
return [l, t, r, b]
|
||||
}
|
||||
|
||||
append(x, y){
|
||||
this.l = Math.min(this.l, x)
|
||||
this.t = Math.min(this.t, y)
|
||||
this.r = Math.max(this.r, x)
|
||||
this.b = Math.max(this.b, y)
|
||||
return this
|
||||
}
|
||||
|
||||
append_many(arr_xy){
|
||||
arr_xy.forEach(e => this.append(e.x, e.y))
|
||||
return this
|
||||
}
|
||||
|
||||
scale(k){
|
||||
this.r = this.l + (this.r - this.l) * k
|
||||
this.b = this.t + (this.b - this.t) * k
|
||||
return this
|
||||
}
|
||||
|
||||
move(dx, dy){
|
||||
this.l += dx
|
||||
this.t += dy
|
||||
this.r += dx
|
||||
this.b += dy
|
||||
return this
|
||||
}
|
||||
|
||||
moveto(x, y){
|
||||
let dx = x - this.l
|
||||
let dy = y - this.t
|
||||
return this.move(dx, dy)
|
||||
}
|
||||
|
||||
clone(){
|
||||
return BBox.fromLTRB(this.l, this.t, this.r, this.b)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BBox
|
||||
module.exports.default = BBox
|
||||
58
libs/coord-system.js
Normal file
58
libs/coord-system.js
Normal file
@ -0,0 +1,58 @@
|
||||
class CoordSystem{
|
||||
/**
|
||||
* Создает ненормированную систему координат с началом в x0,y0 и направлением x1,y1
|
||||
* @param {*} x0
|
||||
* @param {*} y0
|
||||
* @param {*} x1
|
||||
* @param {*} y1
|
||||
* @returns
|
||||
*/
|
||||
constructor(x0, y0, x1, y1) {
|
||||
this.x0 = x0
|
||||
this.y0 = y0
|
||||
this.x1 = x1
|
||||
this.y1 = y1
|
||||
}
|
||||
|
||||
scale(k){
|
||||
this.x1 *= k
|
||||
this.y1 *= k
|
||||
return this
|
||||
}
|
||||
|
||||
move(dx, dy){
|
||||
this.x0 += dx
|
||||
this.y0 += dy
|
||||
this.x1 += dx
|
||||
this.y1 += dy
|
||||
return this
|
||||
}
|
||||
|
||||
moveto(x, y){
|
||||
let dx = x - this.x0
|
||||
let dy = y - this.y0
|
||||
return this.move(dx, dy)
|
||||
}
|
||||
|
||||
flipx(){
|
||||
let x = this.x0
|
||||
this.x0 = this.x1
|
||||
this.x1 = x
|
||||
// this.x0 += 500
|
||||
// this.x1 = 2 * this.x0 - this.x1 + 500
|
||||
return this
|
||||
}
|
||||
|
||||
flipy(){
|
||||
this.y1 = 2 * this.y0 - this.y1
|
||||
return this
|
||||
}
|
||||
|
||||
clone(){
|
||||
return new CoordSystem(this.x0, this.y0, this.x1, this.y1)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = CoordSystem
|
||||
module.exports.default = CoordSystem
|
||||
91
libs/file.js
Normal file
91
libs/file.js
Normal file
@ -0,0 +1,91 @@
|
||||
export default {
|
||||
/**
|
||||
* Downloads file
|
||||
* @param {*} filename
|
||||
* @param {*} data
|
||||
*/
|
||||
download(filename, data) {
|
||||
var element = document.createElement("a");
|
||||
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(data));
|
||||
element.setAttribute("download", filename);
|
||||
|
||||
element.style.display = "none";
|
||||
document.body.appendChild(element);
|
||||
|
||||
element.click();
|
||||
|
||||
document.body.removeChild(element);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert data of file selected in input to base64 string
|
||||
* @param {*} input
|
||||
*/
|
||||
async toBase64(input) {
|
||||
return new Promise((resolve) => {
|
||||
if (input.files.length == 0){
|
||||
resolve(null)
|
||||
}
|
||||
else if (input.files.length == 1){
|
||||
this.fileToBase64(input.files[0]).then(resolve)
|
||||
}
|
||||
else
|
||||
Promise.all(Array(...input.files).map(this.fileToBase64)).then(resolve)
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert data of file selected in input to base64 string
|
||||
* @param {*} input
|
||||
*/
|
||||
async fileToBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
reader.onload = function () {
|
||||
resolve(reader.result)
|
||||
};
|
||||
reader.onerror = function (error) {
|
||||
reject(error)
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Read data of file/files selected in input as string
|
||||
* @param {*} input
|
||||
*/
|
||||
async read(input) {
|
||||
return new Promise((resolve) => {
|
||||
if (input.files.length == 0){
|
||||
resolve(null)
|
||||
}
|
||||
else if (input.files.length == 1){
|
||||
this.readFile(input.files[0]).then(resolve)
|
||||
}
|
||||
else
|
||||
Promise.all(Array(...input.files).map(this.readFile)).then(resolve)
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Read data of file/files selected in input as string
|
||||
* @param {*} input
|
||||
*/
|
||||
async readFile(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file);
|
||||
|
||||
reader.onload = function () {
|
||||
resolve(reader.result)
|
||||
};
|
||||
reader.onerror = function (error) {
|
||||
reject(error)
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
13
libs/math.js
Normal file
13
libs/math.js
Normal file
@ -0,0 +1,13 @@
|
||||
export default {
|
||||
/**
|
||||
* Создает данные дл круговой диаграммы из набора значений v0,v1,v2,v3 -> [{a0: 0, a1: v0}, {a0: v0, a1: v0+v1}, {a0: v0+v1, a1: v0+v1+v2},]
|
||||
* @param { [Number] } values Значения долей
|
||||
* @param { boolean } norm Нормировать ли значения диапазонов в отрезок 0-1
|
||||
* @returns Массив с диапазонами долей 1,2,3,4 -> [{0,0.1},{0.1,0.3},{0.3,0.6},{0.6,1}]
|
||||
*/
|
||||
make_ranges(values, norm = true) {
|
||||
let ranges = values.reduce((s, c, i) => [...s, {...c, a0: i && s[i - 1].a1, a1: c + (i && s[i - 1].a1)}], [])
|
||||
let max = ranges[ranges.length - 1].a1
|
||||
return norm ? ranges.map(x => ({a0: x.a0 / max, a1: x.a1 / max})) : ranges
|
||||
},
|
||||
};
|
||||
33
libs/transform.js
Normal file
33
libs/transform.js
Normal file
@ -0,0 +1,33 @@
|
||||
class Transfrom {
|
||||
static fromCoordSyses(cs1, cs2){
|
||||
let tr = new Transfrom()
|
||||
|
||||
tr.cs1 = cs1
|
||||
tr.cs2 = cs2
|
||||
|
||||
let dx1 = cs1.x1 - cs1.x0;
|
||||
let dy1 = cs1.y1 - cs1.y0;
|
||||
let dx2 = cs2.x1 - cs2.x0;
|
||||
let dy2 = cs2.y1 - cs2.y0;
|
||||
|
||||
tr.kx12 = dx1 ? dx2 / dx1 : 1;
|
||||
tr.ky12 = dy1 ? dy2 / dy1 : 1;
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
trx(x){
|
||||
return (x - this.cs1.x0) * this.kx12 + this.cs2.x0;
|
||||
}
|
||||
|
||||
try(y){
|
||||
return (y - this.cs1.y0) * this.ky12 + this.cs2.y0;
|
||||
}
|
||||
|
||||
trp(p){
|
||||
return {x: this.trx(p.x), y: this.trx(p.y)}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Transfrom
|
||||
module.exports.default = Transfrom
|
||||
16
package.json
Normal file
16
package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "app_mapbuilder",
|
||||
"version": "1.0.0",
|
||||
"description": "Svg map builder tools",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://git.dev.aurora.hub01.site/djerom/app_mapbuilder.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
26
services/map.js
Normal file
26
services/map.js
Normal file
@ -0,0 +1,26 @@
|
||||
module.exports = class {
|
||||
|
||||
set_scale(scale){
|
||||
this.scale = scale
|
||||
}
|
||||
|
||||
get_bbox(data){
|
||||
return data.reduce(
|
||||
(s, c) => ({
|
||||
l: Math.min(s.l, c.x),
|
||||
t: Math.min(s.t, c.y),
|
||||
r: Math.max(s.r, c.x),
|
||||
b: Math.max(s.b, c.y),
|
||||
}),
|
||||
{ l: data[0].x, t: data[0].y, r: data[0].x, b: data[0].y }
|
||||
)
|
||||
}
|
||||
|
||||
wells_layer(wells){
|
||||
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
}
|
||||
}
|
||||
116
services/sql/prod_inj.js
Normal file
116
services/sql/prod_inj.js
Normal file
@ -0,0 +1,116 @@
|
||||
export default {
|
||||
max_date(){
|
||||
return `SELECT MAX(date(year||'-01-01', (month - 1)||' month')) as date FROM production_injections`
|
||||
},
|
||||
|
||||
devobjs(){
|
||||
return `SELECT distinct(object) as devobj FROM production_injections`
|
||||
},
|
||||
|
||||
totals(devobj){
|
||||
return `SELECT
|
||||
wells.well, wells.whx, wells.why
|
||||
,SUM(production_injections.woptm) as wopt
|
||||
,SUM(production_injections.wwptm) as wwpt
|
||||
,SUM(production_injections.wsgptv) as wgpt
|
||||
,SUM(production_injections.wwitv) as wwit
|
||||
,SUM(production_injections.days) as days
|
||||
,SUM(production_injections.wwptm)+SUM(production_injections.woptm) as wlpt
|
||||
,SUM(production_injections.wwptm)/(SUM(production_injections.wwptm)+SUM(production_injections.woptm)) as wlf
|
||||
FROM
|
||||
wells, production_injections
|
||||
WHERE
|
||||
wells.well=production_injections.well
|
||||
AND production_injections.object='${devobj}'
|
||||
GROUP BY
|
||||
wells.well
|
||||
ORDER BY
|
||||
wlpt DESC, wwit DESC`
|
||||
},
|
||||
|
||||
rates(devobj, date){
|
||||
date = new Date(date)
|
||||
const year_month = date.getFullYear()*100 + date.getMonth()
|
||||
return `SELECT
|
||||
wells.well, wells.whx, wells.why
|
||||
,SUM(production_injections.woptm)/SUM(production_injections.days) as wopr
|
||||
,SUM(production_injections.wwptm)/SUM(production_injections.days) as wwpr
|
||||
,SUM(production_injections.wsgptv)/SUM(production_injections.days) as wgpr
|
||||
,SUM(production_injections.wwitv)/SUM(production_injections.days) as wwir
|
||||
,SUM(production_injections.days) as days
|
||||
,(SUM(production_injections.wwptm)+SUM(production_injections.woptm)) / SUM(production_injections.days) as wlpr
|
||||
,SUM(production_injections.wwptm)/(SUM(production_injections.wwptm)+SUM(production_injections.woptm)) as wlf
|
||||
FROM
|
||||
wells, production_injections
|
||||
WHERE
|
||||
wells.well=production_injections.well
|
||||
AND production_injections.object='${devobj}'
|
||||
AND (year*100+month)=${year_month}
|
||||
GROUP BY
|
||||
wells.well`
|
||||
},
|
||||
|
||||
|
||||
production_injection(field, devobj, date){
|
||||
const f_date = date ? `AND year*1000+month=${date.getFullYear()*1000+date.getMonth()}` : ''
|
||||
console.log(f_date)
|
||||
|
||||
return `SELECT
|
||||
wells.well, wells.whx, wells.why
|
||||
,SUM(production_injections.woptm) as wopt
|
||||
,SUM(production_injections.wwptm) as wwpt
|
||||
,SUM(production_injections.wsgptv) as wgpt
|
||||
,SUM(production_injections.wwitv) as wwit
|
||||
,SUM(production_injections.days) as days
|
||||
,SUM(production_injections.wwptm)+SUM(production_injections.woptm) as wlpt
|
||||
,SUM(production_injections.wwptm)/(SUM(production_injections.wwptm)+SUM(production_injections.woptm)) as wlf
|
||||
FROM
|
||||
wells, production_injections
|
||||
WHERE
|
||||
AND wells.well=production_injections.well
|
||||
AND production_injections.object='${devobj}'
|
||||
AND (year*1000+month)=${max_year_month}
|
||||
GROUP BY
|
||||
wells.well`
|
||||
},
|
||||
|
||||
production_total(field, devobj){
|
||||
return `SELECT
|
||||
wells.well, wells.whx, wells.why
|
||||
,SUM(production_injections.woptm) as wopt
|
||||
,SUM(production_injections.wwptm) as wwpt
|
||||
,SUM(production_injections.wsgptv) as wgpt
|
||||
,SUM(production_injections.wwitv) as wwit
|
||||
,SUM(production_injections.wwptm)+SUM(production_injections.woptm) as wlpt
|
||||
,SUM(production_injections.wwptm)/(SUM(production_injections.wwptm)+SUM(production_injections.woptm)) as wlf
|
||||
FROM
|
||||
wells, production_injections
|
||||
WHERE
|
||||
wells.well=production_injections.well
|
||||
AND object='${devobj}'
|
||||
GROUP BY
|
||||
wells.well`
|
||||
},
|
||||
|
||||
injection_total(){
|
||||
const query_all = `SELECT
|
||||
wells.well, wells.whx, wells.why
|
||||
,SUM(production_injections.woptm) as wopt
|
||||
,SUM(production_injections.wwptm) as wwpt
|
||||
,SUM(production_injections.wsgptv) as wgpt
|
||||
,SUM(production_injections.wwitv) as wwit
|
||||
,SUM(production_injections.wwptm)+SUM(production_injections.woptm) as wlpt
|
||||
,SUM(production_injections.wwptm)/(SUM(production_injections.wwptm)+SUM(production_injections.woptm)) as wlf
|
||||
FROM
|
||||
wells, production_injections
|
||||
WHERE
|
||||
wells.well=production_injections.well
|
||||
AND object='${devobj}'
|
||||
GROUP BY
|
||||
wells.well
|
||||
HAVING
|
||||
wwit>0
|
||||
|
||||
`
|
||||
}
|
||||
}
|
||||
9
services/wells.js
Normal file
9
services/wells.js
Normal file
@ -0,0 +1,9 @@
|
||||
module.exports = class {
|
||||
constructor(url){
|
||||
this.url = url
|
||||
}
|
||||
|
||||
get_wells(){
|
||||
|
||||
}
|
||||
}
|
||||
3
svgmap/drawers/corel-layer.js
Normal file
3
svgmap/drawers/corel-layer.js
Normal file
@ -0,0 +1,3 @@
|
||||
const SvgNodes = require("./svg-nodes");
|
||||
|
||||
module.exports = (name) => SvgNodes.group(['<metadata id="CorelCorpID_WWPTCorel-Layer"/>']).set_attr("id", name);
|
||||
134
svgmap/drawers/svg-nodes.js
Normal file
134
svgmap/drawers/svg-nodes.js
Normal file
@ -0,0 +1,134 @@
|
||||
const SvgNode = require("./../svg-node.js");
|
||||
|
||||
function svg() {
|
||||
return new SvgNode("svg", {
|
||||
version: "1.1",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
"xml:space": "preserve",
|
||||
"xmlns:xlink": "http://www.w3.org/1999/xlink",
|
||||
style: "shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd",
|
||||
// viewBox: "0 0 2000 2000"
|
||||
});
|
||||
}
|
||||
|
||||
function node(name, attrs, items) {
|
||||
return new SvgNode(name, attrs, items);
|
||||
}
|
||||
|
||||
function container(items) {
|
||||
return new SvgNode(null, null, items);
|
||||
}
|
||||
|
||||
function group(items) {
|
||||
return new SvgNode("g", null, items);
|
||||
}
|
||||
|
||||
function circle(r) {
|
||||
return new SvgNode("circle", { r });
|
||||
}
|
||||
|
||||
function ngon(r, n, ang = 0) {
|
||||
const da = (2 * Math.PI) / n;
|
||||
ang = (ang * Math.PI) / 180;
|
||||
const pts = Array(n)
|
||||
.fill(0)
|
||||
.map((x, i) => [Math.sin(i * da + ang) * r, Math.cos(i * da + ang) * r]);
|
||||
return new SvgNode("polygon", { points: pts.map((x) => `${x[0]},${x[1]}`) });
|
||||
}
|
||||
|
||||
function spike1(w, h, ang) {
|
||||
const da = (ang * Math.PI) / 180;
|
||||
const sa = Math.sin(da);
|
||||
const ca = Math.cos(da);
|
||||
h = h / 2;
|
||||
const pts = `${-sa * h},${-ca * h} ${ca * w},${-sa * w}, ${sa * h},${ca * h}`;
|
||||
return new SvgNode("polygon", { points: pts });
|
||||
}
|
||||
|
||||
function sector(r, a0, a1) {
|
||||
const k = Math.PI / 180;
|
||||
let s0 = -Math.sin(a0 * k) * r;
|
||||
let c0 = Math.cos(a0 * k) * r;
|
||||
let s1 = -Math.sin(a1 * k) * r;
|
||||
let c1 = Math.cos(a1 * k) * r;
|
||||
|
||||
var aa = a1 - a0 > 180 ? 1 : 0;
|
||||
// var p = new TimalSvg.Data.SvgPath(string.Format("M0 0 L{0} 0 A {0} {0} 0 {3} 0 {1} {2} z", FN(r), ca, sa, aa));
|
||||
// p.Transform = string.Format("rotate({0})", FN(ang / 2));
|
||||
|
||||
return new SvgNode("path", { d: `M0 0 L${c0} ${s0} A ${r} ${r} 0 ${aa} 0 ${c1} ${s1} z` });
|
||||
}
|
||||
|
||||
function ring_sector(r0, r1, a0, a1) {
|
||||
const k = Math.PI / 180;
|
||||
let s0 = -Math.sin(a0 * k);
|
||||
let c0 = Math.cos(a0 * k);
|
||||
let s1 = -Math.sin(a1 * k);
|
||||
let c1 = Math.cos(a1 * k);
|
||||
|
||||
var aa = a1 - a0 > 180 ? 1 : 0;
|
||||
|
||||
return new SvgNode("path", {
|
||||
d: `M${c0 * r0} ${s0 * r0}
|
||||
A ${r0} ${r0} 0 ${aa} 0 ${c1 * r0} ${s1 * r0}
|
||||
L${c1 * r1} ${s1 * r1}
|
||||
A ${r1} ${r1} 0 ${aa} 1 ${c0 * r1} ${s0 * r1} z`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param r0
|
||||
* @param r1
|
||||
* @param a0
|
||||
* @param a1
|
||||
* @param { [{v, style}] } rings
|
||||
*/
|
||||
function ring_sectors(r0, r1, sectors) {
|
||||
let sum = sectors.reduce((s, c) => s + c.v, 0);
|
||||
let angs = sectors.reduce((s, c, i) => [...s, { ...c, a0: i && s[i - 1].a1, a1: c.v + (i && s[i - 1].a1) }], []);
|
||||
let items = angs.map((x) => ring_sector(r0, r1, (x.a0 * 360) / sum, (x.a1 * 360) / sum).add_style(x.style));
|
||||
|
||||
return group(items);
|
||||
}
|
||||
|
||||
function text(text) {
|
||||
let node = new SvgNode("text");
|
||||
node.items = [text];
|
||||
node.set_attrs({ x: 0, y: 0 });
|
||||
return node;
|
||||
}
|
||||
|
||||
const defs = {
|
||||
simple: {
|
||||
radialGradient(id, color0, color1) {
|
||||
let s0 = new SvgNode("stop", { offset: "0%", "stop-color": color0 });
|
||||
let s1 = new SvgNode("stop", { offset: "100%", "stop-color": color1 });
|
||||
return new SvgNode("radialGradient", { id }).append(s0, s1);
|
||||
},
|
||||
},
|
||||
|
||||
radialGradient(id, cx, cy, r) {
|
||||
return new SvgNode("radialGradient", { id, cx, cy, r });
|
||||
},
|
||||
|
||||
stop(offset, color) {
|
||||
return new SvgNode("stop", { offset, "stop-color": color });
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
node,
|
||||
svg,
|
||||
container,
|
||||
group,
|
||||
circle,
|
||||
ngon,
|
||||
spike1,
|
||||
sector,
|
||||
ring_sector,
|
||||
ring_sectors,
|
||||
text,
|
||||
};
|
||||
|
||||
module.exports.default = module.exports;
|
||||
30
svgmap/drawers/svg-well.js
Normal file
30
svgmap/drawers/svg-well.js
Normal file
@ -0,0 +1,30 @@
|
||||
// export default {
|
||||
// wellhead: {
|
||||
// prod(x, y, r, style){
|
||||
// return SvgNodes.circle(r).add_style(style).move(w.x, w.y);
|
||||
// },
|
||||
|
||||
// inj(x, y, r, style){
|
||||
// return SvgNodes.circle(r).add_style(style).move(w.x, w.y);
|
||||
// }
|
||||
// },
|
||||
|
||||
// // [{x,y}]
|
||||
// heads(wells, r, style) {
|
||||
// return wells.map((w) => SvgNodes.circle(r).add_style(style).move(w.x, w.y));
|
||||
// },
|
||||
|
||||
// // [{x,y,name}]
|
||||
// names(wells, style, shift) {
|
||||
// return wells.map((w) =>
|
||||
// SvgNodes.text(w.name)
|
||||
// .add_style(style)
|
||||
// .move(w.x + shift.x, w.y + shift.y)
|
||||
// );
|
||||
// },
|
||||
|
||||
// // {x,y,ring[1,2,3,4,5]}
|
||||
// ring(x, y, r0, r1, a0, a1, style) {
|
||||
// return SvgNodes.ring_sector(r0, r1, a0, a1).move(x, y).add_style(style);
|
||||
// },
|
||||
// }
|
||||
77
svgmap/drawers/well-head.js
Normal file
77
svgmap/drawers/well-head.js
Normal file
@ -0,0 +1,77 @@
|
||||
const SvgNode = require("./../svg-node.js");
|
||||
const SvgNodes = require("./svg-nodes.js");
|
||||
|
||||
function name(text, ppu, styles) {
|
||||
return SvgNodes.text(text)
|
||||
.move(styles["wellhead-name"].dx * ppu, styles["wellhead-name"].dy * ppu)
|
||||
.add_style(styles["wellhead-name"]);
|
||||
}
|
||||
|
||||
function wlp(wlf, ppu, styles) {
|
||||
return SvgNodes.text(`${Math.round(wlf * 1000) / 10 || ""}%`)
|
||||
.move(styles.wlf.dx * ppu, styles.wlf.dy * ppu)
|
||||
.add_style(styles.wlf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Добывающая скважина
|
||||
* @param {*} ppu
|
||||
* @param {*} styles
|
||||
* @returns
|
||||
*/
|
||||
function prod(ppu, styles) {
|
||||
return SvgNodes.circle(1.5 * ppu).add_style(styles["wellhead-black"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Нагнетательная
|
||||
* @param {*} ppu
|
||||
* @param {*} styles
|
||||
* @returns
|
||||
*/
|
||||
function inj(ppu, styles) {
|
||||
const style_spike = {
|
||||
"stroke-width": "0",
|
||||
fill: "#000",
|
||||
};
|
||||
|
||||
const style_blue = {
|
||||
"stroke-width": Math.round(styles._units["1pt"]),
|
||||
stroke: "#000",
|
||||
fill: "#00f",
|
||||
};
|
||||
|
||||
return SvgNodes.group([
|
||||
SvgNodes.group([
|
||||
SvgNodes.spike1(1.8 * ppu, 1.7 * ppu, 0).move(2 * ppu, 0),
|
||||
SvgNodes.spike1(1.8 * ppu, 1.7 * ppu, 90).move(0, -2 * ppu),
|
||||
SvgNodes.spike1(1.8 * ppu, 1.7 * ppu, 180).move(-2 * ppu, 0),
|
||||
SvgNodes.spike1(1.8 * ppu, 1.7 * ppu, 270).move(0, 2 * ppu),
|
||||
]).add_style(style_spike),
|
||||
new SvgNode("line", { x1: -2 * ppu, x2: 2 * ppu, y1: 0, y2: 0 }),
|
||||
new SvgNode("line", { y1: -2 * ppu, y2: 2 * ppu, x1: 0, x2: 0 }),
|
||||
SvgNodes.circle(1.5 * ppu).add_style(style_blue),
|
||||
]).add_style(style_blue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Серая с треугольником с малым дебитом/нагнетанием
|
||||
* @param {*} ppu
|
||||
* @param {*} styles
|
||||
* @returns
|
||||
*/
|
||||
function gray(ppu, styles) {
|
||||
return SvgNodes.group([
|
||||
SvgNodes.circle(1.5 * ppu).add_style(styles["wellhead-gray"]),
|
||||
SvgNodes.ngon(1.5 * ppu, 3, 0).add_style(styles["wellhead-black"]),
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
wlp,
|
||||
prod,
|
||||
inj,
|
||||
gray
|
||||
};
|
||||
module.exports.default = module.exports;
|
||||
18
svgmap/drawers/well-ring.js
Normal file
18
svgmap/drawers/well-ring.js
Normal file
@ -0,0 +1,18 @@
|
||||
const SvgNodes = require("./svg-nodes");
|
||||
|
||||
function pt(wopt, wwpt, rmm, ppu, style) {
|
||||
return SvgNodes.ring_sectors(1.5 * ppu, rmm * ppu, [
|
||||
{ v: wopt, style: style.opt },
|
||||
{ v: wwpt, style: style.wpt },
|
||||
]);
|
||||
}
|
||||
|
||||
function it(rmm, ppu, style) {
|
||||
return SvgNodes.circle(rmm * ppu).add_style(style.wit);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
pt,
|
||||
it,
|
||||
};
|
||||
module.exports.default = module.exports;
|
||||
48
svgmap/helpers/style-adaptor.js
Normal file
48
svgmap/helpers/style-adaptor.js
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Преобразовать размер шрифта в единицы карты
|
||||
* @param { string | Number } v Значение для перевода "10mm", "22pt"
|
||||
* @param {*} ppu Pixel per unit
|
||||
* @returns
|
||||
*/
|
||||
function size2ppu(v, ppu) {
|
||||
if (typeof v !== "string") return v;
|
||||
|
||||
if (v.endsWith("mm")) {
|
||||
return parseFloat(v.substring(0, v.length - 2) * ppu * 100) / 69;
|
||||
}
|
||||
if (v.endsWith("pt")) {
|
||||
return (parseFloat(v.slice(0, v.length - 2)) * ppu * 100) / 283.46;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Перегоняет стиль в единицы карты (возвращает новый объект)
|
||||
* @param {*} style Объект стиля для преобразования
|
||||
* @param {*} ppu Pixel per unit
|
||||
*/
|
||||
function update_style(style, ppu) {
|
||||
let s = { ...style };
|
||||
const convertable = ["font-size", "stroke-width", "1pt", "1mm"];
|
||||
Object.keys(s).forEach((k) => {
|
||||
if (convertable.includes(k)) s[k] = size2ppu(s[k], ppu);
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Перегоняет все стили в единицы карты (возвращает новый объект)
|
||||
* @param {*} style Объект стиля для преобразования
|
||||
* @param {*} ppu Pixel per unit
|
||||
*/
|
||||
function update_styles(styles, ppu) {
|
||||
return Object.keys(styles).reduce((s, c) => ({ ...s, [c]: update_style(styles[c], ppu) }), {});
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
size2ppu,
|
||||
update_style,
|
||||
update_styles
|
||||
};
|
||||
|
||||
module.exports.default = module.exports;
|
||||
50
svgmap/helpers/style-defs.js
Normal file
50
svgmap/helpers/style-defs.js
Normal file
@ -0,0 +1,50 @@
|
||||
const SvgNode = require("../svg-node");
|
||||
|
||||
function simple_radial_gradient(id, color0, color1) {
|
||||
let s0 = new SvgNode("stop", { offset: "0%", "stop-color": color0 });
|
||||
let s1 = new SvgNode("stop", { offset: "100%", "stop-color": color1 });
|
||||
return new SvgNode("radialGradient", { id }).append(s0, s1);
|
||||
}
|
||||
|
||||
function radial_gradient(id, cx, cy, r) {
|
||||
return new SvgNode("radialGradient", { id, cx, cy, r });
|
||||
}
|
||||
|
||||
function stop(offset, color) {
|
||||
return new SvgNode("stop", { offset, "stop-color": color });
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts from styles items which must be in defs section.
|
||||
* @param {*} style
|
||||
*/
|
||||
function extract_style_defs(style) {
|
||||
const skeys = Object.keys(style).filter((x) => x.startsWith("$"));
|
||||
|
||||
return skeys.map((skey) => extract_class_def(style[skey], skey.substring(1)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts from styles items which must be in defs section.
|
||||
* @param {*} style
|
||||
*/
|
||||
function extract_class_def(cls, id) {
|
||||
if (cls.type == "radial-gradient") {
|
||||
const ckeys = Object.keys(cls);
|
||||
const stops = ckeys
|
||||
.filter((x) => x.endsWith("%"))
|
||||
.map((x) => new SvgNode("stop", { offset: x, "stop-color": cls[x] }));
|
||||
|
||||
return new SvgNode("radialGradient", { id }, stops);
|
||||
}
|
||||
|
||||
throw `Unknown system style ${cls.type}`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
simple_radial_gradient,
|
||||
radial_gradient,
|
||||
extract_style_defs,
|
||||
};
|
||||
|
||||
module.exports.default = module.exports;
|
||||
0
svgmap/index.js
Normal file
0
svgmap/index.js
Normal file
62
svgmap/svg-map-builder.js
Normal file
62
svgmap/svg-map-builder.js
Normal file
@ -0,0 +1,62 @@
|
||||
const SvgNode = require("./svg-node.js");
|
||||
const SvgNodes = require("./drawers/svg-nodes.js");
|
||||
const Defs = require('./helpers/style-defs')
|
||||
const well_ring = require('./drawers/well-ring')
|
||||
const well_head = require('./drawers/well-head')
|
||||
const corel_layer = require('./drawers/corel-layer')
|
||||
|
||||
function build_pt_layer(wells, settings, style) {
|
||||
function t2r(tons) {
|
||||
// tonns/mm2 = tonns/cm2 / 100. S(mm)=Pi*r*r=tons/tons_in_cm2*100. r = sqrt(tons/tons_in_cm2*100 / PI)
|
||||
return Math.sqrt(((tons / settings.tons_in_cm2) * 100) / Math.PI);
|
||||
}
|
||||
|
||||
let { ppu } = settings;
|
||||
|
||||
let svg = corel_layer("WWPT");
|
||||
// Круги
|
||||
svg.append(wells.map((x) => well_ring.pt(x.wopt, x.wwpt, t2r(x.wlpt), ppu, style).move(x.lx, x.ly)));
|
||||
|
||||
// Знак скважины
|
||||
svg.append(
|
||||
wells.map((x) => well_head[t2r(x.wlpt) > 1.6 ? "prod" : "gray"](ppu, style).move(x.lx, x.ly))
|
||||
);
|
||||
|
||||
// Имя скважины
|
||||
svg.append(wells.map((x) => well_head.name(x.name, ppu, style).move(x.lx, x.ly)));
|
||||
// Обводненность
|
||||
svg.append(wells.map((x) => well_head.wlp(x.wlf, ppu, style).move(x.lx, x.ly)));
|
||||
|
||||
return { svg };
|
||||
}
|
||||
|
||||
function build_it_layer(wells, settings) {
|
||||
function t2r(tons) {
|
||||
// tonns/mm2 = tonns/cm2 / 100. S(mm)=Pi*r*r=tons/tons_in_cm2*100. r = sqrt(tons/tons_in_cm2*100 / PI)
|
||||
return Math.sqrt(((tons / settings.tons_in_cm2) * 100) / Math.PI);
|
||||
}
|
||||
|
||||
let { ppu, style } = settings;
|
||||
|
||||
let svg = corel_layer("WWIT");
|
||||
|
||||
// Круги
|
||||
svg.append(wells.map((x) => SvgWellNodes.ring.it(t2r(x.wwit), ppu, style).move(x.lx, x.ly)));
|
||||
|
||||
// Знак скважины
|
||||
svg.append(
|
||||
wells.map((x) => SvgWellNodes.wellhead[t2r(x.wwit) > 1.6 ? "inj" : "gray"](ppu, style).move(x.lx, x.ly))
|
||||
);
|
||||
|
||||
// Имя скважины
|
||||
svg.append(wells.map((x) => SvgWellNodes.wellhead.name(x.name, ppu, style).move(x.lx, x.ly)));
|
||||
|
||||
return { svg };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
build_pt_layer,
|
||||
build_it_layer,
|
||||
};
|
||||
|
||||
module.exports.default = module.exports;
|
||||
53
svgmap/svg-map-saver.js
Normal file
53
svgmap/svg-map-saver.js
Normal file
@ -0,0 +1,53 @@
|
||||
const CoordSystem = require("../libs/coord-system");
|
||||
const BBox = require("../libs/bbox");
|
||||
const transfrom = require("../libs/transform");
|
||||
// const SvgMapBuilder = require("./svg-map-builder");
|
||||
const SvgNodes = require("./drawers/svg-nodes");
|
||||
const adaptor = require("./helpers/style-adaptor");
|
||||
const { extract_style_defs } = require('./helpers/style-defs');
|
||||
|
||||
module.exports = class SvgSaver {
|
||||
constructor(settings, style, bbox) {
|
||||
// Функция перевода координат из глобальных в локальные.
|
||||
const cs1 = new CoordSystem(bbox.l, bbox.t, bbox.r, bbox.b);
|
||||
const cs_mm = cs1.clone().flipy().moveto(0, 0).scale(settings.map_scale * 1000);
|
||||
const cs_ppu = cs_mm.clone().scale(settings.ppu);
|
||||
const csw = Math.abs(cs_mm.x1 - cs_mm.x0);
|
||||
const csh = Math.abs(cs_mm.y1 - cs_mm.y0);
|
||||
const bbox_ppu = BBox.fromLTRB(cs_ppu.x0, cs_ppu.y0, cs_ppu.x1, cs_ppu.y1);
|
||||
|
||||
this.tr = transfrom.fromCoordSyses(cs1, cs_ppu);
|
||||
|
||||
this.settings = settings
|
||||
this.style = adaptor.update_styles(style, settings.ppu);
|
||||
const defs = extract_style_defs(style)
|
||||
|
||||
this.svg = SvgNodes.svg()
|
||||
.set_attr("width", csw + "mm")
|
||||
.set_attr("height", csh + "mm")
|
||||
.set_attr("viewBox", `${bbox_ppu.l} ${bbox_ppu.t} ${bbox_ppu.w()} ${bbox_ppu.h()}`);
|
||||
|
||||
if (defs.length){
|
||||
this.svg.append(SvgNodes.node('defs', null, defs))
|
||||
}
|
||||
|
||||
// console.log(style)
|
||||
}
|
||||
|
||||
append_defs(defs) {
|
||||
this.svg.append(defs);
|
||||
}
|
||||
|
||||
append_svg(svg) {
|
||||
this.svg.append(svg);
|
||||
}
|
||||
|
||||
append_layer(layer) {
|
||||
this.append_defs(layer.defs);
|
||||
this.append_svg(layer.svg);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.svg.render();
|
||||
}
|
||||
};
|
||||
87
svgmap/svg-map-ui.js
Normal file
87
svgmap/svg-map-ui.js
Normal file
@ -0,0 +1,87 @@
|
||||
export default class SvgMapUI {
|
||||
constructor(host) {
|
||||
this.host = host
|
||||
this.scale = 1
|
||||
this.pos = { x: 0, y: 0 }
|
||||
console.log(host)
|
||||
this.host.onwheel = this.handle_wheel.bind(this)
|
||||
this.host.onmousedown = this.handle_mousedown.bind(this)
|
||||
this.host.onmousemove = this.handle_mousemove.bind(this)
|
||||
this.host.onmouseup = this.handle_mouseup.bind(this)
|
||||
|
||||
this.is_down = false
|
||||
|
||||
this.set_scale(1)
|
||||
}
|
||||
|
||||
|
||||
set(html){
|
||||
this.host.innerHTML = html
|
||||
}
|
||||
|
||||
handle_mousedown(event) {
|
||||
this.is_down = true
|
||||
this.downin = { x: event.clientX, y: event.clientY }
|
||||
console.log(event)
|
||||
// clientX: 451, clientY: 297
|
||||
// layerX: 451, layerY: 297
|
||||
}
|
||||
|
||||
handle_mousemove(event) {
|
||||
if (this.is_down) {
|
||||
event.preventDefault()
|
||||
let dx = event.clientX - this.downin.x
|
||||
let dy = event.clientY - this.downin.y
|
||||
|
||||
this.pos.x -= dx * this.scale
|
||||
this.pos.y -= dy * this.scale
|
||||
this.set_scale(this.scale)
|
||||
this.downin = { x: event.clientX, y: event.clientY }
|
||||
// this.downin = {x: event.clientX, y: event.clientY}
|
||||
}
|
||||
// console.log(event.x, event.clientX + this.pos.x, this.scale)
|
||||
}
|
||||
|
||||
handle_mouseup(event) {
|
||||
this.is_down = false
|
||||
}
|
||||
|
||||
|
||||
handle_wheel(event) {
|
||||
event.preventDefault()
|
||||
|
||||
if (event.ctrlKey) {
|
||||
if (event.deltaY > 0) {
|
||||
this.scale_up()
|
||||
}
|
||||
else
|
||||
this.scale_down()
|
||||
}
|
||||
|
||||
else if (event.shiftKey) {
|
||||
console.log('shifted')
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
}
|
||||
|
||||
console.log(event)
|
||||
}
|
||||
|
||||
set_scale(scale) {
|
||||
this.scale = scale
|
||||
if (!this.host.childNodes.length) return;
|
||||
this.host.childNodes[0].setAttribute("viewBox", `${this.pos.x} ${this.pos.y} ${2000 * this.scale} ${2000 * this.scale}`)
|
||||
// this.host.childNodes[0].setAttribute("width", `1000`)
|
||||
// this.host.childNodes[0].setAttribute("height", `1000`)
|
||||
}
|
||||
|
||||
scale_up() {
|
||||
this.set_scale(this.scale * 1.1)
|
||||
}
|
||||
|
||||
scale_down() {
|
||||
this.set_scale(this.scale * 0.9)
|
||||
}
|
||||
}
|
||||
140
svgmap/svg-map.js
Normal file
140
svgmap/svg-map.js
Normal file
@ -0,0 +1,140 @@
|
||||
import { parse } from "svg-parser";
|
||||
|
||||
import SvgNode from './svg-node.js'
|
||||
import SvgNodes from './svg-nodes.js'
|
||||
|
||||
export default class {
|
||||
async parse(xml) {
|
||||
let result1 = parse(xml);
|
||||
|
||||
this.svg = result1.children.filter((x) => x.tagName == "svg")[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить слои документа. Имя слоя можно получить через поле id.
|
||||
* @returns
|
||||
*/
|
||||
get_layers() {
|
||||
return this.svg.children.filter((x) => x.tagName == "g");
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить данные масштаба карты.
|
||||
* @returns {w, h, k, u} Ширина в мм, высота в мм, k * v[px] = v[мм], юниты (mm, cm, inch)
|
||||
*/
|
||||
get_map_scale() {
|
||||
// console.log(this.svg)
|
||||
let vb = this.svg.properties.viewBox.split(" ").map((x) => parseFloat(x));
|
||||
let w = this.svg.properties.width;
|
||||
let h = this.svg.properties.height;
|
||||
|
||||
let units = {
|
||||
in: 25.4,
|
||||
mm: 1,
|
||||
cm: 10,
|
||||
px: 0.0846646,
|
||||
// '%': 1
|
||||
};
|
||||
|
||||
const u = Object.keys(units).filter((x) => w.endsWith(x))[0];
|
||||
if (!u) throw "Unsupported units";
|
||||
|
||||
w = Math.round(parseFloat(w.substring(0, w.length - u.length)) * units[u] * 100) / 100;
|
||||
h = Math.round(parseFloat(h.substring(0, h.length - u.length)) * units[u] * 100) / 100;
|
||||
let k = vb[2] / w;
|
||||
|
||||
return { w, h, k, u };
|
||||
}
|
||||
|
||||
/**
|
||||
* Достать из слоя опордные скважины
|
||||
* @param {*} layer Слой в котором 2 последние группы содержат опорные скважины.
|
||||
* @returns { w1, w2 } Опрорные скважины
|
||||
*/
|
||||
extract_anchor(layer) {
|
||||
let w1 = this.extract_well(layer.children[layer.children.length - 1]);
|
||||
let w2 = this.extract_well(layer.children[layer.children.length - 2]);
|
||||
|
||||
return { w1, w2 };
|
||||
}
|
||||
|
||||
_flat(node) {
|
||||
if (!node.children) return [node];
|
||||
return node.children.reduce((s, c) => s.concat(this._flat(c)), [node]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить из группы данные скважины (имя, координаты)
|
||||
* @param {*} pivot_group Svg группа
|
||||
* @returns { {x, y, name} }
|
||||
*/
|
||||
extract_well(pivot_group) {
|
||||
let flat = this._flat(pivot_group);
|
||||
let ellipse = flat.filter((x) => x.tagName == "circle" || x.tagName == "ellipse")[0];
|
||||
let tr = ellipse.properties.transform
|
||||
.replace("matrix(", "")
|
||||
.replace(")", "")
|
||||
.split(" ")
|
||||
.map((x) => parseFloat(x));
|
||||
|
||||
let text = flat.filter((x) => x.type == "text")[0];
|
||||
let name = text.value;
|
||||
return { x: tr[4], y: tr[5], name };
|
||||
}
|
||||
|
||||
build_tp_layer(wells, settings){
|
||||
const sc = this.get_map_scale()
|
||||
|
||||
function t2r(tons){
|
||||
// tonns/mm2 = tonns/cm2 / 100. S(mm)=Pi*r*r=tons/tons_in_cm2*100. r = sqrt(tons/tons_in_cm2*100 / PI)
|
||||
return Math.sqrt(tons / settings.tons_in_cm2 * 100 / Math.PI)
|
||||
}
|
||||
|
||||
let {styles} = settings
|
||||
|
||||
let defs = new SvgNode("defs")
|
||||
defs.append(SvgNodes.defs.simple.radialGradient("rg_opt", "#fff", "#B86B41"))
|
||||
defs.append(SvgNodes.defs.simple.radialGradient("rg_wpt", "#fff", "#67c2e5"))
|
||||
|
||||
let svg = SvgNodes.group(['<metadata id="CorelCorpID_WWPTCorel-Layer"/>']).set_attr("id", "WWPT")
|
||||
// Круги
|
||||
svg.append(wells.map((x) => SvgNodes.ring_sectors(1.5 * sc.k, t2r(x.wlpt) * sc.k, [{v: x.wopt, style: styles.opt}, {v: x.wwpt, style: styles.wpt}]).move(x.lx, x.ly)));
|
||||
// Знак скважины
|
||||
svg.append(wells.map((x) => SvgNodes.circle(1.5 * sc.k).move(x.lx, x.ly).add_style(styles.wellhead)));
|
||||
// Имя скважины
|
||||
svg.append(wells.map((x) => SvgNodes.text(x.well).move(x.lx + styles.wellhead.dx * sc.k, x.ly + styles.wellhead.dy * sc.k).add_style(styles.wellhead)));
|
||||
// Обводненность
|
||||
svg.append(wells.map((x) => SvgNodes.text(`${Math.round(x.wlf * 1000)/10 || ''}%`).move(x.lx + styles.wlf.dx * sc.k, x.ly + styles.wlf.dy * sc.k).add_style(styles.wlf)));
|
||||
|
||||
return {defs, svg}
|
||||
}
|
||||
|
||||
build_ti_layer(wells, settings){
|
||||
const sc = this.get_map_scale()
|
||||
|
||||
function t2r(tons){
|
||||
// tonns/mm2 = tonns/cm2 / 100. S(mm)=Pi*r*r=tons/tons_in_cm2*100. r = sqrt(tons/tons_in_cm2*100 / PI)
|
||||
return Math.sqrt(tons / settings.tons_in_cm2 * 100 / Math.PI)
|
||||
}
|
||||
|
||||
let {styles} = settings
|
||||
|
||||
let defs = SvgNodes.container()
|
||||
defs.append(SvgNodes.defs.simple.radialGradient("rg1", "#fff", "#c1ff5e"))
|
||||
|
||||
let svg = SvgNodes.group(['<metadata id="CorelCorpID_WWITCorel-Layer"/>']).set_attr("id", "WWIT")
|
||||
// Круги
|
||||
// let g_rings = SvgNodes.group(['<metadata id="CorelCorpID_WWITRingsCorel-Layer"/>']).set_attr("id", "Круги")
|
||||
// svg.append(g_rings)
|
||||
svg.append(wells.map((x) => SvgNodes.circle(t2r(x.wwit) * sc.k).add_style(styles.wit).move(x.lx, x.ly)));
|
||||
// Знак скважины
|
||||
svg.append(wells.map((x) => SvgNodes.circle(1.5 * sc.k).move(x.lx, x.ly).add_style(styles.wellhead)));
|
||||
// Имя скважины
|
||||
svg.append(wells.map((x) => SvgNodes.text(x.well).move(x.lx + styles.wellhead.dx * sc.k, x.ly + styles.wellhead.dy * sc.k).add_style(styles.wellhead)));
|
||||
// Обводненность
|
||||
svg.append(wells.map((x) => SvgNodes.text(`${Math.round(x.wlf * 1000)/10 || ''}%`).move(x.lx + styles.wlf.dx * sc.k, x.ly + styles.wlf.dy * sc.k).add_style(styles.wlf)));
|
||||
|
||||
return {defs, svg}
|
||||
}
|
||||
|
||||
}
|
||||
70
svgmap/svg-node.js
Normal file
70
svgmap/svg-node.js
Normal file
@ -0,0 +1,70 @@
|
||||
class SvgNode {
|
||||
constructor(tag, attrs, items) {
|
||||
this.tag = tag
|
||||
this.attrs = attrs || {}
|
||||
this.items = items || []
|
||||
}
|
||||
|
||||
append(...items){
|
||||
this.items.push(...items)
|
||||
return this
|
||||
}
|
||||
|
||||
set_attr(attr, value) {
|
||||
this.attrs[attr] = value
|
||||
return this
|
||||
}
|
||||
|
||||
set_attrs(attrs) {
|
||||
this.attrs = { ...this.attrs, ...attrs }
|
||||
return this
|
||||
}
|
||||
|
||||
add_style(style) {
|
||||
this.style = { ...this.style || {}, ...style }
|
||||
return this
|
||||
}
|
||||
|
||||
clear_style() {
|
||||
this.style = null
|
||||
return this
|
||||
}
|
||||
|
||||
move(x, y) {
|
||||
if (this.transform)
|
||||
this.transform = { x: this.transform.x + x, y: this.transform.y + y }
|
||||
else
|
||||
this.transform = { x, y }
|
||||
return this
|
||||
}
|
||||
|
||||
get(attr) {
|
||||
|
||||
}
|
||||
|
||||
_render_node(node) {
|
||||
// console.log(typeof node)
|
||||
// if (typeof node == 'undefined') return ''
|
||||
if (typeof node == 'string') return node
|
||||
else if (typeof node == 'object' && node.tag) return node.render()
|
||||
else if (Array.isArray(node)) return node.map(this._render_node).join('')
|
||||
else return ''
|
||||
}
|
||||
|
||||
render() {
|
||||
let attrs = Object.keys(this.attrs).filter(x => this.attrs[x]).map(x => ` ${x}="${this.attrs[x]}"`).join('')
|
||||
// console.log(this.style ? Object.keys(this.style).map(x => `${x}:${this.style[x]}`) : '')
|
||||
let style = this.style ? ' style="' + Object.keys(this.style).map(x => `${x}:${this.style[x]}`).join('; ') + '"' : ''
|
||||
let transfrom = this.transform ? ` transform="translate(${this.transform.x},${this.transform.y})"` : ''
|
||||
let items = this.items ? this.items.map(x => this._render_node(x)).join('') : ''
|
||||
|
||||
// console.log('this.items', this.items, items)
|
||||
if (this.tag)
|
||||
return `<${this.tag}${attrs}${style}${transfrom}>${items}</${this.tag}>`
|
||||
else
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SvgNode
|
||||
module.exports.default = module.exports;
|
||||
Loading…
Reference in New Issue
Block a user