[TOC]
[email protected] 2016-06-06 16:29 markdown Poimoepoimoe
B/S SocketCanvasAJAXHTTPComet
**** HTML5 + CSS3 + JavaScript **** Nodejs **** MongoDB
PHP + MySql
**** Mac OS X **** Sublime Text 3 **** Git **** HomebrewNPM MongoDB Node
PoimoeSPA 5
MVVMVuejs + Angularjs Bootstrap Webpack ECMAScriptBabel
RESTful APIrestify MongoDBMongoose
RESTful API
TCP/IPSocketComet
**** CentOS ****Nginx + php-fpm
Cookie + localStoragedocument.domainpoimoe
///
/
/
/
/
/
Webpack
var webpack = require('webpack');
module.exports = {
entry: './src/index.js',
output: {
path: __dirname,
filename: './dist/build.js'
},
module: {
loaders: [
{ test: /\.vue$/, loader: 'vue' },
{ test: /\.css$/, loader: "style!css" },
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' },
{ test: /\.js$/, loader: 'jsx-loader?harmony' },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff2" },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" }
]
},
babel: {
presets: ['es2015', 'stage-0'],
plugins: ['transform-runtime']
},
resolve: {
//require
extensions: ['', '.js', '.json', '.css'],
//
alias: {
vueStrap: './node_modules/vue-strap/dist/vue-strap.min.js',
bootstrap: './node_modules/bootstrap/dist/css/bootstrap.min.css'
}
}
}
if (process.env.NODE_ENV === 'production') {
module.exports.plugins = [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new webpack.optimize.OccurenceOrderPlugin()
]
} else {
module.exports.devtool = '#source-map'
}
JS/CSS//
npm run dev
.
npm run build
gulp
var args = require('yargs').argv,
path = require('path'),
flip = require('css-flip'),
through = require('through2'),
gulp = require('gulp'),
$ = require('gulp-load-plugins')(),
gulpsync = $.sync(gulp),
PluginError = $.util.PluginError,
del = require('del'),
connect = require('gulp-connect');
//---------------
// MAIN TASKS
//---------------
// build for production (minify)
gulp.task('build', gulpsync.sync([
'prod',
'vendor',
'assets'
]));
gulp.task('prod', function() {
log('Starting production build...');
isProduction = true;
});
// build with sourcemaps (no minify)
gulp.task('sourcemaps', ['usesources', 'default']);
gulp.task('usesources', function(){ useSourceMaps = true; });
// default (no minify)
gulp.task('default', gulpsync.sync([
'vendor',
'assets',
'serve',
'watch'
]), function(){
log('************');
log('* All Done * You can start editing your code, LiveReload will update your browser after any change..');
log('************');
});
gulp.task('serve', function () {
connect.server({
root: '../',
livereload: false,
port: 8080
});
});
gulp.task('assets',[
'scripts:app',
'styles:app',
'styles:app:rtl',
'styles:themes',
'templates:index',
'templates:views'
]);
jscssscsslessjadehtml/
gulp
gulp build
git + ssh
echo "commit"
read msg
git add .
git commit -a -m "$msg"
git push -u origin master
rsync -avz -4 --exclude-from "/var/www/poimoe/exclude.md" /var/www/poimoe/ [email protected]:/var/www/poimoe/
github
Supervisor
poikaku:
npm run dev
8080
gulp
8080
supervisorsupervisorNode
cd /var/www/poimoe/admin/master/ && gulp build
cd /var/www/poimoe/web/kaku && npm run build
cd /var/www/poimoe/web/poi && npm run build
sh p.sh #
supervisorSocketAPI
screen -S poimoe_api && cd /var/www/poimoe/api && supervisor app.js
screen -S poimoe_socket && cd /var/www/poimoe/socket && supervisor app.js
nginx
systemctl start mariadb
systemctl start php-fpm
mongod
. README.md admin app index.html master server vendor api app.js conf controllers models node_modules package.json routes.js sc.sh util build.sh cdn exclude.md image index.php upload.php npm-debug.log p.sh r.sh server.sh socket index.html index.js node_modules package.json util web index kaku poi Poimoe adminapiapiimagesocketweb
p.shgithub r.sh
. app.js conf controllers models node_modules package.json routes.js sc.sh util
apiAPI
app.js api conf controllers models node_modules nodejs routes.js api sc.sh util
API
var restify = require('restify');
var mongoose = require('mongoose');
var routes = require('./routes');
var dbconf = require('./conf/db');
var conf = require('./conf/conf');
var models = require('./models/index');
//mongodb
mongoose.connect('mongodb://' + dbconf.mongo.host + '/' + dbconf.mongo.database);
var db = mongoose.connection;
var Schema = mongoose.Schema;
db.on('error', console.error.bind(console,'connection error'));
db.once('open', function(callback) {
});
//restify
var server = restify.createServer({
name: 'poimoe'
});
restify.CORS.ALLOW_HEADERS.push('authorization');
server.use(restify.authorizationParser());
server.use(restify.bodyParser());
server.use(restify.queryParser());
server.use(restify.CORS());
//
routes.init(server, mongoose, restify);
//
server.listen(2333, function() {
console.log('%s listening at %s', server.name, server.url);
});
supervisor app.js
JavaScriptCORSCORS
server.pre(function(req, res, next) {
res.charSet('utf-8');
res.setHeader('Allow', 'GET, POST, OPTIONS, PUT, DELETE');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, Api-Version, Authorization');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
res.setHeader('Access-Control-Allow-Credentials', 'true');
return next();
});
restify
server.use(ctrl.userCtrl.auth);
userauthauth
auth: function(req, res, next) {
var reqRoute = req.route.path;
var routesNoneAuth = [
'/themes/hot', '/tags/select/hotTags',
'/user/recommended', '/user/register/:email/:password',
'/user/login/:email/:password', '/themes/select/:tid',
'/user/profile/get/:uid', '/site/search/:val/:page/:count', '/timeline/message/personal/count/:uid',
'/timeline/message/index/count/:uid', '/timeline/message/index/count/:uid',
'/kaku/room/all/:page/:count'
];
if(req.username == 'anonymous') {
var reqRouteList = reqRoute.split('/');
var isHasNoneAuthRoute = false;
for (var i = routesNoneAuth.length - 1; i >= 0; i--) {
var currRoute = routesNoneAuth[i];
if(currRoute == reqRoute) {
isHasNoneAuthRoute = true;
break;
}
};
//
if(!isHasNoneAuthRoute) {
res.send(util.retMsg(4001, ""));
}else {
return next();
}
}else {
var User = ctrlInitial.models.User();
User.findByAccessToken(req.authorization.credentials, function(err, u) {
if(err) {
res.send(util.retMsg(400, err.toString()));
}
if(u.length === 0) {
res.send(util.retMsg(4001, "access_token"));
}
if(u[0].tokenCreatedAt == undefined || u[0].tokenDestoriedAt == undefined) {
res.send(util.retMsg(4001, "access_token"));
}
var currentTimestamp = Date.now();
if(currentTimestamp > u[0].tokenDestoriedAt) {
res.send(util.retMsg(4001, "access_token"));
}
if(u[0].isBlocked === true) {
res.send(util.retMsg(400, "" + thisEmail + " "));
}
if(u[0].isDeleted === true) {
res.send(util.retMsg(400, "" + thisEmail + " "));
}
global.currentUserId = u[0]._id;
var group = u[0].group;
if(group.length === 0) {
res.send(util.retMsg(401, ""));
}
var group = group[0];
if(group.name == 'root' && group.code == 100) {
//root
next();
}else {
var ug = ctrlInitial.models.UserGroups();
ug.findById(group._id, function(err, auth) {
if(err) {
res.send(util.retMsg(400, err.toString()));
}
if(auth.length === 0) {
res.send(util.retMsg(401, ""));
}else {
var authList = auth[0].rightsList;
var hadAuth = false;
var AuthName = '';
for (var i = 0; i < authList.length; i++) {
var currentAuth = authList[i];
var router = currentAuth.router;
if(router == reqRoute) {
hadAuth = true;
break;
}
};
if(!hadAuth) {
res.send(util.retMsg(401, ""));
}else {
next();
}
}
});
}
});
}
},
PoimoeOAuthAccessTokentokenauth
Poimoe
root
json
applyAuthority: function(req, res, next) {
var rights = req.params.rights;
var id = req.params.id;
if(rights == undefined || rights == '') {
res.send(util.retMsg(401, ""));
}
if(id == undefined || id == '') {
res.send(util.retMsg(401, "id"));
}
if(rights.length === 0) {
res.send(util.retMsg(401, ""));
}
var UG = ctrlInitial.models.UserGroups();
UG.findById(id, function(err, ug) {
if(err) {
res.send(util.retMsg(401, err.toString()));
}
if(ug.length === 0) {
res.send(util.retMsg(401, ''));
}
ug = ug[0];
if(ug.code == '100') {
// res.send(util.retMsg(401, ''));
}
UG.update(id, {
rightsList: rights
}, function(err, ug) {
if(err) {
res.send(util.retMsg(401, err.toString()));
}
res.send(util.retMsg(200, '', ug));
});
});
},
applyToUser: function(req, res, next) {
var aid = req.params.aid;
var uid = req.params.uid;
if(uid == undefined || uid == '') {
res.send(util.retMsg(401, "id"));
}
if(aid == undefined || aid == '') {
res.send(util.retMsg(401, "id"));
}
var UG = ctrlInitial.models.UserGroups();
UG.findById(aid, function(err, ug) {
if(err) {
res.send(util.retMsg(401, err.toString()));
}
if(ug.length === 0) {
res.send(util.retMsg(401, ''));
}
ug = ug[0];
var User = ctrlInitial.models.User();
User.updateGroup(aid, uid, function(err, user) {
if(err) {
res.send(util.retMsg(401, err.toString()));
}
res.send(util.retMsg(200, '', user));
});
});
}
CGCGCGCGCGAJAXComet
PoimoeComet
TimelinePoimoe
PoimoeTimeline
personalMessageQueue: [{
operator: {
type: Schema.Types.ObjectId,
ref: 'users'
},
targetUser: {
type: Schema.Types.ObjectId,
ref: 'users'
},
targetTheme: {
type: Schema.Types.ObjectId,
ref: 'themes'
},
did: {
type: String,
default: 'repost' //repost || favourite
},
createdAt: {
type: Date,
default: Date.now
}
}]
ididCG id
messageQueue: [{
type: Schema.Types.ObjectId,
ref: 'themes'
}],
getMessageCount: function(req, res, next) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive"
});
var count = 0;
var loadMessageCount = function() {
var uid = req.params.uid;
if(uid == '' || uid == undefined) {
res.write(util.retESMsg(401, 'id'));
}
var User = ctrlInitial.models.User();
var Timeline = ctrlInitial.models.Timeline();
Timeline.findMessageCount(uid, function(err, tl_messageCount) {
if(err) {
res.write(util.retESMsg(401, err.toString()));
}
if(tl_messageCount == null) {
var tline = new Timeline({
user_id: uid
});
tline.save(function(err, new_tl) {
if(err) {
res.write(util.retESMsg(401, err.toString()));
}
res.write(util.retESMsg(200, new_tl.messageCount));
});
}else {
res.write(util.retESMsg(200, tl_messageCount.messageCount));
}
});
};
console.log('user start index message count comet service');
global.currentCountInterval = setInterval(function() {
loadMessageCount();
}, 500);
res.connection.on('end', function(){
console.log('user exit index message count comet service');
clearInterval(currentCountInterval);
});
},
CometHTTP header
content-typetext/event-stream
CometHTML5EventSource
startIndexTimelineComet: function() {
var _this = this;
var es = new EventSource('http://api.poimoe.com//timeline/message/index/count/' + localStorage._id);
es.onmessage = function(e) {
_this.indexMesssageCount = JSON.parse(e.data).message;
console.log(_this.indexMesssageCount);
};
es.onerror = function(e) {
util.handleError('comet');
};
es.onopen = function(e) {}
}
. index.html index.js node_modules express express-mongoose mongoose request socket.io package.json util index.js
socketididaccessToken
enter chatting room succeedenter chatting room failed
UI
UIUI
enterRoom: function(id) {
var _this = this;
var chatSocket = io('ws://socket.poimoe.com/chat');
chatSocket.emit('enter chatting room', {
people: localStorage._id,
roomId: id,
passport: sessionStorage[id],
username: localStorage.username,
accessToken: localStorage.accessToken
});
window.chatSocket = chatSocket;
chatSocket.on('enter chatting room succeed', function(res) {
var code = res.code;
var data = res.message;
if(code != 200) {
util.messageBox(data);
router.go('/index');
return false;
}
_this.room = data[0];
_this.room.chatting.reverse();
if(_this.room.paint != null) {
_this.paint = _this.room.paint;
// falsetruefalsetrue
for(var key in _this.paint) {
_this.paint[key] = _this.paint[key] == 'false' ? false : (_this.paint[key] == 'true' ? true : _this.paint[key]);
if(key == 'layer' || key == 'currentLayer') {
if(typeof _this.paint[key].length == 'number') {
for (var i = 0; i < _this.paint[key].length; i++) {
var curr = _this.paint[key][i];
for(var k in curr) {
_this.paint[key][i][k] = _this.paint[key][i] == 'false' ? false : ( _this.paint[key][i][k] == 'true' ? true : _this.paint[key][i][k] );
}
};
}
}
}
//
// toggleLayer(key, layer.id, paint.currentLayer.index);
_this.paint.x = [];
_this.paint.y = [];
_this.paint.clickDrag = [];
}
// _this.paintUI = _this.room.paintUI;
setTimeout(function() {
_this.initPaint();
_this.initBasePaint();
//
//dataURLtoDataURL
_this.drawImageOnCanvas(_this.paint.dataURL, _this.paint.baseCxt);
_this.drawImageOnCanvas(_this.paint.dataURL, _this.paint.cxt);
var activeLayerIndex = _this.paint.currentLayer.index;
var activeLayerId = _this.paint.layer[activeLayerIndex].id;
var activeLayer = {
cxt: '',
url: ''
};
for (var i = 0; i < _this.paint.layer.length; i++) {
var currentLayer = _this.paint.layer[i];
var tmpCxt = document.getElementById(currentLayer.id).getContext('2d');
if(currentLayer.dataURL != '') {
console.log(currentLayer.dataURL);
_this.drawImageOnCanvas(currentLayer.dataURL, tmpCxt);
if(activeLayerId == currentLayer.id) {
activeLayer.cxt = tmpCxt;
activeLayer.url = currentLayer.dataURL;
}
}
};
// //dataURL
// console.log(activeLayer);
// _this.drawImageOnCanvas(activeLayer.url, activeLayer.cxt);
_this.isLoaded = true;
setTimeout(function() {
common.adjustUI();
}, 400);
_this.initKakuMQSocket();
_this.initKakuInstantSavingThread();
}, 10);
//// _this.initKakuSocket(id);
});
chatSocket.on('enter chatting room failed', function(msg) {
util.handleError(msg, 'socket');
});
chatSocket.on('leave room failed', function(msg) {
util.handleError(msg, 'socket');
});
chatSocket.on('leave room succeed', function(msg) {
console.log(msg);
});
chatSocket.on('sys', function(msg) {
util.handleError(msg, 'socket');
});
chatSocket.on('chat message', function(msg) {
if(typeof msg === 'string') {
msg = JSON.parse(msg);
}
var code = msg.code;
var data = msg.message;
if(code != 200) {
util.messageBox(data);
return false;
}
_this.room.chatting.push(data.chatting[0]);
_this.message = '';
});
},
chatSocket.emit('leave', {
leaver: localStorage._id,
roomId: router._currentRoute.params.id,
accessToken: localStorage.accessToken
});
var dataURL = this.paint.baseCanvas.toDataURL();
PoimoebaseCanvas
toDataURL
cloneObject: function(original, ignoreList) {
ignoreList = ignoreList || false;
var tmp = {};
for(var key in original) {
if(ignoreList) {
if(ignoreList.indexOf(key) === -1) {
tmp[key] = original[key];
}
}else {
tmp[key] = original[key];
}
}
return tmp;
},
Poimoe
getLayerDataURL: function(canvas) {
var cxt = canvas.getContext('2d');
var oldData = cxt.getImageData(0, 0, canvas.width, canvas.height);
var newCanvas = document.createElement("canvas");
newCanvas.width = canvas.width;
newCanvas.height = canvas.height;
newCanvas.id = "tmpLayer";
document.body.appendChild(newCanvas);
var newCxt = newCanvas.getContext("2d");
newCxt.putImageData(oldData, 0 ,0);
var data = newCanvas.toDataURL();
newCanvas.parentNode.removeChild(newCanvas);
return data;
}
canvascxt.getImageDatacanvascanvascanvasPoimoegetImageDatatoDataURL
CGPoi
shareThisCG: function(obj, cb) {
var navToPoi;
if(obj != undefined) {
navToPoi = obj.navToPoi == false ? obj.navToPoi : true;
}else {
navToPoi = true;
obj = {
isLayer: false,
nodel: 'no'
}
}
var _this = this;
//
//cookie
//poiCG
var base64 = obj.base64 || this.paint.baseCanvas.toDataURL();
var requestParams = navToPoi ? localStorage._id + '/roomCG/' + this.room._id + '/sharing' : localStorage._id + '/roomCG/' + this.room._id + '/painting';
requestParams = obj.isLayer ? requestParams + '/layers' : requestParams;
services.KakuService.uploadBase64ToServer({
uid: requestParams,
nodel: obj.nodel || 'no'
}, {
base64Image: base64
}).then(function(res) {
var code = res.data.status;
var data = res.data.message;
if(code != 200) {
util.messageBox(data, true);
return false;
}
var imageUrl = data.origin;
if(navToPoi) {
var split = imageUrl.split('/');
var name = split[split.length - 1];
window.location.href = 'http://poi.poimoe.com/#!/cg/new/' + _this.room._id + '/' + name;
}else {
cb(imageUrl);
}
}, function(err) {
util.handleError(err);
});
},
canvasbase64postbase64
toggleSyncPaintingStatus: function() {
if(this.instantSaving.startInstantSavingThread) {
clearInterval(this.instantSaving.instantSavingThreadFlag);
this.instantSaving.tips = '';
util.messageBox('');
this.instantSaving.startInstantSavingThread = false;
}else {
util.messageBox('');
_this.instantSaving.tips = '';
this.instantSaving.startInstantSavingThread = true;
this.initKakuInstantSavingThread();
}
}
myId: localStorage._id,
room: {},
message: '',
isLoaded: false,
paint: {
x: [], //x
y: [], //y
lock: false, //
isEraser: false,
eraserRadius: 15,
isColorPicker: false,
canvas: '',
cxt: '',
baseCanvas: '',
baseCxt: '',
lineWidth: 5,
strokeStyle: 'rgba(0, 0, 0, 0)',
width: 0,
height: 0,
clickDrag: [],
touch: ('createTouch' in document),
startEvent: this.touch ? 'touchstart' : 'mousedown',
moveEvent: this.touch ? 'touchmove' : 'mousemove',
endEvent: this.touch ? 'touchend' : 'mouseup',
layer: [{
name: '',
opacity: 100,
display: 'block',
zindex: 1,
id: 'layer-bg',
active: true,
editable: false,
marginTop: 0,
dataURL: ''
}],
currentLayer: {
id: 'layer-bg',
index: 0
},
picData: '',
dataURL: ''
},
paintUI: {
colorPickerCursorPosition: '',
colorPicker: {}
},
instantSaving: {
instantSavingThreadFlag: 0,
startInstantSavingThread: false,
tips: ''
}
myId:id room message isLoaded paint paint.xx paint.yy paint.lock paint.isEraser paint.eraserRadius paint.canvas paint.cxtcanvas paint.baseCanvascanvas paint.baseCxt paint.lineWidth paint.strokeStyle paint.width paint.height paint.clickDrag paint.touchtouch paint.startEvent paint.moveEvent paint.endEvent paint.layer paint.currentLayer paint.picData
canvascanvas
layer: [{
name: '',
opacity: 100,
display: 'block',
zindex: 1,
id: 'layer-bg',
active: true,
editable: false,
marginTop: 0,
dataURL: ''
}],
currentLayer: {
id: 'layer-bg',
index: 0
}
layer.name layer.opacity layer.displaydisplay layer.zindex layer.idcanvasdomid layer.active layer.editable layer.marginTop layer.dataURL
addNewLayer: function(layer, noSocket) {
noSocket = noSocket || false;
var thisPaint = this.paint;
var thisPaintLayer = thisPaint.layer;
var currentLayerIndex = thisPaint.currentLayer.index;
thisPaintLayer[currentLayerIndex].active = false;
thisPaintLayer[currentLayerIndex].zindex = -1;
var layerId = 'LAYER' + util.randomString(8);
var layerCount = thisPaintLayer.length;
var layer = layer || {
name: '' + layerCount,
opacity: 100,
display: 'block',
zindex: 1,
id: layerId,
active: true,
editable: false,
marginTop: '-800px',
dataURL: ''
};
thisPaintLayer.push(layer);
this.toggleLayer(layerCount, layerId, currentLayerIndex);
layer.people = localStorage._id;
if(!noSocket) {
chatSocket.emit('new layer', layer);
}
},
removeThisLayer: function(index, noSocket) {
noSocket = noSocket || false;
var thisPaint = this.paint;
var thisPaintLayer = thisPaint.layer;
var currentLayer = thisPaint.currentLayer;
var currentLayerIndex = index || currentLayer.index;
var tmpIndex = currentLayerIndex;
if(currentLayerIndex === 0) {
util.messageBox('');
return false;
}
thisPaintLayer.splice(currentLayerIndex);
this.toggleLayer(currentLayerIndex - 1, thisPaintLayer[currentLayerIndex - 1].id);
if(!noSocket) {
chatSocket.emit('remove layer', {
index: tmpIndex,
people: localStorage._id
});
}
},
toggleLayer: function(activeIndex, activeId, unactiveIndex, noSocket) {
if(activeIndex == unactiveIndex) {
return false;
}
noSocket = noSocket || false;
var thisPaint = this.paint;
var thisPaintLayer = thisPaint.layer;
var currentLayer = thisPaint.currentLayer;
currentLayer.index = activeIndex;
currentLayer.id = activeId;
thisPaintLayer[activeIndex].active = true;
thisPaintLayer[activeIndex].zindex = 1;
if(typeof unactiveIndex != 'undefined') {
thisPaintLayer[unactiveIndex].active = false;
thisPaintLayer[unactiveIndex].zindex = -1;
}
this.initPaintInterval(activeId);
if(!noSocket) {
chatSocket.emit('toggle layer', {
activeIndex: activeIndex,
activeId: activeId,
unactiveIndex: unactiveIndex,
people: localStorage._id
});
}
},
showThisLayer: function(id, noSocket) {
noSocket = noSocket || false;
this.paint.layer[id].display = 'block';
if(!noSocket) {
chatSocket.emit('show layer', {
index: id,
people: localStorage._id
});
}
},
hideThisLayer: function(id, noSocket) {
noSocket = noSocket || false;
this.paint.layer[id].display = 'none';
if(!noSocket) {
chatSocket.emit('hide layer', {
index: id,
people: localStorage._id
});
}
},
makeThisLayerEditable: function(id, makeFalse) {
makeFalse = makeFalse || true;
this.paint.layer[id].editable = !this.paint.layer[id].editable;
if(!makeFalse) {
setTimeout(function() {
this.paint.layer[id].editable = false;
}, 10);
}
},
confirmEditThisLayerName: function(index, name) {
this.paint.layer[index].editable = false;
var layer = this.paint.layer[index];
layer.people = localStorage._id;
layer.index = index;
chatSocket.emit('modify layer', layer);
},
MVVMthis.paint.lineWidthdomDOMslider
canvasColorPicker
kaku/src/commons/scripts/ColorPicker.js
_this.colorPicker = ColorPicker.init({
onColorChange: function(color) {
_this.paint.strokeStyle = color;
chatSocket.emit('color change', {
people: localStorage._id,
color: _this.paint.strokeStyle
});
},
defaultColor: 'rgba(0, 0, 0, 255)'
});
var panel = _this.colorPicker.getPanel();
document.getElementById('color-picker-area').appendChild(panel);
resetErase: function(_x, _y, touch) {
var t = this.paint;
var cxt = t.cxt;
for (var i = 0; i < 2; i++) {
if(i === 1) {
cxt = t.baseCxt;
}
cxt.globalCompositeOperation = "destination-out";
cxt.beginPath();
cxt.arc(_x, _y, t.eraserRadius, 0, Math.PI * 2);
cxt.strokeStyle = "rgba(250,250,250,0)";
cxt.fill();
cxt.globalCompositeOperation = "source-over";
};
}
HTMLFileReadercanvas
getPicFile: function() {
var file = document.getElementById('upfile');
var reader = new FileReader();
var _this = this;
reader.readAsDataURL(file.files[0]);
reader.onload = function(e){
_this.drawImage(this.result);
};
reader.onerror = function(e) {
console.log(e);
};
reader.onabort = function(e) {
console.log(e);
};
}
drawImagecanvas
canvasdataURL
window.open(this.paint.baseCanvas.toDataURL());
Socket.io expresssocket
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var mongoose = require('mongoose');
var request = require('request');
var lib = require('./util/index.js');
app.get('/', function(req, res){
res.send('welcome to poimoe socket server');
});
var chat = io.of('/chat');
var kaku = io.of('/kaku');
Socketchat message
socket.on('chat message', function(msg){
console.log('msg reveived: ');
if(!roomInfo[roomId]) {
roomInfo[roomId] = [];
}
if (roomInfo[roomId].indexOfA(user) === -1) {
return false;
}
request.post({
url: 'http://api.poimoe.com/kaku/room/chat/send',
encoding: 'utf8',
headers: {
'Authorization': 'Basic ' + msg.accessToken
},
form: msg
},
function(error, response, body){
if(!error && response.statusCode == 200){
console.log(body);
chat.to(roomId).emit('chat message', body);
}else{
console.log(response.statusCode);
chat.to(roomId).emit('chat message', {
code: response.statusCode,
message: response.body,
error: error,
headers: response.headers,
request: response.request
});
}
}
);
});
confirmToSendChattingMessage: function() {
var _this = this;
if(_this.message == '') {
util.messageBox('');
return false;
}
var chatMessage = {
sender: localStorage._id,
roomId: _this.room._id,
message: _this.message,
accessToken: localStorage.accessToken
};
chatSocket.emit('chat message', chatMessage);
},
ididaccessToken
chatSocket.on('chat message', function(msg) {
if(typeof msg === 'string') {
msg = JSON.parse(msg);
}
var code = msg.code;
var data = msg.message;
if(code != 200) {
util.messageBox(data);
return false;
}
_this.room.chatting.push(data.chatting[0]);
_this.message = '';
});
Socket
socketstart draw kaku
socket.on('start draw kaku', function(msg) {
if(!roomInfo[roomId]) {
roomInfo[roomId] = [];
}
if (roomInfo[roomId].indexOfA(user) === -1) {
return false;
}
chat.to(roomId).emit('get kaku path', msg);
});
emitget kaku path
chatSocket.emit('start draw kaku', {
x: t.x,
y: t.y,
strokeStyle: t.strokeStyle,
clickDrag: t.clickDrag,
lineWidth: t.lineWidth,
eraserRadius: t.eraserRadius,
people: localStorage._id
});
xyid
chatSocket.on('get kaku path', function(data) {
if(!(data.people.toString() == localStorage._id)) {
_this.paint.strokeStyle = data.strokeStyle;
_this.paint.lineWidth = data.lineWidth;
_this.paint.x = data.x;
_this.paint.y = data.y;
_this.paint.clickDrag = data.clickDrag;
_this.paint.eraserRadius = data.eraserRadius;
_this.drawPoint();
_this.drawPoint(false, _this.paint.baseCxt);
}
});
idid
drawPoint
drawPoint: function(sendSocket, cxt) {
sendSocket = sendSocket || false;
var t = this.paint;
var cxt = cxt || t.cxt;
cxt.fillStyle = "#000000";
if(sendSocket) {
chatSocket.emit('start draw kaku', {
x: t.x,
y: t.y,
strokeStyle: t.strokeStyle,
clickDrag: t.clickDrag,
lineWidth: t.lineWidth,
eraserRadius: t.eraserRadius,
people: localStorage._id
});
}
for(var i=0; i < t.x.length; i++) {
cxt.beginPath();//context.beginPath() ,
if(t.clickDrag[i] && i){//i!=0
cxt.moveTo(t.x[i-1], t.y[i-1]);//context.moveTo(x, y) ,
}else{
cxt.moveTo(t.x[i] - 1, t.y[i]);
}
cxt.lineTo(t.x[i], t.y[i]);//context.lineTo(x, y) ,
cxt.closePath();//context.closePath() ,
cxt.stroke();//context.stroke() ,
}
cxt.save();
}
socket
. 448c34a56d699c29117adc64c43affeb.woff2 89889688147bd7575d6327160d64e760.svg README.md dist e18bbf611f2a2e43afc071aa2f4e1512.ttf f4769f9bdb7466be65088239c12046d1.eot fa2772327f55d8198301fdb8bcfc8158.woff index.html node_modules package.json remove.sh src upload.html webpack.config.js
Poikaku****MVVMVueJS
. 404.vue app.vue commons components config.js filters index.js npm-debug.log routes.js services
app.vue 404.vue commons jscssimages components filters index.js routes.js services api
iframe
upload.html
<script type="text/javascript">
function getQueryString(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
return null;
}
localStorage.pictureUploadedJSON = getQueryString('data');
document.write(localStorage.pictureUploadedJSON);
</script>
DOM
<div @click="uploadCG()" class="timeline-new-section-outer" id="my-cg-viewer">
<h1 v-show="isCGShow === false" style="line-height: 14">CG</h1>
<div id="cg-outer">
<img style="display:none" id="sharing-viewer" class="cg-viewer" width="100" height="100" border="0">
</div>
<form style="display:none" enctype="multipart/form-data" method="post" target="upload" v-bind:action="cgUploadAction" >
<input type="file" id="cg-source" name="upfile" v-on:change="previewImage()"/>
<input id="submit-cg-btn" type="submit" />
</form>
<iframe style="display:none" id="ifr" name="upload"></iframe>
</div>
uploadCG
document.getElementById("cg-source").click();
formpreviewImage
previewImage: function() {
var width = document.getElementById('my-cg-viewer').style.width;
var height = document.getElementById('my-cg-viewer').offsetHeight - 2;
util.previewImage('cg-source', 'cg-outer', 'cg-viewer', '', 'width:100%;height:' + height + 'px;');
this.isCGShow = true;
var _this = this;
util.syncUploadPic('submit-cg-btn', 'ifr', function(picJSON) {
_this.cg.image = picJSON.message.preview;
});
}
11
syncUploadPic: function(submitBtnId, ifrId, cb) {
document.getElementById(submitBtnId).click();
var _this = this;
var getJSON = function() {
var picJSON = JSON.parse(localStorage.pictureUploadedJSON);
if(picJSON.status != 200) {
_this.messageBox('');
return false;
}
cb(picJSON);
};
var oFrm = document.getElementById(ifrId);
oFrm.onload = oFrm.onreadystatechange = function() {
if (this.readyState && this.readyState != 'complete') {
return false;
}
else {
getJSON();
}
}
},
formsubmitiframeurl
php
if(!$cors) {
returnMessage(200, array('origin' => 'http://image.poimoe.com/'.$destination_folder.$fname, 'preview' => 'http://image.poimoe.com/'.$destination));
}else {
header('Location:'.$corsurl.'?data='.returnMessage(200, array('origin' => 'http://image.poimoe.com/'.$destination_folder.$fname, 'preview' => 'http://image.poimoe.com/'.$destination), true));
}
. error nodata.vue favourites index.vue footer.vue header.vue index.vue loading loading.vue search search.vue search.vue timeline index.vue personal.vue public.vue users login.vue notifications.vue profile.vue relations signin.vue works index.vue new.vue view.vue
error favourites cg footer header loading ajax search timeline uses works workwork
poicometapi
. index.php upload.php
PHPNginx + php-fpmCORS
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, Api-Version, Authorization');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE');
header('Access-Control-Allow-Credentials: true');
header("Content-type: text/html; charset=utf-8");
. app css documentation i18n img js vendor views index.html master bower.json bower_components gulpfile.js jade js less node_modules package.json sass vendor.base.json vendor.json server sidebar-menu.json vendor angular-datatables angular-ui-map datatables fontawesome modernizr simple-line-icons weather-icons
angularjsjadehtmllesscss
master
// START widgets box
.row(ng-controller="DashboardController as dash")
.col-lg-3.col-sm-6
// START widget
.panel.widget.bg-primary
.row.row-table
.col-xs-4.text-center.bg-primary-dark.pv-lg
em.icon-user.fa-3x
.col-xs-8.pv-lg
.h2.mt0 {{dash.dashboardInfo.usersAddedToday}}
.text-uppercase
.col-lg-3.col-sm-6
// START widget
.panel.widget.bg-purple
.row.row-table
.col-xs-4.text-center.bg-purple-dark.pv-lg
em.icon-users.fa-3x
.col-xs-8.pv-lg
.h2.mt0 {{dash.dashboardInfo.usersCount}}
.text-uppercase
.col-lg-3.col-md-6.col-sm-12
// START widget
.panel.widget.bg-green
.row.row-table
.col-xs-4.text-center.bg-green-dark.pv-lg
em.icon-bubbles.fa-3x
.col-xs-8.pv-lg
.h2.mt0 {{dash.dashboardInfo.themesCount}}
.text-uppercase
.col-lg-3.col-md-6.col-sm-12
// START date widget
.panel.widget
.row.row-table
.col-xs-4.text-center.bg-green.pv-lg
// See formats: https://docs.angularjs.org/api/ng/filter/date
em.icon-tag.fa-3x
.col-xs-8.pv-lg
.h2.mt0 {{dash.dashboardInfo.tagsCount}}
.text-uppercase
// END date widget
// END widgets box
UserService.getAll(1, 1000)
.success(function(res, status, headers, config) {
if(res.code != 200) {
var toast = $mdToast.simple()
.content(res.message)
.action('')
.highlightAction(false)
.position('top right');
$mdToast.show(toast).then(function() {
});
}
vm.usersList = res.message;
})
.error(function(res, status, headers, config) {
var toast = $mdToast.simple()
.content('' + status)
.action('')
.highlightAction(false)
.position('top right');
$mdToast.show(toast).then(function() {
});
});
javascriptpromisegulp